Chromium Code Reviews| Index: tools/json_schema_compiler/model.py |
| diff --git a/tools/json_schema_compiler/model.py b/tools/json_schema_compiler/model.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e4c3bcfc473c5a26b31bc77477e7435d1ab6365f |
| --- /dev/null |
| +++ b/tools/json_schema_compiler/model.py |
| @@ -0,0 +1,138 @@ |
| +# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +import os.path |
| + |
| +class Model(object): |
| + """Model of the API. |
|
Yoyo Zhou
2012/01/19 02:19:40
This is a little vague. What API is it modeling? T
calamity
2012/01/20 01:10:25
Comment has been changed. Still not sure if it's d
|
| + """ |
| + def __init__(self): |
| + self.namespaces = {} |
| + self.types = {} |
| + |
| + def add_namespace(self, json, source_file, namespace_suffix): |
| + """Add a namespace's json to the model if it has a "compile" property set |
| + to true. Returns the new namespace or None if a namespac wasn't added. |
|
Yoyo Zhou
2012/01/19 02:19:40
typo: namespac
calamity
2012/01/20 01:10:25
Done.
|
| + """ |
| + if not json.get('compile'): |
| + return None |
| + namespace = Namespace(json, source_file, namespace_suffix) |
| + self.namespaces[namespace.name] = namespace |
| + for tipe in namespace.types.values(): |
|
Yoyo Zhou
2012/01/19 02:19:40
type_ is better than tipe.
calamity
2012/01/20 01:10:25
Done.
|
| + self.types[tipe.name] = namespace |
| + return namespace |
| + |
| +class Namespace(object): |
| + """An API namespace. |
| + """ |
| + def __init__(self, json, source_file, namespace_suffix): |
| + self.name = json['namespace'] |
| + self.source_file = source_file |
| + self.source_file_dir, self.source_file_filename = os.path.split(source_file) |
| + self.target_namespace = self.name + namespace_suffix |
| + self.type_dependencies = {} |
| + self.types = {} |
| + self.functions = {} |
| + for type_json in json['types']: |
| + tipe = Type(type_json) |
| + self.types[tipe.name] = tipe |
| + for function_json in json['functions']: |
| + if not function_json.get('nocompile'): |
| + function = Function(function_json) |
| + self.functions[function.name] = function |
| + |
| +class Type(object): |
| + """A Type defined in the json. |
| + """ |
| + def __init__(self, json): |
| + self.name = json['id'] |
| + self.description = json.get('description') |
| + self.properties = {} |
| + for prop_name, prop_json in json['properties'].items(): |
| + self.properties[prop_name] = Property(prop_name, prop_json) |
| + |
| +class Callback(object): |
| + """A callback parameter to a Function. |
| + """ |
| + def __init__(self, json): |
| + params = json['parameters'] |
| + if len(params) == 0: |
| + self.param = None |
| + elif len(params) == 1: |
| + param = params[0] |
| + self.param = Property(param['name'], param) |
| + else: |
| + raise AssertionError("Callbacks can have at most a single parameter") |
|
Yoyo Zhou
2012/01/19 02:19:40
Where does this constraint come from?
calamity
2012/01/20 01:10:25
I believe it's just how the extensions api system
|
| + |
| +class Function(object): |
| + """A Function defined in the API. |
| + """ |
| + def __init__(self, json): |
| + self.name = json['name'] |
| + self.params = [] |
| + self.description = json['description'] |
| + self.callback = None |
| + self.type_dependencies = {} |
| + for param in json['parameters']: |
| + if param.get('type') == 'function': |
| + assert (not self.callback), "Function has more than one callback" |
| + self.callback = Callback(param) |
| + else: |
| + self.params.append(Property(param['name'], param)) |
| + assert (self.callback), "Function does not support callback" |
| + |
| +# TODO(calamity): handle Enum/choices |
| +class Property(object): |
| + """A property of a type OR a parameter to a function. |
| + |
| + Members will change based on PropertyType. Check self.type to determine which |
| + members actually exist. |
| + """ |
| + def __init__(self, name, json): |
| + self.name = name |
| + self.optional = json.get('optional', False) |
| + self.description = json.get('description') |
| + # TODO(calamity) maybe check for circular refs? could that be a problem? |
| + if '$ref' in json: |
| + self.ref_type = json['$ref'] |
| + self.type = PropertyType.REF |
| + elif 'type' in json: |
| + json_type = json['type'] |
| + if json_type == 'string': |
| + self.type = PropertyType.STRING |
|
Yoyo Zhou
2012/01/19 02:19:40
I think even though you can name an attribute the
calamity
2012/01/20 01:10:25
Done.
|
| + elif json_type == 'boolean': |
| + self.type = PropertyType.BOOLEAN |
| + elif json_type == 'integer': |
| + self.type = PropertyType.INTEGER |
| + elif json_type == 'double': |
| + self.type = PropertyType.DOUBLE |
| + elif json_type == 'array': |
| + self.item_type = Property(name + "_inner", json['items']) |
| + self.type = PropertyType.ARRAY |
| + elif json_type == 'object': |
| + self.properties = {} |
| + self.type = PropertyType.OBJECT |
| + for key, val in json['properties'].items(): |
| + self.properties[key] = Property(key, val) |
| + else: |
| + raise NotImplementedError(json_type) |
| + elif 'choices' in json: |
| + self.type = PropertyType.CHOICES |
| + self.choices = {} |
| + |
| +class PropertyType(object): |
| + """Enum of different types of properties/parameters. |
| + """ |
| + class __Info(object): |
| + def __init__(self, is_fundamental): |
| + self.is_fundamental = is_fundamental |
| + |
| + INTEGER = __Info(True) |
| + DOUBLE = __Info(True) |
| + BOOLEAN = __Info(True) |
| + STRING = __Info(True) |
| + ARRAY = __Info(False) |
| + REF = __Info(False) |
| + CHOICES = __Info(False) |
| + OBJECT = __Info(False) |