Permalink
Browse files

Fixed #18023 -- Removed bundled simplejson.

And started the deprecation path for django.utils.simplejson.

Thanks Alex Ogier, Clueless, and other contributors for their
work on the patch.
  • Loading branch information...
1 parent ee0a7c7 commit cec6bd5a59547dc97fe98975c570fc27a1e970be @aaugustin aaugustin committed Apr 29, 2012
View
@@ -6,7 +6,6 @@ include MANIFEST.in
include django/contrib/gis/gdal/LICENSE
include django/contrib/gis/geos/LICENSE
include django/dispatch/license.txt
-include django/utils/simplejson/LICENSE.txt
recursive-include docs *
recursive-include scripts *
recursive-include extras *
@@ -1,6 +1,7 @@
+import json
+
from django.core.exceptions import SuspiciousOperation
from django.core.signing import BadSignature
-from django.utils import simplejson as json
from django.contrib.formtools.wizard import storage
@@ -3,10 +3,10 @@
for the GEOS and GDAL tests.
"""
import gzip
+import json
import os
from django.contrib import gis
-from django.utils import simplejson
# This global used to store reference geometry data.
@@ -100,6 +100,6 @@ def geometries(self):
if GEOMETRIES is None:
# Load up the test geometry data from fixture into global.
gzf = gzip.GzipFile(os.path.join(TEST_DATA, 'geometries.json.gz'))
- geometries = simplejson.loads(gzf.read())
+ geometries = json.loads(gzf.read())
GEOMETRIES = TestGeomSet(**strconvert(geometries))
return GEOMETRIES
@@ -1,7 +1,8 @@
+import json
+
from django.conf import settings
from django.contrib.messages.storage.base import BaseStorage, Message
from django.http import SimpleCookie
-from django.utils import simplejson as json
from django.utils.crypto import salted_hmac, constant_time_compare
@@ -1,10 +1,11 @@
+import json
+
from django.contrib.messages import constants
from django.contrib.messages.tests.base import BaseTest
from django.contrib.messages.storage.cookie import (CookieStorage,
MessageEncoder, MessageDecoder)
from django.contrib.messages.storage.base import Message
from django.test.utils import override_settings
-from django.utils import simplejson as json
def set_cookie_data(storage, messages, invalid=False, encode_empty=False):
@@ -2,14 +2,17 @@
Serialize data to/from JSON
"""
+# Avoid shadowing the standard library json module
+from __future__ import absolute_import
+
import datetime
import decimal
+import json
from StringIO import StringIO
from django.core.serializers.base import DeserializationError
from django.core.serializers.python import Serializer as PythonSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
-from django.utils import simplejson
from django.utils.timezone import is_aware
class Serializer(PythonSerializer):
@@ -19,10 +22,10 @@ class Serializer(PythonSerializer):
internal_use_only = False
def end_serialization(self):
- if simplejson.__version__.split('.') >= ['2', '1', '3']:
+ if json.__version__.split('.') >= ['2', '1', '3']:
# Use JS strings to represent Python Decimal instances (ticket #16850)
self.options.update({'use_decimal': False})
- simplejson.dump(self.objects, self.stream, cls=DjangoJSONEncoder, **self.options)
+ json.dump(self.objects, self.stream, cls=DjangoJSONEncoder, **self.options)
def getvalue(self):
if callable(getattr(self.stream, 'getvalue', None)):
@@ -38,7 +41,7 @@ def Deserializer(stream_or_string, **options):
else:
stream = stream_or_string
try:
- for obj in PythonDeserializer(simplejson.load(stream), **options):
+ for obj in PythonDeserializer(json.load(stream), **options):
yield obj
except GeneratorExit:
raise
@@ -47,7 +50,7 @@ def Deserializer(stream_or_string, **options):
raise DeserializationError(e)
-class DjangoJSONEncoder(simplejson.JSONEncoder):
+class DjangoJSONEncoder(json.JSONEncoder):
@maraujop
maraujop Jun 19, 2012

I've updated to Djando dev and found Tastypie serialization is broken because json.JSONEncoder doesn't accept a keyword argument namedtuple_as_object, while simplejson.JSONEncoder does. This breaks backwards compatibility, is this the desired behavior? Should this be fixed in Django or in Tastypie?

Thanks

@maraujop
maraujop Jun 19, 2012

Most likely this is due to the fact that Tastypie is doing simplejson.dumps(data, cls=json.DjangoJSONEncoder, sort_keys=True, ensure_ascii=False) and passing a DjangoJSONEncoder which is no longer a simplejson encoder anymore, so simplejson passes to it kwargs it doesn't accept. So I'm leaning towards patching this in Tastypie.

Thanks, cheers

@ogier
ogier Jun 22, 2012

I consider this a bug in simplejson.

>>> import json
>>> import simplejson
>>> simplejson.dumps({'hello': 'world'}, cls=json.JSONEncoder)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/aogier/.virtualenvs/simp/lib/python2.7/site-packages/simplejson/__init__.py", line 334, in dumps
    **kw).encode(obj)
TypeError: __init__() got an unexpected keyword argument 'namedtuple_as_object'

Basically, simplejson 2.2 broke backwards compatibility, both with itself and with the Python standard library by adding this keyword argument.

@spookylukey
spookylukey Jun 22, 2012 Django member

There's a similar issue in django-piston - here was my fix: https://bitbucket.org/jespern/django-piston/pull-request/25/compatibility-fix-for-json-emitter-with

I think we should just document the problem, given that the workaround isn't too bad. Doing anything else would just perpetuate the problems that simplejson has caused.

"""
JSONEncoder subclass that knows how to encode date/time and decimal types.
"""
@@ -33,12 +33,13 @@
These functions make use of all of them.
"""
import base64
+import json
import time
import zlib
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
-from django.utils import baseconv, simplejson
+from django.utils import baseconv
from django.utils.crypto import constant_time_compare, salted_hmac
from django.utils.encoding import force_unicode, smart_str
from django.utils.importlib import import_module
@@ -89,14 +90,14 @@ def get_cookie_signer(salt='django.core.signing.get_cookie_signer'):
class JSONSerializer(object):
"""
- Simple wrapper around simplejson to be used in signing.dumps and
+ Simple wrapper around json to be used in signing.dumps and
signing.loads.
"""
def dumps(self, obj):
- return simplejson.dumps(obj, separators=(',', ':'))
+ return json.dumps(obj, separators=(',', ':'))
def loads(self, data):
- return simplejson.loads(data)
+ return json.loads(data)
def dumps(obj, key=None, salt='django.core.signing', serializer=JSONSerializer, compress=False):
@@ -1,4 +1,5 @@
import difflib
+import json
import os
import re
import sys
@@ -33,7 +34,7 @@
from django.test.utils import (get_warnings_state, restore_warnings_state,
override_settings)
from django.test.utils import ContextList
-from django.utils import simplejson, unittest as ut2
+from django.utils import unittest as ut2
from django.utils.encoding import smart_str, force_unicode
from django.utils.unittest.util import safe_repr
from django.views.static import serve
@@ -189,8 +190,8 @@ def check_output_json(self, want, got, optionsflags):
"""
want, got = self._strip_quotes(want, got)
try:
- want_json = simplejson.loads(want)
- got_json = simplejson.loads(got)
+ want_json = json.loads(want)
+ got_json = json.loads(got)
except Exception:
return False
return want_json == got_json
@@ -0,0 +1,31 @@
+# Django 1.5 only supports Python >= 2.6, where the standard library includes
+# the json module. Previous version of Django shipped a copy for Python < 2.6.
+
+# For backwards compatibility, we're keeping an importable json module
+# at this location, with the same lookup sequence.
+
+# Avoid shadowing the simplejson module
+from __future__ import absolute_import
+
+import warnings
+warnings.warn("django.utils.simplejson is deprecated; use json instead.",
+ PendingDeprecationWarning)
+
+try:
+ import simplejson
+except ImportError:
+ use_simplejson = False
+else:
+ # The system-installed version has priority providing it is either not an
+ # earlier version or it contains the C speedups.
+ from json import __version__ as stdlib_json_version
+ use_simplejson = (hasattr(simplejson, '_speedups') or
+ simplejson.__version__.split('.') >= stdlib_json_version.split('.'))
+
+# Make sure we copy over the version. See #17071
+if use_simplejson:
+ from simplejson import *
+ from simplejson import __version__
+else:
+ from json import *
+ from json import __version__
@@ -1,19 +0,0 @@
-Copyright (c) 2006 Bob Ippolito
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
Oops, something went wrong. Retry.

0 comments on commit cec6bd5

Please sign in to comment.