DebugClients/Python/coverage/templite.py

changeset 5141
bc64243b7672
parent 5126
d28b92dabc2b
parent 5140
01484c0afbc6
child 5144
1ab536d25072
--- a/DebugClients/Python/coverage/templite.py	Fri Sep 02 19:08:02 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,293 +0,0 @@
-# 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 #}
-
-    Any of these constructs can have a hypen at the end (`-}}`, `-%}`, `-#}`),
-    which will collapse the whitespace following the tag.
-
-    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)
-
-        squash = False
-
-        for token in tokens:
-            if token.startswith('{'):
-                start, end = 2, -2
-                squash = (token[-3] == '-')
-                if squash:
-                    end = -3
-
-                if token.startswith('{#'):
-                    # Comment: ignore it and move on.
-                    continue
-                elif token.startswith('{{'):
-                    # An expression to evaluate.
-                    expr = self._expr_code(token[start:end].strip())
-                    buffered.append("to_str(%s)" % expr)
-                elif token.startswith('{%'):
-                    # Action tag: split into words and parse further.
-                    flush_output()
-
-                    words = token[start:end].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 squash:
-                    token = token.lstrip()
-                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
-
-#
-# eflag: FileType = Python2

eric ide

mercurial