Skip to content

Commit

Permalink
When registering filters, allow the caller to control how the compati…
Browse files Browse the repository at this point in the history
…bility layer is applied. This fixes the test which the previous commit broke.
  • Loading branch information
miracle2k committed Aug 2, 2010
1 parent 279536b commit 32044fc
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 29 deletions.
18 changes: 9 additions & 9 deletions coffin/template/defaultfilters.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,29 @@

register = Library()

@register.filter(jinja2_only=True)
@register.jinja2_filter(jinja2_only=True)
def url(view_name, *args, **kwargs):
"""This is an alternative to the {% url %} tag. It comes from a time
before Coffin had a port of the tag.
"""
from coffin.template.defaulttags import url
return url._reverse(view_name, args, kwargs)

@register.filter(jinja2_only=True)
@register.jinja2_filter(jinja2_only=True)
def timesince(value, *arg):
if value is None or isinstance(value, Undefined):
return u''
from django.utils.timesince import timesince
return timesince(value, *arg)

@register.filter(jinja2_only=True)
@register.jinja2_filter(jinja2_only=True)
def timeuntil(value, *args):
if value is None or isinstance(value, Undefined):
return u''
from django.utils.timesince import timeuntil
return timeuntil(value, *args)

@register.filter(jinja2_only=True)
@register.jinja2_filter(jinja2_only=True)
def date(value, arg=None):
if value is None or isinstance(value, Undefined):
return u''
Expand All @@ -45,7 +45,7 @@ def date(value, arg=None):
arg = settings.DATE_FORMAT
return format(value, arg)

@register.filter(jinja2_only=True)
@register.jinja2_filter(jinja2_only=True)
def time(value, arg=None):
if value is None or isinstance(value, Undefined):
return u''
Expand All @@ -55,19 +55,19 @@ def time(value, arg=None):
arg = settings.TIME_FORMAT
return time_format(value, arg)

@register.filter(jinja2_only=True)
@register.jinja2_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)
@register.jinja2_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)
@register.jinja2_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
Expand All @@ -90,7 +90,7 @@ def pluralize(value, s1='s', s2=None):
return plural_suffix
return singular_suffix

@register.filter(jinja2_only=True)
@register.jinja2_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.
Expand Down
68 changes: 48 additions & 20 deletions coffin/template/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,9 @@ def from_django(cls, django_library):
"""
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)
for name, func in django_library.filters.iteritems():
result._register_filter(name, func, type='django')
return result

def test(self, name=None, func=None):
Expand Down Expand Up @@ -155,7 +154,7 @@ def tag_function(self, func_or_node):
else:
return super(Library, self).tag_function(func_or_node)

def filter(self, name=None, filter_func=None, jinja2_only=False):
def filter(self, name=None, filter_func=None, type=None, jinja2_only=None):
"""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
Expand All @@ -167,6 +166,12 @@ def filter(self, name=None, filter_func=None, jinja2_only=False):
supported in Django. Such filters will only be registered with
Jinja.
If you know which template language the filter was written for,
you may want to specify type="django" or type="jinja2", to disable
the interop layer which in some cases might not be able to operate
entirely opaque. For example, Jinja 2 filters may not receive a
"Undefined" value if the interop layer is applied.
Supports the same invocation syntax as the original Django
version, including use as a decorator.
Expand All @@ -178,7 +183,7 @@ def filter(self, name=None, filter_func=None, jinja2_only=False):
def filter_function(f):
return self._register_filter(
getattr(f, "_decorated_function", f).__name__,
f, jinja2_only=jinja2_only)
f, type=type, jinja2_only=jinja2_only)
if name == None and filter_func == None:
# @register.filter()
return filter_function
Expand All @@ -189,34 +194,57 @@ def filter_function(f):
else:
# @register.filter('somename') or @register.filter(name='somename')
def dec(func):
return self.filter(name, func, jinja2_only=jinja2_only)
return self.filter(name, func, type=type,
jinja2_only=jinja2_only)
return dec
elif name != None and filter_func != None:
# register.filter('somename', somefunc)
return self._register_filter(name, filter_func,
return self._register_filter(name, filter_func, type=type,
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):
def jinja2_filter(self, *args, **kwargs):
"""Shortcut for filter(type='jinja2').
"""
kw = {'type': JINJA2}
kw.update(kwargs)
return self.filter(*args, **kw)

def _register_filter(self, name, func, type=None, jinja2_only=None):
assert type in (None, JINJA2, DJANGO,)

# The user might not specify the language the filter was written
# for, but sometimes we can auto detect it.
filter_type, can_be_ported = guess_filter_type(func)
if filter_type == JINJA2 and not can_be_ported:
assert not (filter_type and type) or filter_type == type, \
"guessed filter type (%s) not matching claimed type (%s)" % (
filter_type, type,
)
if not filter_type and type:
filter_type = type

if filter_type == JINJA2:
self.jinja2_filters[name] = func
if can_be_ported and not jinja2_only:
self.filters[name] = jinja2_filter_to_django(func)
return func
elif filter_type == DJANGO and not can_be_ported:
if jinja2_only:
raise ValueError('This filter cannot be ported to Jinja2.')
elif filter_type == DJANGO:
self.filters[name] = func
return func
elif jinja2_only:
func = django_filter_to_jinja2(func)
self.jinja2_filters[name] = func
if not can_be_ported and jinja2_only:
raise ValueError('This filter cannot be ported to Jinja2.')
if can_be_ported:
self.jinja2_filters[name] = django_filter_to_jinja2(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)
if jinja2_only:
self.jinja2_filters[name] = jinja2_func
return jinja2_func
else:
# register the filter with both engines
self.filters[name] = django_func
self.jinja2_filters[name] = jinja2_func
return (django_func, jinja2_func)

0 comments on commit 32044fc

Please sign in to comment.