mirror of
https://gitee.com/openharmony/third_party_jinja2
synced 2024-11-27 09:20:49 +00:00
added support for dotted names in tests and filters
--HG-- branch : trunk
This commit is contained in:
parent
09c002e6fa
commit
b9e7875e43
25
docs/api.rst
25
docs/api.rst
@ -68,13 +68,15 @@ High Level API
|
||||
|
||||
A dict of filters for this environment. As long as no template was
|
||||
loaded it's safe to add new filters or remove old. For custom filters
|
||||
see :ref:`writing-filters`.
|
||||
see :ref:`writing-filters`. For valid filter names have a look at
|
||||
:ref:`identifier-naming`.
|
||||
|
||||
.. attribute:: tests
|
||||
|
||||
A dict of test functions for this environment. As long as no
|
||||
template was loaded it's safe to modify this dict. For custom tests
|
||||
see :ref:`writing-tests`.
|
||||
see :ref:`writing-tests`. For valid test names have a look at
|
||||
:ref:`identifier-naming`.
|
||||
|
||||
.. attribute:: globals
|
||||
|
||||
@ -82,6 +84,7 @@ High Level API
|
||||
in a template and (if the optimizer is enabled) may not be
|
||||
overridden by templates. As long as no template was loaded it's safe
|
||||
to modify this dict. For more details see :ref:`global-namespace`.
|
||||
For valid object names have a look at :ref:`identifier-naming`.
|
||||
|
||||
.. automethod:: overlay([options])
|
||||
|
||||
@ -111,6 +114,24 @@ High Level API
|
||||
:members: disable_buffering, enable_buffering
|
||||
|
||||
|
||||
.. _identifier-naming:
|
||||
|
||||
Notes on Identifiers
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Jinja2 uses the regular Python 2.x naming rules. Valid identifiers have to
|
||||
match ``[a-zA-Z_][a-zA-Z0-9_]*``. As a matter of fact non ASCII characters
|
||||
are currently not allowed. This limitation will probably go away as soon as
|
||||
unicode identifiers are fully specified for Python 3.
|
||||
|
||||
Filters and tests are looked up in separate namespaces and have slightly
|
||||
modified identifier syntax. Filters and tests may contain dots to group
|
||||
filters and tests by topic. For example it's perfectly valid to add a
|
||||
function into the filter dict and call it `to.unicode`. The regular
|
||||
expression for filter and test identifiers is
|
||||
``[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*```.
|
||||
|
||||
|
||||
Undefined Types
|
||||
---------------
|
||||
|
||||
|
@ -102,6 +102,13 @@ task and usually not needed as the default tags and expressions cover all
|
||||
common use cases. The i18n extension is a good example of why extensions are
|
||||
useful, another one would be fragment caching.
|
||||
|
||||
When writing extensions you have to keep in mind that you are working with the
|
||||
Jinja2 template compiler which does not validate the node tree you are possing
|
||||
to it. If the AST is malformed you will get all kinds of compiler or runtime
|
||||
errors that are horrible to debug. Always make sure you are using the nodes
|
||||
you create correctly. The API documentation below shows which nodes exist and
|
||||
how to use them.
|
||||
|
||||
Example Extension
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -325,6 +325,10 @@ class CodeGenerator(NodeVisitor):
|
||||
# the current line number
|
||||
self.code_lineno = 1
|
||||
|
||||
# registry of all filters and tests (global, not block local)
|
||||
self.tests = {}
|
||||
self.filters = {}
|
||||
|
||||
# the debug information
|
||||
self.debug_info = []
|
||||
self._write_debug_info = None
|
||||
@ -473,10 +477,13 @@ class CodeGenerator(NodeVisitor):
|
||||
visitor = DependencyFinderVisitor()
|
||||
for node in nodes:
|
||||
visitor.visit(node)
|
||||
for name in visitor.filters:
|
||||
self.writeline('f_%s = environment.filters[%r]' % (name, name))
|
||||
for name in visitor.tests:
|
||||
self.writeline('t_%s = environment.tests[%r]' % (name, name))
|
||||
for dependency in 'filters', 'tests':
|
||||
mapping = getattr(self, dependency)
|
||||
for name in getattr(visitor, dependency):
|
||||
if name not in mapping:
|
||||
mapping[name] = self.temporary_identifier()
|
||||
self.writeline('%s = environment.%s[%r]' %
|
||||
(mapping[name], dependency, name))
|
||||
|
||||
def collect_shadowed(self, frame):
|
||||
"""This function returns all the shadowed variables in a dict
|
||||
@ -1215,7 +1222,7 @@ class CodeGenerator(NodeVisitor):
|
||||
self.visit(node.step, frame)
|
||||
|
||||
def visit_Filter(self, node, frame, initial=None):
|
||||
self.write('f_%s(' % node.name)
|
||||
self.write(self.filters[node.name] + '(')
|
||||
func = self.environment.filters.get(node.name)
|
||||
if func is None:
|
||||
raise TemplateAssertionError('no filter named %r' % node.name,
|
||||
@ -1234,7 +1241,7 @@ class CodeGenerator(NodeVisitor):
|
||||
self.write(')')
|
||||
|
||||
def visit_Test(self, node, frame):
|
||||
self.write('t_%s(' % node.name)
|
||||
self.write(self.tests[node.name] + '(')
|
||||
if node.name not in self.environment.tests:
|
||||
raise TemplateAssertionError('no test named %r' % node.name,
|
||||
node.lineno, self.filename)
|
||||
|
@ -727,6 +727,9 @@ class EnvironmentAttribute(Expr):
|
||||
class ExtensionAttribute(Expr):
|
||||
"""Returns the attribute of an extension bound to the environment.
|
||||
The identifier is the identifier of the :class:`Extension`.
|
||||
|
||||
This node is usually constructed by calling the
|
||||
:meth:`~jinja2.ext.Extension.attr` method on an extension.
|
||||
"""
|
||||
fields = ('identifier', 'attr')
|
||||
|
||||
|
@ -676,18 +676,21 @@ class Parser(object):
|
||||
lineno=token.lineno)
|
||||
|
||||
def parse_filter(self, node, start_inline=False):
|
||||
lineno = self.stream.current.type
|
||||
while self.stream.current.type == 'pipe' or start_inline:
|
||||
if not start_inline:
|
||||
self.stream.next()
|
||||
token = self.stream.expect('name')
|
||||
name = token.value
|
||||
while self.stream.current.type is 'dot':
|
||||
self.stream.next()
|
||||
name += '.' + self.stream.expect('name').value
|
||||
if self.stream.current.type is 'lparen':
|
||||
args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
|
||||
else:
|
||||
args = []
|
||||
kwargs = []
|
||||
dyn_args = dyn_kwargs = None
|
||||
node = nodes.Filter(node, token.value, args, kwargs, dyn_args,
|
||||
node = nodes.Filter(node, name, args, kwargs, dyn_args,
|
||||
dyn_kwargs, lineno=token.lineno)
|
||||
start_inline = False
|
||||
return node
|
||||
@ -700,6 +703,9 @@ class Parser(object):
|
||||
else:
|
||||
negated = False
|
||||
name = self.stream.expect('name').value
|
||||
while self.stream.current.type is 'dot':
|
||||
self.stream.next()
|
||||
name += '.' + self.stream.expect('name').value
|
||||
dyn_args = dyn_kwargs = None
|
||||
kwargs = []
|
||||
if self.stream.current.type is 'lparen':
|
||||
|
Loading…
Reference in New Issue
Block a user