import requests
from .api import Drug_Label_Client
[docs]
class Drug:
"""
OVERVIEW:
Drug object is the primary object used to engage with drugs in the
openFDA drug/label dataset after retrieved from API call. Drugs are
generated by inputting the "meta" and "results" sections of the raw
json return, and can be generated with make_drug in our final package
implementation. Drugs allow users to call a number of different
functions to collect individual parameter values from the openFDA
dataset or to provide high level overviews, risk scores, or
comprehensive data structure with all fields from the raw json file.
This class is designed to make accessing information about a particular
drug extremely easy based on the raw json file.
ATTRIBUTES
raw: core json output for results of an individual query about a drug
meta: meta information from a query used to produce this individual drug
openfda: specific openfda subsection of the json output for this drug
USAGE EXAMPLE:
>>> # User function loads in API key as api_key
>>> client = Drug_Label_Client(api_key)
>>> advil_items = generic_search("brand_name", "Advil")
>>> advil_json = search_request(advil_items, limit=1)
>>> advil_drug = Drug(advil_json["meta"], advil_json["results"][0])
>>> advil_drug.drug_overview() # returns overall dict about drug stats
"""
def __init__(self, meta: dict, result: dict):
"""
OVERVIEW:
Initializes the Drug class obj by storing result dict, meta dict,
and separating openfda dict from original json entries
PARAMETERS:
meta (dict): dictionary containing high level query data ab drug
result (dict): detailed individualized dict about drug info
RETURN VALUE:
None
USAGE EXAMPLE:
>>> # User function loads meta and results through make_drug
>>> Advil = Drug(advil_meta, advil_result)
"""
# check type for meta and result objects
if not isinstance(meta, dict):
raise TypeError("meta must be a dictionary input")
if not isinstance(result, dict):
raise TypeError("result must be a dictionary input")
# initialize self attributes for raw, meta, and openfda
self.raw = result
self.meta = meta
self.openfda = self.raw.get("openfda", {})
[docs]
def raw_drug(self):
"""
OVERVIEW:
Returns the raw json of the results without any processing for
interested parties to manipulate with their own functions.
PARAMETERS:
None: simply takes the object and returns an attribute
RETURN VALUE:
raw (dict): returns the json format of the results section
USAGE EXAMPLE:
>>> Advil.raw_drug() # returns raw value of self.raw
"""
# super simple return of self.raw attribute, no testing precautions needed
return self.raw
[docs]
def get_name(self):
"""
OVERVIEW:
Returns the drug's name from the openfda subsection of results
by checking for name in "brand_name." If not available in that
field, checks backups of "generic_name" and "substance_name" to
try and locate an appropriate name. Returns None if not possible.
PARAMETERS:
None: simply takes the object and returns an attribute
RETURN VALUE:
name (str/None): returns the name of a given drug if available
USAGE EXAMPLE:
>>> Advil.get_name() # returns full name of advil drug if available
"""
# search across all possible name fields for drug name in "brand_name" and two backups
for criteria in ["brand_name", "generic_name", "substance_name"]:
if criteria in self.openfda and self.openfda[criteria]:
return self.openfda[criteria][0]
# return None if name is not available
return None
[docs]
def get_parameter(self, parameter: str):
"""
OVERVIEW:
Returns (if available) the field for a provided parameter of the
drug in whatever contained format is present. If field is not
available, returns None as a value to the user. Rejects name
parameters and asks user to use get_name function shown above.
PARAMETERS:
parameter (str): field we want to extract value of for Drug
RETURN VALUE:
value (str/list/None): value contained in dict for parameter
# if parameter contains a list, returns the first element
USAGE EXAMPLE:
>>> Advil.get_parameter("ingredients") # returns advil ingredients
"""
# check parameter value/type
if not isinstance(parameter, str):
raise TypeError("Please input a string to check for parameters")
if not parameter:
raise ValueError("parameter cannot be empty")
# check if name is query'd and redirect if needed
if parameter in ["brand_name", "generic_name", "substance_name", "name"]:
raise ValueError("Please use get_name function")
# return values if possible, else None
if parameter in self.raw and self.raw[parameter]:
return self.raw[parameter][0] if isinstance(self.raw[parameter], list) else self.raw[parameter]
elif parameter in self.openfda and self.openfda[parameter]:
return self.openfda[parameter][0] if isinstance(self.openfda[parameter], list) else self.openfda[parameter]
else:
return None
[docs]
def drug_overview(self):
"""
OVERVIEW:
Function that provides a dictionary with a high level overview of
descriptive statistics on the drug object. Includes drug name,
universal production code, manufacturer name, product type, route,
description, and risk score, which measures number of fields with
high risks that are actually populated using risk_score function
below.
PARAMETERS:
None
RETURN VALUE:
drug_info (dict): contains keys for overview parameters and values
name (str): name of drug
upc (str): universal product code of drug
manufacturer name (str): man. who made the drug
product type (str): kind of product sold
route (str): how to take this drug (e.g. "ORAL")
description (str): description string for this drug
risk score (float): percentage of risky fields filled in risk_score
USAGE EXAMPLE:
>>> advil = Drug(meta, result)
>>> overview = advil.drug_overview() # returns dict with overview fields
"""
# return dictionary to be filled
drug_info = {}
# add name using get_name
drug_info["name"] = self.get_name()
# upc is unique because we extend the acronym to be clear in result
if "upc" in self.openfda and self.openfda["upc"]:
drug_info["universal production code"] = self.get_parameter("upc")
# run get_parameter function to populate the rest
for field in ["manufacturer_name", "product_type", "route","description"]:
split_field = field.split("_")
modified_field = " ".join(split_field)
drug_info[modified_field] = self.get_parameter(field)
# run risk_score to get risk score and return drug_info dict
drug_info["risk score"] = self.risk_score()[1]
return drug_info
[docs]
def get_date(self):
"""
OVERVIEW:
Returns date of most recently published drug in the drug query used to
collect original json of this drug.
PARAMETERS:
None
RETURN VALUE:
Date (str): date of most recent pull from meta field of drug
USAGE EXAMPLE:
>>> advil = Drug(meta, result)
>>> date = advil.get_date() # returns most recent update date of advil
"""
# simple check to see if date is available
if "last_updated" in self.meta:
return self.meta["last_updated"]
return None
[docs]
def risk_score(self):
"""
OVERVIEW:
Returns computed risk dict/score for 9 core categories of risk. If these fields
contain any non-None data, they receive a True in the risk dictionary and add
to the total risk tally. Total risk tally is taken as a percentage of nine and
also returned with function output. Thus, function provides flexibility of seeing
which individual risks are True (or exist) and total percentage of risks that this
drug carries.
PARAMETERS:
None
RETURN VALUE:
risk_list (list): list containing risk dictionary with booleans and risk score
USAGE EXAMPLE:
>>> advil = Drug(meta, result)
>>> date = advil.risk_score() # returns [advil_risk_info, advil_risk_score]
"""
# initiate risk_count and risk_info
risk_count = 0
risk_info = {}
# all risk fields
risk_fields = ["overdosage", "boxed_warning", "contraindications",
"drug_interactions", "controlled_substance", "abuse", "dependence",
"precautions", "user_safety_warnings"]
# iterate through fields and check all datasets of results
for risk in risk_fields:
if risk in self.openfda and self.openfda[risk]:
risk_count += 1
risk_info[risk] = True
elif risk in self.raw and self.raw[risk]:
risk_count += 1
risk_info[risk] = True
# compute risk_score and return list
risk_score = risk_count/len(risk_fields)
return [risk_info, risk_score]
[docs]
def drug_comprehensive(self):
"""
OVERVIEW:
Provides a comprehensive dictionary covering all fields contained in results ection
of the Drug object. Iterates through json format and appends to all_info dict,
returning result.
PARAMETERS:
None
RETURN VALUE:
all_info (dict): dictionary containing all parameters and stored values in Drug
USAGE EXAMPLE:
>>> advil = Drug(meta, result)
>>> date = advil.drug_comprehensive() # returns all parameters and fields in a dict
"""
# initiate all_info dict
all_info = {}
# iterate through entire json
for field in self.raw:
if field == "openfda":
for subfield in self.openfda:
all_info[subfield] = self.openfda[subfield]
else:
all_info[field] = self.raw[field]
# return everything
return all_info