annotate genshi/template/eval.py @ 645:938d2a59196d experimental-sandboxed

readded lambda, it's better to wrap the rendering with a try/except and check for a RuntimeError that represents recursion
author aronacher
date Wed, 26 Sep 2007 17:01:16 +0000
parents e60298f5b17b
children b6cdfcb37496
rev   line source
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
2 #
408
49a3bae5a8bb Update copyright year for files modified this year.
cmlenz
parents: 406
diff changeset
3 # Copyright (C) 2006-2007 Edgewall Software
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
4 # All rights reserved.
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
5 #
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
6 # This software is licensed as described in the file COPYING, which
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
7 # you should have received as part of this distribution. The terms
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
8 # are also available at http://genshi.edgewall.org/wiki/License.
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
9 #
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
10 # This software consists of voluntary contributions made by many
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
11 # individuals. For the exact contribution history, see the revision
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
12 # history and logs, available at http://genshi.edgewall.org/log/.
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
13
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
14 """Support for "safe" evaluation of Python expressions."""
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
15
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
16 import __builtin__
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
17 from compiler import ast, parse
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
18 from compiler.pycodegen import ExpressionCodeGenerator, ModuleCodeGenerator
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
19 import new
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
20 try:
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
21 set
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
22 except NameError:
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
23 from sets import ImmutableSet as frozenset
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
24 from sets import Set as set
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
25 import sys
601
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
26 from textwrap import dedent
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
27 from types import FunctionType, MethodType
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
28
401
9582328f82e5 Make the `Markup` class available by default in template expressions. Closes #67.
cmlenz
parents: 396
diff changeset
29 from genshi.core import Markup
418
878ffab274a6 Make expression error handling more strict. Closes #88.
cmlenz
parents: 408
diff changeset
30 from genshi.template.base import TemplateRuntimeError
643
e5363d3c22d3 some more work on the sandbox
aronacher
parents: 642
diff changeset
31 from genshi.util import flatten, safe_range
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
32
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
33 __all__ = ['Code', 'Expression', 'Suite', 'LenientLookup', 'StrictLookup',
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
34 'Undefined', 'UndefinedError']
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
35 __docformat__ = 'restructuredtext en'
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
36
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
37
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
38 class Code(object):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
39 """Abstract base class for the `Expression` and `Suite` classes."""
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
40 __slots__ = ['source', 'code', 'ast', 'secure', '_globals']
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
41
606
9ada030ad986 Changed the default error handling mode to "strict".
cmlenz
parents: 604
diff changeset
42 def __init__(self, source, filename=None, lineno=-1, lookup='strict',
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
43 xform=None, secure=False):
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
44 """Create the code object, either from a string, or from an AST node.
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
45
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
46 :param source: either a string containing the source code, or an AST
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
47 node
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
48 :param filename: the (preferably absolute) name of the file containing
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
49 the code
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
50 :param lineno: the number of the line on which the code was found
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
51 :param lookup: the lookup class that defines how variables are looked
606
9ada030ad986 Changed the default error handling mode to "strict".
cmlenz
parents: 604
diff changeset
52 up in the context; can be either "strict" (the default),
9ada030ad986 Changed the default error handling mode to "strict".
cmlenz
parents: 604
diff changeset
53 "lenient", or a custom lookup class
604
6d1fa718794f Fix bug that slipped into [717]: the code of a `py:with` directive was not being compiled with AST transformations applied.
cmlenz
parents: 601
diff changeset
54 :param xform: the AST transformer that should be applied to the code;
6d1fa718794f Fix bug that slipped into [717]: the code of a `py:with` directive was not being compiled with AST transformations applied.
cmlenz
parents: 601
diff changeset
55 if `None`, the appropriate transformation is chosen
6d1fa718794f Fix bug that slipped into [717]: the code of a `py:with` directive was not being compiled with AST transformations applied.
cmlenz
parents: 601
diff changeset
56 depending on the mode
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
57 :param secure: If security features should be enabled.
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
58 """
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
59 if isinstance(source, basestring):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
60 self.source = source
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
61 node = _parse(source, mode=self.mode)
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
62 else:
601
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
63 assert isinstance(source, ast.Node), \
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
64 'Expected string or AST node, but got %r' % source
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
65 self.source = '?'
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
66 if self.mode == 'eval':
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
67 node = ast.Expression(source)
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
68 else:
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
69 node = ast.Module(None, source)
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
70
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
71 self.ast = node
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
72 self.code = _compile(node, self.source, mode=self.mode,
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
73 filename=filename, lineno=lineno, xform=xform,
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
74 secure=secure)
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
75 if lookup is None:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
76 lookup = LenientLookup
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
77 elif isinstance(lookup, basestring):
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
78 lookup = {
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
79 'lenient': LenientLookup,
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
80 'strict': StrictLookup
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
81 }[lookup]
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
82 if secure:
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
83 lookup = SecurityLookupWrapper(lookup)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
84 self.secure = secure
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
85 self._globals = lookup.globals()
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
86
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
87 def __eq__(self, other):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
88 return (type(other) == type(self)) and (self.code == other.code)
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
89
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
90 def __hash__(self):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
91 return hash(self.code)
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
92
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
93 def __ne__(self, other):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
94 return not self == other
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
95
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
96 def __repr__(self):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
97 return '%s(%r)' % (self.__class__.__name__, self.source)
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
98
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
99
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
100 class Expression(Code):
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
101 """Evaluates Python expressions used in templates.
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
102
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
103 >>> data = dict(test='Foo', items=[1, 2, 3], dict={'some': 'thing'})
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
104 >>> Expression('test').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
105 'Foo'
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
106
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
107 >>> Expression('items[0]').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
108 1
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
109 >>> Expression('items[-1]').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
110 3
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
111 >>> Expression('dict["some"]').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
112 'thing'
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
113
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
114 Similar to e.g. Javascript, expressions in templates can use the dot
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
115 notation for attribute access to access items in mappings:
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
116
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
117 >>> Expression('dict.some').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
118 'thing'
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
119
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
120 This also works the other way around: item access can be used to access
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
121 any object attribute:
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
122
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
123 >>> class MyClass(object):
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
124 ... myattr = 'Bar'
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
125 >>> data = dict(mine=MyClass(), key='myattr')
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
126 >>> Expression('mine.myattr').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
127 'Bar'
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
128 >>> Expression('mine["myattr"]').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
129 'Bar'
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
130 >>> Expression('mine[key]').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
131 'Bar'
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
132
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
133 All of the standard Python operators are available to template expressions.
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
134 Built-in functions such as ``len()`` are also available in template
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
135 expressions:
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
136
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
137 >>> data = dict(items=[1, 2, 3])
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
138 >>> Expression('len(items)').evaluate(data)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
139 3
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
140 """
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
141 __slots__ = []
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
142 mode = 'eval'
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
143
343
4ff2338e89cd Remove automatic calling of expression evaluation results if they are callable. See [http://groups.google.com/group/genshi/browse_thread/thread/f515986760918d41 this mailing list thread].
cmlenz
parents: 340
diff changeset
144 def evaluate(self, data):
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
145 """Evaluate the expression against the given data dictionary.
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
146
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
147 :param data: a mapping containing the data to evaluate against
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
148 :return: the result of the evaluation
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
149 """
418
878ffab274a6 Make expression error handling more strict. Closes #88.
cmlenz
parents: 408
diff changeset
150 __traceback_hide__ = 'before_and_this'
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
151 _globals = self._globals
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
152 _globals['data'] = data
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
153 return eval(self.code, _globals, {'data': data})
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
154
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
155
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
156 class Suite(Code):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
157 """Executes Python statements used in templates.
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
158
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
159 >>> data = dict(test='Foo', items=[1, 2, 3], dict={'some': 'thing'})
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
160 >>> Suite("foo = dict['some']").execute(data)
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
161 >>> data['foo']
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
162 'thing'
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
163 """
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
164 __slots__ = []
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
165 mode = 'exec'
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
166
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
167 def execute(self, data):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
168 """Execute the suite in the given data dictionary.
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
169
425
5b248708bbed Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents: 418
diff changeset
170 :param data: a mapping containing the data to execute in
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
171 """
418
878ffab274a6 Make expression error handling more strict. Closes #88.
cmlenz
parents: 408
diff changeset
172 __traceback_hide__ = 'before_and_this'
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
173 _globals = self._globals
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
174 _globals['data'] = data
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
175 exec self.code in _globals, data
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
176
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
177
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
178 UNDEFINED = object()
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
179
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
180
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
181 class UndefinedError(TemplateRuntimeError):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
182 """Exception thrown when a template expression attempts to access a variable
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
183 not defined in the context.
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
184
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
185 :see: `LenientLookup`, `StrictLookup`
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
186 """
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
187 def __init__(self, name, owner=UNDEFINED):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
188 if owner is not UNDEFINED:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
189 message = '%s has no member named "%s"' % (repr(owner), name)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
190 else:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
191 message = '"%s" not defined' % name
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
192 TemplateRuntimeError.__init__(self, message)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
193
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
194
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
195 class Undefined(object):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
196 """Represents a reference to an undefined variable.
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
197
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
198 Unlike the Python runtime, template expressions can refer to an undefined
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
199 variable without causing a `NameError` to be raised. The result will be an
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
200 instance of the `Undefined` class, which is treated the same as ``False`` in
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
201 conditions, but raise an exception on any other operation:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
202
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
203 >>> foo = Undefined('foo')
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
204 >>> bool(foo)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
205 False
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
206 >>> list(foo)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
207 []
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
208 >>> print foo
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
209 undefined
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
210
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
211 However, calling an undefined variable, or trying to access an attribute
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
212 of that variable, will raise an exception that includes the name used to
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
213 reference that undefined variable.
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
214
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
215 >>> foo('bar')
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
216 Traceback (most recent call last):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
217 ...
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
218 UndefinedError: "foo" not defined
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
219
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
220 >>> foo.bar
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
221 Traceback (most recent call last):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
222 ...
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
223 UndefinedError: "foo" not defined
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
224
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
225 :see: `LenientLookup`
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
226 """
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
227 __slots__ = ['_name', '_owner']
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
228
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
229 def __init__(self, name, owner=UNDEFINED):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
230 """Initialize the object.
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
231
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
232 :param name: the name of the reference
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
233 :param owner: the owning object, if the variable is accessed as a member
418
878ffab274a6 Make expression error handling more strict. Closes #88.
cmlenz
parents: 408
diff changeset
234 """
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
235 self._name = name
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
236 self._owner = owner
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
237
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
238 def __iter__(self):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
239 return iter([])
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
240
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
241 def __nonzero__(self):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
242 return False
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
243
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
244 def __repr__(self):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
245 return '<%s %r>' % (self.__class__.__name__, self._name)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
246
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
247 def __str__(self):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
248 return 'undefined'
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
249
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
250 def _die(self, *args, **kwargs):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
251 """Raise an `UndefinedError`."""
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
252 __traceback_hide__ = True
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
253 raise UndefinedError(self._name, self._owner)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
254 __call__ = __getattr__ = __getitem__ = _die
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
255
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
256
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
257 class LookupBase(object):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
258 """Abstract base class for variable lookup implementations."""
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
259
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
260 def globals(cls):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
261 """Construct the globals dictionary to use as the execution context for
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
262 the expression or suite.
418
878ffab274a6 Make expression error handling more strict. Closes #88.
cmlenz
parents: 408
diff changeset
263 """
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
264 return {
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
265 '_lookup_name': cls.lookup_name,
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
266 '_lookup_attr': cls.lookup_attr,
579
71e3205925e6 Fix for augmented assignments to local variables. Thanks to Erik Bray for reporting the problem.
cmlenz
parents: 569
diff changeset
267 '_lookup_item': cls.lookup_item,
71e3205925e6 Fix for augmented assignments to local variables. Thanks to Erik Bray for reporting the problem.
cmlenz
parents: 569
diff changeset
268 'UndefinedError': UndefinedError
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
269 }
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
270 globals = classmethod(globals)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
271
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
272 def lookup_name(cls, data, name):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
273 __traceback_hide__ = True
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
274 val = data.get(name, UNDEFINED)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
275 if val is UNDEFINED:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
276 val = BUILTINS.get(name, val)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
277 if val is UNDEFINED:
569
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
278 val = cls.undefined(name)
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
279 return val
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
280 lookup_name = classmethod(lookup_name)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
281
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
282 def lookup_attr(cls, data, obj, key):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
283 __traceback_hide__ = True
569
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
284 val = getattr(obj, key, UNDEFINED)
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
285 if val is UNDEFINED:
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
286 try:
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
287 val = obj[key]
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
288 except (KeyError, TypeError):
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
289 val = cls.undefined(key, owner=obj)
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
290 return val
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
291 lookup_attr = classmethod(lookup_attr)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
292
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
293 def lookup_item(cls, data, obj, key):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
294 __traceback_hide__ = True
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
295 if len(key) == 1:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
296 key = key[0]
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
297 try:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
298 return obj[key]
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
299 except (AttributeError, KeyError, IndexError, TypeError), e:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
300 if isinstance(key, basestring):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
301 val = getattr(obj, key, UNDEFINED)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
302 if val is UNDEFINED:
569
4cbd8031ed76 Attribute access in template expressions no longer silently ignores exceptions other than `AttributeError` raised in the attribute accessor.
cmlenz
parents: 568
diff changeset
303 val = cls.undefined(key, owner=obj)
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
304 return val
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
305 raise
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
306 lookup_item = classmethod(lookup_item)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
307
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
308 def undefined(cls, key, owner=UNDEFINED):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
309 """Can be overridden by subclasses to specify behavior when undefined
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
310 variables are accessed.
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
311
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
312 :param key: the name of the variable
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
313 :param owner: the owning object, if the variable is accessed as a member
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
314 """
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
315 raise NotImplementedError
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
316 undefined = classmethod(undefined)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
317
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
318
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
319 class LenientLookup(LookupBase):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
320 """Default variable lookup mechanism for expressions.
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
321
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
322 When an undefined variable is referenced using this lookup style, the
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
323 reference evaluates to an instance of the `Undefined` class:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
324
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
325 >>> expr = Expression('nothing', lookup='lenient')
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
326 >>> undef = expr.evaluate({})
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
327 >>> undef
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
328 <Undefined 'nothing'>
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
329
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
330 The same will happen when a non-existing attribute or item is accessed on
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
331 an existing object:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
332
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
333 >>> expr = Expression('something.nil', lookup='lenient')
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
334 >>> expr.evaluate({'something': dict()})
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
335 <Undefined 'nil'>
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
336
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
337 See the documentation of the `Undefined` class for details on the behavior
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
338 of such objects.
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
339
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
340 :see: `StrictLookup`
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
341 """
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
342 def undefined(cls, key, owner=UNDEFINED):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
343 """Return an ``Undefined`` object."""
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
344 __traceback_hide__ = True
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
345 return Undefined(key, owner=owner)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
346 undefined = classmethod(undefined)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
347
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
348
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
349 class StrictLookup(LookupBase):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
350 """Strict variable lookup mechanism for expressions.
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
351
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
352 Referencing an undefined variable using this lookup style will immediately
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
353 raise an ``UndefinedError``:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
354
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
355 >>> expr = Expression('nothing', lookup='strict')
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
356 >>> expr.evaluate({})
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
357 Traceback (most recent call last):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
358 ...
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
359 UndefinedError: "nothing" not defined
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
360
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
361 The same happens when a non-existing attribute or item is accessed on an
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
362 existing object:
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
363
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
364 >>> expr = Expression('something.nil', lookup='strict')
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
365 >>> expr.evaluate({'something': dict()})
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
366 Traceback (most recent call last):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
367 ...
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
368 UndefinedError: {} has no member named "nil"
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
369 """
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
370 def undefined(cls, key, owner=UNDEFINED):
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
371 """Raise an ``UndefinedError`` immediately."""
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
372 __traceback_hide__ = True
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
373 raise UndefinedError(key, owner=owner)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
374 undefined = classmethod(undefined)
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
375
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
376
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
377 class SecurityLookupWrapper(object):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
378 """
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
379 Special class that wraps a lookup so that insecure accesses result
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
380 in undefined. Additionally the globals are secured.
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
381 """
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
382
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
383 def __init__(self, lookup):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
384 self._lookup = lookup
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
385
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
386 def __getattr__(self, name):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
387 return getattr(self._lookup, name)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
388
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
389 def globals(self):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
390 namespace = self._lookup.globals()
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
391 namespace.update(
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
392 _lookup_name=self.lookup_name,
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
393 _lookup_attr=self.lookup_attr,
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
394 _lookup_item=self.lookup_item
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
395 )
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
396 return namespace
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
397
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
398 def lookup_name(self, data, name):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
399 __traceback_hide__ = True
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
400 if name.startswith('_'):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
401 val = self._lookup.undefined(name)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
402 else:
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
403 val = data.get(name, UNDEFINED)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
404 if val is UNDEFINED:
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
405 val = SECURE_BUILTINS.get(name, val)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
406 if val is UNDEFINED:
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
407 val = self._lookup.undefined(name)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
408 return val
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
409
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
410 def lookup_attr(self, data, obj, key):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
411 __traceback_hide__ = True
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
412 # XXX: if we weaken this, don't forget to create an
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
413 # _unsafe_test for sys._active_frames / sys._getframe
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
414 if key.startswith('_') or self._unsafe_test(obj, key):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
415 return self._lookup.undefined(key)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
416 return self._lookup.lookup_attr(data, obj, key)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
417
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
418 def lookup_item(cls, data, obj, key):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
419 __traceback_hide__ = True
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
420 if key.startswith('_') or self._unsafe_test(obj, key):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
421 return self._lookup.undefined(key)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
422 return self._lookup.lookup_item(data, obj, key)
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
423
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
424 def _unsafe_test(self, obj, key):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
425 if isinstance(obj, MethodType):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
426 if key in ('im_class', 'im_func', 'im_self'):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
427 return True
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
428 obj = obj.im_func
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
429 if isinstance(obj, FunctionType):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
430 return key in ('func_closure', 'func_code', 'func_defaults',
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
431 'func_dict', 'func_doc', 'func_globals',
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
432 'func_name')
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
433 known_unsafe = getattr(obj, '__genshi_unsafe__', ())
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
434 return key in known_unsafe
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
435
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
436
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
437 def _parse(source, mode='eval'):
601
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
438 source = source.strip()
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
439 if mode == 'exec':
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
440 lines = [line.expandtabs() for line in source.splitlines()]
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
441 first = lines[0]
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
442 rest = dedent('\n'.join(lines[1:])).rstrip()
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
443 if first.rstrip().endswith(':') and not rest[0].isspace():
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
444 rest = '\n'.join([' %s' % line for line in rest.splitlines()])
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
445 source = '\n'.join([first, rest])
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
446 if isinstance(source, unicode):
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
447 source = '\xef\xbb\xbf' + source.encode('utf-8')
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
448 return parse(source, mode)
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
449
604
6d1fa718794f Fix bug that slipped into [717]: the code of a `py:with` directive was not being compiled with AST transformations applied.
cmlenz
parents: 601
diff changeset
450 def _compile(node, source=None, mode='eval', filename=None, lineno=-1,
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
451 xform=None, secure=False):
604
6d1fa718794f Fix bug that slipped into [717]: the code of a `py:with` directive was not being compiled with AST transformations applied.
cmlenz
parents: 601
diff changeset
452 if xform is None:
6d1fa718794f Fix bug that slipped into [717]: the code of a `py:with` directive was not being compiled with AST transformations applied.
cmlenz
parents: 601
diff changeset
453 xform = {'eval': ExpressionASTTransformer}.get(mode,
6d1fa718794f Fix bug that slipped into [717]: the code of a `py:with` directive was not being compiled with AST transformations applied.
cmlenz
parents: 601
diff changeset
454 TemplateASTTransformer)
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
455 tree = xform(secure).visit(node)
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
456 if isinstance(filename, unicode):
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
457 # unicode file names not allowed for code objects
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
458 filename = filename.encode('utf-8', 'replace')
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
459 elif not filename:
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
460 filename = '<string>'
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
461 tree.filename = filename
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
462 if lineno <= 0:
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
463 lineno = 1
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
464
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
465 if mode == 'eval':
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
466 gen = ExpressionCodeGenerator(tree)
601
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
467 name = '<Expression %r>' % (source or '?')
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
468 else:
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
469 gen = ModuleCodeGenerator(tree)
601
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
470 lines = source.splitlines()
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
471 extract = lines[0]
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
472 if len(lines) > 1:
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
473 extract += ' ...'
9ae986bcba9a Simplify implementation of `py:with` directive by compiling to a `Suite`, instead of manually breaking up the statement and compiling each part to an `Expression`. Also, the first line of code in a `Suite` is now stored as the "function name" of the bytecode, so that it shows up in tracebacks.
cmlenz
parents: 586
diff changeset
474 name = '<Suite %r>' % (extract)
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
475 gen.optimized = True
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
476 code = gen.getCode()
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
477
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
478 # We'd like to just set co_firstlineno, but it's readonly. So we need to
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
479 # clone the code object while adjusting the line number
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
480 return new.code(0, code.co_nlocals, code.co_stacksize,
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
481 code.co_flags | 0x0040, code.co_code, code.co_consts,
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
482 code.co_names, code.co_varnames, filename, name, lineno,
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
483 code.co_lnotab, (), ())
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
484
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
485 BUILTINS = __builtin__.__dict__.copy()
442
ff7c72b52fb2 Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents: 438
diff changeset
486 BUILTINS.update({'Markup': Markup, 'Undefined': Undefined})
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
487
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
488 # XXX: if we weaken the rule for global name resultion so that leading
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
489 # underscores are valid we have to add __import__ here.
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
490 UNSAFE_NAMES = ['file', 'open', 'eval', 'locals', 'globals', 'vars',
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
491 'help', 'quit', 'exit', 'input', 'raw_input', 'setattr',
643
e5363d3c22d3 some more work on the sandbox
aronacher
parents: 642
diff changeset
492 'delattr', 'reload', 'compile', 'type']
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
493
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
494 # XXX: provide a secure range function
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
495 SECURE_BUILTINS = BUILTINS.copy()
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
496 for _unsafe_name in UNSAFE_NAMES:
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
497 del SECURE_BUILTINS[_unsafe_name]
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
498 del _unsafe_name
643
e5363d3c22d3 some more work on the sandbox
aronacher
parents: 642
diff changeset
499 SECURE_BUILTINS['range'] = safe_range
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
500
563
80fb59bd2342 Built-in Python constants (such as `None`) in expressions are used directly instead of being looked up from the context.
cmlenz
parents: 473
diff changeset
501 CONSTANTS = frozenset(['False', 'True', 'None', 'NotImplemented', 'Ellipsis'])
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
502
564
b3b07279b86c Alias `__contains__` to `has_key` in `Context` class for code outside of Genshi that may expect that for some wild reason.
cmlenz
parents: 563
diff changeset
503
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
504 class ASTTransformer(object):
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
505 """General purpose base class for AST transformations.
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
506
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
507 Every visitor method can be overridden to return an AST node that has been
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
508 altered or replaced in some way.
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
509 """
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
510
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
511 def __init__(self, secure):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
512 self.secure = secure
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
513
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
514 def visit(self, node):
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
515 if node is None:
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
516 return None
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
517 if type(node) is tuple:
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
518 return tuple([self.visit(n) for n in node])
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
519 visitor = getattr(self, 'visit%s' % node.__class__.__name__,
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
520 self._visitDefault)
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
521 return visitor(node)
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
522
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
523 def _clone(self, node, *args):
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
524 lineno = getattr(node, 'lineno', None)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
525 node = node.__class__(*args)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
526 if lineno is not None:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
527 node.lineno = lineno
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
528 if isinstance(node, (ast.Class, ast.Function, ast.GenExpr, ast.Lambda)):
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
529 node.filename = '<string>' # workaround for bug in pycodegen
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
530 return node
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
531
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
532 def _visitDefault(self, node):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
533 return node
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
534
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
535 def visitExpression(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
536 return self._clone(node, self.visit(node.node))
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
537
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
538 def visitModule(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
539 return self._clone(node, node.doc, self.visit(node.node))
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
540
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
541 def visitStmt(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
542 return self._clone(node, [self.visit(x) for x in node.nodes])
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
543
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
544 # Classes, Functions & Accessors
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
545
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
546 def visitCallFunc(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
547 return self._clone(node, self.visit(node.node),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
548 [self.visit(x) for x in node.args],
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
549 node.star_args and self.visit(node.star_args) or None,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
550 node.dstar_args and self.visit(node.dstar_args) or None
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
551 )
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
552
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
553 def visitClass(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
554 return self._clone(node, node.name, [self.visit(x) for x in node.bases],
568
8f0d601afc0c AST transformer needs to also handle the class body.
cmlenz
parents: 565
diff changeset
555 node.doc, self.visit(node.code)
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
556 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
557
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
558 def visitFunction(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
559 args = []
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
560 if hasattr(node, 'decorators'):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
561 args.append(self.visit(node.decorators))
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
562 return self._clone(node, *args + [
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
563 node.name,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
564 node.argnames,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
565 [self.visit(x) for x in node.defaults],
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
566 node.flags,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
567 node.doc,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
568 self.visit(node.code)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
569 ])
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
570
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
571 def visitGetattr(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
572 return self._clone(node, self.visit(node.expr), node.attrname)
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
573
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
574 def visitLambda(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
575 node = self._clone(node, node.argnames,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
576 [self.visit(x) for x in node.defaults], node.flags,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
577 self.visit(node.code)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
578 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
579 return node
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
580
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
581 def visitSubscript(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
582 return self._clone(node, self.visit(node.expr), node.flags,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
583 [self.visit(x) for x in node.subs]
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
584 )
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
585
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
586 # Statements
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
587
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
588 def visitAssert(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
589 return self._clone(node, self.visit(node.test), self.visit(node.fail))
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
590
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
591 def visitAssign(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
592 return self._clone(node, [self.visit(x) for x in node.nodes],
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
593 self.visit(node.expr)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
594 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
595
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
596 def visitAssAttr(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
597 return self._clone(node, self.visit(node.expr), node.attrname,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
598 node.flags
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
599 )
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
600
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
601 def visitAugAssign(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
602 return self._clone(node, self.visit(node.node), node.op,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
603 self.visit(node.expr)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
604 )
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
605
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
606 def visitDecorators(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
607 return self._clone(node, [self.visit(x) for x in node.nodes])
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
608
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
609 def visitExec(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
610 return self._clone(node, self.visit(node.expr), self.visit(node.locals),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
611 self.visit(node.globals)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
612 )
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
613
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
614 def visitFor(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
615 return self._clone(node, self.visit(node.assign), self.visit(node.list),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
616 self.visit(node.body), self.visit(node.else_)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
617 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
618
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
619 def visitIf(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
620 return self._clone(node, [self.visit(x) for x in node.tests],
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
621 self.visit(node.else_)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
622 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
623
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
624 def _visitPrint(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
625 return self._clone(node, [self.visit(x) for x in node.nodes],
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
626 self.visit(node.dest)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
627 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
628 visitPrint = visitPrintnl = _visitPrint
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
629
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
630 def visitRaise(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
631 return self._clone(node, self.visit(node.expr1), self.visit(node.expr2),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
632 self.visit(node.expr3)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
633 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
634
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
635 def visitReturn(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
636 return self._clone(node, self.visit(node.value))
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
637
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
638 def visitTryExcept(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
639 return self._clone(node, self.visit(node.body), self.visit(node.handlers),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
640 self.visit(node.else_)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
641 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
642
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
643 def visitTryFinally(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
644 return self._clone(node, self.visit(node.body), self.visit(node.final))
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
645
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
646 def visitWhile(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
647 return self._clone(node, self.visit(node.test), self.visit(node.body),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
648 self.visit(node.else_)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
649 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
650
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
651 def visitWith(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
652 return self._clone(node, self.visit(node.expr),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
653 [self.visit(x) for x in node.vars], self.visit(node.body)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
654 )
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
655
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
656 def visitYield(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
657 return self._clone(node, self.visit(node.value))
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
658
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
659 # Operators
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
660
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
661 def _visitBoolOp(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
662 return self._clone(node, [self.visit(x) for x in node.nodes])
396
22a581cfa537 add visitor for xor operator
mgood
parents: 393
diff changeset
663 visitAnd = visitOr = visitBitand = visitBitor = visitBitxor = _visitBoolOp
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
664 visitAssTuple = visitAssList = _visitBoolOp
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
665
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
666 def _visitBinOp(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
667 return self._clone(node,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
668 (self.visit(node.left), self.visit(node.right))
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
669 )
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
670 visitAdd = visitSub = _visitBinOp
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
671 visitDiv = visitFloorDiv = visitMod = visitMul = visitPower = _visitBinOp
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
672 visitLeftShift = visitRightShift = _visitBinOp
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
673
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
674 def visitCompare(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
675 return self._clone(node, self.visit(node.expr),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
676 [(op, self.visit(n)) for op, n in node.ops]
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
677 )
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
678
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
679 def _visitUnaryOp(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
680 return self._clone(node, self.visit(node.expr))
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
681 visitUnaryAdd = visitUnarySub = visitNot = visitInvert = _visitUnaryOp
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
682 visitBackquote = visitDiscard = _visitUnaryOp
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
683
393
a056613621ab add support for Python 2.5 conditional expressions (fixes #74)
mgood
parents: 382
diff changeset
684 def visitIfExp(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
685 return self._clone(node, self.visit(node.test), self.visit(node.then),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
686 self.visit(node.else_)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
687 )
393
a056613621ab add support for Python 2.5 conditional expressions (fixes #74)
mgood
parents: 382
diff changeset
688
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
689 # Identifiers, Literals and Comprehensions
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
690
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
691 def visitDict(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
692 return self._clone(node,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
693 [(self.visit(k), self.visit(v)) for k, v in node.items]
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
694 )
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
695
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
696 def visitGenExpr(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
697 return self._clone(node, self.visit(node.code))
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
698
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
699 def visitGenExprFor(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
700 return self._clone(node, self.visit(node.assign), self.visit(node.iter),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
701 [self.visit(x) for x in node.ifs]
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
702 )
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
703
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
704 def visitGenExprIf(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
705 return self._clone(node, self.visit(node.test))
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
706
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
707 def visitGenExprInner(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
708 quals = [self.visit(x) for x in node.quals]
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
709 return self._clone(node, self.visit(node.expr), quals)
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
710
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
711 def visitKeyword(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
712 return self._clone(node, node.name, self.visit(node.expr))
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
713
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
714 def visitList(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
715 return self._clone(node, [self.visit(n) for n in node.nodes])
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
716
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
717 def visitListComp(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
718 quals = [self.visit(x) for x in node.quals]
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
719 return self._clone(node, self.visit(node.expr), quals)
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
720
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
721 def visitListCompFor(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
722 return self._clone(node, self.visit(node.assign), self.visit(node.list),
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
723 [self.visit(x) for x in node.ifs]
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
724 )
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
725
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
726 def visitListCompIf(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
727 return self._clone(node, self.visit(node.test))
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
728
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
729 def visitSlice(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
730 return self._clone(node, self.visit(node.expr), node.flags,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
731 node.lower and self.visit(node.lower) or None,
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
732 node.upper and self.visit(node.upper) or None
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
733 )
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
734
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
735 def visitSliceobj(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
736 return self._clone(node, [self.visit(x) for x in node.nodes])
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
737
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
738 def visitTuple(self, node):
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
739 return self._clone(node, [self.visit(n) for n in node.nodes])
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
740
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
741
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
742 class TemplateASTTransformer(ASTTransformer):
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
743 """Concrete AST transformer that implements the AST transformations needed
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
744 for code embedded in templates.
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
745 """
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
746
642
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
747 def __init__(self, secure):
1cf5fdfe7214 first implementaiton of a secure genshi
aronacher
parents: 606
diff changeset
748 ASTTransformer.__init__(self, secure)
586
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
749 self.locals = [CONSTANTS]
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
750
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
751 def visitConst(self, node):
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
752 if isinstance(node.value, str):
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
753 try: # If the string is ASCII, return a `str` object
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
754 node.value.decode('ascii')
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
755 except ValueError: # Otherwise return a `unicode` object
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
756 return ast.Const(node.value.decode('utf-8'))
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
757 return node
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
758
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
759 def visitAssName(self, node):
586
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
760 if len(self.locals) > 1:
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
761 self.locals[-1].add(node.name)
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
762 return node
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
763
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
764 def visitAugAssign(self, node):
579
71e3205925e6 Fix for augmented assignments to local variables. Thanks to Erik Bray for reporting the problem.
cmlenz
parents: 569
diff changeset
765 if isinstance(node.node, ast.Name) \
582
b21da79c9bde Follow-up fix to [693:694]. Again, thanks to Erik Bray for reporting.
cmlenz
parents: 579
diff changeset
766 and node.node.name not in flatten(self.locals):
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
767 name = node.node.name
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
768 node.node = ast.Subscript(ast.Name('data'), 'OP_APPLY',
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
769 [ast.Const(name)])
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
770 node.expr = self.visit(node.expr)
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
771 return ast.If([
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
772 (ast.Compare(ast.Const(name), [('in', ast.Name('data'))]),
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
773 ast.Stmt([node]))],
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
774 ast.Stmt([ast.Raise(ast.CallFunc(ast.Name('UndefinedError'),
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
775 [ast.Const(name)]),
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
776 None, None)]))
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
777 else:
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
778 return ASTTransformer.visitAugAssign(self, node)
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
779
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
780 def visitClass(self, node):
586
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
781 if len(self.locals) > 1:
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
782 self.locals[-1].add(node.name)
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
783 self.locals.append(set())
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
784 try:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
785 return ASTTransformer.visitClass(self, node)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
786 finally:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
787 self.locals.pop()
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
788
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
789 def visitFor(self, node):
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
790 self.locals.append(set())
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
791 try:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
792 return ASTTransformer.visitFor(self, node)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
793 finally:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
794 self.locals.pop()
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
795
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
796 def visitFunction(self, node):
586
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
797 if len(self.locals) > 1:
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
798 self.locals[-1].add(node.name)
405
bd5da099c113 Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents: 401
diff changeset
799 self.locals.append(set(node.argnames))
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
800 try:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
801 return ASTTransformer.visitFunction(self, node)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
802 finally:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
803 self.locals.pop()
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
804
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
805 def visitGenExpr(self, node):
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
806 self.locals.append(set())
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
807 try:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
808 return ASTTransformer.visitGenExpr(self, node)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
809 finally:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
810 self.locals.pop()
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
811
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
812 def visitLambda(self, node):
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
813 self.locals.append(set(flatten(node.argnames)))
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
814 try:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
815 return ASTTransformer.visitLambda(self, node)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
816 finally:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
817 self.locals.pop()
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
818
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
819 def visitListComp(self, node):
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
820 self.locals.append(set())
565
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
821 try:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
822 return ASTTransformer.visitListComp(self, node)
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
823 finally:
aa8e85a4085e * The I18n extractor now handles gettext function calls that use non-string parameters as well as keyword arguments.
cmlenz
parents: 564
diff changeset
824 self.locals.pop()
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
825
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
826 def visitName(self, node):
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
827 # If the name refers to a local inside a lambda, list comprehension, or
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
828 # generator expression, leave it alone
586
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
829 if node.name not in flatten(self.locals):
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
830 # Otherwise, translate the name ref into a context lookup
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
831 func_args = [ast.Name('data'), ast.Const(node.name)]
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
832 node = ast.CallFunc(ast.Name('_lookup_name'), func_args)
5413c9d95db1 Fixes for nonlocal variable access in code blocks, as well as nested function and class definitions.
cmlenz
parents: 582
diff changeset
833 return node
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
834
473
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
835
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
836 class ExpressionASTTransformer(TemplateASTTransformer):
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
837 """Concrete AST transformer that implements the AST transformations needed
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
838 for code embedded in templates.
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
839 """
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
840
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
841 def visitGetattr(self, node):
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
842 return ast.CallFunc(ast.Name('_lookup_attr'), [
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
843 ast.Name('data'), self.visit(node.expr),
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
844 ast.Const(node.attrname)
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
845 ])
5870bdf03fca Apply patch from #113, also closing #114.
cmlenz
parents: 442
diff changeset
846
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
847 def visitSubscript(self, node):
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
848 return ast.CallFunc(ast.Name('_lookup_item'), [
357
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
849 ast.Name('data'), self.visit(node.expr),
c5684b65c9b7 Improve the way locals (in list comprehensions, lambdas and generator expressions) are handled in template expressions.
cmlenz
parents: 343
diff changeset
850 ast.Tuple([self.visit(sub) for sub in node.subs])
336
5f2c7782cd8a Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
851 ])
Copyright (C) 2012-2017 Edgewall Software