﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
21882	Early modification bug in Django 1.6. with mark_safe + ugettext_lazy	Neal Todd	Baptiste Mispelon	"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?).

I reported this on django-users first to see if people thought it is a bug but had no responses.

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>:`

It seems as though the SafeString is being modified at some point and becoming unsafe again (that may mean it's not restricted to label_tag). 

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"	Bug	closed	Internationalization	1.6	Release blocker	fixed	mark_safe ugettext_lazy		Accepted	1	0	0	0	0	0
