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

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

Issue 11018003: Extensions Docs Server: Server code for showing properties of properties (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixes Created 8 years, 2 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 | Annotate | Revision Log
« no previous file with comments | « chrome/common/extensions/docs/server2/test_data/test_json/expected_test_file.json ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 copy 5 import copy
6 import os.path 6 import os.path
7 import re 7 import re
8 8
9 class ParseException(Exception): 9 class ParseException(Exception):
10 """Thrown when data in the model is invalid. 10 """Thrown when data in the model is invalid.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 - |functions| a map of function names to their model.Function 44 - |functions| a map of function names to their model.Function
45 - |events| a map of event names to their model.Function 45 - |events| a map of event names to their model.Function
46 - |properties| a map of property names to their model.Property 46 - |properties| a map of property names to their model.Property
47 """ 47 """
48 def __init__(self, json, source_file): 48 def __init__(self, json, source_file):
49 self.name = json['namespace'] 49 self.name = json['namespace']
50 self.unix_name = UnixName(self.name) 50 self.unix_name = UnixName(self.name)
51 self.source_file = source_file 51 self.source_file = source_file
52 self.source_file_dir, self.source_file_filename = os.path.split(source_file) 52 self.source_file_dir, self.source_file_filename = os.path.split(source_file)
53 self.parent = None 53 self.parent = None
54 _AddTypes(self, json) 54 _AddTypes(self, json, self)
55 _AddFunctions(self, json) 55 _AddFunctions(self, json, self)
56 _AddEvents(self, json) 56 _AddEvents(self, json, self)
57 _AddProperties(self, json) 57 _AddProperties(self, json, self)
58 58
59 class Type(object): 59 class Type(object):
60 """A Type defined in the json. 60 """A Type defined in the json.
61 61
62 Properties: 62 Properties:
63 - |name| the type name 63 - |name| the type name
64 - |description| the description of the type (if provided) 64 - |description| the description of the type (if provided)
65 - |properties| a map of property unix_names to their model.Property 65 - |properties| a map of property unix_names to their model.Property
66 - |functions| a map of function names to their model.Function 66 - |functions| a map of function names to their model.Function
67 - |events| a map of event names to their model.Event 67 - |events| a map of event names to their model.Event
68 - |from_client| indicates that instances of the Type can originate from the 68 - |from_client| indicates that instances of the Type can originate from the
69 users of generated code, such as top-level types and function results 69 users of generated code, such as top-level types and function results
70 - |from_json| indicates that instances of the Type can originate from the 70 - |from_json| indicates that instances of the Type can originate from the
71 JSON (as described by the schema), such as top-level types and function 71 JSON (as described by the schema), such as top-level types and function
72 parameters 72 parameters
73 - |type_| the PropertyType of this Type 73 - |type_| the PropertyType of this Type
74 - |item_type| if this is an array, the type of items in the array 74 - |item_type| if this is an array, the type of items in the array
75 - |simple_name| the name of this Type without a namespace
75 """ 76 """
76 def __init__(self, parent, name, json): 77 def __init__(self, parent, name, json, namespace):
77 if json.get('type') == 'array': 78 if json.get('type') == 'array':
78 self.type_ = PropertyType.ARRAY 79 self.type_ = PropertyType.ARRAY
79 self.item_type = Property(self, name + "Element", json['items'], 80 self.item_type = Property(self,
81 name + "Element",
82 json['items'],
83 namespace,
80 from_json=True, 84 from_json=True,
81 from_client=True) 85 from_client=True)
82 elif 'enum' in json: 86 elif 'enum' in json:
83 self.enum_values = [] 87 self.enum_values = []
84 for value in json['enum']: 88 for value in json['enum']:
85 self.enum_values.append(value) 89 self.enum_values.append(value)
86 self.type_ = PropertyType.ENUM 90 self.type_ = PropertyType.ENUM
87 elif json.get('type') == 'string': 91 elif json.get('type') == 'string':
88 self.type_ = PropertyType.STRING 92 self.type_ = PropertyType.STRING
89 else: 93 else:
90 if not ( 94 if not (
91 'properties' in json or 95 'properties' in json or
92 'additionalProperties' in json or 96 'additionalProperties' in json or
93 'functions' in json or 97 'functions' in json or
94 'events' in json): 98 'events' in json):
95 raise ParseException(self, name + " has no properties or functions") 99 raise ParseException(self, name + " has no properties or functions")
96 self.type_ = PropertyType.OBJECT 100 self.type_ = PropertyType.OBJECT
97 self.name = name 101 self.name = name
102 self.simple_name = _StripNamespace(self.name, namespace)
98 self.unix_name = UnixName(self.name) 103 self.unix_name = UnixName(self.name)
99 self.description = json.get('description') 104 self.description = json.get('description')
100 self.from_json = True 105 self.from_json = True
101 self.from_client = True 106 self.from_client = True
102 self.parent = parent 107 self.parent = parent
103 self.instance_of = json.get('isInstanceOf', None) 108 self.instance_of = json.get('isInstanceOf', None)
104 _AddFunctions(self, json) 109 _AddFunctions(self, json, namespace)
105 _AddEvents(self, json) 110 _AddEvents(self, json, namespace)
106 _AddProperties(self, json, from_json=True, from_client=True) 111 _AddProperties(self, json, namespace, from_json=True, from_client=True)
107 112
108 additional_properties_key = 'additionalProperties' 113 additional_properties_key = 'additionalProperties'
109 additional_properties = json.get(additional_properties_key) 114 additional_properties = json.get(additional_properties_key)
110 if additional_properties: 115 if additional_properties:
111 self.properties[additional_properties_key] = Property( 116 self.properties[additional_properties_key] = Property(
112 self, 117 self,
113 additional_properties_key, 118 additional_properties_key,
114 additional_properties, 119 additional_properties,
120 namespace,
115 is_additional_properties=True) 121 is_additional_properties=True)
116 122
117 class Function(object): 123 class Function(object):
118 """A Function defined in the API. 124 """A Function defined in the API.
119 125
120 Properties: 126 Properties:
121 - |name| the function name 127 - |name| the function name
122 - |params| a list of parameters to the function (order matters). A separate 128 - |params| a list of parameters to the function (order matters). A separate
123 parameter is used for each choice of a 'choices' parameter. 129 parameter is used for each choice of a 'choices' parameter.
124 - |description| a description of the function (if provided) 130 - |description| a description of the function (if provided)
125 - |callback| the callback parameter to the function. There should be exactly 131 - |callback| the callback parameter to the function. There should be exactly
126 one 132 one
127 - |optional| whether the Function is "optional"; this only makes sense to be 133 - |optional| whether the Function is "optional"; this only makes sense to be
128 present when the Function is representing a callback property. 134 present when the Function is representing a callback property.
135 - |simple_name| the name of this Function without a namespace
129 """ 136 """
130 def __init__(self, parent, json, from_json=False, from_client=False): 137 def __init__(self,
138 parent,
139 json,
140 namespace,
141 from_json=False,
142 from_client=False):
131 self.name = json['name'] 143 self.name = json['name']
144 self.simple_name = _StripNamespace(self.name, namespace)
132 self.params = [] 145 self.params = []
133 self.description = json.get('description') 146 self.description = json.get('description')
134 self.callback = None 147 self.callback = None
135 self.optional = json.get('optional', False) 148 self.optional = json.get('optional', False)
136 self.parent = parent 149 self.parent = parent
137 self.nocompile = json.get('nocompile') 150 self.nocompile = json.get('nocompile')
138 options = json.get('options', {}) 151 options = json.get('options', {})
139 self.conditions = options.get('conditions', []) 152 self.conditions = options.get('conditions', [])
140 self.actions = options.get('actions', []) 153 self.actions = options.get('actions', [])
141 self.supports_listeners = options.get('supportsListeners', True) 154 self.supports_listeners = options.get('supportsListeners', True)
142 self.supports_rules = options.get('supportsRules', False) 155 self.supports_rules = options.get('supportsRules', False)
143 def GeneratePropertyFromParam(p): 156 def GeneratePropertyFromParam(p):
144 return Property(self, 157 return Property(self,
145 p['name'], p, 158 p['name'], p,
159 namespace,
146 from_json=from_json, 160 from_json=from_json,
147 from_client=from_client) 161 from_client=from_client)
148 162
149 self.filters = [GeneratePropertyFromParam(filter) 163 self.filters = [GeneratePropertyFromParam(filter)
150 for filter in json.get('filters', [])] 164 for filter in json.get('filters', [])]
151 callback_param = None 165 callback_param = None
152 for param in json.get('parameters', []): 166 for param in json.get('parameters', []):
153 167
154 if param.get('type') == 'function': 168 if param.get('type') == 'function':
155 if callback_param: 169 if callback_param:
156 # No ParseException because the webstore has this. 170 # No ParseException because the webstore has this.
157 # Instead, pretend all intermediate callbacks are properties. 171 # Instead, pretend all intermediate callbacks are properties.
158 self.params.append(GeneratePropertyFromParam(callback_param)) 172 self.params.append(GeneratePropertyFromParam(callback_param))
159 callback_param = param 173 callback_param = param
160 else: 174 else:
161 self.params.append(GeneratePropertyFromParam(param)) 175 self.params.append(GeneratePropertyFromParam(param))
162 176
163 if callback_param: 177 if callback_param:
164 self.callback = Function(self, callback_param, from_client=True) 178 self.callback = Function(self,
179 callback_param,
180 namespace,
181 from_client=True)
165 182
166 self.returns = None 183 self.returns = None
167 if 'returns' in json: 184 if 'returns' in json:
168 self.returns = Property(self, 'return', json['returns']) 185 self.returns = Property(self, 'return', json['returns'], namespace)
169 186
170 class Property(object): 187 class Property(object):
171 """A property of a type OR a parameter to a function. 188 """A property of a type OR a parameter to a function.
172 189
173 Properties: 190 Properties:
174 - |name| name of the property as in the json. This shouldn't change since 191 - |name| name of the property as in the json. This shouldn't change since
175 it is the key used to access DictionaryValues 192 it is the key used to access DictionaryValues
176 - |unix_name| the unix_style_name of the property. Used as variable name 193 - |unix_name| the unix_style_name of the property. Used as variable name
177 - |optional| a boolean representing whether the property is optional 194 - |optional| a boolean representing whether the property is optional
178 - |description| a description of the property (if provided) 195 - |description| a description of the property (if provided)
179 - |type_| the model.PropertyType of this property 196 - |type_| the model.PropertyType of this property
180 - |compiled_type| the model.PropertyType that this property should be 197 - |compiled_type| the model.PropertyType that this property should be
181 compiled to from the JSON. Defaults to |type_|. 198 compiled to from the JSON. Defaults to |type_|.
182 - |ref_type| the type that the REF property is referencing. Can be used to 199 - |ref_type| the type that the REF property is referencing. Can be used to
183 map to its model.Type 200 map to its model.Type
184 - |item_type| a model.Property representing the type of each element in an 201 - |item_type| a model.Property representing the type of each element in an
185 ARRAY 202 ARRAY
186 - |properties| the properties of an OBJECT parameter 203 - |properties| the properties of an OBJECT parameter
187 - |from_client| indicates that instances of the Type can originate from the 204 - |from_client| indicates that instances of the Type can originate from the
188 users of generated code, such as top-level types and function results 205 users of generated code, such as top-level types and function results
189 - |from_json| indicates that instances of the Type can originate from the 206 - |from_json| indicates that instances of the Type can originate from the
190 JSON (as described by the schema), such as top-level types and function 207 JSON (as described by the schema), such as top-level types and function
191 parameters 208 parameters
209 - |simple_name| the name of this Property without a namespace
192 """ 210 """
193 211
194 def __init__(self, parent, name, json, is_additional_properties=False, 212 def __init__(self,
195 from_json=False, from_client=False): 213 parent,
214 name,
215 json,
216 namespace,
217 is_additional_properties=False,
218 from_json=False,
219 from_client=False):
196 self.name = name 220 self.name = name
221 self.simple_name = _StripNamespace(self.name, namespace)
197 self._unix_name = UnixName(self.name) 222 self._unix_name = UnixName(self.name)
198 self._unix_name_used = False 223 self._unix_name_used = False
199 self.optional = json.get('optional', False) 224 self.optional = json.get('optional', False)
200 self.functions = {} 225 self.functions = {}
201 self.has_value = False 226 self.has_value = False
202 self.description = json.get('description') 227 self.description = json.get('description')
203 self.parent = parent 228 self.parent = parent
204 self.from_json = from_json 229 self.from_json = from_json
205 self.from_client = from_client 230 self.from_client = from_client
206 self.instance_of = json.get('isInstanceOf', None) 231 self.instance_of = json.get('isInstanceOf', None)
207 _AddProperties(self, json) 232 _AddProperties(self, json, namespace)
208 if is_additional_properties: 233 if is_additional_properties:
209 self.type_ = PropertyType.ADDITIONAL_PROPERTIES 234 self.type_ = PropertyType.ADDITIONAL_PROPERTIES
210 elif '$ref' in json: 235 elif '$ref' in json:
211 self.ref_type = json['$ref'] 236 self.ref_type = json['$ref']
212 self.type_ = PropertyType.REF 237 self.type_ = PropertyType.REF
213 elif 'enum' in json and json.get('type') == 'string': 238 elif 'enum' in json and json.get('type') == 'string':
214 # Non-string enums (as in the case of [legalValues=(1,2)]) should fall 239 # Non-string enums (as in the case of [legalValues=(1,2)]) should fall
215 # through to the next elif. 240 # through to the next elif.
216 self.enum_values = [] 241 self.enum_values = []
217 for value in json['enum']: 242 for value in json['enum']:
218 self.enum_values.append(value) 243 self.enum_values.append(value)
219 self.type_ = PropertyType.ENUM 244 self.type_ = PropertyType.ENUM
220 elif 'type' in json: 245 elif 'type' in json:
221 self.type_ = self._JsonTypeToPropertyType(json['type']) 246 self.type_ = self._JsonTypeToPropertyType(json['type'])
222 if self.type_ == PropertyType.ARRAY: 247 if self.type_ == PropertyType.ARRAY:
223 self.item_type = Property(self, name + "Element", json['items'], 248 self.item_type = Property(self,
224 from_json=from_json, 249 name + "Element",
225 from_client=from_client) 250 json['items'],
251 namespace,
252 from_json=from_json,
253 from_client=from_client)
226 elif self.type_ == PropertyType.OBJECT: 254 elif self.type_ == PropertyType.OBJECT:
227 # These members are read when this OBJECT Property is used as a Type 255 # These members are read when this OBJECT Property is used as a Type
228 type_ = Type(self, self.name, json) 256 type_ = Type(self, self.name, json, namespace)
229 # self.properties will already have some value from |_AddProperties|. 257 # self.properties will already have some value from |_AddProperties|.
230 self.properties.update(type_.properties) 258 self.properties.update(type_.properties)
231 self.functions = type_.functions 259 self.functions = type_.functions
232 elif 'choices' in json: 260 elif 'choices' in json:
233 if not json['choices'] or len(json['choices']) == 0: 261 if not json['choices'] or len(json['choices']) == 0:
234 raise ParseException(self, 'Choices has no choices') 262 raise ParseException(self, 'Choices has no choices')
235 self.choices = {} 263 self.choices = {}
236 self.type_ = PropertyType.CHOICES 264 self.type_ = PropertyType.CHOICES
237 self.compiled_type = self.type_ 265 self.compiled_type = self.type_
238 for choice_json in json['choices']: 266 for choice_json in json['choices']:
239 choice = Property(self, self.name, choice_json, 267 choice = Property(self,
240 from_json=from_json, 268 self.name,
241 from_client=from_client) 269 choice_json,
270 namespace,
271 from_json=from_json,
272 from_client=from_client)
242 choice.unix_name = UnixName(self.name + choice.type_.name) 273 choice.unix_name = UnixName(self.name + choice.type_.name)
243 # The existence of any single choice is optional 274 # The existence of any single choice is optional
244 choice.optional = True 275 choice.optional = True
245 self.choices[choice.type_] = choice 276 self.choices[choice.type_] = choice
246 elif 'value' in json: 277 elif 'value' in json:
247 self.has_value = True 278 self.has_value = True
248 self.value = json['value'] 279 self.value = json['value']
249 if type(self.value) == int: 280 if type(self.value) == int:
250 self.type_ = PropertyType.INTEGER 281 self.type_ = PropertyType.INTEGER
251 self.compiled_type = self.type_ 282 self.compiled_type = self.type_
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 def UnixName(name): 377 def UnixName(name):
347 """Returns the unix_style name for a given lowerCamelCase string. 378 """Returns the unix_style name for a given lowerCamelCase string.
348 """ 379 """
349 # First replace any lowerUpper patterns with lower_Upper. 380 # First replace any lowerUpper patterns with lower_Upper.
350 s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name) 381 s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name)
351 # Now replace any ACMEWidgets patterns with ACME_Widgets 382 # Now replace any ACMEWidgets patterns with ACME_Widgets
352 s2 = re.sub('([A-Z]+)([A-Z][a-z])', r'\1_\2', s1) 383 s2 = re.sub('([A-Z]+)([A-Z][a-z])', r'\1_\2', s1)
353 # Finally, replace any remaining periods, and make lowercase. 384 # Finally, replace any remaining periods, and make lowercase.
354 return s2.replace('.', '_').lower() 385 return s2.replace('.', '_').lower()
355 386
387 def _StripNamespace(name, namespace):
388 if name.startswith(namespace.name + '.'):
389 return name[len(namespace.name + '.'):]
390 return name
391
356 def _GetModelHierarchy(entity): 392 def _GetModelHierarchy(entity):
357 """Returns the hierarchy of the given model entity.""" 393 """Returns the hierarchy of the given model entity."""
358 hierarchy = [] 394 hierarchy = []
359 while entity: 395 while entity:
360 try: 396 try:
361 hierarchy.append(entity.name) 397 hierarchy.append(entity.name)
362 except AttributeError: 398 except AttributeError:
363 hierarchy.append(repr(entity)) 399 hierarchy.append(repr(entity))
364 entity = entity.parent 400 entity = entity.parent
365 hierarchy.reverse() 401 hierarchy.reverse()
366 return hierarchy 402 return hierarchy
367 403
368 def _AddTypes(model, json): 404 def _AddTypes(model, json, namespace):
369 """Adds Type objects to |model| contained in the 'types' field of |json|. 405 """Adds Type objects to |model| contained in the 'types' field of |json|.
370 """ 406 """
371 model.types = {} 407 model.types = {}
372 for type_json in json.get('types', []): 408 for type_json in json.get('types', []):
373 type_ = Type(model, type_json['id'], type_json) 409 type_ = Type(model, type_json['id'], type_json, namespace)
374 model.types[type_.name] = type_ 410 model.types[type_.name] = type_
375 411
376 def _AddFunctions(model, json): 412 def _AddFunctions(model, json, namespace):
377 """Adds Function objects to |model| contained in the 'functions' field of 413 """Adds Function objects to |model| contained in the 'functions' field of
378 |json|. 414 |json|.
379 """ 415 """
380 model.functions = {} 416 model.functions = {}
381 for function_json in json.get('functions', []): 417 for function_json in json.get('functions', []):
382 function = Function(model, function_json, from_json=True) 418 function = Function(model, function_json, namespace, from_json=True)
383 model.functions[function.name] = function 419 model.functions[function.name] = function
384 420
385 def _AddEvents(model, json): 421 def _AddEvents(model, json, namespace):
386 """Adds Function objects to |model| contained in the 'events' field of |json|. 422 """Adds Function objects to |model| contained in the 'events' field of |json|.
387 """ 423 """
388 model.events = {} 424 model.events = {}
389 for event_json in json.get('events', []): 425 for event_json in json.get('events', []):
390 event = Function(model, event_json, from_client=True) 426 event = Function(model, event_json, namespace, from_client=True)
391 model.events[event.name] = event 427 model.events[event.name] = event
392 428
393 def _AddProperties(model, json, from_json=False, from_client=False): 429 def _AddProperties(model,
430 json,
431 namespace,
432 from_json=False,
433 from_client=False):
394 """Adds model.Property objects to |model| contained in the 'properties' field 434 """Adds model.Property objects to |model| contained in the 'properties' field
395 of |json|. 435 of |json|.
396 """ 436 """
397 model.properties = {} 437 model.properties = {}
398 for name, property_json in json.get('properties', {}).items(): 438 for name, property_json in json.get('properties', {}).items():
399 model.properties[name] = Property( 439 model.properties[name] = Property(
400 model, 440 model,
401 name, 441 name,
402 property_json, 442 property_json,
443 namespace,
403 from_json=from_json, 444 from_json=from_json,
404 from_client=from_client) 445 from_client=from_client)
OLDNEW
« no previous file with comments | « chrome/common/extensions/docs/server2/test_data/test_json/expected_test_file.json ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698