diff --git a/src/dgipy/integrations/clinical_trials.py b/src/dgipy/integrations/clinical_trials.py index 631aa4d..f4b63a8 100644 --- a/src/dgipy/integrations/clinical_trials.py +++ b/src/dgipy/integrations/clinical_trials.py @@ -2,12 +2,90 @@ import logging -from regbot.fetch.clinical_trials import StandardAge +from regbot.fetch.clinical_trials import StandardAge, Status, Study from regbot.fetch.clinical_trials import get_clinical_trials as get_trials_from_fda _logger = logging.getLogger(__name__) +def _add_study_to_output(output: dict[str, list], drug_name: str, study: Study) -> None: + """Update `output` in-place with results from study + + :param output: in-progress raw columnar data + :param study: clinical trial study data to add to output + """ + output["drug_name"].append(drug_name.upper()) + output["trial_id"].append(study.protocol.identification.nct_id) + output["brief"].append(study.protocol.identification.brief_title) + output["study_type"].append(study.protocol.design.study_type) + min_age = ( + study.protocol.eligibility.min_age + if study.protocol and study.protocol.eligibility + else None + ) + output["min_age"].append(min_age) + max_age = ( + study.protocol.eligibility.max_age + if study.protocol and study.protocol.eligibility + else None + ) + output["max_age"].append(max_age) + age_groups = ( + study.protocol.eligibility.std_age + if study.protocol and study.protocol.eligibility + else None + ) + output["age_groups"].append(age_groups) + output["pediatric"].append(StandardAge.CHILD in age_groups if age_groups else None) + output["conditions"].append( + study.protocol.conditions.conditions + if study.protocol and study.protocol.conditions + else None + ) + output["interventions"].append( + [i._asdict() for i in study.protocol.arms_intervention.interventions] + if study.protocol + and study.protocol.arms_intervention + and study.protocol.arms_intervention.interventions + else None + ) + eligibility = study.protocol.eligibility + if not eligibility: + output["incl_excl_criteria"].append(None) + output["population_sex"].append(None) + output["population_description"] + else: + output["incl_excl_criteria"].append(eligibility.description) + output["population_sex"].append(eligibility.sex) + output["population_description"].append(eligibility.population) + all_locations = ( + study.protocol.contacts_locations.locations + if study.protocol.contacts_locations + and study.protocol.contacts_locations.locations + else [] + ) + + potential_sites = [ + { + "name": location.facility, + "status": location.status, + "city": location.city, + "country": location.country, + "coordinates": location.geo, + } + for location in all_locations + if location.status + in { + Status.RECRUITING, + Status.NOT_YET_RECRUITING, + Status.AVAILABLE, + Status.TEMPORARILY_NOT_AVAILABLE, + Status.UNKNOWN, + } + ] + output["potential_sites"].append(potential_sites) + + def get_clinical_trials(terms: list[str]) -> dict: """Acquire associated clinical trials data for drug term @@ -41,47 +119,16 @@ def get_clinical_trials(terms: list[str]) -> dict: "pediatric": [], "conditions": [], "interventions": [], + "incl_excl_criteria": [], + "population_sex": [], + "population_description": [], + "potential_sites": [], } for drug in terms: results = get_trials_from_fda(drug) for study in results: - output["drug_name"].append(drug.upper()) - output["trial_id"].append(study.protocol.identification.nct_id) - output["brief"].append(study.protocol.identification.brief_title) - output["study_type"].append(study.protocol.design.study_type) - min_age = ( - study.protocol.eligibility.min_age - if study.protocol and study.protocol.eligibility - else None - ) - output["min_age"].append(min_age) - max_age = ( - study.protocol.eligibility.max_age - if study.protocol and study.protocol.eligibility - else None - ) - output["max_age"].append(max_age) - age_groups = ( - study.protocol.eligibility.std_age - if study.protocol and study.protocol.eligibility - else None - ) - output["age_groups"].append(age_groups) - output["pediatric"].append( - StandardAge.CHILD in age_groups if age_groups else None - ) - output["conditions"].append( - study.protocol.conditions.conditions - if study.protocol and study.protocol.conditions - else None - ) - output["interventions"].append( - [i._asdict() for i in study.protocol.arms_intervention.interventions] - if study.protocol - and study.protocol.arms_intervention - and study.protocol.arms_intervention.interventions - else None - ) + _add_study_to_output(output, drug, study) + return output diff --git a/tests/integrations/test_clinical_trials.py b/tests/integrations/test_clinical_trials.py index 3ea4507..1eb66d3 100644 --- a/tests/integrations/test_clinical_trials.py +++ b/tests/integrations/test_clinical_trials.py @@ -2,7 +2,12 @@ from pathlib import Path import requests_mock -from regbot.fetch.clinical_trials import InterventionType, StandardAge, StudyType +from regbot.fetch.clinical_trials import ( + InterventionType, + StandardAge, + Status, + StudyType, +) from dgipy.integrations.clinical_trials import get_clinical_trials @@ -63,3 +68,14 @@ def test_get_clinical_trials(fixtures_dir: Path): "aliases": ["AVXS-101", "Zolgensma"], } ] + assert ( + results["incl_excl_criteria"][example_index] + == "Inclusion Criteria\n\n* SMA diagnosis\n* Aged 2 to \\< 18 years\n* Have had at least four loading doses of nusinersen (Spinraza\u00ae) or at least 3 months of treatment with risdiplam (Evrysdi\u00ae) at Screening\n* Must have symptoms of SMA as defined in the protocol\n\nExclusion Criteria:\n\n* Anti Adeno Associated Virus Serotype 9 (AAV9) antibody titer using an immunoassay is reported as elevated\n* Clinically significant abnormalities in test results during screening\n* Contraindications for lumbar puncture procedure\n* At Baseline, participants are excluded if they received:\n\n * nusinersen (Spinraza\u00ae) or\n * risdiplam (Evrysdi\u00ae) within a defined timeframe\n* Vaccinations 2 weeks prior to administration of OAV101\n* Hospitalization for a pulmonary event, or for nutritional support within 2 months prior to Screening or inpatient major surgery planned.\n* Presence of an infection or febrile illness up to 30 days prior to administration of OAV101\n* Requiring invasive ventilation" + ) + assert { + "name": "Child Hosp of the Kings Daughters", + "status": Status.RECRUITING, + "city": "Norfolk", + "country": "United States", + "coordinates": (36.84681, -76.28522), + } in results["potential_sites"][3]