| Index: tools/metrics/common/models.py
|
| diff --git a/tools/metrics/common/models.py b/tools/metrics/common/models.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3ba301c4eec8bfd368f0d983c9c24c7cb47ef4aa
|
| --- /dev/null
|
| +++ b/tools/metrics/common/models.py
|
| @@ -0,0 +1,214 @@
|
| +# Copyright 2015 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.
|
| +
|
| +"""Model types for describing description xml models."""
|
| +
|
| +from xml.dom import minidom
|
| +
|
| +import sys
|
| +import os
|
| +
|
| +import pretty_print_xml
|
| +
|
| +
|
| +def GetComments(node):
|
| + """Extracts comments in the current node.
|
| +
|
| + Args:
|
| + node: The DOM node to extract comments from.
|
| + Returns:
|
| + A list of comment DOM nodes.
|
| + """
|
| + return [n for n in node.childNodes if n.nodeType == minidom.Node.COMMENT_NODE]
|
| +
|
| +
|
| +def PutComments(node, comments):
|
| + """Append comments to the DOM node.
|
| +
|
| + Args:
|
| + node: The DOM node to write comments to.
|
| + comments: A list of comment DOM nodes.
|
| + """
|
| + for n in comments:
|
| + node.appendChild(n)
|
| +
|
| +
|
| +class NodeType(object):
|
| + """Base type for a type of XML node.
|
| +
|
| + Args:
|
| + dont_indent: True iff this node should not have it's children indented
|
| + when pretty printing.
|
| + extra_newlines: None or a triple of integers describing the number of
|
| + newlines that should be printed (after_open, before_close, after_close)
|
| + single_line: True iff this node may be squashed into a single line.
|
| + """
|
| + def __init__(self, tag,
|
| + dont_indent=False,
|
| + extra_newlines=None,
|
| + single_line=False):
|
| + self.tag = tag
|
| + self.dont_indent = dont_indent
|
| + self.extra_newlines = extra_newlines
|
| + self.single_line = single_line
|
| +
|
| + def Unmarshall(self, node):
|
| + return None
|
| +
|
| + def Marshall(self, doc, obj):
|
| + return None
|
| +
|
| + def GetAttributes(self):
|
| + return []
|
| +
|
| + def GetNodeTypes(self):
|
| + return {self.tag: self}
|
| +
|
| +
|
| +class TextNodeType(NodeType):
|
| + """A type for simple nodes that just have a tag and some text content.
|
| +
|
| + Unmarshalls nodes to strings.
|
| +
|
| + Args:
|
| + tag: The name of XML tag for this type of node.
|
| + """
|
| + def __init__(self, tag, **kwargs):
|
| + NodeType.__init__(self, tag, **kwargs)
|
| +
|
| + def __str__(self):
|
| + return 'TextNodeType("%s")' % self.tag
|
| +
|
| + def Unmarshall(self, node):
|
| + return node.firstChild.nodeValue.strip()
|
| +
|
| + def Marshall(self, doc, obj):
|
| + node = doc.createElement(self.tag)
|
| + node.appendChild(doc.createTextNode(obj))
|
| + return node
|
| +
|
| +
|
| +class ChildType(object):
|
| + """Metadata about a nodes children.
|
| +
|
| + Args:
|
| + attr: The field name of the parents model object storing the child's model.
|
| + node_type: The NodeType of the child.
|
| + multiple: True if the child can be repeated.
|
| + """
|
| + def __init__(self, attr, node_type, multiple):
|
| + self.attr = attr
|
| + self.node_type = node_type
|
| + self.multiple = multiple
|
| +
|
| +
|
| +class ObjectNodeType(NodeType):
|
| + """A complex node type that has attributes or other nodes as children.
|
| +
|
| + Unmarshalls nodes to objects.
|
| +
|
| + Args:
|
| + tag: The name of XML tag for this type of node.
|
| + int_attributes: A list of names of integer attributes.
|
| + float_attributes: A list of names of float attributes.
|
| + string_attributes: A list of names of string attributes.
|
| + children: A list of ChildTypes describing the objects children.
|
| + """
|
| + def __init__(self, tag,
|
| + int_attributes=[],
|
| + float_attributes=[],
|
| + string_attributes=[],
|
| + children=[],
|
| + **kwargs):
|
| + NodeType.__init__(self, tag, **kwargs)
|
| + self.int_attributes = int_attributes
|
| + self.float_attributes = float_attributes
|
| + self.string_attributes = string_attributes
|
| + self.children = children
|
| +
|
| + def __str__(self):
|
| + return 'ObjectNodeType("%s")' % self.tag
|
| +
|
| + def Unmarshall(self, node):
|
| + obj = {}
|
| +
|
| + obj['comments'] = GetComments(node)
|
| +
|
| + for attr in self.int_attributes:
|
| + obj[attr] = int(node.getAttribute(attr))
|
| +
|
| + for attr in self.float_attributes:
|
| + obj[attr] = float(node.getAttribute(attr))
|
| +
|
| + for attr in self.string_attributes:
|
| + obj[attr] = node.getAttribute(attr)
|
| +
|
| + for child in self.children:
|
| + nodes = node.getElementsByTagName(child.node_type.tag)
|
| + if child.multiple:
|
| + obj[child.attr] = [child.node_type.Unmarshall(n) for n in nodes]
|
| + else:
|
| + obj[child.attr] = child.node_type.Unmarshall(nodes[0])
|
| + return obj
|
| +
|
| + def Marshall(self, doc, obj):
|
| + node = doc.createElement(self.tag)
|
| + attributes = (self.int_attributes +
|
| + self.float_attributes +
|
| + self.string_attributes)
|
| + for attr in attributes:
|
| + node.setAttribute(attr, str(obj[attr]))
|
| +
|
| + PutComments(node, obj['comments'])
|
| +
|
| + for child in self.children:
|
| + if child.multiple:
|
| + for o in obj[child.attr]:
|
| + node.appendChild(child.node_type.Marshall(doc, o))
|
| + else:
|
| + node.appendChild(child.node_type.Marshall(doc, obj[child.attr]))
|
| + return node
|
| +
|
| + def GetAttributes(self):
|
| + return self.int_attributes + self.float_attributes + self.string_attributes
|
| +
|
| + def GetNodeTypes(self):
|
| + types = {self.tag: self}
|
| + for child in self.children:
|
| + types.update(child.node_type.GetNodeTypes())
|
| + return types
|
| +
|
| +
|
| +class DocumentType(object):
|
| + """Model for the root of an XML description file.
|
| +
|
| + Args:
|
| + root_type: A NodeType describing the root tag of the document.
|
| + """
|
| + def __init__(self, root_type):
|
| + self.root_type = root_type
|
| +
|
| + def Parse(self, input_file):
|
| + tree = minidom.parseString(input_file)
|
| + comments = GetComments(tree)
|
| + return comments, self.root_type.Unmarshall(
|
| + tree.getElementsByTagName(self.root_type.tag)[0])
|
| +
|
| + def GetPrintStyle(self):
|
| + types = self.root_type.GetNodeTypes()
|
| + return pretty_print_xml.XmlStyle(
|
| + {t: types[t].GetAttributes() for t in types},
|
| + {t: types[t].extra_newlines for t in types if types[t].extra_newlines},
|
| + [t for t in types if types[t].dont_indent],
|
| + [t for t in types if types[t].single_line])
|
| +
|
| + def ToXML(self, comments, obj):
|
| + doc = minidom.Document()
|
| + for comment in comments:
|
| + doc.appendChild(comment)
|
| + doc.appendChild(self.root_type.Marshall(doc, obj))
|
| + return doc
|
| +
|
| + def PrettyPrint(self, comments, obj):
|
| + return self.GetPrintStyle().PrettyPrintNode(self.ToXML(comments, obj))
|
|
|