forked from OCA/rest-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
/
tools.py
145 lines (123 loc) · 4.53 KB
/
tools.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# Copyright 2018 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import inspect
import logging
from collections import OrderedDict
_logger = logging.getLogger(__name__)
SUPPORTED_META = ["title", "description", "example", "examples"]
def cerberus_to_json(schema):
"""Convert a Cerberus schema to a JSON schema"""
result = OrderedDict()
required = []
properties = OrderedDict()
result["type"] = "object"
result["required"] = required
result["properties"] = properties
for field, spec in list(schema.items()):
props = _get_field_props(spec)
properties[field] = props
if spec.get("required"):
required.append(field)
# sort required to get the same order on each run and easy comparison into
# the tests
required.sort()
return result
def _get_field_props(spec): # noqa: C901
resp = OrderedDict()
# dictionary of tuple (json type, json fromat) by cerberus type for
# cerberus types requiring a specific mapping to a json type/format
type_map = {
"dict": ("object",),
"list": ("array",),
"objectid": ("string", "objectid"),
"datetime": ("string", "date-time"),
"float": ("number", "float"),
}
_type = spec.get("type")
if _type is None:
return resp
if "description" in spec:
resp["description"] = spec["description"]
if "meta" in spec:
for key in SUPPORTED_META:
value = spec["meta"].get(key)
if value:
resp[key] = value
if "allowed" in spec:
resp["enum"] = spec["allowed"]
if "default" in spec:
resp["default"] = spec["default"]
if "minlength" in spec:
if _type == "string":
resp["minLength"] = spec["minlength"]
elif _type == "list":
resp["minItems"] = spec["minlength"]
if "maxlength" in spec:
if _type == "string":
resp["maxLength"] = spec["maxlength"]
elif _type == "list":
resp["maxItems"] = spec["maxlength"]
if "min" in spec:
if _type in ["number", "integer", "float"]:
resp["minimum"] = spec["min"]
if "max" in spec:
if _type in ["number", "integer", "float"]:
resp["maximum"] = spec["max"]
if "readonly" in spec:
resp["readOnly"] = spec["readonly"]
if "regex" in spec:
resp["pattern"] = spec["regex"]
if "nullable" in spec:
resp["nullable"] = spec["nullable"]
if "allowed" in spec:
resp["enum"] = spec["allowed"]
json_type = type_map.get(_type, (_type,))
resp["type"] = json_type[0]
if json_type[0] == "object":
if "schema" in spec:
resp.update(cerberus_to_json(spec["schema"]))
additional_properties = {}
if "keysrules" in spec:
rule_value_type = spec["keysrules"].get("type", "string")
if rule_value_type != "string":
_logger.debug(
"Openapi only support key/value mapping definition where"
" the keys are strings. Received %s",
rule_value_type,
)
if "valuesrules" in spec:
values_rules = spec["valuesrules"]
rule_value_type = values_rules.get("type", "string")
additional_properties["type"] = rule_value_type
if "schema" in values_rules:
additional_properties.update(cerberus_to_json(values_rules["schema"]))
if additional_properties:
resp["additionalProperties"] = additional_properties
elif json_type[0] == "array":
if "schema" in spec:
resp["items"] = _get_field_props(spec["schema"])
else:
resp["items"] = {"type": "string"}
else:
try:
resp["format"] = json_type[1]
# pylint:disable=except-pass
except IndexError:
pass
return resp
def _inspect_methods(cls):
"""Return all methods of a given class as (name, value) pairs sorted by
name.
inspect.getmembers was initially used. Unfortunately, instance's properties
was accessed into the loop and could raise some exception since we are
into the startup process and all the resources are not yet initialized.
"""
results = []
for attribute in inspect.classify_class_attrs(cls):
if attribute.kind != "method":
continue
name = attribute.name
method = getattr(cls, name)
results.append((name, method))
results.sort(key=lambda pair: pair[0])
return results