diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index 8896e4f2c..d1dabd368 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -6,6 +6,9 @@ from __future__ import unicode_literals import datetime import decimal import json +from json.encoder import (FLOAT_REPR, INFINITY, c_make_encoder, + encode_basestring_ascii, encode_basestring, + _make_iterencode) import uuid from django.db.models.query import QuerySet @@ -21,6 +24,72 @@ class JSONEncoder(json.JSONEncoder): JSONEncoder subclass that knows how to encode date/time/timedelta, decimal types, generators and other basic python objects. """ + + def iterencode(self, o, _one_shot=False): + """Encode the given object and yield each string + representation as available. + For example:: + for chunk in JSONEncoder().iterencode(bigobject): + mysocket.write(chunk) + """ + if self.check_circular: + markers = {} + else: + markers = None + if self.ensure_ascii: + _encoder = encode_basestring_ascii + else: + _encoder = encode_basestring + if six.PY2: + if self.encoding != 'utf-8': + def _encoder(o, _orig_encoder=_encoder, + _encoding=self.encoding): + if isinstance(o, str): + o = o.decode(_encoding) + return _orig_encoder(o) + + if self.encoding != 'utf-8': + def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding): + if isinstance(o, str): + o = o.decode(_encoding) + return _orig_encoder(o) + + def floatstr(o, allow_nan=self.allow_nan, + _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY): + # 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 = 'null' + elif o == _inf: + text = 'null' + elif o == _neginf: + text = 'null' + else: + return _repr(o) + + if not allow_nan: + raise ValueError( + "Out of range float values are not JSON compliant: " + + repr(o)) + + return text + + + if (_one_shot and c_make_encoder is not None + and self.indent is None): + _iterencode = c_make_encoder( + markers, self.default, _encoder, self.indent, + self.key_separator, self.item_separator, self.sort_keys, + self.skipkeys, self.allow_nan) + else: + _iterencode = _make_iterencode( + markers, self.default, _encoder, self.indent, floatstr, + self.key_separator, self.item_separator, self.sort_keys, + self.skipkeys, _one_shot) + return _iterencode(o, 0) + def default(self, obj): # For Date Time string spec, see ECMA 262 # http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 @@ -55,7 +124,8 @@ class JSONEncoder(json.JSONEncoder): elif hasattr(obj, 'tolist'): # Numpy arrays and array scalars. return obj.tolist() - elif (coreapi is not None) and isinstance(obj, (coreapi.Document, coreapi.Error)): + elif (coreapi is not None) and isinstance(obj, (coreapi.Document, + coreapi.Error)): raise RuntimeError( 'Cannot return a coreapi object from a JSON view. ' 'You should be using a schema renderer instead for this view.'