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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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():
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user