From 762079cd25921596b9e1227e6c3bad6d465c430f Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 8 May 2008 23:57:56 +0200 Subject: [PATCH] more updates on the extension API --HG-- branch : trunk --- docs/_static/metal.png | Bin 0 -> 21543 bytes docs/_static/style.css | 5 +- docs/api.rst | 2 +- docs/cache_extension.py | 39 +++++++-------- docs/extensions.rst | 104 ++++++++++++++++++++-------------------- jinja2/environment.py | 9 ++++ jinja2/ext.py | 74 ++++++++++++++-------------- jinja2/nodes.py | 3 +- jinja2/parser.py | 11 ++++- 9 files changed, 132 insertions(+), 115 deletions(-) create mode 100644 docs/_static/metal.png diff --git a/docs/_static/metal.png b/docs/_static/metal.png new file mode 100644 index 0000000000000000000000000000000000000000..97166f131933d6808f8098ba09075c4f973dbe6c GIT binary patch literal 21543 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 V` + can be used to extract strings for babel. For a web application that is available in multiple languages but gives all the users the same language (for example a multilingual forum software @@ -43,40 +78,16 @@ translation methods to the environment at environment generation time:: translations = get_gettext_translations() env = Environment(extensions=['jinja.ext.i18n']) - env.globals.update( - gettext=translations.ugettext, - ngettext=translations.ungettext - ) + env.install_gettext_translations(translations) The `get_gettext_translations` function would return the translator for the -current configuration. Keep in mind that Jinja2 uses unicode internally so -you must pass the `ugettext` and `ungettext` functions to the template. - -The default `_` function injected by the extension calls `gettext` -automatically. - -If you want to pass the gettext function into the context at render time -because you don't know the language/translations earlier and the optimizer -is enabled (which it is per default), you have to unregister the `gettext` -and `ugettext` functions first:: - - del env.globals['gettext'], env.globals['ugettext'] - -Jinja2 also provides a way to extract recognized strings. For one the -`jinja.ext` module provides a function that can return all the occurences -of gettext calls in a node (as returned by :meth:`Environment.parse`): - -.. autofunction:: extract_from_ast - -If `babel`_ is installed :ref:`the babel integration ` -can be used to. +current configuration. (For example by using `gettext.find`) The usage of the `i18n` extension for template designers is covered as part :ref:`of the template documentation `. - .. _gettext: http://docs.python.org/dev/library/gettext -.. _babel: http://babel.edgewall.org/ +.. _Babel: http://babel.edgewall.org/ .. _writing-extensions: @@ -84,6 +95,8 @@ The usage of the `i18n` extension for template designers is covered as part Writing Extensions ------------------ +.. module:: jinja2.ext + By writing extensions you can add custom tags to Jinja2. This is a non trival 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 @@ -92,32 +105,19 @@ useful, another one would be fragment caching. Example Extension ~~~~~~~~~~~~~~~~~ -The following example implements a `cache` tag for Jinja2: +The following example implements a `cache` tag for Jinja2 by using the +`Werkzeug`_ caching contrib module: .. literalinclude:: cache_extension.py :language: python -In order to use the cache extension it makes sense to subclass the environment -to implement the `add_fragment_to_cache` and `load_fragment_from_cache` -methods. The following example shows how to use the `Werkzeug`_ caching -with the extension from above:: +And here is how you use it in an environment:: from jinja2 import Environment from werkzeug.contrib.cache import SimpleCache - cache = SimpleCache() - cache_prefix = 'tempalte_fragment/' - - class MyEnvironment(Environment): - - def __init__(self): - Environment.__init__(self, extensions=[CacheExtension]) - - def add_fragment_to_cache(self, key, value, timeout): - cache.add(cache_prefix + key, value, timeout) - - def load_fragment_from_cache(self, key): - return cache.get(cache_prefix + key) + env = Environment(extensions=[FragmentCacheExtension]) + env.fragment_cache = SimpleCache() .. _Werkzeug: http://werkzeug.pocoo.org/ @@ -147,8 +147,8 @@ expressions of different types. The following methods may be used by extensions: .. autoclass:: jinja2.parser.Parser - :members: parse_expression, parse_tuple, parse_statements, ignore_colon, - free_identifier + :members: parse_expression, parse_tuple, parse_statements, skip_colon, + skip_comma, free_identifier .. attribute:: filename diff --git a/jinja2/environment.py b/jinja2/environment.py index e771dd6d..2fbe217b 100644 --- a/jinja2/environment.py +++ b/jinja2/environment.py @@ -222,6 +222,15 @@ class Environment(object): _environment_sanity_check(self) + def extend(self, **attributes): + """Add the items to the instance of the environment if they do not exist + yet. This is used by :ref:`extensions ` to register + callbacks and configuration values without breaking inheritance. + """ + for key, value in attributes.iteritems(): + if not hasattr(self, key): + setattr(self, key, value) + def overlay(self, block_start_string=missing, block_end_string=missing, variable_start_string=missing, variable_end_string=missing, comment_start_string=missing, comment_end_string=missing, diff --git a/jinja2/ext.py b/jinja2/ext.py index 22adf828..f60b85a1 100644 --- a/jinja2/ext.py +++ b/jinja2/ext.py @@ -40,6 +40,17 @@ class Extension(object): may not store environment specific data on `self`. The reason for this is that an extension can be bound to another environment (for overlays) by creating a copy and reassigning the `environment` attribute. + + As extensions are created by the environment they cannot accept any + arguments for configuration. One may want to work around that by using + a factory function, but that is not possible as extensions are identified + by their import name. The correct way to configure the extension is + storing the configuration values on the environment. Because this way the + environment ends up acting as central configuration storage the + attributes may clash which is why extensions have to ensure that the names + they choose for configuration are not too generic. ``prefix`` for example + is a terrible name, ``fragment_cache_prefix`` on the other hand is a good + name as includes the name of the extension (fragment cache). """ __metaclass__ = ExtensionRegistry @@ -74,49 +85,40 @@ class Extension(object): return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno) -class CacheExtension(Extension): - """An example extension that adds cacheable blocks.""" - tags = set(['cache']) +class InternationalizationExtension(Extension): + """This extension adds gettext support to Jinja2.""" + tags = set(['trans']) def __init__(self, environment): Extension.__init__(self, environment) - environment.globals['__cache_ext_support'] = self.cache_support - - def cache_support(self, name, timeout, caller): - """Helper for the cache_fragment function.""" - if not hasattr(environment, 'cache_support'): - return caller() - args = [name] - if timeout is not None: - args.append(timeout) - return self.environment.cache_support(generate=caller, *args) + environment.globals['_'] = contextfunction(lambda c, x: c['gettext'](x)) + environment.extend( + install_gettext_translations=self._install, + install_null_translations=self._install_null, + uninstall_gettext_translations=self._uninstall, + extract_translations=self._extract + ) - def parse(self, parser): - lineno = parser.stream.next().lineno - args = [parser.parse_expression()] - if parser.stream.current.type is 'comma': - parser.stream.next() - args.append(parser.parse_expression()) - else: - args.append(nodes.Const(None, lineno=lineno)) - body = parser.parse_statements(('name:endcache',), drop_needle=True) - return nodes.CallBlock( - nodes.Call(nodes.Name('__cache_ext_support', 'load', lineno=lineno), - args, [], None, None), [], [], body, lineno=lineno + def _install(self, translations): + self.environment.globals.update( + gettext=translations.ugettext, + ngettext=translations.ungettext ) + def _install_null(self): + self.environment.globals.update( + gettext=lambda x: x, + ngettext=lambda s, p, n: (n != 1 and (p,) or (s,))[0] + ) -class InternationalizationExtension(Extension): - """This extension adds gettext support to Jinja.""" - tags = set(['trans']) + def _uninstall(self, translations): + for key in 'gettext', 'ngettext': + self.environment.globals.pop(key, None) - def __init__(self, environment): - Extension.__init__(self, environment) - environment.globals.update({ - '_': contextfunction(lambda c, x: c['gettext'](x)), - 'gettext': lambda x: x, - 'ngettext': lambda s, p, n: (s, p)[n != 1] - }) + def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS): + if isinstance(source, basestring): + source = self.environment.parse(source) + return extract_from_ast(source, gettext_functions) def parse(self, parser): """Parse a translatable tag.""" @@ -132,7 +134,7 @@ class InternationalizationExtension(Extension): parser.stream.expect('comma') # skip colon for python compatibility - if parser.ignore_colon(): + if parser.skip_colon(): break name = parser.stream.expect('name') diff --git a/jinja2/nodes.py b/jinja2/nodes.py index 0d921a7b..25196826 100644 --- a/jinja2/nodes.py +++ b/jinja2/nodes.py @@ -742,7 +742,8 @@ class ImportedName(Expr): class InternalName(Expr): """An internal name in the compiler. You cannot create these nodes - yourself but the parser provides a `free_identifier` method that creates + yourself but the parser provides a + :meth:`~jinja2.parser.Parser.free_identifier` method that creates a new identifier for you. This identifier is not available from the template and is not threated specially by the compiler. """ diff --git a/jinja2/parser.py b/jinja2/parser.py index 91a848b6..427cb058 100644 --- a/jinja2/parser.py +++ b/jinja2/parser.py @@ -42,13 +42,20 @@ class Parser(object): 'rparen') or \ self.stream.current.test('name:in') - def ignore_colon(self): + def skip_colon(self): """If there is a colon, skip it and return `True`, else `False`.""" if self.stream.current.type is 'colon': self.stream.next() return True return False + def skip_comma(self): + """If there is a comma, skip it and return `True`, else `False`.""" + if self.stream.current.type is 'comma': + self.stream.next() + return True + return False + def free_identifier(self, lineno=None): """Return a new free identifier as :class:`~jinja2.nodes.InternalName`.""" self._last_identifier += 1 @@ -100,7 +107,7 @@ class Parser(object): can be set to `True` and the end token is removed. """ # the first token may be a colon for python compatibility - self.ignore_colon() + self.skip_colon() # in the future it would be possible to add whole code sections # by adding some sort of end of statement token and parsing those here. -- 2.47.2