Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(430)

Side by Side Diff: tools/json_schema_compiler/model.py

Issue 9309044: Supporting more APIs with json_schema_compiler (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: rework Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import os.path 5 import os.path
6 import re
6 7
7 class Model(object): 8 class Model(object):
8 """Model of all namespaces that comprise an API. 9 """Model of all namespaces that comprise an API.
10
11 Properties:
12 - |namespaces| a map of a namespace name to its model.Namespace
9 """ 13 """
10 def __init__(self): 14 def __init__(self):
11 self.namespaces = {} 15 self.namespaces = {}
12 16
13 def AddNamespace(self, json, source_file): 17 def AddNamespace(self, json, source_file):
14 """Add a namespace's json to the model if it has a "compile" property set 18 """Add a namespace's json to the model if it doesn't have "nocompile"
15 to true. Returns the new namespace or None if a namespace wasn't added. 19 property set to true. Returns the new namespace or None if a namespace
20 wasn't added.
16 """ 21 """
17 if not json.get('compile'): 22 if json.get('nocompile', False):
18 return None 23 return None
19 namespace = Namespace(json, source_file) 24 namespace = Namespace(json, source_file)
20 self.namespaces[namespace.name] = namespace 25 self.namespaces[namespace.name] = namespace
21 return namespace 26 return namespace
22 27
23 class Namespace(object): 28 class Namespace(object):
24 """An API namespace. 29 """An API namespace.
30
31 Properties:
32 - |name| the name of the namespace
33 - |source_file| the file that contained the namespace definition
34 - |source_file_dir| the directory component of |source_file|
35 - |source_file_filename| the filename component of |source_file|
36 - |types| a map of type names to their model.Type
37 - |functions| a map of function names to their model.Function
25 """ 38 """
26 def __init__(self, json, source_file): 39 def __init__(self, json, source_file):
27 self.name = json['namespace'] 40 self.name = json['namespace']
28 self.source_file = source_file 41 self.source_file = source_file
29 self.source_file_dir, self.source_file_filename = os.path.split(source_file) 42 self.source_file_dir, self.source_file_filename = os.path.split(source_file)
30 self.type_dependencies = {}
31 self.types = {} 43 self.types = {}
32 self.functions = {} 44 self.functions = {}
33 for type_json in json['types']: 45 for type_json in json['types']:
34 type_ = Type(type_json) 46 type_ = Type(type_json)
35 self.types[type_.name] = type_ 47 self.types[type_.name] = type_
36 for function_json in json['functions']: 48 for function_json in json['functions']:
37 if not function_json.get('nocompile'): 49 if not function_json.get('nocompile', False):
38 function = Function(function_json) 50 function = Function(function_json)
39 self.functions[function.name] = function 51 self.functions[function.name] = function
40 52
41 class Type(object): 53 class Type(object):
42 """A Type defined in the json. 54 """A Type defined in the json.
55
56 Properties:
57 - |name| the type name
58 - |description| the description of the type (if provided)
59 - |properties| a map of property names to their model.Property
43 """ 60 """
44 def __init__(self, json): 61 def __init__(self, json):
45 self.name = json['id'] 62 self.name = json['id']
46 self.description = json.get('description') 63 self.description = json.get('description')
47 self.properties = {} 64 self.properties = {}
65 properties = json.get('properties')
48 for prop_name, prop_json in json['properties'].items(): 66 for prop_name, prop_json in json['properties'].items():
49 self.properties[prop_name] = Property(prop_name, prop_json) 67 self.properties[prop_name] = Property(prop_name, prop_json)
50 68
51 class Callback(object): 69 class Callback(object):
52 """A callback parameter to a Function. 70 """A callback parameter to a Function.
71
72 Properties:
73 - |params| the parameters to this callback. There should only be one unless
74 the parameter is of type 'choices' in which case each choice is processed
75 as a separate parameter
53 """ 76 """
54 def __init__(self, json): 77 def __init__(self, json):
55 params = json['parameters'] 78 params = json['parameters']
79 self.params = []
56 if len(params) == 0: 80 if len(params) == 0:
57 self.param = None 81 return
58 elif len(params) == 1: 82 elif len(params) == 1:
59 param = params[0] 83 param = params[0]
60 self.param = Property(param['name'], param) 84 if param.get('choices'):
85 for choice in param['choices']:
86 self.params.append(_Choice('callback', choice))
87 else:
88 self.params.append(Property(param['name'], param))
61 else: 89 else:
62 raise AssertionError("Callbacks can have at most a single parameter") 90 raise AssertionError("Callbacks can have at most a single parameter")
63 91
64 class Function(object): 92 class Function(object):
65 """A Function defined in the API. 93 """A Function defined in the API.
94
95 Properties:
96 - |name| the function name
97 - |params| a list of parameters to the function (order matters). A separate
98 parameter is used for each choice of a 'choices' parameter.
99 - |description| a description of the function (if provided)
100 - |callback| the callback parameter to the function. There should be exactly
101 one
66 """ 102 """
67 def __init__(self, json): 103 def __init__(self, json):
68 self.name = json['name'] 104 self.name = json['name']
69 self.params = [] 105 self.params = []
70 self.description = json['description'] 106 self.description = json['description']
71 self.callback = None 107 self.callback = None
72 self.type_dependencies = {}
73 for param in json['parameters']: 108 for param in json['parameters']:
74 if param.get('type') == 'function': 109 if param.get('type') == 'function':
75 assert (not self.callback), "Function has more than one callback" 110 assert (not self.callback), self.name + " has more than one callback"
76 self.callback = Callback(param) 111 self.callback = Callback(param)
112 elif param.get('choices'):
113 for choice in param['choices']:
114 self.params.append(_Choice(self.name, choice))
77 else: 115 else:
78 self.params.append(Property(param['name'], param)) 116 self.params.append(Property(param['name'], param))
79 assert (self.callback), "Function does not support callback" 117 assert (self.callback), self.name + " does not support callback"
80 118
81 # TODO(calamity): handle Enum/choices 119 # TODO(calamity): handle Enum
82 class Property(object): 120 class Property(object):
83 """A property of a type OR a parameter to a function. 121 """A property of a type OR a parameter to a function.
84 122
85 Members will change based on PropertyType. Check self.type_ to determine which 123 Properties:
86 members actually exist. 124 - |name| name of the property as in the json
125 - |unix_name| the unix_style_name of the property
126 - |optional| a boolean representing whether the property is optional
127 - |description| a description of the property (if provided)
128 - |type_| the model.PropertyType of this property
129 - |ref_type| the type that the REF property is referencing. Can be used to map to
130 its model.Type
not at google - send to devlin 2012/02/06 13:14:48 line wrap
calamity 2012/02/08 00:52:31 Done.
131 - |item_type| a model.Property representing the type of each element in an
132 ARRAY
133 - |properties| the properties of an OBJECT parameter
87 """ 134 """
88 def __init__(self, name, json): 135 def __init__(self, name, json, unix_name=None, is_choice=False):
136 if not re.match('^[a-z][a-zA-Z0-9]*$', name):
137 raise AssertionError('Name %s must be lowerCamelCase' % name)
89 self.name = name 138 self.name = name
139 self.unix_name = unix_name
140 self.is_choice = is_choice
141 if not self.unix_name:
142 self.unix_name = _UnixName(self.name)
90 self.optional = json.get('optional', False) 143 self.optional = json.get('optional', False)
91 self.description = json.get('description') 144 self.description = json.get('description')
92 # TODO(calamity) maybe check for circular refs? could that be a problem?
93 if '$ref' in json: 145 if '$ref' in json:
94 self.ref_type = json['$ref'] 146 self.ref_type = json['$ref']
95 self.type_ = PropertyType.REF 147 self.type_ = PropertyType.REF
96 elif 'type' in json: 148 elif 'type' in json:
97 json_type = json['type'] 149 json_type = json['type']
98 if json_type == 'string': 150 if json_type == 'string':
99 self.type_ = PropertyType.STRING 151 self.type_ = PropertyType.STRING
100 elif json_type == 'boolean': 152 elif json_type == 'any':
153 self.type_ = PropertyType.ANY
154 elif json_type == 'boolean':
101 self.type_ = PropertyType.BOOLEAN 155 self.type_ = PropertyType.BOOLEAN
102 elif json_type == 'integer': 156 elif json_type == 'integer':
103 self.type_ = PropertyType.INTEGER 157 self.type_ = PropertyType.INTEGER
104 elif json_type == 'double': 158 elif json_type == 'number':
105 self.type_ = PropertyType.DOUBLE 159 self.type_ = PropertyType.DOUBLE
106 elif json_type == 'array': 160 elif json_type == 'array':
107 self.item_type = Property(name + "_inner", json['items']) 161 self.item_type = Property(name + "Element", json['items'])
108 self.type_ = PropertyType.ARRAY 162 self.type_ = PropertyType.ARRAY
109 elif json_type == 'object': 163 elif json_type == 'object':
110 self.properties = {} 164 self.properties = {}
111 self.type_ = PropertyType.OBJECT 165 self.type_ = PropertyType.OBJECT
112 for key, val in json['properties'].items(): 166 for key, val in json['properties'].items():
113 self.properties[key] = Property(key, val) 167 if 'choices' in val:
168 for choice in val['choices']:
169 choice_property = _Choice(self.name, choice)
170 self.properties[choice_property.name] = choice_property
171 else:
172 self.properties[key] = Property(key, val)
114 else: 173 else:
115 raise NotImplementedError(json_type) 174 raise NotImplementedError(json_type)
116 elif 'choices' in json: 175 else:
117 self.type_ = PropertyType.CHOICES 176 raise NotImplementedError(json)
118 self.choices = {}
119 177
120 class PropertyType(object): 178 class PropertyType(object):
121 """Enum of different types of properties/parameters. 179 """Enum of different types of properties/parameters.
122 """ 180 """
123 class _Info(object): 181 class _Info(object):
124 def __init__(self, is_fundamental): 182 def __init__(self, is_fundamental, name):
125 self.is_fundamental = is_fundamental 183 self.is_fundamental = is_fundamental
184 self.name = name
126 185
127 INTEGER = _Info(True) 186 def __repr__(self):
128 DOUBLE = _Info(True) 187 return self.name
129 BOOLEAN = _Info(True) 188
130 STRING = _Info(True) 189 INTEGER = _Info(True, "INTEGER")
131 ARRAY = _Info(False) 190 DOUBLE = _Info(True, "DOUBLE")
132 REF = _Info(False) 191 BOOLEAN = _Info(True, "BOOLEAN")
133 CHOICES = _Info(False) 192 STRING = _Info(True, "STRING")
134 OBJECT = _Info(False) 193 ARRAY = _Info(False, "ARRAY")
194 REF = _Info(False, "REF")
195 CHOICE = _Info(False, "CHOICE")
196 OBJECT = _Info(False, "OBJECT")
197 ANY = _Info(False, "ANY")
198
199 def _UnixName(name):
200 """Returns the unix_style name for a given string.
201 """
202 return '_'.join([x.lower()
203 for x in re.findall('[A-Z][a-z_]*', name[0].upper() + name[1:])])
204
205 def _Choice(name, json):
not at google - send to devlin 2012/02/06 13:14:48 I made a comment here earlier about structuring th
not at google - send to devlin 2012/02/06 13:25:34 Sorry, I should have said an array of possible Pro
calamity 2012/02/08 00:52:31 Done.
206 """Creates a Property for an item under 'choices' in the json.
207 """
208 raise NotImplementedError('%s\nChoices is not fully implemented' % json)
not at google - send to devlin 2012/02/06 13:14:48 Choices is implemented for return values right? O
calamity 2012/02/08 00:52:31 It's done now, but I thought it made sense to disa
209 property_type = json.get('type')
210 if not property_type:
211 property_type = json['$ref'].lower()
212 if not property_type:
213 raise NotImplementedError(json)
214 # Append choice type to the unix_name
215 return Property(name, json, is_choice=True,
216 unix_name=_UnixName('%s%s' %
217 (name, property_type[0].upper() + property_type[1:]))
218 )
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698