From 2acbac1fb2639558408daf49d9d39185142595b4 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 11 Apr 2007 21:49:48 +0200 Subject: [PATCH] [svn] checked in changes from the last days regarding jinja, added jinja 1.1 notice for floor divison operator --HG-- branch : trunk --- CHANGES | 3 ++ docs/src/designerdoc.txt | 22 ++++++++++++--- docs/src/devintro.txt | 20 +++++++++++++ docs/src/index.txt | 2 ++ jinja/datastructure.py | 5 +++- jinja/defaults.py | 4 +-- jinja/parser.py | 2 ++ jinja/translators/python.py | 11 ++++---- jinja/utils.py | 56 +++++++++++++++++++++++++++++++------ 9 files changed, 104 insertions(+), 21 deletions(-) diff --git a/CHANGES b/CHANGES index 1fb0393..18545e5 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,9 @@ Version 1.1 - added a bunch of new docstrings to the Jinja classes. Makes fun now to use pydoc :-) +- fixed severe memcaching bug. Formerly it wasn't possible to use memcaching + without enabling disk cache. + Version 1.0 ----------- diff --git a/docs/src/designerdoc.txt b/docs/src/designerdoc.txt index 959a79b..b8d7904 100644 --- a/docs/src/designerdoc.txt +++ b/docs/src/designerdoc.txt @@ -88,9 +88,9 @@ with the arguments ``'foo'`` and ``'bar'``, and pass the result to the filter .. admonition:: note - Filters have a pretty low priority. If you want to add fitered values - you have to put them into parentheses. The same applies if you want to access - attributes: + The filter operator has a pretty low priority. If you want to add fitered + values you have to put them into parentheses. The same applies if you want + to access attributes or return values: .. sourcecode:: jinja @@ -104,6 +104,19 @@ with the arguments ``'foo'`` and ``'bar'``, and pass the result to the filter wrong: {{ foo|filter.attribute }} +*new in Jinja 1.1*: + +Because the application can provide additional filters you can get a documentation +of all the provided filters by calling ``debug.filters()``: + +.. sourcecode:: jinja + + {{ debug.filters() }} + -> returns a plain text representation of all the filters + + {{ debug.filters(False) }} + -> same as above but without the builtin ones. + Tests ===== @@ -368,7 +381,8 @@ can use expressions. In expressions you can use any of the following operators: ``/`` divide the left operand by the right one. ``{{ 1 / 2 }}`` would return ``0.5``. ``//`` divide the left operand by the right one and return a truncated - integer result: ``{{ 20 // 7 }}`` is ``2``. + integer result: ``{{ 20 // 7 }}`` is ``2``. (*new in + Jinja 1.1*) ``*`` multiply the left operand with the right one. ``{{ 2 * 2 }}`` would return ``4``. ``**`` raise the left operand to the power of the right diff --git a/docs/src/devintro.txt b/docs/src/devintro.txt index 9bf7b41..11cf2f0 100644 --- a/docs/src/devintro.txt +++ b/docs/src/devintro.txt @@ -24,6 +24,26 @@ This example should output the following string after execution:: If you receive an error, check if you have a typo in your code. If not, have a look at the `installation`_ page for troubleshooting. +Basically the important method on a template is the `render` method. It +takes either a dict or keyword arguments. All keyword arguments appear +in the template as variables. + +So these two snippets do the same: + +.. sourcecode:: python + + tmpl.render( + knights='we say nih', + spam='and eggs' + ) + +.. sourcecode:: python + + tmpl.render({ + 'knights': 'we say nih', + 'spam': 'and eggs' + }) + The Environment =============== diff --git a/docs/src/index.txt b/docs/src/index.txt index 3a81e17..6253ec8 100644 --- a/docs/src/index.txt +++ b/docs/src/index.txt @@ -30,6 +30,8 @@ Welcome in the Jinja documentation. - `Internationalization `_ + - `Recipies `_ + - Template Designer Documentation: - `Syntax Reference `_ diff --git a/jinja/datastructure.py b/jinja/datastructure.py index e59cda9..432e9df 100644 --- a/jinja/datastructure.py +++ b/jinja/datastructure.py @@ -182,7 +182,7 @@ class Flush(TemplateData): class Context(object): """ - Dict like object. + Dict like object containing the variables for the template. """ def __init__(self, _environment_, *args, **kwargs): @@ -190,6 +190,9 @@ class Context(object): self._stack = [_environment_.globals, dict(*args, **kwargs), {}] self.globals, self.initial, self.current = self._stack + # translator function added by the environment rendering function + self.translate_func = None + # cache object used for filters and tests self.cache = {} diff --git a/jinja/defaults.py b/jinja/defaults.py index 7d13c60..43b67a1 100644 --- a/jinja/defaults.py +++ b/jinja/defaults.py @@ -10,7 +10,7 @@ """ from jinja.filters import FILTERS as DEFAULT_FILTERS from jinja.tests import TESTS as DEFAULT_TESTS -from jinja.utils import debug_context, safe_range, generate_lorem_ipsum, \ +from jinja.utils import debug_helper, safe_range, generate_lorem_ipsum, \ watch_changes, flush @@ -19,7 +19,7 @@ __all__ = ['DEFAULT_FILTERS', 'DEFAULT_TESTS', 'DEFAULT_NAMESPACE'] DEFAULT_NAMESPACE = { 'range': safe_range, - 'debug': debug_context, + 'debug': debug_helper, 'lipsum': generate_lorem_ipsum, 'watchchanges': watch_changes, 'flush': flush diff --git a/jinja/parser.py b/jinja/parser.py index ec09e60..033b101 100644 --- a/jinja/parser.py +++ b/jinja/parser.py @@ -474,6 +474,8 @@ class Parser(object): # if a string is ASCII only we yield it as string # in other cases as unicode. This works around # problems with datetimeobj.strftime() + # also escape newlines in strings + t_data = t_data.replace('\n', '\\n') try: str(t_data) except UnicodeError: diff --git a/jinja/translators/python.py b/jinja/translators/python.py index 1fe6335..d58537f 100644 --- a/jinja/translators/python.py +++ b/jinja/translators/python.py @@ -416,7 +416,8 @@ class PythonTranslator(Translator): ' def translate(s, p=None, n=None, r=None):\n' ' if p is None:\n' ' return translator.gettext(s) % (r or {})\n' - ' return translator.ngettext(s, p, r[n]) % (r or {})' + ' return translator.ngettext(s, p, r[n]) % (r or {})\n' + ' context.translate_func = translate' ) # add body lines and "generator hook" @@ -585,7 +586,7 @@ class PythonTranslator(Translator): buf = [] write = lambda x: buf.append(self.indent(x)) - write('if not %r in context.current:' % name) + write('if %r not in context.current:' % name) self.indention += 1 write(self.nodeinfo(node)) if node.seq.__class__ in (ast.Tuple, ast.List): @@ -683,7 +684,7 @@ class PythonTranslator(Translator): self.indention += 1 write('yield None') self.indention -= 2 - write('yield %s' % self.filter('u\'\'.join(filtered())', + write('yield %s' % self.filter('buffereater(filtered)()', node.filters)) return '\n'.join(buf) @@ -734,7 +735,7 @@ class PythonTranslator(Translator): else: replacements = 'None' return self.indent(self.nodeinfo(node)) + '\n' +\ - self.indent('yield translate(%r, %r, %r, %s)' % ( + self.indent('yield context.translate_func(%r, %r, %r, %s)' % ( node.singular, node.plural, node.indicator, @@ -751,7 +752,7 @@ class PythonTranslator(Translator): return self.constants[node.name] elif node.name == '_': self.require_translations = True - return 'translate' + return 'context.translate_func' return 'context[%r]' % node.name def handle_compare(self, node): diff --git a/jinja/utils.py b/jinja/utils.py index 45b19d1..33afac7 100644 --- a/jinja/utils.py +++ b/jinja/utils.py @@ -29,6 +29,11 @@ if sys.version_info >= (2, 5): else: deque = None +try: + set +except NameError: + from sets import Set as set + #: number of maximal range items MAX_RANGE = 1000000 @@ -123,15 +128,6 @@ def get_attribute(obj, name): return getattr(obj, name) -def debug_context(env, context): - """ - Use this function in templates to get a printed context. - """ - from pprint import pformat - return pformat(context.to_dict()) -debug_context.jinja_context_callable = True - - def safe_range(start, stop=None, step=None): """ "Safe" form of range that does not generate too large lists. @@ -370,6 +366,48 @@ def collect_translations(ast): return result +class DebugHelper(object): + """ + Debugging Helper. Available in the template as "debug". + """ + jinja_context_callable = True + jinja_allowed_attributes = ['filters'] + + def __init__(self): + raise TypeError('cannot create %r instances' % + self.__class__.__name__) + + def __call__(self, env, context): + """Print a nice representation of the context.""" + from pprint import pformat + return pformat(context.to_dict()) + + def filters(self, env, context, builtins=True): + """List the filters.""" + from inspect import getdoc + strip = set() + if not builtins: + from jinja.defaults import DEFAULT_FILTERS + strip = set(DEFAULT_FILTERS.values()) + filters = env.filters.items() + filters.sort(lambda a, b: cmp(a[0].lower(), b[0].lower())) + result = [] + for name, f in filters: + if f in strip: + continue + doc = '\n'.join(' ' + x for x in (getdoc(f) or '').splitlines()) + result.append('`%s`\n\n%s' % (name, doc)) + return '\n\n'.join(result) + filters.jinja_context_callable = True + + def __str__(self): + print 'use debug() for debugging the context' + + +#: the singleton instance of `DebugHelper` +debug_helper = object.__new__(DebugHelper) + + class TracebackLoader(object): """ Fake importer that just returns the source of a template. -- 2.26.2