├── .codeclimate.yml ├── .coveragerc ├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.rst ├── daily_med ├── __init__.py ├── daily_med.py ├── exceptions.py ├── hl7.py ├── models │ ├── __init__.py │ ├── spl.py │ └── spl_document.py ├── request_paginator.py └── tests │ ├── __init__.py │ ├── spl_doc_1.xml │ ├── spl_doc_2.xml │ ├── test_daily_med.py │ ├── test_request_paginator.py │ └── test_spl_document.py ├── requirements.txt └── setup.py /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | languages: 2 | JavaScript: false 3 | Python: true 4 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | 3 | branch = True 4 | 5 | [report] 6 | 7 | exclude_lines = 8 | pragma: no cover 9 | def __repr__ 10 | if self.debug: 11 | raise NotImplementedError 12 | if __name__ == .__main__.: 13 | 14 | ignore_errors = True 15 | 16 | include = 17 | */daily_med/* 18 | 19 | omit = 20 | */virtualenv/* 21 | */tests/* 22 | setup.py 23 | */__init__.py 24 | tests.py 25 | daily_med/models/spl_document.py 26 | 27 | [xml] 28 | 29 | output = coverage.xml 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | addons: 2 | apt: 3 | packages: 4 | - expect-dev # provides unbuffer utility 5 | 6 | language: python 7 | 8 | python: 9 | - "2.7" 10 | - "pypy-5.4" 11 | 12 | env: 13 | global: 14 | - PROJECT="python-daily-med" 15 | - VERSION="0.1" 16 | - RELEASE="0.1.0" 17 | - DOCS_PY_VERSION="2.7" 18 | - DOCS_SEPARATE_PAGE="1" 19 | - DOCS_AUTO_SUMMARY="1" 20 | - BRANCH_PROD="release/initial" 21 | - secure: "HLV0BXRFLZ8KnK9IyOJscPaccBTMhL27bHqluWFbq+hVZg2uYSe6c11ZDGLEZtSHxfv2j89p36t3f7Q+CTfeWQUy2uOz4ZQLxc9SJ+AxkxzM6La8rS3bKwXYgYA0MXiD4wQ5+Ou3S+cZ0IoRUyG2AnWizsciGnM8/rRK2sgKpeghFSeD1oGdAvIukq/YpqyFOBUzeHPE/6uOKgICL3Ho22K+ny+Xgx3u7i1pcbCXZQX0uRS2FrVzwkJK7vOzXAHl8kQohqwyUrW2NfbnGE03KI3qpzVQfGKUPZnGXcjL3MoFXlEdBWXin/HFUGc9audTtvQm5sJ/O8QhuySJHM2f/klDk8KhYwCtUDFTKyRwjN5z9NrCvyTn/tSfnUkVRzBeuySaEA3fpZTK7YzvnBxgouvDgb6W0cf3bkhM8JzYyE1oYrELuN/u4ofPOkcvjgDQhQGgbsVie99lTgvkMhgdRndLzawQO8Fzq1zR6OBoNWx+V0adve5sfdbKQxTbZ1ChXXSSI5tcpozhebdwbOMWRz3wrRCX52P78R+ItKiWxN3SUSNkGk29q3YjXn2vck1q7Wgr9bi+VYJibCfe0EVONYxY69bHia+ymXyQW85YGf0D2IiOzxTzRgo+D3YaRypv+MPTXwvaADxQd4WhLo/doO9bjGfrwGf07QxZzett1/A=" 22 | matrix: 23 | - TESTS="1" 24 | - PYPI="1" 25 | - DOCS="1" 26 | - LINT_CHECK="1" 27 | 28 | install: 29 | - git clone --depth=1 https://github.com/LasLabs/python-quality-tools.git -b feature/docs-sep-page ${HOME}/python-quality-tools 30 | - export PATH=${HOME}/python-quality-tools/travis:${PATH} 31 | - travis_install 32 | 33 | script: 34 | - travis_run 35 | 36 | after_success: 37 | - travis_after_success 38 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright `2017` `LasLabs Inc.` 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the “Software”), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | |License MIT| | |Build Status| | |Coveralls Status| | |Codecov Status| | |Code Climate| 2 | 3 | ================ 4 | Python Daily Med 5 | ================ 6 | 7 | This library interacts with the United States National Library of Medicine's Daily 8 | Med API. 9 | 10 | Installation 11 | ============ 12 | 13 | * Install Python requirements ``pip install -r ./requirements`` 14 | 15 | Setup 16 | ===== 17 | 18 | * 19 | 20 | Usage 21 | ===== 22 | 23 | * `Read The API Documentation `_ 24 | 25 | Import and Instantiate 26 | ---------------------- 27 | 28 | Importing an instantiating the Daily Med object: 29 | 30 | .. code-block:: python 31 | 32 | from daily_med import DailyMed 33 | dm = DailyMed() 34 | 35 | Structured Product Label Metadata 36 | --------------------------------- 37 | 38 | `get_spls` mirrors the `/spls` interface as documented `here 39 | `_. 79 | 80 | Contributors 81 | ------------ 82 | 83 | * Dave Lasley 84 | 85 | Maintainer 86 | ---------- 87 | 88 | .. image:: https://laslabs.com/logo.png 89 | :alt: LasLabs Inc. 90 | :target: https://laslabs.com 91 | 92 | This module is maintained by LasLabs Inc. 93 | 94 | .. |Build Status| image:: https://api.travis-ci.org/LasLabs/python-daily-med.svg?branch=master 95 | :target: https://travis-ci.org/LasLabs/python-daily-med 96 | .. |Coveralls Status| image:: https://coveralls.io/repos/LasLabs/python-daily-med/badge.svg?branch=master 97 | :target: https://coveralls.io/r/LasLabs/python-daily-med?branch=master 98 | .. |Codecov Status| image:: https://codecov.io/gh/LasLabs/python-daily-med/branch/master/graph/badge.svg 99 | :target: https://codecov.io/gh/LasLabs/python-daily-med 100 | .. |Code Climate| image:: https://codeclimate.com/github/LasLabs/python-daily-med/badges/gpa.svg 101 | :target: https://codeclimate.com/github/LasLabs/python-daily-med 102 | .. |License MIT| image:: https://img.shields.io/badge/license-MIT-blue.svg 103 | :target: https://opensource.org/licenses/MIT 104 | :alt: License: AGPL-3 105 | -------------------------------------------------------------------------------- /daily_med/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .daily_med import DailyMed 6 | 7 | __all__ = [ 8 | 'DailyMed', 9 | ] 10 | -------------------------------------------------------------------------------- /daily_med/daily_med.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import requests 6 | 7 | from . import models 8 | 9 | from .hl7 import str_to_time 10 | from .request_paginator import RequestPaginator 11 | 12 | 13 | class DailyMed(object): 14 | """ It provides Python bindings to the Daily Med API. 15 | 16 | Additional documentation regarding the API endpoints is available at 17 | https://dailymed.nlm.nih.gov/dailymed/app-support-web-services.cfm 18 | """ 19 | 20 | API_BASE = 'https://dailymed.nlm.nih.gov/dailymed/services/v2' 21 | 22 | def get_spls(self, **kwargs): 23 | """ get_spls returns an iterator of matching SPL Meta Data. 24 | 25 | For more information about SPLs (Structured Product Labels), please 26 | visit the FDA documentation. 27 | 28 | Args: 29 | application_number (str): New Drug Application (NDA) number. See 30 | the documentation for resource /applicationnumbers for more 31 | information. 32 | boxed_warning (bool): Whether or not a drug contains a boxed 33 | warning. 34 | dea_schedule_code (str): Code representing a Drug Enforcement 35 | Administration Schedule for drugs. See the FDA documentation 36 | for DEA Schedules for more information. Acceptable values are 37 | listed below: 38 | * none - Not Scheduled. 39 | * C48672 - CI. 40 | * C48675 - CII. 41 | * C48676 - CIII. 42 | * C48677 - CIV. 43 | * C48679 - CV. 44 | doctype (str): FDA's Logical Observation Identifiers Names 45 | and Codes system. Determines the type of document or content 46 | of a label. 47 | drug_class_code (str): Code representing a pharmacologic drug 48 | class. See the documentation for resource /drugclasses 49 | for more information. 50 | drug_class_coding_system (str): Used with drug_class_code 51 | to specify the coding system of the drug class code. 52 | Acceptable values are listed below: 53 | * 2.16.840.1.113883.3.26.1.5 - National Drug File 54 | Reference Terminology. (Default value) 55 | drug_name (str): Generic or brand name. See the documentation 56 | for resource /drugnames for more information. 57 | name_type (str): Used with drug_name to specify whether the given 58 | name is a generic name or brand name. Acceptable values are 59 | listed below: 60 | * `g` or `generic` - Generic name. 61 | * `b` or `brand` - Brand name. 62 | * `both` - Either generic or brand name. (Default value) 63 | labeler (str): Name of labeler for the drug. 64 | manufacturer (str): Name of manufacturer for the drug. 65 | marketing_category_code (str): FDA's Marketing Categories for 66 | types of drugs. See the FDA documentation for Marketing 67 | Category for more information. 68 | ndc (str): National Drug Code (NDC). See the documentation for 69 | resource /ndcs for more information. 70 | published_date (str): The date that the drug was published on 71 | DailyMed. The accepted date format is YYYY-MM-DD 72 | (ex. 2015-09-10) 73 | published_date_comparison (str): Used with published_date to 74 | specify the type of comparison used with the date. Acceptable 75 | values are listed below: 76 | * `lt` - Drugs that have a published date Less Than 77 | the published_date parameter. 78 | * `lte` - Drugs that have a published date Less Than 79 | or Equal To the published_date parameter. 80 | * `gt` - Drugs that have a published date Greater Than 81 | the published_date parameter. 82 | * `gte` - Drugs that have a published date Greater Than 83 | or Equal To the published_date parameter. 84 | * `eq` - Drugs that have a published date Equal 85 | To the published_date parameter (Default value) 86 | rxcui (str): RxNorm Concept Unique Identifier (RXCUI) code. 87 | See the documentation for resource /rxcuis for more 88 | information. 89 | setid (str): Set ID of a label. 90 | unii_code (str): Unique Ingredient Identifier (UNII) code. 91 | See the documentation for resource /uniis for more 92 | information. 93 | Returns: 94 | SPL: Object containing metadata, but no document. 95 | """ 96 | return self.call('spls', models.SPL, kwargs) 97 | 98 | def get_spl(self, set_id): 99 | """ get_spl returns an SPLDocument for the set_id. 100 | 101 | Args: 102 | set_id (str): Set ID of the label. 103 | Returns: 104 | SPL: Object containing both the metadada and document. 105 | """ 106 | response = requests.get( 107 | url='%s/spls/%s.xml' % (self.API_BASE, set_id), 108 | ) 109 | spl_document = models.spl_document.parseString( 110 | response.text, silence=True, 111 | ) 112 | title_vals = models.spl_document.get_all_values( 113 | spl_document.title.content_ 114 | ) 115 | return models.SPL( 116 | set_id=spl_document.id.root, 117 | title=' '.join([val for val in title_vals if val.strip()]), 118 | spl_version=spl_document.versionNumber.value, 119 | published_date=str_to_time(spl_document.effectiveTime.value), 120 | document=spl_document, 121 | ) 122 | 123 | def call(self, endpoint, output_type, params=None): 124 | """ It calls the remote endpoint and returns the result, if success. 125 | 126 | Args: 127 | endpoint (str): DailyMed endpoint to call (e.g. ``ndcs``). 128 | output_type (type): Class type to output. Object will be 129 | instantiated using the current row before output. 130 | params: (dict|bytes) Data to be sent in the query string 131 | for the Request. 132 | Returns: 133 | RequestPaginator: Iterator representing all pages of the call 134 | result. 135 | Raises: 136 | DailyMedRemoteException: In the event of something that is TBD. 137 | """ 138 | endpoint = '%s.json' % '/'.join((self.API_BASE, endpoint)) 139 | return RequestPaginator(endpoint, params, output_type=output_type) 140 | -------------------------------------------------------------------------------- /daily_med/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | 6 | class DailyMedRemoteException(EnvironmentError): 7 | """ DailyMedRemoteException is raised to indicate an error from the API. 8 | """ 9 | -------------------------------------------------------------------------------- /daily_med/hl7.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | """ hl7.py Provides tools related to coercing HL7 formats. """ 6 | 7 | from datetime import datetime 8 | 9 | FMT_DATE = '%Y%m%d' 10 | FMT_TIME = '%H:%M' 11 | FMT_DATETIME = '%s%s' % (FMT_DATE, FMT_TIME) 12 | 13 | 14 | def str_to_time(date_str): 15 | """ str_to_time returns a date(time) object representing date_str. 16 | 17 | Returns: 18 | datetime: Object representing date string. 19 | """ 20 | if 'T' in date_str: 21 | return datetime.strptime(date_str, FMT_DATETIME) 22 | return datetime.strptime(date_str, FMT_DATE) 23 | -------------------------------------------------------------------------------- /daily_med/models/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from .spl import SPL 6 | 7 | __all__ = [ 8 | 'SPL', 9 | ] 10 | -------------------------------------------------------------------------------- /daily_med/models/spl.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import properties 6 | 7 | from .spl_document import POCP_MT050100UV_Document 8 | 9 | 10 | class SPL(properties.HasProperties): 11 | """ SPL provides Structured Product Label meta + document. """ 12 | 13 | set_id = properties.String( 14 | 'Set ID', 15 | ) 16 | title = properties.String( 17 | 'Title', 18 | ) 19 | spl_version = properties.String( 20 | 'Version', 21 | ) 22 | published_date = properties.DateTime( 23 | 'Published Date', 24 | ) 25 | document = properties.Instance( 26 | 'Structured Product Label Document', 27 | POCP_MT050100UV_Document, 28 | required=False, 29 | ) 30 | -------------------------------------------------------------------------------- /daily_med/request_paginator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import requests 6 | 7 | 8 | class RequestPaginator(object): 9 | """ RequestPaginator provides an iterator based upon an initial request. 10 | """ 11 | 12 | PAGE_SIZE = 'pagesize' 13 | PAGE_NUM = 'page' 14 | PAGE_TOTAL = 'total_pages' 15 | PAGE_CURRENT = 'current_page' 16 | PAGE_DATA = 'data' 17 | PAGE_META = 'metadata' 18 | 19 | SSL_VERIFY = True 20 | 21 | def __init__(self, endpoint, params=None, page_size=25, page_start=1, 22 | output_type=dict, 23 | ): 24 | """ It initializes the RequestPaginator object. 25 | 26 | Args: 27 | endpoint (str): URI endpoint to call. 28 | params (dict|bytes): Data to be sent in the query string 29 | for the Request. 30 | page_size (int): Size of pages to iterate. 31 | page_start (int): Page number to start on. 32 | output_type (type): Class type to output. Object will be 33 | instantiated using the current row before output. 34 | """ 35 | self.endpoint = endpoint 36 | self.params = params 37 | self.page_size = page_size 38 | self.page_start = page_start 39 | self.session = requests.Session() 40 | self.output_type = output_type 41 | 42 | def __iter__(self, page_num=None): 43 | """ It provides an iterator for the remote request. 44 | 45 | The result is returned as an instantiated `self.output_type`. 46 | """ 47 | 48 | params = self.params.copy() 49 | page_num = page_num or self.page_start 50 | params.update({ 51 | self.PAGE_SIZE: self.page_size, 52 | self.PAGE_NUM: page_num, 53 | }) 54 | result = self.call(params) 55 | meta = result[self.PAGE_META] 56 | data = result[self.PAGE_DATA] 57 | for row in data: 58 | yield self.output_type(**row) 59 | if meta[self.PAGE_CURRENT] != meta[self.PAGE_TOTAL]: 60 | for inner_row in self.__iter__(page_num + 1): 61 | yield inner_row 62 | else: 63 | raise StopIteration() 64 | 65 | def call(self, params): 66 | """ It calls the remote endpoint and returns the JSON decoded result. 67 | """ 68 | response = self.session.get( 69 | url=self.endpoint, 70 | params=params, 71 | verify=self.SSL_VERIFY, 72 | ) 73 | return response.json() 74 | -------------------------------------------------------------------------------- /daily_med/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | -------------------------------------------------------------------------------- /daily_med/tests/spl_doc_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | RENESE<sup>®</sup> 7 | <br/> 8 | <br/>(polythiazide)<br/> 9 | <br/>TABLETS<br/> 10 | <br/>for Oral Administration 11 | 12 | 13 | 14 | 15 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | Renese 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | polythiazide 46 | 47 | 48 | 49 | polythiazide 50 | 51 | 52 | 53 | 54 | 55 | 56 | polythiazide 57 | 58 | 59 | 60 | 61 | dibasic calcium phosphate 62 | 63 | 64 | 65 | 66 | lactose 67 | 68 | 69 | 70 | 71 | magnesium stearate 72 | 73 | 74 | 75 | 76 | polyethylene glycol 77 | 78 | 79 | 80 | 81 | sodium lauryl sulfate 82 | 83 | 84 | 85 | 86 | starch 87 | 88 | 89 | 90 | 91 | vanillin 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | White 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | Round 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | Pfizer;375 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | Renese 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | polythiazide 180 | 181 | 182 | 183 | polythiazide 184 | 185 | 186 | 187 | 188 | 189 | 190 | polythiazide 191 | 192 | 193 | 194 | 195 | dibasic calcium phosphate 196 | 197 | 198 | 199 | 200 | lactose 201 | 202 | 203 | 204 | 205 | magnesium stearate 206 | 207 | 208 | 209 | 210 | polyethylene glycol 211 | 212 | 213 | 214 | 215 | sodium lauryl sulfate 216 | 217 | 218 | 219 | 220 | starch 221 | 222 | 223 | 224 | 225 | vanillin 226 | 227 | 228 | 229 | 230 | yellow 6 231 | 232 | 233 | 234 | 235 | yellow 10 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | Yellow 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | Round 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | Pfizer;376 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | Renese 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | polythiazide 324 | 325 | 326 | 327 | polythiazide 328 | 329 | 330 | 331 | 332 | 333 | 334 | polythiazide 335 | 336 | 337 | 338 | 339 | dibasic calcium phosphate 340 | 341 | 342 | 343 | 344 | lactose 345 | 346 | 347 | 348 | 349 | magnesium stearate 350 | 351 | 352 | 353 | 354 | polyethylene glycol 355 | 356 | 357 | 358 | 359 | sodium lauryl sulfate 360 | 361 | 362 | 363 | 364 | starch 365 | 366 | 367 | 368 | 369 | vanillin 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | White 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | Round 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | Pfizer;377 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 |
441 |
442 | 443 |
444 | 445 | 446 | DESCRIPTION 447 | 448 | Renese® is designated generically as polythiazide, and chemically as 2H-1,2,4-Benzothiadiazine-7-sulfonamide, 6-chloro-3,4-dihydro-2-methyl-3-[[(2,2,2-trifluoroethyl)thio]methyl]-, 1,1-dioxide. It is a white crystalline substance, insoluble in water but readily soluble in alkaline solution. 449 | Inert Ingredients: dibasic calcium phosphate; lactose; magnesium stearate; polyethylene glycol; sodium lauryl sulfate; starch; vanillin. The 2 mg tablets also contain: Yellow 6; Yellow 10. 450 | 451 | 452 |
453 |
454 | 455 |
456 | 457 | 458 | ACTION 459 | 460 | The mechanism of action results in an interference with the renal tubular mechanism of electrolyte reabsorption. At maximal therapeutic dosage all thiazides are approximately equal in their diuretic potency. The mechanism whereby thiazides function in the control of hypertension is unknown. 461 | 462 | 463 |
464 |
465 | 466 |
467 | 468 | 469 | INDICATIONS 470 | 471 | Renese is indicated as adjunctive therapy in edema associated with congestive heart failure, hepatic cirrhosis, and corticosteroid and estrogen therapy. 472 | Renese has also been found useful in edema due to various forms of renal dysfunction as: Nephrotic syndrome; Acute glomerulonephritis; and Chronic renal failure. 473 | Renese is indicated in the management of hypertension either as the sole therapeutic agent or to enhance the effectiveness of other antihypertensive drugs in the more severe forms of hypertension. 474 | 475 | 476 | 477 |
478 | 479 | 480 | Usage in Pregnancy 481 | 482 | The routine use of diuretics in an otherwise healthy woman is inappropriate and exposes mother and fetus to unnecessary hazard. Diuretics do not prevent development of toxemia of pregnancy, and there is no satisfactory evidence that they are useful in the treatment of developed toxemia. 483 | Edema during pregnancy may arise from pathological causes or from the physiologic and mechanical consequences of pregnancy. Thiazides are indicated in pregnancy when edema is due to pathologic causes, just as they are in the absence of pregnancy (however, see Warnings, below). Dependent edema in pregnancy, resulting from restriction of venous return by the expanded uterus, is properly treated through elevation of the lower extremities and use of support hose; use of diuretics to lower intravascular volume in this case is illogical and unnecessary. There is hypervolemia during normal pregnancy which is harmful to neither the fetus nor the mother (in the absence of cardiovascular disease), but which is associated with edema, including generalized edema, in the majority of pregnant women. If this edema produces discomfort, increased recumbency will often provide relief. In rare instances, this edema may cause extreme discomfort which is not relieved by rest. In these cases, a short course of diuretics may provide relief and may be appropriate. 484 | 485 | 486 |
487 |
488 |
489 |
490 | 491 |
492 | 493 | 494 | CONTRAINDICATIONS 495 | 496 | Anuria. Hypersensitivity to this or other sulfonamide derived drugs. 497 | 498 | 499 |
500 |
501 | 502 |
503 | 504 | 505 | WARNINGS 506 | 507 | Thiazides should be used with caution in severe renal disease. In patients with renal disease, thiazides may precipitate azotemia. Cumulative effects of the drug may develop in patients with impaired renal function. 508 | Thiazides should be used with caution in patients with impaired hepatic function or progressive liver disease, since minor alterations of fluid and electrolyte balance may precipitate hepatic coma. 509 | Thiazides may add to or potentiate the action of other antihypertensive drugs. Potentiation occurs with ganglionic or peripheral adrenergic blocking drugs. 510 | Sensitivity reactions may occur in patients with a history of allergy or bronchial asthma. 511 | The possibility of exacerbation or activation of systemic lupus erythematosus has been reported. 512 | 513 | 514 | 515 |
516 | 517 | 518 | Usage in Pregnancy 519 | 520 | Thiazides cross the placental barrier and appear in cord blood. The use of thiazides in pregnant women requires that the anticipated benefit be weighed against possible hazards to the fetus. These hazards include fetal or neonatal jaundice, thrombocytopenia, and possibly other adverse reactions which have occurred in the adult. 521 | 522 | 523 |
524 |
525 | 526 |
527 | 528 | 529 | Nursing Mothers 530 | 531 | Thiazides appear in breast milk. If use of the drug is deemed essential, the patient should stop nursing. 532 | 533 | 534 |
535 |
536 |
537 |
538 | 539 |
540 | 541 | 542 | PRECAUTIONS 543 | 544 | Periodic determination of serum electrolytes to detect possible electrolyte imbalance should be performed at appropriate intervals. 545 | All patients receiving thiazide therapy should be observed for clinical signs of fluid or electrolyte imbalance; namely, hyponatremia, hypochloremic alkalosis, and hypokalemia. Serum and urine electrolyte determinations are particularly important when the patient is vomiting excessively or receiving parenteral fluids. Medication such as digitalis may also influence serum electrolytes. Warning signs, irrespective of cause, are: dryness of mouth, thirst, weakness, lethargy, drowsiness, restlessness, muscle pains or cramps, muscular fatigue, hypotension, oliguria, tachycardia, and gastrointestinal disturbances such as nausea and vomiting. 546 | Hypokalemia may develop with thiazides as with any other potent diuretic, especially with brisk diuresis, when severe cirrhosis is present, or during concomitant use of corticosteroids or ACTH. 547 | Interference with adequate oral electrolyte intake will also contribute to hypokalemia. Digitalis therapy may exaggerate metabolic effects of hypokalemia especially with reference to myocardial activity. 548 | Any chloride deficit is generally mild and usually does not require specific treatment except under extraordinary circumstances (as in liver disease or renal disease). Dilutional hyponatremia may occur in edematous patients in hot weather; appropriate therapy is water restriction, rather than administration of salt except in rare instances when the hyponatremia is life threatening. In actual salt depletion, appropriate replacement is the therapy of choice. 549 | Hyperuricemia may occur or frank gout may be precipitated in certain patients receiving thiazide therapy. 550 | Insulin requirements in diabetic patients may be increased, decreased, or unchanged. Latent diabetes mellitus may become manifest during thiazide administration. 551 | Thiazide drugs may increase the responsiveness to tubocurarine. 552 | The antihypertensive effects of the drug may be enhanced in the postsympathectomy patient. 553 | Thiazides may decrease arterial responsiveness to norepinephrine. This diminution is not sufficient to preclude effectiveness of the pressor agent for therapeutic use. 554 | If progressive renal impairment becomes evident, as indicated by a rising nonprotein nitrogen or blood urea nitrogen, a careful reappraisal of therapy is necessary with consideration given to withholding or discontinuing diuretic therapy. 555 | Thiazides may decrease serum PBI levels without signs of thyroid disturbance. 556 | 557 | 558 | 559 |
560 | 561 | 562 | Pediatric Use 563 | 564 | Safety and effectiveness in pediatric patients have not been established. 565 | 566 | 567 |
568 |
569 |
570 |
571 | 572 |
573 | 574 | 575 | ADVERSE REACTIONS 576 | 577 | 578 | 579 | 580 | 581 |
582 | 583 | 584 | A. GASTROINTESTINAL SYSTEM REACTIONS 585 | 586 | 587 | anorexia 588 | gastric irritation 589 | nausea 590 | vomiting 591 | cramping 592 | diarrhea 593 | constipation 594 | jaundice (intrahepatic cholestatic jaundice) 595 | pancreatitis 596 | 597 | 598 | 599 | 600 |
601 |
602 | 603 |
604 | 605 | 606 | B. CENTRAL NERVOUS SYSTEM REACTIONS 607 | 608 | 609 | dizziness 610 | vertigo 611 | paresthesias 612 | headache 613 | xanthopsia 614 | 615 | 616 | 617 | 618 |
619 |
620 | 621 |
622 | 623 | 624 | C. HEMATOLOGIC REACTIONS 625 | 626 | 627 | leukopenia 628 | agranulocytosis 629 | thrombocytopenia 630 | aplastic anemia 631 | 632 | 633 | 634 | 635 |
636 |
637 | 638 |
639 | 640 | 641 | D. DERMATOLOGIC—HYPERSENSITIVITY REACTIONS 642 | 643 | 644 | purpura 645 | photosensitivity 646 | rash 647 | urticaria 648 | necrotizing angiitis
649 |
(vasculitis)
650 |
(cutaneous vasculitis)
651 |
652 | 653 |
654 | 655 |
656 |
657 | 658 |
659 | 660 | 661 | E. CARDIOVASCULAR REACTION 662 | 663 | Orthostatic hypotension may occur and may be aggravated by alcohol, barbiturates or narcotics. 664 | 665 | 666 |
667 |
668 | 669 |
670 | 671 | 672 | F. OTHER 673 | 674 | 675 | hyperglycemia 676 | glycosuria 677 | hyperuricemia 678 | muscle spasm 679 | weakness 680 | restlessness 681 | 682 | Whenever adverse reactions are moderate or severe, thiazide dosage should be reduced or therapy withdrawn. 683 | 684 | 685 |
686 |
687 |
688 |
689 | 690 |
691 | 692 | 693 | DOSAGE AND ADMINISTRATION 694 | 695 | Therapy should be individualized according to patient response. This therapy should be titrated to gain maximal therapeutic response as well as the minimal dose possible to maintain that therapeutic response. The usual dosage of Renese tablets for diuretic therapy is 1 to 4 mg daily, and for antihypertensive therapy is 2 to 4 mg daily. 696 | 697 | 698 |
699 |
700 | 701 |
702 | 703 | 704 | HOW SUPPLIED 705 | 706 | RENESE (polythiazide) Tablets are available as: 707 | 1 mg white, scored tablets in bottles of 100 (NDC 0069-3750-66). 708 | 2 mg yellow, scored tablets in bottles of 100 (NDC 0069-3760-66). 709 | 4 mg white, scored tablets in bottles of 100 (NDC 0069-3770-66). 710 | 711 | 712 |
713 |
714 | 715 |
716 | 717 | 718 | 719 | <text> 720 | <paragraph> 721 | <content styleCode="bold">Rx Only</content> 722 | </paragraph> 723 | <renderMultiMedia referencedObject="MM1"/> 724 | <paragraph>69-1116-00-6</paragraph> 725 | <paragraph>April 1997</paragraph> 726 | </text> 727 | <effectiveTime value="20051214"/> 728 | <component> 729 | <observationMedia ID="MM1"> 730 | <value mediaType="image/jpeg" xsi:type="ED"> 731 | <reference value="renese-image01.jpg"/> 732 | </value> 733 | </observationMedia> 734 | </component> 735 | </section> 736 | </component> 737 | </structuredBody> 738 | </component> 739 | </document> 740 | -------------------------------------------------------------------------------- /daily_med/tests/test_daily_med.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import mock 6 | import os 7 | import unittest 8 | 9 | from properties import HasProperties as BaseModel 10 | 11 | from ..daily_med import DailyMed 12 | from ..models import SPL 13 | 14 | 15 | mock_path = 'daily_med.daily_med' 16 | 17 | 18 | class TestDailyMed(unittest.TestCase): 19 | 20 | def setUp(self): 21 | self.dm = DailyMed() 22 | 23 | def get_sample_xml(self): 24 | xml_path = os.path.join( 25 | os.path.abspath(os.path.dirname(__file__)), 'spl_doc_1.xml', 26 | ) 27 | with open(xml_path, 'r') as fh: 28 | return fh.read() 29 | 30 | @mock.patch('%s.RequestPaginator' % mock_path) 31 | def test_call(self, paginator): 32 | """ It should create a RequestPaginator w/ the proper args. """ 33 | self.dm.API_BASE = 'base' 34 | params = {'params': 1} 35 | self.dm.call('endpoint', BaseModel, params) 36 | paginator.assert_called_once_with( 37 | 'base/endpoint.json', params, output_type=BaseModel, 38 | ) 39 | 40 | @mock.patch('%s.RequestPaginator' % mock_path) 41 | def test_call_return(self, paginator): 42 | """ It should return the paginator. """ 43 | res = self.dm.call('endpoint', BaseModel) 44 | self.assertEqual(res, paginator()) 45 | 46 | @mock.patch('%s.requests' % mock_path) 47 | def test_get_spl_request(self, requests): 48 | """ It should request the proper URI. """ 49 | text_mock = mock.MagicMock() 50 | text_mock.text = self.get_sample_xml() 51 | requests.get.return_value = text_mock 52 | self.dm.API_BASE = 'base' 53 | self.dm.get_spl('set_id') 54 | requests.get.assert_called_once_with( 55 | url='base/spls/set_id.xml', 56 | ) 57 | 58 | @mock.patch('%s.requests' % mock_path) 59 | def test_get_spl_return(self, requests): 60 | """ It should return an SPLDocument """ 61 | text_mock = mock.MagicMock() 62 | text_mock.text = self.get_sample_xml() 63 | requests.get.return_value = text_mock 64 | res = self.dm.get_spl('set_id') 65 | self.assertIsInstance(res, SPL) 66 | 67 | def test_get_spls(self): 68 | """ It should make the proper call and return it. """ 69 | with mock.patch.object(self.dm, 'call') as call: 70 | kwargs = {'kwargs': 'sZdsdfd'} 71 | res = self.dm.get_spls(**kwargs) 72 | call.assert_called_once_with( 73 | 'spls', SPL, kwargs, 74 | ) 75 | self.assertEqual(res, call()) 76 | -------------------------------------------------------------------------------- /daily_med/tests/test_request_paginator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import mock 6 | import unittest 7 | 8 | from ..request_paginator import RequestPaginator 9 | 10 | 11 | class TestRequestPaginator(unittest.TestCase): 12 | 13 | def setUp(self): 14 | self.vals = { 15 | 'endpoint': 'endpoint', 16 | 'params': {'param': 1}, 17 | 'page_size': 30, 18 | 'page_start': 3, 19 | 'output_type': dict, 20 | } 21 | self.test_responses = [ 22 | { 23 | 'metadata': { 24 | 'current_page': 1, 25 | 'total_pages': 3, 26 | }, 27 | 'data': [{ 28 | 'page': 1, 29 | }], 30 | }, 31 | { 32 | 'metadata': { 33 | 'current_page': 2, 34 | 'total_pages': 3, 35 | }, 36 | 'data': [{ 37 | 'page': 2, 38 | }], 39 | }, 40 | { 41 | 'metadata': { 42 | 'current_page': 3, 43 | 'total_pages': 3, 44 | }, 45 | 'data': [{ 46 | 'page': 3, 47 | }], 48 | }, 49 | ] 50 | self.paginator = RequestPaginator(**self.vals) 51 | 52 | def test_init_attrs(self): 53 | """ It should correctly assign instance attributes. """ 54 | attrs = { 55 | attr: getattr(self.paginator, attr) for attr in self.vals.keys() 56 | } 57 | self.assertDictEqual(attrs, self.vals) 58 | 59 | @mock.patch('daily_med.request_paginator.requests') 60 | def test_init_session(self, requests): 61 | """ It should initialize a requests session. """ 62 | paginator = RequestPaginator(**self.vals) 63 | self.assertEqual(paginator.session, requests.Session()) 64 | 65 | def test_call_gets(self): 66 | """ It should call the session with proper args. """ 67 | params = {'param_test': 23234} 68 | with mock.patch.object(self.paginator, 'session') as session: 69 | self.paginator.call(params) 70 | session.get.assert_called_once_with( 71 | url=self.vals['endpoint'], 72 | params=params, 73 | verify=True, 74 | ) 75 | 76 | def test_call_return(self): 77 | """ It should return the json decoded response. """ 78 | with mock.patch.object(self.paginator, 'session') as session: 79 | res = self.paginator.call({}) 80 | self.assertEqual(res, session.get().json()) 81 | 82 | def test_iter(self): 83 | """ It should iterate until the end & yield data. """ 84 | with mock.patch.object(self.paginator, 'call') as call: 85 | call.side_effect = self.test_responses 86 | res = list(self.paginator) 87 | expect = [{'page': 1}, {'page': 2}, {'page': 3}] 88 | self.assertEqual(res, expect) 89 | -------------------------------------------------------------------------------- /daily_med/tests/test_spl_document.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2017-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | import os 6 | import unittest 7 | 8 | from ..models.spl_document import parse, parseString, get_all_values 9 | 10 | 11 | class TestSPLDocument(unittest.TestCase): 12 | 13 | TEST_FILES = [ 14 | 'spl_doc_1.xml', 15 | 'spl_doc_1.xml', 16 | ] 17 | TEST_DIR = os.path.abspath(os.path.dirname(__file__)) 18 | 19 | def _parse_file(self, test_file, as_string=True): 20 | test_file = os.path.join(self.TEST_DIR, test_file) 21 | if not as_string: 22 | return parse(test_file, True) 23 | with open(test_file, 'r') as fh: 24 | return parseString(fh.read(), True) 25 | 26 | def test_parse(self): 27 | """ It should parse the sample files without errors. """ 28 | for test_file in self.TEST_FILES: 29 | spl_doc = self._parse_file(test_file, as_string=False) 30 | self.assertTrue(spl_doc.id.root) 31 | self.assertTrue(spl_doc.title) 32 | self.assertTrue(spl_doc.code.code) 33 | 34 | def test_parse_string(self): 35 | """ It should parse the sample files as string without errors. """ 36 | for test_file in self.TEST_FILES: 37 | spl_doc = self._parse_file(test_file, as_string=True) 38 | self.assertTrue(spl_doc.id.root) 39 | self.assertTrue(spl_doc.title) 40 | self.assertTrue(spl_doc.code.code) 41 | 42 | def test_get_all_values(self): 43 | """ It should return a list of the node values. """ 44 | spl_doc = self._parse_file(self.TEST_FILES[0]) 45 | expect = ['RENESE', '\n\t\t', '\n\t\t', '(polythiazide)', 46 | '\n\t\t', 'TABLETS', '\n\t\t', 'for Oral Administration'] 47 | self.assertEqual( 48 | get_all_values(spl_doc.title.content_), expect, 49 | ) 50 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | lxml 2 | requests 3 | properties 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Copyright 2016-TODAY LasLabs Inc. 3 | # License MIT (https://opensource.org/licenses/MIT). 4 | 5 | from setuptools import Command, setup 6 | from setuptools import find_packages 7 | from unittest import TestLoader, TextTestRunner 8 | 9 | from os import environ, path 10 | 11 | 12 | PROJECT = 'python-daily-med' 13 | SHORT_DESC = 'Interact with US NLM Daily Med API using Python.' 14 | README_FILE = 'README.rst' 15 | 16 | CLASSIFIERS = [ 17 | 'Development Status :: 4 - Beta', 18 | 'Environment :: Console', 19 | 'Intended Audience :: Developers', 20 | 'License :: OSI Approved :: MIT License', 21 | 'Programming Language :: Python', 22 | 'Topic :: Software Development :: Libraries :: Python Modules', 23 | ] 24 | 25 | version = environ.get('RELEASE') or environ.get('VERSION') or '0.0.0' 26 | 27 | if environ.get('TRAVIS_BUILD_NUMBER'): 28 | version += 'b%s' % environ.get('TRAVIS_BUILD_NUMBER') 29 | 30 | 31 | setup_vals = { 32 | 'name': PROJECT, 33 | 'author': 'LasLabs Inc.', 34 | 'author_email': 'support@laslabs.com', 35 | 'description': SHORT_DESC, 36 | 'url': 'https://laslabs.github.io/%s' % PROJECT, 37 | 'download_url': 'https://github.com/LasLabs/%s' % PROJECT, 38 | 'license': 'MIT', 39 | 'classifiers': CLASSIFIERS, 40 | 'version': version, 41 | } 42 | 43 | 44 | if path.exists(README_FILE): 45 | with open(README_FILE) as fh: 46 | setup_vals['long_description'] = fh.read() 47 | 48 | 49 | install_requires = [] 50 | if path.exists('requirements.txt'): 51 | with open('requirements.txt') as fh: 52 | install_requires = fh.read().splitlines() 53 | 54 | 55 | class FailTestException(Exception): 56 | """ It provides a failing build """ 57 | pass 58 | 59 | 60 | class Tests(Command): 61 | ''' Run test & coverage, save reports as XML ''' 62 | 63 | user_options = [] # < For Command API compatibility 64 | 65 | def initialize_options(self, ): 66 | pass 67 | 68 | def finalize_options(self, ): 69 | pass 70 | 71 | def run(self, ): 72 | loader = TestLoader() 73 | tests = loader.discover('.', 'test_*.py') 74 | t = TextTestRunner(verbosity=1) 75 | res = t.run(tests) 76 | if not res.wasSuccessful(): 77 | raise FailTestException() 78 | 79 | 80 | if __name__ == "__main__": 81 | setup( 82 | packages=find_packages(exclude=('tests')), 83 | cmdclass={'test': Tests}, 84 | tests_require=[ 85 | 'mock', 86 | ], 87 | install_requires=install_requires, 88 | **setup_vals 89 | ) 90 | --------------------------------------------------------------------------------