Home | History | Annotate | Download | only in docs
      1 #!/usr/bin/python
      2 
      3 #
      4 # Copyright (C) 2012 The Android Open Source Project
      5 #
      6 # Licensed under the Apache License, Version 2.0 (the "License");
      7 # you may not use this file except in compliance with the License.
      8 # You may obtain a copy of the License at
      9 #
     10 #      http://www.apache.org/licenses/LICENSE-2.0
     11 #
     12 # Unless required by applicable law or agreed to in writing, software
     13 # distributed under the License is distributed on an "AS IS" BASIS,
     14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 # See the License for the specific language governing permissions and
     16 # limitations under the License.
     17 #
     18 
     19 """
     20 A set of classes (models) each closely representing an XML node in the
     21 metadata_properties.xml file.
     22 
     23   Node: Base class for most nodes.
     24   Entry: A node corresponding to <entry> elements.
     25   Clone: A node corresponding to <clone> elements.
     26   MergedEntry: A node corresponding to either <entry> or <clone> elements.
     27   Kind: A node corresponding to <dynamic>, <static>, <controls> elements.
     28   InnerNamespace: A node corresponding to a <namespace> nested under a <kind>.
     29   OuterNamespace: A node corresponding to a <namespace> with <kind> children.
     30   Section: A node corresponding to a <section> element.
     31   Enum: A class corresponding an <enum> element within an <entry>
     32   EnumValue: A class corresponding to a <value> element within an Enum
     33   Metadata: Root node that also provides tree construction functionality.
     34   Tag: A node corresponding to a top level <tag> element.
     35   Typedef: A node corresponding to a <typedef> element under <types>.
     36 """
     37 
     38 import sys
     39 import itertools
     40 from collections import OrderedDict
     41 
     42 class Node(object):
     43   """
     44   Base class for most nodes that are part of the Metadata graph.
     45 
     46   Attributes (Read-Only):
     47     parent: An edge to a parent Node.
     48     name: A string describing the name, usually but not always the 'name'
     49           attribute of the corresponding XML node.
     50   """
     51 
     52   def __init__(self):
     53     self._parent = None
     54     self._name = None
     55 
     56   @property
     57   def parent(self):
     58     return self._parent
     59 
     60   @property
     61   def name(self):
     62     return self._name
     63 
     64   def find_all(self, pred):
     65     """
     66     Find all descendants that match the predicate.
     67 
     68     Args:
     69       pred: a predicate function that acts as a filter for a Node
     70 
     71     Yields:
     72       A sequence of all descendants for which pred(node) is true,
     73       in a pre-order visit order.
     74     """
     75     if pred(self):
     76       yield self
     77 
     78     if self._get_children() is None:
     79       return
     80 
     81     for i in self._get_children():
     82       for j in i.find_all(pred):
     83         yield j
     84 
     85   def find_first(self, pred):
     86     """
     87     Find the first descendant that matches the predicate.
     88 
     89     Args:
     90       pred: a predicate function that acts as a filter for a Node
     91 
     92     Returns:
     93       The first Node from find_all(pred), or None if there were no results.
     94     """
     95     for i in self.find_all(pred):
     96       return i
     97 
     98     return None
     99 
    100   def find_parent_first(self, pred):
    101     """
    102     Find the first ancestor that matches the predicate.
    103 
    104     Args:
    105       pred: A predicate function that acts as a filter for a Node
    106 
    107     Returns:
    108       The first ancestor closest to the node for which pred(node) is true.
    109     """
    110     for i in self.find_parents(pred):
    111       return i
    112 
    113     return None
    114 
    115   def find_parents(self, pred):
    116     """
    117     Find all ancestors that match the predicate.
    118 
    119     Args:
    120       pred: A predicate function that acts as a filter for a Node
    121 
    122     Yields:
    123       A sequence of all ancestors (closest to furthest) from the node,
    124       where pred(node) is true.
    125     """
    126     parent = self.parent
    127 
    128     while parent is not None:
    129       if pred(parent):
    130         yield parent
    131       parent = parent.parent
    132 
    133   def sort_children(self):
    134     """
    135     Sorts the immediate children in-place.
    136     """
    137     self._sort_by_name(self._children)
    138 
    139   def _sort_by_name(self, what):
    140     what.sort(key=lambda x: x.name)
    141 
    142   def _get_name(self):
    143     return lambda x: x.name
    144 
    145   # Iterate over all children nodes. None when node doesn't support children.
    146   def _get_children(self):
    147     return (i for i in self._children)
    148 
    149   def _children_name_map_matching(self, match=lambda x: True):
    150     d = {}
    151     for i in self._get_children():
    152       if match(i):
    153         d[i.name] = i
    154     return d
    155 
    156   @staticmethod
    157   def _dictionary_by_name(values):
    158     d = OrderedDict()
    159     for i in values:
    160       d[i.name] = i
    161 
    162     return d
    163 
    164   def validate_tree(self):
    165     """
    166     Sanity check the tree recursively, ensuring for a node n, all children's
    167     parents are also n.
    168 
    169     Returns:
    170       True if validation succeeds, False otherwise.
    171     """
    172     succ = True
    173     children = self._get_children()
    174     if children is None:
    175       return True
    176 
    177     for child in self._get_children():
    178       if child.parent != self:
    179         print >> sys.stderr, ("ERROR: Node '%s' doesn't match the parent" +    \
    180                              "(expected: %s, actual %s)")                      \
    181                              %(child, self, child.parent)
    182         succ = False
    183 
    184       succ = child.validate_tree() and succ
    185 
    186     return succ
    187 
    188   def __str__(self):
    189     return "<%s name='%s'>" %(self.__class__, self.name)
    190 
    191 class Metadata(Node):
    192   """
    193   A node corresponding to a <metadata> entry.
    194 
    195   Attributes (Read-Only):
    196     parent: An edge to the parent Node. This is always None for Metadata.
    197     outer_namespaces: A sequence of immediate OuterNamespace children.
    198     tags: A sequence of all Tag instances available in the graph.
    199     types: An iterable of all Typedef instances available in the graph.
    200   """
    201 
    202   def __init__(self):
    203     """
    204     Initialize with no children. Use insert_* functions and then
    205     construct_graph() to build up the Metadata from some source.
    206     """
    207 
    208 # Private
    209     self._entries = []
    210     # kind => { name => entry }
    211     self._entry_map = { 'static': {}, 'dynamic': {}, 'controls': {} }
    212     self._entries_ordered = [] # list of ordered Entry/Clone instances
    213     self._clones = []
    214 
    215 # Public (Read Only)
    216     self._parent = None
    217     self._outer_namespaces = None
    218     self._tags = []
    219     self._types = []
    220 
    221   @property
    222   def outer_namespaces(self):
    223     if self._outer_namespaces is None:
    224       return None
    225     else:
    226       return (i for i in self._outer_namespaces)
    227 
    228   @property
    229   def tags(self):
    230     return (i for i in self._tags)
    231 
    232   @property
    233   def types(self):
    234     return (i for i in self._types)
    235 
    236   def _get_properties(self):
    237 
    238     for i in self._entries:
    239       yield i
    240 
    241     for i in self._clones:
    242       yield i
    243 
    244   def insert_tag(self, tag, description=""):
    245     """
    246     Insert a tag into the metadata.
    247 
    248     Args:
    249       tag: A string identifier for a tag.
    250       description: A string description for a tag.
    251 
    252     Example:
    253       metadata.insert_tag("BC", "Backwards Compatibility for old API")
    254 
    255     Remarks:
    256       Subsequent calls to insert_tag with the same tag are safe (they will
    257       be ignored).
    258     """
    259     tag_ids = [tg.name for tg in self.tags if tg.name == tag]
    260     if not tag_ids:
    261       self._tags.append(Tag(tag, self, description))
    262 
    263   def insert_type(self, type_name, type_selector="typedef", **kwargs):
    264     """
    265     Insert a type into the metadata.
    266 
    267     Args:
    268       type_name: A type's name
    269       type_selector: The selector for the type, e.g. 'typedef'
    270 
    271     Args (if type_selector == 'typedef'):
    272       languages: A map of 'language name' -> 'fully qualified class path'
    273 
    274     Example:
    275       metadata.insert_type('rectangle', 'typedef',
    276                            { 'java': 'android.graphics.Rect' })
    277 
    278     Remarks:
    279       Subsequent calls to insert_type with the same type name are safe (they
    280       will be ignored)
    281     """
    282 
    283     if type_selector != 'typedef':
    284       raise ValueError("Unsupported type_selector given " + type_selector)
    285 
    286     type_names = [tp.name for tp in self.types if tp.name == tp]
    287     if not type_names:
    288       self._types.append(Typedef(type_name, self, kwargs.get('languages')))
    289 
    290   def insert_entry(self, entry):
    291     """
    292     Insert an entry into the metadata.
    293 
    294     Args:
    295       entry: A key-value dictionary describing an entry. Refer to
    296              Entry#__init__ for the keys required/optional.
    297 
    298     Remarks:
    299       Subsequent calls to insert_entry with the same entry+kind name are safe
    300       (they will be ignored).
    301     """
    302     e = Entry(**entry)
    303     self._entries.append(e)
    304     self._entry_map[e.kind][e.name] = e
    305     self._entries_ordered.append(e)
    306 
    307   def insert_clone(self, clone):
    308     """
    309     Insert a clone into the metadata.
    310 
    311     Args:
    312       clone: A key-value dictionary describing a clone. Refer to
    313             Clone#__init__ for the keys required/optional.
    314 
    315     Remarks:
    316       Subsequent calls to insert_clone with the same clone+kind name are safe
    317       (they will be ignored). Also the target entry need not be inserted
    318       ahead of the clone entry.
    319     """
    320     # figure out corresponding entry later. allow clone insert, entry insert
    321     entry = None
    322     c = Clone(entry, **clone)
    323     self._entry_map[c.kind][c.name] = c
    324     self._clones.append(c)
    325     self._entries_ordered.append(c)
    326 
    327   def prune_clones(self):
    328     """
    329     Remove all clones that don't point to an existing entry.
    330 
    331     Remarks:
    332       This should be called after all insert_entry/insert_clone calls have
    333       finished.
    334     """
    335     remove_list = []
    336     for p in self._clones:
    337       if p.entry is None:
    338         remove_list.append(p)
    339 
    340     for p in remove_list:
    341 
    342       # remove from parent's entries list
    343       if p.parent is not None:
    344         p.parent._entries.remove(p)
    345       # remove from parents' _leafs list
    346       for ancestor in p.find_parents(lambda x: not isinstance(x, Metadata)):
    347         ancestor._leafs.remove(p)
    348 
    349       # remove from global list
    350       self._clones.remove(p)
    351       self._entry_map[p.kind].pop(p.name)
    352       self._entries_ordered.remove(p)
    353 
    354 
    355   # After all entries/clones are inserted,
    356   # invoke this to generate the parent/child node graph all these objects
    357   def construct_graph(self):
    358     """
    359     Generate the graph recursively, after which all Entry nodes will be
    360     accessible recursively by crawling through the outer_namespaces sequence.
    361 
    362     Remarks:
    363       This is safe to be called multiple times at any time. It should be done at
    364       least once or there will be no graph.
    365     """
    366     self.validate_tree()
    367     self._construct_tags()
    368     self.validate_tree()
    369     self._construct_types()
    370     self.validate_tree()
    371     self._construct_clones()
    372     self.validate_tree()
    373     self._construct_outer_namespaces()
    374     self.validate_tree()
    375 
    376   def _construct_tags(self):
    377     tag_dict = self._dictionary_by_name(self.tags)
    378     for p in self._get_properties():
    379       p._tags = []
    380       for tag_id in p._tag_ids:
    381         tag = tag_dict.get(tag_id)
    382 
    383         if tag not in p._tags:
    384           p._tags.append(tag)
    385 
    386         if p not in tag.entries:
    387           tag._entries.append(p)
    388 
    389   def _construct_types(self):
    390     type_dict = self._dictionary_by_name(self.types)
    391     for p in self._get_properties():
    392       if p._type_name:
    393         type_node = type_dict.get(p._type_name)
    394         p._typedef = type_node
    395 
    396         if p not in type_node.entries:
    397           type_node._entries.append(p)
    398 
    399   def _construct_clones(self):
    400     for p in self._clones:
    401       target_kind = p.target_kind
    402       target_entry = self._entry_map[target_kind].get(p.name)
    403       p._entry = target_entry
    404 
    405       # should not throw if we pass validation
    406       # but can happen when importing obsolete CSV entries
    407       if target_entry is None:
    408         print >> sys.stderr, ("WARNING: Clone entry '%s' target kind '%s'" +   \
    409                               " has no corresponding entry")                   \
    410                              %(p.name, p.target_kind)
    411 
    412   def _construct_outer_namespaces(self):
    413 
    414     if self._outer_namespaces is None: #the first time this runs
    415       self._outer_namespaces = []
    416 
    417     root = self._dictionary_by_name(self._outer_namespaces)
    418     for ons_name, ons in root.iteritems():
    419       ons._leafs = []
    420 
    421     for p in self._entries_ordered:
    422       ons_name = p.get_outer_namespace()
    423       ons = root.get(ons_name, OuterNamespace(ons_name, self))
    424       root[ons_name] = ons
    425 
    426       if p not in ons._leafs:
    427         ons._leafs.append(p)
    428 
    429     for ons_name, ons in root.iteritems():
    430 
    431       ons.validate_tree()
    432 
    433       self._construct_sections(ons)
    434 
    435       if ons not in self._outer_namespaces:
    436         self._outer_namespaces.append(ons)
    437 
    438       ons.validate_tree()
    439 
    440   def _construct_sections(self, outer_namespace):
    441 
    442     sections_dict = self._dictionary_by_name(outer_namespace.sections)
    443     for sec_name, sec in sections_dict.iteritems():
    444       sec._leafs = []
    445       sec.validate_tree()
    446 
    447     for p in outer_namespace._leafs:
    448       does_exist = sections_dict.get(p.get_section())
    449 
    450       sec = sections_dict.get(p.get_section(), \
    451           Section(p.get_section(), outer_namespace))
    452       sections_dict[p.get_section()] = sec
    453 
    454       sec.validate_tree()
    455 
    456       if p not in sec._leafs:
    457         sec._leafs.append(p)
    458 
    459     for sec_name, sec in sections_dict.iteritems():
    460 
    461       if not sec.validate_tree():
    462         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
    463                              "construct_sections (start), with section = '%s'")\
    464                              %(sec)
    465 
    466       self._construct_kinds(sec)
    467 
    468       if sec not in outer_namespace.sections:
    469         outer_namespace._sections.append(sec)
    470 
    471       if not sec.validate_tree():
    472         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
    473                               "construct_sections (end), with section = '%s'") \
    474                              %(sec)
    475 
    476   # 'controls', 'static' 'dynamic'. etc
    477   def _construct_kinds(self, section):
    478     for kind in section.kinds:
    479       kind._leafs = []
    480       section.validate_tree()
    481 
    482     group_entry_by_kind = itertools.groupby(section._leafs, lambda x: x.kind)
    483     leaf_it = ((k, g) for k, g in group_entry_by_kind)
    484 
    485     # allow multiple kinds with the same name. merge if adjacent
    486     # e.g. dynamic,dynamic,static,static,dynamic -> dynamic,static,dynamic
    487     # this helps maintain ABI compatibility when adding an entry in a new kind
    488     for idx, (kind_name, entry_it) in enumerate(leaf_it):
    489       if idx >= len(section._kinds):
    490         kind = Kind(kind_name, section)
    491         section._kinds.append(kind)
    492         section.validate_tree()
    493 
    494       kind = section._kinds[idx]
    495 
    496       for p in entry_it:
    497         if p not in kind._leafs:
    498           kind._leafs.append(p)
    499 
    500     for kind in section._kinds:
    501       kind.validate_tree()
    502       self._construct_inner_namespaces(kind)
    503       kind.validate_tree()
    504       self._construct_entries(kind)
    505       kind.validate_tree()
    506 
    507       if not section.validate_tree():
    508         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
    509                              "construct_kinds, with kind = '%s'") %(kind)
    510 
    511       if not kind.validate_tree():
    512         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
    513                               "construct_kinds, with kind = '%s'") %(kind)
    514 
    515   def _construct_inner_namespaces(self, parent, depth=0):
    516     #parent is InnerNamespace or Kind
    517     ins_dict = self._dictionary_by_name(parent.namespaces)
    518     for name, ins in ins_dict.iteritems():
    519       ins._leafs = []
    520 
    521     for p in parent._leafs:
    522       ins_list = p.get_inner_namespace_list()
    523 
    524       if len(ins_list) > depth:
    525         ins_str = ins_list[depth]
    526         ins = ins_dict.get(ins_str, InnerNamespace(ins_str, parent))
    527         ins_dict[ins_str] = ins
    528 
    529         if p not in ins._leafs:
    530           ins._leafs.append(p)
    531 
    532     for name, ins in ins_dict.iteritems():
    533       ins.validate_tree()
    534       # construct children INS
    535       self._construct_inner_namespaces(ins, depth + 1)
    536       ins.validate_tree()
    537       # construct children entries
    538       self._construct_entries(ins, depth + 1)
    539 
    540       if ins not in parent.namespaces:
    541         parent._namespaces.append(ins)
    542 
    543       if not ins.validate_tree():
    544         print >> sys.stderr, ("ERROR: Failed to validate tree in " +           \
    545                               "construct_inner_namespaces, with ins = '%s'")   \
    546                              %(ins)
    547 
    548   # doesnt construct the entries, so much as links them
    549   def _construct_entries(self, parent, depth=0):
    550     #parent is InnerNamespace or Kind
    551     entry_dict = self._dictionary_by_name(parent.entries)
    552     for p in parent._leafs:
    553       ins_list = p.get_inner_namespace_list()
    554 
    555       if len(ins_list) == depth:
    556         entry = entry_dict.get(p.name, p)
    557         entry_dict[p.name] = entry
    558 
    559     for name, entry in entry_dict.iteritems():
    560 
    561       old_parent = entry.parent
    562       entry._parent = parent
    563 
    564       if entry not in parent.entries:
    565         parent._entries.append(entry)
    566 
    567       if old_parent is not None and old_parent != parent:
    568         print >> sys.stderr, ("ERROR: Parent changed from '%s' to '%s' for " + \
    569                               "entry '%s'")                                    \
    570                              %(old_parent.name, parent.name, entry.name)
    571 
    572   def _get_children(self):
    573     if self.outer_namespaces is not None:
    574       for i in self.outer_namespaces:
    575         yield i
    576 
    577     if self.tags is not None:
    578       for i in self.tags:
    579         yield i
    580 
    581 class Tag(Node):
    582   """
    583   A tag Node corresponding to a top-level <tag> element.
    584 
    585   Attributes (Read-Only):
    586     name: alias for id
    587     id: The name of the tag, e.g. for <tag id="BC"/> id = 'BC'
    588     description: The description of the tag, the contents of the <tag> element.
    589     parent: An edge to the parent, which is always the Metadata root node.
    590     entries: A sequence of edges to entries/clones that are using this Tag.
    591   """
    592   def __init__(self, name, parent, description=""):
    593     self._name        = name  # 'id' attribute in XML
    594     self._id          = name
    595     self._description = description
    596     self._parent      = parent
    597 
    598     # all entries that have this tag, including clones
    599     self._entries     = []  # filled in by Metadata#construct_tags
    600 
    601   @property
    602   def id(self):
    603     return self._id
    604 
    605   @property
    606   def description(self):
    607     return self._description
    608 
    609   @property
    610   def entries(self):
    611     return (i for i in self._entries)
    612 
    613   def _get_children(self):
    614     return None
    615 
    616 class Typedef(Node):
    617   """
    618   A typedef Node corresponding to a <typedef> element under a top-level <types>.
    619 
    620   Attributes (Read-Only):
    621     name: The name of this typedef as a string.
    622     languages: A dictionary of 'language name' -> 'fully qualified class'.
    623     parent: An edge to the parent, which is always the Metadata root node.
    624     entries: An iterable over all entries which reference this typedef.
    625   """
    626   def __init__(self, name, parent, languages=None):
    627     self._name        = name
    628     self._parent      = parent
    629 
    630     # all entries that have this typedef
    631     self._entries     = []  # filled in by Metadata#construct_types
    632 
    633     self._languages   = languages or {}
    634 
    635   @property
    636   def languages(self):
    637     return self._languages
    638 
    639   @property
    640   def entries(self):
    641     return (i for i in self._entries)
    642 
    643   def _get_children(self):
    644     return None
    645 
    646 class OuterNamespace(Node):
    647   """
    648   A node corresponding to a <namespace> element under <metadata>
    649 
    650   Attributes (Read-Only):
    651     name: The name attribute of the <namespace name="foo"> element.
    652     parent: An edge to the parent, which is always the Metadata root node.
    653     sections: A sequence of Section children.
    654   """
    655   def __init__(self, name, parent, sections=[]):
    656     self._name = name
    657     self._parent = parent # MetadataSet
    658     self._sections = sections[:]
    659     self._leafs = []
    660 
    661     self._children = self._sections
    662 
    663   @property
    664   def sections(self):
    665     return (i for i in self._sections)
    666 
    667 class Section(Node):
    668   """
    669   A node corresponding to a <section> element under <namespace>
    670 
    671   Attributes (Read-Only):
    672     name: The name attribute of the <section name="foo"> element.
    673     parent: An edge to the parent, which is always an OuterNamespace instance.
    674     description: A string description of the section, or None.
    675     kinds: A sequence of Kind children.
    676     merged_kinds: A sequence of virtual Kind children,
    677                   with each Kind's children merged by the kind.name
    678   """
    679   def __init__(self, name, parent, description=None, kinds=[]):
    680     self._name = name
    681     self._parent = parent
    682     self._description = description
    683     self._kinds = kinds[:]
    684 
    685     self._leafs = []
    686 
    687 
    688   @property
    689   def description(self):
    690     return self._description
    691 
    692   @property
    693   def kinds(self):
    694     return (i for i in self._kinds)
    695 
    696   def sort_children(self):
    697     self.validate_tree()
    698     # order is always controls,static,dynamic
    699     find_child = lambda x: [i for i in self._get_children() if i.name == x]
    700     new_lst = find_child('controls') \
    701             + find_child('static')   \
    702             + find_child('dynamic')
    703     self._kinds = new_lst
    704     self.validate_tree()
    705 
    706   def _get_children(self):
    707     return (i for i in self.kinds)
    708 
    709   @property
    710   def merged_kinds(self):
    711 
    712     def aggregate_by_name(acc, el):
    713       existing = [i for i in acc if i.name == el.name]
    714       if existing:
    715         k = existing[0]
    716       else:
    717         k = Kind(el.name, el.parent)
    718         acc.append(k)
    719 
    720       k._namespaces.extend(el._namespaces)
    721       k._entries.extend(el._entries)
    722 
    723       return acc
    724 
    725     new_kinds_lst = reduce(aggregate_by_name, self.kinds, [])
    726 
    727     for k in new_kinds_lst:
    728       yield k
    729 
    730   def combine_kinds_into_single_node(self):
    731     r"""
    732     Combines the section's Kinds into a single node.
    733 
    734     Combines all the children (kinds) of this section into a single
    735     virtual Kind node.
    736 
    737     Returns:
    738       A new Kind node that collapses all Kind siblings into one, combining
    739       all their children together.
    740 
    741       For example, given self.kinds == [ x, y ]
    742 
    743         x  y               z
    744       / |  | \    -->   / | | \
    745       a b  c d          a b c d
    746 
    747       a new instance z is returned in this example.
    748 
    749     Remarks:
    750       The children of the kinds are the same references as before, that is
    751       their parents will point to the old parents and not to the new parent.
    752     """
    753     combined = Kind(name="combined", parent=self)
    754 
    755     for k in self._get_children():
    756       combined._namespaces.extend(k.namespaces)
    757       combined._entries.extend(k.entries)
    758 
    759     return combined
    760 
    761 class Kind(Node):
    762   """
    763   A node corresponding to one of: <static>,<dynamic>,<controls> under a
    764   <section> element.
    765 
    766   Attributes (Read-Only):
    767     name: A string which is one of 'static', 'dynamic, or 'controls'.
    768     parent: An edge to the parent, which is always a Section  instance.
    769     namespaces: A sequence of InnerNamespace children.
    770     entries: A sequence of Entry/Clone children.
    771     merged_entries: A sequence of MergedEntry virtual nodes from entries
    772   """
    773   def __init__(self, name, parent):
    774     self._name = name
    775     self._parent = parent
    776     self._namespaces = []
    777     self._entries = []
    778 
    779     self._leafs = []
    780 
    781   @property
    782   def namespaces(self):
    783     return self._namespaces
    784 
    785   @property
    786   def entries(self):
    787     return self._entries
    788 
    789   @property
    790   def merged_entries(self):
    791     for i in self.entries:
    792       yield i.merge()
    793 
    794   def sort_children(self):
    795     self._namespaces.sort(key=self._get_name())
    796     self._entries.sort(key=self._get_name())
    797 
    798   def _get_children(self):
    799     for i in self.namespaces:
    800       yield i
    801     for i in self.entries:
    802       yield i
    803 
    804   def combine_children_by_name(self):
    805     r"""
    806     Combine multiple children with the same name into a single node.
    807 
    808     Returns:
    809       A new Kind where all of the children with the same name were combined.
    810 
    811       For example:
    812 
    813       Given a Kind k:
    814 
    815               k
    816             / | \
    817             a b c
    818             | | |
    819             d e f
    820 
    821       a.name == "foo"
    822       b.name == "foo"
    823       c.name == "bar"
    824 
    825       The returned Kind will look like this:
    826 
    827              k'
    828             /  \
    829             a' c'
    830           / |  |
    831           d e  f
    832 
    833     Remarks:
    834       This operation is not recursive. To combine the grandchildren and other
    835       ancestors, call this method on the ancestor nodes.
    836     """
    837     return Kind._combine_children_by_name(self, new_type=type(self))
    838 
    839   # new_type is either Kind or InnerNamespace
    840   @staticmethod
    841   def _combine_children_by_name(self, new_type):
    842     new_ins_dict = OrderedDict()
    843     new_ent_dict = OrderedDict()
    844 
    845     for ins in self.namespaces:
    846       new_ins = new_ins_dict.setdefault(ins.name,
    847                                         InnerNamespace(ins.name, parent=self))
    848       new_ins._namespaces.extend(ins.namespaces)
    849       new_ins._entries.extend(ins.entries)
    850 
    851     for ent in self.entries:
    852       new_ent = new_ent_dict.setdefault(ent.name,
    853                                         ent.merge())
    854 
    855     kind = new_type(self.name, self.parent)
    856     kind._namespaces = new_ins_dict.values()
    857     kind._entries = new_ent_dict.values()
    858 
    859     return kind
    860 
    861 class InnerNamespace(Node):
    862   """
    863   A node corresponding to a <namespace> which is an ancestor of a Kind.
    864   These namespaces may have other namespaces recursively, or entries as leafs.
    865 
    866   Attributes (Read-Only):
    867     name: Name attribute from the element, e.g. <namespace name="foo"> -> 'foo'
    868     parent: An edge to the parent, which is an InnerNamespace or a Kind.
    869     namespaces: A sequence of InnerNamespace children.
    870     entries: A sequence of Entry/Clone children.
    871     merged_entries: A sequence of MergedEntry virtual nodes from entries
    872   """
    873   def __init__(self, name, parent):
    874     self._name        = name
    875     self._parent      = parent
    876     self._namespaces  = []
    877     self._entries     = []
    878     self._leafs       = []
    879 
    880   @property
    881   def namespaces(self):
    882     return self._namespaces
    883 
    884   @property
    885   def entries(self):
    886     return self._entries
    887 
    888   @property
    889   def merged_entries(self):
    890     for i in self.entries:
    891       yield i.merge()
    892 
    893   def sort_children(self):
    894     self._namespaces.sort(key=self._get_name())
    895     self._entries.sort(key=self._get_name())
    896 
    897   def _get_children(self):
    898     for i in self.namespaces:
    899       yield i
    900     for i in self.entries:
    901       yield i
    902 
    903   def combine_children_by_name(self):
    904     r"""
    905     Combine multiple children with the same name into a single node.
    906 
    907     Returns:
    908       A new InnerNamespace where all of the children with the same name were
    909       combined.
    910 
    911       For example:
    912 
    913       Given an InnerNamespace i:
    914 
    915               i
    916             / | \
    917             a b c
    918             | | |
    919             d e f
    920 
    921       a.name == "foo"
    922       b.name == "foo"
    923       c.name == "bar"
    924 
    925       The returned InnerNamespace will look like this:
    926 
    927              i'
    928             /  \
    929             a' c'
    930           / |  |
    931           d e  f
    932 
    933     Remarks:
    934       This operation is not recursive. To combine the grandchildren and other
    935       ancestors, call this method on the ancestor nodes.
    936     """
    937     return Kind._combine_children_by_name(self, new_type=type(self))
    938 
    939 class EnumValue(Node):
    940   """
    941   A class corresponding to a <value> element within an <enum> within an <entry>.
    942 
    943   Attributes (Read-Only):
    944     name: A string,                 e.g. 'ON' or 'OFF'
    945     id: An optional numeric string, e.g. '0' or '0xFF'
    946     optional: A boolean
    947     notes: A string describing the notes, or None.
    948     parent: An edge to the parent, always an Enum instance.
    949   """
    950   def __init__(self, name, parent, id=None, optional=False, notes=None):
    951     self._name = name                    # str, e.g. 'ON' or 'OFF'
    952     self._id = id                        # int, e.g. '0'
    953     self._optional = optional            # bool
    954     self._notes = notes                  # None or str
    955     self._parent = parent
    956 
    957   @property
    958   def id(self):
    959     return self._id
    960 
    961   @property
    962   def optional(self):
    963     return self._optional
    964 
    965   @property
    966   def notes(self):
    967     return self._notes
    968 
    969   def _get_children(self):
    970     return None
    971 
    972 class Enum(Node):
    973   """
    974   A class corresponding to an <enum> element within an <entry>.
    975 
    976   Attributes (Read-Only):
    977     parent: An edge to the parent, always an Entry instance.
    978     values: A sequence of EnumValue children.
    979     has_values_with_id: A boolean representing if any of the children have a
    980         non-empty id property.
    981   """
    982   def __init__(self, parent, values, ids={}, optionals=[], notes={}):
    983     self._values =                                                             \
    984       [ EnumValue(val, self, ids.get(val), val in optionals, notes.get(val))   \
    985         for val in values ]
    986 
    987     self._parent = parent
    988     self._name = None
    989 
    990   @property
    991   def values(self):
    992     return (i for i in self._values)
    993 
    994   @property
    995   def has_values_with_id(self):
    996     return bool(any(i for i in self.values if i.id))
    997 
    998   def _get_children(self):
    999     return (i for i in self._values)
   1000 
   1001 class Entry(Node):
   1002   """
   1003   A node corresponding to an <entry> element.
   1004 
   1005   Attributes (Read-Only):
   1006     parent: An edge to the parent node, which is an InnerNamespace or Kind.
   1007     name: The fully qualified name string, e.g. 'android.shading.mode'
   1008     name_short: The name attribute from <entry name="mode">, e.g. mode
   1009     type: The type attribute from <entry type="bar">
   1010     kind: A string ('static', 'dynamic', 'controls') corresponding to the
   1011           ancestor Kind#name
   1012     container: The container attribute from <entry container="array">, or None.
   1013     container_sizes: A sequence of size strings or None if container is None.
   1014     enum: An Enum instance if the enum attribute is true, None otherwise.
   1015     visibility: The visibility of this entry ('system', 'hidden', 'public')
   1016                 across the system. System entries are only visible in native code
   1017                 headers. Hidden entries are marked @hide in managed code, while
   1018                 public entries are visible in the Android SDK.
   1019     applied_visibility: As visibility, but always valid, defaulting to 'system'
   1020                         if no visibility is given for an entry.
   1021     optional: a bool representing the optional attribute, which denotes the entry
   1022               is required for hardware level full devices, but optional for other
   1023               hardware levels.  None if not present.
   1024     applied_optional: As optional but always valid, defaulting to False if no
   1025                       optional attribute is present.
   1026     tuple_values: A sequence of strings describing the tuple values,
   1027                   None if container is not 'tuple'.
   1028     description: A string description, or None.
   1029     range: A string range, or None.
   1030     units: A string units, or None.
   1031     tags: A sequence of Tag nodes associated with this Entry.
   1032     type_notes: A string describing notes for the type, or None.
   1033     typedef: A Typedef associated with this Entry, or None.
   1034 
   1035   Remarks:
   1036     Subclass Clone can be used interchangeable with an Entry,
   1037     for when we don't care about the underlying type.
   1038 
   1039     parent and tags edges are invalid until after Metadata#construct_graph
   1040     has been invoked.
   1041   """
   1042   def __init__(self, **kwargs):
   1043     """
   1044     Instantiate a new Entry node.
   1045 
   1046     Args:
   1047       name: A string with the fully qualified name, e.g. 'android.shading.mode'
   1048       type: A string describing the type, e.g. 'int32'
   1049       kind: A string describing the kind, e.g. 'static'
   1050 
   1051     Args (if container):
   1052       container: A string describing the container, e.g. 'array' or 'tuple'
   1053       container_sizes: A list of string sizes if a container, or None otherwise
   1054 
   1055     Args (if container is 'tuple'):
   1056       tuple_values: A list of tuple values, e.g. ['width', 'height']
   1057 
   1058     Args (if the 'enum' attribute is true):
   1059       enum: A boolean, True if this is an enum, False otherwise
   1060       enum_values: A list of value strings, e.g. ['ON', 'OFF']
   1061       enum_optionals: A list of optional enum values, e.g. ['OFF']
   1062       enum_notes: A dictionary of value->notes strings.
   1063       enum_ids: A dictionary of value->id strings.
   1064 
   1065     Args (optional):
   1066       description: A string with a description of the entry.
   1067       range: A string with the range of the values of the entry, e.g. '>= 0'
   1068       units: A string with the units of the values, e.g. 'inches'
   1069       notes: A string with the notes for the entry
   1070       tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
   1071       type_notes: A string with the notes for the type
   1072       visibility: A string describing the visibility, eg 'system', 'hidden',
   1073                   'public'
   1074       optional: A bool to mark whether optional for non-full hardware devices
   1075       typedef: A string corresponding to a typedef's name attribute.
   1076     """
   1077 
   1078     if kwargs.get('type') is None:
   1079       print >> sys.stderr, "ERROR: Missing type for entry '%s' kind  '%s'"     \
   1080       %(kwargs.get('name'), kwargs.get('kind'))
   1081 
   1082     # Attributes are Read-Only, but edges may be mutated by
   1083     # Metadata, particularly during construct_graph
   1084 
   1085     self._name = kwargs['name']
   1086     self._type = kwargs['type']
   1087     self._kind = kwargs['kind'] # static, dynamic, or controls
   1088 
   1089     self._init_common(**kwargs)
   1090 
   1091   @property
   1092   def type(self):
   1093     return self._type
   1094 
   1095   @property
   1096   def kind(self):
   1097     return self._kind
   1098 
   1099   @property
   1100   def visibility(self):
   1101     return self._visibility
   1102 
   1103   @property
   1104   def applied_visibility(self):
   1105     return self._visibility or 'system'
   1106 
   1107   @property
   1108   def optional(self):
   1109     return self._optional
   1110 
   1111   @property
   1112   def applied_optional(self):
   1113     return self._optional or False
   1114 
   1115   @property
   1116   def name_short(self):
   1117     return self.get_name_minimal()
   1118 
   1119   @property
   1120   def container(self):
   1121     return self._container
   1122 
   1123   @property
   1124   def container_sizes(self):
   1125     if self._container_sizes is None:
   1126       return None
   1127     else:
   1128       return (i for i in self._container_sizes)
   1129 
   1130   @property
   1131   def tuple_values(self):
   1132     if self._tuple_values is None:
   1133       return None
   1134     else:
   1135       return (i for i in self._tuple_values)
   1136 
   1137   @property
   1138   def description(self):
   1139     return self._description
   1140 
   1141   @property
   1142   def range(self):
   1143     return self._range
   1144 
   1145   @property
   1146   def units(self):
   1147     return self._units
   1148 
   1149   @property
   1150   def notes(self):
   1151     return self._notes
   1152 
   1153   @property
   1154   def tags(self):
   1155     if self._tags is None:
   1156       return None
   1157     else:
   1158       return (i for i in self._tags)
   1159 
   1160   @property
   1161   def type_notes(self):
   1162     return self._type_notes
   1163 
   1164   @property
   1165   def typedef(self):
   1166     return self._typedef
   1167 
   1168   @property
   1169   def enum(self):
   1170     return self._enum
   1171 
   1172   def _get_children(self):
   1173     if self.enum:
   1174       yield self.enum
   1175 
   1176   def sort_children(self):
   1177     return None
   1178 
   1179   def is_clone(self):
   1180     """
   1181     Whether or not this is a Clone instance.
   1182 
   1183     Returns:
   1184       False
   1185     """
   1186     return False
   1187 
   1188   def _init_common(self, **kwargs):
   1189 
   1190     self._parent = None # filled in by Metadata::_construct_entries
   1191 
   1192     self._container = kwargs.get('container')
   1193     self._container_sizes = kwargs.get('container_sizes')
   1194 
   1195     # access these via the 'enum' prop
   1196     enum_values = kwargs.get('enum_values')
   1197     enum_optionals = kwargs.get('enum_optionals')
   1198     enum_notes = kwargs.get('enum_notes')  # { value => notes }
   1199     enum_ids = kwargs.get('enum_ids')  # { value => notes }
   1200     self._tuple_values = kwargs.get('tuple_values')
   1201 
   1202     self._description = kwargs.get('description')
   1203     self._range = kwargs.get('range')
   1204     self._units = kwargs.get('units')
   1205     self._notes = kwargs.get('notes')
   1206 
   1207     self._tag_ids = kwargs.get('tag_ids', [])
   1208     self._tags = None  # Filled in by Metadata::_construct_tags
   1209 
   1210     self._type_notes = kwargs.get('type_notes')
   1211     self._type_name = kwargs.get('type_name')
   1212     self._typedef = None # Filled in by Metadata::_construct_types
   1213 
   1214     if kwargs.get('enum', False):
   1215       self._enum = Enum(self, enum_values, enum_ids, enum_optionals, enum_notes)
   1216     else:
   1217       self._enum = None
   1218 
   1219     self._visibility = kwargs.get('visibility')
   1220     self._optional = kwargs.get('optional')
   1221 
   1222     self._property_keys = kwargs
   1223 
   1224   def merge(self):
   1225     """
   1226     Copy the attributes into a new entry, merging it with the target entry
   1227     if it's a clone.
   1228     """
   1229     return MergedEntry(self)
   1230 
   1231   # Helpers for accessing less than the fully qualified name
   1232 
   1233   def get_name_as_list(self):
   1234     """
   1235     Returns the name as a list split by a period.
   1236 
   1237     For example:
   1238       entry.name is 'android.lens.info.shading'
   1239       entry.get_name_as_list() == ['android', 'lens', 'info', 'shading']
   1240     """
   1241     return self.name.split(".")
   1242 
   1243   def get_inner_namespace_list(self):
   1244     """
   1245     Returns the inner namespace part of the name as a list
   1246 
   1247     For example:
   1248       entry.name is 'android.lens.info.shading'
   1249       entry.get_inner_namespace_list() == ['info']
   1250     """
   1251     return self.get_name_as_list()[2:-1]
   1252 
   1253   def get_outer_namespace(self):
   1254     """
   1255     Returns the outer namespace as a string.
   1256 
   1257     For example:
   1258       entry.name is 'android.lens.info.shading'
   1259       entry.get_outer_namespace() == 'android'
   1260 
   1261     Remarks:
   1262       Since outer namespaces are non-recursive,
   1263       and each entry has one, this does not need to be a list.
   1264     """
   1265     return self.get_name_as_list()[0]
   1266 
   1267   def get_section(self):
   1268     """
   1269     Returns the section as a string.
   1270 
   1271     For example:
   1272       entry.name is 'android.lens.info.shading'
   1273       entry.get_section() == ''
   1274 
   1275     Remarks:
   1276       Since outer namespaces are non-recursive,
   1277       and each entry has one, this does not need to be a list.
   1278     """
   1279     return self.get_name_as_list()[1]
   1280 
   1281   def get_name_minimal(self):
   1282     """
   1283     Returns only the last component of the fully qualified name as a string.
   1284 
   1285     For example:
   1286       entry.name is 'android.lens.info.shading'
   1287       entry.get_name_minimal() == 'shading'
   1288 
   1289     Remarks:
   1290       entry.name_short it an alias for this
   1291     """
   1292     return self.get_name_as_list()[-1]
   1293 
   1294   def get_path_without_name(self):
   1295     """
   1296     Returns a string path to the entry, with the name component excluded.
   1297 
   1298     For example:
   1299       entry.name is 'android.lens.info.shading'
   1300       entry.get_path_without_name() == 'android.lens.info'
   1301     """
   1302     return ".".join(self.get_name_as_list()[0:-1])
   1303 
   1304 
   1305 class Clone(Entry):
   1306   """
   1307   A Node corresponding to a <clone> element. It has all the attributes of an
   1308   <entry> element (Entry) plus the additions specified below.
   1309 
   1310   Attributes (Read-Only):
   1311     entry: an edge to an Entry object that this targets
   1312     target_kind: A string describing the kind of the target entry.
   1313     name: a string of the name, same as entry.name
   1314     kind: a string of the Kind ancestor, one of 'static', 'controls', 'dynamic'
   1315           for the <clone> element.
   1316     type: always None, since a clone cannot override the type.
   1317   """
   1318   def __init__(self, entry=None, **kwargs):
   1319     """
   1320     Instantiate a new Clone node.
   1321 
   1322     Args:
   1323       name: A string with the fully qualified name, e.g. 'android.shading.mode'
   1324       type: A string describing the type, e.g. 'int32'
   1325       kind: A string describing the kind, e.g. 'static'
   1326       target_kind: A string for the kind of the target entry, e.g. 'dynamic'
   1327 
   1328     Args (if container):
   1329       container: A string describing the container, e.g. 'array' or 'tuple'
   1330       container_sizes: A list of string sizes if a container, or None otherwise
   1331 
   1332     Args (if container is 'tuple'):
   1333       tuple_values: A list of tuple values, e.g. ['width', 'height']
   1334 
   1335     Args (if the 'enum' attribute is true):
   1336       enum: A boolean, True if this is an enum, False otherwise
   1337       enum_values: A list of value strings, e.g. ['ON', 'OFF']
   1338       enum_optionals: A list of optional enum values, e.g. ['OFF']
   1339       enum_notes: A dictionary of value->notes strings.
   1340       enum_ids: A dictionary of value->id strings.
   1341 
   1342     Args (optional):
   1343       entry: An edge to the corresponding target Entry.
   1344       description: A string with a description of the entry.
   1345       range: A string with the range of the values of the entry, e.g. '>= 0'
   1346       units: A string with the units of the values, e.g. 'inches'
   1347       notes: A string with the notes for the entry
   1348       tag_ids: A list of tag ID strings, e.g. ['BC', 'V1']
   1349       type_notes: A string with the notes for the type
   1350 
   1351     Remarks:
   1352       Note that type is not specified since it has to be the same as the
   1353       entry.type.
   1354     """
   1355     self._entry = entry  # Entry object
   1356     self._target_kind = kwargs['target_kind']
   1357     self._name = kwargs['name']  # same as entry.name
   1358     self._kind = kwargs['kind']
   1359 
   1360     # illegal to override the type, it should be the same as the entry
   1361     self._type = None
   1362     # the rest of the kwargs are optional
   1363     # can be used to override the regular entry data
   1364     self._init_common(**kwargs)
   1365 
   1366   @property
   1367   def entry(self):
   1368     return self._entry
   1369 
   1370   @property
   1371   def target_kind(self):
   1372     return self._target_kind
   1373 
   1374   def is_clone(self):
   1375     """
   1376     Whether or not this is a Clone instance.
   1377 
   1378     Returns:
   1379       True
   1380     """
   1381     return True
   1382 
   1383 class MergedEntry(Entry):
   1384   """
   1385   A MergedEntry has all the attributes of a Clone and its target Entry merged
   1386   together.
   1387 
   1388   Remarks:
   1389     Useful when we want to 'unfold' a clone into a real entry by copying out
   1390     the target entry data. In this case we don't care about distinguishing
   1391     a clone vs an entry.
   1392   """
   1393   def __init__(self, entry):
   1394     """
   1395     Create a new instance of MergedEntry.
   1396 
   1397     Args:
   1398       entry: An Entry or Clone instance
   1399     """
   1400     props_distinct = ['description', 'units', 'range', 'notes', 'tags', 'kind']
   1401 
   1402     for p in props_distinct:
   1403       p = '_' + p
   1404       if entry.is_clone():
   1405         setattr(self, p, getattr(entry, p) or getattr(entry.entry, p))
   1406       else:
   1407         setattr(self, p, getattr(entry, p))
   1408 
   1409     props_common = ['parent', 'name', 'container',
   1410                     'container_sizes', 'enum',
   1411                     'tuple_values',
   1412                     'type',
   1413                     'type_notes',
   1414                     'visibility',
   1415                     'optional',
   1416                     'typedef'
   1417                    ]
   1418 
   1419     for p in props_common:
   1420       p = '_' + p
   1421       if entry.is_clone():
   1422         setattr(self, p, getattr(entry.entry, p))
   1423       else:
   1424         setattr(self, p, getattr(entry, p))
   1425