4
4
import re
5
5
import inflect
6
6
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' }
9
10
11
+ # For plural->singular conversion
10
12
p = inflect .engine ()
11
13
12
14
@@ -15,6 +17,7 @@ def underscorize(name):
15
17
return re .sub ('([a-z0-9])([A-Z])' , r'\1_\2' , s1 ).lower ()
16
18
17
19
20
+ # Write python indented lines
18
21
def pout (file , indent , text ):
19
22
file .write (' ' * indent )
20
23
file .write (text )
@@ -45,16 +48,20 @@ def write_model_file(model):
45
48
46
49
47
50
def write_get_or_update (file , model , output_model , method , query ):
51
+ """Output code to query and instantiate models based on the result."""
48
52
if method ['is_array' ]:
49
53
pout (file , 2 , 'items = ' + query )
50
54
else :
51
55
pout (file , 2 , 'data = ' + query )
52
56
53
57
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.
54
60
if model ['name' ] != output_model :
55
61
pkg = underscorize (output_model )
56
62
pout (file , 2 , "from .{0} import {1}\n " .format (pkg , output_model ))
57
63
64
+ # Instantiate models with result JSON
58
65
if method ['is_array' ]:
59
66
pout (file , 2 , "result = []\n " )
60
67
pout (file , 2 , "if items is not None:\n " )
@@ -64,10 +71,11 @@ def write_get_or_update(file, model, output_model, method, query):
64
71
indent = 2
65
72
66
73
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 "
68
75
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 "
70
77
78
+ pout (file , indent , construct_line .format (output_model ))
71
79
pout (file , indent , "model.data = data\n " )
72
80
73
81
if method ['is_array' ]:
@@ -84,26 +92,35 @@ def write_get_or_update(file, model, output_model, method, query):
84
92
85
93
86
94
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
87
97
keys = [k for k in api_split if k and not k .startswith (':' )]
98
+ # The last one will be the type we want.
88
99
last_key = keys [- 1 ]
100
+ # Some of them have a 'rel' path element...seems extraneous? not sure
89
101
if last_key == 'rel' :
90
- last_key = keys [- 2 ] # why?
102
+ last_key = keys [- 2 ]
91
103
104
+ # Get a singular name, if it's plural
92
105
last_key_singular = p .singular_noun (last_key ) or last_key
106
+ # Lowercase for matching to our list of models.
93
107
last_key_singular = last_key_singular .lower ()
108
+ # Get all the model names
94
109
model_names = list (extracted_models .keys ())
110
+ # Lowercase them for matching
95
111
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.
97
113
if last_key_singular not in extracted_models_lower :
98
- if 'people' in api_split : print (last_key_singular )
99
114
return None
100
- if 'people' in api_split : print ( 'passed' )
115
+ # Return the actual model name.
101
116
model_index = extracted_models_lower .index (last_key_singular .lower ())
102
117
return model_names [model_index ]
103
118
104
119
105
120
def write_method (file , model , method ):
121
+ """Output the code for a REST API method."""
106
122
if method ['type' ] == 'loopback' :
123
+ # The loopback method is a special case - refreshes the data we have.
107
124
url = method ['url' ].replace (':id' , '{0}' )
108
125
pout (file , 1 , 'def refresh(self):\n ' )
109
126
pout (file , 2 , "api = \" {0}\" .format(self._id)\n " .format (url ))
@@ -120,32 +137,34 @@ def write_method(file, model, method):
120
137
121
138
root_model = p .singular_noun (api_split [1 ]) or api_split [1 ]
122
139
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' ]))
124
142
return
125
143
144
+ # Gather all the foreign key stuff...
126
145
fk_index = api_split .index (':fk' ) if ':fk' in api_split else None
127
146
if fk_index is not None :
128
147
fk_name = api_split [fk_index - 1 ]
129
148
if fk_name == 'rel' :
130
149
fk_name = api_split [fk_index - 2 ] # Why?
131
150
fk_name = underscorize (fk_name )
132
151
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 ))
133
154
else :
134
155
fk_name = None
135
156
fk_name_singular = None
157
+ fk_line = ''
136
158
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' :
140
161
api = method ['url' ].replace (':fk' , '{0}' )
141
-
142
- if fk_name_singular is not None :
143
- fk_line = (", {0}_id" .format (fk_name_singular ))
144
162
else :
145
- fk_line = ''
163
+ api = method [ 'url' ]. replace ( ':id' , '{0}' ). replace ( ':fk' , '{1}' )
146
164
147
165
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 )
149
168
pout (file , 1 , "@classmethod\n " )
150
169
pout (file , 1 , decl )
151
170
pout (file , 2 , 'if attribs is None:\n ' )
@@ -158,15 +177,18 @@ def write_method(file, model, method):
158
177
pout (file , 2 , "api = \" {0}\" {1}\n " .format (api , format_line ))
159
178
code = "session.call_api(api, attribs, \' {0}\' )\n \n "
160
179
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 )
162
182
pout (file , 1 , decl )
163
183
pout (file , 2 , 'if attribs is None:\n ' )
164
184
pout (file , 3 , 'attribs = {}\n ' )
165
185
166
186
if fk_name is not None :
167
187
format_line = ".format(self._id, {0}_id)" .format (fk_name_singular )
168
- else :
188
+ elif '{0}' in api :
169
189
format_line = '.format(self._id)'
190
+ else :
191
+ format_line = ''
170
192
pout (file , 2 , "api = \" {0}\" {1}\n " .format (api , format_line ))
171
193
code = "self._session.call_api(api, attribs, \' {0}\' )\n \n "
172
194
@@ -231,7 +253,8 @@ def write_method(file, model, method):
231
253
match = re .search (RE_CLASS_API_DECL , line )
232
254
233
255
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 }
235
258
method ['name' ] = underscorize (method ['name' ]).replace ('__' , '_' )
236
259
model ['methods' ][method ['name' ]] = method
237
260
state = 'api'
@@ -240,16 +263,19 @@ def write_method(file, model, method):
240
263
match = re .search (RE_SUBMODEL_API_DECL , line )
241
264
242
265
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 ('__' , '_' )
245
270
model ['methods' ][method ['name' ]] = method
246
271
state = 'api'
247
272
continue
248
273
249
274
match = re .search (RE_MODEL_API_DECL , line )
250
275
251
276
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 }
253
279
method ['name' ] = underscorize (method ['name' ])
254
280
model ['methods' ][method ['name' ]] = method
255
281
state = 'api'
@@ -288,4 +314,4 @@ def write_method(file, model, method):
288
314
continue
289
315
290
316
for model in sorted (extracted_models .keys ()):
291
- write_model_file (extracted_models [model ])
317
+ write_model_file (extracted_models [model ])
0 commit comments