OLD | NEW |
---|---|
(Empty) | |
1 # Copyright 2013 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 | |
5 import collections | |
6 import json | |
7 | |
8 | |
9 def _NameForNode(node): | |
10 '''Creates a unique id for an object in an API schema, depending on | |
11 what type of attribute the object is a member of. | |
12 ''' | |
13 if 'namespace' in node: return node['namespace'] | |
14 if 'name' in node: return node['name'] | |
15 if 'id' in node: return node['id'] | |
16 if 'type' in node: return node['type'] | |
17 assert False, 'Problems with naming node: %s' % json.dumps(node, indent=3) | |
18 | |
19 | |
20 def _IsObjectList(value): | |
21 '''Determines whether or not |value| is a list made up entirely of | |
22 dict-like objects. | |
23 ''' | |
24 return (isinstance(value, collections.Iterable) and | |
25 all(isinstance(node, collections.Mapping) for node in value)) | |
26 | |
27 | |
28 def _CreateMap(root): | |
29 '''Recursively moves through an API schema, replacing lists of objects | |
30 and non-object values with objects. | |
31 ''' | |
32 api_schema_map = {} | |
33 if _IsObjectList(root): | |
34 for node in root: | |
35 name = _NameForNode(node) | |
36 assert name not in api_schema_map, 'Duplicate name in availability map.' | |
37 api_schema_map[name] = dict((key, _CreateMap(value)) for key, value | |
38 in node.iteritems()) | |
39 elif isinstance(root, collections.Mapping): | |
40 for name, node in root.iteritems(): | |
41 api_schema_map[name] = dict((key, _CreateMap(value)) for key, value | |
42 in node.iteritems()) | |
43 return api_schema_map | |
44 | |
45 | |
46 def _Subtract(minuend, subtrahend): | |
47 ''' A Set Difference adaptation for maps. Returns a |difference|, | |
48 which contains key-value pairs found in |minuend| but not in | |
49 |subtrahend|. | |
50 ''' | |
51 difference = {} | |
52 for key in minuend: | |
53 if key not in subtrahend: | |
54 # Record all of this key's children as being part of the difference. | |
55 difference[key] = _Subtract(minuend[key], {}) | |
56 else: | |
57 # Note that |minuend| and |subtrahend| are assumed to be maps, and | |
58 # therefore should have no lists present, only keys and nodes. | |
59 rest = _Subtract(minuend[key], subtrahend[key]) | |
60 if rest: | |
61 # Record a difference if children of this key differed at some point. | |
62 difference[key] = rest | |
63 return difference | |
64 | |
65 | |
66 class APISchemaMap(object): | |
not at google - send to devlin
2013/09/16 14:06:24
I preferred Graph, and "graph" naming rather than
epeterson
2013/09/16 17:47:23
Done. I considered 'tree' earlier on but decided i
| |
67 '''Provides an interface for interacting with an API schema map, a | |
68 nested dict structure that allows for simpler lookups of schema data. | |
69 ''' | |
70 | |
71 def __init__(self, api_schema): | |
72 self._map = _CreateMap(api_schema) | |
73 | |
74 def Subtract(self, other): | |
75 '''Returns an APISchemaMap instance representing keys that are in | |
76 this map but not in |other|. | |
77 ''' | |
78 return APISchemaMap(_Subtract(self._map, other._map)) | |
79 | |
80 def Lookup(self, *path): | |
81 '''Given a list of path components, |path|, checks if the | |
82 APISchemaMap instance contains |path|. | |
83 ''' | |
84 node = self._map | |
85 for path_piece in path: | |
86 node = node.get(path_piece) | |
87 if node is None: | |
88 return False | |
89 return True | |
OLD | NEW |