Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
encoder.py462 linesDownload Raw Back to json
1"""Implementation of JSONEncoder2"""3import re4 5try:6    from _json import encode_basestring_ascii as c_encode_basestring_ascii7except ImportError:8    c_encode_basestring_ascii = None9try:10    from _json import encode_basestring as c_encode_basestring11except ImportError:12    c_encode_basestring = None13try:14    from _json import make_encoder as c_make_encoder15except ImportError:16    c_make_encoder = None17 18ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')19ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')20HAS_UTF8 = re.compile(b'[\x80-\xff]')21ESCAPE_DCT = {22    '\\': '\\\\',23    '"': '\\"',24    '\b': '\\b',25    '\f': '\\f',26    '\n': '\\n',27    '\r': '\\r',28    '\t': '\\t',29}30for i in range(0x20):31    ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))32    #ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))33del i34 35INFINITY = float('inf')36 37def py_encode_basestring(s):38    """Return a JSON representation of a Python string39 40    """41    def replace(match):42        return ESCAPE_DCT[match.group(0)]43    return '"' + ESCAPE.sub(replace, s) + '"'44 45 46encode_basestring = (c_encode_basestring or py_encode_basestring)47 48 49def py_encode_basestring_ascii(s):50    """Return an ASCII-only JSON representation of a Python string51 52    """53    def replace(match):54        s = match.group(0)55        try:56            return ESCAPE_DCT[s]57        except KeyError:58            n = ord(s)59            if n < 0x10000:60                return '\\u{0:04x}'.format(n)61                #return '\\u%04x' % (n,)62            else:63                # surrogate pair64                n -= 0x1000065                s1 = 0xd800 | ((n >> 10) & 0x3ff)66                s2 = 0xdc00 | (n & 0x3ff)67                return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)68    return '"' + ESCAPE_ASCII.sub(replace, s) + '"'69 70 71encode_basestring_ascii = (72    c_encode_basestring_ascii or py_encode_basestring_ascii)73 74class JSONEncoder(object):75    """Extensible JSON <https://json.org> encoder for Python data structures.76 77    Supports the following objects and types by default:78 79    +-------------------+---------------+80    | Python            | JSON          |81    +===================+===============+82    | dict              | object        |83    +-------------------+---------------+84    | list, tuple       | array         |85    +-------------------+---------------+86    | str               | string        |87    +-------------------+---------------+88    | int, float        | number        |89    +-------------------+---------------+90    | True              | true          |91    +-------------------+---------------+92    | False             | false         |93    +-------------------+---------------+94    | None              | null          |95    +-------------------+---------------+96 97    To extend this to recognize other objects, subclass and implement a98    ``.default()`` method with another method that returns a serializable99    object for ``o`` if possible, otherwise it should call the superclass100    implementation (to raise ``TypeError``).101 102    """103    item_separator = ', '104    key_separator = ': '105    def __init__(self, *, skipkeys=False, ensure_ascii=True,106            check_circular=True, allow_nan=True, sort_keys=False,107            indent=None, separators=None, default=None):108        """Constructor for JSONEncoder, with sensible defaults.109 110        If skipkeys is false, then it is a TypeError to attempt111        encoding of keys that are not str, int, float, bool or None.112        If skipkeys is True, such items are simply skipped.113 114        If ensure_ascii is true, the output is guaranteed to be str objects115        with all incoming non-ASCII and non-printable characters escaped.116        If ensure_ascii is false, the output can contain non-ASCII and117        non-printable characters.118 119        If check_circular is true, then lists, dicts, and custom encoded120        objects will be checked for circular references during encoding to121        prevent an infinite recursion (which would cause an RecursionError).122        Otherwise, no such check takes place.123 124        If allow_nan is true, then NaN, Infinity, and -Infinity will be125        encoded as such.  This behavior is not JSON specification compliant,126        but is consistent with most JavaScript based encoders and decoders.127        Otherwise, it will be a ValueError to encode such floats.128 129        If sort_keys is true, then the output of dictionaries will be130        sorted by key; this is useful for regression tests to ensure131        that JSON serializations can be compared on a day-to-day basis.132 133        If indent is a non-negative integer, then JSON array134        elements and object members will be pretty-printed with that135        indent level.  An indent level of 0 will only insert newlines.136        None is the most compact representation.137 138        If specified, separators should be an (item_separator,139        key_separator) tuple.  The default is (', ', ': ') if *indent* is140        ``None`` and (',', ': ') otherwise.  To get the most compact JSON141        representation, you should specify (',', ':') to eliminate142        whitespace.143 144        If specified, default is a function that gets called for objects145        that can't otherwise be serialized.  It should return a JSON146        encodable version of the object or raise a ``TypeError``.147 148        """149 150        self.skipkeys = skipkeys151        self.ensure_ascii = ensure_ascii152        self.check_circular = check_circular153        self.allow_nan = allow_nan154        self.sort_keys = sort_keys155        self.indent = indent156        if separators is not None:157            self.item_separator, self.key_separator = separators158        elif indent is not None:159            self.item_separator = ','160        if default is not None:161            self.default = default162 163    def default(self, o):164        """Implement this method in a subclass such that it returns165        a serializable object for ``o``, or calls the base implementation166        (to raise a ``TypeError``).167 168        For example, to support arbitrary iterators, you could169        implement default like this::170 171            def default(self, o):172                try:173                    iterable = iter(o)174                except TypeError:175                    pass176                else:177                    return list(iterable)178                # Let the base class default method raise the TypeError179                return super().default(o)180 181        """182        raise TypeError(f'Object of type {o.__class__.__name__} '183                        f'is not JSON serializable')184 185    def encode(self, o):186        """Return a JSON string representation of a Python data structure.187 188        >>> from json.encoder import JSONEncoder189        >>> JSONEncoder().encode({"foo": ["bar", "baz"]})190        '{"foo": ["bar", "baz"]}'191 192        """193        # This is for extremely simple cases and benchmarks.194        if isinstance(o, str):195            if self.ensure_ascii:196                return encode_basestring_ascii(o)197            else:198                return encode_basestring(o)199        # This doesn't pass the iterator directly to ''.join() because the200        # exceptions aren't as detailed.  The list call should be roughly201        # equivalent to the PySequence_Fast that ''.join() would do.202        chunks = self.iterencode(o, _one_shot=True)203        if not isinstance(chunks, (list, tuple)):204            chunks = list(chunks)205        return ''.join(chunks)206 207    def iterencode(self, o, _one_shot=False):208        """Encode the given object and yield each string209        representation as available.210 211        For example::212 213            for chunk in JSONEncoder().iterencode(bigobject):214                mysocket.write(chunk)215 216        """217        if self.check_circular:218            markers = {}219        else:220            markers = None221        if self.ensure_ascii:222            _encoder = encode_basestring_ascii223        else:224            _encoder = encode_basestring225 226        def floatstr(o, allow_nan=self.allow_nan,227                _repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):228            # Check for specials.  Note that this type of test is processor229            # and/or platform-specific, so do tests which don't depend on the230            # internals.231 232            if o != o:233                text = 'NaN'234            elif o == _inf:235                text = 'Infinity'236            elif o == _neginf:237                text = '-Infinity'238            else:239                return _repr(o)240 241            if not allow_nan:242                raise ValueError(243                    "Out of range float values are not JSON compliant: " +244                    repr(o))245 246            return text247 248 249        if self.indent is None or isinstance(self.indent, str):250            indent = self.indent251        else:252            indent = ' ' * self.indent253        if _one_shot and c_make_encoder is not None:254            _iterencode = c_make_encoder(255                markers, self.default, _encoder, indent,256                self.key_separator, self.item_separator, self.sort_keys,257                self.skipkeys, self.allow_nan)258        else:259            _iterencode = _make_iterencode(260                markers, self.default, _encoder, indent, floatstr,261                self.key_separator, self.item_separator, self.sort_keys,262                self.skipkeys, _one_shot)263        return _iterencode(o, 0)264 265def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,266        _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,267        ## HACK: hand-optimized bytecode; turn globals into locals268        ValueError=ValueError,269        dict=dict,270        float=float,271        id=id,272        int=int,273        isinstance=isinstance,274        list=list,275        str=str,276        tuple=tuple,277        _intstr=int.__repr__,278    ):279 280    def _iterencode_list(lst, _current_indent_level):281        if not lst:282            yield '[]'283            return284        if markers is not None:285            markerid = id(lst)286            if markerid in markers:287                raise ValueError("Circular reference detected")288            markers[markerid] = lst289        buf = '['290        if _indent is not None:291            _current_indent_level += 1292            newline_indent = '\n' + _indent * _current_indent_level293            separator = _item_separator + newline_indent294            buf += newline_indent295        else:296            newline_indent = None297            separator = _item_separator298        for i, value in enumerate(lst):299            if i:300                buf = separator301            try:302                if isinstance(value, str):303                    yield buf + _encoder(value)304                elif value is None:305                    yield buf + 'null'306                elif value is True:307                    yield buf + 'true'308                elif value is False:309                    yield buf + 'false'310                elif isinstance(value, int):311                    # Subclasses of int/float may override __repr__, but we still312                    # want to encode them as integers/floats in JSON. One example313                    # within the standard library is IntEnum.314                    yield buf + _intstr(value)315                elif isinstance(value, float):316                    # see comment above for int317                    yield buf + _floatstr(value)318                else:319                    yield buf320                    if isinstance(value, (list, tuple)):321                        chunks = _iterencode_list(value, _current_indent_level)322                    elif isinstance(value, dict):323                        chunks = _iterencode_dict(value, _current_indent_level)324                    else:325                        chunks = _iterencode(value, _current_indent_level)326                    yield from chunks327            except GeneratorExit:328                raise329            except BaseException as exc:330                exc.add_note(f'when serializing {type(lst).__name__} item {i}')331                raise332        if newline_indent is not None:333            _current_indent_level -= 1334            yield '\n' + _indent * _current_indent_level335        yield ']'336        if markers is not None:337            del markers[markerid]338 339    def _iterencode_dict(dct, _current_indent_level):340        if not dct:341            yield '{}'342            return343        if markers is not None:344            markerid = id(dct)345            if markerid in markers:346                raise ValueError("Circular reference detected")347            markers[markerid] = dct348        yield '{'349        if _indent is not None:350            _current_indent_level += 1351            newline_indent = '\n' + _indent * _current_indent_level352            item_separator = _item_separator + newline_indent353        else:354            newline_indent = None355            item_separator = _item_separator356        first = True357        if _sort_keys:358            items = sorted(dct.items())359        else:360            items = dct.items()361        for key, value in items:362            if isinstance(key, str):363                pass364            # JavaScript is weakly typed for these, so it makes sense to365            # also allow them.  Many encoders seem to do something like this.366            elif isinstance(key, float):367                # see comment for int/float in _make_iterencode368                key = _floatstr(key)369            elif key is True:370                key = 'true'371            elif key is False:372                key = 'false'373            elif key is None:374                key = 'null'375            elif isinstance(key, int):376                # see comment for int/float in _make_iterencode377                key = _intstr(key)378            elif _skipkeys:379                continue380            else:381                raise TypeError(f'keys must be str, int, float, bool or None, '382                                f'not {key.__class__.__name__}')383            if first:384                first = False385                if newline_indent is not None:386                    yield newline_indent387            else:388                yield item_separator389            yield _encoder(key)390            yield _key_separator391            try:392                if isinstance(value, str):393                    yield _encoder(value)394                elif value is None:395                    yield 'null'396                elif value is True:397                    yield 'true'398                elif value is False:399                    yield 'false'400                elif isinstance(value, int):401                    # see comment for int/float in _make_iterencode402                    yield _intstr(value)403                elif isinstance(value, float):404                    # see comment for int/float in _make_iterencode405                    yield _floatstr(value)406                else:407                    if isinstance(value, (list, tuple)):408                        chunks = _iterencode_list(value, _current_indent_level)409                    elif isinstance(value, dict):410                        chunks = _iterencode_dict(value, _current_indent_level)411                    else:412                        chunks = _iterencode(value, _current_indent_level)413                    yield from chunks414            except GeneratorExit:415                raise416            except BaseException as exc:417                exc.add_note(f'when serializing {type(dct).__name__} item {key!r}')418                raise419        if not first and newline_indent is not None:420            _current_indent_level -= 1421            yield '\n' + _indent * _current_indent_level422        yield '}'423        if markers is not None:424            del markers[markerid]425 426    def _iterencode(o, _current_indent_level):427        if isinstance(o, str):428            yield _encoder(o)429        elif o is None:430            yield 'null'431        elif o is True:432            yield 'true'433        elif o is False:434            yield 'false'435        elif isinstance(o, int):436            # see comment for int/float in _make_iterencode437            yield _intstr(o)438        elif isinstance(o, float):439            # see comment for int/float in _make_iterencode440            yield _floatstr(o)441        elif isinstance(o, (list, tuple)):442            yield from _iterencode_list(o, _current_indent_level)443        elif isinstance(o, dict):444            yield from _iterencode_dict(o, _current_indent_level)445        else:446            if markers is not None:447                markerid = id(o)448                if markerid in markers:449                    raise ValueError("Circular reference detected")450                markers[markerid] = o451            newobj = _default(o)452            try:453                yield from _iterencode(newobj, _current_indent_level)454            except GeneratorExit:455                raise456            except BaseException as exc:457                exc.add_note(f'when serializing {type(o).__name__} object')458                raise459            if markers is not None:460                del markers[markerid]461    return _iterencode462 
codekingpro/portable-devtools · Team Ai