Opened 7 years ago

Closed 7 years ago

#5868 closed (fixed)

Newforms ErrorDict serialization problem

Reported by: tangerine Owned by: nobody
Component: Forms Version: master
Severity: Keywords: serialization newforms JSON
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Around r6625 a bug has been introduced whereby an attempt to serialize a ErrorDict instance will fail and throw a TypeError, complaining of not being able to serialize a proxy object e.g. something like django.utils.functional.__proxy__ object at 0xdeecd0> is not JSON serializable . I have attached some sample code to illustrate the problem.

Attachments (1)

serialization_example.py (408 bytes) - added by tangerine 7 years ago.
Sample

Download all attachments as: .zip

Change History (5)

Changed 7 years ago by tangerine

Sample

comment:1 Changed 7 years ago by gwilson

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Design decision needed

Yes, r6625 turned all newforms error messages into lazy strings, which aren't supported by the default JSONEncoder:

>>> from django.utils import simplejson
>>> simplejson.dumps(ugettext_lazy('hello world'))
Traceback (most recent call last):
  File "<console>", line 1, in ?
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/__init__.py", line 181, in dumps
    separators=separators,
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/encoder.py", line 312, in encode
    chunks = list(self.iterencode(o))
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/encoder.py", line 273, in _iterencode
    for chunk in self._iterencode_default(o, markers):
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/encoder.py", line 279, in _iterencode_default
    newobj = self.default(o)
  File "/home/gdub/bzr/django/upstream/django/utils/simplejson/encoder.py", line 300, in default
    raise TypeError("%r is not JSON serializable" % (o,))
TypeError: <django.utils.functional.__proxy__ object at 0x892378c> is not JSON serializable

The JSONEncoder docstring states:

    To extend this to recognize other objects, subclass and implement a
    ``.default()`` method with another method that returns a serializable
    object for ``o`` if possible, otherwise it should call the superclass
    implementation (to raise ``TypeError``).

Looks like we might want to do this since lazy strings are used in several places throughout Django. Here's a quick and dirty one that works:

from django.utils.functional import Promise
from django.utils.translation import force_unicode
from django.utils.simplejson import JSONEncoder

class LazyEncoder(JSONEncoder):
    def default(self, o):
        if isinstance(o, Promise):
            return force_unicode(o)
        else:
            return super(LazyEncoder, self).default(o)
>>> simplejson.dumps(ugettext_lazy('hello world'), cls=LazyEncoder)
'"hello world"'
>>> simplejson.dumps([1, 2, ugettext_lazy('hi')], cls=LazyEncoder)
'[1, 2, "hi"]'

comment:2 Changed 7 years ago by mtredinnick

  • Triage Stage changed from Design decision needed to Accepted

We shouldn't add this code by default, since it's usually going to be unnecessary overhead. It somebody's going to use simplejson directly, they will need to write such a class if there's a chance they are dumping lazy translation objects. I'll update the docs.

I will add something to Django's core serializers to handle the analogous case over there, though.

comment:3 Changed 7 years ago by mtredinnick

Hmm .. on second thoughts, I can't see how we'd ever end up sending a lazy translation object to Django's serializers, so it's not necessary there.

comment:4 Changed 7 years ago by mtredinnick

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

(In [6645]) Fixed #5868 -- Provided an example of how to extend simplejson to serialize
lazy translation objects for those who want to use it directly.

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