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

Unified Diff: tools/telemetry/third_party/coverage/coverage/templite.py

Issue 1366913004: Add coverage Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months 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
Index: tools/telemetry/third_party/coverage/coverage/templite.py
diff --git a/tools/telemetry/third_party/coverage/coverage/templite.py b/tools/telemetry/third_party/coverage/coverage/templite.py
new file mode 100644
index 0000000000000000000000000000000000000000..f131f748baefdbfc3375bcade3dd2ad374cb1f77
--- /dev/null
+++ b/tools/telemetry/third_party/coverage/coverage/templite.py
@@ -0,0 +1,276 @@
+# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
+# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
+
+"""A simple Python template renderer, for a nano-subset of Django syntax.
+
+For a detailed discussion of this code, see this chapter from 500 Lines:
+http://aosabook.org/en/500L/a-template-engine.html
+
+"""
+
+# Coincidentally named the same as http://code.activestate.com/recipes/496702/
+
+import re
+
+from coverage import env
+
+
+class TempliteSyntaxError(ValueError):
+ """Raised when a template has a syntax error."""
+ pass
+
+
+class TempliteValueError(ValueError):
+ """Raised when an expression won't evaluate in a template."""
+ pass
+
+
+class CodeBuilder(object):
+ """Build source code conveniently."""
+
+ def __init__(self, indent=0):
+ self.code = []
+ self.indent_level = indent
+
+ def __str__(self):
+ return "".join(str(c) for c in self.code)
+
+ def add_line(self, line):
+ """Add a line of source to the code.
+
+ Indentation and newline will be added for you, don't provide them.
+
+ """
+ self.code.extend([" " * self.indent_level, line, "\n"])
+
+ def add_section(self):
+ """Add a section, a sub-CodeBuilder."""
+ section = CodeBuilder(self.indent_level)
+ self.code.append(section)
+ return section
+
+ INDENT_STEP = 4 # PEP8 says so!
+
+ def indent(self):
+ """Increase the current indent for following lines."""
+ self.indent_level += self.INDENT_STEP
+
+ def dedent(self):
+ """Decrease the current indent for following lines."""
+ self.indent_level -= self.INDENT_STEP
+
+ def get_globals(self):
+ """Execute the code, and return a dict of globals it defines."""
+ # A check that the caller really finished all the blocks they started.
+ assert self.indent_level == 0
+ # Get the Python source as a single string.
+ python_source = str(self)
+ # Execute the source, defining globals, and return them.
+ global_namespace = {}
+ exec(python_source, global_namespace)
+ return global_namespace
+
+
+class Templite(object):
+ """A simple template renderer, for a nano-subset of Django syntax.
+
+ Supported constructs are extended variable access::
+
+ {{var.modifier.modifier|filter|filter}}
+
+ loops::
+
+ {% for var in list %}...{% endfor %}
+
+ and ifs::
+
+ {% if var %}...{% endif %}
+
+ Comments are within curly-hash markers::
+
+ {# This will be ignored #}
+
+ Construct a Templite with the template text, then use `render` against a
+ dictionary context to create a finished string::
+
+ templite = Templite('''
+ <h1>Hello {{name|upper}}!</h1>
+ {% for topic in topics %}
+ <p>You are interested in {{topic}}.</p>
+ {% endif %}
+ ''',
+ {'upper': str.upper},
+ )
+ text = templite.render({
+ 'name': "Ned",
+ 'topics': ['Python', 'Geometry', 'Juggling'],
+ })
+
+ """
+ def __init__(self, text, *contexts):
+ """Construct a Templite with the given `text`.
+
+ `contexts` are dictionaries of values to use for future renderings.
+ These are good for filters and global values.
+
+ """
+ self.context = {}
+ for context in contexts:
+ self.context.update(context)
+
+ self.all_vars = set()
+ self.loop_vars = set()
+
+ # We construct a function in source form, then compile it and hold onto
+ # it, and execute it to render the template.
+ code = CodeBuilder()
+
+ code.add_line("def render_function(context, do_dots):")
+ code.indent()
+ vars_code = code.add_section()
+ code.add_line("result = []")
+ code.add_line("append_result = result.append")
+ code.add_line("extend_result = result.extend")
+ if env.PY2:
+ code.add_line("to_str = unicode")
+ else:
+ code.add_line("to_str = str")
+
+ buffered = []
+
+ def flush_output():
+ """Force `buffered` to the code builder."""
+ if len(buffered) == 1:
+ code.add_line("append_result(%s)" % buffered[0])
+ elif len(buffered) > 1:
+ code.add_line("extend_result([%s])" % ", ".join(buffered))
+ del buffered[:]
+
+ ops_stack = []
+
+ # Split the text to form a list of tokens.
+ tokens = re.split(r"(?s)({{.*?}}|{%.*?%}|{#.*?#})", text)
+
+ for token in tokens:
+ if token.startswith('{#'):
+ # Comment: ignore it and move on.
+ continue
+ elif token.startswith('{{'):
+ # An expression to evaluate.
+ expr = self._expr_code(token[2:-2].strip())
+ buffered.append("to_str(%s)" % expr)
+ elif token.startswith('{%'):
+ # Action tag: split into words and parse further.
+ flush_output()
+ words = token[2:-2].strip().split()
+ if words[0] == 'if':
+ # An if statement: evaluate the expression to determine if.
+ if len(words) != 2:
+ self._syntax_error("Don't understand if", token)
+ ops_stack.append('if')
+ code.add_line("if %s:" % self._expr_code(words[1]))
+ code.indent()
+ elif words[0] == 'for':
+ # A loop: iterate over expression result.
+ if len(words) != 4 or words[2] != 'in':
+ self._syntax_error("Don't understand for", token)
+ ops_stack.append('for')
+ self._variable(words[1], self.loop_vars)
+ code.add_line(
+ "for c_%s in %s:" % (
+ words[1],
+ self._expr_code(words[3])
+ )
+ )
+ code.indent()
+ elif words[0].startswith('end'):
+ # Endsomething. Pop the ops stack.
+ if len(words) != 1:
+ self._syntax_error("Don't understand end", token)
+ end_what = words[0][3:]
+ if not ops_stack:
+ self._syntax_error("Too many ends", token)
+ start_what = ops_stack.pop()
+ if start_what != end_what:
+ self._syntax_error("Mismatched end tag", end_what)
+ code.dedent()
+ else:
+ self._syntax_error("Don't understand tag", words[0])
+ else:
+ # Literal content. If it isn't empty, output it.
+ if token:
+ buffered.append(repr(token))
+
+ if ops_stack:
+ self._syntax_error("Unmatched action tag", ops_stack[-1])
+
+ flush_output()
+
+ for var_name in self.all_vars - self.loop_vars:
+ vars_code.add_line("c_%s = context[%r]" % (var_name, var_name))
+
+ code.add_line('return "".join(result)')
+ code.dedent()
+ self._render_function = code.get_globals()['render_function']
+
+ def _expr_code(self, expr):
+ """Generate a Python expression for `expr`."""
+ if "|" in expr:
+ pipes = expr.split("|")
+ code = self._expr_code(pipes[0])
+ for func in pipes[1:]:
+ self._variable(func, self.all_vars)
+ code = "c_%s(%s)" % (func, code)
+ elif "." in expr:
+ dots = expr.split(".")
+ code = self._expr_code(dots[0])
+ args = ", ".join(repr(d) for d in dots[1:])
+ code = "do_dots(%s, %s)" % (code, args)
+ else:
+ self._variable(expr, self.all_vars)
+ code = "c_%s" % expr
+ return code
+
+ def _syntax_error(self, msg, thing):
+ """Raise a syntax error using `msg`, and showing `thing`."""
+ raise TempliteSyntaxError("%s: %r" % (msg, thing))
+
+ def _variable(self, name, vars_set):
+ """Track that `name` is used as a variable.
+
+ Adds the name to `vars_set`, a set of variable names.
+
+ Raises an syntax error if `name` is not a valid name.
+
+ """
+ if not re.match(r"[_a-zA-Z][_a-zA-Z0-9]*$", name):
+ self._syntax_error("Not a valid name", name)
+ vars_set.add(name)
+
+ def render(self, context=None):
+ """Render this template by applying it to `context`.
+
+ `context` is a dictionary of values to use in this rendering.
+
+ """
+ # Make the complete context we'll use.
+ render_context = dict(self.context)
+ if context:
+ render_context.update(context)
+ return self._render_function(render_context, self._do_dots)
+
+ def _do_dots(self, value, *dots):
+ """Evaluate dotted expressions at run-time."""
+ for dot in dots:
+ try:
+ value = getattr(value, dot)
+ except AttributeError:
+ try:
+ value = value[dot]
+ except (TypeError, KeyError):
+ raise TempliteValueError(
+ "Couldn't evaluate %r.%s" % (value, dot)
+ )
+ if callable(value):
+ value = value()
+ return value

Powered by Google App Engine
This is Rietveld 408576698