label_tag bug in Django 1.6. with mark_safe + ugettext_lazy ?

65 views
Skip to first unread message

ne...@torchbox.com

unread,
Jan 24, 2014, 11:59:13 AM1/24/14
to django...@googlegroups.com
Hi,

I'm in the process of upgrading a Django application from 1.5 to 1.6 and I've come across a mark_safe + ugettext_lazy issue in form field labels that I think might be a bug introduced in 1.6 (possibly related to the introduction of the new Form.label_suffix?).

Before reporting it I thought I check here first to see if people think it is a bug.

In essence, given a label that is a translatable string containing HTML and wrapped in mark_safe, e.g. mark_safe(_("<em>Foo</em>"), calling label_tag on the field in a template:

in Django 1.5 results in a non-escaped string: <em>Foo</em>
in Django 1.6 results in an escaped string: &lt;em&gt;Foo&lt;/em&gt;:

(including the default label suffix of ":" for 1.6).

I was expecting 1.6 to render: <em>Foo</em>:

Here's a shell example for 1.5 and 1.6 that distills what I'm getting:

>>> import django
>>> django.get_version()
'1.5.5'
>>> from django import forms
>>> from django.template import Template, Context
>>> from django.utils.safestring import mark_safe
>>> from django.utils.translation import ugettext_lazy as _
>>> class FooForm(forms.Form):
...     foo = forms.IntegerField(label=mark_safe(_("<em>Foo</em>")))
... 
>>> fooForm = FooForm()
>>> fooForm.fields['foo'].label
u'<em>Foo</em>'
>>> Template("{{ f }}").render(Context({'f': fooForm}))
u'<tr><th><label for="id_foo"><em>Foo</em>:</label></th><td><input id="id_foo" name="foo" type="text" /></td></tr>'
>>> Template("{{ f.foo.label }}").render(Context({'f': fooForm}))
u'<em>Foo</em>'
>>> Template("{{ f.foo.label_tag }}").render(Context({'f': fooForm}))
u'<label for="id_foo"><em>Foo</em></label>'


>>> import django
>>> django.get_version()
'1.6.1'
>>> from django import forms
>>> from django.template import Template, Context
>>> from django.utils.safestring import mark_safe
>>> from django.utils.translation import ugettext_lazy as _
>>> class FooForm(forms.Form):
...     foo = forms.IntegerField(label=mark_safe(_("<em>Foo</em>")))
... 
>>> fooForm = FooForm()
>>> fooForm.fields['foo'].label
<django.utils.functional.__proxy__ object at 0xabba38c>
>>> Template("{{ f }}").render(Context({'f': fooForm}))
u'<tr><th><label for="id_foo"><em>Foo</em>:</label></th><td><input id="id_foo" name="foo" type="number" /></td></tr>'
>>> Template("{{ f.foo.label }}").render(Context({'f': fooForm}))
u'<em>Foo</em>'
>>> Template("{{ f.foo.label_tag }}").render(Context({'f': fooForm}))
u'<label for="id_foo">&lt;em&gt;Foo&lt;/em&gt;:</label>'


It may or may not be related but when I tried delaying the translation as described in https://docs.djangoproject.com/en/dev/topics/i18n/translation/#other-uses-of-lazy-in-delayed-translations I got a TypeError under 1.6 when passing the lazy object to ugettext:

>>> import django
>>> django.get_version()
'1.5.5'
>>> from django.utils import six  # Python 3 compatibility
>>> from django.utils.functional import lazy
>>> from django.utils.safestring import mark_safe
>>> from django.utils.translation import ugettext_lazy as _
>>> mark_safe_lazy = lazy(mark_safe, six.text_type)
>>> lazy_string = mark_safe_lazy(_("<p>My <strong>string!</strong></p>"))
>>> lazy_string
<django.utils.functional.__proxy__ object at 0x9a0052c>
>>> from django.utils.translation import ugettext
>>> ugettext(lazy_string)
u'<p>My <strong>string!</strong></p>'


>>> import django
>>> django.get_version()
'1.6.1'
>>> from django.utils import six  # Python 3 compatibility
>>> from django.utils.functional import lazy
>>> from django.utils.safestring import mark_safe
>>> from django.utils.translation import ugettext_lazy as _
>>> mark_safe_lazy = lazy(mark_safe, six.text_type)
>>> lazy_string = mark_safe_lazy(_("<p>My <strong>string!</strong></p>"))
>>> lazy_string
<django.utils.functional.__proxy__ object at 0xb00b24c>
>>> from django.utils.translation import ugettext
>>> ugettext(lazy_string)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File ".../lib/python2.7/site-packages/django/utils/translation/__init__.py", line 76, in ugettext
    return _trans.ugettext(message)
  File ".../lib/python2.7/site-packages/django/utils/translation/trans_real.py", line 281, in ugettext
    return do_translate(message, 'ugettext')
  File ".../lib/python2.7/site-packages/django/utils/translation/trans_real.py", line 256, in do_translate
    eol_message = message.replace(str('\r\n'), str('\n')).replace(str('\r'), str('\n'))
  File ".../lib/python2.7/site-packages/django/utils/functional.py", line 129, in __wrapper__
    raise TypeError("Lazy object returned unexpected type.")
TypeError: Lazy object returned unexpected type.


Any ideas as to whether it may be a bug, or whether I'm just doing it wrong and 1.6 has exposed that?

Cheers, Neal
Reply all
Reply to author
Forward
0 new messages