implementation of jsonencoder escapedct setdefaultchri u04x i return a json representation of a python string return an asciionly json representation of a python string return u04x n surrogate pair extensible json https json org encoder for python data structures supports the following objects and types by default python json dict object list tuple array str string int float number true true false false none null 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 constructor for jsonencoder with sensible defaults if skipkeys is false then it is a typeerror to attempt encoding of keys that are not str int float or none if skipkeys is true such items are simply skipped if ensureascii is true the output is guaranteed to be str objects with all incoming nonascii characters escaped if ensureascii is false the output can contain nonascii characters if checkcircular is true then lists dicts and custom encoded objects will be checked for circular references during encoding to prevent an infinite recursion which would cause an recursionerror otherwise no such check takes place if allownan is true then nan infinity and infinity will be encoded as such this behavior is not json specification compliant but is consistent with most javascript based encoders and decoders otherwise it will be a valueerror to encode such floats if sortkeys is true then the output of dictionaries will be sorted by key this is useful for regression tests to ensure that json serializations can be compared on a daytoday basis if indent is a nonnegative integer then json array elements and object members will be prettyprinted with that indent level an indent level of 0 will only insert newlines none is the most compact representation if specified separators should be an itemseparator keyseparator tuple the default is if indent is none and otherwise to get the most compact json representation you should specify to eliminate whitespace if specified default is a function that gets called for objects that can t otherwise be serialized it should return a json encodable version of the object or raise a typeerror implement this method in a subclass such that it returns a serializable object for o or calls the base implementation to raise a typeerror for example to support arbitrary iterators you could implement default like this def defaultself o try iterable itero except typeerror pass else return listiterable let the base class default method raise the typeerror return jsonencoder defaultself o return a json string representation of a python data structure from json encoder import jsonencoder jsonencoder encodefoo bar baz foo bar baz this is for extremely simple cases and benchmarks this doesn t pass the iterator directly to join because the exceptions aren t as detailed the list call should be roughly equivalent to the pysequencefast that join would do encode the given object and yield each string representation as available for example for chunk in jsonencoder iterencodebigobject mysocket writechunk check for specials note that this type of test is processor andor platformspecific so do tests which don t depend on the internals hack handoptimized bytecode turn globals into locals subclasses of intfloat may override repr but we still want to encode them as integersfloats in json one example within the standard library is intenum see comment above for int javascript is weakly typed for these so it makes sense to also allow them many encoders seem to do something like this see comment for intfloat in makeiterencode see comment for intfloat in makeiterencode see comment for intfloat in makeiterencode see comment for intfloat in makeiterencode see comment for intfloat in makeiterencode see comment for intfloat in makeiterencode escape_dct setdefault chr i u 04x i return a json representation of a python string return an ascii only json representation of a python string return u 04x n surrogate pair extensible json https json org encoder for python data structures supports the following objects and types by default python json dict object list tuple array str string int float number true true false false none null 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 constructor for jsonencoder with sensible defaults if skipkeys is false then it is a typeerror to attempt encoding of keys that are not str int float or none if skipkeys is true such items are simply skipped if ensure_ascii is true the output is guaranteed to be str objects with all incoming non ascii characters escaped if ensure_ascii is false the output can contain non ascii characters if check_circular is true then lists dicts and custom encoded objects will be checked for circular references during encoding to prevent an infinite recursion which would cause an recursionerror otherwise no such check takes place if allow_nan is true then nan infinity and infinity will be encoded as such this behavior is not json specification compliant but is consistent with most javascript based encoders and decoders otherwise it will be a valueerror to encode such floats if sort_keys is true then the output of dictionaries will be sorted by key this is useful for regression tests to ensure that json serializations can be compared on a day to day basis if indent is a non negative integer then json array elements and object members will be pretty printed with that indent level an indent level of 0 will only insert newlines none is the most compact representation if specified separators should be an item_separator key_separator tuple the default is if indent is none and otherwise to get the most compact json representation you should specify to eliminate whitespace if specified default is a function that gets called for objects that can t otherwise be serialized it should return a json encodable version of the object or raise a typeerror implement this method in a subclass such that it returns a serializable object for o or calls the base implementation to raise a typeerror for example to support arbitrary iterators you could implement default like this def default self o try iterable iter o except typeerror pass else return list iterable let the base class default method raise the typeerror return jsonencoder default self o return a json string representation of a python data structure from json encoder import jsonencoder jsonencoder encode foo bar baz foo bar baz this is for extremely simple cases and benchmarks this doesn t pass the iterator directly to join because the exceptions aren t as detailed the list call should be roughly equivalent to the pysequence_fast that join would do encode the given object and yield each string representation as available for example for chunk in jsonencoder iterencode bigobject mysocket write chunk 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 hack hand optimized bytecode turn globals into locals subclasses of int float may override __repr__ but we still want to encode them as integers floats in json one example within the standard library is intenum see comment above for int javascript is weakly typed for these so it makes sense to also allow them many encoders seem to do something like this see comment for int float in _make_iterencode see comment for int float in _make_iterencode see comment for int float in _make_iterencode see comment for int float in _make_iterencode see comment for int float in _make_iterencode see comment for int float in _make_iterencode
import re

try:
    from _json import encode_basestring_ascii as c_encode_basestring_ascii
except ImportError:
    c_encode_basestring_ascii = None
try:
    from _json import encode_basestring as c_encode_basestring
except ImportError:
    c_encode_basestring = None
try:
    from _json import make_encoder as c_make_encoder
except ImportError:
    c_make_encoder = None

ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')
ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
HAS_UTF8 = re.compile(b'[\x80-\xff]')
ESCAPE_DCT = {
    '\\': '\\\\',
    '"': '\\"',
    '\b': '\\b',
    '\f': '\\f',
    '\n': '\\n',
    '\r': '\\r',
    '\t': '\\t',
}
for i in range(0x20):
    ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
    
del i

INFINITY = float('inf')

def py_encode_basestring(s):
    
    def replace(match):
        return ESCAPE_DCT[match.group(0)]
    return '"' + ESCAPE.sub(replace, s) + '"'


encode_basestring = (c_encode_basestring or py_encode_basestring)


def py_encode_basestring_ascii(s):
    
    def replace(match):
        s = match.group(0)
        try:
            return ESCAPE_DCT[s]
        except KeyError:
            n = ord(s)
            if n < 0x10000:
                return '\\u{0:04x}'.format(n)
                
            else:
                
                n -= 0x10000
                s1 = 0xd800 | ((n >> 10) & 0x3ff)
                s2 = 0xdc00 | (n & 0x3ff)
                return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
    return '"' + ESCAPE_ASCII.sub(replace, s) + '"'


encode_basestring_ascii = (
    c_encode_basestring_ascii or py_encode_basestring_ascii)

class JSONEncoder(object):
    
    item_separator = ', '
    key_separator = ': '
    def __init__(self, *, skipkeys=False, ensure_ascii=True,
            check_circular=True, allow_nan=True, sort_keys=False,
            indent=None, separators=None, default=None):
        

        self.skipkeys = skipkeys
        self.ensure_ascii = ensure_ascii
        self.check_circular = check_circular
        self.allow_nan = allow_nan
        self.sort_keys = sort_keys
        self.indent = indent
        if separators is not None:
            self.item_separator, self.key_separator = separators
        elif indent is not None:
            self.item_separator = ','
        if default is not None:
            self.default = default

    def default(self, o):
        
        raise TypeError(f'Object of type {o.__class__.__name__} '
                        f'is not JSON serializable')

    def encode(self, o):
        
        
        if isinstance(o, str):
            if self.ensure_ascii:
                return encode_basestring_ascii(o)
            else:
                return encode_basestring(o)
        
        
        
        chunks = self.iterencode(o, _one_shot=True)
        if not isinstance(chunks, (list, tuple)):
            chunks = list(chunks)
        return ''.join(chunks)

    def iterencode(self, o, _one_shot=False):
        
        if self.check_circular:
            markers = {}
        else:
            markers = None
        if self.ensure_ascii:
            _encoder = encode_basestring_ascii
        else:
            _encoder = encode_basestring

        def floatstr(o, allow_nan=self.allow_nan,
                _repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):
            
            
            

            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


        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 _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
        _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
        
        ValueError=ValueError,
        dict=dict,
        float=float,
        id=id,
        int=int,
        isinstance=isinstance,
        list=list,
        str=str,
        tuple=tuple,
        _intstr=int.__repr__,
    ):

    if _indent is not None and not isinstance(_indent, str):
        _indent = ' ' * _indent

    def _iterencode_list(lst, _current_indent_level):
        if not lst:
            yield '[]'
            return
        if markers is not None:
            markerid = id(lst)
            if markerid in markers:
                raise ValueError("Circular reference detected")
            markers[markerid] = lst
        buf = '['
        if _indent is not None:
            _current_indent_level += 1
            newline_indent = '\n' + _indent * _current_indent_level
            separator = _item_separator + newline_indent
            buf += newline_indent
        else:
            newline_indent = None
            separator = _item_separator
        first = True
        for value in lst:
            if first:
                first = False
            else:
                buf = separator
            if isinstance(value, str):
                yield buf + _encoder(value)
            elif value is None:
                yield buf + 'null'
            elif value is True:
                yield buf + 'true'
            elif value is False:
                yield buf + 'false'
            elif isinstance(value, int):
                
                
                
                yield buf + _intstr(value)
            elif isinstance(value, float):
                
                yield buf + _floatstr(value)
            else:
                yield buf
                if isinstance(value, (list, tuple)):
                    chunks = _iterencode_list(value, _current_indent_level)
                elif isinstance(value, dict):
                    chunks = _iterencode_dict(value, _current_indent_level)
                else:
                    chunks = _iterencode(value, _current_indent_level)
                yield from chunks
        if newline_indent is not None:
            _current_indent_level -= 1
            yield '\n' + _indent * _current_indent_level
        yield ']'
        if markers is not None:
            del markers[markerid]

    def _iterencode_dict(dct, _current_indent_level):
        if not dct:
            yield '{}'
            return
        if markers is not None:
            markerid = id(dct)
            if markerid in markers:
                raise ValueError("Circular reference detected")
            markers[markerid] = dct
        yield '{'
        if _indent is not None:
            _current_indent_level += 1
            newline_indent = '\n' + _indent * _current_indent_level
            item_separator = _item_separator + newline_indent
            yield newline_indent
        else:
            newline_indent = None
            item_separator = _item_separator
        first = True
        if _sort_keys:
            items = sorted(dct.items())
        else:
            items = dct.items()
        for key, value in items:
            if isinstance(key, str):
                pass
            
            
            elif isinstance(key, float):
                
                key = _floatstr(key)
            elif key is True:
                key = 'true'
            elif key is False:
                key = 'false'
            elif key is None:
                key = 'null'
            elif isinstance(key, int):
                
                key = _intstr(key)
            elif _skipkeys:
                continue
            else:
                raise TypeError(f'keys must be str, int, float, bool or None, '
                                f'not {key.__class__.__name__}')
            if first:
                first = False
            else:
                yield item_separator
            yield _encoder(key)
            yield _key_separator
            if isinstance(value, str):
                yield _encoder(value)
            elif value is None:
                yield 'null'
            elif value is True:
                yield 'true'
            elif value is False:
                yield 'false'
            elif isinstance(value, int):
                
                yield _intstr(value)
            elif isinstance(value, float):
                
                yield _floatstr(value)
            else:
                if isinstance(value, (list, tuple)):
                    chunks = _iterencode_list(value, _current_indent_level)
                elif isinstance(value, dict):
                    chunks = _iterencode_dict(value, _current_indent_level)
                else:
                    chunks = _iterencode(value, _current_indent_level)
                yield from chunks
        if newline_indent is not None:
            _current_indent_level -= 1
            yield '\n' + _indent * _current_indent_level
        yield '}'
        if markers is not None:
            del markers[markerid]

    def _iterencode(o, _current_indent_level):
        if isinstance(o, str):
            yield _encoder(o)
        elif o is None:
            yield 'null'
        elif o is True:
            yield 'true'
        elif o is False:
            yield 'false'
        elif isinstance(o, int):
            
            yield _intstr(o)
        elif isinstance(o, float):
            
            yield _floatstr(o)
        elif isinstance(o, (list, tuple)):
            yield from _iterencode_list(o, _current_indent_level)
        elif isinstance(o, dict):
            yield from _iterencode_dict(o, _current_indent_level)
        else:
            if markers is not None:
                markerid = id(o)
                if markerid in markers:
                    raise ValueError("Circular reference detected")
                markers[markerid] = o
            o = _default(o)
            yield from _iterencode(o, _current_indent_level)
            if markers is not None:
                del markers[markerid]
    return _iterencode