Interop can now preprocess Jinja 2 "Undefined" values to make them usable with filters written for Django.

This breaks a test for our Jinja2-specific date filter. The core problem is that we don't have a way to register a filter while saying "this was written for Jinja" or "this was written for Django". Thus the interop layer is always applied, and no filter registered via Coffin can every get to see a "Undefined". We need to make some slightly for fundamental changes to fix this.
This commit is contained in:
Michael Elsdörfer
2010-08-02 19:11:57 +02:00
parent 3663541e3f
commit 279536b588
4 changed files with 22 additions and 5 deletions

View File

@@ -19,7 +19,7 @@ General notes:
import inspect
from django.utils.safestring import SafeUnicode, SafeData, EscapeData
from jinja2 import Markup, environmentfilter
from jinja2 import Markup, environmentfilter, Undefined
__all__ = (
@@ -43,15 +43,23 @@ def django_filter_to_jinja2(filter_func):
TODO: Django's "func.is_safe" is not yet handled
"""
def _convert(v):
def _convert_out(v):
if isinstance(v, SafeData):
return Markup(v)
if isinstance(v, EscapeData):
return Markup.escape(v) # not 100% equivalent, see mod docs
return v
def conversion_wrapper(*args, **kwargs):
result = filter_func(*args, **kwargs)
return _convert(result)
def _convert_in(v):
if isinstance(v, Undefined):
# Essentially the TEMPLATE_STRING_IF_INVALID default
# setting. If a non-default is set, Django wouldn't apply
# filters. This is something that we neither can nor want to
# simulate in Jinja.
return ''
return v
def conversion_wrapper(value, *args, **kwargs):
result = filter_func(_convert_in(value), *args, **kwargs)
return _convert_out(result)
# Jinja2 supports a similar machanism to Django's
# ``needs_autoescape`` filters: environment filters. We can
# thus support Django filters that use it in Jinja2 with just

View File

@@ -21,6 +21,9 @@ def unsafe_output(value):
return unicode(value)
def django_raw_output(value):
return value
def django_escape_output(value):
# Make sure the value is converted to unicode first, because otherwise,
# if it is already SafeData (for example, when coming from the template
@@ -34,5 +37,6 @@ register = Library()
register.filter('needing_autoescape', needing_autoescape)
register.filter('jinja_safe_output', jinja_safe_output)
register.filter('django_safe_output', django_safe_output)
register.filter('django_raw_output', django_raw_output)
register.filter('unsafe_output', unsafe_output)
register.filter('django_escape_output', django_escape_output)

View File

@@ -17,6 +17,7 @@ def test_django_builtins_available():
from coffin.template import defaultfilters
assert not hasattr(defaultfilters, 'get_digit') # has no port
assert r('{{ "23475"|get_digit("2") }}') == '7'
assert r('{{ unknown|get_digit("2") }}') == ''
def test_url():

View File

@@ -15,6 +15,7 @@ from django.template import Template, Context, \
# registering them manually with the environment, rather than having to
# place them in fake Django apps in completely different files to have
# them loaded.
# The tests for the compatibility layer could also be factored out.
def test_nodes_and_extensions():
@@ -120,4 +121,7 @@ def test_filter_compat_other():
# [bug] @needs_autoescape also (still) works correctly in Django
assert Template('{% load compat_filters %}{{ "b"|needing_autoescape }}').render(Context()) == 'True'
# The Django filters can handle "Undefined" values
assert env.from_string('{{ doesnotexist|django_raw_output }}').render() == ''
# TODO: test @stringfilter