blob: fd4808e22bc663a45d0c899b0591e7fb976fe875 [file] [log] [blame]
Matteo Scandolod2044a42017-08-07 16:08:28 -07001# Copyright 2017-present Open Networking Foundation
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
Zack Williams9a42f872019-02-15 17:56:04 -070015from __future__ import absolute_import, print_function
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070016import pdb
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020017import re
Scott Baker391f5d82018-10-02 16:34:41 -070018from inflect import engine as inflect_engine_class
19
20inflect_engine = inflect_engine_class()
Sapan Bhatia7886e122017-05-17 11:19:39 +020021
Zack Williams045b63d2019-01-22 16:30:57 -070022
Sapan Bhatiaf7934b52017-06-12 05:04:23 -070023class FieldNotFound(Exception):
24 def __init__(self, message):
25 super(FieldNotFound, self).__init__(message)
26
Zack Williams045b63d2019-01-22 16:30:57 -070027
Sapan Bhatiad4567592017-07-24 17:26:26 -040028def xproto_debug(**kwargs):
Zack Williams045b63d2019-01-22 16:30:57 -070029 print(kwargs)
Sapan Bhatiad4567592017-07-24 17:26:26 -040030 pdb.set_trace()
31
Zack Williams045b63d2019-01-22 16:30:57 -070032
Sapan Bhatia943dad52017-05-19 18:41:01 +020033def xproto_unquote(s):
34 return unquote(s)
35
Zack Williams045b63d2019-01-22 16:30:57 -070036
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020037def unquote(s):
Zack Williams67142162019-03-06 14:01:32 -070038 if s and s.startswith('"') and s.endswith('"'):
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020039 return s[1:-1]
Matteo Scandolo292cc2a2017-07-31 19:02:12 -070040 else:
41 return s
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020042
Zack Williams045b63d2019-01-22 16:30:57 -070043
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020044def xproto_singularize(field):
45 try:
46 # The user has set a singular, as an exception that cannot be handled automatically
Zack Williams045b63d2019-01-22 16:30:57 -070047 singular = field["options"]["singular"]
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020048 singular = unquote(singular)
49 except KeyError:
Zack Williams045b63d2019-01-22 16:30:57 -070050 singular = inflect_engine.singular_noun(field["name"])
Scott Bakera1b089a2018-10-05 09:59:17 -070051 if singular is False:
52 # singular_noun returns False on a noun it can't singularize
53 singular = field["name"]
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020054
55 return singular
56
Zack Williams045b63d2019-01-22 16:30:57 -070057
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +020058def xproto_singularize_pluralize(field):
59 try:
60 # The user has set a plural, as an exception that cannot be handled automatically
Zack Williams045b63d2019-01-22 16:30:57 -070061 plural = field["options"]["plural"]
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +020062 plural = unquote(plural)
63 except KeyError:
Zack Williams045b63d2019-01-22 16:30:57 -070064 singular = inflect_engine.singular_noun(field["name"])
Scott Bakera1b089a2018-10-05 09:59:17 -070065 if singular is False:
66 # singular_noun returns False on a noun it can't singularize
67 singular = field["name"]
68
69 plural = inflect_engine.plural_noun(singular)
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +020070
71 return plural
72
Zack Williams045b63d2019-01-22 16:30:57 -070073
Sapan Bhatia7886e122017-05-17 11:19:39 +020074def xproto_pluralize(field):
75 try:
76 # The user has set a plural, as an exception that cannot be handled automatically
Zack Williams045b63d2019-01-22 16:30:57 -070077 plural = field["options"]["plural"]
Sapan Bhatia49b54ae2017-05-19 17:11:32 +020078 plural = unquote(plural)
Sapan Bhatia7886e122017-05-17 11:19:39 +020079 except KeyError:
Zack Williams045b63d2019-01-22 16:30:57 -070080 plural = inflect_engine.plural_noun(field["name"])
Sapan Bhatia7886e122017-05-17 11:19:39 +020081
82 return plural
Sapan Bhatiac4f803f2017-04-21 11:50:39 +020083
Zack Williams045b63d2019-01-22 16:30:57 -070084
85def xproto_base_def(model_name, base, suffix="", suffix_list=[]):
86 if model_name == "XOSBase":
87 return "(models.Model, PlModelMixIn)"
88 elif not base:
89 return ""
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070090 else:
Zack Williams045b63d2019-01-22 16:30:57 -070091 int_base = [i["name"] + suffix for i in base if i["name"] in suffix_list]
92 ext_base = [i["name"] for i in base if i["name"] not in suffix_list]
93 return "(" + ",".join(int_base + ext_base) + ")"
94
Sapan Bhatiaff1b8fa2017-04-10 19:44:38 -070095
Sapan Bhatia504cc972017-04-27 01:56:28 +020096def xproto_first_non_empty(lst):
97 for l in lst:
Zack Williams045b63d2019-01-22 16:30:57 -070098 if l:
99 return l
100
Sapan Bhatia504cc972017-04-27 01:56:28 +0200101
Sapan Bhatia943dad52017-05-19 18:41:01 +0200102def xproto_api_type(field):
103 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700104 if unquote(field["options"]["content_type"]) == "date":
105 return "double"
Sapan Bhatia943dad52017-05-19 18:41:01 +0200106 except KeyError:
107 pass
108
Zack Williams045b63d2019-01-22 16:30:57 -0700109 return field["type"]
Sapan Bhatia943dad52017-05-19 18:41:01 +0200110
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200111
112def xproto_base_name(n):
113 # Hack - Refactor NetworkParameter* to make this go away
Zack Williams045b63d2019-01-22 16:30:57 -0700114 if n.startswith("NetworkParameter"):
115 return "_"
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200116
Zack Williams045b63d2019-01-22 16:30:57 -0700117 expr = r"^[A-Z]+[a-z]*"
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200118
119 try:
120 match = re.findall(expr, n)[0]
Zack Williams045b63d2019-01-22 16:30:57 -0700121 except BaseException:
122 return "_"
Sapan Bhatiac4f803f2017-04-21 11:50:39 +0200123
124 return match
Sapan Bhatiaae9645c2017-05-05 15:35:54 +0200125
Zack Williams045b63d2019-01-22 16:30:57 -0700126
Sapan Bhatia943dad52017-05-19 18:41:01 +0200127def xproto_base_fields(m, table):
128 fields = []
129
Zack Williams045b63d2019-01-22 16:30:57 -0700130 for b in m["bases"]:
131 option1 = b["fqn"]
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200132 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700133 option2 = m["package"] + "." + b["name"]
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200134 except TypeError:
135 option2 = option1
Sapan Bhatia943dad52017-05-19 18:41:01 +0200136
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200137 accessor = None
Zack Williams045b63d2019-01-22 16:30:57 -0700138 if option1 in table:
139 accessor = option1
140 elif option2 in table:
141 accessor = option2
Sapan Bhatia3cfdf632017-06-08 05:14:03 +0200142
143 if accessor:
144 base_fields = xproto_base_fields(table[accessor], table)
145
Zack Williams045b63d2019-01-22 16:30:57 -0700146 model_fields = [x.copy() for x in table[accessor]["fields"]]
Scott Bakerc237f882018-09-28 14:12:47 -0700147 for field in model_fields:
148 field["accessor"] = accessor
149
Sapan Bhatia943dad52017-05-19 18:41:01 +0200150 fields.extend(base_fields)
151 fields.extend(model_fields)
152
Zack Williams045b63d2019-01-22 16:30:57 -0700153 if "no_sync" in m["options"] and m["options"]["no_sync"]:
154 fields = [
155 f
156 for f in fields
157 if f["name"] != "backend_status" and f["name"] != "backend_code"
158 ]
Matteo Scandolo39b4a272017-11-17 11:09:21 -0800159
Zack Williams045b63d2019-01-22 16:30:57 -0700160 if "no_policy" in m["options"] and m["options"]["no_policy"]:
161 fields = [
162 f
163 for f in fields
164 if f["name"] != "policy_status" and f["name"] != "policy_code"
165 ]
Matteo Scandolo39b4a272017-11-17 11:09:21 -0800166
Sapan Bhatia943dad52017-05-19 18:41:01 +0200167 return fields
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200168
Zack Williams045b63d2019-01-22 16:30:57 -0700169
Scott Bakerc237f882018-09-28 14:12:47 -0700170def xproto_fields(m, table):
171 """ Generate the full list of models for the xproto message `m` including fields from the classes it inherits.
172
173 Inserts the special field "id" at the very beginning.
174
175 Each time we descend a new level of inheritance, increment the offset field numbers by 100. The base
176 class's fields will be numbered from 1-99, the first descendant will be number 100-199, the second
177 descdendant numbered from 200-299, and so on. This assumes any particular model as at most 100
178 fields.
179 """
180
181 model_fields = [x.copy() for x in m["fields"]]
182 for field in model_fields:
183 field["accessor"] = m["fqn"]
184
185 fields = xproto_base_fields(m, table) + model_fields
186
187 # The "id" field is a special field. Every model has one. Put it up front and pretend it's part of the
188
Scott Baker1f7791d2018-10-04 13:21:20 -0700189 if not fields:
Zack Williams045b63d2019-01-22 16:30:57 -0700190 raise Exception(
191 "Model %s has no fields. Check for missing base class." % m["name"]
192 )
Scott Baker1f7791d2018-10-04 13:21:20 -0700193
Zack Williams045b63d2019-01-22 16:30:57 -0700194 id_field = {
195 "type": "int32",
196 "name": "id",
197 "options": {},
198 "id": "1",
199 "accessor": fields[0]["accessor"],
200 }
Scott Bakerc237f882018-09-28 14:12:47 -0700201
202 fields = [id_field] + fields
203
204 # Walk through the list of fields. They will be in depth-first search order from the base model forward. Each time
205 # the model changes, offset the protobuf field numbers by 100.
206 offset = 0
207 last_accessor = fields[0]["accessor"]
208 for field in fields:
Zack Williams045b63d2019-01-22 16:30:57 -0700209 if field["accessor"] != last_accessor:
Scott Bakerc237f882018-09-28 14:12:47 -0700210 last_accessor = field["accessor"]
211 offset += 100
212 field_id = int(field["id"])
213 if (field_id < 1) or (field_id >= 100):
Zack Williams045b63d2019-01-22 16:30:57 -0700214 raise Exception(
215 "Only field numbers from 1 to 99 are permitted, field %s in model %s"
216 % (field["name"], field["accessor"])
217 )
Scott Bakerc237f882018-09-28 14:12:47 -0700218 field["id"] = int(field["id"]) + offset
219
220 # Check for duplicates
221 fields_by_number = {}
222 for field in fields:
223 id = field["id"]
224 dup = fields_by_number.get(id)
225 if dup:
Zack Williams045b63d2019-01-22 16:30:57 -0700226 raise Exception(
227 "Field %s has duplicate number %d with field %s in model %s"
228 % (field["name"], id, dup["name"], field["accessor"])
229 )
Scott Bakerc237f882018-09-28 14:12:47 -0700230 fields_by_number[id] = field
231
232 return fields
233
Zack Williams045b63d2019-01-22 16:30:57 -0700234
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200235def xproto_base_rlinks(m, table):
236 links = []
237
Zack Williams045b63d2019-01-22 16:30:57 -0700238 for base in m["bases"]:
239 b = base["name"]
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200240 if b in table:
241 base_rlinks = xproto_base_rlinks(table[b], table)
242
Zack Williams045b63d2019-01-22 16:30:57 -0700243 model_rlinks = [x.copy() for x in table[b]["rlinks"]]
Scott Bakerd87c02a2018-10-29 16:24:29 -0700244 for link in model_rlinks:
245 link["accessor"] = b
246
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200247 links.extend(base_rlinks)
248 links.extend(model_rlinks)
249
250 return links
251
Zack Williams045b63d2019-01-22 16:30:57 -0700252
Scott Bakerc237f882018-09-28 14:12:47 -0700253def xproto_rlinks(m, table):
254 """ Return the reverse links for the xproto message `m`.
255
Scott Bakerd87c02a2018-10-29 16:24:29 -0700256 If the link includes a reverse_id, then it will be used for the protobuf field id. Each level of inheritance
257 will add an offset of 100 to the supplied reverse_id.
258
259 If there is no reverse_id, then one will automatically be allocated started at id 1900. It is encouraged that
260 all links include reverse_ids, so that field identifiers are deterministic across all protobuf messages.
Scott Bakerc237f882018-09-28 14:12:47 -0700261 """
262
Scott Bakerd87c02a2018-10-29 16:24:29 -0700263 model_rlinks = [x.copy() for x in m["rlinks"]]
264 for link in model_rlinks:
265 link["accessor"] = m["fqn"]
266
267 links = xproto_base_rlinks(m, table) + model_rlinks
Scott Bakerc237f882018-09-28 14:12:47 -0700268
Zack Williams045b63d2019-01-22 16:30:57 -0700269 links = [
270 x for x in links if ("+" not in x["src_port"]) and ("+" not in x["dst_port"])
271 ]
Scott Bakerc237f882018-09-28 14:12:47 -0700272
Scott Bakerd87c02a2018-10-29 16:24:29 -0700273 if links:
274 last_accessor = links[0]["accessor"]
275 offset = 0
276 index = 1900
277 for link in links:
Zack Williams045b63d2019-01-22 16:30:57 -0700278 if link["accessor"] != last_accessor:
Scott Bakerd87c02a2018-10-29 16:24:29 -0700279 last_accessor = link["accessor"]
280 offset += 100
Scott Bakerc237f882018-09-28 14:12:47 -0700281
Scott Bakerd87c02a2018-10-29 16:24:29 -0700282 if link["reverse_id"]:
283 # Statically numbered reverse links. Use the id that the developer supplied, adding the offset based on
284 # inheritance depth.
285 link["id"] = int(link["reverse_id"]) + offset
286 else:
287 # Automatically numbered reverse links. These will eventually go away.
288 link["id"] = index
289 index += 1
290
291 # check for duplicates
Zack Williams045b63d2019-01-22 16:30:57 -0700292 links_by_number = {}
Scott Bakerd87c02a2018-10-29 16:24:29 -0700293 for link in links:
294 id = link["id"]
Zack Williams045b63d2019-01-22 16:30:57 -0700295 dup = links_by_number.get(id)
Scott Bakerd87c02a2018-10-29 16:24:29 -0700296 if dup:
Zack Williams045b63d2019-01-22 16:30:57 -0700297 raise Exception(
298 "Field %s has duplicate number %d in model %s with reverse field %s"
299 % (link["src_port"], id, m["name"], dup["src_port"])
300 )
Scott Bakerd87c02a2018-10-29 16:24:29 -0700301 links_by_number[id] = link
Scott Bakerc237f882018-09-28 14:12:47 -0700302
303 return links
304
305
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200306def xproto_base_links(m, table):
307 links = []
308
Zack Williams045b63d2019-01-22 16:30:57 -0700309 for base in m["bases"]:
310 b = base["name"]
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200311 if b in table:
312 base_links = xproto_base_links(table[b], table)
313
Zack Williams045b63d2019-01-22 16:30:57 -0700314 model_links = table[b]["links"]
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200315 links.extend(base_links)
316 links.extend(model_links)
317 return links
318
Zack Williams045b63d2019-01-22 16:30:57 -0700319
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200320def xproto_string_type(xptags):
Scott Baker08d10402019-04-08 16:19:59 -0700321 if "text" not in xptags:
322 # String fields have a mandatory maximum length.
323 # They are intended for relatively short strings.
Zack Williams045b63d2019-01-22 16:30:57 -0700324 return "string"
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200325 else:
Scott Baker08d10402019-04-08 16:19:59 -0700326 # Text fields have an optional maximuim length.
327 # They are intended for long, potentially multiline strings.
Zack Williams045b63d2019-01-22 16:30:57 -0700328 return "text"
329
Sapan Bhatiad022aeb2017-06-07 15:49:55 +0200330
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700331def xproto_tuplify(nested_list_or_set):
Zack Williams045b63d2019-01-22 16:30:57 -0700332 if not isinstance(nested_list_or_set, list) and not isinstance(
333 nested_list_or_set, set
334 ):
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700335 return nested_list_or_set
336 else:
337 return tuple([xproto_tuplify(i) for i in nested_list_or_set])
338
Zack Williams045b63d2019-01-22 16:30:57 -0700339
340def xproto_field_graph_components(fields, model, tag="unique_with"):
Zack Williams9a42f872019-02-15 17:56:04 -0700341 """
342 NOTE: Don't use set theory operators if you want repeatable tests - many
343 of them have non-deterministic behavior
344 """
345
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700346 def find_components(graph):
Zack Williams9a42f872019-02-15 17:56:04 -0700347
348 # 'graph' dict structure:
349 # - keys are strings
350 # - values are sets containing strings that are names of other keys in 'graph'
351
352 # take keys from 'graph' dict and put in 'pending' set
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700353 pending = set(graph.keys())
Zack Williams9a42f872019-02-15 17:56:04 -0700354
355 # create an empty list named 'components'
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700356 components = []
357
Zack Williams9a42f872019-02-15 17:56:04 -0700358 # loop while 'pending' is true - while there are still items in the 'pending' set
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700359 while pending:
Zack Williams9a42f872019-02-15 17:56:04 -0700360
361 # remove a random item from pending set, and put in 'front'
362 # this is the primary source of nondeterminism
Zack Williams045b63d2019-01-22 16:30:57 -0700363 front = {pending.pop()}
Zack Williams9a42f872019-02-15 17:56:04 -0700364
365 # create an empty set named 'component'
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700366 component = set()
367
Zack Williams9a42f872019-02-15 17:56:04 -0700368 # loop while 'front' is true. Front is modified below
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700369 while front:
Zack Williams9a42f872019-02-15 17:56:04 -0700370
371 # take the (only?) item out of the 'front' dict, and put in 'node'
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700372 node = front.pop()
Zack Williams9a42f872019-02-15 17:56:04 -0700373
374 # from 'graph' dict take set with key of 'node' and put into 'neighbors'
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700375 neighbours = graph[node]
Zack Williams9a42f872019-02-15 17:56:04 -0700376
377 # remove the set of items in components from neighbors
Matteo Scandoloa17e6e42018-05-25 10:28:25 -0700378 neighbours -= component # These we have already visited
Zack Williams9a42f872019-02-15 17:56:04 -0700379
380 # add all remaining neighbors to front
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700381 front |= neighbours
382
Zack Williams9a42f872019-02-15 17:56:04 -0700383 # remove neighbors from pending
Matteo Scandoloa17e6e42018-05-25 10:28:25 -0700384 pending -= neighbours
Zack Williams9a42f872019-02-15 17:56:04 -0700385
386 # add neighbors to component
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700387 component |= neighbours
Zack Williams045b63d2019-01-22 16:30:57 -0700388
Zack Williams9a42f872019-02-15 17:56:04 -0700389 # append component set to components list, sorted
390 components.append(sorted(component))
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700391
Zack Williams9a42f872019-02-15 17:56:04 -0700392 # return 'components', which is a list of sets
393 return sorted(components)
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700394
395 field_graph = {}
Zack Williams045b63d2019-01-22 16:30:57 -0700396 field_names = {f["name"] for f in fields}
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700397
398 for f in fields:
399 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700400 tagged_str = unquote(f["options"][tag])
401 tagged_fields = tagged_str.split(",")
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700402
403 for uf in tagged_fields:
404 if uf not in field_names:
Zack Williams045b63d2019-01-22 16:30:57 -0700405 raise FieldNotFound(
406 'Field "%s" not found in model "%s", referenced from field "%s" by option "%s"'
407 % (uf, model["name"], f["name"], tag)
408 )
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700409
Zack Williams045b63d2019-01-22 16:30:57 -0700410 field_graph.setdefault(f["name"], set()).add(uf)
411 field_graph.setdefault(uf, set()).add(f["name"])
Zack Williams9a42f872019-02-15 17:56:04 -0700412
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700413 except KeyError:
414 pass
415
Matteo Scandoloa17e6e42018-05-25 10:28:25 -0700416 return find_components(field_graph)
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700417
Zack Williams045b63d2019-01-22 16:30:57 -0700418
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200419def xproto_api_opts(field):
420 options = []
Zack Williams045b63d2019-01-22 16:30:57 -0700421 if "max_length" in field["options"] and field["type"] == "string":
422 options.append("(val).maxLength = %s" % field["options"]["max_length"])
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700423
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200424 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700425 if field["options"]["null"] == "False":
426 options.append("(val).nonNull = true")
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200427 except KeyError:
428 pass
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700429
Zack Williams045b63d2019-01-22 16:30:57 -0700430 if "link" in field and "model" in field["options"]:
431 options.append('(foreignKey).modelName = "%s"' % field["options"]["model"])
Scott Bakerc4156c32017-12-08 10:58:21 -0800432 if ("options" in field) and ("port" in field["options"]):
Zack Williams045b63d2019-01-22 16:30:57 -0700433 options.append(
434 '(foreignKey).reverseFieldName = "%s"' % field["options"]["port"]
435 )
Sapan Bhatiaf7934b52017-06-12 05:04:23 -0700436
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200437 if options:
Zack Williams045b63d2019-01-22 16:30:57 -0700438 options_str = "[" + ", ".join(options) + "]"
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200439 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700440 options_str = ""
Sapan Bhatiacb35e7f2017-05-24 12:17:28 +0200441
442 return options_str
Matteo Scandolo67654fa2017-06-09 09:33:17 -0700443
Zack Williams045b63d2019-01-22 16:30:57 -0700444
Matteo Scandolo431781c2017-09-06 15:33:07 -0700445def xproto_type_to_swagger_type(f):
446 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700447 content_type = f["options"]["content_type"]
Matteo Scandolo431781c2017-09-06 15:33:07 -0700448 content_type = eval(content_type)
Zack Williams045b63d2019-01-22 16:30:57 -0700449 except BaseException:
Matteo Scandolo431781c2017-09-06 15:33:07 -0700450 content_type = None
451 pass
452
Zack Williams045b63d2019-01-22 16:30:57 -0700453 if "choices" in f["options"]:
454 return "string"
455 elif content_type == "date":
456 return "string"
457 elif f["type"] == "bool":
458 return "boolean"
459 elif f["type"] == "string":
460 return "string"
461 elif f["type"] in ["int", "uint32", "int32"] or "link" in f:
462 return "integer"
463 elif f["type"] in ["double", "float"]:
464 return "string"
465
Matteo Scandolo431781c2017-09-06 15:33:07 -0700466
467def xproto_field_to_swagger_enum(f):
Zack Williams045b63d2019-01-22 16:30:57 -0700468 if "choices" in f["options"]:
Zack Williams9a42f872019-02-15 17:56:04 -0700469 c_list = []
Matteo Scandolo431781c2017-09-06 15:33:07 -0700470
Zack Williams045b63d2019-01-22 16:30:57 -0700471 for c in eval(xproto_unquote(f["options"]["choices"])):
Zack Williams9a42f872019-02-15 17:56:04 -0700472 c_list.append(c[0])
Matteo Scandolo431781c2017-09-06 15:33:07 -0700473
Zack Williams9a42f872019-02-15 17:56:04 -0700474 return sorted(c_list)
Matteo Scandolo431781c2017-09-06 15:33:07 -0700475 else:
Sapan Bhatiabfb233a2018-02-09 14:53:09 -0800476 return False
Scott Bakera33ccb02018-01-26 13:03:28 -0800477
Zack Williams045b63d2019-01-22 16:30:57 -0700478
Scott Bakera33ccb02018-01-26 13:03:28 -0800479def xproto_is_true(x):
480 # TODO: Audit xproto and make specification of trueness more uniform
Zack Williams045b63d2019-01-22 16:30:57 -0700481 if x is True or (x == "True") or (x == '"True"'):
Scott Bakera33ccb02018-01-26 13:03:28 -0800482 return True
483 return False