forked from HHS/pillbox_docs
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpillbox.py
211 lines (169 loc) · 5.53 KB
/
pillbox.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
"""
Python wrapper for NIH's Pillbox API.
Parameters:
key - Security key required for API access
shape - FDA SPL code for shape of pill (see definition below)
color - FDA SPL code for color of pill (see definition below)
score - Numeric value for FDA score value for pill
size - Numeric value (whole number) for size in mm of pill. Search +/- 2 mm
ingredient - Name of active ingredient. Currently only one ingredient may be searched in each call. There is currently no spellchecker.
prodcode - FDA 9-digit Product Code in dashed format
has_image - If 0, no image. If 1, image exists.
"""
import urllib, urllib2
import xml.etree.cElementTree as etree
from decimal import Decimal
BASE_URL = "http://pillbox.nlm.nih.gov/PHP/pillboxAPIService.php?"
SHAPES = {
'BULLET': 'C48335',
'CAPSULE': 'C48336',
'CLOVER': 'C48337',
'DIAMOND': 'C48338',
'DOUBLE_CIRCLE': 'C48339',
'FREEFORM': 'C48340',
'GEAR': 'C48341',
'HEPTAGON': 'C48342',
'HEXAGON': 'C48343',
'OCTAGON': 'C48344',
'OVAL': 'C48345',
'PENTAGON': 'C48346',
'RECTANGLE': 'C48347',
'ROUND': 'C48348',
'SEMI_CIRCLE': 'C48349',
'SQUARE': 'C48350',
'TEAR': 'C48351',
'TRAPEZOID': 'C48352',
'TRIANGLE': 'C48353',
}
SHAPE_CODES = {
'C48335': 'BULLET',
'C48336': 'CAPSULE',
'C48337': 'CLOVER',
'C48338': 'DIAMOND',
'C48339': 'DOUBLE_CIRCLE',
'C48340': 'FREEFORM',
'C48341': 'GEAR',
'C48342': 'HEPTAGON',
'C48343': 'HEXAGON',
'C48344': 'OCTAGON',
'C48345': 'OVAL',
'C48346': 'PENTAGON',
'C48347': 'RECTANGLE',
'C48348': 'ROUND',
'C48349': 'SEMI_CIRCLE',
'C48350': 'SQUARE',
'C48351': 'TEAR',
'C48352': 'TRAPEZOID',
'C48353': 'TRIANGLE'
}
COLORS = {
'BLACK': 'C48323',
'BLUE': 'C48333',
'BROWN': 'C48332',
'GRAY': 'C48324',
'GREEN': 'C48329',
'ORANGE': 'C48331',
'PINK': 'C48328',
'PURPLE': 'C48327',
'RED': 'C48326',
'TURQUOISE': 'C48334',
'WHITE': 'C48325',
'YELLOW': 'C48330',
}
COLOR_CODES = {
'C48323': 'BLACK',
'C48324': 'GRAY',
'C48325': 'WHITE',
'C48326': 'RED',
'C48327': 'PURPLE',
'C48328': 'PINK',
'C48329': 'GREEN',
'C48330': 'YELLOW',
'C48331': 'ORANGE',
'C48332': 'BROWN',
'C48333': 'BLUE',
'C48334': 'TURQUOISE'
}
IMAGE_SIZES = {
'super_small': 'ss', # 91 x 65 png
'small': 'sm', # 161 x 115 jpg
'medium': 'md', # 448 x 320 jpg
'large': 'lg' # 840 x 600 jpg
}
class PillboxError(Exception):
pass
class Pill(object):
"Storage class for pills returned by Pillbox"
def __init__(self, d):
self.__dict__ = d
# properties
color = property(lambda self: COLOR_CODES[self.SPLCOLOR])
description = property(lambda self: self.RXSTRING)
has_image = property(lambda self: bool(self.HAS_IMAGE))
imprint = property(lambda self: self.SPLIMPRINT)
ingredients = property(lambda self: self.INGREDIENTS.split('; '))
product_code = property(lambda self: self.PRODUCT_CODE)
rxcui = property(lambda self: self.RXCUI)
rxtty = property(lambda self: self.RXTTY)
score = property(lambda self: int(self.SPLSCORE))
set_id = property(lambda self: self.SETID)
shape = property(lambda self: SHAPE_CODES[self.SPLSHAPE])
size = property(lambda self: Decimal(self.SPLSIZE))
spl_id = property(lambda self: self.SPL_ID)
def image(self, size='small'):
if not self.image_id:
return ""
IMAGE_URL = "http://pillbox.nlm.nih.gov/assets/%(size)s/%(image_id)s%(size_short)s.%(ext)s"
if size == "super_small":
ext = "png"
else:
ext = "jpg"
return IMAGE_URL % {
'size': size,
'image_id': self.image_id,
'size_short': IMAGE_SIZES[size],
'ext': ext
}
def __str__(self):
return self.description
def __repr__(self):
return "<Pill: %s>" % self.__str__()
class Pillbox(object):
"Python client for NIH's Pillbox"
def __init__(self, api_key):
self.api_key = api_key
def _apicall(self, **params):
response = urllib2.urlopen(BASE_URL + urllib.urlencode(params)).read()
if response == "No records found":
return response
try:
pills = etree.fromstring(response)
except Exception, e:
raise PillboxError(e)
return list(self._handle_pills(pills))
def _handle_pills(self, pills):
for pill in pills.findall('pill'):
d = dict([
(p.tag, p.text) for p in pill.getchildren()
])
pill = Pill(d)
yield pill
def search(self, **params):
params['key'] = self.api_key
color = None
if 'color' in params:
if params['color'] in COLORS.values():
color = params['color'] # if you want to use the color code, that's cool
else:
color = COLORS[params['color'].upper()]
if color:
params['color'] = color
shape = None
if 'shape' in params:
if params['shape'] in SHAPES.values():
shape = params['shape']
else:
shape = SHAPES[params['shape'].upper()]
if shape:
params['shape'] = shape
return self._apicall(**params)