Skip to content

Commit

Permalink
[#1078] smaller simplejson hack: use for_json and pretend to be an int
Browse files Browse the repository at this point in the history
  • Loading branch information
wardi committed Dec 11, 2014
1 parent 6dc1333 commit 3462450
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 65 deletions.
9 changes: 3 additions & 6 deletions ckan/controllers/api.py
Expand Up @@ -16,7 +16,6 @@
import ckan.lib.navl.dictization_functions
import ckan.lib.jsonp as jsonp
import ckan.lib.munge as munge
import ckan.lib.lazyjson as lazyjson

from ckan.common import _, c, request, response

Expand Down Expand Up @@ -84,11 +83,9 @@ def _finish(self, status_int, response_data=None,
if response_data is not None:
response.headers['Content-Type'] = CONTENT_TYPES[content_type]
if content_type == 'json':
try:
response_msg = h.json.dumps(response_data)
except TypeError:
response_msg = lazyjson.LazyJSONEncoder().encode(
response_data)
response_msg = h.json.dumps(
response_data,
for_json=True) # handle objects with for_json methods
else:
response_msg = response_data
# Support "JSONP" callback.
Expand Down
72 changes: 13 additions & 59 deletions ckan/lib/lazyjson.py
Expand Up @@ -17,10 +17,10 @@ def _loads(self):
def __nonzero__(self):
return True

def to_json_string(self, *args, **kwargs):
def for_json(self):
if self._json_string:
return self._json_string
return json.dumps(self._json_dict, *args, **kwargs)
return JSONString(self._json_string)
return self._json_dict


def _loads_method(name):
Expand All @@ -36,62 +36,16 @@ def method(self, *args, **kwargs):
setattr(LazyJSONObject, fn, _loads_method(fn))


class JSONString(str):
'''a type for already-encoded JSON'''
pass
class JSONString(int):
'''
A type for already-encoded JSON
Fake-out simplejson by subclassing int so that simplejson calls
our __str__ method to produce JSON.
'''
def __init__(self, s):
self.s = s
super(JSONString, self).__init__(-1)

def _encode_jsonstring(s):
if isinstance(s, JSONString):
def __str__(self):
return s
return json_encoder.encode_basestring(s)


class LazyJSONEncoder(json.JSONEncoder):
'''JSON encoder that handles LazyJSONObject elements'''
def iterencode(self, o, _one_shot=False):
'''
most of JSONEncoder.iterencode() copied so that _encode_jsonstring
may be used instead of encode_basestring
'''
if self.check_circular:
markers = {}
else:
markers = None

def floatstr(o, allow_nan=self.allow_nan,
_repr=json_encoder.FLOAT_REPR,
_inf=json_encoder.PosInf,
_neginf=-json_encoder.PosInf):
# Check for specials. Note that this type of test is processor
# and/or platform-specific, so do tests which don't depend on the
# internals.

if o != o:
text = 'NaN'
elif o == _inf:
text = 'Infinity'
elif o == _neginf:
text = '-Infinity'
else:
return _repr(o)

if not allow_nan:
raise ValueError(
"Out of range float values are not JSON compliant: " +
repr(o))

return text
_iterencode = json_encoder._make_iterencode(
markers, self.default, _encode_jsonstring, self.indent, floatstr,
self.key_separator, self.item_separator, self.sort_keys,
self.skipkeys, _one_shot, self.use_decimal,
self.namedtuple_as_object, self.tuple_as_array,
self.bigint_as_string, self.item_sort_key,
self.encoding, Decimal=json_encoder.Decimal)
return _iterencode(o, 0)

def default(self, o):
if hasattr(o, 'to_json_string'):
return JSONString(o.to_json_string())
return json.JSONEncoder.default(self, o)

0 comments on commit 3462450

Please sign in to comment.