Skip to content

Commit 1c1fc92

Browse files
committed
Cleanup.
1 parent 27bd7c0 commit 1c1fc92

File tree

2 files changed

+51
-25
lines changed

2 files changed

+51
-25
lines changed

api_scraper.py

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import re
55
import inflect
66

7-
REST_MAP = {'GET': 'get', 'PUT': 'update', 'POST': 'create', 'DELETE': 'delete'}
8-
7+
# Map HTTP method names to REST API names
8+
REST_MAP = {'GET': 'get', 'PUT': 'update',
9+
'POST': 'create', 'DELETE': 'delete'}
910

11+
# For plural->singular conversion
1012
p = inflect.engine()
1113

1214

@@ -15,6 +17,7 @@ def underscorize(name):
1517
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
1618

1719

20+
# Write python indented lines
1821
def pout(file, indent, text):
1922
file.write(' ' * indent)
2023
file.write(text)
@@ -45,16 +48,20 @@ def write_model_file(model):
4548

4649

4750
def write_get_or_update(file, model, output_model, method, query):
51+
"""Output code to query and instantiate models based on the result."""
4852
if method['is_array']:
4953
pout(file, 2, 'items = ' + query)
5054
else:
5155
pout(file, 2, 'data = ' + query)
5256

5357
if method['type'] == 'class' or model['name'] != output_model:
58+
# If it's a class method or the output model doesn't match the parent
59+
# class, then we need to import the right class.
5460
if model['name'] != output_model:
5561
pkg = underscorize(output_model)
5662
pout(file, 2, "from .{0} import {1}\n".format(pkg, output_model))
5763

64+
# Instantiate models with result JSON
5865
if method['is_array']:
5966
pout(file, 2, "result = []\n")
6067
pout(file, 2, "if items is not None:\n")
@@ -64,10 +71,11 @@ def write_get_or_update(file, model, output_model, method, query):
6471
indent = 2
6572

6673
if method['type'] == 'class':
67-
pout(file, indent, "model = {0}(session, data['id'])\n".format(output_model))
74+
construct_line = "model = {0}(session, data['id'])\n"
6875
else:
69-
pout(file, indent, "model = {0}(self._session, data['id'])\n".format(output_model))
76+
construct_line = "model = {0}(self._session, data['id'])\n"
7077

78+
pout(file, indent, construct_line.format(output_model))
7179
pout(file, indent, "model.data = data\n")
7280

7381
if method['is_array']:
@@ -84,26 +92,35 @@ def write_get_or_update(file, model, output_model, method, query):
8492

8593

8694
def extract_model_from_url(api_split):
95+
"""This method figures out the output model for a REST API method,"""
96+
# Get all the path elements that don't refer to IDs
8797
keys = [k for k in api_split if k and not k.startswith(':')]
98+
# The last one will be the type we want.
8899
last_key = keys[-1]
100+
# Some of them have a 'rel' path element...seems extraneous? not sure
89101
if last_key == 'rel':
90-
last_key = keys[-2] # why?
102+
last_key = keys[-2]
91103

104+
# Get a singular name, if it's plural
92105
last_key_singular = p.singular_noun(last_key) or last_key
106+
# Lowercase for matching to our list of models.
93107
last_key_singular = last_key_singular.lower()
108+
# Get all the model names
94109
model_names = list(extracted_models.keys())
110+
# Lowercase them for matching
95111
extracted_models_lower = [name.lower() for name in model_names]
96-
if 'people' in api_split: print('"' + last_key_singular + '"')
112+
# Our path element key does not seem to match any model we know about.
97113
if last_key_singular not in extracted_models_lower:
98-
if 'people' in api_split: print(last_key_singular)
99114
return None
100-
if 'people' in api_split: print('passed')
115+
# Return the actual model name.
101116
model_index = extracted_models_lower.index(last_key_singular.lower())
102117
return model_names[model_index]
103118

104119

105120
def write_method(file, model, method):
121+
"""Output the code for a REST API method."""
106122
if method['type'] == 'loopback':
123+
# The loopback method is a special case - refreshes the data we have.
107124
url = method['url'].replace(':id', '{0}')
108125
pout(file, 1, 'def refresh(self):\n')
109126
pout(file, 2, "api = \"{0}\".format(self._id)\n".format(url))
@@ -120,32 +137,34 @@ def write_method(file, model, method):
120137

121138
root_model = p.singular_noun(api_split[1]) or api_split[1]
122139
if root_model.lower() != model['name'].lower():
123-
print("Method {0} on {1} has a different root. Skipping...".format(method, model['name']))
140+
print("Method {0} on {1} has a different root. Skipping...".format(
141+
method, model['name']))
124142
return
125143

144+
# Gather all the foreign key stuff...
126145
fk_index = api_split.index(':fk') if ':fk' in api_split else None
127146
if fk_index is not None:
128147
fk_name = api_split[fk_index - 1]
129148
if fk_name == 'rel':
130149
fk_name = api_split[fk_index - 2] # Why?
131150
fk_name = underscorize(fk_name)
132151
fk_name_singular = p.singular_noun(fk_name) or fk_name
152+
# For the parameter list
153+
fk_line = (", {0}_id".format(fk_name_singular))
133154
else:
134155
fk_name = None
135156
fk_name_singular = None
157+
fk_line = ''
136158

137-
if not method['type'] == 'class':
138-
api = method['url'].replace(':id', '{0}').replace(':fk', '{1}')
139-
else:
159+
# Class methods don't have an :id.
160+
if method['type'] == 'class':
140161
api = method['url'].replace(':fk', '{0}')
141-
142-
if fk_name_singular is not None:
143-
fk_line = (", {0}_id".format(fk_name_singular))
144162
else:
145-
fk_line = ''
163+
api = method['url'].replace(':id', '{0}').replace(':fk', '{1}')
146164

147165
if method['type'] == 'class':
148-
decl = "def {0}(cls, session{1}, attribs=None):\n".format(method['name'], fk_line)
166+
decl = "def {0}(cls, session{1}, attribs=None):\n".format(
167+
method['name'], fk_line)
149168
pout(file, 1, "@classmethod\n")
150169
pout(file, 1, decl)
151170
pout(file, 2, 'if attribs is None:\n')
@@ -158,15 +177,18 @@ def write_method(file, model, method):
158177
pout(file, 2, "api = \"{0}\"{1}\n".format(api, format_line))
159178
code = "session.call_api(api, attribs, \'{0}\')\n\n"
160179
else:
161-
decl = "def {0}(self{1}, attribs=None):\n".format(method['name'], fk_line)
180+
decl = "def {0}(self{1}, attribs=None):\n".format(
181+
method['name'], fk_line)
162182
pout(file, 1, decl)
163183
pout(file, 2, 'if attribs is None:\n')
164184
pout(file, 3, 'attribs = {}\n')
165185

166186
if fk_name is not None:
167187
format_line = ".format(self._id, {0}_id)".format(fk_name_singular)
168-
else:
188+
elif '{0}' in api:
169189
format_line = '.format(self._id)'
190+
else:
191+
format_line = ''
170192
pout(file, 2, "api = \"{0}\"{1}\n".format(api, format_line))
171193
code = "self._session.call_api(api, attribs, \'{0}\')\n\n"
172194

@@ -231,7 +253,8 @@ def write_method(file, model, method):
231253
match = re.search(RE_CLASS_API_DECL, line)
232254

233255
if match is not None:
234-
method = {'name': match.group(1), 'type': 'class', 'is_array': False}
256+
method = {'name': match.group(1), 'type': 'class',
257+
'is_array': False}
235258
method['name'] = underscorize(method['name']).replace('__', '_')
236259
model['methods'][method['name']] = method
237260
state = 'api'
@@ -240,16 +263,19 @@ def write_method(file, model, method):
240263
match = re.search(RE_SUBMODEL_API_DECL, line)
241264

242265
if match is not None:
243-
method = {'name': match.group(1), 'type': 'subinstance', 'is_array': False}
244-
method['name'] = underscorize(method['name'].replace('::', '_')).replace('__', '_')
266+
method = {'name': match.group(1), 'type': 'subinstance',
267+
'is_array': False}
268+
method['name'] = underscorize(
269+
method['name'].replace('::', '_')).replace('__', '_')
245270
model['methods'][method['name']] = method
246271
state = 'api'
247272
continue
248273

249274
match = re.search(RE_MODEL_API_DECL, line)
250275

251276
if match is not None:
252-
method = {'name': match.group(1), 'type': 'instance', 'is_array': False}
277+
method = {'name': match.group(1), 'type': 'instance',
278+
'is_array': False}
253279
method['name'] = underscorize(method['name'])
254280
model['methods'][method['name']] = method
255281
state = 'api'
@@ -288,4 +314,4 @@ def write_method(file, model, method):
288314
continue
289315

290316
for model in sorted(extracted_models.keys()):
291-
write_model_file(extracted_models[model])
317+
write_model_file(extracted_models[model])

decora_wifi/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ def call_api(self, api, payload=None, method='get'):
3131
# Sanity check parameters first...
3232
if (method != 'get' and method != 'post' and
3333
method != 'put' and method != 'delete'):
34-
3534
msg = "Tried decora.call_api with bad method: {0}"
3635
raise ValueError(msg.format(method))
3736

@@ -40,6 +39,7 @@ def call_api(self, api, payload=None, method='get'):
4039

4140
uri = self.LEVITON_ROOT + api
4241

42+
# Payload is always JSON
4343
if payload is not None:
4444
payload_json = json.dumps(payload)
4545
else:

0 commit comments

Comments
 (0)