blob: f07aa143b058ee071a50fb85d38fcda6d312090a [file] [log] [blame]
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -07001import pdb
Sapan Bhatiac4f803f2017-04-21 11:50:39 +02002import re
Sapan Bhatia7886e122017-05-17 11:19:39 +02003from pattern import en
4
Sapan Bhatiaf7934b52017-06-12 05:04:23 -07005class FieldNotFound(Exception):
6 def __init__(self, message):
7 super(FieldNotFound, self).__init__(message)
8
Sapan Bhatia943dad52017-05-19 18:41:01 +02009def xproto_unquote(s):
10 return unquote(s)
11
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020012def unquote(s):
13 if (s.startswith('"') and s.endswith('"')):
14 return s[1:-1]
15
16def xproto_singularize(field):
17 try:
18 # The user has set a singular, as an exception that cannot be handled automatically
19 singular = field['options']['singular']
20 singular = unquote(singular)
21 except KeyError:
22 singular = en.singularize(field['name'])
23
24 return singular
25
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +020026def xproto_singularize_pluralize(field):
27 try:
28 # The user has set a plural, as an exception that cannot be handled automatically
29 plural = field['options']['plural']
30 plural = unquote(plural)
31 except KeyError:
32 plural = en.pluralize(en.singularize(field['name']))
33
34 return plural
35
Sapan Bhatia7886e122017-05-17 11:19:39 +020036def xproto_pluralize(field):
37 try:
38 # The user has set a plural, as an exception that cannot be handled automatically
39 plural = field['options']['plural']
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020040 plural = unquote(plural)
Sapan Bhatia7886e122017-05-17 11:19:39 +020041 except KeyError:
42 plural = en.pluralize(field['name'])
43
44 return plural
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020045
Sapan Bhatia5769d932017-05-17 11:10:54 +020046def xproto_unquote(s):
47 if (s.startswith('"') and s.endswith('"')):
48 s = s[1:-1]
49 return s
50
Sapan Bhatiad022aeb2017-06-07 15:49:55 +020051def xproto_links_to_modeldef_relations(llst):
52 outlist = []
53 seen = []
54 for l in llst:
55 try:
56 t = l['link_type']
57 except KeyError, e:
58 raise e
59
Sapan Bhatia3cfdf632017-06-08 05:14:03 +020060 if l['peer']['fqn'] not in seen and t!='manytomany':
61 outlist.append('- {model: %s, type: %s}\n'%(l['peer']['name'], l['link_type']))
Sapan Bhatiad022aeb2017-06-07 15:49:55 +020062 seen.append(l['peer'])
63
64 return outlist
65
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070066def django_content_type_string(xptags):
67 # Check possibility of KeyError in caller
68 content_type = xptags['content_type']
69
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020070 try:
71 content_type = eval(content_type)
72 except:
73 pass
74
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070075 if (content_type=='url'):
76 return 'URLField'
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020077 if (content_type=='date'):
78 return 'DateTimeField'
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070079 elif (content_type=='ip'):
80 return 'GenericIPAddressField'
81 elif (content_type=='stripped' or content_type=='"stripped"'):
82 return 'StrippedCharField'
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020083 else:
Sapan Bhatia943dad52017-05-19 18:41:01 +020084 raise Exception('Unknown Type: %s'%content_type)
Sapan Bhatia8a57c662017-04-11 10:39:47 -070085
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070086def django_string_type(xptags):
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020087 try:
88 max_length = eval(xptags['max_length'])
89 except:
90 max_length = 1024 * 1024
91
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070092 if ('content_type' in xptags):
93 return django_content_type_string(xptags)
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020094 elif (max_length<1024*1024):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070095 return 'CharField'
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020096 else:
97 return 'TextField'
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070098
Sapan Bhatia4e80a262017-05-19 23:10:51 +020099def xproto_base_def(model_name, base):
100 if (model_name=='XOSBase'):
101 return '(models.Model, PlModelMixIn)'
102 elif (not base):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700103 return ''
104 else:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200105 base = map(lambda s:s['name'], base)
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700106 return '(' + ','.join(base) + ')'
107
Sapan Bhatia504cc972017-04-27 01:56:28 +0200108def xproto_first_non_empty(lst):
109 for l in lst:
110 if l: return l
111
Sapan Bhatia943dad52017-05-19 18:41:01 +0200112def xproto_api_type(field):
113 try:
114 if (unquote(field['options']['content_type'])=='date'):
115 return 'float'
116 except KeyError:
117 pass
118
119 return field['type']
120
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700121def xproto_django_type(xptype, xptags):
122 if (xptype=='string'):
123 return django_string_type(xptags)
124 elif (xptype=='float'):
125 return 'FloatField'
126 elif (xptype=='bool'):
127 return 'BooleanField'
128 elif (xptype=='uint32'):
129 return 'IntegerField'
130 elif (xptype=='int32'):
131 return 'IntegerField'
132 elif (xptype=='int64'):
133 return 'BigIntegerField'
134 else:
135 raise Exception('Unknown Type: %s'%xptype)
136
137
138
139def xproto_django_link_type(f):
140 if (f['link_type']=='manytoone'):
141 return 'ForeignKey'
142 elif (f['link_type']=='manytomany'):
143 if (f['dst_port']):
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200144 return 'ManyToManyField'
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700145 else:
146 return 'GenericRelation'
147
148def format_options_string(d):
149 if (not d):
150 return ''
151 else:
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200152
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700153 lst = []
154 for k,v in d.items():
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200155 if (type(v)==str and k=='default' and v.endswith('()"')):
156 lst.append('%s = %s'%(k,v[1:-3]))
157 elif (type(v)==str and v.startswith('"')):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700158 try:
159 tup = eval(v[1:-1])
160 if (type(tup)==tuple):
161 lst.append('%s = %r'%(k,tup))
162 else:
163 lst.append('%s = %s'%(k,v))
164 except:
165 lst.append('%s = %s'%(k,v))
166 elif (type(v)==bool):
167 lst.append('%s = %r'%(k,bool(v)))
168 else:
169 try:
170 lst.append('%s = %r'%(k,int(v)))
171 except ValueError:
172 lst.append('%s = %s'%(k,v))
173
174 return ', '.join(lst)
175
176def map_xproto_to_django(f):
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200177 allowed_keys=['help_text','default','max_length','modifier','blank','choices','db_index','null','editable','on_delete','verbose_name', 'auto_now_add']
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700178
179 m = {'modifier':{'optional':True, 'required':False, '_target':'null'}}
180 out = {}
181
182 for k,v in f['options'].items():
183 if (k in allowed_keys):
184 try:
185 kv2 = m[k]
186 out[kv2['_target']] = kv2[v]
187 except:
188 out[k] = v
189 return out
190
191
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200192def xproto_django_link_options_str(field, dport=None):
193 output_dict = map_xproto_to_django(field)
194
195 if (dport and (dport=='+' or '+' not in dport)):
196 output_dict['related_name'] = '%r'%dport
197
198 try:
Sapan Bhatiaf7662b02017-04-27 01:03:04 +0200199 if field['through']:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200200 d = {}
201 if isinstance(field['through'], str):
202 split = field['through'].rsplit('.',1)
203 d['name'] = split[-1]
204 if len(split)==2:
205 d['package'] = split[0]
206 d['fqn'] = 'package' + '.' + d['name']
207 else:
208 d['fqn'] = d['name']
209 d['package'] = ''
210 else:
211 d = field['through']
212
213 if not d['name'].endswith('_'+field['name']):
214 output_dict['through'] = '%r'%d['fqn']
Sapan Bhatiaf7662b02017-04-27 01:03:04 +0200215 except KeyError:
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200216 pass
217
218 return format_options_string(output_dict)
219
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700220def xproto_django_options_str(field, dport=None):
221 output_dict = map_xproto_to_django(field)
222
223 if (dport=='_'):
224 dport = '+'
225
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200226 if (dport and (dport=='+' or '+' not in dport)):
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700227 output_dict['related_name'] = '%r'%dport
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200228
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -0700229 return format_options_string(output_dict)
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200230
231def xproto_base_name(n):
232 # Hack - Refactor NetworkParameter* to make this go away
233 if (n.startswith('NetworkParameter')):
234 return '_'
235
Sapan Bhatia4e80a262017-05-19 23:10:51 +0200236 expr = r'^[A-Z]+[a-z]*'
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200237
238 try:
239 match = re.findall(expr, n)[0]
240 except:
241 return '_'
242
243 return match
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200244
Sapan Bhatia943dad52017-05-19 18:41:01 +0200245def xproto_base_fields(m, table):
246 fields = []
247
248 for b in m['bases']:
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200249 option1 = b['fqn']
250 try:
251 option2 = m['package'] + '.' + b['name']
252 except TypeError:
253 option2 = option1
Sapan Bhatia943dad52017-05-19 18:41:01 +0200254
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200255 accessor = None
256 if option1 in table: accessor = option1
257 elif option2 in table: accessor = option2
258
259 if accessor:
260 base_fields = xproto_base_fields(table[accessor], table)
261
262 model_fields = table[accessor]['fields']
Sapan Bhatia943dad52017-05-19 18:41:01 +0200263 fields.extend(base_fields)
264 fields.extend(model_fields)
265
266 return fields
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200267
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200268def xproto_base_rlinks(m, table):
269 links = []
270
271 for base in m['bases']:
272 b = base['name']
273 if b in table:
274 base_rlinks = xproto_base_rlinks(table[b], table)
275
276 model_rlinks = table[b]['rlinks']
277 links.extend(base_rlinks)
278 links.extend(model_rlinks)
279
280 return links
281
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200282def xproto_base_links(m, table):
283 links = []
284
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200285 for base in m['bases']:
286 b = base['name']
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200287 if b in table:
288 base_links = xproto_base_links(table[b], table)
289
290 model_links = table[b]['links']
291 links.extend(base_links)
292 links.extend(model_links)
293 return links
294
295
296def xproto_validators(f):
297 # To be cleaned up when we formalize validation in xproto
298 validators = []
299
300 # bound-based validators
301 bound_validators = [('max_length','maxlength'), ('min', 'min'), ('max', 'max')]
302
303 for v0, v1 in bound_validators:
304 try:
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200305 validators.append({'name':v1, 'int_value':int(f['options'][v0])})
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200306 except KeyError:
307 pass
308
309 # validators based on content_type
310 content_type_validators = ['ip', 'url', 'email']
311
312 for v in content_type_validators:
313 #if f['name']=='ip': pdb.set_trace()
314 try:
315 val = unquote(f['options']['content_type'])==v
316 if not val:
317 raise KeyError
318
319 validators.append({'name':v, 'bool_value': True})
320 except KeyError:
321 pass
322
323 # required validator
324 try:
325 required = f['options']['blank']=='False' and f['options']['null']=='False'
326 if required:
327 validators.append({'name':'required', 'bool_value':required})
328 except KeyError:
329 pass
330
331 return validators
332
333def xproto_string_type(xptags):
334 try:
335 max_length = eval(xptags['max_length'])
336 except:
337 max_length = 1024
338
339 if ('varchar' not in xptags):
340 return 'string'
341 else:
342 return 'text'
343
344def xproto_type_to_ui_type(f):
345 try:
346 content_type = f['options']['content_type']
347 content_type = eval(content_type)
348 except:
349 content_type = None
350 pass
351
352 if content_type == 'date':
353 return 'date'
354 elif f['type'] == 'bool':
355 return 'boolean'
356 elif f['type'] == 'string':
357 return xproto_string_type(f['options'])
358 elif f['type'] in ['int','uint32','int32'] or 'link' in f:
359 return 'number'
360 elif f['type'] in ['double','float']:
361 return 'string'
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700362
363def xproto_tuplify(nested_list_or_set):
364 if not isinstance(nested_list_or_set, list) and not isinstance(nested_list_or_set, set):
365 return nested_list_or_set
366 else:
367 return tuple([xproto_tuplify(i) for i in nested_list_or_set])
368
369def xproto_field_graph_components(fields, tag='unique_with'):
370 def find_components(graph):
371 pending = set(graph.keys())
372 components = []
373
374 while pending:
375 front = { pending.pop() }
376 component = set()
377
378 while front:
379 node = front.pop()
380 neighbours = graph[node]
381 neighbours-=component # These we have already visited
382 front |= neighbours
383
384 pending-=neighbours
385 component |= neighbours
386
387 components.append(component)
388
389 return components
390
391 field_graph = {}
392 field_names = {f['name'] for f in fields}
393
394 for f in fields:
395 try:
396 tagged_str = unquote(f['options'][tag])
397 tagged_fields = tagged_str.split(',')
398
399 for uf in tagged_fields:
400 if uf not in field_names:
401 raise FieldNotFound('Field %s not found'%uf)
402
403 field_graph.setdefault(f['name'],set()).add(uf)
404 field_graph.setdefault(uf,set()).add(f['name'])
405 except KeyError:
406 pass
407
408 components = find_components(field_graph)
409 return components
410
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200411def xproto_api_opts(field):
412 options = []
413 if 'max_length' in field['options'] and field['type']=='string':
414 options.append('(val).maxLength = %s'%field['options']['max_length'])
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700415
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200416 try:
417 if field['options']['null'] == 'False':
418 options.append('(val).nonNull = true')
419 except KeyError:
420 pass
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700421
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200422 if 'link' in field and 'model' in field['options']:
423 options.append('(foreignKey).modelName = "%s"'%field['options']['model'])
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700424
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200425 if options:
426 options_str = '[' + ', '.join(options) + ']'
427 else:
428 options_str = ''
429
430 return options_str
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700431
Matteo Scandolo3b7857b2017-06-30 16:22:33 -0700432def xproto_tosca_required(null, blank, default=None):
433
434 if null == 'True' or blank == 'True' or default != 'False':
435 return "false"
436 return "true"
437
438def xproto_tosca_field_type(type):
439 """
440 TOSCA requires fields of type 'bool' to be 'boolean'
441 """
442 if type == "bool":
443 return "boolean"
444 else:
445 return type
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700446