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