From 3d03547c61d891df556c009541233f4cc5aa4ec8 Mon Sep 17 00:00:00 2001 From: Isi <86603298+Isi-dev@users.noreply.github.com> Date: Mon, 5 Aug 2024 20:52:19 +0100 Subject: [PATCH] Add files via upload --- lib/rotary_embedding_torch/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 376 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 349 bytes .../rotary_embedding_torch.cpython-310.pyc | Bin 0 -> 7479 bytes .../rotary_embedding_torch.cpython-39.pyc | Bin 0 -> 7411 bytes .../rotary_embedding_torch.py | 291 +++++++ lib/simplejson/__init__.py | 562 +++++++++++++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 20943 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 20646 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 995 bytes .../__pycache__/compat.cpython-39.pyc | Bin 0 -> 958 bytes .../__pycache__/decoder.cpython-310.pyc | Bin 0 -> 11417 bytes .../__pycache__/decoder.cpython-39.pyc | Bin 0 -> 11405 bytes .../__pycache__/encoder.cpython-310.pyc | Bin 0 -> 19058 bytes .../__pycache__/encoder.cpython-39.pyc | Bin 0 -> 19022 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 2078 bytes .../__pycache__/errors.cpython-39.pyc | Bin 0 -> 2027 bytes .../__pycache__/ordered_dict.cpython-39.pyc | Bin 0 -> 3885 bytes .../__pycache__/raw_json.cpython-310.pyc | Bin 0 -> 633 bytes .../__pycache__/raw_json.cpython-39.pyc | Bin 0 -> 596 bytes .../__pycache__/scanner.cpython-310.pyc | Bin 0 -> 2291 bytes .../__pycache__/scanner.cpython-39.pyc | Bin 0 -> 2304 bytes .../__pycache__/tool.cpython-39.pyc | Bin 0 -> 1251 bytes lib/simplejson/compat.py | 34 + lib/simplejson/decoder.py | 416 ++++++++++ lib/simplejson/encoder.py | 740 ++++++++++++++++++ lib/simplejson/errors.py | 53 ++ lib/simplejson/ordered_dict.py | 103 +++ lib/simplejson/raw_json.py | 9 + lib/simplejson/scanner.py | 85 ++ lib/simplejson/tests/__init__.py | 91 +++ lib/simplejson/tests/_cibw_runner.py | 7 + lib/simplejson/tests/test_bigint_as_string.py | 67 ++ .../tests/test_bitsize_int_as_string.py | 73 ++ lib/simplejson/tests/test_check_circular.py | 30 + lib/simplejson/tests/test_decimal.py | 71 ++ lib/simplejson/tests/test_decode.py | 127 +++ lib/simplejson/tests/test_default.py | 9 + lib/simplejson/tests/test_dump.py | 249 ++++++ .../tests/test_encode_basestring_ascii.py | 47 ++ lib/simplejson/tests/test_encode_for_html.py | 38 + lib/simplejson/tests/test_errors.py | 68 ++ lib/simplejson/tests/test_fail.py | 178 +++++ lib/simplejson/tests/test_float.py | 38 + lib/simplejson/tests/test_for_json.py | 97 +++ lib/simplejson/tests/test_indent.py | 86 ++ lib/simplejson/tests/test_item_sort_key.py | 27 + lib/simplejson/tests/test_iterable.py | 31 + lib/simplejson/tests/test_namedtuple.py | 174 ++++ lib/simplejson/tests/test_pass1.py | 71 ++ lib/simplejson/tests/test_pass2.py | 14 + lib/simplejson/tests/test_pass3.py | 20 + lib/simplejson/tests/test_raw_json.py | 47 ++ lib/simplejson/tests/test_recursion.py | 67 ++ lib/simplejson/tests/test_scanstring.py | 200 +++++ lib/simplejson/tests/test_separators.py | 42 + lib/simplejson/tests/test_speedups.py | 114 +++ lib/simplejson/tests/test_str_subclass.py | 21 + lib/simplejson/tests/test_subclass.py | 37 + lib/simplejson/tests/test_tool.py | 114 +++ lib/simplejson/tests/test_tuple.py | 47 ++ lib/simplejson/tests/test_unicode.py | 154 ++++ lib/simplejson/tool.py | 42 + test_func/save_targer_keys.py | 108 +++ test_func/test_EndDec.py | 95 +++ test_func/test_dataset.py | 152 ++++ test_func/test_models.py | 56 ++ test_func/test_save_video.py | 24 + 68 files changed, 5232 insertions(+) create mode 100644 lib/rotary_embedding_torch/__init__.py create mode 100644 lib/rotary_embedding_torch/__pycache__/__init__.cpython-310.pyc create mode 100644 lib/rotary_embedding_torch/__pycache__/__init__.cpython-39.pyc create mode 100644 lib/rotary_embedding_torch/__pycache__/rotary_embedding_torch.cpython-310.pyc create mode 100644 lib/rotary_embedding_torch/__pycache__/rotary_embedding_torch.cpython-39.pyc create mode 100644 lib/rotary_embedding_torch/rotary_embedding_torch.py create mode 100644 lib/simplejson/__init__.py create mode 100644 lib/simplejson/__pycache__/__init__.cpython-310.pyc create mode 100644 lib/simplejson/__pycache__/__init__.cpython-39.pyc create mode 100644 lib/simplejson/__pycache__/compat.cpython-310.pyc create mode 100644 lib/simplejson/__pycache__/compat.cpython-39.pyc create mode 100644 lib/simplejson/__pycache__/decoder.cpython-310.pyc create mode 100644 lib/simplejson/__pycache__/decoder.cpython-39.pyc create mode 100644 lib/simplejson/__pycache__/encoder.cpython-310.pyc create mode 100644 lib/simplejson/__pycache__/encoder.cpython-39.pyc create mode 100644 lib/simplejson/__pycache__/errors.cpython-310.pyc create mode 100644 lib/simplejson/__pycache__/errors.cpython-39.pyc create mode 100644 lib/simplejson/__pycache__/ordered_dict.cpython-39.pyc create mode 100644 lib/simplejson/__pycache__/raw_json.cpython-310.pyc create mode 100644 lib/simplejson/__pycache__/raw_json.cpython-39.pyc create mode 100644 lib/simplejson/__pycache__/scanner.cpython-310.pyc create mode 100644 lib/simplejson/__pycache__/scanner.cpython-39.pyc create mode 100644 lib/simplejson/__pycache__/tool.cpython-39.pyc create mode 100644 lib/simplejson/compat.py create mode 100644 lib/simplejson/decoder.py create mode 100644 lib/simplejson/encoder.py create mode 100644 lib/simplejson/errors.py create mode 100644 lib/simplejson/ordered_dict.py create mode 100644 lib/simplejson/raw_json.py create mode 100644 lib/simplejson/scanner.py create mode 100644 lib/simplejson/tests/__init__.py create mode 100644 lib/simplejson/tests/_cibw_runner.py create mode 100644 lib/simplejson/tests/test_bigint_as_string.py create mode 100644 lib/simplejson/tests/test_bitsize_int_as_string.py create mode 100644 lib/simplejson/tests/test_check_circular.py create mode 100644 lib/simplejson/tests/test_decimal.py create mode 100644 lib/simplejson/tests/test_decode.py create mode 100644 lib/simplejson/tests/test_default.py create mode 100644 lib/simplejson/tests/test_dump.py create mode 100644 lib/simplejson/tests/test_encode_basestring_ascii.py create mode 100644 lib/simplejson/tests/test_encode_for_html.py create mode 100644 lib/simplejson/tests/test_errors.py create mode 100644 lib/simplejson/tests/test_fail.py create mode 100644 lib/simplejson/tests/test_float.py create mode 100644 lib/simplejson/tests/test_for_json.py create mode 100644 lib/simplejson/tests/test_indent.py create mode 100644 lib/simplejson/tests/test_item_sort_key.py create mode 100644 lib/simplejson/tests/test_iterable.py create mode 100644 lib/simplejson/tests/test_namedtuple.py create mode 100644 lib/simplejson/tests/test_pass1.py create mode 100644 lib/simplejson/tests/test_pass2.py create mode 100644 lib/simplejson/tests/test_pass3.py create mode 100644 lib/simplejson/tests/test_raw_json.py create mode 100644 lib/simplejson/tests/test_recursion.py create mode 100644 lib/simplejson/tests/test_scanstring.py create mode 100644 lib/simplejson/tests/test_separators.py create mode 100644 lib/simplejson/tests/test_speedups.py create mode 100644 lib/simplejson/tests/test_str_subclass.py create mode 100644 lib/simplejson/tests/test_subclass.py create mode 100644 lib/simplejson/tests/test_tool.py create mode 100644 lib/simplejson/tests/test_tuple.py create mode 100644 lib/simplejson/tests/test_unicode.py create mode 100644 lib/simplejson/tool.py create mode 100644 test_func/save_targer_keys.py create mode 100644 test_func/test_EndDec.py create mode 100644 test_func/test_dataset.py create mode 100644 test_func/test_models.py create mode 100644 test_func/test_save_video.py diff --git a/lib/rotary_embedding_torch/__init__.py b/lib/rotary_embedding_torch/__init__.py new file mode 100644 index 0000000..3a2cfef --- /dev/null +++ b/lib/rotary_embedding_torch/__init__.py @@ -0,0 +1,6 @@ +from ..rotary_embedding_torch.rotary_embedding_torch import ( + apply_rotary_emb, + RotaryEmbedding, + apply_learned_rotations, + broadcat +) diff --git a/lib/rotary_embedding_torch/__pycache__/__init__.cpython-310.pyc b/lib/rotary_embedding_torch/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e53268779dbbcf819fcaca925cfa34dc68e6132b GIT binary patch literal 376 zcmZvW&q@O^5XQ5ADn%%I^U@dCgM9!gq7)BaJSclv0z-C_)<}|BlGL&f;xmXZKz^B-d^7oQGC3tNem~!rZ}I+0#sA1-aTAZ5MsUJ2MRe9=I&X4aG=(mk zG9x^HB31F7v{f0-S>LMxEP7@K5V{R#kGuR%w}NwNR^ehVQG!_`_)h928W+Z`MaDbk zAF5Gv`L|*}2Oe$rJUiaD>3drwlnJAV4`NSJp78U!xT3Wa)=}x?3(^JZMHI--*Hh>$1(oNjES>>0yQBtB=#)Gw_Q{aq}D``M$d>l8#O>rf ugXab{1jVng;U0sU_Rv1TQhC1pQW% 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

-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 literal 0 HcmV?d00001 diff --git a/lib/rotary_embedding_torch/__pycache__/rotary_embedding_torch.cpython-39.pyc b/lib/rotary_embedding_torch/__pycache__/rotary_embedding_torch.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37902f15d94fc6173a9f62b30d8a8ee38d8e4c6a GIT binary patch literal 7411 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 literal 0 HcmV?d00001 diff --git a/lib/rotary_embedding_torch/rotary_embedding_torch.py b/lib/rotary_embedding_torch/rotary_embedding_torch.py new file mode 100644 index 0000000..8937875 --- /dev/null +++ b/lib/rotary_embedding_torch/rotary_embedding_torch.py @@ -0,0 +1,291 @@ +from __future__ import annotations +from math import pi, log + +import torch +from torch.nn import Module, ModuleList +from torch.cuda.amp import autocast +from torch import nn, einsum, broadcast_tensors, Tensor + +from einops import rearrange, repeat + +from typing import Literal + +# helper functions + +def exists(val): + return val is not None + +def default(val, d): + return val if exists(val) else d + +# broadcat, as tortoise-tts was using it + +def broadcat(tensors, dim = -1): + broadcasted_tensors = broadcast_tensors(*tensors) + return torch.cat(broadcasted_tensors, dim = dim) + +# rotary embedding helper functions + +def rotate_half(x): + x = rearrange(x, '... (d r) -> ... d r', r = 2) + x1, x2 = x.unbind(dim = -1) + x = torch.stack((-x2, x1), dim = -1) + return rearrange(x, '... d r -> ... (d r)') + +@autocast(enabled = False) +def apply_rotary_emb(freqs, t, start_index = 0, scale = 1., seq_dim = -2): + dtype = t.dtype + + if t.ndim == 3: + seq_len = t.shape[seq_dim] + freqs = freqs[-seq_len:] + + rot_dim = freqs.shape[-1] + end_index = start_index + rot_dim + + assert rot_dim <= t.shape[-1], f'feature dimension {t.shape[-1]} is not of sufficient size to rotate in all the positions {rot_dim}' + + t_left, t, t_right = t[..., :start_index], t[..., start_index:end_index], t[..., end_index:] + t = (t * freqs.cos() * scale) + (rotate_half(t) * freqs.sin() * scale) + out = torch.cat((t_left, t, t_right), dim = -1) + + return out.type(dtype) + +# learned rotation helpers + +def apply_learned_rotations(rotations, t, start_index = 0, freq_ranges = None): + if exists(freq_ranges): + rotations = einsum('..., f -> ... f', rotations, freq_ranges) + rotations = rearrange(rotations, '... r f -> ... (r f)') + + rotations = repeat(rotations, '... n -> ... (n r)', r = 2) + return apply_rotary_emb(rotations, t, start_index = start_index) + +# classes + +class RotaryEmbedding(Module): + def __init__( + self, + dim, + custom_freqs: Tensor | None = None, + freqs_for: Literal['lang', 'pixel', 'constant'] = 'lang', + theta = 10000, + max_freq = 10, + num_freqs = 1, + learned_freq = False, + use_xpos = False, + xpos_scale_base = 512, + interpolate_factor = 1., + theta_rescale_factor = 1., + seq_before_head_dim = False, + cache_if_possible = True + ): + super().__init__() + # proposed by reddit user bloc97, to rescale rotary embeddings to longer sequence length without fine-tuning + # has some connection to NTK literature + # https://www.reddit.com/r/LocalLLaMA/comments/14lz7j5/ntkaware_scaled_rope_allows_llama_models_to_have/ + + theta *= theta_rescale_factor ** (dim / (dim - 2)) + + self.freqs_for = freqs_for + + if exists(custom_freqs): + freqs = custom_freqs + elif freqs_for == 'lang': + freqs = 1. / (theta ** (torch.arange(0, dim, 2)[:(dim // 2)].float() / dim)) + elif freqs_for == 'pixel': + freqs = torch.linspace(1., max_freq / 2, dim // 2) * pi + elif freqs_for == 'constant': + freqs = torch.ones(num_freqs).float() + + self.cache_if_possible = cache_if_possible + + self.tmp_store('cached_freqs', None) + self.tmp_store('cached_scales', None) + + self.freqs = nn.Parameter(freqs, requires_grad = learned_freq) + + self.learned_freq = learned_freq + + # dummy for device + + self.tmp_store('dummy', torch.tensor(0)) + + # default sequence dimension + + self.seq_before_head_dim = seq_before_head_dim + self.default_seq_dim = -3 if seq_before_head_dim else -2 + + # interpolation factors + + assert interpolate_factor >= 1. + self.interpolate_factor = interpolate_factor + + # xpos + + self.use_xpos = use_xpos + if not use_xpos: + self.tmp_store('scale', None) + return + + scale = (torch.arange(0, dim, 2) + 0.4 * dim) / (1.4 * dim) + self.scale_base = xpos_scale_base + self.tmp_store('scale', scale) + + # add apply_rotary_emb as static method + + self.apply_rotary_emb = staticmethod(apply_rotary_emb) + + @property + def device(self): + return self.dummy.device + + def tmp_store(self, key, value): + self.register_buffer(key, value, persistent = False) + + def get_seq_pos(self, seq_len, device, dtype, offset = 0): + return (torch.arange(seq_len, device = device, dtype = dtype) + offset) / self.interpolate_factor + + def rotate_queries_or_keys(self, t, seq_dim = None, offset = 0, scale = None): + seq_dim = default(seq_dim, self.default_seq_dim) + + assert not self.use_xpos or exists(scale), 'you must use `.rotate_queries_and_keys` method instead and pass in both queries and keys, for length extrapolatable rotary embeddings' + + device, dtype, seq_len = t.device, t.dtype, t.shape[seq_dim] + + seq = self.get_seq_pos(seq_len, device = device, dtype = dtype, offset = offset) + + freqs = self.forward(seq, seq_len = seq_len, offset = offset) + + if seq_dim == -3: + freqs = rearrange(freqs, 'n d -> n 1 d') + + return apply_rotary_emb(freqs, t, scale = default(scale, 1.), seq_dim = seq_dim) + + def rotate_queries_with_cached_keys(self, q, k, seq_dim = None, offset = 0): + dtype, device, seq_dim = q.dtype, q.device, default(seq_dim, self.default_seq_dim) + + q_len, k_len = q.shape[seq_dim], k.shape[seq_dim] + assert q_len <= k_len + + q_scale = k_scale = 1. + + if self.use_xpos: + seq = self.get_seq_pos(k_len, dtype = dtype, device = device) + + q_scale = self.get_scale(seq[-q_len:]).type(dtype) + k_scale = self.get_scale(seq).type(dtype) + + rotated_q = self.rotate_queries_or_keys(q, seq_dim = seq_dim, scale = q_scale, offset = k_len - q_len + offset) + rotated_k = self.rotate_queries_or_keys(k, seq_dim = seq_dim, scale = k_scale ** -1) + + rotated_q = rotated_q.type(q.dtype) + rotated_k = rotated_k.type(k.dtype) + + return rotated_q, rotated_k + + def rotate_queries_and_keys(self, q, k, seq_dim = None): + seq_dim = default(seq_dim, self.default_seq_dim) + + assert self.use_xpos + device, dtype, seq_len = q.device, q.dtype, q.shape[seq_dim] + + seq = self.get_seq_pos(seq_len, dtype = dtype, device = device) + + freqs = self.forward(seq, seq_len = seq_len) + scale = self.get_scale(seq, seq_len = seq_len).to(dtype) + + if seq_dim == -3: + freqs = rearrange(freqs, 'n d -> n 1 d') + scale = rearrange(scale, 'n d -> n 1 d') + + rotated_q = apply_rotary_emb(freqs, q, scale = scale, seq_dim = seq_dim) + rotated_k = apply_rotary_emb(freqs, k, scale = scale ** -1, seq_dim = seq_dim) + + rotated_q = rotated_q.type(q.dtype) + rotated_k = rotated_k.type(k.dtype) + + return rotated_q, rotated_k + + def get_scale( + self, + t: Tensor, + seq_len: int | None = None, + offset = 0 + ): + assert self.use_xpos + + should_cache = ( + self.cache_if_possible and + exists(seq_len) + ) + + if ( + should_cache and \ + exists(self.cached_scales) and \ + (seq_len + offset) <= self.cached_scales.shape[0] + ): + return self.cached_scales[offset:(offset + seq_len)] + + scale = 1. + if self.use_xpos: + power = (t - len(t) // 2) / self.scale_base + scale = self.scale ** rearrange(power, 'n -> n 1') + scale = torch.cat((scale, scale), dim = -1) + + if should_cache: + self.tmp_store('cached_scales', scale) + + return scale + + def get_axial_freqs(self, *dims): + Colon = slice(None) + all_freqs = [] + + for ind, dim in enumerate(dims): + if self.freqs_for == 'pixel': + pos = torch.linspace(-1, 1, steps = dim, device = self.device) + else: + pos = torch.arange(dim, device = self.device) + + freqs = self.forward(pos, seq_len = dim) + + all_axis = [None] * len(dims) + all_axis[ind] = Colon + + new_axis_slice = (Ellipsis, *all_axis, Colon) + all_freqs.append(freqs[new_axis_slice]) + + all_freqs = broadcast_tensors(*all_freqs) + return torch.cat(all_freqs, dim = -1) + + @autocast(enabled = False) + def forward( + self, + t: Tensor, + seq_len = None, + offset = 0 + ): + should_cache = ( + self.cache_if_possible and \ + not self.learned_freq and \ + exists(seq_len) and \ + self.freqs_for != 'pixel' + ) + + if ( + should_cache and \ + exists(self.cached_freqs) and \ + (offset + seq_len) <= self.cached_freqs.shape[0] + ): + return self.cached_freqs[offset:(offset + seq_len)].detach() + + freqs = self.freqs + + freqs = einsum('..., f -> ... f', t.type(freqs.dtype), freqs) + freqs = repeat(freqs, '... n -> ... (n r)', r = 2) + + if should_cache: + self.tmp_store('cached_freqs', freqs.detach()) + + return freqs diff --git a/lib/simplejson/__init__.py b/lib/simplejson/__init__.py new file mode 100644 index 0000000..2d1900d --- /dev/null +++ b/lib/simplejson/__init__.py @@ -0,0 +1,562 @@ +r"""JSON (JavaScript Object Notation) is a subset of +JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data +interchange format. + +:mod:`simplejson` exposes an API familiar to users of the standard library +:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained +version of the :mod:`json` library contained in Python 2.6, but maintains +compatibility back to Python 2.5 and (currently) has significant performance +advantages, even without using the optional C extension for speedups. + +Encoding basic Python object hierarchies:: + + >>> import simplejson as json + >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) + '["foo", {"bar": ["baz", null, 1.0, 2]}]' + >>> print(json.dumps("\"foo\bar")) + "\"foo\bar" + >>> print(json.dumps(u'\u1234')) + "\u1234" + >>> print(json.dumps('\\')) + "\\" + >>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)) + {"a": 0, "b": 0, "c": 0} + >>> from simplejson.compat import StringIO + >>> io = StringIO() + >>> json.dump(['streaming API'], io) + >>> io.getvalue() + '["streaming API"]' + +Compact encoding:: + + >>> import simplejson as json + >>> obj = [1,2,3,{'4': 5, '6': 7}] + >>> json.dumps(obj, separators=(',',':'), sort_keys=True) + '[1,2,3,{"4":5,"6":7}]' + +Pretty printing:: + + >>> import simplejson as json + >>> print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=' ')) + { + "4": 5, + "6": 7 + } + +Decoding JSON:: + + >>> import simplejson as json + >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] + >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj + True + >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar' + True + >>> from simplejson.compat import StringIO + >>> io = StringIO('["streaming API"]') + >>> json.load(io)[0] == 'streaming API' + True + +Specializing JSON object decoding:: + + >>> import simplejson as json + >>> def as_complex(dct): + ... if '__complex__' in dct: + ... return complex(dct['real'], dct['imag']) + ... return dct + ... + >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}', + ... object_hook=as_complex) + (1+2j) + >>> from decimal import Decimal + >>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1') + True + +Specializing JSON object encoding:: + + >>> import simplejson as json + >>> def encode_complex(obj): + ... if isinstance(obj, complex): + ... return [obj.real, obj.imag] + ... raise TypeError('Object of type %s is not JSON serializable' % + ... obj.__class__.__name__) + ... + >>> json.dumps(2 + 1j, default=encode_complex) + '[2.0, 1.0]' + >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j) + '[2.0, 1.0]' + >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j)) + '[2.0, 1.0]' + +Using simplejson.tool from the shell to validate and pretty-print:: + + $ echo '{"json":"obj"}' | python -m simplejson.tool + { + "json": "obj" + } + $ echo '{ 1.2:3.4}' | python -m simplejson.tool + Expecting property name: line 1 column 3 (char 2) + +Parsing multiple documents serialized as JSON lines (newline-delimited JSON):: + + >>> import simplejson as json + >>> def loads_lines(docs): + ... for doc in docs.splitlines(): + ... yield json.loads(doc) + ... + >>> sum(doc["count"] for doc in loads_lines('{"count":1}\n{"count":2}\n{"count":3}\n')) + 6 + +Serializing multiple objects to JSON lines (newline-delimited JSON):: + + >>> import simplejson as json + >>> def dumps_lines(objs): + ... for obj in objs: + ... yield json.dumps(obj, separators=(',',':')) + '\n' + ... + >>> ''.join(dumps_lines([{'count': 1}, {'count': 2}, {'count': 3}])) + '{"count":1}\n{"count":2}\n{"count":3}\n' + +""" +from __future__ import absolute_import +__version__ = '3.19.2' +__all__ = [ + 'dump', 'dumps', 'load', 'loads', + 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', + 'OrderedDict', 'simple_first', 'RawJSON' +] + +__author__ = 'Bob Ippolito ' + +from decimal import Decimal + +from .errors import JSONDecodeError +from .raw_json import RawJSON +from .decoder import JSONDecoder +from .encoder import JSONEncoder, JSONEncoderForHTML +def _import_OrderedDict(): + import collections + try: + return collections.OrderedDict + except AttributeError: + from . import ordered_dict + return ordered_dict.OrderedDict +OrderedDict = _import_OrderedDict() + +def _import_c_make_encoder(): + try: + from ._speedups import make_encoder + return make_encoder + except ImportError: + return None + +_default_encoder = JSONEncoder() + +def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, + allow_nan=False, cls=None, indent=None, separators=None, + encoding='utf-8', default=None, use_decimal=True, + namedtuple_as_object=True, tuple_as_array=True, + bigint_as_string=False, sort_keys=False, item_sort_key=None, + for_json=False, ignore_nan=False, int_as_string_bitcount=None, + iterable_as_array=False, **kw): + """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a + ``.write()``-supporting file-like object). + + If *skipkeys* is true then ``dict`` keys that are not basic types + (``str``, ``int``, ``long``, ``float``, ``bool``, ``None``) + will be skipped instead of raising a ``TypeError``. + + If *ensure_ascii* is false (default: ``True``), then the output may + contain non-ASCII characters, so long as they do not need to be escaped + by JSON. When it is true, all non-ASCII characters are escaped. + + If *allow_nan* is true (default: ``False``), then out of range ``float`` + values (``nan``, ``inf``, ``-inf``) will be serialized to + their JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``) + instead of raising a ValueError. See + *ignore_nan* for ECMA-262 compliant behavior. + + If *indent* is a string, then JSON array elements and object members + will be pretty-printed with a newline followed by that string repeated + for each level of nesting. ``None`` (the default) selects the most compact + representation without any newlines. + + 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. + + *encoding* is the character encoding for str instances, default is UTF-8. + + *default(obj)* is a function that should return a serializable version + of obj or raise ``TypeError``. The default simply raises ``TypeError``. + + If *use_decimal* is true (default: ``True``) then decimal.Decimal + will be natively serialized to JSON with full precision. + + If *namedtuple_as_object* is true (default: ``True``), + :class:`tuple` subclasses with ``_asdict()`` methods will be encoded + as JSON objects. + + If *tuple_as_array* is true (default: ``True``), + :class:`tuple` (and subclasses) will be encoded as JSON arrays. + + If *iterable_as_array* is true (default: ``False``), + any object not in the above table that implements ``__iter__()`` + will be encoded as a JSON array. + + If *bigint_as_string* is true (default: ``False``), ints 2**53 and higher + or lower than -2**53 will be encoded as strings. This is to avoid the + rounding that happens in Javascript otherwise. Note that this is still a + lossy operation that will not round-trip correctly and should be used + sparingly. + + If *int_as_string_bitcount* is a positive number (n), then int of size + greater than or equal to 2**n or lower than or equal to -2**n will be + encoded as strings. + + If specified, *item_sort_key* is a callable used to sort the items in + each dictionary. This is useful if you want to sort items other than + in alphabetical order by key. This option takes precedence over + *sort_keys*. + + If *sort_keys* is true (default: ``False``), the output of dictionaries + will be sorted by item. + + If *for_json* is true (default: ``False``), objects with a ``for_json()`` + method will use the return value of that method for encoding as JSON + instead of the object. + + If *ignore_nan* is true (default: ``False``), then out of range + :class:`float` values (``nan``, ``inf``, ``-inf``) will be serialized as + ``null`` in compliance with the ECMA-262 specification. If true, this will + override *allow_nan*. + + To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the + ``.default()`` method to serialize additional types), specify it with + the ``cls`` kwarg. NOTE: You should use *default* or *for_json* instead + of subclassing whenever possible. + + """ + # cached encoder + if (not skipkeys and ensure_ascii and + check_circular and not allow_nan and + cls is None and indent is None and separators is None and + encoding == 'utf-8' and default is None and use_decimal + and namedtuple_as_object and tuple_as_array and not iterable_as_array + and not bigint_as_string and not sort_keys + and not item_sort_key and not for_json + and not ignore_nan and int_as_string_bitcount is None + and not kw + ): + iterable = _default_encoder.iterencode(obj) + else: + if cls is None: + cls = JSONEncoder + iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, + check_circular=check_circular, allow_nan=allow_nan, indent=indent, + separators=separators, encoding=encoding, + default=default, use_decimal=use_decimal, + namedtuple_as_object=namedtuple_as_object, + tuple_as_array=tuple_as_array, + iterable_as_array=iterable_as_array, + bigint_as_string=bigint_as_string, + sort_keys=sort_keys, + item_sort_key=item_sort_key, + for_json=for_json, + ignore_nan=ignore_nan, + int_as_string_bitcount=int_as_string_bitcount, + **kw).iterencode(obj) + # could accelerate with writelines in some versions of Python, at + # a debuggability cost + for chunk in iterable: + fp.write(chunk) + + +def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, + allow_nan=False, cls=None, indent=None, separators=None, + encoding='utf-8', default=None, use_decimal=True, + namedtuple_as_object=True, tuple_as_array=True, + bigint_as_string=False, sort_keys=False, item_sort_key=None, + for_json=False, ignore_nan=False, int_as_string_bitcount=None, + iterable_as_array=False, **kw): + """Serialize ``obj`` to a JSON formatted ``str``. + + If ``skipkeys`` is true then ``dict`` keys that are not basic types + (``str``, ``int``, ``long``, ``float``, ``bool``, ``None``) + will be skipped instead of raising a ``TypeError``. + + If *ensure_ascii* is false (default: ``True``), then the output may + contain non-ASCII characters, so long as they do not need to be escaped + by JSON. When it is true, all non-ASCII characters are escaped. + + If ``check_circular`` is false, then the circular reference check + for container types will be skipped and a circular reference will + result in an ``OverflowError`` (or worse). + + If *allow_nan* is true (default: ``False``), then out of range ``float`` + values (``nan``, ``inf``, ``-inf``) will be serialized to + their JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``) + instead of raising a ValueError. See + *ignore_nan* for ECMA-262 compliant behavior. + + If ``indent`` is a string, then JSON array elements and object members + will be pretty-printed with a newline followed by that string repeated + for each level of nesting. ``None`` (the default) selects the most compact + representation without any newlines. For backwards compatibility with + versions of simplejson earlier than 2.1.0, an integer is also accepted + and is converted to a string with that many spaces. + + 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. + + ``encoding`` is the character encoding for bytes instances, default is + UTF-8. + + ``default(obj)`` is a function that should return a serializable version + of obj or raise TypeError. The default simply raises TypeError. + + If *use_decimal* is true (default: ``True``) then decimal.Decimal + will be natively serialized to JSON with full precision. + + If *namedtuple_as_object* is true (default: ``True``), + :class:`tuple` subclasses with ``_asdict()`` methods will be encoded + as JSON objects. + + If *tuple_as_array* is true (default: ``True``), + :class:`tuple` (and subclasses) will be encoded as JSON arrays. + + If *iterable_as_array* is true (default: ``False``), + any object not in the above table that implements ``__iter__()`` + will be encoded as a JSON array. + + If *bigint_as_string* is true (not the default), ints 2**53 and higher + or lower than -2**53 will be encoded as strings. This is to avoid the + rounding that happens in Javascript otherwise. + + If *int_as_string_bitcount* is a positive number (n), then int of size + greater than or equal to 2**n or lower than or equal to -2**n will be + encoded as strings. + + If specified, *item_sort_key* is a callable used to sort the items in + each dictionary. This is useful if you want to sort items other than + in alphabetical order by key. This option takes precedence over + *sort_keys*. + + If *sort_keys* is true (default: ``False``), the output of dictionaries + will be sorted by item. + + If *for_json* is true (default: ``False``), objects with a ``for_json()`` + method will use the return value of that method for encoding as JSON + instead of the object. + + If *ignore_nan* is true (default: ``False``), then out of range + :class:`float` values (``nan``, ``inf``, ``-inf``) will be serialized as + ``null`` in compliance with the ECMA-262 specification. If true, this will + override *allow_nan*. + + To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the + ``.default()`` method to serialize additional types), specify it with + the ``cls`` kwarg. NOTE: You should use *default* instead of subclassing + whenever possible. + + """ + # cached encoder + if (not skipkeys and ensure_ascii and + check_circular and not allow_nan and + cls is None and indent is None and separators is None and + encoding == 'utf-8' and default is None and use_decimal + and namedtuple_as_object and tuple_as_array and not iterable_as_array + and not bigint_as_string and not sort_keys + and not item_sort_key and not for_json + and not ignore_nan and int_as_string_bitcount is None + and not kw + ): + return _default_encoder.encode(obj) + if cls is None: + cls = JSONEncoder + return cls( + skipkeys=skipkeys, ensure_ascii=ensure_ascii, + check_circular=check_circular, allow_nan=allow_nan, indent=indent, + separators=separators, encoding=encoding, default=default, + use_decimal=use_decimal, + namedtuple_as_object=namedtuple_as_object, + tuple_as_array=tuple_as_array, + iterable_as_array=iterable_as_array, + bigint_as_string=bigint_as_string, + sort_keys=sort_keys, + item_sort_key=item_sort_key, + for_json=for_json, + ignore_nan=ignore_nan, + int_as_string_bitcount=int_as_string_bitcount, + **kw).encode(obj) + + +_default_decoder = JSONDecoder() + + +def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, + parse_int=None, parse_constant=None, object_pairs_hook=None, + use_decimal=False, allow_nan=False, **kw): + """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing + a JSON document as `str` or `bytes`) to a Python object. + + *encoding* determines the encoding used to interpret any + `bytes` objects decoded by this instance (``'utf-8'`` by + default). It has no effect when decoding `str` objects. + + *object_hook*, if specified, will be called with the result of every + JSON object decoded and its return value will be used in place of the + given :class:`dict`. This can be used to provide custom + deserializations (e.g. to support JSON-RPC class hinting). + + *object_pairs_hook* is an optional function that will be called with + the result of any object literal decode with an ordered list of pairs. + The return value of *object_pairs_hook* will be used instead of the + :class:`dict`. This feature can be used to implement custom decoders + that rely on the order that the key and value pairs are decoded (for + example, :func:`collections.OrderedDict` will remember the order of + insertion). If *object_hook* is also defined, the *object_pairs_hook* + takes priority. + + *parse_float*, if specified, will be called with the string of every + JSON float to be decoded. By default, this is equivalent to + ``float(num_str)``. This can be used to use another datatype or parser + for JSON floats (e.g. :class:`decimal.Decimal`). + + *parse_int*, if specified, will be called with the string of every + JSON int to be decoded. By default, this is equivalent to + ``int(num_str)``. This can be used to use another datatype or parser + for JSON integers (e.g. :class:`float`). + + *allow_nan*, if True (default false), will allow the parser to + accept the non-standard floats ``NaN``, ``Infinity``, and ``-Infinity`` + and enable the use of the deprecated *parse_constant*. + + If *use_decimal* is true (default: ``False``) then it implies + parse_float=decimal.Decimal for parity with ``dump``. + + *parse_constant*, if specified, will be + called with one of the following strings: ``'-Infinity'``, + ``'Infinity'``, ``'NaN'``. It is not recommended to use this feature, + as it is rare to parse non-compliant JSON containing these values. + + To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` + kwarg. NOTE: You should use *object_hook* or *object_pairs_hook* instead + of subclassing whenever possible. + + """ + return loads(fp.read(), + encoding=encoding, cls=cls, object_hook=object_hook, + parse_float=parse_float, parse_int=parse_int, + parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, + use_decimal=use_decimal, allow_nan=allow_nan, **kw) + + +def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, + parse_int=None, parse_constant=None, object_pairs_hook=None, + use_decimal=False, allow_nan=False, **kw): + """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON + document) to a Python object. + + *encoding* determines the encoding used to interpret any + :class:`bytes` objects decoded by this instance (``'utf-8'`` by + default). It has no effect when decoding :class:`unicode` objects. + + *object_hook*, if specified, will be called with the result of every + JSON object decoded and its return value will be used in place of the + given :class:`dict`. This can be used to provide custom + deserializations (e.g. to support JSON-RPC class hinting). + + *object_pairs_hook* is an optional function that will be called with + the result of any object literal decode with an ordered list of pairs. + The return value of *object_pairs_hook* will be used instead of the + :class:`dict`. This feature can be used to implement custom decoders + that rely on the order that the key and value pairs are decoded (for + example, :func:`collections.OrderedDict` will remember the order of + insertion). If *object_hook* is also defined, the *object_pairs_hook* + takes priority. + + *parse_float*, if specified, will be called with the string of every + JSON float to be decoded. By default, this is equivalent to + ``float(num_str)``. This can be used to use another datatype or parser + for JSON floats (e.g. :class:`decimal.Decimal`). + + *parse_int*, if specified, will be called with the string of every + JSON int to be decoded. By default, this is equivalent to + ``int(num_str)``. This can be used to use another datatype or parser + for JSON integers (e.g. :class:`float`). + + *allow_nan*, if True (default false), will allow the parser to + accept the non-standard floats ``NaN``, ``Infinity``, and ``-Infinity`` + and enable the use of the deprecated *parse_constant*. + + If *use_decimal* is true (default: ``False``) then it implies + parse_float=decimal.Decimal for parity with ``dump``. + + *parse_constant*, if specified, will be + called with one of the following strings: ``'-Infinity'``, + ``'Infinity'``, ``'NaN'``. It is not recommended to use this feature, + as it is rare to parse non-compliant JSON containing these values. + + To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` + kwarg. NOTE: You should use *object_hook* or *object_pairs_hook* instead + of subclassing whenever possible. + + """ + if (cls is None and encoding is None and object_hook is None and + parse_int is None and parse_float is None and + parse_constant is None and object_pairs_hook is None + and not use_decimal and not allow_nan and not kw): + return _default_decoder.decode(s) + if cls is None: + cls = JSONDecoder + if object_hook is not None: + kw['object_hook'] = object_hook + if object_pairs_hook is not None: + kw['object_pairs_hook'] = object_pairs_hook + if parse_float is not None: + kw['parse_float'] = parse_float + if parse_int is not None: + kw['parse_int'] = parse_int + if parse_constant is not None: + kw['parse_constant'] = parse_constant + if use_decimal: + if parse_float is not None: + raise TypeError("use_decimal=True implies parse_float=Decimal") + kw['parse_float'] = Decimal + if allow_nan: + kw['allow_nan'] = True + return cls(encoding=encoding, **kw).decode(s) + + +def _toggle_speedups(enabled): + from . import decoder as dec + from . import encoder as enc + from . import scanner as scan + c_make_encoder = _import_c_make_encoder() + if enabled: + dec.scanstring = dec.c_scanstring or dec.py_scanstring + enc.c_make_encoder = c_make_encoder + enc.encode_basestring_ascii = (enc.c_encode_basestring_ascii or + enc.py_encode_basestring_ascii) + scan.make_scanner = scan.c_make_scanner or scan.py_make_scanner + else: + dec.scanstring = dec.py_scanstring + enc.c_make_encoder = None + enc.encode_basestring_ascii = enc.py_encode_basestring_ascii + scan.make_scanner = scan.py_make_scanner + dec.make_scanner = scan.make_scanner + global _default_decoder + _default_decoder = JSONDecoder() + global _default_encoder + _default_encoder = JSONEncoder() + +def simple_first(kv): + """Helper function to pass to item_sort_key to sort simple + elements to the top, then container elements. + """ + return (isinstance(kv[1], (list, dict, tuple)), kv[0]) diff --git a/lib/simplejson/__pycache__/__init__.cpython-310.pyc b/lib/simplejson/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c256663a22f17e1fd81aab89014572aa8b39fca GIT binary patch literal 20943 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 literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/__init__.cpython-39.pyc b/lib/simplejson/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..101c31a3dbb7c83fec94d6ae0304ec517e90b264 GIT binary patch literal 20646 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 literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/compat.cpython-310.pyc b/lib/simplejson/__pycache__/compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36285f9ea6be8eedba661110f4f07f2facacc2f0 GIT binary patch literal 995 zcmZWn-D(su6iza;v$Mb5*56eMdt1RjdRJ7`MPYB+LM_rTFzjx!ZQ7Y+NK)$*@6<=| zA$sZS;&6}+h@Gc6X(kdvHqlJ7g`o2Xu|jbQv(|G9V?AoR;SH%AQ4YnbLY7=|cf zn2`)q%<(Z{c!*eVg7ixk(ttHs^bOJQJccvPtdU1F!ssKCD3v_`UHrn5)%%5Vs zmFyd?O(KjqR>@f9i*kRGo(aj+nMn(!?R1v$>qIg?HCE-RRE(R%ULW6=;*Avf)bi2e z(O4B_l8ISjL|$b4*eIFQ= zeCuyac9xegHXgcWnld#{Qx}-hxb7!VODLHNxlk_HJ=m;pTx)*aLygjzplj>UnsDT>PR&dF5Y| p*#Z-ynDlXoV@${Zckuv|%aDW+i6G`}NY-#4cS(!~S8<4e{}*?H_wWD! literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/compat.cpython-39.pyc b/lib/simplejson/__pycache__/compat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6163c30b286b6b7250e43da1c52e879855818716 GIT binary patch literal 958 zcmZWnTWb_C6iza;v$NN3>va{SulwMQf)6617KMVem9|L3!a6g_Zqv>rOOh6+_@@2~ z@x6a3555S({smw3WM;*J8FD7)oaFn?`I4m9YamTZi+J5TF6ImxRI8Y8||U~wWWOx75NYr%VL1lKO)zB=}&C!EPlfn-FD5%gsE&Y zae*m~>z;uaLdl7cQ{{r)!;K2ZwX(lG)F_>;Vy?7(rM1$!U*VogktxPq%kmF)V#_%P zNUL2Z6*AFf9cibD;SdEmT(|yL3F87GtqXGni5@KZjO%44^2kS8cRWq6R%=oycA5hj zTmsaQixdEgxg$d9p5GV13EJ{-70M-Xs@wMpx%g>~^2|RL^B7D>V%*0ejtRj7+{J6K W_Fsf!Z%GJ|KIuY!u#87IB!2*&fa-t% literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/decoder.cpython-310.pyc b/lib/simplejson/__pycache__/decoder.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..28d0460d923a00c47766b57443f7c360863b866a GIT binary patch literal 11417 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 literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/decoder.cpython-39.pyc b/lib/simplejson/__pycache__/decoder.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..49dc5fb3ea1a48b09163a6c9ed8d091eec16d45c GIT binary patch literal 11405 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 Q{D3vt5A+V_#{SFy17o3BQvd(} literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/encoder.cpython-39.pyc b/lib/simplejson/__pycache__/encoder.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bee2c087ad393ad354608b08e7c52f22f3011554 GIT binary patch literal 19022 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 l`@>c=|CV zM9Ypcrd)W* z+!$>{nkUvOD=Mp`IJpouo6d4IvAP&E*SeM~8YkzIgOy ze2xJ6+{QC)%H$+htA$Zo*-}sA0>`wYa%KLg$UZBwX;Lb2R~+iu#VF5CMr(LRitw}d zW*1G5@<0v*huwhK<{^Fl_Fo}4o0u4;1lOwdp@irTx&lf`ka&;1k+%pIofe!DKmssN zdNWjD5d$GJ$oQ1f3YV8&QMJY()QD{#6XGWA75^8_YF<}44#qij^6Z)n&nBVngEK4 z`i(!er>2L^4S~@3s*r{tF;wu4Kc1FNA9Ksg4WYXGb+_9J!no<;0ubpMbh`y{mA?zn z1HQ$tLhf*L1CuHGKbnux19bZVgkm5Jkp(mXNqiZAFo7cu15r?_QD~?RliwhZsuRZ+ zp~vFeB(GXhi1VyG6Xlr_W1Z(3Rdy;8DYG)uMUsn|(KBVrOxc6MK%gPz1Mv;at75DT z>Z=6tTrG*IvNkzY&J0D~nh^&DM%7dmr8rR(f0h`~)!Bgut(`3sQwm2CN)R66{7f0; zjLB)7WcktwkhV@x{@X?DPm>GmEQY#Jk=wPsn>L0ko>Uv7>`WJuwkowiUe3~8U2C|k zu75Rsap!M}OBuhO4`%H7 zdbwB})IMYfWMpx->=D(7h8TtDefY47oBM7hSgs7Paz%oUvbB6Mj{IT7&0E+x@`l4` zqZzD=tqJ2eE3z_gx7_hDv`h))UD}Mw1l>QI^ literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/errors.cpython-39.pyc b/lib/simplejson/__pycache__/errors.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..28852b8e0b42a2306b6da3d193d43acd63b43d6c GIT binary patch literal 2027 zcma)7O>Z1E7`A6-Ka)9o%CKSA~^?LlgAAbEl@5UP&eTH%H$FHN^4r71P zW_1MEJjApgVUg^RNq)=^x%8xe!45syl`Yx6;D`R#Om-x{z_|*}{lk_F4p`Wmz4xUt zxe-YgTdS-nt&-yCOxScX&D7ZDx?kV==HT(*3zg(jIdI~^)pC&kHs&Kt`v6PDp2LUq zDt_rpe~Zn%3b8!%%m)>BdtYx>94Nj-ZL_&wd6hr%5K%CwdH)6MuooOl=+&(xFLhD3 zO{%5(DGX{~=1J{Ob6dBwR4bhmB-8nC%&bA>ug8z}hfl0Bc9`09oDX9iC%KmK$3vxm zw8JMl{amM$xKP7y)1#qH3$-_mlV|aH`;yWvyc~=H2h)&gY`RfoaYz=1KjxiL{?A;x^FDQDkBL!|y zPBclo$w_P=gtJd?2JF2;N$ink=)0@e9iygMoTxg0V8UMQPwcTlr7}ZFsC}iSp_CX( zTf2y{wp(2Za$9hm6ITDC`B)*TcvZ-}(nieObI8kDh zXIXxl>SGa0nHFiT<4jCVK2@ejmEG_61qMRi7vBM1>QQb`WCi%-DoIR~wWu)%Lj^Z5 zqL#p}oG4w0BSrS7u>lJm4n^MJY!RD6I0jIF&=995$|wgWrBR$_3niqqQG)Q_Dq?pM zpTV;j1kceCrxj7K3uE~@Kaq5r)3tL#$5*WCuZZN7 z9ObUqWZodi9kSM{1FN#pjY`xMub5@Fu-(P9n^+j%=IzCgdfFXtw*6AOzrPGCA+9V3 z$&^f&$a@efHl~TRjggu$QZ^1of$QmffcSb*6KK`2Fv(?^k-Q#7Ka_E{IO#+YXaon85JOj3@$Pa)jmR|! zI<(aN(SJ7j>&}OH2m2aE;w*y^`X6ZC?Jh}_o}0|o-OrkE9uUG(iwwNB-|h9+{su&( B?OFf; literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/ordered_dict.cpython-39.pyc b/lib/simplejson/__pycache__/ordered_dict.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..883171b551af15f0ac1640d9bfcfb6411ee19547 GIT binary patch literal 3885 zcmb_f&vVAeSOrWf7&*Wl1gFZH>%T+;6?D4C>mEI9kHi(O#f_ulv3TLxFI z)EKTO|N499KQoN|n+Bs-1%pRu=6wjsT1;{&V%`%i!P&2vbfo*5Nmn^a9J(!6R-UkC zbznAh+P@bi4Xyfd5UQR^vPLJ>jWCU46=qSInAI<}R9eZ6D9jo!_8Wf)_Iqg}8(*j_ zi;}L=wc5)p>pxgq3sb391H84TOcrEnHB5VJT7^+xnYB+oy?_5_AFtJFZ=fJ+@?x4k z_}l1Jl!WwT^l~wHgl7H;p;(IpkRU*>S<5M*5CmDpxFV;dhkI2{%Np)eaz@s1_vE{B zR$hJ0Thnq*&f`fGe$)tbcb9x^K5TT;tZ`R1tA!J* zq?mrX-&db&o$6xVA3@;zDv`zP<1EwBi`{Ivq!Pv|&_#8(FX8T{Q@BROox;WEP2q0; zNt#opXQ9Nm&pvz5erA+5?Z`x1X*)=Q5F`pdZmVR^w4Wu><0R_gBkkWrFWM%`)V+QX zZUtcAZZ#f_a(GGjZ(X>||)U^7cQx( zr!m_U8bQkn2UfHODaBPhv-6AS7$OCO;v~R9k_Vv=1$iEB3FuaLWY@jA`Eb?vl0zfi4*6XHk!=whU_xLrWerHq+>DT z`$lDOPtW(8l_98YwO>^Bf_PWyC0gW$yIN1eT*k}_nz4C|djRS21|M7>1v>KekQ6w( zNTYKn{TPFc9RqOAPY@dvA#e&m;ce%D9|(e)V0BqDee1IB8F}tCwSo8 zg+Q?j|KBQ;3pJ^%?~r(x1O;s=C>n~o@5A0m6iWL3Jv^CI^u{<}-Y$N6fiYxc8z2wR z$(gBVsEU+Tb55ByM}|EXCoHLD2&9F|b|tXXOdH}atOF*YUV2At1JDlm5%K~W?}!6&#Ga%79J%a>U^^$2F+>|9 zAJ2WBJNkE6i|o-szvDciH|@xp!`U3$oM=p`$mTGD)`hLVnWOZ1ga}<>UGX=u<31UI z+!Tda{ixvEpstNHO9Jcv+Ik$B3oy zhh~m6LZsK>ojQIlm6_$s6&$k@@t$mD8A-Vwbspx2UFI>sfygBg+U`6N6fQEX`5dc^ zO^SRlH@Y89UfAh8TT-xt`wJ3$-y#C=Wtf zqbW5};z)uX46fHOyi`Lh!4VR<<@cmz6@rzPnJB>Jq6^v*ajjjbI6x<~ledwl`0zP-w*-kA7=dD{T8xZJD7@NYQpblQd z%0_U(Wf{&B&hk1s?U7HuCdF(~7nEivlkC~Dv9v}0CF@yZ{1P2H3}*aL=m!~Gc8Hjz z!{W9`f106^(}_59VX(>x){#6E6z@c z;R$crt9nzmP1UBnn&(t;*c%%5 zL-d%(sjq#Do;u^~!e(Gbn!j&mK6ieeGn8NNp6WmN{w3#FGIXv{!y7b;73?!pTqTc8 zC7M5^MWWI>Hp_NzZ`!WWt+r7{F;9lGJ;LtOH!nLOtF|`DPzA2V@3R-h3jM2 z$2=D(6%9TJ{YmGjfjGG5_YCkv9L*OqK1}z+U>%&DB|{c;Q+sOp%{uy{i#iFYV*^!8SjMO67+cIzPpl26ZnZ|{$KX*j^>{)UChwnze;}wp J@r=Dr{{!b)o(BK` literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/raw_json.cpython-39.pyc b/lib/simplejson/__pycache__/raw_json.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b5399f5ef66e7ebad22b4977b0ccf031edf11e2 GIT binary patch literal 596 zcmY*V!A=`75Vdy~h*lu=SoP#<4unH*2q7w@qE=NZh$5ubN|v*pfYYqK*xn){ZtxlX z0e)!@9Oz&4#LN<;bfg)3W<2kWpW55Y8QSFe&-?|?zm#lRhRF$f_=rKXf}JtVb@Iq` z0{kH@5}i)iFk5~4RyRwi!A2F0v%<~Ag}VJd`8m!joczxc%udjIOkf2^+(h#t)rj`U zicDvSxz+8g5msL>y=sKA0&L|pXhFC_yQ(EZF?U{QKSNl?3FN9#A^_)jZGW# zT%c7%{BCq7KSd9u!9Blc62FMld_3gc?wU+4g0sV<%K|Lto<^RSCt3cTpB|Re06vr^ zn1w5qRh6?^eJ;WN4&~IEFV@s5LixkY%3vbwH>&!jt{`AWdJ*)2SGPUKsJZI~QW|Tb zlml9;-}kFm9KBH=6Hvczmc9aOJdrT~ literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/scanner.cpython-310.pyc b/lib/simplejson/__pycache__/scanner.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6798b1da46289b9bea4d96946578ddfa225aaa01 GIT binary patch literal 2291 zcmZ`)&2JM&6rY*>^j87|2tjQX0jlECM9`MDP((^Xs-_A?A_P>&XtmiH2Pf-YcXr*x z?wUhGW&2vG>Y<0ikz@Y^{)b+eYfrgU;+jM0dutmAYS)^dXWsk0nfK<+ya@}1EP?Nr zcmJsVnIq&c9K87%F!&N$Q~}_mOgQDtr)A1DuKTR6l{HGZ!OcgctP6dQlnriidy|z- zK_6Q@Bj}b5EwexXvkT-2E9ZEY=YXFVM&rE5mkXS&l48C+@y+V3(sUedi(oqP+#nD# zyAR8f(mn+&QZ=-2Y9+~l|CFkH-Q5<>aPgw1GEUSGf;StH#GO#N<$5EOak{wF(S}G|^WeM1 zE0wiK$f#0_YFlAtF|1cxYs=0~E#To!?_6eJ!Y64{CKc z7SprSi(#Wx@oO8Es8(lbG)->>iwip81AT!o)6&d;oirTgo%=kL#_Ll3ug^x-ZQpy3?R zLx6;Ak$x7C_Dw+6&&Ar7-e=G^`V`RY=K-z04QTf>fSJApnCnq8}FcQf5=H`mQq3z)=5cAo%8t1>)ykL(UjD4ZFiU{Vl^>ZTiPiWG|MzIe4)k6oF|e1|V5vPB%xcMJ5YbUs?b*#kF8_`g_-JiUWEkz1xcZa6s1;4fgTYDm`fWzM`?xW7!mU6s_*3 z_uHttek8t9MA6bdo^qv?+>)Zp`*^ODy&P0)K`m}6I=hdjt(}=2iHf?)E(cuf4vIr+ zY;MXBYKPK9z>67WMzI9Xlvd-r$`n%8qfKQ8VmJ04xKh!&vT8vrHicArRk|M7?KYGq zMf9|wvT0dz!oU;C76H^ioC*pS7&}3;zJXSCQ4duv+}MIWa2|x=wmLc-G~Aku2BKWU zm632yCsO4GvY@>Ck%*|c(Ll2U5 zZSM8H94ZD_7+w{FPhbFtl5P{3jR}8s?c3QN)G#Ok>>gbA$Mgw23vhLYy}{Ff1yI7< zNQx{ip33li;Yt{tMa{W^1|yai5OC3S7gPqTb(*oSK^9>RwrO5xG)s@O_L={U=#^Qq zAV0&|K1TQ)KxIm6Hy4&}JGYmVk)~eGq3$xmC4^5AFkE>N;UffetH_iENsi&L$uCft zy7?jYFk@=`EpLv4FnSNbgh%ARe&^WO`+82!1En~oEXU!Y=QxTXORbTwA%bys}(cQs#|YcdoCj$g8kMy3pVSOFe%L ksr&ZTddQo;xQ5w^P66lyPmxVc(`GtjaGLagY$JdDU$ag=<^TWy literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/scanner.cpython-39.pyc b/lib/simplejson/__pycache__/scanner.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f382a79a70afb5007e19d6018ed1fa5295b8bbed GIT binary patch literal 2304 zcmZ`)&2JM&6rY*>@Y>!akfcddRVacAWlIwR^pm2b1Y8jm3?c-CV`MEmJwPrUc zaqS)&D%&^Cs0VW7)<31kY7V{hlz$-y+V^IiKv28Z{5-uOd9IRfA6U%yp7 zmyo}ac>lA2_yI;-2H>PbIOVKPOOzYjth0tuGAQ8|w_lKwDa<`mvUr9&8?0mt`Z~k2 zf^Ir6vP%Row?y_?DbI5}5BjdKnh%9r8scn~cy4R#_Uhf@bP{cea5@hBFcdO(0Naw{ z0R{A^8bOVlB8a#sNEyihrAHs?I52L&h`#`6jcR8}gLVidZSsh$5|bos_dErflE)Cx zDw)^l8AZv!<_%SD!`~8>fdigV%2wj05PZ8COU#DKFE^TzOtb^iL>nSA@OOCc#?|s# zEM#1+#kI|-?1z33h1|bV7UA=_ycX83hqZ>Ei1JG9X*sSXVz%iATmFWKfoe4CVl$4y zi-Vo#n!9SE0&Li;5>(!I3f+kHxlu-4YQvCO;A#J)0kf7jGrKsmcy+$Lerfi*CuRP* z=gpMo%KU=2II}JaPu6EIJXzFafO$LmFa<*}aE0@&BH{&fyFQauV z(CPIc6~{Vc52_ceZIJwqe2`=&$**jRa0huDb%9e&^|HYG^8>vc@_7D)p1Z|fQVB`a zD-I1-98S4>1ayIiYxdF@S;uUfoNQCD;%)Oa+b3nCV|DCKrft8Z@#S^~B=>qw+d{gz zz)wvQMY>#%F(CKB{7S7rZtYGY?>!aN(i14)D`_;gs(Sb)}DYuv5V|y4o@U>TH z^#@puYxy4otB(d&6Db$0CbSjs2UbklU^NMHoTbr!Jg}NdxnMP=t$>eK@1HYXY44Nb z;YeYpDT1UHZcIP->)Yaxp4Asz(Vq_Kx}xC$UR`B|+x5Dli82$pEgmRZJA`**&DQ2UwM@?CcTCGgWRmm|mD8o4Amk3`WTtS#exP*YNc}!*Cs1qnTc@>%3)eAV& z1wQhDH{&3Q&j1j3ZvOMfK0800mkXfb4XaG0!lR&4QA`S5;E{}V#`HU-hEKj{sP5P6 zpbkDYnzg!6nTLh@OLtcbDtl*b<-zjGaQbFC5a c?YdaN6N@JRu*zKO*fw(*R^h3)rsZ7!7uKyeIsgCw literal 0 HcmV?d00001 diff --git a/lib/simplejson/__pycache__/tool.cpython-39.pyc b/lib/simplejson/__pycache__/tool.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..055935fdf2a6324708271f9e3c5dfffb83d84ed1 GIT binary patch literal 1251 zcma)5Pj4JG6t`z)cPEog)P|~1sRC<-RJKxq{An;Cm# zdy{Osdttd&<%~GAN4^H10{Os&Q@#QR#Pg7bR9x`LKfihZ{QjA(tYiq*?(aYE|CAu~ zNBFtCBKY|Nw(SFOG(a5lsK8}3h;X3eA|Ax`nG6~{;f){Apeb6sc^H}dqPakz74M>M zi^UkBEnSvO@%2I~L7dhF06AiXgrA+;qJ%QaSQ)_t8$4?OApp`u!{;us$Xt zA8B&yMQ3ca>hwGM`M5K`MP{U$x{+37y(CtaRUv}B7w)L-Uep*ooEwtbvgXd;^-MN; zoBg}Jd;i1h_DLmjC)EMOtt(;Nlqgn;KB*JjAh|9kr6QZ;lYGPs+3aT78PpMVv0puw zZbYqv#7m*vP9FGgR}91w>@C>#HWbbwhsV(Za}0I833NOUoMevG=t35O?15_pO^$Cs z-51e?)`JVJ1hmY5wEnS*z^VaOSgpBc?WYNx*86CIzsEE5>LEs_*IjFz&Jf@dPx;cz zcpg1Qs*@m>O@GDEZ;XQN>*Y5vA2({tCrCwi&|{dN1il4Kg1WMS>~D8!ZH%74Im54d zVA&eCXVDCU=M47p%SMpAUg7OG7{BXbZ3F#??aj+RID$!A**SxPp|dc#9-FgJOOKCD zV4l85o=UYZ3qhXhi3`NDXWw=se-*|EI!P-gjin>45B>7Q3d%(;OIDmFVRE{$U$WXb zdMKvWH>KjxI1~Ehan@b+aUqnCEyxmP4vu`oIxdxO!U3201SUlJYYo$a*k`!8gL@m36B2C;x@hq^fhb= (3, 4): + from importlib import reload as reload_module + else: + from imp import reload as reload_module + def b(s): + return bytes(s, 'latin1') + from io import StringIO, BytesIO + text_type = str + binary_type = bytes + string_types = (str,) + integer_types = (int,) + unichr = chr + +long_type = integer_types[-1] diff --git a/lib/simplejson/decoder.py b/lib/simplejson/decoder.py new file mode 100644 index 0000000..c99a976 --- /dev/null +++ b/lib/simplejson/decoder.py @@ -0,0 +1,416 @@ +"""Implementation of JSONDecoder +""" +from __future__ import absolute_import +import re +import sys +import struct +from .compat import PY3, unichr +from .scanner import make_scanner, JSONDecodeError + +def _import_c_scanstring(): + try: + from ._speedups import scanstring + return scanstring + except ImportError: + return None +c_scanstring = _import_c_scanstring() + +# NOTE (3.1.0): JSONDecodeError may still be imported from this module for +# compatibility, but it was never in the __all__ +__all__ = ['JSONDecoder'] + +FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL + +def _floatconstants(): + if sys.version_info < (2, 6): + _BYTES = '7FF80000000000007FF0000000000000'.decode('hex') + nan, inf = struct.unpack('>dd', _BYTES) + else: + nan = float('nan') + inf = float('inf') + return nan, inf, -inf + +NaN, PosInf, NegInf = _floatconstants() + +_CONSTANTS = { + '-Infinity': NegInf, + 'Infinity': PosInf, + 'NaN': NaN, +} + +STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS) +BACKSLASH = { + '"': u'"', '\\': u'\\', '/': u'/', + 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t', +} + +DEFAULT_ENCODING = "utf-8" + +if hasattr(sys, 'get_int_max_str_digits'): + bounded_int = int +else: + def bounded_int(s, INT_MAX_STR_DIGITS=4300): + """Backport of the integer string length conversion limitation + + https://docs.python.org/3/library/stdtypes.html#int-max-str-digits + """ + if len(s) > INT_MAX_STR_DIGITS: + raise ValueError("Exceeds the limit (%s) for integer string conversion: value has %s digits" % (INT_MAX_STR_DIGITS, len(s))) + return int(s) + + +def scan_four_digit_hex(s, end, _m=re.compile(r'^[0-9a-fA-F]{4}$').match): + """Scan a four digit hex number from s[end:end + 4] + """ + msg = "Invalid \\uXXXX escape sequence" + esc = s[end:end + 4] + if not _m(esc): + raise JSONDecodeError(msg, s, end - 2) + try: + return int(esc, 16), end + 4 + except ValueError: + raise JSONDecodeError(msg, s, end - 2) + +def py_scanstring(s, end, encoding=None, strict=True, + _b=BACKSLASH, _m=STRINGCHUNK.match, _join=u''.join, + _PY3=PY3, _maxunicode=sys.maxunicode, + _scan_four_digit_hex=scan_four_digit_hex): + """Scan the string s for a JSON string. End is the index of the + character in s after the quote that started the JSON string. + Unescapes all valid JSON string escape sequences and raises ValueError + on attempt to decode an invalid string. If strict is False then literal + control characters are allowed in the string. + + Returns a tuple of the decoded string and the index of the character in s + after the end quote.""" + if encoding is None: + encoding = DEFAULT_ENCODING + chunks = [] + _append = chunks.append + begin = end - 1 + while 1: + chunk = _m(s, end) + if chunk is None: + raise JSONDecodeError( + "Unterminated string starting at", s, begin) + prev_end = end + end = chunk.end() + content, terminator = chunk.groups() + # Content is contains zero or more unescaped string characters + if content: + if not _PY3 and not isinstance(content, unicode): + content = unicode(content, encoding) + _append(content) + # Terminator is the end of string, a literal control character, + # or a backslash denoting that an escape sequence follows + if terminator == '"': + break + elif terminator != '\\': + if strict: + msg = "Invalid control character %r at" + raise JSONDecodeError(msg, s, prev_end) + else: + _append(terminator) + continue + try: + esc = s[end] + except IndexError: + raise JSONDecodeError( + "Unterminated string starting at", s, begin) + # If not a unicode escape sequence, must be in the lookup table + if esc != 'u': + try: + char = _b[esc] + except KeyError: + msg = "Invalid \\X escape sequence %r" + raise JSONDecodeError(msg, s, end) + end += 1 + else: + # Unicode escape sequence + uni, end = _scan_four_digit_hex(s, end + 1) + # Check for surrogate pair on UCS-4 systems + # Note that this will join high/low surrogate pairs + # but will also pass unpaired surrogates through + if (_maxunicode > 65535 and + uni & 0xfc00 == 0xd800 and + s[end:end + 2] == '\\u'): + uni2, end2 = _scan_four_digit_hex(s, end + 2) + if uni2 & 0xfc00 == 0xdc00: + uni = 0x10000 + (((uni - 0xd800) << 10) | + (uni2 - 0xdc00)) + end = end2 + char = unichr(uni) + # Append the unescaped character + _append(char) + return _join(chunks), end + + +# Use speedup if available +scanstring = c_scanstring or py_scanstring + +WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS) +WHITESPACE_STR = ' \t\n\r' + +def JSONObject(state, encoding, strict, scan_once, object_hook, + object_pairs_hook, memo=None, + _w=WHITESPACE.match, _ws=WHITESPACE_STR): + (s, end) = state + # Backwards compatibility + if memo is None: + memo = {} + memo_get = memo.setdefault + pairs = [] + # Use a slice to prevent IndexError from being raised, the following + # check will raise a more specific ValueError if the string is empty + nextchar = s[end:end + 1] + # Normally we expect nextchar == '"' + if nextchar != '"': + if nextchar in _ws: + end = _w(s, end).end() + nextchar = s[end:end + 1] + # Trivial empty object + if nextchar == '}': + if object_pairs_hook is not None: + result = object_pairs_hook(pairs) + return result, end + 1 + pairs = {} + if object_hook is not None: + pairs = object_hook(pairs) + return pairs, end + 1 + elif nextchar != '"': + raise JSONDecodeError( + "Expecting property name enclosed in double quotes or '}'", + s, end) + end += 1 + while True: + key, end = scanstring(s, end, encoding, strict) + key = memo_get(key, key) + + # To skip some function call overhead we optimize the fast paths where + # the JSON key separator is ": " or just ":". + if s[end:end + 1] != ':': + end = _w(s, end).end() + if s[end:end + 1] != ':': + raise JSONDecodeError("Expecting ':' delimiter", s, end) + + end += 1 + + try: + if s[end] in _ws: + end += 1 + if s[end] in _ws: + end = _w(s, end + 1).end() + except IndexError: + pass + + value, end = scan_once(s, end) + pairs.append((key, value)) + + try: + nextchar = s[end] + if nextchar in _ws: + end = _w(s, end + 1).end() + nextchar = s[end] + except IndexError: + nextchar = '' + end += 1 + + if nextchar == '}': + break + elif nextchar != ',': + raise JSONDecodeError("Expecting ',' delimiter or '}'", s, end - 1) + + try: + nextchar = s[end] + if nextchar in _ws: + end += 1 + nextchar = s[end] + if nextchar in _ws: + end = _w(s, end + 1).end() + nextchar = s[end] + except IndexError: + nextchar = '' + + end += 1 + if nextchar != '"': + raise JSONDecodeError( + "Expecting property name enclosed in double quotes", + s, end - 1) + + if object_pairs_hook is not None: + result = object_pairs_hook(pairs) + return result, end + pairs = dict(pairs) + if object_hook is not None: + pairs = object_hook(pairs) + return pairs, end + +def JSONArray(state, scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR): + (s, end) = state + values = [] + nextchar = s[end:end + 1] + if nextchar in _ws: + end = _w(s, end + 1).end() + nextchar = s[end:end + 1] + # Look-ahead for trivial empty array + if nextchar == ']': + return values, end + 1 + elif nextchar == '': + raise JSONDecodeError("Expecting value or ']'", s, end) + _append = values.append + while True: + value, end = scan_once(s, end) + _append(value) + nextchar = s[end:end + 1] + if nextchar in _ws: + end = _w(s, end + 1).end() + nextchar = s[end:end + 1] + end += 1 + if nextchar == ']': + break + elif nextchar != ',': + raise JSONDecodeError("Expecting ',' delimiter or ']'", s, end - 1) + + try: + if s[end] in _ws: + end += 1 + if s[end] in _ws: + end = _w(s, end + 1).end() + except IndexError: + pass + + return values, end + +class JSONDecoder(object): + """Simple JSON decoder + + Performs the following translations in decoding by default: + + +---------------+-------------------+ + | JSON | Python | + +===============+===================+ + | object | dict | + +---------------+-------------------+ + | array | list | + +---------------+-------------------+ + | string | str, unicode | + +---------------+-------------------+ + | number (int) | int, long | + +---------------+-------------------+ + | number (real) | float | + +---------------+-------------------+ + | true | True | + +---------------+-------------------+ + | false | False | + +---------------+-------------------+ + | null | None | + +---------------+-------------------+ + + When allow_nan=True, it also understands + ``NaN``, ``Infinity``, and ``-Infinity`` as + their corresponding ``float`` values, which is outside the JSON spec. + + """ + + def __init__(self, encoding=None, object_hook=None, parse_float=None, + parse_int=None, parse_constant=None, strict=True, + object_pairs_hook=None, allow_nan=False): + """ + *encoding* determines the encoding used to interpret any + :class:`str` objects decoded by this instance (``'utf-8'`` by + default). It has no effect when decoding :class:`unicode` objects. + + Note that currently only encodings that are a superset of ASCII work, + strings of other encodings should be passed in as :class:`unicode`. + + *object_hook*, if specified, will be called with the result of every + JSON object decoded and its return value will be used in place of the + given :class:`dict`. This can be used to provide custom + deserializations (e.g. to support JSON-RPC class hinting). + + *object_pairs_hook* is an optional function that will be called with + the result of any object literal decode with an ordered list of pairs. + The return value of *object_pairs_hook* will be used instead of the + :class:`dict`. This feature can be used to implement custom decoders + that rely on the order that the key and value pairs are decoded (for + example, :func:`collections.OrderedDict` will remember the order of + insertion). If *object_hook* is also defined, the *object_pairs_hook* + takes priority. + + *parse_float*, if specified, will be called with the string of every + JSON float to be decoded. By default, this is equivalent to + ``float(num_str)``. This can be used to use another datatype or parser + for JSON floats (e.g. :class:`decimal.Decimal`). + + *parse_int*, if specified, will be called with the string of every + JSON int to be decoded. By default, this is equivalent to + ``int(num_str)``. This can be used to use another datatype or parser + for JSON integers (e.g. :class:`float`). + + *allow_nan*, if True (default false), will allow the parser to + accept the non-standard floats ``NaN``, ``Infinity``, and ``-Infinity``. + + *parse_constant*, if specified, will be + called with one of the following strings: ``'-Infinity'``, + ``'Infinity'``, ``'NaN'``. It is not recommended to use this feature, + as it is rare to parse non-compliant JSON containing these values. + + *strict* controls the parser's behavior when it encounters an + invalid control character in a string. The default setting of + ``True`` means that unescaped control characters are parse errors, if + ``False`` then control characters will be allowed in strings. + + """ + if encoding is None: + encoding = DEFAULT_ENCODING + self.encoding = encoding + self.object_hook = object_hook + self.object_pairs_hook = object_pairs_hook + self.parse_float = parse_float or float + self.parse_int = parse_int or bounded_int + self.parse_constant = parse_constant or (allow_nan and _CONSTANTS.__getitem__ or None) + self.strict = strict + self.parse_object = JSONObject + self.parse_array = JSONArray + self.parse_string = scanstring + self.memo = {} + self.scan_once = make_scanner(self) + + def decode(self, s, _w=WHITESPACE.match, _PY3=PY3): + """Return the Python representation of ``s`` (a ``str`` or ``unicode`` + instance containing a JSON document) + + """ + if _PY3 and isinstance(s, bytes): + s = str(s, self.encoding) + obj, end = self.raw_decode(s) + end = _w(s, end).end() + if end != len(s): + raise JSONDecodeError("Extra data", s, end, len(s)) + return obj + + def raw_decode(self, s, idx=0, _w=WHITESPACE.match, _PY3=PY3): + """Decode a JSON document from ``s`` (a ``str`` or ``unicode`` + beginning with a JSON document) and return a 2-tuple of the Python + representation and the index in ``s`` where the document ended. + Optionally, ``idx`` can be used to specify an offset in ``s`` where + the JSON document begins. + + This can be used to decode a JSON document from a string that may + have extraneous data at the end. + + """ + if idx < 0: + # Ensure that raw_decode bails on negative indexes, the regex + # would otherwise mask this behavior. #98 + raise JSONDecodeError('Expecting value', s, idx) + if _PY3 and not isinstance(s, str): + raise TypeError("Input string must be text, not bytes") + # strip UTF-8 bom + if len(s) > idx: + ord0 = ord(s[idx]) + if ord0 == 0xfeff: + idx += 1 + elif ord0 == 0xef and s[idx:idx + 3] == '\xef\xbb\xbf': + idx += 3 + return self.scan_once(s, idx=_w(s, idx).end()) diff --git a/lib/simplejson/encoder.py b/lib/simplejson/encoder.py new file mode 100644 index 0000000..661ff36 --- /dev/null +++ b/lib/simplejson/encoder.py @@ -0,0 +1,740 @@ +"""Implementation of JSONEncoder +""" +from __future__ import absolute_import +import re +from operator import itemgetter +# Do not import Decimal directly to avoid reload issues +import decimal +from .compat import binary_type, text_type, string_types, integer_types, PY3 +def _import_speedups(): + try: + from . import _speedups + return _speedups.encode_basestring_ascii, _speedups.make_encoder + except ImportError: + return None, None +c_encode_basestring_ascii, c_make_encoder = _import_speedups() + +from .decoder import PosInf +from .raw_json import RawJSON + +ESCAPE = re.compile(r'[\x00-\x1f\\"]') +ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') +HAS_UTF8 = re.compile(r'[\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)) + ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) +del i + +FLOAT_REPR = repr + +def encode_basestring(s, _PY3=PY3, _q=u'"'): + """Return a JSON representation of a Python string + + """ + if _PY3: + if isinstance(s, bytes): + s = str(s, 'utf-8') + elif type(s) is not str: + # convert an str subclass instance to exact str + # raise a TypeError otherwise + s = str.__str__(s) + else: + if isinstance(s, str) and HAS_UTF8.search(s) is not None: + s = unicode(s, 'utf-8') + elif type(s) not in (str, unicode): + # convert an str subclass instance to exact str + # convert a unicode subclass instance to exact unicode + # raise a TypeError otherwise + if isinstance(s, str): + s = str.__str__(s) + else: + s = unicode.__getnewargs__(s)[0] + def replace(match): + return ESCAPE_DCT[match.group(0)] + return _q + ESCAPE.sub(replace, s) + _q + + +def py_encode_basestring_ascii(s, _PY3=PY3): + """Return an ASCII-only JSON representation of a Python string + + """ + if _PY3: + if isinstance(s, bytes): + s = str(s, 'utf-8') + elif type(s) is not str: + # convert an str subclass instance to exact str + # raise a TypeError otherwise + s = str.__str__(s) + else: + if isinstance(s, str) and HAS_UTF8.search(s) is not None: + s = unicode(s, 'utf-8') + elif type(s) not in (str, unicode): + # convert an str subclass instance to exact str + # convert a unicode subclass instance to exact unicode + # raise a TypeError otherwise + if isinstance(s, str): + s = str.__str__(s) + else: + s = unicode.__getnewargs__(s)[0] + 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) + return '\\u%04x' % (n,) + else: + # surrogate pair + n -= 0x10000 + s1 = 0xd800 | ((n >> 10) & 0x3ff) + s2 = 0xdc00 | (n & 0x3ff) + #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) + return '\\u%04x\\u%04x' % (s1, s2) + return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' + + +encode_basestring_ascii = ( + c_encode_basestring_ascii or py_encode_basestring_ascii) + +class JSONEncoder(object): + """Extensible JSON encoder for Python data structures. + + Supports the following objects and types by default: + + +-------------------+---------------+ + | Python | JSON | + +===================+===============+ + | dict, namedtuple | object | + +-------------------+---------------+ + | list, tuple | array | + +-------------------+---------------+ + | str, unicode | string | + +-------------------+---------------+ + | int, long, 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``). + + """ + item_separator = ', ' + key_separator = ': ' + + def __init__(self, skipkeys=False, ensure_ascii=True, + check_circular=True, allow_nan=False, sort_keys=False, + indent=None, separators=None, encoding='utf-8', default=None, + use_decimal=True, namedtuple_as_object=True, + tuple_as_array=True, bigint_as_string=False, + item_sort_key=None, for_json=False, ignore_nan=False, + int_as_string_bitcount=None, iterable_as_array=False): + """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, long, 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 unicode characters escaped. If + ensure_ascii is false, the output will be unicode object. + + 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 OverflowError). + Otherwise, no such check takes place. + + If allow_nan is true (default: False), then out of range float + values (nan, inf, -inf) will be serialized to + their JavaScript equivalents (NaN, Infinity, -Infinity) + instead of raising a ValueError. See + ignore_nan for ECMA-262 compliant behavior. + + 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 string, then JSON array elements and object members + will be pretty-printed with a newline followed by that string repeated + for each level of nesting. ``None`` (the default) selects the most compact + representation without any newlines. For backwards compatibility with + versions of simplejson earlier than 2.1.0, an integer is also accepted + and is converted to a string with that many spaces. + + 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``. + + If encoding is not None, then all input strings will be + transformed into unicode using that encoding prior to JSON-encoding. + The default is UTF-8. + + If use_decimal is true (default: ``True``), ``decimal.Decimal`` will + be supported directly by the encoder. For the inverse, decode JSON + with ``parse_float=decimal.Decimal``. + + If namedtuple_as_object is true (the default), objects with + ``_asdict()`` methods will be encoded as JSON objects. + + If tuple_as_array is true (the default), tuple (and subclasses) will + be encoded as JSON arrays. + + If *iterable_as_array* is true (default: ``False``), + any object not in the above table that implements ``__iter__()`` + will be encoded as a JSON array. + + If bigint_as_string is true (not the default), ints 2**53 and higher + or lower than -2**53 will be encoded as strings. This is to avoid the + rounding that happens in Javascript otherwise. + + If int_as_string_bitcount is a positive number (n), then int of size + greater than or equal to 2**n or lower than or equal to -2**n will be + encoded as strings. + + If specified, item_sort_key is a callable used to sort the items in + each dictionary. This is useful if you want to sort items other than + in alphabetical order by key. + + If for_json is true (not the default), objects with a ``for_json()`` + method will use the return value of that method for encoding as JSON + instead of the object. + + If *ignore_nan* is true (default: ``False``), then out of range + :class:`float` values (``nan``, ``inf``, ``-inf``) will be serialized + as ``null`` in compliance with the ECMA-262 specification. If true, + this will override *allow_nan*. + + """ + + self.skipkeys = skipkeys + self.ensure_ascii = ensure_ascii + self.check_circular = check_circular + self.allow_nan = allow_nan + self.sort_keys = sort_keys + self.use_decimal = use_decimal + self.namedtuple_as_object = namedtuple_as_object + self.tuple_as_array = tuple_as_array + self.iterable_as_array = iterable_as_array + self.bigint_as_string = bigint_as_string + self.item_sort_key = item_sort_key + self.for_json = for_json + self.ignore_nan = ignore_nan + self.int_as_string_bitcount = int_as_string_bitcount + if indent is not None and not isinstance(indent, string_types): + indent = indent * ' ' + 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 + self.encoding = encoding + + def default(self, o): + """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) + return JSONEncoder.default(self, o) + + """ + raise TypeError('Object of type %s is not JSON serializable' % + o.__class__.__name__) + + def encode(self, o): + """Return a JSON string representation of a Python data structure. + + >>> from simplejson import JSONEncoder + >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) + '{"foo": ["bar", "baz"]}' + + """ + # This is for extremely simple cases and benchmarks. + if isinstance(o, binary_type): + _encoding = self.encoding + if (_encoding is not None and not (_encoding == 'utf-8')): + o = text_type(o, _encoding) + if isinstance(o, string_types): + if self.ensure_ascii: + return encode_basestring_ascii(o) + else: + return encode_basestring(o) + # 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. + chunks = self.iterencode(o) + if not isinstance(chunks, (list, tuple)): + chunks = list(chunks) + if self.ensure_ascii: + return ''.join(chunks) + else: + return u''.join(chunks) + + def iterencode(self, o): + """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 self.encoding != 'utf-8' and self.encoding is not None: + def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding): + if isinstance(o, binary_type): + o = text_type(o, _encoding) + return _orig_encoder(o) + + def floatstr(o, allow_nan=self.allow_nan, ignore_nan=self.ignore_nan, + _repr=FLOAT_REPR, _inf=PosInf, _neginf=-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: + if type(o) != float: + # See #118, do not trust custom str/repr + o = float(o) + return _repr(o) + + if ignore_nan: + text = 'null' + elif not allow_nan: + raise ValueError( + "Out of range float values are not JSON compliant: " + + repr(o)) + + return text + + key_memo = {} + int_as_string_bitcount = ( + 53 if self.bigint_as_string else self.int_as_string_bitcount) + if (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, key_memo, self.use_decimal, + self.namedtuple_as_object, self.tuple_as_array, + int_as_string_bitcount, + self.item_sort_key, self.encoding, self.for_json, + self.ignore_nan, decimal.Decimal, self.iterable_as_array) + else: + _iterencode = _make_iterencode( + markers, self.default, _encoder, self.indent, floatstr, + self.key_separator, self.item_separator, self.sort_keys, + self.skipkeys, self.use_decimal, + self.namedtuple_as_object, self.tuple_as_array, + int_as_string_bitcount, + self.item_sort_key, self.encoding, self.for_json, + self.iterable_as_array, Decimal=decimal.Decimal) + try: + return _iterencode(o, 0) + finally: + key_memo.clear() + + +class JSONEncoderForHTML(JSONEncoder): + """An encoder that produces JSON safe to embed in HTML. + + To embed JSON content in, say, a script tag on a web page, the + characters &, < and > should be escaped. They cannot be escaped + with the usual entities (e.g. &) because they are not expanded + within ' + self.assertEqual( + r'"\u003c/script\u003e\u003cscript\u003e' + r'alert(\"gotcha\")\u003c/script\u003e"', + self.encoder.encode(bad_string)) + self.assertEqual( + bad_string, self.decoder.decode( + self.encoder.encode(bad_string))) diff --git a/lib/simplejson/tests/test_errors.py b/lib/simplejson/tests/test_errors.py new file mode 100644 index 0000000..d573825 --- /dev/null +++ b/lib/simplejson/tests/test_errors.py @@ -0,0 +1,68 @@ +import sys, pickle +from unittest import TestCase + +import simplejson as json +from simplejson.compat import text_type, b + +class TestErrors(TestCase): + def test_string_keys_error(self): + data = [{'a': 'A', 'b': (2, 4), 'c': 3.0, ('d',): 'D tuple'}] + try: + json.dumps(data) + except TypeError: + err = sys.exc_info()[1] + else: + self.fail('Expected TypeError') + self.assertEqual(str(err), + 'keys must be str, int, float, bool or None, not tuple') + + def test_not_serializable(self): + try: + json.dumps(json) + except TypeError: + err = sys.exc_info()[1] + else: + self.fail('Expected TypeError') + self.assertEqual(str(err), + 'Object of type module is not JSON serializable') + + def test_decode_error(self): + err = None + try: + json.loads('{}\na\nb') + except json.JSONDecodeError: + err = sys.exc_info()[1] + else: + self.fail('Expected JSONDecodeError') + self.assertEqual(err.lineno, 2) + self.assertEqual(err.colno, 1) + self.assertEqual(err.endlineno, 3) + self.assertEqual(err.endcolno, 2) + + def test_scan_error(self): + err = None + for t in (text_type, b): + try: + json.loads(t('{"asdf": "')) + except json.JSONDecodeError: + err = sys.exc_info()[1] + else: + self.fail('Expected JSONDecodeError') + self.assertEqual(err.lineno, 1) + self.assertEqual(err.colno, 10) + + def test_error_is_pickable(self): + err = None + try: + json.loads('{}\na\nb') + except json.JSONDecodeError: + err = sys.exc_info()[1] + else: + self.fail('Expected JSONDecodeError') + s = pickle.dumps(err) + e = pickle.loads(s) + + self.assertEqual(err.msg, e.msg) + self.assertEqual(err.doc, e.doc) + self.assertEqual(err.pos, e.pos) + self.assertEqual(err.end, e.end) diff --git a/lib/simplejson/tests/test_fail.py b/lib/simplejson/tests/test_fail.py new file mode 100644 index 0000000..5f9a8f6 --- /dev/null +++ b/lib/simplejson/tests/test_fail.py @@ -0,0 +1,178 @@ +import sys +from unittest import TestCase + +import simplejson as json + +# 2007-10-05 +JSONDOCS = [ + # http://json.org/JSON_checker/test/fail1.json + '"A JSON payload should be an object or array, not a string."', + # http://json.org/JSON_checker/test/fail2.json + '["Unclosed array"', + # http://json.org/JSON_checker/test/fail3.json + '{unquoted_key: "keys must be quoted"}', + # http://json.org/JSON_checker/test/fail4.json + '["extra comma",]', + # http://json.org/JSON_checker/test/fail5.json + '["double extra comma",,]', + # http://json.org/JSON_checker/test/fail6.json + '[ , "<-- missing value"]', + # http://json.org/JSON_checker/test/fail7.json + '["Comma after the close"],', + # http://json.org/JSON_checker/test/fail8.json + '["Extra close"]]', + # http://json.org/JSON_checker/test/fail9.json + '{"Extra comma": true,}', + # http://json.org/JSON_checker/test/fail10.json + '{"Extra value after close": true} "misplaced quoted value"', + # http://json.org/JSON_checker/test/fail11.json + '{"Illegal expression": 1 + 2}', + # http://json.org/JSON_checker/test/fail12.json + '{"Illegal invocation": alert()}', + # http://json.org/JSON_checker/test/fail13.json + '{"Numbers cannot have leading zeroes": 013}', + # http://json.org/JSON_checker/test/fail14.json + '{"Numbers cannot be hex": 0x14}', + # http://json.org/JSON_checker/test/fail15.json + '["Illegal backslash escape: \\x15"]', + # http://json.org/JSON_checker/test/fail16.json + '[\\naked]', + # http://json.org/JSON_checker/test/fail17.json + '["Illegal backslash escape: \\017"]', + # http://json.org/JSON_checker/test/fail18.json + '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]', + # http://json.org/JSON_checker/test/fail19.json + '{"Missing colon" null}', + # http://json.org/JSON_checker/test/fail20.json + '{"Double colon":: null}', + # http://json.org/JSON_checker/test/fail21.json + '{"Comma instead of colon", null}', + # http://json.org/JSON_checker/test/fail22.json + '["Colon instead of comma": false]', + # http://json.org/JSON_checker/test/fail23.json + '["Bad value", truth]', + # http://json.org/JSON_checker/test/fail24.json + "['single quote']", + # http://json.org/JSON_checker/test/fail25.json + '["\ttab\tcharacter\tin\tstring\t"]', + # http://json.org/JSON_checker/test/fail26.json + '["tab\\ character\\ in\\ string\\ "]', + # http://json.org/JSON_checker/test/fail27.json + '["line\nbreak"]', + # http://json.org/JSON_checker/test/fail28.json + '["line\\\nbreak"]', + # http://json.org/JSON_checker/test/fail29.json + '[0e]', + # http://json.org/JSON_checker/test/fail30.json + '[0e+]', + # http://json.org/JSON_checker/test/fail31.json + '[0e+-1]', + # http://json.org/JSON_checker/test/fail32.json + '{"Comma instead if closing brace": true,', + # http://json.org/JSON_checker/test/fail33.json + '["mismatch"}', + # http://code.google.com/p/simplejson/issues/detail?id=3 + u'["A\u001FZ control characters in string"]', + # misc based on coverage + '{', + '{]', + '{"foo": "bar"]', + '{"foo": "bar"', + 'nul', + 'nulx', + '-', + '-x', + '-e', + '-e0', + '-Infinite', + '-Inf', + 'Infinit', + 'Infinite', + 'NaM', + 'NuN', + 'falsy', + 'fal', + 'trug', + 'tru', + '1e', + '1ex', + '1e-', + '1e-x', +] + +SKIPS = { + 1: "why not have a string payload?", + 18: "spec doesn't specify any nesting limitations", +} + +class TestFail(TestCase): + def test_failures(self): + for idx, doc in enumerate(JSONDOCS): + idx = idx + 1 + if idx in SKIPS: + json.loads(doc) + continue + try: + json.loads(doc) + except json.JSONDecodeError: + pass + else: + self.fail("Expected failure for fail%d.json: %r" % (idx, doc)) + + def test_array_decoder_issue46(self): + # http://code.google.com/p/simplejson/issues/detail?id=46 + for doc in [u'[,]', '[,]']: + try: + json.loads(doc) + except json.JSONDecodeError: + e = sys.exc_info()[1] + self.assertEqual(e.pos, 1) + self.assertEqual(e.lineno, 1) + self.assertEqual(e.colno, 2) + except Exception: + e = sys.exc_info()[1] + self.fail("Unexpected exception raised %r %s" % (e, e)) + else: + self.fail("Unexpected success parsing '[,]'") + + def test_truncated_input(self): + test_cases = [ + ('', 'Expecting value', 0), + ('[', "Expecting value or ']'", 1), + ('[42', "Expecting ',' delimiter", 3), + ('[42,', 'Expecting value', 4), + ('["', 'Unterminated string starting at', 1), + ('["spam', 'Unterminated string starting at', 1), + ('["spam"', "Expecting ',' delimiter", 7), + ('["spam",', 'Expecting value', 8), + ('{', "Expecting property name enclosed in double quotes or '}'", 1), + ('{"', 'Unterminated string starting at', 1), + ('{"spam', 'Unterminated string starting at', 1), + ('{"spam"', "Expecting ':' delimiter", 7), + ('{"spam":', 'Expecting value', 8), + ('{"spam":42', "Expecting ',' delimiter", 10), + ('{"spam":42,', 'Expecting property name enclosed in double quotes', + 11), + ('"', 'Unterminated string starting at', 0), + ('"spam', 'Unterminated string starting at', 0), + ('[,', "Expecting value", 1), + ('--', 'Expecting value', 0), + ('"\x18d', "Invalid control character %r", 1), + ] + for data, msg, idx in test_cases: + try: + json.loads(data) + except json.JSONDecodeError: + e = sys.exc_info()[1] + self.assertEqual( + e.msg[:len(msg)], + msg, + "%r doesn't start with %r for %r" % (e.msg, msg, data)) + self.assertEqual( + e.pos, idx, + "pos %r != %r for %r" % (e.pos, idx, data)) + except Exception: + e = sys.exc_info()[1] + self.fail("Unexpected exception raised %r %s" % (e, e)) + else: + self.fail("Unexpected success parsing '%r'" % (data,)) diff --git a/lib/simplejson/tests/test_float.py b/lib/simplejson/tests/test_float.py new file mode 100644 index 0000000..a977969 --- /dev/null +++ b/lib/simplejson/tests/test_float.py @@ -0,0 +1,38 @@ +import math +from unittest import TestCase +from simplejson.compat import long_type, text_type +import simplejson as json +from simplejson.decoder import NaN, PosInf, NegInf + +class TestFloat(TestCase): + def test_degenerates_allow(self): + for inf in (PosInf, NegInf): + self.assertEqual(json.loads(json.dumps(inf, allow_nan=True), allow_nan=True), inf) + # Python 2.5 doesn't have math.isnan + nan = json.loads(json.dumps(NaN, allow_nan=True), allow_nan=True) + self.assertTrue((0 + nan) != nan) + + def test_degenerates_ignore(self): + for f in (PosInf, NegInf, NaN): + self.assertEqual(json.loads(json.dumps(f, ignore_nan=True)), None) + + def test_degenerates_deny(self): + for f in (PosInf, NegInf, NaN): + self.assertRaises(ValueError, json.dumps, f, allow_nan=False) + for s in ('Infinity', '-Infinity', 'NaN'): + self.assertRaises(ValueError, json.loads, s, allow_nan=False) + self.assertRaises(ValueError, json.loads, s) + + def test_floats(self): + for num in [1617161771.7650001, math.pi, math.pi**100, + math.pi**-100, 3.1]: + self.assertEqual(float(json.dumps(num)), num) + self.assertEqual(json.loads(json.dumps(num)), num) + self.assertEqual(json.loads(text_type(json.dumps(num))), num) + + def test_ints(self): + for num in [1, long_type(1), 1<<32, 1<<64]: + self.assertEqual(json.dumps(num), str(num)) + self.assertEqual(int(json.dumps(num)), num) + self.assertEqual(json.loads(json.dumps(num)), num) + self.assertEqual(json.loads(text_type(json.dumps(num))), num) diff --git a/lib/simplejson/tests/test_for_json.py b/lib/simplejson/tests/test_for_json.py new file mode 100644 index 0000000..b791b88 --- /dev/null +++ b/lib/simplejson/tests/test_for_json.py @@ -0,0 +1,97 @@ +import unittest +import simplejson as json + + +class ForJson(object): + def for_json(self): + return {'for_json': 1} + + +class NestedForJson(object): + def for_json(self): + return {'nested': ForJson()} + + +class ForJsonList(object): + def for_json(self): + return ['list'] + + +class DictForJson(dict): + def for_json(self): + return {'alpha': 1} + + +class ListForJson(list): + def for_json(self): + return ['list'] + + +class TestForJson(unittest.TestCase): + def assertRoundTrip(self, obj, other, for_json=True): + if for_json is None: + # None will use the default + s = json.dumps(obj) + else: + s = json.dumps(obj, for_json=for_json) + self.assertEqual( + json.loads(s), + other) + + def test_for_json_encodes_stand_alone_object(self): + self.assertRoundTrip( + ForJson(), + ForJson().for_json()) + + def test_for_json_encodes_object_nested_in_dict(self): + self.assertRoundTrip( + {'hooray': ForJson()}, + {'hooray': ForJson().for_json()}) + + def test_for_json_encodes_object_nested_in_list_within_dict(self): + self.assertRoundTrip( + {'list': [0, ForJson(), 2, 3]}, + {'list': [0, ForJson().for_json(), 2, 3]}) + + def test_for_json_encodes_object_nested_within_object(self): + self.assertRoundTrip( + NestedForJson(), + {'nested': {'for_json': 1}}) + + def test_for_json_encodes_list(self): + self.assertRoundTrip( + ForJsonList(), + ForJsonList().for_json()) + + def test_for_json_encodes_list_within_object(self): + self.assertRoundTrip( + {'nested': ForJsonList()}, + {'nested': ForJsonList().for_json()}) + + def test_for_json_encodes_dict_subclass(self): + self.assertRoundTrip( + DictForJson(a=1), + DictForJson(a=1).for_json()) + + def test_for_json_encodes_list_subclass(self): + self.assertRoundTrip( + ListForJson(['l']), + ListForJson(['l']).for_json()) + + def test_for_json_ignored_if_not_true_with_dict_subclass(self): + for for_json in (None, False): + self.assertRoundTrip( + DictForJson(a=1), + {'a': 1}, + for_json=for_json) + + def test_for_json_ignored_if_not_true_with_list_subclass(self): + for for_json in (None, False): + self.assertRoundTrip( + ListForJson(['l']), + ['l'], + for_json=for_json) + + def test_raises_typeerror_if_for_json_not_true_with_object(self): + self.assertRaises(TypeError, json.dumps, ForJson()) + self.assertRaises(TypeError, json.dumps, ForJson(), for_json=False) diff --git a/lib/simplejson/tests/test_indent.py b/lib/simplejson/tests/test_indent.py new file mode 100644 index 0000000..cea25a5 --- /dev/null +++ b/lib/simplejson/tests/test_indent.py @@ -0,0 +1,86 @@ +from unittest import TestCase +import textwrap + +import simplejson as json +from simplejson.compat import StringIO + +class TestIndent(TestCase): + def test_indent(self): + h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', + 'i-vhbjkhnth', + {'nifty': 87}, {'field': 'yes', 'morefield': False} ] + + expect = textwrap.dedent("""\ + [ + \t[ + \t\t"blorpie" + \t], + \t[ + \t\t"whoops" + \t], + \t[], + \t"d-shtaeou", + \t"d-nthiouh", + \t"i-vhbjkhnth", + \t{ + \t\t"nifty": 87 + \t}, + \t{ + \t\t"field": "yes", + \t\t"morefield": false + \t} + ]""") + + + d1 = json.dumps(h) + d2 = json.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) + d3 = json.dumps(h, indent=' ', sort_keys=True, separators=(',', ': ')) + d4 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) + + h1 = json.loads(d1) + h2 = json.loads(d2) + h3 = json.loads(d3) + h4 = json.loads(d4) + + self.assertEqual(h1, h) + self.assertEqual(h2, h) + self.assertEqual(h3, h) + self.assertEqual(h4, h) + self.assertEqual(d3, expect.replace('\t', ' ')) + self.assertEqual(d4, expect.replace('\t', ' ')) + # NOTE: Python 2.4 textwrap.dedent converts tabs to spaces, + # so the following is expected to fail. Python 2.4 is not a + # supported platform in simplejson 2.1.0+. + self.assertEqual(d2, expect) + + def test_indent0(self): + h = {3: 1} + def check(indent, expected): + d1 = json.dumps(h, indent=indent) + self.assertEqual(d1, expected) + + sio = StringIO() + json.dump(h, sio, indent=indent) + self.assertEqual(sio.getvalue(), expected) + + # indent=0 should emit newlines + check(0, '{\n"3": 1\n}') + # indent=None is more compact + check(None, '{"3": 1}') + + def test_separators(self): + lst = [1,2,3,4] + expect = '[\n1,\n2,\n3,\n4\n]' + expect_spaces = '[\n1, \n2, \n3, \n4\n]' + # Ensure that separators still works + self.assertEqual( + expect_spaces, + json.dumps(lst, indent=0, separators=(', ', ': '))) + # Force the new defaults + self.assertEqual( + expect, + json.dumps(lst, indent=0, separators=(',', ': '))) + # Added in 2.1.4 + self.assertEqual( + expect, + json.dumps(lst, indent=0)) diff --git a/lib/simplejson/tests/test_item_sort_key.py b/lib/simplejson/tests/test_item_sort_key.py new file mode 100644 index 0000000..98971b8 --- /dev/null +++ b/lib/simplejson/tests/test_item_sort_key.py @@ -0,0 +1,27 @@ +from unittest import TestCase + +import simplejson as json +from operator import itemgetter + +class TestItemSortKey(TestCase): + def test_simple_first(self): + a = {'a': 1, 'c': 5, 'jack': 'jill', 'pick': 'axe', 'array': [1, 5, 6, 9], 'tuple': (83, 12, 3), 'crate': 'dog', 'zeak': 'oh'} + self.assertEqual( + '{"a": 1, "c": 5, "crate": "dog", "jack": "jill", "pick": "axe", "zeak": "oh", "array": [1, 5, 6, 9], "tuple": [83, 12, 3]}', + json.dumps(a, item_sort_key=json.simple_first)) + + def test_case(self): + a = {'a': 1, 'c': 5, 'Jack': 'jill', 'pick': 'axe', 'Array': [1, 5, 6, 9], 'tuple': (83, 12, 3), 'crate': 'dog', 'zeak': 'oh'} + self.assertEqual( + '{"Array": [1, 5, 6, 9], "Jack": "jill", "a": 1, "c": 5, "crate": "dog", "pick": "axe", "tuple": [83, 12, 3], "zeak": "oh"}', + json.dumps(a, item_sort_key=itemgetter(0))) + self.assertEqual( + '{"a": 1, "Array": [1, 5, 6, 9], "c": 5, "crate": "dog", "Jack": "jill", "pick": "axe", "tuple": [83, 12, 3], "zeak": "oh"}', + json.dumps(a, item_sort_key=lambda kv: kv[0].lower())) + + def test_item_sort_key_value(self): + # https://github.com/simplejson/simplejson/issues/173 + a = {'a': 1, 'b': 0} + self.assertEqual( + '{"b": 0, "a": 1}', + json.dumps(a, item_sort_key=lambda kv: kv[1])) diff --git a/lib/simplejson/tests/test_iterable.py b/lib/simplejson/tests/test_iterable.py new file mode 100644 index 0000000..35d3e75 --- /dev/null +++ b/lib/simplejson/tests/test_iterable.py @@ -0,0 +1,31 @@ +import unittest +from simplejson.compat import StringIO + +import simplejson as json + +def iter_dumps(obj, **kw): + return ''.join(json.JSONEncoder(**kw).iterencode(obj)) + +def sio_dump(obj, **kw): + sio = StringIO() + json.dumps(obj, **kw) + return sio.getvalue() + +class TestIterable(unittest.TestCase): + def test_iterable(self): + for l in ([], [1], [1, 2], [1, 2, 3]): + for opts in [{}, {'indent': 2}]: + for dumps in (json.dumps, iter_dumps, sio_dump): + expect = dumps(l, **opts) + default_expect = dumps(sum(l), **opts) + # Default is False + self.assertRaises(TypeError, dumps, iter(l), **opts) + self.assertRaises(TypeError, dumps, iter(l), iterable_as_array=False, **opts) + self.assertEqual(expect, dumps(iter(l), iterable_as_array=True, **opts)) + # Ensure that the "default" gets called + self.assertEqual(default_expect, dumps(iter(l), default=sum, **opts)) + self.assertEqual(default_expect, dumps(iter(l), iterable_as_array=False, default=sum, **opts)) + # Ensure that the "default" does not get called + self.assertEqual( + expect, + dumps(iter(l), iterable_as_array=True, default=sum, **opts)) diff --git a/lib/simplejson/tests/test_namedtuple.py b/lib/simplejson/tests/test_namedtuple.py new file mode 100644 index 0000000..cc0f8aa --- /dev/null +++ b/lib/simplejson/tests/test_namedtuple.py @@ -0,0 +1,174 @@ +from __future__ import absolute_import +import unittest +import simplejson as json +from simplejson.compat import StringIO + +try: + from unittest import mock +except ImportError: + mock = None + +try: + from collections import namedtuple +except ImportError: + class Value(tuple): + def __new__(cls, *args): + return tuple.__new__(cls, args) + + def _asdict(self): + return {'value': self[0]} + class Point(tuple): + def __new__(cls, *args): + return tuple.__new__(cls, args) + + def _asdict(self): + return {'x': self[0], 'y': self[1]} +else: + Value = namedtuple('Value', ['value']) + Point = namedtuple('Point', ['x', 'y']) + +class DuckValue(object): + def __init__(self, *args): + self.value = Value(*args) + + def _asdict(self): + return self.value._asdict() + +class DuckPoint(object): + def __init__(self, *args): + self.point = Point(*args) + + def _asdict(self): + return self.point._asdict() + +class DeadDuck(object): + _asdict = None + +class DeadDict(dict): + _asdict = None + +CONSTRUCTORS = [ + lambda v: v, + lambda v: [v], + lambda v: [{'key': v}], +] + +class TestNamedTuple(unittest.TestCase): + def test_namedtuple_dumps(self): + for v in [Value(1), Point(1, 2), DuckValue(1), DuckPoint(1, 2)]: + d = v._asdict() + self.assertEqual(d, json.loads(json.dumps(v))) + self.assertEqual( + d, + json.loads(json.dumps(v, namedtuple_as_object=True))) + self.assertEqual(d, json.loads(json.dumps(v, tuple_as_array=False))) + self.assertEqual( + d, + json.loads(json.dumps(v, namedtuple_as_object=True, + tuple_as_array=False))) + + def test_namedtuple_dumps_false(self): + for v in [Value(1), Point(1, 2)]: + l = list(v) + self.assertEqual( + l, + json.loads(json.dumps(v, namedtuple_as_object=False))) + self.assertRaises(TypeError, json.dumps, v, + tuple_as_array=False, namedtuple_as_object=False) + + def test_namedtuple_dump(self): + for v in [Value(1), Point(1, 2), DuckValue(1), DuckPoint(1, 2)]: + d = v._asdict() + sio = StringIO() + json.dump(v, sio) + self.assertEqual(d, json.loads(sio.getvalue())) + sio = StringIO() + json.dump(v, sio, namedtuple_as_object=True) + self.assertEqual( + d, + json.loads(sio.getvalue())) + sio = StringIO() + json.dump(v, sio, tuple_as_array=False) + self.assertEqual(d, json.loads(sio.getvalue())) + sio = StringIO() + json.dump(v, sio, namedtuple_as_object=True, + tuple_as_array=False) + self.assertEqual( + d, + json.loads(sio.getvalue())) + + def test_namedtuple_dump_false(self): + for v in [Value(1), Point(1, 2)]: + l = list(v) + sio = StringIO() + json.dump(v, sio, namedtuple_as_object=False) + self.assertEqual( + l, + json.loads(sio.getvalue())) + self.assertRaises(TypeError, json.dump, v, StringIO(), + tuple_as_array=False, namedtuple_as_object=False) + + def test_asdict_not_callable_dump(self): + for f in CONSTRUCTORS: + self.assertRaises( + TypeError, + json.dump, + f(DeadDuck()), + StringIO(), + namedtuple_as_object=True + ) + sio = StringIO() + json.dump(f(DeadDict()), sio, namedtuple_as_object=True) + self.assertEqual( + json.dumps(f({})), + sio.getvalue()) + self.assertRaises( + TypeError, + json.dump, + f(Value), + StringIO(), + namedtuple_as_object=True + ) + + def test_asdict_not_callable_dumps(self): + for f in CONSTRUCTORS: + self.assertRaises(TypeError, + json.dumps, f(DeadDuck()), namedtuple_as_object=True) + self.assertRaises( + TypeError, + json.dumps, + f(Value), + namedtuple_as_object=True + ) + self.assertEqual( + json.dumps(f({})), + json.dumps(f(DeadDict()), namedtuple_as_object=True)) + + def test_asdict_unbound_method_dumps(self): + for f in CONSTRUCTORS: + self.assertEqual( + json.dumps(f(Value), default=lambda v: v.__name__), + json.dumps(f(Value.__name__)) + ) + + def test_asdict_does_not_return_dict(self): + if not mock: + if hasattr(unittest, "SkipTest"): + raise unittest.SkipTest("unittest.mock required") + else: + print("unittest.mock not available") + return + fake = mock.Mock() + self.assertTrue(hasattr(fake, '_asdict')) + self.assertTrue(callable(fake._asdict)) + self.assertFalse(isinstance(fake._asdict(), dict)) + # https://github.com/simplejson/simplejson/pull/284 + # when running under a debug build of CPython (COPTS=-UNDEBUG) + # a C assertion could fire due to an unchecked error of an PyDict + # API call on a non-dict internally in _speedups.c. Without a debug + # build of CPython this test likely passes either way despite the + # potential for internal data corruption. Getting it to crash in + # a debug build is not always easy either as it requires an + # assert(!PyErr_Occurred()) that could fire later on. + with self.assertRaises(TypeError): + json.dumps({23: fake}, namedtuple_as_object=True, for_json=False) diff --git a/lib/simplejson/tests/test_pass1.py b/lib/simplejson/tests/test_pass1.py new file mode 100644 index 0000000..f0b5b10 --- /dev/null +++ b/lib/simplejson/tests/test_pass1.py @@ -0,0 +1,71 @@ +from unittest import TestCase + +import simplejson as json + +# from http://json.org/JSON_checker/test/pass1.json +JSON = r''' +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact": [1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] +''' + +class TestPass1(TestCase): + def test_parse(self): + # test in/out equivalence and parsing + res = json.loads(JSON) + out = json.dumps(res) + self.assertEqual(res, json.loads(out)) diff --git a/lib/simplejson/tests/test_pass2.py b/lib/simplejson/tests/test_pass2.py new file mode 100644 index 0000000..5d812b3 --- /dev/null +++ b/lib/simplejson/tests/test_pass2.py @@ -0,0 +1,14 @@ +from unittest import TestCase +import simplejson as json + +# from http://json.org/JSON_checker/test/pass2.json +JSON = r''' +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] +''' + +class TestPass2(TestCase): + def test_parse(self): + # test in/out equivalence and parsing + res = json.loads(JSON) + out = json.dumps(res) + self.assertEqual(res, json.loads(out)) diff --git a/lib/simplejson/tests/test_pass3.py b/lib/simplejson/tests/test_pass3.py new file mode 100644 index 0000000..821d60b --- /dev/null +++ b/lib/simplejson/tests/test_pass3.py @@ -0,0 +1,20 @@ +from unittest import TestCase + +import simplejson as json + +# from http://json.org/JSON_checker/test/pass3.json +JSON = r''' +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} +''' + +class TestPass3(TestCase): + def test_parse(self): + # test in/out equivalence and parsing + res = json.loads(JSON) + out = json.dumps(res) + self.assertEqual(res, json.loads(out)) diff --git a/lib/simplejson/tests/test_raw_json.py b/lib/simplejson/tests/test_raw_json.py new file mode 100644 index 0000000..1dfcc2c --- /dev/null +++ b/lib/simplejson/tests/test_raw_json.py @@ -0,0 +1,47 @@ +import unittest +import simplejson as json + +dct1 = { + 'key1': 'value1' +} + +dct2 = { + 'key2': 'value2', + 'd1': dct1 +} + +dct3 = { + 'key2': 'value2', + 'd1': json.dumps(dct1) +} + +dct4 = { + 'key2': 'value2', + 'd1': json.RawJSON(json.dumps(dct1)) +} + + +class TestRawJson(unittest.TestCase): + + def test_normal_str(self): + self.assertNotEqual(json.dumps(dct2), json.dumps(dct3)) + + def test_raw_json_str(self): + self.assertEqual(json.dumps(dct2), json.dumps(dct4)) + self.assertEqual(dct2, json.loads(json.dumps(dct4))) + + def test_list(self): + self.assertEqual( + json.dumps([dct2]), + json.dumps([json.RawJSON(json.dumps(dct2))])) + self.assertEqual( + [dct2], + json.loads(json.dumps([json.RawJSON(json.dumps(dct2))]))) + + def test_direct(self): + self.assertEqual( + json.dumps(dct2), + json.dumps(json.RawJSON(json.dumps(dct2)))) + self.assertEqual( + dct2, + json.loads(json.dumps(json.RawJSON(json.dumps(dct2))))) diff --git a/lib/simplejson/tests/test_recursion.py b/lib/simplejson/tests/test_recursion.py new file mode 100644 index 0000000..662eb66 --- /dev/null +++ b/lib/simplejson/tests/test_recursion.py @@ -0,0 +1,67 @@ +from unittest import TestCase + +import simplejson as json + +class JSONTestObject: + pass + + +class RecursiveJSONEncoder(json.JSONEncoder): + recurse = False + def default(self, o): + if o is JSONTestObject: + if self.recurse: + return [JSONTestObject] + else: + return 'JSONTestObject' + return json.JSONEncoder.default(o) + + +class TestRecursion(TestCase): + def test_listrecursion(self): + x = [] + x.append(x) + try: + json.dumps(x) + except ValueError: + pass + else: + self.fail("didn't raise ValueError on list recursion") + x = [] + y = [x] + x.append(y) + try: + json.dumps(x) + except ValueError: + pass + else: + self.fail("didn't raise ValueError on alternating list recursion") + y = [] + x = [y, y] + # ensure that the marker is cleared + json.dumps(x) + + def test_dictrecursion(self): + x = {} + x["test"] = x + try: + json.dumps(x) + except ValueError: + pass + else: + self.fail("didn't raise ValueError on dict recursion") + x = {} + y = {"a": x, "b": x} + # ensure that the marker is cleared + json.dumps(y) + + def test_defaultrecursion(self): + enc = RecursiveJSONEncoder() + self.assertEqual(enc.encode(JSONTestObject), '"JSONTestObject"') + enc.recurse = True + try: + enc.encode(JSONTestObject) + except ValueError: + pass + else: + self.fail("didn't raise ValueError on default recursion") diff --git a/lib/simplejson/tests/test_scanstring.py b/lib/simplejson/tests/test_scanstring.py new file mode 100644 index 0000000..1f54483 --- /dev/null +++ b/lib/simplejson/tests/test_scanstring.py @@ -0,0 +1,200 @@ +import sys +from unittest import TestCase + +import simplejson as json +import simplejson.decoder +from simplejson.compat import b, PY3 + +class TestScanString(TestCase): + # The bytes type is intentionally not used in most of these tests + # under Python 3 because the decoder immediately coerces to str before + # calling scanstring. In Python 2 we are testing the code paths + # for both unicode and str. + # + # The reason this is done is because Python 3 would require + # entirely different code paths for parsing bytes and str. + # + def test_py_scanstring(self): + self._test_scanstring(simplejson.decoder.py_scanstring) + + def test_c_scanstring(self): + if not simplejson.decoder.c_scanstring: + return + self._test_scanstring(simplejson.decoder.c_scanstring) + + self.assertTrue(isinstance(simplejson.decoder.c_scanstring('""', 0)[0], str)) + + def _test_scanstring(self, scanstring): + if sys.maxunicode == 65535: + self.assertEqual( + scanstring(u'"z\U0001d120x"', 1, None, True), + (u'z\U0001d120x', 6)) + else: + self.assertEqual( + scanstring(u'"z\U0001d120x"', 1, None, True), + (u'z\U0001d120x', 5)) + + self.assertEqual( + scanstring('"\\u007b"', 1, None, True), + (u'{', 8)) + + self.assertEqual( + scanstring('"A JSON payload should be an object or array, not a string."', 1, None, True), + (u'A JSON payload should be an object or array, not a string.', 60)) + + self.assertEqual( + scanstring('["Unclosed array"', 2, None, True), + (u'Unclosed array', 17)) + + self.assertEqual( + scanstring('["extra comma",]', 2, None, True), + (u'extra comma', 14)) + + self.assertEqual( + scanstring('["double extra comma",,]', 2, None, True), + (u'double extra comma', 21)) + + self.assertEqual( + scanstring('["Comma after the close"],', 2, None, True), + (u'Comma after the close', 24)) + + self.assertEqual( + scanstring('["Extra close"]]', 2, None, True), + (u'Extra close', 14)) + + self.assertEqual( + scanstring('{"Extra comma": true,}', 2, None, True), + (u'Extra comma', 14)) + + self.assertEqual( + scanstring('{"Extra value after close": true} "misplaced quoted value"', 2, None, True), + (u'Extra value after close', 26)) + + self.assertEqual( + scanstring('{"Illegal expression": 1 + 2}', 2, None, True), + (u'Illegal expression', 21)) + + self.assertEqual( + scanstring('{"Illegal invocation": alert()}', 2, None, True), + (u'Illegal invocation', 21)) + + self.assertEqual( + scanstring('{"Numbers cannot have leading zeroes": 013}', 2, None, True), + (u'Numbers cannot have leading zeroes', 37)) + + self.assertEqual( + scanstring('{"Numbers cannot be hex": 0x14}', 2, None, True), + (u'Numbers cannot be hex', 24)) + + self.assertEqual( + scanstring('[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]', 21, None, True), + (u'Too deep', 30)) + + self.assertEqual( + scanstring('{"Missing colon" null}', 2, None, True), + (u'Missing colon', 16)) + + self.assertEqual( + scanstring('{"Double colon":: null}', 2, None, True), + (u'Double colon', 15)) + + self.assertEqual( + scanstring('{"Comma instead of colon", null}', 2, None, True), + (u'Comma instead of colon', 25)) + + self.assertEqual( + scanstring('["Colon instead of comma": false]', 2, None, True), + (u'Colon instead of comma', 25)) + + self.assertEqual( + scanstring('["Bad value", truth]', 2, None, True), + (u'Bad value', 12)) + + for c in map(chr, range(0x00, 0x1f)): + self.assertEqual( + scanstring(c + '"', 0, None, False), + (c, 2)) + self.assertRaises( + ValueError, + scanstring, c + '"', 0, None, True) + + self.assertRaises(ValueError, scanstring, '', 0, None, True) + self.assertRaises(ValueError, scanstring, 'a', 0, None, True) + self.assertRaises(ValueError, scanstring, '\\', 0, None, True) + self.assertRaises(ValueError, scanstring, '\\u', 0, None, True) + self.assertRaises(ValueError, scanstring, '\\u0', 0, None, True) + self.assertRaises(ValueError, scanstring, '\\u01', 0, None, True) + self.assertRaises(ValueError, scanstring, '\\u012', 0, None, True) + self.assertRaises(ValueError, scanstring, '\\u0123', 0, None, True) + if sys.maxunicode > 65535: + self.assertRaises(ValueError, + scanstring, '\\ud834\\u"', 0, None, True) + self.assertRaises(ValueError, + scanstring, '\\ud834\\x0123"', 0, None, True) + + self.assertRaises(json.JSONDecodeError, scanstring, '\\u-123"', 0, None, True) + # SJ-PT-23-01: Invalid Handling of Broken Unicode Escape Sequences + self.assertRaises(json.JSONDecodeError, scanstring, '\\u EDD"', 0, None, True) + + def test_issue3623(self): + self.assertRaises(ValueError, json.decoder.scanstring, "xxx", 1, + "xxx") + self.assertRaises(UnicodeDecodeError, + json.encoder.encode_basestring_ascii, b("xx\xff")) + + def test_overflow(self): + # Python 2.5 does not have maxsize, Python 3 does not have maxint + maxsize = getattr(sys, 'maxsize', getattr(sys, 'maxint', None)) + assert maxsize is not None + self.assertRaises(OverflowError, json.decoder.scanstring, "xxx", + maxsize + 1) + + def test_surrogates(self): + scanstring = json.decoder.scanstring + + def assertScan(given, expect, test_utf8=True): + givens = [given] + if not PY3 and test_utf8: + givens.append(given.encode('utf8')) + for given in givens: + (res, count) = scanstring(given, 1, None, True) + self.assertEqual(len(given), count) + self.assertEqual(res, expect) + + assertScan( + u'"z\\ud834\\u0079x"', + u'z\ud834yx') + assertScan( + u'"z\\ud834\\udd20x"', + u'z\U0001d120x') + assertScan( + u'"z\\ud834\\ud834\\udd20x"', + u'z\ud834\U0001d120x') + assertScan( + u'"z\\ud834x"', + u'z\ud834x') + assertScan( + u'"z\\udd20x"', + u'z\udd20x') + assertScan( + u'"z\ud834x"', + u'z\ud834x') + # It may look strange to join strings together, but Python is drunk. + # https://gist.github.com/etrepum/5538443 + assertScan( + u'"z\\ud834\udd20x12345"', + u''.join([u'z\ud834', u'\udd20x12345'])) + assertScan( + u'"z\ud834\\udd20x"', + u''.join([u'z\ud834', u'\udd20x'])) + # these have different behavior given UTF8 input, because the surrogate + # pair may be joined (in maxunicode > 65535 builds) + assertScan( + u''.join([u'"z\ud834', u'\udd20x"']), + u''.join([u'z\ud834', u'\udd20x']), + test_utf8=False) + + self.assertRaises(ValueError, + scanstring, u'"z\\ud83x"', 1, None, True) + self.assertRaises(ValueError, + scanstring, u'"z\\ud834\\udd2x"', 1, None, True) diff --git a/lib/simplejson/tests/test_separators.py b/lib/simplejson/tests/test_separators.py new file mode 100644 index 0000000..91b4d4f --- /dev/null +++ b/lib/simplejson/tests/test_separators.py @@ -0,0 +1,42 @@ +import textwrap +from unittest import TestCase + +import simplejson as json + + +class TestSeparators(TestCase): + def test_separators(self): + h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth', + {'nifty': 87}, {'field': 'yes', 'morefield': False} ] + + expect = textwrap.dedent("""\ + [ + [ + "blorpie" + ] , + [ + "whoops" + ] , + [] , + "d-shtaeou" , + "d-nthiouh" , + "i-vhbjkhnth" , + { + "nifty" : 87 + } , + { + "field" : "yes" , + "morefield" : false + } + ]""") + + + d1 = json.dumps(h) + d2 = json.dumps(h, indent=' ', sort_keys=True, separators=(' ,', ' : ')) + + h1 = json.loads(d1) + h2 = json.loads(d2) + + self.assertEqual(h1, h) + self.assertEqual(h2, h) + self.assertEqual(d2, expect) diff --git a/lib/simplejson/tests/test_speedups.py b/lib/simplejson/tests/test_speedups.py new file mode 100644 index 0000000..8b146df --- /dev/null +++ b/lib/simplejson/tests/test_speedups.py @@ -0,0 +1,114 @@ +from __future__ import with_statement + +import sys +import unittest +from unittest import TestCase + +import simplejson +from simplejson import encoder, decoder, scanner +from simplejson.compat import PY3, long_type, b + + +def has_speedups(): + return encoder.c_make_encoder is not None + + +def skip_if_speedups_missing(func): + def wrapper(*args, **kwargs): + if not has_speedups(): + if hasattr(unittest, 'SkipTest'): + raise unittest.SkipTest("C Extension not available") + else: + sys.stdout.write("C Extension not available") + return + return func(*args, **kwargs) + + return wrapper + + +class BadBool: + def __bool__(self): + 1/0 + __nonzero__ = __bool__ + + +class TestDecode(TestCase): + @skip_if_speedups_missing + def test_make_scanner(self): + self.assertRaises(AttributeError, scanner.c_make_scanner, 1) + + @skip_if_speedups_missing + def test_bad_bool_args(self): + def test(value): + decoder.JSONDecoder(strict=BadBool()).decode(value) + self.assertRaises(ZeroDivisionError, test, '""') + self.assertRaises(ZeroDivisionError, test, '{}') + if not PY3: + self.assertRaises(ZeroDivisionError, test, u'""') + self.assertRaises(ZeroDivisionError, test, u'{}') + +class TestEncode(TestCase): + @skip_if_speedups_missing + def test_make_encoder(self): + self.assertRaises( + TypeError, + encoder.c_make_encoder, + None, + ("\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7" + "\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75"), + None + ) + + @skip_if_speedups_missing + def test_bad_str_encoder(self): + # Issue #31505: There shouldn't be an assertion failure in case + # c_make_encoder() receives a bad encoder() argument. + import decimal + def bad_encoder1(*args): + return None + enc = encoder.c_make_encoder( + None, lambda obj: str(obj), + bad_encoder1, None, ': ', ', ', + False, False, False, {}, False, False, False, + None, None, 'utf-8', False, False, decimal.Decimal, False) + self.assertRaises(TypeError, enc, 'spam', 4) + self.assertRaises(TypeError, enc, {'spam': 42}, 4) + + def bad_encoder2(*args): + 1/0 + enc = encoder.c_make_encoder( + None, lambda obj: str(obj), + bad_encoder2, None, ': ', ', ', + False, False, False, {}, False, False, False, + None, None, 'utf-8', False, False, decimal.Decimal, False) + self.assertRaises(ZeroDivisionError, enc, 'spam', 4) + + @skip_if_speedups_missing + def test_bad_bool_args(self): + def test(name): + encoder.JSONEncoder(**{name: BadBool()}).encode({}) + self.assertRaises(ZeroDivisionError, test, 'skipkeys') + self.assertRaises(ZeroDivisionError, test, 'ensure_ascii') + self.assertRaises(ZeroDivisionError, test, 'check_circular') + self.assertRaises(ZeroDivisionError, test, 'allow_nan') + self.assertRaises(ZeroDivisionError, test, 'sort_keys') + self.assertRaises(ZeroDivisionError, test, 'use_decimal') + self.assertRaises(ZeroDivisionError, test, 'namedtuple_as_object') + self.assertRaises(ZeroDivisionError, test, 'tuple_as_array') + self.assertRaises(ZeroDivisionError, test, 'bigint_as_string') + self.assertRaises(ZeroDivisionError, test, 'for_json') + self.assertRaises(ZeroDivisionError, test, 'ignore_nan') + self.assertRaises(ZeroDivisionError, test, 'iterable_as_array') + + @skip_if_speedups_missing + def test_int_as_string_bitcount_overflow(self): + long_count = long_type(2)**32+31 + def test(): + encoder.JSONEncoder(int_as_string_bitcount=long_count).encode(0) + self.assertRaises((TypeError, OverflowError), test) + + if PY3: + @skip_if_speedups_missing + def test_bad_encoding(self): + with self.assertRaises(UnicodeEncodeError): + encoder.JSONEncoder(encoding='\udcff').encode({b('key'): 123}) diff --git a/lib/simplejson/tests/test_str_subclass.py b/lib/simplejson/tests/test_str_subclass.py new file mode 100644 index 0000000..b6c8351 --- /dev/null +++ b/lib/simplejson/tests/test_str_subclass.py @@ -0,0 +1,21 @@ +from unittest import TestCase + +import simplejson +from simplejson.compat import text_type + +# Tests for issue demonstrated in https://github.com/simplejson/simplejson/issues/144 +class WonkyTextSubclass(text_type): + def __getslice__(self, start, end): + return self.__class__('not what you wanted!') + +class TestStrSubclass(TestCase): + def test_dump_load(self): + for s in ['', '"hello"', 'text', u'\u005c']: + self.assertEqual( + s, + simplejson.loads(simplejson.dumps(WonkyTextSubclass(s)))) + + self.assertEqual( + s, + simplejson.loads(simplejson.dumps(WonkyTextSubclass(s), + ensure_ascii=False))) diff --git a/lib/simplejson/tests/test_subclass.py b/lib/simplejson/tests/test_subclass.py new file mode 100644 index 0000000..2bae3b6 --- /dev/null +++ b/lib/simplejson/tests/test_subclass.py @@ -0,0 +1,37 @@ +from unittest import TestCase +import simplejson as json + +from decimal import Decimal + +class AlternateInt(int): + def __repr__(self): + return 'invalid json' + __str__ = __repr__ + + +class AlternateFloat(float): + def __repr__(self): + return 'invalid json' + __str__ = __repr__ + + +# class AlternateDecimal(Decimal): +# def __repr__(self): +# return 'invalid json' + + +class TestSubclass(TestCase): + def test_int(self): + self.assertEqual(json.dumps(AlternateInt(1)), '1') + self.assertEqual(json.dumps(AlternateInt(-1)), '-1') + self.assertEqual(json.loads(json.dumps({AlternateInt(1): 1})), {'1': 1}) + + def test_float(self): + self.assertEqual(json.dumps(AlternateFloat(1.0)), '1.0') + self.assertEqual(json.dumps(AlternateFloat(-1.0)), '-1.0') + self.assertEqual(json.loads(json.dumps({AlternateFloat(1.0): 1})), {'1.0': 1}) + + # NOTE: Decimal subclasses are not supported as-is + # def test_decimal(self): + # self.assertEqual(json.dumps(AlternateDecimal('1.0')), '1.0') + # self.assertEqual(json.dumps(AlternateDecimal('-1.0')), '-1.0') diff --git a/lib/simplejson/tests/test_tool.py b/lib/simplejson/tests/test_tool.py new file mode 100644 index 0000000..914bff8 --- /dev/null +++ b/lib/simplejson/tests/test_tool.py @@ -0,0 +1,114 @@ +from __future__ import with_statement +import os +import sys +import textwrap +import unittest +import subprocess +import tempfile +try: + # Python 3.x + from test.support import strip_python_stderr +except ImportError: + # Python 2.6+ + try: + from test.test_support import strip_python_stderr + except ImportError: + # Python 2.5 + import re + def strip_python_stderr(stderr): + return re.sub( + r"\[\d+ refs\]\r?\n?$".encode(), + "".encode(), + stderr).strip() + +def open_temp_file(): + if sys.version_info >= (2, 6): + file = tempfile.NamedTemporaryFile(delete=False) + filename = file.name + else: + fd, filename = tempfile.mkstemp() + file = os.fdopen(fd, 'w+b') + return file, filename + +class TestTool(unittest.TestCase): + data = """ + + [["blorpie"],[ "whoops" ] , [ + ],\t"d-shtaeou",\r"d-nthiouh", + "i-vhbjkhnth", {"nifty":87}, {"morefield" :\tfalse,"field" + :"yes"} ] + """ + + expect = textwrap.dedent("""\ + [ + [ + "blorpie" + ], + [ + "whoops" + ], + [], + "d-shtaeou", + "d-nthiouh", + "i-vhbjkhnth", + { + "nifty": 87 + }, + { + "field": "yes", + "morefield": false + } + ] + """) + + def runTool(self, args=None, data=None): + argv = [sys.executable, '-m', 'simplejson.tool'] + if args: + argv.extend(args) + proc = subprocess.Popen(argv, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE) + out, err = proc.communicate(data) + self.assertEqual(strip_python_stderr(err), ''.encode()) + self.assertEqual(proc.returncode, 0) + return out.decode('utf8').splitlines() + + def test_stdin_stdout(self): + self.assertEqual( + self.runTool(data=self.data.encode()), + self.expect.splitlines()) + + def test_infile_stdout(self): + infile, infile_name = open_temp_file() + try: + infile.write(self.data.encode()) + infile.close() + self.assertEqual( + self.runTool(args=[infile_name]), + self.expect.splitlines()) + finally: + os.unlink(infile_name) + + def test_infile_outfile(self): + infile, infile_name = open_temp_file() + try: + infile.write(self.data.encode()) + infile.close() + # outfile will get overwritten by tool, so the delete + # may not work on some platforms. Do it manually. + outfile, outfile_name = open_temp_file() + try: + outfile.close() + self.assertEqual( + self.runTool(args=[infile_name, outfile_name]), + []) + with open(outfile_name, 'rb') as f: + self.assertEqual( + f.read().decode('utf8').splitlines(), + self.expect.splitlines() + ) + finally: + os.unlink(outfile_name) + finally: + os.unlink(infile_name) diff --git a/lib/simplejson/tests/test_tuple.py b/lib/simplejson/tests/test_tuple.py new file mode 100644 index 0000000..4ad7b0e --- /dev/null +++ b/lib/simplejson/tests/test_tuple.py @@ -0,0 +1,47 @@ +import unittest + +from simplejson.compat import StringIO +import simplejson as json + +class TestTuples(unittest.TestCase): + def test_tuple_array_dumps(self): + t = (1, 2, 3) + expect = json.dumps(list(t)) + # Default is True + self.assertEqual(expect, json.dumps(t)) + self.assertEqual(expect, json.dumps(t, tuple_as_array=True)) + self.assertRaises(TypeError, json.dumps, t, tuple_as_array=False) + # Ensure that the "default" does not get called + self.assertEqual(expect, json.dumps(t, default=repr)) + self.assertEqual(expect, json.dumps(t, tuple_as_array=True, + default=repr)) + # Ensure that the "default" gets called + self.assertEqual( + json.dumps(repr(t)), + json.dumps(t, tuple_as_array=False, default=repr)) + + def test_tuple_array_dump(self): + t = (1, 2, 3) + expect = json.dumps(list(t)) + # Default is True + sio = StringIO() + json.dump(t, sio) + self.assertEqual(expect, sio.getvalue()) + sio = StringIO() + json.dump(t, sio, tuple_as_array=True) + self.assertEqual(expect, sio.getvalue()) + self.assertRaises(TypeError, json.dump, t, StringIO(), + tuple_as_array=False) + # Ensure that the "default" does not get called + sio = StringIO() + json.dump(t, sio, default=repr) + self.assertEqual(expect, sio.getvalue()) + sio = StringIO() + json.dump(t, sio, tuple_as_array=True, default=repr) + self.assertEqual(expect, sio.getvalue()) + # Ensure that the "default" gets called + sio = StringIO() + json.dump(t, sio, tuple_as_array=False, default=repr) + self.assertEqual( + json.dumps(repr(t)), + sio.getvalue()) diff --git a/lib/simplejson/tests/test_unicode.py b/lib/simplejson/tests/test_unicode.py new file mode 100644 index 0000000..0c7b1a6 --- /dev/null +++ b/lib/simplejson/tests/test_unicode.py @@ -0,0 +1,154 @@ +import sys +import codecs +from unittest import TestCase + +import simplejson as json +from simplejson.compat import unichr, text_type, b, BytesIO + +class TestUnicode(TestCase): + def test_encoding1(self): + encoder = json.JSONEncoder(encoding='utf-8') + u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' + s = u.encode('utf-8') + ju = encoder.encode(u) + js = encoder.encode(s) + self.assertEqual(ju, js) + + def test_encoding2(self): + u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' + s = u.encode('utf-8') + ju = json.dumps(u, encoding='utf-8') + js = json.dumps(s, encoding='utf-8') + self.assertEqual(ju, js) + + def test_encoding3(self): + u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' + j = json.dumps(u) + self.assertEqual(j, '"\\u03b1\\u03a9"') + + def test_encoding4(self): + u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' + j = json.dumps([u]) + self.assertEqual(j, '["\\u03b1\\u03a9"]') + + def test_encoding5(self): + u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' + j = json.dumps(u, ensure_ascii=False) + self.assertEqual(j, u'"' + u + u'"') + + def test_encoding6(self): + u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}' + j = json.dumps([u], ensure_ascii=False) + self.assertEqual(j, u'["' + u + u'"]') + + def test_big_unicode_encode(self): + u = u'\U0001d120' + self.assertEqual(json.dumps(u), '"\\ud834\\udd20"') + self.assertEqual(json.dumps(u, ensure_ascii=False), u'"\U0001d120"') + + def test_big_unicode_decode(self): + u = u'z\U0001d120x' + self.assertEqual(json.loads('"' + u + '"'), u) + self.assertEqual(json.loads('"z\\ud834\\udd20x"'), u) + + def test_unicode_decode(self): + for i in range(0, 0xd7ff): + u = unichr(i) + #s = '"\\u{0:04x}"'.format(i) + s = '"\\u%04x"' % (i,) + self.assertEqual(json.loads(s), u) + + def test_object_pairs_hook_with_unicode(self): + s = u'{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}' + p = [(u"xkd", 1), (u"kcw", 2), (u"art", 3), (u"hxm", 4), + (u"qrt", 5), (u"pad", 6), (u"hoy", 7)] + self.assertEqual(json.loads(s), eval(s)) + self.assertEqual(json.loads(s, object_pairs_hook=lambda x: x), p) + od = json.loads(s, object_pairs_hook=json.OrderedDict) + self.assertEqual(od, json.OrderedDict(p)) + self.assertEqual(type(od), json.OrderedDict) + # the object_pairs_hook takes priority over the object_hook + self.assertEqual(json.loads(s, + object_pairs_hook=json.OrderedDict, + object_hook=lambda x: None), + json.OrderedDict(p)) + + + def test_default_encoding(self): + self.assertEqual(json.loads(u'{"a": "\xe9"}'.encode('utf-8')), + {'a': u'\xe9'}) + + def test_unicode_preservation(self): + self.assertEqual(type(json.loads(u'""')), text_type) + self.assertEqual(type(json.loads(u'"a"')), text_type) + self.assertEqual(type(json.loads(u'["a"]')[0]), text_type) + + def test_ensure_ascii_false_returns_unicode(self): + # http://code.google.com/p/simplejson/issues/detail?id=48 + self.assertEqual(type(json.dumps([], ensure_ascii=False)), text_type) + self.assertEqual(type(json.dumps(0, ensure_ascii=False)), text_type) + self.assertEqual(type(json.dumps({}, ensure_ascii=False)), text_type) + self.assertEqual(type(json.dumps("", ensure_ascii=False)), text_type) + + def test_ensure_ascii_false_bytestring_encoding(self): + # http://code.google.com/p/simplejson/issues/detail?id=48 + doc1 = {u'quux': b('Arr\xc3\xaat sur images')} + doc2 = {u'quux': u'Arr\xeat sur images'} + doc_ascii = '{"quux": "Arr\\u00eat sur images"}' + doc_unicode = u'{"quux": "Arr\xeat sur images"}' + self.assertEqual(json.dumps(doc1), doc_ascii) + self.assertEqual(json.dumps(doc2), doc_ascii) + self.assertEqual(json.dumps(doc1, ensure_ascii=False), doc_unicode) + self.assertEqual(json.dumps(doc2, ensure_ascii=False), doc_unicode) + + def test_ensure_ascii_linebreak_encoding(self): + # http://timelessrepo.com/json-isnt-a-javascript-subset + s1 = u'\u2029\u2028' + s2 = s1.encode('utf8') + expect = '"\\u2029\\u2028"' + expect_non_ascii = u'"\u2029\u2028"' + self.assertEqual(json.dumps(s1), expect) + self.assertEqual(json.dumps(s2), expect) + self.assertEqual(json.dumps(s1, ensure_ascii=False), expect_non_ascii) + self.assertEqual(json.dumps(s2, ensure_ascii=False), expect_non_ascii) + + def test_invalid_escape_sequences(self): + # incomplete escape sequence + self.assertRaises(json.JSONDecodeError, json.loads, '"\\u') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\u1') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\u12') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\u123') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\u1234') + # invalid escape sequence + self.assertRaises(json.JSONDecodeError, json.loads, '"\\u123x"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\u12x4"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\u1x34"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ux234"') + if sys.maxunicode > 65535: + # invalid escape sequence for low surrogate + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u0"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u00"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u000"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u000x"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u00x0"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\u0x00"') + self.assertRaises(json.JSONDecodeError, json.loads, '"\\ud800\\ux000"') + + def test_ensure_ascii_still_works(self): + # in the ascii range, ensure that everything is the same + for c in map(unichr, range(0, 127)): + self.assertEqual( + json.dumps(c, ensure_ascii=False), + json.dumps(c)) + snowman = u'\N{SNOWMAN}' + self.assertEqual( + json.dumps(c, ensure_ascii=False), + '"' + c + '"') + + def test_strip_bom(self): + content = u"\u3053\u3093\u306b\u3061\u308f" + json_doc = codecs.BOM_UTF8 + b(json.dumps(content)) + self.assertEqual(json.load(BytesIO(json_doc)), content) + for doc in json_doc, json_doc.decode('utf8'): + self.assertEqual(json.loads(doc), content) diff --git a/lib/simplejson/tool.py b/lib/simplejson/tool.py new file mode 100644 index 0000000..062e8e2 --- /dev/null +++ b/lib/simplejson/tool.py @@ -0,0 +1,42 @@ +r"""Command-line tool to validate and pretty-print JSON + +Usage:: + + $ echo '{"json":"obj"}' | python -m simplejson.tool + { + "json": "obj" + } + $ echo '{ 1.2:3.4}' | python -m simplejson.tool + Expecting property name: line 1 column 2 (char 2) + +""" +from __future__ import with_statement +import sys +import simplejson as json + +def main(): + if len(sys.argv) == 1: + infile = sys.stdin + outfile = sys.stdout + elif len(sys.argv) == 2: + infile = open(sys.argv[1], 'r') + outfile = sys.stdout + elif len(sys.argv) == 3: + infile = open(sys.argv[1], 'r') + outfile = open(sys.argv[2], 'w') + else: + raise SystemExit(sys.argv[0] + " [infile [outfile]]") + with infile: + try: + obj = json.load(infile, + object_pairs_hook=json.OrderedDict, + use_decimal=True) + except ValueError: + raise SystemExit(sys.exc_info()[1]) + with outfile: + json.dump(obj, outfile, sort_keys=True, indent=' ', use_decimal=True) + outfile.write('\n') + + +if __name__ == '__main__': + main() diff --git a/test_func/save_targer_keys.py b/test_func/save_targer_keys.py new file mode 100644 index 0000000..b2d7545 --- /dev/null +++ b/test_func/save_targer_keys.py @@ -0,0 +1,108 @@ +import os +import sys +import json +import torch +import imageio +import numpy as np +import os.path as osp +sys.path.insert(0, '/'.join(osp.realpath(__file__).split('/')[:-2])) +from thop import profile +from ptflops import get_model_complexity_info + +import artist.data as data +from tools.modules.config import cfg +from tools.modules.unet.util import * +from utils.config import Config as pConfig +from utils.registry_class import ENGINE, MODEL + + +def save_temporal_key(): + cfg_update = pConfig(load=True) + + for k, v in cfg_update.cfg_dict.items(): + if isinstance(v, dict) and k in cfg: + cfg[k].update(v) + else: + cfg[k] = v + + model = MODEL.build(cfg.UNet) + + temp_name = '' + temp_key_list = [] + spth = 'workspace/module_list/UNetSD_I2V_vs_Text_temporal_key_list.json' + for name, module in model.named_modules(): + if isinstance(module, (TemporalTransformer, TemporalTransformer_attemask, TemporalAttentionBlock, TemporalAttentionMultiBlock, TemporalConvBlock_v2, TemporalConvBlock)): + temp_name = name + print(f'Model: {name}') + elif isinstance(module, (ResidualBlock, ResBlock, SpatialTransformer, Upsample, Downsample)): + temp_name = '' + + if hasattr(module, 'weight'): + if temp_name != '' and (temp_name in name): + temp_key_list.append(name) + print(f'{name}') + # print(name) + + save_module_list = [] + for k, p in model.named_parameters(): + for item in temp_key_list: + if item in k: + print(f'{item} --> {k}') + save_module_list.append(k) + + print(int(sum(p.numel() for k, p in model.named_parameters()) / (1024 ** 2)), 'M parameters') + + # spth = 'workspace/module_list/{}' + json.dump(save_module_list, open(spth, 'w')) + a = 0 + + +def save_spatial_key(): + cfg_update = pConfig(load=True) + + for k, v in cfg_update.cfg_dict.items(): + if isinstance(v, dict) and k in cfg: + cfg[k].update(v) + else: + cfg[k] = v + + model = MODEL.build(cfg.UNet) + temp_name = '' + temp_key_list = [] + spth = 'workspace/module_list/UNetSD_I2V_HQ_P_spatial_key_list.json' + for name, module in model.named_modules(): + if isinstance(module, (ResidualBlock, ResBlock, SpatialTransformer, Upsample, Downsample)): + temp_name = name + print(f'Model: {name}') + elif isinstance(module, (TemporalTransformer, TemporalTransformer_attemask, TemporalAttentionBlock, TemporalAttentionMultiBlock, TemporalConvBlock_v2, TemporalConvBlock)): + temp_name = '' + + if hasattr(module, 'weight'): + if temp_name != '' and (temp_name in name): + temp_key_list.append(name) + print(f'{name}') + # print(name) + + save_module_list = [] + for k, p in model.named_parameters(): + for item in temp_key_list: + if item in k: + print(f'{item} --> {k}') + save_module_list.append(k) + + print(int(sum(p.numel() for k, p in model.named_parameters()) / (1024 ** 2)), 'M parameters') + + # spth = 'workspace/module_list/{}' + json.dump(save_module_list, open(spth, 'w')) + a = 0 + + +if __name__ == '__main__': + # save_temporal_key() + save_spatial_key() + + + +# print([k for (k, _) in self.input_blocks.named_parameters()]) + + diff --git a/test_func/test_EndDec.py b/test_func/test_EndDec.py new file mode 100644 index 0000000..0f256b6 --- /dev/null +++ b/test_func/test_EndDec.py @@ -0,0 +1,95 @@ +import os +import sys +import torch +import imageio +import numpy as np +import os.path as osp +sys.path.insert(0, '/'.join(osp.realpath(__file__).split('/')[:-2])) +from PIL import Image, ImageDraw, ImageFont + +from einops import rearrange + +from tools import * +import utils.transforms as data +from utils.seed import setup_seed +from tools.modules.config import cfg +from utils.config import Config as pConfig +from utils.registry_class import ENGINE, DATASETS, AUTO_ENCODER + + +def test_enc_dec(gpu=0): + setup_seed(0) + cfg_update = pConfig(load=True) + + for k, v in cfg_update.cfg_dict.items(): + if isinstance(v, dict) and k in cfg: + cfg[k].update(v) + else: + cfg[k] = v + + save_dir = os.path.join('workspace/test_data/autoencoder', cfg.auto_encoder['type']) + os.system('rm -rf %s' % (save_dir)) + os.makedirs(save_dir, exist_ok=True) + + train_trans = data.Compose([ + data.CenterCropWide(size=cfg.resolution), + data.ToTensor(), + data.Normalize(mean=cfg.mean, std=cfg.std)]) + + vit_trans = data.Compose([ + data.CenterCropWide(size=(cfg.resolution[0], cfg.resolution[0])) if cfg.resolution[0]>cfg.vit_resolution[0] else data.CenterCropWide(size=cfg.vit_resolution), + data.Resize(cfg.vit_resolution), + data.ToTensor(), + data.Normalize(mean=cfg.vit_mean, std=cfg.vit_std)]) + + video_mean = torch.tensor(cfg.mean).view(1, -1, 1, 1) #n c f h w + video_std = torch.tensor(cfg.std).view(1, -1, 1, 1) #n c f h w + + txt_size = cfg.resolution[1] + nc = int(38 * (txt_size / 256)) + font = ImageFont.truetype('data/font/DejaVuSans.ttf', size=13) + + dataset = DATASETS.build(cfg.vid_dataset, sample_fps=4, transforms=train_trans, vit_transforms=vit_trans) + print('There are %d videos' % (len(dataset))) + + autoencoder = AUTO_ENCODER.build(cfg.auto_encoder) + autoencoder.eval() # freeze + for param in autoencoder.parameters(): + param.requires_grad = False + autoencoder.to(gpu) + for idx, item in enumerate(dataset): + local_path = os.path.join(save_dir, '%04d.mp4' % idx) + # ref_frame, video_data, caption = item + ref_frame, vit_frame, video_data = item[:3] + video_data = video_data.to(gpu) + + image_list = [] + video_data_list = torch.chunk(video_data, video_data.shape[0]//cfg.chunk_size,dim=0) + with torch.no_grad(): + decode_data = [] + for chunk_data in video_data_list: + latent_z = autoencoder.encode_firsr_stage(chunk_data).detach() + # latent_z = get_first_stage_encoding(encoder_posterior).detach() + kwargs = {"timesteps": chunk_data.shape[0]} + recons_data = autoencoder.decode(latent_z, **kwargs) + + vis_data = torch.cat([chunk_data, recons_data], dim=2).cpu() + vis_data = vis_data.mul_(video_std).add_(video_mean) # 8x3x16x256x384 + vis_data = vis_data.cpu() + vis_data.clamp_(0, 1) + vis_data = vis_data.permute(0, 2, 3, 1) + vis_data = [(image.numpy() * 255).astype('uint8') for image in vis_data] + image_list.extend(vis_data) + + num_image = len(image_list) + frame_dir = os.path.join(save_dir, 'temp') + os.makedirs(frame_dir, exist_ok=True) + for idx in range(num_image): + tpth = os.path.join(frame_dir, '%04d.png' % (idx+1)) + cv2.imwrite(tpth, image_list[idx][:,:,::-1], [int(cv2.IMWRITE_JPEG_QUALITY), 100]) + cmd = f'ffmpeg -y -f image2 -loglevel quiet -framerate 8 -i {frame_dir}/%04d.png -vcodec libx264 -crf 17 -pix_fmt yuv420p {local_path}' + os.system(cmd); os.system(f'rm -rf {frame_dir}') + + +if __name__ == '__main__': + test_enc_dec() diff --git a/test_func/test_dataset.py b/test_func/test_dataset.py new file mode 100644 index 0000000..33f2a35 --- /dev/null +++ b/test_func/test_dataset.py @@ -0,0 +1,152 @@ +import os +import sys +import imageio +import numpy as np +import os.path as osp +sys.path.insert(0, '/'.join(osp.realpath(__file__).split('/')[:-2])) +from PIL import Image, ImageDraw, ImageFont +import torchvision.transforms as T + +import utils.transforms as data +from tools.modules.config import cfg +from utils.config import Config as pConfig +from utils.registry_class import ENGINE, DATASETS + +from tools import * + +def test_video_dataset(): + cfg_update = pConfig(load=True) + + for k, v in cfg_update.cfg_dict.items(): + if isinstance(v, dict) and k in cfg: + cfg[k].update(v) + else: + cfg[k] = v + + exp_name = os.path.basename(cfg.cfg_file).split('.')[0] + save_dir = os.path.join('workspace', 'test_data/datasets', cfg.vid_dataset['type'], exp_name) + os.system('rm -rf %s' % (save_dir)) + os.makedirs(save_dir, exist_ok=True) + + train_trans = data.Compose([ + data.CenterCropWide(size=cfg.resolution), + data.ToTensor(), + data.Normalize(mean=cfg.mean, std=cfg.std)]) + vit_trans = T.Compose([ + data.CenterCropWide(cfg.vit_resolution), + T.ToTensor(), + T.Normalize(mean=cfg.vit_mean, std=cfg.vit_std)]) + + video_mean = torch.tensor(cfg.mean).view(1, -1, 1, 1) #n c f h w + video_std = torch.tensor(cfg.std).view(1, -1, 1, 1) #n c f h w + + img_mean = torch.tensor(cfg.mean).view(-1, 1, 1) # c f h w + img_std = torch.tensor(cfg.std).view(-1, 1, 1) # c f h w + + vit_mean = torch.tensor(cfg.vit_mean).view(-1, 1, 1) # c f h w + vit_std = torch.tensor(cfg.vit_std).view(-1, 1, 1) # c f h w + + txt_size = cfg.resolution[1] + nc = int(38 * (txt_size / 256)) + font = ImageFont.truetype('data/font/DejaVuSans.ttf', size=13) + + dataset = DATASETS.build(cfg.vid_dataset, sample_fps=cfg.sample_fps[0], transforms=train_trans, vit_transforms=vit_trans) + print('There are %d videos' % (len(dataset))) + for idx, item in enumerate(dataset): + ref_frame, vit_frame, video_data, caption, video_key = item + + video_data = video_data.mul_(video_std).add_(video_mean) + video_data.clamp_(0, 1) + video_data = video_data.permute(0, 2, 3, 1) + video_data = [(image.numpy() * 255).astype('uint8') for image in video_data] + + # Single Image + ref_frame = ref_frame.mul_(img_mean).add_(img_std) + ref_frame.clamp_(0, 1) + ref_frame = ref_frame.permute(1, 2, 0) + ref_frame = (ref_frame.numpy() * 255).astype('uint8') + + # Text image + txt_img = Image.new("RGB", (txt_size, txt_size), color="white") + draw = ImageDraw.Draw(txt_img) + lines = "\n".join(caption[start:start + nc] for start in range(0, len(caption), nc)) + draw.text((0, 0), lines, fill="black", font=font) + txt_img = np.array(txt_img) + + video_data = [np.concatenate([ref_frame, u, txt_img], axis=1) for u in video_data] + spath = os.path.join(save_dir, '%04d.gif' % (idx)) + imageio.mimwrite(spath, video_data, fps =8) + + # if idx > 100: break + + +def test_vit_image(test_video_flag=True): + cfg_update = pConfig(load=True) + + for k, v in cfg_update.cfg_dict.items(): + if isinstance(v, dict) and k in cfg: + cfg[k].update(v) + else: + cfg[k] = v + + exp_name = os.path.basename(cfg.cfg_file).split('.')[0] + save_dir = os.path.join('workspace', 'test_data/datasets', cfg.img_dataset['type'], exp_name) + os.system('rm -rf %s' % (save_dir)) + os.makedirs(save_dir, exist_ok=True) + + train_trans = data.Compose([ + data.CenterCropWide(size=cfg.resolution), + data.ToTensor(), + data.Normalize(mean=cfg.mean, std=cfg.std)]) + vit_trans = data.Compose([ + data.CenterCropWide(cfg.resolution), + data.Resize(cfg.vit_resolution), + data.ToTensor(), + data.Normalize(mean=cfg.vit_mean, std=cfg.vit_std)]) + + img_mean = torch.tensor(cfg.mean).view(-1, 1, 1) # c f h w + img_std = torch.tensor(cfg.std).view(-1, 1, 1) # c f h w + + vit_mean = torch.tensor(cfg.vit_mean).view(-1, 1, 1) # c f h w + vit_std = torch.tensor(cfg.vit_std).view(-1, 1, 1) # c f h w + + txt_size = cfg.resolution[1] + nc = int(38 * (txt_size / 256)) + font = ImageFont.truetype('artist/font/DejaVuSans.ttf', size=13) + + dataset = DATASETS.build(cfg.img_dataset, transforms=train_trans, vit_transforms=vit_trans) + print('There are %d videos' % (len(dataset))) + for idx, item in enumerate(dataset): + ref_frame, vit_frame, video_data, caption, video_key = item + video_data = video_data.mul_(img_std).add_(img_mean) + video_data.clamp_(0, 1) + video_data = video_data.permute(0, 2, 3, 1) + video_data = [(image.numpy() * 255).astype('uint8') for image in video_data] + + # Single Image + vit_frame = vit_frame.mul_(vit_std).add_(vit_mean) + vit_frame.clamp_(0, 1) + vit_frame = vit_frame.permute(1, 2, 0) + vit_frame = (vit_frame.numpy() * 255).astype('uint8') + + zero_frame = np.zeros((cfg.resolution[1], cfg.resolution[1], 3), dtype=np.uint8) + zero_frame[:vit_frame.shape[0], :vit_frame.shape[1], :] = vit_frame + + # Text image + txt_img = Image.new("RGB", (txt_size, txt_size), color="white") + draw = ImageDraw.Draw(txt_img) + lines = "\n".join(caption[start:start + nc] for start in range(0, len(caption), nc)) + draw.text((0, 0), lines, fill="black", font=font) + txt_img = np.array(txt_img) + + video_data = [np.concatenate([zero_frame, u, txt_img], axis=1) for u in video_data] + spath = os.path.join(save_dir, '%04d.gif' % (idx)) + imageio.mimwrite(spath, video_data, fps =8) + + # if idx > 100: break + + +if __name__ == '__main__': + # test_video_dataset() + test_vit_image() + diff --git a/test_func/test_models.py b/test_func/test_models.py new file mode 100644 index 0000000..aa7f78f --- /dev/null +++ b/test_func/test_models.py @@ -0,0 +1,56 @@ +import os +import sys +import torch +import imageio +import numpy as np +import os.path as osp +sys.path.insert(0, '/'.join(osp.realpath(__file__).split('/')[:-2])) +from thop import profile +from ptflops import get_model_complexity_info + +import artist.data as data +from tools.modules.config import cfg +from utils.config import Config as pConfig +from utils.registry_class import ENGINE, MODEL + + +def test_model(): + cfg_update = pConfig(load=True) + + for k, v in cfg_update.cfg_dict.items(): + if isinstance(v, dict) and k in cfg: + cfg[k].update(v) + else: + cfg[k] = v + + model = MODEL.build(cfg.UNet) + print(int(sum(p.numel() for k, p in model.named_parameters()) / (1024 ** 2)), 'M parameters') + + # state_dict = torch.load('cache/pretrain_model/jiuniu_0600000.pth', map_location='cpu') + # model.load_state_dict(state_dict, strict=False) + model = model.cuda() + + x = torch.Tensor(1, 4, 16, 32, 56).cuda() + t = torch.Tensor(1).cuda() + sims = torch.Tensor(1, 32).cuda() + fps = torch.Tensor([8]).cuda() + y = torch.Tensor(1, 1, 1024).cuda() + image = torch.Tensor(1, 3, 256, 448).cuda() + + ret = model(x=x, t=t, y=y, ori_img=image, sims=sims, fps=fps) + print('Out shape if {}'.format(ret.shape)) + + # flops, params = profile(model=model, inputs=(x, t, y, image, sims, fps)) + # print('Model: {:.2f} GFLOPs and {:.2f}M parameters'.format(flops/1e9, params/1e6)) + + def prepare_input(resolution): + return dict(x=[x, t, y, image, sims, fps]) + + flops, params = get_model_complexity_info(model, (1, 4, 16, 32, 56), + input_constructor = prepare_input, + as_strings=True, print_per_layer_stat=True) + print(' - Flops: ' + flops) + print(' - Params: ' + params) + +if __name__ == '__main__': + test_model() diff --git a/test_func/test_save_video.py b/test_func/test_save_video.py new file mode 100644 index 0000000..926308f --- /dev/null +++ b/test_func/test_save_video.py @@ -0,0 +1,24 @@ +import numpy as np +import cv2 + +cap = cv2.VideoCapture('workspace/img_dir/tst.mp4') + +fourcc = cv2.VideoWriter_fourcc(*'H264') + +ret, frame = cap.read() +vid_size = frame.shape[:2][::-1] + +out = cv2.VideoWriter('workspace/img_dir/testwrite.mp4',fourcc, 8, vid_size) +out.write(frame) + +while(cap.isOpened()): + ret, frame = cap.read() + if not ret: break + out.write(frame) + + +cap.release() +out.release() + + +