diff options
Diffstat (limited to 'coffin/template')
-rw-r--r-- | coffin/template/.___init__.py | bin | 187 -> 0 bytes | |||
-rw-r--r-- | coffin/template/._defaultfilters.py | bin | 185 -> 0 bytes | |||
-rw-r--r-- | coffin/template/._defaulttags.py | bin | 184 -> 0 bytes | |||
-rw-r--r-- | coffin/template/._library.py | bin | 187 -> 0 bytes | |||
-rw-r--r-- | coffin/template/._loader.py | bin | 187 -> 0 bytes | |||
-rw-r--r-- | coffin/template/._loaders.py | bin | 184 -> 0 bytes | |||
-rw-r--r-- | coffin/template/__init__.py | 93 | ||||
-rw-r--r-- | coffin/template/defaultfilters.py | 99 | ||||
-rw-r--r-- | coffin/template/defaulttags.py | 364 | ||||
-rw-r--r-- | coffin/template/library.py | 215 | ||||
-rw-r--r-- | coffin/template/loader.py | 66 | ||||
-rw-r--r-- | coffin/template/loaders.py | 38 |
12 files changed, 0 insertions, 875 deletions
diff --git a/coffin/template/.___init__.py b/coffin/template/.___init__.py Binary files differdeleted file mode 100644 index 87947898..00000000 --- a/coffin/template/.___init__.py +++ /dev/null diff --git a/coffin/template/._defaultfilters.py b/coffin/template/._defaultfilters.py Binary files differdeleted file mode 100644 index 8fd7d746..00000000 --- a/coffin/template/._defaultfilters.py +++ /dev/null diff --git a/coffin/template/._defaulttags.py b/coffin/template/._defaulttags.py Binary files differdeleted file mode 100644 index db9dcec7..00000000 --- a/coffin/template/._defaulttags.py +++ /dev/null diff --git a/coffin/template/._library.py b/coffin/template/._library.py Binary files differdeleted file mode 100644 index 18fe8260..00000000 --- a/coffin/template/._library.py +++ /dev/null diff --git a/coffin/template/._loader.py b/coffin/template/._loader.py Binary files differdeleted file mode 100644 index 3b699201..00000000 --- a/coffin/template/._loader.py +++ /dev/null diff --git a/coffin/template/._loaders.py b/coffin/template/._loaders.py Binary files differdeleted file mode 100644 index e17a06d5..00000000 --- a/coffin/template/._loaders.py +++ /dev/null diff --git a/coffin/template/__init__.py b/coffin/template/__init__.py deleted file mode 100644 index b487c8f5..00000000 --- a/coffin/template/__init__.py +++ /dev/null @@ -1,93 +0,0 @@ -from django.template import ( - Context as DjangoContext, - add_to_builtins as django_add_to_builtins, - get_library) -from jinja2 import Template as _Jinja2Template - -# Merge with ``django.template``. -from django.template import __all__ -from django.template import * - -# Override default library class with ours -from library import * - - -class Template(_Jinja2Template): - """Fixes the incompabilites between Jinja2's template class and - Django's. - - The end result should be a class that renders Jinja2 templates but - is compatible with the interface specfied by Django. - - This includes flattening a ``Context`` instance passed to render - and making sure that this class will automatically use the global - coffin environment. - """ - - def __new__(cls, template_string, origin=None, name=None): - # We accept the "origin" and "name" arguments, but discard them - # right away - Jinja's Template class (apparently) stores no - # equivalent information. - from coffin.common import env - - return env.from_string(template_string, template_class=cls) - - def __iter__(self): - # TODO: Django allows iterating over the templates nodes. Should - # be parse ourself and iterate over the AST? - raise NotImplementedError() - - def render(self, context=None): - """Differs from Django's own render() slightly in that makes the - ``context`` parameter optional. We try to strike a middle ground - here between implementing Django's interface while still supporting - Jinja's own call syntax as well. - """ - if context is None: - context = {} - else: - context = dict_from_django_context(context) - assert isinstance(context, dict) # Required for **-operator. - return super(Template, self).render(**context) - - -def dict_from_django_context(context): - """Flattens a Django :class:`django.template.context.Context` object. - """ - if not isinstance(context, DjangoContext): - return context - else: - dict_ = {} - # Newest dicts are up front, so update from oldest to newest. - for subcontext in reversed(list(context)): - dict_.update(dict_from_django_context(subcontext)) - return dict_ - - -# libraries to load by default for a new environment -builtins = [] - - -def add_to_builtins(module_name): - """Add the given module to both Coffin's list of default template - libraries as well as Django's. This makes sense, since Coffin - libs are compatible with Django libraries. - - You can still use Django's own ``add_to_builtins`` to register - directly with Django and bypass Coffin. - - TODO: Allow passing path to (or reference of) extensions and - filters directly. This would make it easier to use this function - with 3rd party Jinja extensions that do not know about Coffin and - thus will not provide a Library object. - - XXX/TODO: Why do we need our own custom list of builtins? Our - Library object is compatible, remember!? We can just add them - directly to Django's own list of builtins. - """ - builtins.append(get_library(module_name)) - django_add_to_builtins(module_name) - - -add_to_builtins('coffin.template.defaulttags') -add_to_builtins('coffin.template.defaultfilters')
\ No newline at end of file diff --git a/coffin/template/defaultfilters.py b/coffin/template/defaultfilters.py deleted file mode 100644 index c566a7d2..00000000 --- a/coffin/template/defaultfilters.py +++ /dev/null @@ -1,99 +0,0 @@ -"""Jinja2-ports of many of Django's default filters. - -TODO: Most of the filters in here need to be updated for autoescaping. -""" - -from coffin.template import Library -from jinja2.runtime import Undefined -# from jinja2 import Markup - -register = Library() - -@register.filter(jinja2_only=True) -def url(view_name, *args, **kwargs): - from coffin.template.defaulttags import url - return url._reverse(view_name, args, kwargs) - -@register.filter(jinja2_only=True) -def timesince(value, arg=None): - if value is None or isinstance(value, Undefined): - return u'' - from django.utils.timesince import timesince - if arg: - return timesince(value, arg) - return timesince(value) - -@register.filter(jinja2_only=True) -def timeuntil(value, arg=None): - if value is None or isinstance(value, Undefined): - return u'' - from django.utils.timesince import timeuntil - return timeuntil(date, arg) - -@register.filter(jinja2_only=True) -def date(value, arg=None): - if value is None or isinstance(value, Undefined): - return u'' - from django.conf import settings - from django.utils.dateformat import format - if arg is None: - arg = settings.DATE_FORMAT - return format(value, arg) - -@register.filter(jinja2_only=True) -def time(value, arg=None): - if value is None or isinstance(value, Undefined): - return u'' - from django.conf import settings - from django.utils.dateformat import time_format - if arg is None: - arg = settings.TIME_FORMAT - return time_format(value, arg) - -@register.filter(jinja2_only=True) -def truncatewords(value, length): - # Jinja2 has it's own ``truncate`` filter that supports word - # boundaries and more stuff, but cannot deal with HTML. - from django.utils.text import truncate_words - return truncate_words(value, int(length)) - -@register.filter(jinja2_only=True) -def truncatewords_html(value, length): - from django.utils.text import truncate_html_words - return truncate_html_words(value, int(length)) - -@register.filter(jinja2_only=True) -def pluralize(value, s1='s', s2=None): - """Like Django's pluralize-filter, but instead of using an optional - comma to separate singular and plural suffixes, it uses two distinct - parameters. - - It also is less forgiving if applied to values that do not allow - making a decision between singular and plural. - """ - if s2 is not None: - singular_suffix, plural_suffix = s1, s2 - else: - plural_suffix = s1 - singular_suffix = '' - - try: - if int(value) != 1: - return plural_suffix - except TypeError: # not a string or a number; maybe it's a list? - if len(value) != 1: - return plural_suffix - return singular_suffix - -@register.filter(jinja2_only=True) -def floatformat(value, arg=-1): - """Builds on top of Django's own version, but adds strict error - checking, staying with the philosophy. - """ - from django.template.defaultfilters import floatformat - from coffin.interop import django_filter_to_jinja2 - arg = int(arg) # raise exception - result = django_filter_to_jinja2(floatformat)(value, arg) - if result == '': # django couldn't handle the value - raise ValueError(value) - return result
\ No newline at end of file diff --git a/coffin/template/defaulttags.py b/coffin/template/defaulttags.py deleted file mode 100644 index b9994257..00000000 --- a/coffin/template/defaulttags.py +++ /dev/null @@ -1,364 +0,0 @@ -from jinja2 import nodes -from jinja2.ext import Extension -from jinja2.exceptions import TemplateSyntaxError -from django.conf import settings -from coffin.template import Library - - -class LoadExtension(Extension): - """The load-tag is a no-op in Coffin. Instead, all template libraries - are always loaded. - - Note: Supporting a functioning load-tag in Jinja is tough, though - theoretically possible. The trouble is activating new extensions while - parsing is ongoing. The ``Parser.extensions`` dict of the current - parser instance needs to be modified, but apparently the only way to - get access would be by hacking the stack. - """ - - tags = set(['load']) - - def parse(self, parser): - while not parser.stream.current.type == 'block_end': - parser.stream.next() - return [] - - -"""class AutoescapeExtension(Extension): - ""#" - Template to output works in three phases in Jinja2: parsing, - generation (compilation, AST-traversal), and rendering (execution). - - Unfortunatly, the environment ``autoescape`` option comes into effect - during traversal, the part where we happen to have basically no control - over as an extension. It determines whether output is wrapped in - ``escape()`` calls. - - Solutions that could possibly work: - - * This extension could preprocess it's childnodes and wrap - everything output related inside the appropriate - ``Markup()`` or escape() call. - - * We could use the ``preprocess`` hook to insert the - appropriate ``|safe`` and ``|escape`` filters on a - string-basis. This is very unlikely to work well. - - There's also the issue of inheritance and just generally the nesting - of autoescape-tags to consider. - - Other things of note: - - * We can access ``parser.environment``, but that would only - affect the **parsing** of our child nodes. - - * In the commented-out code below we are trying to affect the - autoescape setting during rendering. As noted, this could be - necessary for rare border cases where custom extension use - the autoescape attribute. - - Both the above things would break Environment thread-safety though! - - Overall, it's not looking to good for this extension. - ""#" - - tags = ['autoescape'] - - def parse(self, parser): - lineno = parser.stream.next().lineno - - old_autoescape = parser.environment.autoescape - parser.environment.autoescape = True - try: - body = parser.parse_statements( - ['name:endautoescape'], drop_needle=True) - finally: - parser.environment.autoescape = old_autoescape - - # Not sure yet if the code below is necessary - it changes - # environment.autoescape during template rendering. If for example - # a CallBlock function accesses ``environment.autoescape``, it - # presumably is. - # This also should use try-finally though, which Jinja's API - # doesn't support either. We could fake that as well by using - # InternalNames that output the necessary indentation and keywords, - # but at this point it starts to get really messy. - # - # TODO: Actually, there's ``nodes.EnvironmentAttribute``. - #ae_setting = object.__new__(nodes.InternalName) - #nodes.Node.__init__(ae_setting, 'environment.autoescape', lineno=lineno) - #temp = parser.free_identifier() - #body.insert(0, nodes.Assign(temp, ae_setting)) - #body.insert(1, nodes.Assign(ae_setting, nodes.Const(True))) - #body.insert(len(body), nodes.Assign(ae_setting, temp)) - return body -""" - - -class URLExtension(Extension): - """Returns an absolute URL matching given view with its parameters. - - This is a way to define links that aren't tied to a particular URL - configuration:: - - {% url path.to.some_view arg1,arg2,name1=value1 %} - - Known differences to Django's url-Tag: - - - In Django, the view name may contain any non-space character. - Since Jinja's lexer does not identify whitespace to us, only - characters that make up valid identifers, plus dots and hyphens - are allowed. Note that identifers in Jinja 2 may not contain - non-ascii characters. - - As an alternative, you may specifify the view as a string, - which bypasses all these restrictions. It further allows you - to apply filters: - - {% url "меткаda.some-view"|afilter %} - """ - - tags = set(['url']) - - def parse(self, parser): - stream = parser.stream - - tag = stream.next() - - # get view name - if stream.current.test('string'): - viewname = parser.parse_primary() - else: - # parse valid tokens and manually build a string from them - bits = [] - name_allowed = True - while True: - if stream.current.test_any('dot', 'sub'): - bits.append(stream.next()) - name_allowed = True - elif stream.current.test('name') and name_allowed: - bits.append(stream.next()) - name_allowed = False - else: - break - viewname = nodes.Const("".join([b.value for b in bits])) - if not bits: - raise TemplateSyntaxError("'%s' requires path to view" % - tag.value, tag.lineno) - - # get arguments - args = [] - kwargs = [] - while not stream.current.test_any('block_end', 'name:as'): - if args or kwargs: - stream.expect('comma') - if stream.current.test('name') and stream.look().test('assign'): - key = nodes.Const(stream.next().value) - stream.skip() - value = parser.parse_expression() - kwargs.append(nodes.Pair(key, value, lineno=key.lineno)) - else: - args.append(parser.parse_expression()) - - make_call_node = lambda *kw: \ - self.call_method('_reverse', - args=[viewname, nodes.List(args), nodes.Dict(kwargs)], - kwargs=kw) - - # if an as-clause is specified, write the result to context... - if stream.next_if('name:as'): - var = nodes.Name(stream.expect('name').value, 'store') - call_node = make_call_node(nodes.Keyword('fail', nodes.Const(False))) - return nodes.Assign(var, call_node) - # ...otherwise print it out. - else: - return nodes.Output([make_call_node()]).set_lineno(tag.lineno) - - @classmethod - def _reverse(self, viewname, args, kwargs, fail=True): - from django.core.urlresolvers import reverse, NoReverseMatch - - # Try to look up the URL twice: once given the view name, - # and again relative to what we guess is the "main" app. - url = '' - try: - url = reverse(viewname, args=args, kwargs=kwargs) - except NoReverseMatch: - projectname = settings.SETTINGS_MODULE.split('.')[0] - try: - url = reverse(projectname + '.' + viewname, - args=args, kwargs=kwargs) - except NoReverseMatch: - if fail: - raise - else: - return '' - - return url - - -class WithExtension(Extension): - """Adds a value to the context (inside this block) for caching and - easy access, just like the Django-version does. - - For example:: - - {% with person.some_sql_method as total %} - {{ total }} object{{ total|pluralize }} - {% endwith %} - - TODO: The new Scope node introduced in Jinja2 6334c1eade73 (the 2.2 - dev version) would help here, but we don't want to rely on that yet. - See also: - http://dev.pocoo.org/projects/jinja/browser/tests/test_ext.py - http://dev.pocoo.org/projects/jinja/ticket/331 - http://dev.pocoo.org/projects/jinja/ticket/329 - """ - - tags = set(['with']) - - def parse(self, parser): - lineno = parser.stream.next().lineno - - value = parser.parse_expression() - parser.stream.expect('name:as') - name = parser.stream.expect('name') - - body = parser.parse_statements(['name:endwith'], drop_needle=True) - return nodes.CallBlock( - self.call_method('_render_block', args=[value]), - [nodes.Name(name.value, 'store')], [], body).\ - set_lineno(lineno) - - def _render_block(self, value, caller=None): - return caller(value) - - -class CacheExtension(Extension): - """Exactly like Django's own tag, but supports full Jinja2 - expressiveness for all arguments. - - {% cache gettimeout()*2 "foo"+options.cachename %} - ... - {% endcache %} - - This actually means that there is a considerable incompatibility - to Django: In Django, the second argument is simply a name, but - interpreted as a literal string. This tag, with Jinja2 stronger - emphasis on consistent syntax, requires you to actually specify the - quotes around the name to make it a string. Otherwise, allowing - Jinja2 expressions would be very hard to impossible (one could use - a lookahead to see if the name is followed by an operator, and - evaluate it as an expression if so, or read it as a string if not. - TODO: This may not be the right choice. Supporting expressions - here is probably not very important, so compatibility should maybe - prevail. Unfortunately, it is actually pretty hard to be compatibly - in all cases, simply because Django's per-character parser will - just eat everything until the next whitespace and consider it part - of the fragment name, while we have to work token-based: ``x*2`` - would actually be considered ``"x*2"`` in Django, while Jinja2 - would give us three tokens: ``x``, ``*``, ``2``. - - General Syntax: - - {% cache [expire_time] [fragment_name] [var1] [var2] .. %} - .. some expensive processing .. - {% endcache %} - - Available by default (does not need to be loaded). - - Partly based on the ``FragmentCacheExtension`` from the Jinja2 docs. - - TODO: Should there be scoping issues with the internal dummy macro - limited access to certain outer variables in some cases, there is a - different way to write this. Generated code would look like this: - - internal_name = environment.extensions['..']._get_cache_value(): - if internal_name is not None: - yield internal_name - else: - internal_name = "" # or maybe use [] and append() for performance - internalname += "..." - internalname += "..." - internalname += "..." - environment.extensions['..']._set_cache_value(internalname): - yield internalname - - In other words, instead of using a CallBlock which uses a local - function and calls into python, we have to separate calls into - python, but put the if-else logic itself into the compiled template. - """ - - tags = set(['cache']) - - def parse(self, parser): - lineno = parser.stream.next().lineno - - expire_time = parser.parse_expression() - fragment_name = parser.parse_expression() - vary_on = [] - while not parser.stream.current.test('block_end'): - vary_on.append(parser.parse_expression()) - - body = parser.parse_statements(['name:endcache'], drop_needle=True) - - return nodes.CallBlock( - self.call_method('_cache_support', - [expire_time, fragment_name, - nodes.List(vary_on), nodes.Const(lineno)]), - [], [], body).set_lineno(lineno) - - def _cache_support(self, expire_time, fragm_name, vary_on, lineno, caller): - from django.core.cache import cache # delay depending in settings - from django.utils.http import urlquote - - try: - expire_time = int(expire_time) - except (ValueError, TypeError): - raise TemplateSyntaxError('"%s" tag got a non-integer ' - 'timeout value: %r' % (list(self.tags)[0], expire_time), lineno) - - cache_key = u':'.join([fragm_name] + [urlquote(v) for v in vary_on]) - value = cache.get(cache_key) - if value is None: - value = caller() - cache.set(cache_key, value, expire_time) - return value - - -class SpacelessExtension(Extension): - """Removes whitespace between HTML tags, including tab and - newline characters. - - Works exactly like Django's own tag. - """ - - tags = ['spaceless'] - - def parse(self, parser): - lineno = parser.stream.next().lineno - body = parser.parse_statements(['name:endspaceless'], drop_needle=True) - return nodes.CallBlock( - self.call_method('_strip_spaces', [], [], None, None), - [], [], body - ).set_lineno(lineno) - - def _strip_spaces(self, caller=None): - from django.utils.html import strip_spaces_between_tags - return strip_spaces_between_tags(caller().strip()) - - -# nicer import names -load = LoadExtension -url = URLExtension -with_ = WithExtension -cache = CacheExtension -spaceless = SpacelessExtension - - -register = Library() -register.tag(load) -register.tag(url) -register.tag(with_) -register.tag(cache) -register.tag(spaceless)
\ No newline at end of file diff --git a/coffin/template/library.py b/coffin/template/library.py deleted file mode 100644 index 8e80edc5..00000000 --- a/coffin/template/library.py +++ /dev/null @@ -1,215 +0,0 @@ -from django.template import Library as DjangoLibrary, InvalidTemplateLibrary -from jinja2.ext import Extension as Jinja2Extension -from coffin.interop import ( - DJANGO, JINJA2, - guess_filter_type, jinja2_filter_to_django, django_filter_to_jinja2) - - -__all__ = ['Library'] - - -class Library(DjangoLibrary): - """Version of the Django ``Library`` class that can handle both - Django template engine tags and filters, as well as Jinja2 - extensions and filters. - - Tries to present a common registration interface to the extension - author, but provides both template engines with only those - components they can support. - - Since custom Django tags and Jinja2 extensions are two completely - different beasts, they are handled completely separately. You can - register custom Django tags as usual, for example: - - register.tag('current_time', do_current_time) - - Or register a Jinja2 extension like this: - - register.tag(CurrentTimeNode) - - Filters, on the other hand, work similarily in both engines, and - for the most one can't tell whether a filter function was written - for Django or Jinja2. A compatibility layer is used to make to - make the filters you register usuable with both engines: - - register.filter('cut', cut) - - However, some of the more powerful filters just won't work in - Django, for example if more than one argument is required, or if - context- or environmentfilters are used. If ``cut`` in the above - example where such an extended filter, it would only be registered - with Jinja. - - See also the module documentation for ``coffin.interop`` for - information on some of the limitations of this conversion. - - TODO: Jinja versions of the ``simple_tag`` and ``inclusion_tag`` - helpers would be nice, though since custom tags are not needed as - often in Jinja, this is not urgent. - """ - - def __init__(self): - super(Library, self).__init__() - self.jinja2_filters = {} - self.jinja2_extensions = [] - self.jinja2_globals = {} - self.jinja2_tests = {} - - @classmethod - def from_django(cls, django_library): - """Create a Coffin library object from a Django library. - - Specifically, this ensures that filters already registered - with the Django library are also made available to Jinja, - where applicable. - """ - from copy import copy - result = cls() - result.filters = copy(django_library.filters) - result.tags = copy(django_library.tags) - for name, func in result.filters.iteritems(): - result._register_filter(name, func, jinja2_only=True) - return result - - def test(self, name=None, func=None): - def inner(f): - name = getattr(f, "_decorated_function", f).__name__ - self.jinja2_tests[name] = f - return f - if name == None and func == None: - # @register.test() - return inner - elif func == None: - if (callable(name)): - # register.test() - return inner(name) - else: - # @register.test('somename') or @register.test(name='somename') - def dec(func): - return self.test(name, func) - return dec - elif name != None and func != None: - # register.filter('somename', somefunc) - self.jinja2_tests[name] = func - return func - else: - raise InvalidTemplateLibrary("Unsupported arguments to " - "Library.test: (%r, %r)", (name, func)) - - def object(self, name=None, func=None): - def inner(f): - name = getattr(f, "_decorated_function", f).__name__ - self.jinja2_globals[name] = f - return f - if name == None and func == None: - # @register.object() - return inner - elif func == None: - if (callable(name)): - # register.object() - return inner(name) - else: - # @register.object('somename') or @register.object(name='somename') - def dec(func): - return self.object(name, func) - return dec - elif name != None and func != None: - # register.object('somename', somefunc) - self.jinja2_globals[name] = func - return func - else: - raise InvalidTemplateLibrary("Unsupported arguments to " - "Library.object: (%r, %r)", (name, func)) - - def tag(self, name_or_node=None, compile_function=None): - """Register a Django template tag (1) or Jinja 2 extension (2). - - For (1), supports the same invocation syntax as the original - Django version, including use as a decorator. - - For (2), since Jinja 2 extensions are classes (which can't be - decorated), and have the tag name effectively built in, only the - following syntax is supported: - - register.tag(MyJinjaExtensionNode) - """ - if isinstance(name_or_node, Jinja2Extension): - if compile_function: - raise InvalidTemplateLibrary('"compile_function" argument not supported for Jinja2 extensions') - self.jinja2_extensions.append(name_or_node) - return name_or_node - else: - return super(Library, self).tag(name_or_node, compile_function) - - def tag_function(self, func_or_node): - if issubclass(func_or_node, Jinja2Extension): - self.jinja2_extensions.append(func_or_node) - return func_or_node - else: - return super(Library, self).tag_function(func_or_node) - - def filter(self, name=None, filter_func=None, jinja2_only=False): - """Register a filter with both the Django and Jinja2 template - engines, if possible - or only Jinja2, if ``jinja2_only`` is - specified. ``jinja2_only`` does not affect conversion of the - filter if neccessary. - - Implements a compatibility layer to handle the different - auto-escaping approaches transparently. Extended Jinja2 filter - features like environment- and contextfilters are however not - supported in Django. Such filters will only be registered with - Jinja. - - Supports the same invocation syntax as the original Django - version, including use as a decorator. - - If the function is supposed to return the registered filter - (by example of the superclass implementation), but has - registered multiple filters, a tuple of all filters is - returned. - """ - def filter_function(f): - return self._register_filter( - getattr(f, "_decorated_function", f).__name__, - f, jinja2_only=jinja2_only) - if name == None and filter_func == None: - # @register.filter() - return filter_function - elif filter_func == None: - if (callable(name)): - # @register.filter - return filter_function(name) - else: - # @register.filter('somename') or @register.filter(name='somename') - def dec(func): - return self.filter(name, func, jinja2_only=jinja2_only) - return dec - elif name != None and filter_func != None: - # register.filter('somename', somefunc) - return self._register_filter(name, filter_func, - jinja2_only=jinja2_only) - else: - raise InvalidTemplateLibrary("Unsupported arguments to " - "Library.filter: (%r, %r)", (name, filter_func)) - - def _register_filter(self, name, func, jinja2_only=None): - filter_type, can_be_ported = guess_filter_type(func) - if filter_type == JINJA2 and not can_be_ported: - self.jinja2_filters[name] = func - return func - elif filter_type == DJANGO and not can_be_ported: - if jinja2_only: - raise ValueError('This filter cannot be ported to Jinja2.') - self.filters[name] = func - return func - elif jinja2_only: - func = django_filter_to_jinja2(func) - self.jinja2_filters[name] = func - return func - else: - # register the filter with both engines - django_func = jinja2_filter_to_django(func) - jinja2_func = django_filter_to_jinja2(func) - self.filters[name] = django_func - self.jinja2_filters[name] = jinja2_func - return (django_func, jinja2_func) diff --git a/coffin/template/loader.py b/coffin/template/loader.py deleted file mode 100644 index 1f2bbb1f..00000000 --- a/coffin/template/loader.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Replacement for ``django.template.loader`` that uses Jinja 2.
-
-The module provides a generic way to load templates from an arbitrary
-backend storage (e.g. filesystem, database).
-"""
-
-from coffin.template import Template as CoffinTemplate
-from jinja2 import TemplateNotFound
-
-
-def find_template_source(name, dirs=None):
- # This is Django's most basic loading function through which
- # all template retrievals go. Not sure if Jinja 2 publishes
- # an equivalent, but no matter, it mostly for internal use
- # anyway - developers will want to start with
- # ``get_template()`` or ``get_template_from_string`` anyway.
- raise NotImplementedError()
-
-
-def get_template(template_name):
- # Jinja will handle this for us, and env also initializes
- # the loader backends the first time it is called.
- from coffin.common import env
- return env.get_template(template_name)
-
-
-def get_template_from_string(source):
- """
- Does not support then ``name`` and ``origin`` parameters from
- the Django version.
- """
- from coffin.common import env
- return env.from_string(source)
-
-
-def render_to_string(template_name, dictionary=None, context_instance=None):
- """Loads the given ``template_name`` and renders it with the given
- dictionary as context. The ``template_name`` may be a string to load
- a single template using ``get_template``, or it may be a tuple to use
- ``select_template`` to find one of the templates in the list.
-
- ``dictionary`` may also be Django ``Context`` object.
-
- Returns a string.
- """
- dictionary = dictionary or {}
- if isinstance(template_name, (list, tuple)):
- template = select_template(template_name)
- else:
- template = get_template(template_name)
- if context_instance:
- context_instance.update(dictionary)
- else:
- context_instance = dictionary
- return template.render(context_instance)
-
-
-def select_template(template_name_list):
- "Given a list of template names, returns the first that can be loaded."
- for template_name in template_name_list:
- try:
- return get_template(template_name)
- except TemplateNotFound:
- continue
- # If we get here, none of the templates could be loaded
- raise TemplateNotFound(', '.join(template_name_list))
diff --git a/coffin/template/loaders.py b/coffin/template/loaders.py deleted file mode 100644 index cb42fd5d..00000000 --- a/coffin/template/loaders.py +++ /dev/null @@ -1,38 +0,0 @@ -from jinja2 import loaders - - -def jinja_loader_from_django_loader(django_loader): - """Attempts to make a conversion from the given Django loader to an - similarly-behaving Jinja loader. - - :param django_loader: Django loader module string. - :return: The similarly-behaving Jinja loader, or None if a similar loader - could not be found. - """ - for substr, func in _JINJA_LOADER_BY_DJANGO_SUBSTR.iteritems(): - if substr in django_loader: - return func() - return None - - -def _make_jinja_app_loader(): - """Makes an 'app loader' for Jinja which acts like - :mod:`django.template.loaders.app_directories`. - """ - from django.template.loaders.app_directories import app_template_dirs - return loaders.FileSystemLoader(app_template_dirs) - - -def _make_jinja_filesystem_loader(): - """Makes a 'filesystem loader' for Jinja which acts like - :mod:`django.template.loaders.filesystem`. - """ - from django.conf import settings - return loaders.FileSystemLoader(settings.TEMPLATE_DIRS) - - -# Determine loaders from Django's conf. -_JINJA_LOADER_BY_DJANGO_SUBSTR = { # {substr: callable, ...} - 'app_directories': _make_jinja_app_loader, - 'filesystem': _make_jinja_filesystem_loader, -} |