diff --git a/ckan/controllers/api.py b/ckan/controllers/api.py index 934d531c87f..f81e5d718f9 100644 --- a/ckan/controllers/api.py +++ b/ckan/controllers/api.py @@ -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 @@ -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. diff --git a/ckan/lib/lazyjson.py b/ckan/lib/lazyjson.py index 50bcf0a4f6c..2d5d6b5a82a 100644 --- a/ckan/lib/lazyjson.py +++ b/ckan/lib/lazyjson.py @@ -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): @@ -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)