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 from json_parse import OrderedDict | 9 from json_parse import OrderedDict |
| 10 | 10 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 - |functions| a map of function names to their model.Function | 46 - |functions| a map of function names to their model.Function |
| 47 - |events| a map of event names to their model.Function | 47 - |events| a map of event names to their model.Function |
| 48 - |properties| a map of property names to their model.Property | 48 - |properties| a map of property names to their model.Property |
| 49 """ | 49 """ |
| 50 def __init__(self, json, source_file): | 50 def __init__(self, json, source_file): |
| 51 self.name = json['namespace'] | 51 self.name = json['namespace'] |
| 52 self.unix_name = UnixName(self.name) | 52 self.unix_name = UnixName(self.name) |
| 53 self.source_file = source_file | 53 self.source_file = source_file |
| 54 self.source_file_dir, self.source_file_filename = os.path.split(source_file) | 54 self.source_file_dir, self.source_file_filename = os.path.split(source_file) |
| 55 self.parent = None | 55 self.parent = None |
| 56 _AddTypes(self, json, self) | 56 self.types = _GetTypes( |
| 57 _AddFunctions(self, json, self) | 57 self, json, self, Origin(from_client=True, from_json=True)) |
| 58 _AddEvents(self, json, self) | 58 self.functions = _GetFunctions(self, json, self) |
| 59 _AddProperties(self, json, self) | 59 self.events = _GetEvents(self, json, self) |
| 60 self.properties = _GetProperties(self, json, self, Origin()) | |
| 61 | |
| 62 class Origin(object): | |
| 63 """Stores the origin of model object as a pair of bools. These are: | |
|
Yoyo Zhou
2013/01/15 01:49:25
possible origin?
not at google - send to devlin
2013/01/15 21:47:27
Done.
| |
| 64 | |
| 65 |from_client| indicating that instances will originate from users of | |
|
Yoyo Zhou
2013/01/15 01:49:25
s/will/can/?
not at google - send to devlin
2013/01/15 21:47:27
Done.
| |
| 66 generated code (for example, function results), or | |
| 67 |from_json| indicating that instances can originate from the JSON (for | |
| 68 example, function parameters) | |
| 69 | |
| 70 It is possible for model objects to originate from both the client and json, | |
| 71 for example Types defined in the top-level schema, in which case both | |
| 72 |from_client| and |from_json| would be True. | |
|
Yoyo Zhou
2013/01/15 01:49:25
And what does it mean if both are false?
not at google - send to devlin
2013/01/15 21:47:27
Error. Done.
| |
| 73 """ | |
| 74 def __init__(self, from_client=False, from_json=False): | |
| 75 self.from_client = from_client | |
| 76 self.from_json = from_json | |
| 60 | 77 |
| 61 class Type(object): | 78 class Type(object): |
| 62 """A Type defined in the json. | 79 """A Type defined in the json. |
| 63 | 80 |
| 64 Properties: | 81 Properties: |
| 65 - |name| the type name | 82 - |name| the type name |
| 83 - |namespace| the Type's namespace | |
| 66 - |description| the description of the type (if provided) | 84 - |description| the description of the type (if provided) |
| 67 - |properties| a map of property unix_names to their model.Property | 85 - |properties| a map of property unix_names to their model.Property |
| 68 - |functions| a map of function names to their model.Function | 86 - |functions| a map of function names to their model.Function |
| 69 - |events| a map of event names to their model.Event | 87 - |events| a map of event names to their model.Event |
| 70 - |from_client| indicates that instances of the Type can originate from the | 88 - |origin| the Origin of the type |
| 71 users of generated code, such as top-level types and function results | 89 - |property_type| the PropertyType of this Type |
| 72 - |from_json| indicates that instances of the Type can originate from the | |
| 73 JSON (as described by the schema), such as top-level types and function | |
| 74 parameters | |
| 75 - |type_| the PropertyType of this Type | |
| 76 - |item_type| if this is an array, the type of items in the array | 90 - |item_type| if this is an array, the type of items in the array |
| 77 - |simple_name| the name of this Type without a namespace | 91 - |simple_name| the name of this Type without a namespace |
| 92 - |additional_properties| the type of the additional properties, if any is | |
| 93 specified | |
| 78 """ | 94 """ |
| 79 def __init__(self, parent, name, json, namespace): | 95 def __init__(self, |
| 80 if json.get('type') == 'array': | 96 parent, |
| 81 self.type_ = PropertyType.ARRAY | 97 name, |
| 82 self.item_type = Property(self, | 98 json, |
| 83 name + "Element", | 99 namespace, |
| 84 json['items'], | 100 origin): |
| 85 namespace, | 101 self.name = name |
| 86 from_json=True, | 102 self.namespace = namespace |
| 87 from_client=True) | 103 self.simple_name = _StripNamespace(self.name, namespace) |
| 88 elif 'enum' in json: | 104 self.unix_name = UnixName(self.name) |
| 89 self.enum_values = [] | 105 self.description = json.get('description', None) |
| 90 for value in json['enum']: | 106 self.origin = origin |
| 91 self.enum_values.append(value) | 107 self.parent = parent |
| 92 self.type_ = PropertyType.ENUM | 108 self.instance_of = json.get('isInstanceOf', None) |
| 93 elif json.get('type') == 'string': | 109 |
| 94 self.type_ = PropertyType.STRING | 110 # TODO(kalman): Only objects need functions/events/properties, but callers |
| 95 else: | 111 # assume that all types have them. Fix this. |
| 112 self.functions = _GetFunctions(self, json, namespace) | |
| 113 self.events = _GetEvents(self, json, namespace) | |
| 114 self.properties = _GetProperties(self, json, namespace, origin) | |
| 115 | |
| 116 json_type = json.get('type', None) | |
| 117 if json_type == 'array': | |
| 118 self.property_type = PropertyType.ARRAY | |
| 119 self.item_type = Type( | |
| 120 self, '%sType' % name, json['items'], namespace, origin) | |
| 121 elif '$ref' in json: | |
| 122 self.property_type = PropertyType.REF | |
| 123 self.ref_type = json['$ref'] | |
| 124 elif 'enum' in json and json_type == 'string': | |
| 125 self.property_type = PropertyType.ENUM | |
| 126 self.enum_values = [value for value in json['enum']] | |
| 127 elif json_type == 'any': | |
| 128 self.property_type = PropertyType.ANY | |
| 129 elif json_type == 'binary': | |
| 130 self.property_type = PropertyType.BINARY | |
| 131 elif json_type == 'boolean': | |
| 132 self.property_type = PropertyType.BOOLEAN | |
| 133 elif json_type == 'integer': | |
| 134 self.property_type = PropertyType.INTEGER | |
| 135 elif (json_type == 'double' or | |
| 136 json_type == 'number'): | |
| 137 self.property_type = PropertyType.DOUBLE | |
| 138 elif json_type == 'string': | |
| 139 self.property_type = PropertyType.STRING | |
| 140 elif 'choices' in json: | |
| 141 self.property_type = PropertyType.CHOICES | |
| 142 self.choices = [Type(self, | |
| 143 # The name of the choice type - there had better be | |
| 144 # either a type or a $ref specified for the choice. | |
| 145 json.get('type', json.get('$ref')), | |
| 146 json, | |
| 147 namespace, | |
| 148 origin) | |
| 149 for json in json['choices']] | |
| 150 elif json_type == 'object': | |
| 96 if not ( | 151 if not ( |
| 97 'properties' in json or | 152 'properties' in json or |
| 98 'additionalProperties' in json or | 153 'additionalProperties' in json or |
| 99 'functions' in json or | 154 'functions' in json or |
| 100 'events' in json): | 155 'events' in json): |
| 101 raise ParseException(self, name + " has no properties or functions") | 156 raise ParseException(self, name + " has no properties or functions") |
| 102 self.type_ = PropertyType.OBJECT | 157 self.property_type = PropertyType.OBJECT |
| 103 self.name = name | 158 additional_properties_json = json.get('additionalProperties', None) |
| 104 self.simple_name = _StripNamespace(self.name, namespace) | 159 if additional_properties_json is not None: |
| 105 self.unix_name = UnixName(self.name) | 160 self.additional_properties = Type(self, |
| 106 self.description = json.get('description') | 161 'additionalProperties', |
| 107 self.from_json = True | 162 additional_properties_json, |
| 108 self.from_client = True | 163 namespace, |
| 109 self.parent = parent | 164 origin) |
| 110 self.instance_of = json.get('isInstanceOf', None) | 165 else: |
| 111 _AddFunctions(self, json, namespace) | 166 self.additional_properties = None |
| 112 _AddEvents(self, json, namespace) | 167 elif json_type == 'function': |
| 113 _AddProperties(self, json, namespace, from_json=True, from_client=True) | 168 self.property_type = PropertyType.FUNCTION |
| 114 | 169 # Sometimes we might have an unnamed function, e.g. if it's a property |
| 115 additional_properties_key = 'additionalProperties' | 170 # of an object. Use the name of the property in that case. |
| 116 additional_properties = json.get(additional_properties_key) | 171 function_name = json.get('name', name) |
| 117 if additional_properties: | 172 self.function = Function(self, function_name, json, namespace, origin) |
| 118 self.properties[additional_properties_key] = Property( | 173 else: |
| 119 self, | 174 raise ParseException(self, 'Unsupported JSON type %s' % json_type) |
| 120 additional_properties_key, | |
| 121 additional_properties, | |
| 122 namespace, | |
| 123 is_additional_properties=True) | |
| 124 | 175 |
| 125 class Function(object): | 176 class Function(object): |
| 126 """A Function defined in the API. | 177 """A Function defined in the API. |
| 127 | 178 |
| 128 Properties: | 179 Properties: |
| 129 - |name| the function name | 180 - |name| the function name |
| 130 - |params| a list of parameters to the function (order matters). A separate | 181 - |params| a list of parameters to the function (order matters). A separate |
| 131 parameter is used for each choice of a 'choices' parameter. | 182 parameter is used for each choice of a 'choices' parameter. |
| 132 - |description| a description of the function (if provided) | 183 - |description| a description of the function (if provided) |
| 133 - |callback| the callback parameter to the function. There should be exactly | 184 - |callback| the callback parameter to the function. There should be exactly |
| 134 one | 185 one |
| 135 - |optional| whether the Function is "optional"; this only makes sense to be | 186 - |optional| whether the Function is "optional"; this only makes sense to be |
| 136 present when the Function is representing a callback property. | 187 present when the Function is representing a callback property. |
| 137 - |simple_name| the name of this Function without a namespace | 188 - |simple_name| the name of this Function without a namespace |
| 138 """ | 189 """ |
| 139 def __init__(self, | 190 def __init__(self, |
| 140 parent, | 191 parent, |
| 192 name, | |
| 141 json, | 193 json, |
| 142 namespace, | 194 namespace, |
| 143 from_json=False, | 195 origin): |
| 144 from_client=False): | 196 self.name = name |
| 145 self.name = json['name'] | |
| 146 self.simple_name = _StripNamespace(self.name, namespace) | 197 self.simple_name = _StripNamespace(self.name, namespace) |
| 147 self.params = [] | 198 self.params = [] |
| 148 self.description = json.get('description') | 199 self.description = json.get('description') |
| 149 self.callback = None | 200 self.callback = None |
| 150 self.optional = json.get('optional', False) | 201 self.optional = json.get('optional', False) |
| 151 self.parent = parent | 202 self.parent = parent |
| 152 self.nocompile = json.get('nocompile') | 203 self.nocompile = json.get('nocompile') |
| 153 options = json.get('options', {}) | 204 options = json.get('options', {}) |
| 154 self.conditions = options.get('conditions', []) | 205 self.conditions = options.get('conditions', []) |
| 155 self.actions = options.get('actions', []) | 206 self.actions = options.get('actions', []) |
| 156 self.supports_listeners = options.get('supportsListeners', True) | 207 self.supports_listeners = options.get('supportsListeners', True) |
| 157 self.supports_rules = options.get('supportsRules', False) | 208 self.supports_rules = options.get('supportsRules', False) |
| 209 | |
| 158 def GeneratePropertyFromParam(p): | 210 def GeneratePropertyFromParam(p): |
| 159 return Property(self, | 211 return Property.FromJSON(self, p['name'], p, namespace, origin) |
| 160 p['name'], p, | |
| 161 namespace, | |
| 162 from_json=from_json, | |
| 163 from_client=from_client) | |
| 164 | 212 |
| 165 self.filters = [GeneratePropertyFromParam(filter) | 213 self.filters = [GeneratePropertyFromParam(filter) |
| 166 for filter in json.get('filters', [])] | 214 for filter in json.get('filters', [])] |
| 167 callback_param = None | 215 callback_param = None |
| 168 for param in json.get('parameters', []): | 216 for param in json.get('parameters', []): |
| 169 | |
| 170 if param.get('type') == 'function': | 217 if param.get('type') == 'function': |
| 171 if callback_param: | 218 if callback_param: |
| 172 # No ParseException because the webstore has this. | 219 # No ParseException because the webstore has this. |
| 173 # Instead, pretend all intermediate callbacks are properties. | 220 # Instead, pretend all intermediate callbacks are properties. |
| 174 self.params.append(GeneratePropertyFromParam(callback_param)) | 221 self.params.append(GeneratePropertyFromParam(callback_param)) |
| 175 callback_param = param | 222 callback_param = param |
| 176 else: | 223 else: |
| 177 self.params.append(GeneratePropertyFromParam(param)) | 224 self.params.append(GeneratePropertyFromParam(param)) |
| 178 | 225 |
| 179 if callback_param: | 226 if callback_param: |
| 180 self.callback = Function(self, | 227 self.callback = Function(self, |
| 228 callback_param['name'], | |
| 181 callback_param, | 229 callback_param, |
| 182 namespace, | 230 namespace, |
| 183 from_client=True) | 231 Origin(from_client=True)) |
| 184 | 232 |
| 185 self.returns = None | 233 self.returns = None |
| 186 if 'returns' in json: | 234 if 'returns' in json: |
| 187 self.returns = Property(self, 'return', json['returns'], namespace) | 235 self.returns = Property.FromJSON( |
| 236 self, 'return', json['returns'], namespace, origin) | |
| 188 | 237 |
| 189 class Property(object): | 238 class Property(object): |
| 190 """A property of a type OR a parameter to a function. | 239 """A property of a type OR a parameter to a function. |
| 191 | |
| 192 Properties: | 240 Properties: |
| 193 - |name| name of the property as in the json. This shouldn't change since | 241 - |name| name of the property as in the json. This shouldn't change since |
| 194 it is the key used to access DictionaryValues | 242 it is the key used to access DictionaryValues |
| 195 - |unix_name| the unix_style_name of the property. Used as variable name | 243 - |unix_name| the unix_style_name of the property. Used as variable name |
| 196 - |optional| a boolean representing whether the property is optional | 244 - |optional| a boolean representing whether the property is optional |
| 197 - |description| a description of the property (if provided) | 245 - |description| a description of the property (if provided) |
| 198 - |type_| the model.PropertyType of this property | 246 - |type_| the model.Type of this property |
| 199 - |compiled_type| the model.PropertyType that this property should be | |
| 200 compiled to from the JSON. Defaults to |type_|. | |
| 201 - |ref_type| the type that the REF property is referencing. Can be used to | |
| 202 map to its model.Type | |
| 203 - |item_type| a model.Property representing the type of each element in an | |
| 204 ARRAY | |
| 205 - |properties| the properties of an OBJECT parameter | |
| 206 - |from_client| indicates that instances of the Type can originate from the | |
| 207 users of generated code, such as top-level types and function results | |
| 208 - |from_json| indicates that instances of the Type can originate from the | |
| 209 JSON (as described by the schema), such as top-level types and function | |
| 210 parameters | |
| 211 - |simple_name| the name of this Property without a namespace | 247 - |simple_name| the name of this Property without a namespace |
| 212 """ | 248 """ |
| 213 | 249 |
| 250 @staticmethod | |
| 251 def FromJSON(parent, name, json, namespace, origin): | |
| 252 """Creates a Property from JSON. | |
| 253 """ | |
| 254 opt_args = {} | |
| 255 if 'description' in json: | |
| 256 opt_args['description'] = json['description'] | |
| 257 if 'optional' in json: | |
| 258 opt_args['optional'] = json.get('optional') | |
| 259 if 'isInstanceOf' in json: | |
| 260 opt_args['instance_of'] = json.get('isInstanceOf') | |
| 261 | |
| 262 # HACK: only support very specific value types. | |
| 263 is_allowed_value = ( | |
| 264 '$ref' not in json and | |
| 265 ('type' not in json or json['type'] == 'integer' | |
| 266 or json['type'] == 'string')) | |
| 267 | |
| 268 if 'value' in json and is_allowed_value: | |
| 269 value = json['value'] | |
| 270 opt_args['value'] = value | |
| 271 if 'type' not in json: | |
| 272 # Sometimes the type of the value is left out, and we need to figure | |
| 273 # it out for ourselves. | |
| 274 if isinstance(value, int): | |
| 275 json['type'] = 'integer' | |
| 276 elif isinstance(value, basestring): | |
| 277 json['type'] = 'string' | |
| 278 else: | |
| 279 # TODO(kalman): support more types as necessary. | |
| 280 raise ParseException( | |
| 281 parent, '"%s" is not a supported type for "value"' % type(value)) | |
| 282 | |
| 283 type_ = Type(parent, name, json, namespace, origin) | |
| 284 return Property(parent, | |
| 285 name, | |
| 286 namespace, | |
| 287 type_, | |
| 288 origin, | |
| 289 **opt_args); | |
| 290 | |
| 214 def __init__(self, | 291 def __init__(self, |
| 215 parent, | 292 parent, |
| 216 name, | 293 name, |
| 217 json, | |
| 218 namespace, | 294 namespace, |
| 219 is_additional_properties=False, | 295 type_, |
| 220 from_json=False, | 296 origin, |
| 221 from_client=False): | 297 description=None, |
| 298 optional=False, | |
| 299 returns=None, | |
| 300 instance_of=None, | |
| 301 value=None): | |
| 302 """Directly initializes the fields of the Property. | |
| 303 """ | |
| 222 self.name = name | 304 self.name = name |
| 223 self.simple_name = _StripNamespace(self.name, namespace) | 305 self.simple_name = _StripNamespace(self.name, namespace) |
| 224 self._unix_name = UnixName(self.name) | 306 self._unix_name = UnixName(self.name) |
| 225 self._unix_name_used = False | 307 self._unix_name_used = False |
| 226 self.optional = json.get('optional', False) | 308 self.optional = optional |
| 227 self.functions = OrderedDict() | 309 self.description = description |
| 228 self.has_value = False | |
| 229 self.description = json.get('description') | |
| 230 self.parent = parent | 310 self.parent = parent |
| 231 self.from_json = from_json | 311 self.origin = origin |
| 232 self.from_client = from_client | 312 if not isinstance(type_, Type): |
| 233 self.instance_of = json.get('isInstanceOf', None) | 313 raise ValueError("not Type: %s" % type_) |
| 234 self.params = [] | 314 self.type_ = type_ |
| 235 self.returns = None | 315 self.returns = returns |
| 236 _AddProperties(self, json, namespace) | 316 if instance_of is not None: |
| 237 if is_additional_properties: | 317 self.instance_of = instance_of |
| 238 self.type_ = PropertyType.ADDITIONAL_PROPERTIES | 318 self.value = value |
| 239 elif '$ref' in json: | |
| 240 self.ref_type = json['$ref'] | |
| 241 self.type_ = PropertyType.REF | |
| 242 elif 'enum' in json and json.get('type') == 'string': | |
| 243 # Non-string enums (as in the case of [legalValues=(1,2)]) should fall | |
| 244 # through to the next elif. | |
| 245 self.enum_values = [] | |
| 246 for value in json['enum']: | |
| 247 self.enum_values.append(value) | |
| 248 self.type_ = PropertyType.ENUM | |
| 249 elif 'type' in json: | |
| 250 self.type_ = self._JsonTypeToPropertyType(json['type']) | |
| 251 if self.type_ == PropertyType.ARRAY: | |
| 252 self.item_type = Property(self, | |
| 253 name + "Element", | |
| 254 json['items'], | |
| 255 namespace, | |
| 256 from_json=from_json, | |
| 257 from_client=from_client) | |
| 258 elif self.type_ == PropertyType.OBJECT: | |
| 259 # These members are read when this OBJECT Property is used as a Type | |
| 260 type_ = Type(self, self.name, json, namespace) | |
| 261 # self.properties will already have some value from |_AddProperties|. | |
| 262 self.properties.update(type_.properties) | |
| 263 self.functions = type_.functions | |
| 264 elif self.type_ == PropertyType.FUNCTION: | |
| 265 for p in json.get('parameters', []): | |
| 266 self.params.append(Property(self, | |
| 267 p['name'], | |
| 268 p, | |
| 269 namespace, | |
| 270 from_json=from_json, | |
| 271 from_client=from_client)) | |
| 272 if 'returns' in json: | |
| 273 self.returns = Property(self, 'return', json['returns'], namespace) | |
| 274 elif 'choices' in json: | |
| 275 if not json['choices'] or len(json['choices']) == 0: | |
| 276 raise ParseException(self, 'Choices has no choices') | |
| 277 self.choices = {} | |
| 278 self.type_ = PropertyType.CHOICES | |
| 279 self.compiled_type = self.type_ | |
| 280 for choice_json in json['choices']: | |
| 281 choice = Property(self, | |
| 282 self.name, | |
| 283 choice_json, | |
| 284 namespace, | |
| 285 from_json=from_json, | |
| 286 from_client=from_client) | |
| 287 choice.unix_name = UnixName(self.name + choice.type_.name) | |
| 288 # The existence of any single choice is optional | |
| 289 choice.optional = True | |
| 290 self.choices[choice.type_] = choice | |
| 291 elif 'value' in json: | |
| 292 self.has_value = True | |
| 293 self.value = json['value'] | |
| 294 if type(self.value) == int: | |
| 295 self.type_ = PropertyType.INTEGER | |
| 296 self.compiled_type = self.type_ | |
| 297 else: | |
| 298 # TODO(kalman): support more types as necessary. | |
| 299 raise ParseException( | |
| 300 self, '"%s" is not a supported type' % type(self.value)) | |
| 301 else: | |
| 302 raise ParseException( | |
| 303 self, 'Property has no type, $ref, choices, or value') | |
| 304 if 'compiled_type' in json: | |
| 305 if 'type' in json: | |
| 306 self.compiled_type = self._JsonTypeToPropertyType(json['compiled_type']) | |
| 307 else: | |
| 308 raise ParseException(self, 'Property has compiled_type but no type') | |
| 309 else: | |
| 310 self.compiled_type = self.type_ | |
| 311 | |
| 312 def _JsonTypeToPropertyType(self, json_type): | |
| 313 try: | |
| 314 return { | |
| 315 'any': PropertyType.ANY, | |
| 316 'array': PropertyType.ARRAY, | |
| 317 'binary': PropertyType.BINARY, | |
| 318 'boolean': PropertyType.BOOLEAN, | |
| 319 'integer': PropertyType.INTEGER, | |
| 320 'int64': PropertyType.INT64, | |
| 321 'function': PropertyType.FUNCTION, | |
| 322 'number': PropertyType.DOUBLE, | |
| 323 'object': PropertyType.OBJECT, | |
| 324 'string': PropertyType.STRING, | |
| 325 }[json_type] | |
| 326 except KeyError: | |
| 327 raise NotImplementedError('Type %s not recognized' % json_type) | |
| 328 | 319 |
| 329 def GetUnixName(self): | 320 def GetUnixName(self): |
| 330 """Gets the property's unix_name. Raises AttributeError if not set. | 321 """Gets the property's unix_name. Raises AttributeError if not set. |
| 331 """ | 322 """ |
| 332 if not self._unix_name: | 323 if not self._unix_name: |
| 333 raise AttributeError('No unix_name set on %s' % self.name) | 324 raise AttributeError('No unix_name set on %s' % self.name) |
| 334 self._unix_name_used = True | 325 self._unix_name_used = True |
| 335 return self._unix_name | 326 return self._unix_name |
| 336 | 327 |
| 337 def SetUnixName(self, unix_name): | 328 def SetUnixName(self, unix_name): |
| 338 """Set the property's unix_name. Raises AttributeError if the unix_name has | 329 """Set the property's unix_name. Raises AttributeError if the unix_name has |
| 339 already been used (GetUnixName has been called). | 330 already been used (GetUnixName has been called). |
| 340 """ | 331 """ |
| 341 if unix_name == self._unix_name: | 332 if unix_name == self._unix_name: |
| 342 return | 333 return |
| 343 if self._unix_name_used: | 334 if self._unix_name_used: |
| 344 raise AttributeError( | 335 raise AttributeError( |
| 345 'Cannot set the unix_name on %s; ' | 336 'Cannot set the unix_name on %s; ' |
| 346 'it is already used elsewhere as %s' % | 337 'it is already used elsewhere as %s' % |
| 347 (self.name, self._unix_name)) | 338 (self.name, self._unix_name)) |
| 348 self._unix_name = unix_name | 339 self._unix_name = unix_name |
| 349 | 340 |
| 350 def Copy(self): | |
| 351 """Makes a copy of this model.Property object and allow the unix_name to be | |
| 352 set again. | |
| 353 """ | |
| 354 property_copy = copy.copy(self) | |
| 355 property_copy._unix_name_used = False | |
| 356 return property_copy | |
| 357 | |
| 358 unix_name = property(GetUnixName, SetUnixName) | 341 unix_name = property(GetUnixName, SetUnixName) |
| 359 | 342 |
| 360 class _PropertyTypeInfo(object): | 343 class _PropertyTypeInfo(object): |
| 361 """This class is not an inner class of |PropertyType| so it can be pickled. | 344 """This class is not an inner class of |PropertyType| so it can be pickled. |
| 362 """ | 345 """ |
| 363 def __init__(self, is_fundamental, name): | 346 def __init__(self, is_fundamental, name): |
| 364 self.is_fundamental = is_fundamental | 347 self.is_fundamental = is_fundamental |
| 365 self.name = name | 348 self.name = name |
| 366 | 349 |
| 367 def __repr__(self): | 350 def __repr__(self): |
| 368 return self.name | 351 return self.name |
| 369 | 352 |
| 370 def __eq__(self, other): | 353 def __eq__(self, other): |
| 371 return isinstance(other, _PropertyTypeInfo) and self.name == other.name | 354 return isinstance(other, _PropertyTypeInfo) and self.name == other.name |
| 372 | 355 |
| 373 def __ne__(self, other): | 356 def __ne__(self, other): |
| 374 # Yes. You seriously do need this. | 357 # Yes. You seriously do need this. |
| 375 return not (self == other) | 358 return not (self == other) |
| 376 | 359 |
| 377 class PropertyType(object): | 360 class PropertyType(object): |
| 378 """Enum of different types of properties/parameters. | 361 """Enum of different types of properties/parameters. |
| 379 """ | 362 """ |
| 380 INTEGER = _PropertyTypeInfo(True, "INTEGER") | 363 INTEGER = _PropertyTypeInfo(True, "integer") |
| 381 INT64 = _PropertyTypeInfo(True, "INT64") | 364 INT64 = _PropertyTypeInfo(True, "int64") |
| 382 DOUBLE = _PropertyTypeInfo(True, "DOUBLE") | 365 DOUBLE = _PropertyTypeInfo(True, "double") |
| 383 BOOLEAN = _PropertyTypeInfo(True, "BOOLEAN") | 366 BOOLEAN = _PropertyTypeInfo(True, "boolean") |
| 384 STRING = _PropertyTypeInfo(True, "STRING") | 367 STRING = _PropertyTypeInfo(True, "string") |
| 385 ENUM = _PropertyTypeInfo(False, "ENUM") | 368 ENUM = _PropertyTypeInfo(False, "enum") |
| 386 ARRAY = _PropertyTypeInfo(False, "ARRAY") | 369 ARRAY = _PropertyTypeInfo(False, "array") |
| 387 REF = _PropertyTypeInfo(False, "REF") | 370 REF = _PropertyTypeInfo(False, "ref") |
| 388 CHOICES = _PropertyTypeInfo(False, "CHOICES") | 371 CHOICES = _PropertyTypeInfo(False, "choices") |
| 389 OBJECT = _PropertyTypeInfo(False, "OBJECT") | 372 OBJECT = _PropertyTypeInfo(False, "object") |
| 390 FUNCTION = _PropertyTypeInfo(False, "FUNCTION") | 373 FUNCTION = _PropertyTypeInfo(False, "function") |
| 391 BINARY = _PropertyTypeInfo(False, "BINARY") | 374 BINARY = _PropertyTypeInfo(False, "binary") |
| 392 ANY = _PropertyTypeInfo(False, "ANY") | 375 ANY = _PropertyTypeInfo(False, "any") |
| 393 ADDITIONAL_PROPERTIES = _PropertyTypeInfo(False, "ADDITIONAL_PROPERTIES") | |
| 394 | 376 |
| 395 def UnixName(name): | 377 def UnixName(name): |
| 396 """Returns the unix_style name for a given lowerCamelCase string. | 378 """Returns the unix_style name for a given lowerCamelCase string. |
| 397 """ | 379 """ |
| 398 # First replace any lowerUpper patterns with lower_Upper. | 380 # First replace any lowerUpper patterns with lower_Upper. |
| 399 s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name) | 381 s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name) |
| 400 # Now replace any ACMEWidgets patterns with ACME_Widgets | 382 # Now replace any ACMEWidgets patterns with ACME_Widgets |
| 401 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) |
| 402 # Finally, replace any remaining periods, and make lowercase. | 384 # Finally, replace any remaining periods, and make lowercase. |
| 403 return s2.replace('.', '_').lower() | 385 return s2.replace('.', '_').lower() |
| 404 | 386 |
| 405 def _StripNamespace(name, namespace): | 387 def _StripNamespace(name, namespace): |
| 406 if name.startswith(namespace.name + '.'): | 388 if name.startswith(namespace.name + '.'): |
| 407 return name[len(namespace.name + '.'):] | 389 return name[len(namespace.name + '.'):] |
| 408 return name | 390 return name |
| 409 | 391 |
| 410 def _GetModelHierarchy(entity): | 392 def _GetModelHierarchy(entity): |
| 411 """Returns the hierarchy of the given model entity.""" | 393 """Returns the hierarchy of the given model entity.""" |
| 412 hierarchy = [] | 394 hierarchy = [] |
| 413 while entity: | 395 while entity is not None: |
| 414 try: | 396 hierarchy.append(getattr(entity, 'name', repr(entity))) |
| 415 hierarchy.append(entity.name) | 397 if isinstance(entity, Namespace): |
| 416 except AttributeError: | 398 hierarchy.insert(0, ' in %s' % entity.source_file) |
| 417 hierarchy.append(repr(entity)) | 399 entity = getattr(entity, 'parent', None) |
| 418 entity = entity.parent | |
| 419 hierarchy.reverse() | 400 hierarchy.reverse() |
| 420 return hierarchy | 401 return hierarchy |
| 421 | 402 |
| 422 def _AddTypes(model, json, namespace): | 403 def _GetTypes(parent, json, namespace, origin): |
| 423 """Adds Type objects to |model| contained in the 'types' field of |json|. | 404 """Adds Type objects to |model| contained in the 'types' field of |json|. |
|
Yoyo Zhou
2013/01/15 01:49:25
Do all these descriptions need to be updated?
not at google - send to devlin
2013/01/15 21:47:27
Done.
| |
| 424 """ | 405 """ |
| 425 model.types = OrderedDict() | 406 types = OrderedDict() |
| 426 for type_json in json.get('types', []): | 407 for type_json in json.get('types', []): |
| 427 type_ = Type(model, type_json['id'], type_json, namespace) | 408 type_ = Type(parent, type_json['id'], type_json, namespace, origin) |
| 428 model.types[type_.name] = type_ | 409 types[type_.name] = type_ |
| 410 return types | |
| 429 | 411 |
| 430 def _AddFunctions(model, json, namespace): | 412 def _GetFunctions(parent, json, namespace): |
| 431 """Adds Function objects to |model| contained in the 'functions' field of | 413 """Adds Function objects to |model| contained in the 'functions' field of |
| 432 |json|. | 414 |json|. |
| 433 """ | 415 """ |
| 434 model.functions = OrderedDict() | 416 functions = OrderedDict() |
| 435 for function_json in json.get('functions', []): | 417 for function_json in json.get('functions', []): |
| 436 function = Function(model, function_json, namespace, from_json=True) | 418 function = Function(parent, |
| 437 model.functions[function.name] = function | 419 function_json['name'], |
| 420 function_json, | |
| 421 namespace, | |
| 422 Origin(from_json=True)) | |
| 423 functions[function.name] = function | |
| 424 return functions | |
| 438 | 425 |
| 439 def _AddEvents(model, json, namespace): | 426 def _GetEvents(parent, json, namespace): |
| 440 """Adds Function objects to |model| contained in the 'events' field of |json|. | 427 """Adds Function objects to |model| contained in the 'events' field of |json|. |
| 441 """ | 428 """ |
| 442 model.events = OrderedDict() | 429 events = OrderedDict() |
| 443 for event_json in json.get('events', []): | 430 for event_json in json.get('events', []): |
| 444 event = Function(model, event_json, namespace, from_client=True) | 431 event = Function(parent, |
| 445 model.events[event.name] = event | 432 event_json['name'], |
| 433 event_json, | |
| 434 namespace, | |
| 435 Origin(from_client=True)) | |
| 436 events[event.name] = event | |
| 437 return events | |
| 446 | 438 |
| 447 def _AddProperties(model, | 439 def _GetProperties(parent, json, namespace, origin): |
| 448 json, | |
| 449 namespace, | |
| 450 from_json=False, | |
| 451 from_client=False): | |
| 452 """Adds model.Property objects to |model| contained in the 'properties' field | 440 """Adds model.Property objects to |model| contained in the 'properties' field |
| 453 of |json|. | 441 of |json|. |
| 454 """ | 442 """ |
| 455 model.properties = OrderedDict() | 443 properties = OrderedDict() |
| 456 for name, property_json in json.get('properties', {}).items(): | 444 for name, property_json in json.get('properties', {}).items(): |
| 457 model.properties[name] = Property( | 445 properties[name] = Property.FromJSON( |
| 458 model, | 446 parent, name, property_json, namespace, origin) |
| 459 name, | 447 return properties |
| 460 property_json, | |
| 461 namespace, | |
| 462 from_json=from_json, | |
| 463 from_client=from_client) | |
| OLD | NEW |