#22565 closed Bug (fixed)

pgettext_lazy returns "unexpected type"

Reported by: ygbo Owned by: claudep
Component: Internationalization Version: 1.5
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

The issue is similar to https://code.djangoproject.com/ticket/19272 but with pgettext_lazy:

In [1]: from django.utils.translation import pgettext_lazy

In [2]: s = pgettext_lazy("a context", "foo bar")  # using bytestring

In [3]: s.upper()
/usr/lib/python2.7/dist-packages/django/db/backends/sqlite3/base.py:53: RuntimeWarning: SQLite received a naive datetime (2014-04-29 12:18:28.940685) while time zone support is active.
  RuntimeWarning)

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/usr/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 s.upper()

/usr/lib/python2.7/dist-packages/django/utils/functional.pyc in __wrapper__(self, *args, **kw)
    121                     if t in self.__dispatch:
    122                         return self.__dispatch[t][funcname](res, *args, **kw)
--> 123                 raise TypeError("Lazy object returned unexpected type.")
    124 
    125             if klass not in cls.__dispatch:

TypeError: Lazy object returned unexpected type.

In [4]: s = pgettext_lazy("a context", u"foo bar")  # using unicode string

In [5]: s.upper()
Out[5]: u'FOO BAR'

Change History (7)

comment:1 Changed 15 months ago by claudep

  • Component changed from Uncategorized to Internationalization
  • Needs documentation unset
  • Needs tests unset
  • Owner changed from nobody to claudep
  • Patch needs improvement unset
  • Status changed from new to assigned
  • Triage Stage changed from Unreviewed to Accepted
  • Type changed from Uncategorized to Bug

The situation is a bit different, as pgettext_lazy is unicode-based (it calls ugettext internally). But I think this can still be fixed.

comment:2 Changed 15 months ago by Claude Paroz <claude@…>

  • Resolution set to fixed
  • Status changed from assigned to closed

In 142c27218a0bb07bb197faab7b1d8eb3a084f5b9:

Fixed #22565 -- Prevented pgettext_lazy crash with bytestring input

Thanks ygbo for the report.

comment:3 Changed 15 months ago by Claude Paroz <claude@…>

In 61fd00d4fd65f44d0a05be4c7e95124e4102ec27:

[1.7.x] Fixed #22565 -- Prevented pgettext_lazy crash with bytestring input

Thanks ygbo for the report.
Backport of 142c27218 from master.

comment:4 Changed 15 months ago by Claude Paroz <claude@…>

In 034866204b39f797c73997b03cd90443aa03aa91:

[1.6.x] Fixed #22565 -- Prevented pgettext_lazy crash with bytestring input

Thanks ygbo for the report.
Backport of 142c27218 from master.

comment:5 Changed 15 months ago by wdoekes

For those affected on 1.4:

--- django/utils/translation/trans_real.py.orig	2014-05-15 11:16:54.384046616 +0200
+++ django/utils/translation/trans_real.py	2014-05-15 11:17:03.491749365 +0200
@@ -282,7 +282,7 @@ def pgettext(context, message):
         u"%s%s%s" % (context, CONTEXT_SEPARATOR, message), 'ugettext')
     if CONTEXT_SEPARATOR in result:
         # Translation not found
-        result = message
+        result = unicode(message)
     return result
 
 def gettext_noop(message):

And a slightly longer explanation:

  • You're use pgettext_lazy('context', 'bytestring') instead of pgettext_lazy('context', u'unicodestring').
  • The translation is NOT found. Generally happens for English, since that's your base language: no need for po/mo files for that.
  • result holds context\x04bytestring (which means it wasn't translated), so it is overwritten by the original which was a bytestring.
  • When the lazy object is converted to non-lazy it trips on the wrong data type, since it expected unicode -- pgettext_lazy = lazy(pgettext, unicode) -- and gets a bytestring, hence the TypeError: Lazy object returned unexpected type.

After patching you can safely forget the u again which you weren't used to using for ugettext_lazy either.

Cheers,
Walter Doekes
OSSO B.V.

Last edited 15 months ago by wdoekes (previous) (diff)

comment:6 Changed 15 months ago by Fak3

  • Resolution fixed deleted
  • Status changed from closed to new
  • Version changed from 1.6 to 1.5

Django 1.5 also has this bug. Can this be backported?

comment:7 Changed 15 months ago by claudep

  • Resolution set to fixed
  • Status changed from new to closed

Sorry, but probably not. 1.5 is in security-fix mode, and you can easily workaround this issue by passing unicode strings to pgettext_lazy.

Note: See TracTickets for help on using tickets.
Back to Top