[Django] #32272: gettext_lazy inconsistent error when nested

23 views
Skip to first unread message

Django

unread,
Dec 15, 2020, 12:42:18 PM12/15/20
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
--------------------------------------+------------------------
Reporter: John Bazik | Owner: nobody
Type: Bug | Status: new
Component: Utilities | Version: 3.1
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
--------------------------------------+------------------------
When gettext_lazy is called with a lazy object, it returns a nested lazy
object which has inconsistent behavior, depending on whether USE_I18N is
set or not.


{{{
>>> from django import __version__
>>> print(__version__)
3.1
>>> from django.utils.functional import lazy
>>> from django.utils.translation.trans_real import gettext as
gettext_real
>>> from django.utils.translation.trans_null import gettext as
gettext_noop
>>> gettext_lazy_real = lazy(gettext_real, str)
>>> gettext_lazy_noop = lazy(gettext_noop, str)
>>> r1 = gettext_lazy_real('Real')
>>> r2 = gettext_lazy_real(r1)
>>> n1 = gettext_lazy_noop('Noop')
>>> n2 = gettext_lazy_noop(n1)
>>> print(str(r1))
Real
>>> print(str(r2))
Real
>>> print(str(n1))
Noop
>>> print(str(n2))
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: __str__ returned non-string (type __proxy__)
}}}

I discovered this problem while working with version 2.2.

I've run across this twice now. The first time, I created a pull request
for another project to avoid the nesting. However, now that I've seen it
again, I think that because it works in the case of USE_I18N=True, it's
easy for developers to miss the problem, especially so since testing
USE_I18N has some quirks. Here's my pull request:

https://github.com/django-cms/django-cms/pull/6896

I think the best fix would be to disallow nesting by simply returning
already-nested objects, but I'm not sure of all the subtleties in that
code.

--
Ticket URL: <https://code.djangoproject.com/ticket/32272>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Dec 17, 2020, 2:11:47 AM12/17/20
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
----------------------------+--------------------------------------

Reporter: John Bazik | Owner: nobody
Type: Bug | Status: new
Component: Utilities | Version: 3.1
Severity: Normal | Resolution:
Keywords: claudep | Triage Stage: Unreviewed

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
----------------------------+--------------------------------------
Changes (by Carlton Gibson):

* keywords: => claudep


--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:1>

Django

unread,
Dec 17, 2020, 2:26:46 AM12/17/20
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
----------------------------+--------------------------------------

Reporter: John Bazik | Owner: nobody
Type: Bug | Status: new
Component: Utilities | Version: 3.1
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
----------------------------+--------------------------------------
Changes (by Mariusz Felisiak):

* cc: Claude Paroz (added)
* keywords: claudep =>


--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:2>

Django

unread,
Dec 22, 2020, 2:47:13 AM12/22/20
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
--------------------------------------+------------------------------------

Reporter: John Bazik | Owner: nobody
Type: Bug | Status: new
Component: Internationalization | Version: 3.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------------+------------------------------------
Changes (by Carlton Gibson):

* component: Utilities => Internationalization
* stage: Unreviewed => Accepted


Comment:

I'll accept this, since there is a difference in behaviour.

Given the code in `trans_null.py`, I'm not quite sure how the issue
arrises:

{{{
def gettext(message):
return message


gettext_noop = gettext_lazy = _ = gettext
}}}

Here `gettext_lazy` (and `_`) don't actually use `lazy`, so I'm not 100%
sure how the equivalent line from the report comes up:

{{{
gettext_lazy_noop = lazy(gettext_noop, str)
}}}

However, you've hit it in the wild, so I must presume it does 🤔

I wonder if forcing a string from `gettext()` in the the `trans_null` case
makes sense?


{{{
diff --git a/django/utils/translation/trans_null.py
b/django/utils/translation/trans_null.py
index a687572b69..f590ff23cd 100644
--- a/django/utils/translation/trans_null.py
+++ b/django/utils/translation/trans_null.py
@@ -6,7 +6,7 @@ from django.conf import settings


def gettext(message):
- return message
+ return str(message)


gettext_noop = gettext_lazy = _ = gettext
}}}

Resolves the reported issue but I don't know if it would have other
consequences.

--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:3>

Django

unread,
Dec 24, 2020, 1:24:50 AM12/24/20
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
--------------------------------------+------------------------------------

Reporter: John Bazik | Owner: nobody
Type: Bug | Status: new
Component: Internationalization | Version: 3.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------------+------------------------------------

Comment (by John Bazik):

Although {{{gettext_lazy}}} is, as you mention, set in {{{trans_null.py}}}

{{{


gettext_noop = gettext_lazy = _ = gettext
}}}

It is also set in {{{translation/__init__.py}}}, and that's what gets
imported.

{{{
_trans = Trans()


def gettext(message):
return _trans.gettext(message)


gettext_lazy = lazy(gettext, str)
}}}

In {{{class Trans}}}, at the top of that file, {{{_trans.gettext}}} is set
to {{{trans_null.gettext}}}, which is this


{{{
def gettext(message):
return message
}}}

I skipped all that in my example to keep it simple. Coercing the message,
as you suggest, looks like a good solution to me.

--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:4>

Django

unread,
Dec 24, 2020, 2:25:25 AM12/24/20
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
--------------------------------------+------------------------------------

Reporter: John Bazik | Owner: nobody
Type: Bug | Status: new
Component: Internationalization | Version: 3.1
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------------+------------------------------------

Comment (by John Bazik):

Here is another solution.

If {{{gettext_lazy}}} was defined in {{{trans_real.py}}} (it is not now),
then it could be set in {{{translation/__init__.py}}} like this

{{{
def gettext_lazy(message):
return _trans.gettext_lazy(message)
}}}

Then {{{lazy}}} would never get called when it isn't needed.

That would require moving some or all of the lazy stuff from
{{{__init__.py}}} to {{{trans_real.py}}} which is more work. And there's
a lot going on in {{{trans_real.py}}} already.

Another possibility is to apply {{{lazy}}} in {{{Trans.__getattr__}}}, in
{{{__init__.py}}}, where USE_I18N is tested.

--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:5>

Django

unread,
Apr 8, 2025, 2:24:22 AM4/8/25
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
-------------------------------------+-------------------------------------
Reporter: John Bazik | Owner: Ahmed
| Nassar
Type: Bug | Status: assigned
Component: | Version: 3.1
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Ahmed Nassar):

* owner: nobody => Ahmed Nassar
* status: new => assigned

--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:6>

Django

unread,
Apr 20, 2025, 6:54:38 AM4/20/25
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
-------------------------------------+-------------------------------------
Reporter: John Bazik | Owner: Ahmed
| Nassar
Type: Bug | Status: assigned
Component: | Version: 3.1
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Ahmed Nassar):

* has_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:7>

Django

unread,
May 9, 2025, 9:47:24 AM5/9/25
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
-------------------------------------+-------------------------------------
Reporter: John Bazik | Owner: Ahmed
| Nassar
Type: Bug | Status: assigned
Component: | Version: 3.1
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* needs_better_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:8>

Django

unread,
May 10, 2025, 10:56:25 PM5/10/25
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
-------------------------------------+-------------------------------------
Reporter: John Bazik | Owner: Ahmed
| Nassar
Type: Bug | Status: assigned
Component: | Version: 3.1
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Ahmed Nassar):

* needs_better_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:9>

Django

unread,
May 12, 2025, 2:51:20 AM5/12/25
to django-...@googlegroups.com
#32272: gettext_lazy inconsistent error when nested
-------------------------------------+-------------------------------------
Reporter: John Bazik | Owner: Ahmed
| Nassar
Type: Bug | Status: assigned
Component: | Version: 3.1
Internationalization |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 1 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Claude Paroz):

* needs_better_patch: 0 => 1
* needs_tests: 0 => 1

Comment:

Ahmed, you know that any code change needs at least one test in Django,
right?
--
Ticket URL: <https://code.djangoproject.com/ticket/32272#comment:10>
Reply all
Reply to author
Forward
0 new messages