Skip to content

Commit

Permalink
feat!: add RxClass API fetcher
Browse files Browse the repository at this point in the history
  • Loading branch information
jsstevenson committed Oct 17, 2024
1 parent 2cdb170 commit cfebf81
Show file tree
Hide file tree
Showing 5 changed files with 708 additions and 23 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ ignore = [
# B011 - assert-false
# INP001 - implicit-namespace-package
# D103 - missing-docstring-public-function
"tests/*" = ["ANN001", "ANN2", "ANN102", "S101", "B011", "INP001", "D103"]
"tests/*" = ["ANN001", "ANN2", "ANN102", "S101", "B011", "INP001", "D103", "D100"]

[tool.ruff.format]
docstring-code-format = true
6 changes: 3 additions & 3 deletions src/regbot/fetch/drugsfda.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ def _get_result(data: dict, normalize: bool) -> Result:
)


def get_drugsfda_results(
def make_drugsatfda_request(
url: str, normalize: bool = False, limit: int = 500
) -> list[Result] | None:
"""Get Drugs@FDA data given an API query URL.
Expand Down Expand Up @@ -677,7 +677,7 @@ def get_anda_results(anda: str, normalize: bool = False) -> list[Result] | None:
:return: list of Drugs@FDA ``Result``s if successful
"""
url = f"https://api.fda.gov/drug/drugsfda.json?search=openfda.application_number:ANDA{anda}"
return get_drugsfda_results(url, normalize)
return make_drugsatfda_request(url, normalize)


def get_nda_results(nda: str, normalize: bool = False) -> list[Result] | None:
Expand All @@ -689,4 +689,4 @@ def get_nda_results(nda: str, normalize: bool = False) -> list[Result] | None:
:return: list of Drugs@FDA ``Result``s if successful
"""
url = f"https://api.fda.gov/drug/drugsfda.json?search=openfda.application_number:NDA{nda}"
return get_drugsfda_results(url, normalize)
return make_drugsatfda_request(url, normalize)
80 changes: 61 additions & 19 deletions src/regbot/fetch/rxclass.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""todo"""
"""Fetch data from RxClass API."""

import logging
from collections import namedtuple
Expand Down Expand Up @@ -118,46 +118,74 @@ def _missing_(cls, value): # noqa: ANN001 ANN206
)


def _get_concept(concept_raw: dict) -> DrugConcept:
"""TODO"""
def _get_concept(concept_raw: dict, normalize: bool) -> DrugConcept:
return DrugConcept(
concept_id=f"rxcui:{concept_raw['rxcui']}",
name=concept_raw["name"],
term_type=TermType[concept_raw["tty"]],
term_type=TermType[concept_raw["tty"]] if normalize else concept_raw["tty"],
)


def _get_classification(classification_raw: dict) -> DrugClassification:
"""TODO"""
def _get_classification(
classification_raw: dict, normalize: bool
) -> DrugClassification:
return DrugClassification(
class_id=classification_raw["classId"],
class_name=classification_raw["className"],
class_type=classification_raw["classType"],
class_type=ClassType(classification_raw["classType"].lower())
if normalize
else classification_raw["classType"],
class_url=classification_raw.get("classUrl"),
)


def _get_rxclass_entry(drug_info: dict) -> RxClassEntry:
"""Todo"""
def _get_relation(raw_value: str | None, normalize: bool) -> str | Relation | None:
if raw_value is None:
return None
if normalize:
return Relation(raw_value.lower())
return raw_value


def _get_relation_source(raw_value: str, normalize: bool) -> str | RelationSource:
return RelationSource(raw_value.lower()) if normalize else raw_value


def _get_rxclass_entry(drug_info: dict, normalize: bool) -> RxClassEntry:
return RxClassEntry(
concept=_get_concept(drug_info["minConcept"]),
drug_classification=_get_classification(drug_info["rxclassMinConceptItem"]),
relation=Relation(drug_info["rela"].lower()) if drug_info["rela"] else None,
relation_source=RelationSource(drug_info["relaSource"].lower()),
concept=_get_concept(drug_info["minConcept"], normalize),
drug_classification=_get_classification(
drug_info["rxclassMinConceptItem"], normalize
),
relation=_get_relation(drug_info.get("rela"), normalize),
relation_source=_get_relation_source(drug_info["relaSource"], normalize),
)


def make_rxclass_request(url: str, include_snomedt: bool = False) -> list[RxClassEntry]:
"""TODO"""
def make_rxclass_request(
url: str, include_snomedt: bool = False, normalize: bool = False
) -> list[RxClassEntry]:
"""Issue an API request to RxClass.
:param url: RxClass API URL to request
:param include_snomedct: if ``True``, include class claims provided by SNOMEDCT.
These are provided under a different license from the rest of the data and
may present publishability issues for data consumers.
:param normalize: if ``True``, try to normalize values to controlled enumerations
and appropriate Python datatypes
:return: processed list of drug class descriptions from RxClass
"""
with requests.get(url, timeout=30) as r:
try:
r.raise_for_status()
except RequestException as e:
_logger.warning("Request to %s returned status code %s", url, r.status_code)
raise e
raw_data = r.json()
if not raw_data:
return []
processed_results = [
_get_rxclass_entry(entry)
_get_rxclass_entry(entry, normalize)
for entry in raw_data["rxclassDrugInfoList"]["rxclassDrugInfo"]
]
if not include_snomedt:
Expand All @@ -167,9 +195,23 @@ def make_rxclass_request(url: str, include_snomedt: bool = False) -> list[RxClas
return processed_results


def get_drug_info(drug: str) -> list[RxClassEntry]:
"""TODO"""
def get_drug_class_info(
drug: str, include_snomedct: bool = False, normalize: bool = False
) -> list[RxClassEntry]:
"""Get RxClass-provided drug info.
See also RxClass getClassByRxNormDrugName API:
https://lhncbc.nlm.nih.gov/RxNav/APIs/api-RxClass.getClassByRxNormDrugName.html
:param drug: RxNorm-provided drug name
:param include_snomedct: if ``True``, include class claims provided by SNOMEDCT.
These are provided under a different license from the rest of the data and
may present publishability issues for data consumers.
:param normalize: if ``True``, try to normalize values to controlled enumerations
and appropriate Python datatypes
:return: list of drug class descriptions from RxClass
"""
url = (
f"https://rxnav.nlm.nih.gov/REST/rxclass/class/byDrugName.json?drugName={drug}"
)
return make_rxclass_request(url)
return make_rxclass_request(url, include_snomedct, normalize)
Loading

0 comments on commit cfebf81

Please sign in to comment.