blob: 724b85dc87ac319b0df47a30aefcbba08827b426 [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
15
Sapan Bhatia5ea307d2017-07-19 00:13:21 -040016from base import *
17import pdb
Sapan Bhatia1e021772017-08-19 02:15:48 -040018import re
Sapan Bhatia5ea307d2017-07-19 00:13:21 -040019
Zack Williams045b63d2019-01-22 16:30:57 -070020
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040021def django_content_type_string(xptags):
22 # Check possibility of KeyError in caller
Zack Williams045b63d2019-01-22 16:30:57 -070023 content_type = xptags["content_type"]
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040024
25 try:
26 content_type = eval(content_type)
Zack Williams045b63d2019-01-22 16:30:57 -070027 except BaseException:
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040028 pass
29
Zack Williams045b63d2019-01-22 16:30:57 -070030 if content_type == "url":
31 return "URLField"
32 if content_type == "date":
33 return "DateTimeField"
34 elif content_type == "ip":
35 return "GenericIPAddressField"
36 elif content_type == "stripped" or content_type == '"stripped"':
37 return "StrippedCharField"
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040038 else:
Zack Williams045b63d2019-01-22 16:30:57 -070039 raise Exception("Unknown Type: %s" % content_type)
40
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040041
42def django_string_type(xptags):
43 try:
Zack Williams045b63d2019-01-22 16:30:57 -070044 max_length = eval(xptags["max_length"])
45 except BaseException:
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040046 max_length = 1024 * 1024
47
Zack Williams045b63d2019-01-22 16:30:57 -070048 if "content_type" in xptags:
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040049 return django_content_type_string(xptags)
Zack Williams045b63d2019-01-22 16:30:57 -070050 elif max_length < 1024 * 1024:
51 return "CharField"
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040052 else:
Zack Williams045b63d2019-01-22 16:30:57 -070053 return "TextField"
54
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040055
56def xproto_django_type(xptype, xptags):
Zack Williams045b63d2019-01-22 16:30:57 -070057 if xptype == "string":
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040058 return django_string_type(xptags)
Zack Williams045b63d2019-01-22 16:30:57 -070059 elif xptype == "float":
60 return "FloatField"
61 elif xptype == "bool":
62 return "BooleanField"
63 elif xptype == "uint32":
64 return "IntegerField"
65 elif xptype == "int32":
66 return "IntegerField"
67 elif xptype == "int64":
68 return "BigIntegerField"
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040069 else:
Zack Williams045b63d2019-01-22 16:30:57 -070070 raise Exception("Unknown Type: %s" % xptype)
71
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040072
73def xproto_django_link_type(f):
Zack Williams045b63d2019-01-22 16:30:57 -070074 if f["link_type"] == "manytoone":
75 return "ForeignKey"
76 elif f["link_type"] == "onetoone":
77 return "OneToOneField"
78 elif f["link_type"] == "manytomany":
79 if f["dst_port"]:
80 return "ManyToManyField"
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040081 else:
Zack Williams045b63d2019-01-22 16:30:57 -070082 return "GenericRelation"
83
Sapan Bhatiad8e4a232017-07-12 21:20:06 -040084
85def map_xproto_to_django(f):
Zack Williams045b63d2019-01-22 16:30:57 -070086 allowed_keys = [
87 "help_text",
88 "default",
89 "max_length",
90 "modifier",
91 "blank",
92 "choices",
93 "db_index",
94 "null",
95 "editable",
96 "on_delete",
97 "verbose_name",
98 "auto_now_add",
99 "unique",
100 "min_value",
101 "max_value",
102 ]
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400103
Scott Baker2e856be2019-02-07 09:28:09 -0800104 if f.get("link_type") == "manytomany":
105 # map for fields that do not support null
106 m = {
107 "modifier": {"optional": True, "required": False, "_targets": ["blank"]}
108 }
109 else:
110 # map for fields that do support null
111 # TODO evaluate if setting Null = False for all strings
112 m = {
113 "modifier": {"optional": True, "required": False, "_targets": ["null", "blank"]}
114 }
115
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400116 out = {}
117
Zack Williams045b63d2019-01-22 16:30:57 -0700118 for k, v in f["options"].items():
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400119 if k in allowed_keys:
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400120 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700121 # NOTE this will be used to parse xproto optional/required field prefix
122 # and apply it to the null and blank fields
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400123 kv2 = m[k]
Zack Williams045b63d2019-01-22 16:30:57 -0700124 for t in kv2["_targets"]:
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400125 out[t] = kv2[v]
Zack Williams045b63d2019-01-22 16:30:57 -0700126 except BaseException:
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400127 out[k] = v
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400128
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400129 return out
130
Zack Williams045b63d2019-01-22 16:30:57 -0700131
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400132def xproto_django_link_options_str(field, dport=None):
Scott Baker2e856be2019-02-07 09:28:09 -0800133 # Note that this function is called for links (ForeignKeys, M2Ms)
134
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400135 output_dict = map_xproto_to_django(field)
136
Zack Williams045b63d2019-01-22 16:30:57 -0700137 if dport and (dport == "+" or "+" not in dport):
138 output_dict["related_name"] = "%r" % dport
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400139
140 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700141 if field["through"]:
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400142 d = {}
Zack Williams045b63d2019-01-22 16:30:57 -0700143 if isinstance(field["through"], str):
144 split = field["through"].rsplit(".", 1)
145 d["name"] = split[-1]
146 if len(split) == 2:
147 d["package"] = split[0]
148 d["fqn"] = "package" + "." + d["name"]
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400149 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700150 d["fqn"] = d["name"]
151 d["package"] = ""
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400152 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700153 d = field["through"]
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400154
Zack Williams045b63d2019-01-22 16:30:57 -0700155 if not d["name"].endswith("_" + field["name"]):
156 output_dict["through"] = "%r" % d["fqn"]
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400157 except KeyError:
158 pass
159
160 return format_options_string(output_dict)
161
Zack Williams045b63d2019-01-22 16:30:57 -0700162
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400163def use_native_django_validators(k, v):
164
165 validators_map = {
Zack Williams045b63d2019-01-22 16:30:57 -0700166 "min_value": "MinValueValidator",
167 "max_value": "MaxValueValidator",
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400168 }
169
170 return "%s(%s)" % (validators_map[k], v)
171
Zack Williams045b63d2019-01-22 16:30:57 -0700172
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400173def format_options_string(d):
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400174
Zack Williams045b63d2019-01-22 16:30:57 -0700175 known_validators = ["min_value", "max_value"]
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400176 validator_lst = []
177
Zack Williams045b63d2019-01-22 16:30:57 -0700178 if not d:
179 return ""
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400180 else:
181
182 lst = []
Zack Williams045b63d2019-01-22 16:30:57 -0700183 for k, v in d.items():
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400184 if k in known_validators:
185 validator_lst.append(use_native_django_validators(k, v))
Zack Williams045b63d2019-01-22 16:30:57 -0700186 elif isinstance(v, str) and k == "default" and v.endswith('()"'):
187 lst.append("%s = %s" % (k, v[1:-3]))
188 elif isinstance(v, str) and v.startswith('"'):
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400189 try:
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400190 # unquote the value if necessary
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400191 tup = eval(v[1:-1])
Zack Williams045b63d2019-01-22 16:30:57 -0700192 if isinstance(tup, tuple):
193 lst.append("%s = %r" % (k, tup))
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400194 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700195 lst.append("%s = %s" % (k, v))
196 except BaseException:
197 lst.append("%s = %s" % (k, v))
198 elif isinstance(v, bool):
199 lst.append("%s = %r" % (k, bool(v)))
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400200 else:
201 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700202 lst.append("%s = %r" % (k, int(v)))
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400203 except ValueError:
Zack Williams045b63d2019-01-22 16:30:57 -0700204 lst.append("%s = %s" % (k, v))
205 validator_string = "validators=[%s]" % ", ".join(validator_lst)
206 option_string = ", ".join(lst)
Matteo Scandolo61a9f202018-08-01 08:58:13 -0400207 if len(validator_lst) == 0:
208 return option_string
209 elif len(lst) == 0:
210 return validator_string
211 else:
Zack Williams045b63d2019-01-22 16:30:57 -0700212 return option_string + ", " + validator_string
213
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400214
215def xproto_django_options_str(field, dport=None):
Scott Baker2e856be2019-02-07 09:28:09 -0800216 # This function is called for non-links (Strings, Ints, Booleans, ...)
217
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400218 output_dict = map_xproto_to_django(field)
219
Zack Williams045b63d2019-01-22 16:30:57 -0700220 if dport == "_":
221 dport = "+"
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400222
Zack Williams045b63d2019-01-22 16:30:57 -0700223 if dport and (dport == "+" or "+" not in dport):
224 output_dict["related_name"] = "%r" % dport
Sapan Bhatiad8e4a232017-07-12 21:20:06 -0400225
226 return format_options_string(output_dict)
Sapan Bhatia5ea307d2017-07-19 00:13:21 -0400227
Zack Williams045b63d2019-01-22 16:30:57 -0700228
Sapan Bhatia1e021772017-08-19 02:15:48 -0400229def xproto_camel_to_underscore(name):
Zack Williams045b63d2019-01-22 16:30:57 -0700230 return re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name)
231
Sapan Bhatia1e021772017-08-19 02:15:48 -0400232
Sapan Bhatia5ea307d2017-07-19 00:13:21 -0400233def xproto_validations(options):
234 try:
Zack Williams045b63d2019-01-22 16:30:57 -0700235 return [
236 map(str.strip, validation.split(":"))
237 for validation in unquote(options["validators"]).split(",")
238 ]
Sapan Bhatia5ea307d2017-07-19 00:13:21 -0400239 except KeyError:
240 return []
Matteo Scandolo23cf15f2018-03-06 18:12:36 -0800241
Zack Williams045b63d2019-01-22 16:30:57 -0700242
Matteo Scandolo23cf15f2018-03-06 18:12:36 -0800243def xproto_optioned_fields_to_list(fields, option, val):
244 """
245 List all the field that have a particural option
246 :param fields: (list) an array of message fields
247 :param option: (string) the option to look for
248 :param val: (any) the value of the option
249 :return: list of strings, field names where option is set
250 """
251
252 optioned_fields = []
253 for f in fields:
254 option_names = []
Zack Williams045b63d2019-01-22 16:30:57 -0700255 for k, v in f["options"].items():
Matteo Scandolo23cf15f2018-03-06 18:12:36 -0800256 option_names.append(k)
257
Zack Williams045b63d2019-01-22 16:30:57 -0700258 if option in option_names and f["options"][option] == val:
259 optioned_fields.append(f["name"])
Matteo Scandolo23cf15f2018-03-06 18:12:36 -0800260
261 return optioned_fields
262
Zack Williams045b63d2019-01-22 16:30:57 -0700263
Matteo Scandolo23cf15f2018-03-06 18:12:36 -0800264# TODO
265# - in modeldefs add info about this fields
266# - update the gui to have this fields as readonly