forked from StackStorm/st2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
api_models.py
88 lines (69 loc) · 3.04 KB
/
api_models.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
# Copyright 2019 Extreme Networks, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Plugin which tells Pylint how to handle classes which define attributes using jsonschema
in "schema" class attribute.
Those classes dyamically assign attributes defined in the schema on the class inside the
constructor.
"""
import six
from astroid import MANAGER
from astroid import nodes
from astroid import scoped_nodes
# A list of class names for which we want to skip the checks
CLASS_NAME_BLACKLIST = [
'ExecutionSpecificationAPI'
]
def register(linter):
pass
def transform(cls):
if cls.name in CLASS_NAME_BLACKLIST:
return
if cls.name.endswith('API') or 'schema' in cls.locals:
# This is a class which defines attributes in "schema" variable using json schema.
# Those attributes are then assigned during run time inside the constructor
fqdn = cls.qname()
module_name, class_name = fqdn.rsplit('.', 1)
module = __import__(module_name, fromlist=[class_name])
actual_cls = getattr(module, class_name)
schema = actual_cls.schema
if not isinstance(schema, dict):
# Not a class we are interested in
return
properties = schema.get('properties', {})
for property_name, property_data in six.iteritems(properties):
property_name = property_name.replace('-', '_') # Note: We do the same in Python code
property_type = property_data.get('type', None)
if isinstance(property_type, (list, tuple)):
# Hack for attributes with multiple types (e.g. string, null)
property_type = property_type[0]
if property_type == 'object':
node = nodes.Dict()
elif property_type == 'array':
node = nodes.List()
elif property_type == 'integer':
node = scoped_nodes.builtin_lookup('int')[1][0]
elif property_type == 'number':
node = scoped_nodes.builtin_lookup('float')[1][0]
elif property_type == 'string':
node = scoped_nodes.builtin_lookup('str')[1][0]
elif property_type == 'boolean':
node = scoped_nodes.builtin_lookup('bool')[1][0]
elif property_type == 'null':
node = scoped_nodes.builtin_lookup('None')[1][0]
else:
# Unknown type
node = scoped_nodes.Class(property_name, None)
cls.locals[property_name] = [node]
MANAGER.register_transform(scoped_nodes.Class, transform)