Index: chrome/common/extensions/docs/server2/availability_graph.py |
diff --git a/chrome/common/extensions/docs/server2/availability_graph.py b/chrome/common/extensions/docs/server2/availability_graph.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3d3133deb8aa1caefe986f12a31e76652f87d6ee |
--- /dev/null |
+++ b/chrome/common/extensions/docs/server2/availability_graph.py |
@@ -0,0 +1,102 @@ |
+# Copyright 2013 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. |
+ |
+_ATTRIBUTES = ('events', 'functions', 'parameters', 'properties', 'types') |
not at google - send to devlin
2013/09/06 23:29:38
I'm thinking this shouldn't care about what the co
epeterson
2013/09/12 00:32:01
Done.
|
+ |
+ |
+def _NameForNode(node, node_type): |
+ '''Creates a unique id for an object in an API schema, depending on |
+ what type of attribute the object is a member of. |
+ ''' |
+ if node_type == 'properties': return node |
+ if node_type == 'types': return node['id'] |
+ if node_type is None: return node['namespace'] |
+ if 'name' in node: |
+ return node['name'] |
+ # The API Schema probably had an error here. Fall back to the 'type' field to |
+ # avoid raising an error. |
+ return node['type'] |
+ |
+ |
+def _CreateGraph(api_schema, node_type=None): |
+ '''Recursively move through an API schema, replacing lists of objects |
+ for each attribute listed in |attributes| with a dict containing a |
+ key for each object in the list. |
+ ''' |
+ availability_graph = {} |
+ for node in api_schema: |
not at google - send to devlin
2013/09/06 23:29:38
confusing dicts and lists here is.. odd. And I can
epeterson
2013/09/12 00:32:01
Done.
|
+ name = _NameForNode(node, node_type) |
not at google - send to devlin
2013/09/06 23:29:38
how about asserting "name not in graph" here.
epeterson
2013/09/12 00:32:01
Done.
|
+ availability_graph[name] = { 'availability': None } |
+ if node_type == 'properties': |
+ # The 'properties' attribute is a key -> value mapping. Grab the value. |
+ node = api_schema[node] |
+ for attribute in _ATTRIBUTES: |
+ if attribute in node: |
+ availability_graph[name][attribute] = _CreateGraph(node[attribute], |
+ node_type=attribute) |
+ return availability_graph |
+ |
+ |
+class AvailabilityGraph(object): |
+ '''Represents an API schema as a nested dict structure, where lists of |
+ schema nodes (falling under one of |_ATTRIBUTES|) are converted to |
+ dicts with a key representing each node. Availability information for |
+ schema nodes is tracked as the graph is created and processed. |
+ ''' |
+ |
+ def __init__(self, api_schema, channel_info): |
+ self.graph = _CreateGraph(api_schema) |
+ self.channel_info = channel_info |
not at google - send to devlin
2013/09/06 23:29:38
these need to be private.
epeterson
2013/09/12 00:32:01
Done.
|
+ self._paths = [] |
+ |
+ def SetPaths(self, other): |
+ '''Sets a list of '/'-delimited dictionary-keys, or 'paths', that |
+ exist in this object's |graph| but not in |other|'s graph. Update |
+ 'availability' for keys based on which graphs they are initially |
+ found in. |
+ ''' |
+ def get_missing_paths(this_graph, other_graph, path=''): |
+ paths = [] |
+ for key in this_graph: |
+ if key == 'availability': |
+ continue |
+ current_path = '%s/%s' % (path, key) if path else key |
+ paths.extend(get_missing_paths(this_graph[key], |
+ other_graph.get(key, {}), |
+ current_path)) |
+ if key not in _ATTRIBUTES: |
+ # Add the path if the value was not available upon the API's release. |
+ if key not in other_graph: |
+ this_graph[key]['availability'] = self.channel_info |
+ paths.append(current_path) |
+ else: |
+ this_graph[key]['availability'] = other.channel_info |
+ return paths |
+ |
+ self._paths = get_missing_paths(self.graph, other.graph) |
+ |
+ def UpdatePaths(self, other): |
+ '''Check each path in |_paths|, removing a path if it has become |
+ available and updating that path's availability in the |graph|. |
+ ''' |
+ for path in self._paths[:]: |
+ path_pieces = path.split('/') |
+ if other.Lookup(*path_pieces) is not None: |
+ node = self.graph |
+ for path_piece in path_pieces: |
+ node = node[path_piece] |
+ node['availability'] = other.channel_info |
+ self._paths.remove(path) |
+ return bool(self._paths) |
not at google - send to devlin
2013/09/06 23:29:38
Would a better set of methods on this class be som
epeterson
2013/09/12 00:32:01
Done.
|
+ |
+ def Lookup(self, *path): |
+ '''Given a list of path components, |path|, checks if |graph| |
+ contains |path| and returns its availability if found. |
+ ''' |
+ node = self.graph |
+ for path_piece in path: |
+ node = node.get(path_piece) |
+ if node is None: |
+ return None |
+ return node.get('availability') |