Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Unified Diff: grit/node/base.py

Issue 1442863002: Remove contents of grit's SVN repository. (Closed) Base URL: http://grit-i18n.googlecode.com/svn/trunk/
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « grit/node/__init__.py ('k') | grit/node/base_unittest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: grit/node/base.py
===================================================================
--- grit/node/base.py (revision 202)
+++ grit/node/base.py (working copy)
@@ -1,613 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-'''Base types for nodes in a GRIT resource tree.
-'''
-
-import ast
-import os
-import types
-from xml.sax import saxutils
-
-from grit import clique
-from grit import exception
-from grit import util
-
-
-class Node(object):
- '''An item in the tree that has children.'''
-
- # Valid content types that can be returned by _ContentType()
- _CONTENT_TYPE_NONE = 0 # No CDATA content but may have children
- _CONTENT_TYPE_CDATA = 1 # Only CDATA, no children.
- _CONTENT_TYPE_MIXED = 2 # CDATA and children, possibly intermingled
-
- # Default nodes to not whitelist skipped
- _whitelist_marked_as_skip = False
-
- # A class-static cache to speed up EvaluateExpression().
- # Keys are expressions (e.g. 'is_ios and lang == "fr"'). Values are tuples
- # (code, variables_in_expr) where code is the compiled expression and can be
- # directly eval'd, and variables_in_expr is the list of variable and method
- # names used in the expression (e.g. ['is_ios', 'lang']).
- eval_expr_cache = {}
-
- def __init__(self):
- self.children = [] # A list of child elements
- self.mixed_content = [] # A list of u'' and/or child elements (this
- # duplicates 'children' but
- # is needed to preserve markup-type content).
- self.name = u'' # The name of this element
- self.attrs = {} # The set of attributes (keys to values)
- self.parent = None # Our parent unless we are the root element.
- self.uberclique = None # Allows overriding uberclique for parts of tree
-
- # This context handler allows you to write "with node:" and get a
- # line identifying the offending node if an exception escapes from the body
- # of the with statement.
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_value, traceback):
- if exc_type is not None:
- print u'Error processing node %s' % unicode(self)
-
- def __iter__(self):
- '''A preorder iteration through the tree that this node is the root of.'''
- return self.Preorder()
-
- def Preorder(self):
- '''Generator that generates first this node, then the same generator for
- any child nodes.'''
- yield self
- for child in self.children:
- for iterchild in child.Preorder():
- yield iterchild
-
- def ActiveChildren(self):
- '''Returns the children of this node that should be included in the current
- configuration. Overridden by <if>.'''
- return [node for node in self.children if not node.WhitelistMarkedAsSkip()]
-
- def ActiveDescendants(self):
- '''Yields the current node and all descendants that should be included in
- the current configuration, in preorder.'''
- yield self
- for child in self.ActiveChildren():
- for descendant in child.ActiveDescendants():
- yield descendant
-
- def GetRoot(self):
- '''Returns the root Node in the tree this Node belongs to.'''
- curr = self
- while curr.parent:
- curr = curr.parent
- return curr
-
- # TODO(joi) Use this (currently untested) optimization?:
- #if hasattr(self, '_root'):
- # return self._root
- #curr = self
- #while curr.parent and not hasattr(curr, '_root'):
- # curr = curr.parent
- #if curr.parent:
- # self._root = curr._root
- #else:
- # self._root = curr
- #return self._root
-
- def StartParsing(self, name, parent):
- '''Called at the start of parsing.
-
- Args:
- name: u'elementname'
- parent: grit.node.base.Node or subclass or None
- '''
- assert isinstance(name, types.StringTypes)
- assert not parent or isinstance(parent, Node)
- self.name = name
- self.parent = parent
-
- def AddChild(self, child):
- '''Adds a child to the list of children of this node, if it is a valid
- child for the node.'''
- assert isinstance(child, Node)
- if (not self._IsValidChild(child) or
- self._ContentType() == self._CONTENT_TYPE_CDATA):
- explanation = 'invalid child %s for parent %s' % (str(child), self.name)
- raise exception.UnexpectedChild(explanation)
- self.children.append(child)
- self.mixed_content.append(child)
-
- def RemoveChild(self, child_id):
- '''Removes the first node that has a "name" attribute which
- matches "child_id" in the list of immediate children of
- this node.
-
- Args:
- child_id: String identifying the child to be removed
- '''
- index = 0
- # Safe not to copy since we only remove the first element found
- for child in self.children:
- name_attr = child.attrs['name']
- if name_attr == child_id:
- self.children.pop(index)
- self.mixed_content.pop(index)
- break
- index += 1
-
- def AppendContent(self, content):
- '''Appends a chunk of text as content of this node.
-
- Args:
- content: u'hello'
-
- Return:
- None
- '''
- assert isinstance(content, types.StringTypes)
- if self._ContentType() != self._CONTENT_TYPE_NONE:
- self.mixed_content.append(content)
- elif content.strip() != '':
- raise exception.UnexpectedContent()
-
- def HandleAttribute(self, attrib, value):
- '''Informs the node of an attribute that was parsed out of the GRD file
- for it.
-
- Args:
- attrib: 'name'
- value: 'fooblat'
-
- Return:
- None
- '''
- assert isinstance(attrib, types.StringTypes)
- assert isinstance(value, types.StringTypes)
- if self._IsValidAttribute(attrib, value):
- self.attrs[attrib] = value
- else:
- raise exception.UnexpectedAttribute(attrib)
-
- def EndParsing(self):
- '''Called at the end of parsing.'''
-
- # TODO(joi) Rewrite this, it's extremely ugly!
- if len(self.mixed_content):
- if isinstance(self.mixed_content[0], types.StringTypes):
- # Remove leading and trailing chunks of pure whitespace.
- while (len(self.mixed_content) and
- isinstance(self.mixed_content[0], types.StringTypes) and
- self.mixed_content[0].strip() == ''):
- self.mixed_content = self.mixed_content[1:]
- # Strip leading and trailing whitespace from mixed content chunks
- # at front and back.
- if (len(self.mixed_content) and
- isinstance(self.mixed_content[0], types.StringTypes)):
- self.mixed_content[0] = self.mixed_content[0].lstrip()
- # Remove leading and trailing ''' (used to demarcate whitespace)
- if (len(self.mixed_content) and
- isinstance(self.mixed_content[0], types.StringTypes)):
- if self.mixed_content[0].startswith("'''"):
- self.mixed_content[0] = self.mixed_content[0][3:]
- if len(self.mixed_content):
- if isinstance(self.mixed_content[-1], types.StringTypes):
- # Same stuff all over again for the tail end.
- while (len(self.mixed_content) and
- isinstance(self.mixed_content[-1], types.StringTypes) and
- self.mixed_content[-1].strip() == ''):
- self.mixed_content = self.mixed_content[:-1]
- if (len(self.mixed_content) and
- isinstance(self.mixed_content[-1], types.StringTypes)):
- self.mixed_content[-1] = self.mixed_content[-1].rstrip()
- if (len(self.mixed_content) and
- isinstance(self.mixed_content[-1], types.StringTypes)):
- if self.mixed_content[-1].endswith("'''"):
- self.mixed_content[-1] = self.mixed_content[-1][:-3]
-
- # Check that all mandatory attributes are there.
- for node_mandatt in self.MandatoryAttributes():
- mandatt_list = []
- if node_mandatt.find('|') >= 0:
- mandatt_list = node_mandatt.split('|')
- else:
- mandatt_list.append(node_mandatt)
-
- mandatt_option_found = False
- for mandatt in mandatt_list:
- assert mandatt not in self.DefaultAttributes().keys()
- if mandatt in self.attrs:
- if not mandatt_option_found:
- mandatt_option_found = True
- else:
- raise exception.MutuallyExclusiveMandatoryAttribute(mandatt)
-
- if not mandatt_option_found:
- raise exception.MissingMandatoryAttribute(mandatt)
-
- # Add default attributes if not specified in input file.
- for defattr in self.DefaultAttributes():
- if not defattr in self.attrs:
- self.attrs[defattr] = self.DefaultAttributes()[defattr]
-
- def GetCdata(self):
- '''Returns all CDATA of this element, concatenated into a single
- string. Note that this ignores any elements embedded in CDATA.'''
- return ''.join([c for c in self.mixed_content
- if isinstance(c, types.StringTypes)])
-
- def __unicode__(self):
- '''Returns this node and all nodes below it as an XML document in a Unicode
- string.'''
- header = u'<?xml version="1.0" encoding="UTF-8"?>\n'
- return header + self.FormatXml()
-
- def FormatXml(self, indent = u'', one_line = False):
- '''Returns this node and all nodes below it as an XML
- element in a Unicode string. This differs from __unicode__ in that it does
- not include the <?xml> stuff at the top of the string. If one_line is true,
- children and CDATA are layed out in a way that preserves internal
- whitespace.
- '''
- assert isinstance(indent, types.StringTypes)
-
- content_one_line = (one_line or
- self._ContentType() == self._CONTENT_TYPE_MIXED)
- inside_content = self.ContentsAsXml(indent, content_one_line)
-
- # Then the attributes for this node.
- attribs = u''
- default_attribs = self.DefaultAttributes()
- for attrib, value in sorted(self.attrs.items()):
- # Only print an attribute if it is other than the default value.
- if attrib not in default_attribs or value != default_attribs[attrib]:
- attribs += u' %s=%s' % (attrib, saxutils.quoteattr(value))
-
- # Finally build the XML for our node and return it
- if len(inside_content) > 0:
- if one_line:
- return u'<%s%s>%s</%s>' % (self.name, attribs, inside_content, self.name)
- elif content_one_line:
- return u'%s<%s%s>\n%s %s\n%s</%s>' % (
- indent, self.name, attribs,
- indent, inside_content,
- indent, self.name)
- else:
- return u'%s<%s%s>\n%s\n%s</%s>' % (
- indent, self.name, attribs,
- inside_content,
- indent, self.name)
- else:
- return u'%s<%s%s />' % (indent, self.name, attribs)
-
- def ContentsAsXml(self, indent, one_line):
- '''Returns the contents of this node (CDATA and child elements) in XML
- format. If 'one_line' is true, the content will be laid out on one line.'''
- assert isinstance(indent, types.StringTypes)
-
- # Build the contents of the element.
- inside_parts = []
- last_item = None
- for mixed_item in self.mixed_content:
- if isinstance(mixed_item, Node):
- inside_parts.append(mixed_item.FormatXml(indent + u' ', one_line))
- if not one_line:
- inside_parts.append(u'\n')
- else:
- message = mixed_item
- # If this is the first item and it starts with whitespace, we add
- # the ''' delimiter.
- if not last_item and message.lstrip() != message:
- message = u"'''" + message
- inside_parts.append(util.EncodeCdata(message))
- last_item = mixed_item
-
- # If there are only child nodes and no cdata, there will be a spurious
- # trailing \n
- if len(inside_parts) and inside_parts[-1] == '\n':
- inside_parts = inside_parts[:-1]
-
- # If the last item is a string (not a node) and ends with whitespace,
- # we need to add the ''' delimiter.
- if (isinstance(last_item, types.StringTypes) and
- last_item.rstrip() != last_item):
- inside_parts[-1] = inside_parts[-1] + u"'''"
-
- return u''.join(inside_parts)
-
- def SubstituteMessages(self, substituter):
- '''Applies substitutions to all messages in the tree.
-
- Called as a final step of RunGatherers.
-
- Args:
- substituter: a grit.util.Substituter object.
- '''
- for child in self.children:
- child.SubstituteMessages(substituter)
-
- def _IsValidChild(self, child):
- '''Returns true if 'child' is a valid child of this node.
- Overridden by subclasses.'''
- return False
-
- def _IsValidAttribute(self, name, value):
- '''Returns true if 'name' is the name of a valid attribute of this element
- and 'value' is a valid value for that attribute. Overriden by
- subclasses unless they have only mandatory attributes.'''
- return (name in self.MandatoryAttributes() or
- name in self.DefaultAttributes())
-
- def _ContentType(self):
- '''Returns the type of content this element can have. Overridden by
- subclasses. The content type can be one of the _CONTENT_TYPE_XXX constants
- above.'''
- return self._CONTENT_TYPE_NONE
-
- def MandatoryAttributes(self):
- '''Returns a list of attribute names that are mandatory (non-optional)
- on the current element. One can specify a list of
- "mutually exclusive mandatory" attributes by specifying them as one
- element in the list, separated by a "|" character.
- '''
- return []
-
- def DefaultAttributes(self):
- '''Returns a dictionary of attribute names that have defaults, mapped to
- the default value. Overridden by subclasses.'''
- return {}
-
- def GetCliques(self):
- '''Returns all MessageClique objects belonging to this node. Overridden
- by subclasses.
-
- Return:
- [clique1, clique2] or []
- '''
- return []
-
- def ToRealPath(self, path_from_basedir):
- '''Returns a real path (which can be absolute or relative to the current
- working directory), given a path that is relative to the base directory
- set for the GRIT input file.
-
- Args:
- path_from_basedir: '..'
-
- Return:
- 'resource'
- '''
- return util.normpath(os.path.join(self.GetRoot().GetBaseDir(),
- os.path.expandvars(path_from_basedir)))
-
- def GetInputPath(self):
- '''Returns a path, relative to the base directory set for the grd file,
- that points to the file the node refers to.
- '''
- # This implementation works for most nodes that have an input file.
- return self.attrs['file']
-
- def UberClique(self):
- '''Returns the uberclique that should be used for messages originating in
- a given node. If the node itself has its uberclique set, that is what we
- use, otherwise we search upwards until we find one. If we do not find one
- even at the root node, we set the root node's uberclique to a new
- uberclique instance.
- '''
- node = self
- while not node.uberclique and node.parent:
- node = node.parent
- if not node.uberclique:
- node.uberclique = clique.UberClique()
- return node.uberclique
-
- def IsTranslateable(self):
- '''Returns false if the node has contents that should not be translated,
- otherwise returns false (even if the node has no contents).
- '''
- if not 'translateable' in self.attrs:
- return True
- else:
- return self.attrs['translateable'] == 'true'
-
- def GetNodeById(self, id):
- '''Returns the node in the subtree parented by this node that has a 'name'
- attribute matching 'id'. Returns None if no such node is found.
- '''
- for node in self:
- if 'name' in node.attrs and node.attrs['name'] == id:
- return node
- return None
-
- def GetChildrenOfType(self, type):
- '''Returns a list of all subnodes (recursing to all leaves) of this node
- that are of the indicated type (or tuple of types).
-
- Args:
- type: A type you could use with isinstance().
-
- Return:
- A list, possibly empty.
- '''
- return [child for child in self if isinstance(child, type)]
-
- def GetTextualIds(self):
- '''Returns a list of the textual ids of this node.
- '''
- if 'name' in self.attrs:
- return [self.attrs['name']]
- return []
-
- @classmethod
- def EvaluateExpression(cls, expr, defs, target_platform, extra_variables={}):
- '''Worker for EvaluateCondition (below) and conditions in XTB files.'''
- if expr in cls.eval_expr_cache:
- code, variables_in_expr = cls.eval_expr_cache[expr]
- else:
- # Get a list of all variable and method names used in the expression.
- syntax_tree = ast.parse(expr, mode='eval')
- variables_in_expr = [node.id for node in ast.walk(syntax_tree) if
- isinstance(node, ast.Name) and node.id not in ('True', 'False')]
- code = compile(syntax_tree, filename='<string>', mode='eval')
- cls.eval_expr_cache[expr] = code, variables_in_expr
-
- # Set values only for variables that are needed to eval the expression.
- variable_map = {}
- for name in variables_in_expr:
- if name == 'os':
- value = target_platform
- elif name == 'defs':
- value = defs
-
- elif name == 'is_linux':
- value = target_platform.startswith('linux')
- elif name == 'is_macosx':
- value = target_platform == 'darwin'
- elif name == 'is_win':
- value = target_platform in ('cygwin', 'win32')
- elif name == 'is_android':
- value = target_platform == 'android'
- elif name == 'is_ios':
- value = target_platform == 'ios'
- elif name == 'is_bsd':
- value = 'bsd' in target_platform
- elif name == 'is_posix':
- value = (target_platform in ('darwin', 'linux2', 'linux3', 'sunos5',
- 'android', 'ios')
- or 'bsd' in target_platform)
-
- elif name == 'pp_ifdef':
- def pp_ifdef(symbol):
- return symbol in defs
- value = pp_ifdef
- elif name == 'pp_if':
- def pp_if(symbol):
- return defs.get(symbol, False)
- value = pp_if
-
- elif name in defs:
- value = defs[name]
- elif name in extra_variables:
- value = extra_variables[name]
- else:
- # Undefined variables default to False.
- value = False
-
- variable_map[name] = value
-
- eval_result = eval(code, {}, variable_map)
- assert isinstance(eval_result, bool)
- return eval_result
-
- def EvaluateCondition(self, expr):
- '''Returns true if and only if the Python expression 'expr' evaluates
- to true.
-
- The expression is given a few local variables:
- - 'lang' is the language currently being output
- (the 'lang' attribute of the <output> element).
- - 'context' is the current output context
- (the 'context' attribute of the <output> element).
- - 'defs' is a map of C preprocessor-style symbol names to their values.
- - 'os' is the current platform (likely 'linux2', 'win32' or 'darwin').
- - 'pp_ifdef(symbol)' is a shorthand for "symbol in defs".
- - 'pp_if(symbol)' is a shorthand for "symbol in defs and defs[symbol]".
- - 'is_linux', 'is_macosx', 'is_win', 'is_posix' are true if 'os'
- matches the given platform.
- '''
- root = self.GetRoot()
- lang = getattr(root, 'output_language', '')
- context = getattr(root, 'output_context', '')
- defs = getattr(root, 'defines', {})
- target_platform = getattr(root, 'target_platform', '')
- extra_variables = {
- 'lang': lang,
- 'context': context,
- }
- return Node.EvaluateExpression(
- expr, defs, target_platform, extra_variables)
-
- def OnlyTheseTranslations(self, languages):
- '''Turns off loading of translations for languages not in the provided list.
-
- Attrs:
- languages: ['fr', 'zh_cn']
- '''
- for node in self:
- if (hasattr(node, 'IsTranslation') and
- node.IsTranslation() and
- node.GetLang() not in languages):
- node.DisableLoading()
-
- def FindBooleanAttribute(self, attr, default, skip_self):
- '''Searches all ancestors of the current node for the nearest enclosing
- definition of the given boolean attribute.
-
- Args:
- attr: 'fallback_to_english'
- default: What to return if no node defines the attribute.
- skip_self: Don't check the current node, only its parents.
- '''
- p = self.parent if skip_self else self
- while p:
- value = p.attrs.get(attr, 'default').lower()
- if value != 'default':
- return (value == 'true')
- p = p.parent
- return default
-
- def PseudoIsAllowed(self):
- '''Returns true if this node is allowed to use pseudo-translations. This
- is true by default, unless this node is within a <release> node that has
- the allow_pseudo attribute set to false.
- '''
- return self.FindBooleanAttribute('allow_pseudo',
- default=True, skip_self=True)
-
- def ShouldFallbackToEnglish(self):
- '''Returns true iff this node should fall back to English when
- pseudotranslations are disabled and no translation is available for a
- given message.
- '''
- return self.FindBooleanAttribute('fallback_to_english',
- default=False, skip_self=True)
-
- def WhitelistMarkedAsSkip(self):
- '''Returns true if the node is marked to be skipped in the output by a
- whitelist.
- '''
- return self._whitelist_marked_as_skip
-
- def SetWhitelistMarkedAsSkip(self, mark_skipped):
- '''Sets WhitelistMarkedAsSkip.
- '''
- self._whitelist_marked_as_skip = mark_skipped
-
- def ExpandVariables(self):
- '''Whether we need to expand variables on a given node.'''
- return False
-
- def IsResourceMapSource(self):
- '''Whether this node is a resource map source.'''
- return False
-
- def GeneratesResourceMapEntry(self, output_all_resource_defines,
- is_active_descendant):
- '''Whether this node should output a resource map entry.
-
- Args:
- output_all_resource_defines: The value of output_all_resource_defines for
- the root node.
- is_active_descendant: Whether the current node is an active descendant
- from the root node.'''
- return False
-
-
-class ContentNode(Node):
- '''Convenience baseclass for nodes that can have content.'''
- def _ContentType(self):
- return self._CONTENT_TYPE_MIXED
-
« no previous file with comments | « grit/node/__init__.py ('k') | grit/node/base_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698