blob: 50a9c581403ec992d64fe5c25c69c3aa5ea93057 [file] [log] [blame]
[email protected]15f08dd2012-01-27 07:29:481# 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
3# found in the LICENSE file.
4
5import os.path
6
[email protected]b2fad3f2012-11-20 02:13:247from json_parse import OrderedDict
[email protected]cb5670c2013-04-10 06:31:088from memoize import memoize
[email protected]b2fad3f2012-11-20 02:13:249
[email protected]116f0a3a2012-04-19 04:22:3810class ParseException(Exception):
11 """Thrown when data in the model is invalid.
12 """
13 def __init__(self, parent, message):
14 hierarchy = _GetModelHierarchy(parent)
15 hierarchy.append(message)
16 Exception.__init__(
17 self, 'Model parse exception at:\n' + '\n'.join(hierarchy))
18
[email protected]15f08dd2012-01-27 07:29:4819class Model(object):
20 """Model of all namespaces that comprise an API.
[email protected]cfe484902012-02-15 14:52:3221
22 Properties:
23 - |namespaces| a map of a namespace name to its model.Namespace
[email protected]15f08dd2012-01-27 07:29:4824 """
25 def __init__(self):
26 self.namespaces = {}
27
[email protected]4636c832013-01-11 02:10:1128 def AddNamespace(self, json, source_file, include_compiler_options=False):
[email protected]a1f774972012-04-17 02:11:0929 """Add a namespace's json to the model and returns the namespace.
[email protected]15f08dd2012-01-27 07:29:4830 """
[email protected]4636c832013-01-11 02:10:1131 namespace = Namespace(json,
32 source_file,
33 include_compiler_options=include_compiler_options)
[email protected]15f08dd2012-01-27 07:29:4834 self.namespaces[namespace.name] = namespace
35 return namespace
36
37class Namespace(object):
38 """An API namespace.
[email protected]cfe484902012-02-15 14:52:3239
40 Properties:
41 - |name| the name of the namespace
[email protected]8426f8d72013-06-23 04:24:5542 - |description| the description of the namespace
[email protected]712eca0f2012-02-21 01:13:0743 - |unix_name| the unix_name of the namespace
44 - |source_file| the file that contained the namespace definition
45 - |source_file_dir| the directory component of |source_file|
46 - |source_file_filename| the filename component of |source_file|
[email protected]4636c832013-01-11 02:10:1147 - |platforms| if not None, the list of platforms that the namespace is
48 available to
[email protected]cfe484902012-02-15 14:52:3249 - |types| a map of type names to their model.Type
50 - |functions| a map of function names to their model.Function
[email protected]b741e8f2012-07-16 21:47:2451 - |events| a map of event names to their model.Function
[email protected]116f0a3a2012-04-19 04:22:3852 - |properties| a map of property names to their model.Property
[email protected]bee7a7932013-08-12 23:45:3853 - |compiler_options| the compiler_options dict, only not empty if
[email protected]4636c832013-01-11 02:10:1154 |include_compiler_options| is True
[email protected]15f08dd2012-01-27 07:29:4855 """
[email protected]4636c832013-01-11 02:10:1156 def __init__(self, json, source_file, include_compiler_options=False):
[email protected]15f08dd2012-01-27 07:29:4857 self.name = json['namespace']
[email protected]8426f8d72013-06-23 04:24:5558 if 'description' not in json:
[email protected]a081aeb2013-07-09 20:52:4759 # TODO(kalman): Go back to throwing an error here.
60 print('%s must have a "description" field. This will appear '
[email protected]8426f8d72013-06-23 04:24:5561 'on the API summary page.' % self.name)
[email protected]a081aeb2013-07-09 20:52:4762 json['description'] = ''
63 self.description = json['description']
[email protected]4ba6bdc2012-06-18 20:40:1464 self.unix_name = UnixName(self.name)
[email protected]15f08dd2012-01-27 07:29:4865 self.source_file = source_file
66 self.source_file_dir, self.source_file_filename = os.path.split(source_file)
[email protected]feba21e2012-03-02 15:05:2767 self.parent = None
[email protected]4636c832013-01-11 02:10:1168 self.platforms = _GetPlatforms(json)
[email protected]242d5e7a2013-01-17 06:50:3169 toplevel_origin = Origin(from_client=True, from_json=True)
70 self.types = _GetTypes(self, json, self, toplevel_origin)
71 self.functions = _GetFunctions(self, json, self)
72 self.events = _GetEvents(self, json, self)
73 self.properties = _GetProperties(self, json, self, toplevel_origin)
[email protected]bee7a7932013-08-12 23:45:3874 self.compiler_options = (json.get('compiler_options', {})
75 if include_compiler_options else {})
[email protected]15f08dd2012-01-27 07:29:4876
[email protected]242d5e7a2013-01-17 06:50:3177class Origin(object):
78 """Stores the possible origin of model object as a pair of bools. These are:
79
80 |from_client| indicating that instances can originate from users of
81 generated code (for example, function results), or
82 |from_json| indicating that instances can originate from the JSON (for
83 example, function parameters)
84
85 It is possible for model objects to originate from both the client and json,
86 for example Types defined in the top-level schema, in which case both
87 |from_client| and |from_json| would be True.
88 """
89 def __init__(self, from_client=False, from_json=False):
90 if not from_client and not from_json:
91 raise ValueError('One of from_client or from_json must be true')
92 self.from_client = from_client
93 self.from_json = from_json
94
[email protected]15f08dd2012-01-27 07:29:4895class Type(object):
96 """A Type defined in the json.
[email protected]cfe484902012-02-15 14:52:3297
98 Properties:
99 - |name| the type name
[email protected]242d5e7a2013-01-17 06:50:31100 - |namespace| the Type's namespace
[email protected]cfe484902012-02-15 14:52:32101 - |description| the description of the type (if provided)
[email protected]feba21e2012-03-02 15:05:27102 - |properties| a map of property unix_names to their model.Property
103 - |functions| a map of function names to their model.Function
[email protected]d32b8e52012-07-23 18:40:08104 - |events| a map of event names to their model.Event
[email protected]242d5e7a2013-01-17 06:50:31105 - |origin| the Origin of the type
106 - |property_type| the PropertyType of this Type
[email protected]cf6d0b32012-04-12 04:30:22107 - |item_type| if this is an array, the type of items in the array
[email protected]0b255f002012-10-05 01:58:47108 - |simple_name| the name of this Type without a namespace
[email protected]242d5e7a2013-01-17 06:50:31109 - |additional_properties| the type of the additional properties, if any is
110 specified
[email protected]15f08dd2012-01-27 07:29:48111 """
[email protected]242d5e7a2013-01-17 06:50:31112 def __init__(self,
113 parent,
114 name,
115 json,
116 namespace,
117 origin):
118 self.name = name
119 self.namespace = namespace
120 self.simple_name = _StripNamespace(self.name, namespace)
121 self.unix_name = UnixName(self.name)
122 self.description = json.get('description', None)
123 self.origin = origin
124 self.parent = parent
125 self.instance_of = json.get('isInstanceOf', None)
126
127 # TODO(kalman): Only objects need functions/events/properties, but callers
128 # assume that all types have them. Fix this.
129 self.functions = _GetFunctions(self, json, namespace)
130 self.events = _GetEvents(self, json, namespace)
131 self.properties = _GetProperties(self, json, namespace, origin)
132
133 json_type = json.get('type', None)
134 if json_type == 'array':
135 self.property_type = PropertyType.ARRAY
136 self.item_type = Type(
137 self, '%sType' % name, json['items'], namespace, origin)
138 elif '$ref' in json:
139 self.property_type = PropertyType.REF
140 self.ref_type = json['$ref']
141 elif 'enum' in json and json_type == 'string':
142 self.property_type = PropertyType.ENUM
143 self.enum_values = [value for value in json['enum']]
144 elif json_type == 'any':
145 self.property_type = PropertyType.ANY
146 elif json_type == 'binary':
147 self.property_type = PropertyType.BINARY
148 elif json_type == 'boolean':
149 self.property_type = PropertyType.BOOLEAN
150 elif json_type == 'integer':
151 self.property_type = PropertyType.INTEGER
152 elif (json_type == 'double' or
153 json_type == 'number'):
154 self.property_type = PropertyType.DOUBLE
155 elif json_type == 'string':
156 self.property_type = PropertyType.STRING
157 elif 'choices' in json:
158 self.property_type = PropertyType.CHOICES
[email protected]e11b9aa2013-07-13 00:05:42159 def generate_type_name(type_json):
160 if 'items' in type_json:
161 return '%ss' % generate_type_name(type_json['items'])
162 if '$ref' in type_json:
163 return type_json['$ref']
164 if 'type' in type_json:
165 return type_json['type']
166 return None
167 self.choices = [
168 Type(self,
169 generate_type_name(choice) or 'choice%s' % i,
170 choice,
171 namespace,
172 origin)
173 for i, choice in enumerate(json['choices'])]
[email protected]242d5e7a2013-01-17 06:50:31174 elif json_type == 'object':
[email protected]cf6d0b32012-04-12 04:30:22175 if not (
176 'properties' in json or
177 'additionalProperties' in json or
[email protected]e975d112012-07-31 22:12:43178 'functions' in json or
179 'events' in json):
[email protected]116f0a3a2012-04-19 04:22:38180 raise ParseException(self, name + " has no properties or functions")
[email protected]242d5e7a2013-01-17 06:50:31181 self.property_type = PropertyType.OBJECT
182 additional_properties_json = json.get('additionalProperties', None)
183 if additional_properties_json is not None:
184 self.additional_properties = Type(self,
185 'additionalProperties',
186 additional_properties_json,
187 namespace,
188 origin)
189 else:
190 self.additional_properties = None
191 elif json_type == 'function':
192 self.property_type = PropertyType.FUNCTION
193 # Sometimes we might have an unnamed function, e.g. if it's a property
194 # of an object. Use the name of the property in that case.
195 function_name = json.get('name', name)
196 self.function = Function(self, function_name, json, namespace, origin)
197 else:
198 raise ParseException(self, 'Unsupported JSON type %s' % json_type)
[email protected]15f08dd2012-01-27 07:29:48199
[email protected]15f08dd2012-01-27 07:29:48200class Function(object):
201 """A Function defined in the API.
[email protected]cfe484902012-02-15 14:52:32202
203 Properties:
204 - |name| the function name
[email protected]4636c832013-01-11 02:10:11205 - |platforms| if not None, the list of platforms that the function is
206 available to
[email protected]cfe484902012-02-15 14:52:32207 - |params| a list of parameters to the function (order matters). A separate
[email protected]4636c832013-01-11 02:10:11208 parameter is used for each choice of a 'choices' parameter
[email protected]cfe484902012-02-15 14:52:32209 - |description| a description of the function (if provided)
210 - |callback| the callback parameter to the function. There should be exactly
[email protected]4636c832013-01-11 02:10:11211 one
[email protected]4b3f7852012-07-17 06:33:30212 - |optional| whether the Function is "optional"; this only makes sense to be
[email protected]4636c832013-01-11 02:10:11213 present when the Function is representing a callback property
[email protected]0b255f002012-10-05 01:58:47214 - |simple_name| the name of this Function without a namespace
[email protected]32096af2013-02-06 01:29:31215 - |returns| the return type of the function; None if the function does not
216 return a value
[email protected]15f08dd2012-01-27 07:29:48217 """
[email protected]0b255f002012-10-05 01:58:47218 def __init__(self,
219 parent,
[email protected]242d5e7a2013-01-17 06:50:31220 name,
[email protected]0b255f002012-10-05 01:58:47221 json,
222 namespace,
[email protected]242d5e7a2013-01-17 06:50:31223 origin):
224 self.name = name
[email protected]0b255f002012-10-05 01:58:47225 self.simple_name = _StripNamespace(self.name, namespace)
[email protected]4636c832013-01-11 02:10:11226 self.platforms = _GetPlatforms(json)
[email protected]15f08dd2012-01-27 07:29:48227 self.params = []
[email protected]feba21e2012-03-02 15:05:27228 self.description = json.get('description')
[email protected]15f08dd2012-01-27 07:29:48229 self.callback = None
[email protected]4b3f7852012-07-17 06:33:30230 self.optional = json.get('optional', False)
[email protected]feba21e2012-03-02 15:05:27231 self.parent = parent
[email protected]a9ead752012-05-24 02:08:45232 self.nocompile = json.get('nocompile')
[email protected]c0718352012-08-21 02:34:24233 options = json.get('options', {})
234 self.conditions = options.get('conditions', [])
235 self.actions = options.get('actions', [])
236 self.supports_listeners = options.get('supportsListeners', True)
237 self.supports_rules = options.get('supportsRules', False)
[email protected]242d5e7a2013-01-17 06:50:31238
[email protected]c0718352012-08-21 02:34:24239 def GeneratePropertyFromParam(p):
[email protected]627b54d2013-02-04 23:53:59240 return Property(self, p['name'], p, namespace, origin)
[email protected]db943992012-08-02 14:02:54241
[email protected]c0718352012-08-21 02:34:24242 self.filters = [GeneratePropertyFromParam(filter)
243 for filter in json.get('filters', [])]
[email protected]db943992012-08-02 14:02:54244 callback_param = None
[email protected]b741e8f2012-07-16 21:47:24245 for param in json.get('parameters', []):
[email protected]15f08dd2012-01-27 07:29:48246 if param.get('type') == 'function':
[email protected]db943992012-08-02 14:02:54247 if callback_param:
248 # No ParseException because the webstore has this.
249 # Instead, pretend all intermediate callbacks are properties.
250 self.params.append(GeneratePropertyFromParam(callback_param))
251 callback_param = param
[email protected]15f08dd2012-01-27 07:29:48252 else:
[email protected]db943992012-08-02 14:02:54253 self.params.append(GeneratePropertyFromParam(param))
254
255 if callback_param:
[email protected]0b255f002012-10-05 01:58:47256 self.callback = Function(self,
[email protected]242d5e7a2013-01-17 06:50:31257 callback_param['name'],
[email protected]0b255f002012-10-05 01:58:47258 callback_param,
259 namespace,
[email protected]242d5e7a2013-01-17 06:50:31260 Origin(from_client=True))
[email protected]db943992012-08-02 14:02:54261
[email protected]491e60d32012-07-20 01:03:13262 self.returns = None
263 if 'returns' in json:
[email protected]627b54d2013-02-04 23:53:59264 self.returns = Type(self,
265 '%sReturnType' % name,
266 json['returns'],
267 namespace,
268 origin)
[email protected]15f08dd2012-01-27 07:29:48269
[email protected]15f08dd2012-01-27 07:29:48270class Property(object):
271 """A property of a type OR a parameter to a function.
[email protected]cfe484902012-02-15 14:52:32272 Properties:
273 - |name| name of the property as in the json. This shouldn't change since
274 it is the key used to access DictionaryValues
275 - |unix_name| the unix_style_name of the property. Used as variable name
276 - |optional| a boolean representing whether the property is optional
277 - |description| a description of the property (if provided)
[email protected]242d5e7a2013-01-17 06:50:31278 - |type_| the model.Type of this property
[email protected]0b255f002012-10-05 01:58:47279 - |simple_name| the name of this Property without a namespace
[email protected]15f08dd2012-01-27 07:29:48280 """
[email protected]627b54d2013-02-04 23:53:59281 def __init__(self, parent, name, json, namespace, origin):
[email protected]242d5e7a2013-01-17 06:50:31282 """Creates a Property from JSON.
283 """
[email protected]627b54d2013-02-04 23:53:59284 self.parent = parent
285 self.name = name
286 self._unix_name = UnixName(self.name)
287 self._unix_name_used = False
288 self.origin = origin
289 self.simple_name = _StripNamespace(self.name, namespace)
290 self.description = json.get('description', None)
291 self.optional = json.get('optional', None)
292 self.instance_of = json.get('isInstanceOf', None)
[email protected]242d5e7a2013-01-17 06:50:31293
294 # HACK: only support very specific value types.
295 is_allowed_value = (
296 '$ref' not in json and
297 ('type' not in json or json['type'] == 'integer'
298 or json['type'] == 'string'))
299
[email protected]627b54d2013-02-04 23:53:59300 self.value = None
[email protected]242d5e7a2013-01-17 06:50:31301 if 'value' in json and is_allowed_value:
[email protected]627b54d2013-02-04 23:53:59302 self.value = json['value']
[email protected]242d5e7a2013-01-17 06:50:31303 if 'type' not in json:
304 # Sometimes the type of the value is left out, and we need to figure
305 # it out for ourselves.
[email protected]627b54d2013-02-04 23:53:59306 if isinstance(self.value, int):
[email protected]242d5e7a2013-01-17 06:50:31307 json['type'] = 'integer'
[email protected]627b54d2013-02-04 23:53:59308 elif isinstance(self.value, basestring):
[email protected]242d5e7a2013-01-17 06:50:31309 json['type'] = 'string'
310 else:
311 # TODO(kalman): support more types as necessary.
312 raise ParseException(
[email protected]627b54d2013-02-04 23:53:59313 parent,
314 '"%s" is not a supported type for "value"' % type(self.value))
[email protected]242d5e7a2013-01-17 06:50:31315
[email protected]627b54d2013-02-04 23:53:59316 self.type_ = Type(parent, name, json, namespace, origin)
[email protected]cfe484902012-02-15 14:52:32317
318 def GetUnixName(self):
319 """Gets the property's unix_name. Raises AttributeError if not set.
320 """
[email protected]116f0a3a2012-04-19 04:22:38321 if not self._unix_name:
[email protected]cfe484902012-02-15 14:52:32322 raise AttributeError('No unix_name set on %s' % self.name)
323 self._unix_name_used = True
324 return self._unix_name
325
326 def SetUnixName(self, unix_name):
327 """Set the property's unix_name. Raises AttributeError if the unix_name has
328 already been used (GetUnixName has been called).
329 """
330 if unix_name == self._unix_name:
331 return
332 if self._unix_name_used:
333 raise AttributeError(
334 'Cannot set the unix_name on %s; '
335 'it is already used elsewhere as %s' %
336 (self.name, self._unix_name))
337 self._unix_name = unix_name
338
339 unix_name = property(GetUnixName, SetUnixName)
[email protected]15f08dd2012-01-27 07:29:48340
[email protected]4636c832013-01-11 02:10:11341class _Enum(object):
342 """Superclass for enum types with a "name" field, setting up repr/eq/ne.
343 Enums need to do this so that equality/non-equality work over pickling.
[email protected]fe027682012-08-21 01:51:34344 """
[email protected]4636c832013-01-11 02:10:11345 @staticmethod
346 def GetAll(cls):
347 """Yields all _Enum objects declared in |cls|.
348 """
349 for prop_key in dir(cls):
350 prop_value = getattr(cls, prop_key)
351 if isinstance(prop_value, _Enum):
352 yield prop_value
353
354 def __init__(self, name):
[email protected]fe027682012-08-21 01:51:34355 self.name = name
356
[email protected]dc5f2fecf2012-08-31 01:55:51357 def __eq__(self, other):
[email protected]4636c832013-01-11 02:10:11358 return type(other) == type(self) and other.name == self.name
[email protected]e15dccb2012-10-05 06:02:25359 def __ne__(self, other):
[email protected]e15dccb2012-10-05 06:02:25360 return not (self == other)
361
[email protected]e11b9aa2013-07-13 00:05:42362 def __repr__(self):
363 return self.name
364
365 def __str__(self):
366 return repr(self)
367
[email protected]4636c832013-01-11 02:10:11368class _PropertyTypeInfo(_Enum):
369 def __init__(self, is_fundamental, name):
370 _Enum.__init__(self, name)
371 self.is_fundamental = is_fundamental
372
[email protected]15f08dd2012-01-27 07:29:48373class PropertyType(object):
374 """Enum of different types of properties/parameters.
375 """
[email protected]242d5e7a2013-01-17 06:50:31376 ANY = _PropertyTypeInfo(False, "any")
[email protected]e11b9aa2013-07-13 00:05:42377 ARRAY = _PropertyTypeInfo(False, "array")
378 BINARY = _PropertyTypeInfo(False, "binary")
379 BOOLEAN = _PropertyTypeInfo(True, "boolean")
380 CHOICES = _PropertyTypeInfo(False, "choices")
381 DOUBLE = _PropertyTypeInfo(True, "double")
382 ENUM = _PropertyTypeInfo(False, "enum")
383 FUNCTION = _PropertyTypeInfo(False, "function")
384 INT64 = _PropertyTypeInfo(True, "int64")
385 INTEGER = _PropertyTypeInfo(True, "integer")
386 OBJECT = _PropertyTypeInfo(False, "object")
387 REF = _PropertyTypeInfo(False, "ref")
388 STRING = _PropertyTypeInfo(True, "string")
[email protected]cfe484902012-02-15 14:52:32389
[email protected]cb5670c2013-04-10 06:31:08390@memoize
[email protected]4ba6bdc2012-06-18 20:40:14391def UnixName(name):
[email protected]cb5670c2013-04-10 06:31:08392 '''Returns the unix_style name for a given lowerCamelCase string.
393 '''
394 unix_name = []
395 for i, c in enumerate(name):
[email protected]e11b9aa2013-07-13 00:05:42396 if c.isupper() and i > 0 and name[i - 1] != '_':
[email protected]cb5670c2013-04-10 06:31:08397 # Replace lowerUpper with lower_Upper.
398 if name[i - 1].islower():
399 unix_name.append('_')
400 # Replace ACMEWidgets with ACME_Widgets
401 elif i + 1 < len(name) and name[i + 1].islower():
402 unix_name.append('_')
403 if c == '.':
404 # Replace hello.world with hello_world.
405 unix_name.append('_')
406 else:
407 # Everything is lowercase.
408 unix_name.append(c.lower())
409 return ''.join(unix_name)
[email protected]cfe484902012-02-15 14:52:32410
[email protected]0b255f002012-10-05 01:58:47411def _StripNamespace(name, namespace):
412 if name.startswith(namespace.name + '.'):
413 return name[len(namespace.name + '.'):]
414 return name
415
[email protected]116f0a3a2012-04-19 04:22:38416def _GetModelHierarchy(entity):
[email protected]feba21e2012-03-02 15:05:27417 """Returns the hierarchy of the given model entity."""
418 hierarchy = []
[email protected]242d5e7a2013-01-17 06:50:31419 while entity is not None:
420 hierarchy.append(getattr(entity, 'name', repr(entity)))
421 if isinstance(entity, Namespace):
422 hierarchy.insert(0, ' in %s' % entity.source_file)
423 entity = getattr(entity, 'parent', None)
[email protected]feba21e2012-03-02 15:05:27424 hierarchy.reverse()
425 return hierarchy
[email protected]116f0a3a2012-04-19 04:22:38426
[email protected]242d5e7a2013-01-17 06:50:31427def _GetTypes(parent, json, namespace, origin):
428 """Creates Type objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38429 """
[email protected]242d5e7a2013-01-17 06:50:31430 types = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38431 for type_json in json.get('types', []):
[email protected]242d5e7a2013-01-17 06:50:31432 type_ = Type(parent, type_json['id'], type_json, namespace, origin)
433 types[type_.name] = type_
434 return types
[email protected]116f0a3a2012-04-19 04:22:38435
[email protected]242d5e7a2013-01-17 06:50:31436def _GetFunctions(parent, json, namespace):
437 """Creates Function objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38438 """
[email protected]242d5e7a2013-01-17 06:50:31439 functions = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38440 for function_json in json.get('functions', []):
[email protected]242d5e7a2013-01-17 06:50:31441 function = Function(parent,
442 function_json['name'],
443 function_json,
444 namespace,
445 Origin(from_json=True))
446 functions[function.name] = function
447 return functions
[email protected]116f0a3a2012-04-19 04:22:38448
[email protected]242d5e7a2013-01-17 06:50:31449def _GetEvents(parent, json, namespace):
450 """Creates Function objects generated from the events in |json|.
[email protected]b741e8f2012-07-16 21:47:24451 """
[email protected]242d5e7a2013-01-17 06:50:31452 events = OrderedDict()
[email protected]b741e8f2012-07-16 21:47:24453 for event_json in json.get('events', []):
[email protected]242d5e7a2013-01-17 06:50:31454 event = Function(parent,
455 event_json['name'],
456 event_json,
457 namespace,
458 Origin(from_client=True))
459 events[event.name] = event
460 return events
[email protected]b741e8f2012-07-16 21:47:24461
[email protected]242d5e7a2013-01-17 06:50:31462def _GetProperties(parent, json, namespace, origin):
463 """Generates Property objects extracted from |json|.
[email protected]116f0a3a2012-04-19 04:22:38464 """
[email protected]242d5e7a2013-01-17 06:50:31465 properties = OrderedDict()
[email protected]116f0a3a2012-04-19 04:22:38466 for name, property_json in json.get('properties', {}).items():
[email protected]627b54d2013-02-04 23:53:59467 properties[name] = Property(parent, name, property_json, namespace, origin)
[email protected]242d5e7a2013-01-17 06:50:31468 return properties
[email protected]4636c832013-01-11 02:10:11469
470class _PlatformInfo(_Enum):
471 def __init__(self, name):
472 _Enum.__init__(self, name)
473
474class Platforms(object):
475 """Enum of the possible platforms.
476 """
477 CHROMEOS = _PlatformInfo("chromeos")
478 CHROMEOS_TOUCH = _PlatformInfo("chromeos_touch")
479 LINUX = _PlatformInfo("linux")
480 MAC = _PlatformInfo("mac")
481 WIN = _PlatformInfo("win")
482
483def _GetPlatforms(json):
484 if 'platforms' not in json:
485 return None
486 platforms = []
487 for platform_name in json['platforms']:
488 for platform_enum in _Enum.GetAll(Platforms):
489 if platform_name == platform_enum.name:
490 platforms.append(platform_enum)
491 break
492 return platforms