def test_overloading(file_regression: FileRegressionFixture) -> None: try: # Create and register a custom encoder @sdjson.encoders.register(Decimal) def encoder_1(obj): return "Result from first registration" # Test that we get the expected output from the first encoder assert sdjson.dumps(Decimal(1)) == '"Result from first registration"' # Create and register a new custom encoder that overloads the previous one @sdjson.encoders.register(Decimal) def encoder_2(obj): return "Result from second registration" # Test that we get the expected output from the second encoder assert sdjson.dumps(Decimal(2)) == '"Result from second registration"' print(sdjson.encoders.registry.items()) check_file_regression(remove_memaddr(str(sdjson.encoders.registry.items())), file_regression) finally: # Cleanup sdjson.encoders.unregister(Decimal)
def test_sdjson(): d = Device( 1000, "Television", DeviceType.RC, MagicMapping( make="Samsung", smart=True, ports=Counter([Port.HDMI, Port.HDMI, Port.HDMI, Port.VGA]), ), ) expected = """{ "device_id": 1000, "display_name": "Television", "device_type": 1, "configuration": { "make": "Samsung", "smart": true, "ports": { "1": 3, "2": 1 } } }""" assert sdjson.dumps(d, indent=2) == expected loaded_device = Device.from_dict(sdjson.loads(sdjson.dumps(d))) # the Counter won't be equal because the enum's have become disassociated assert loaded_device.device_id == d.device_id assert loaded_device.display_name == d.display_name assert loaded_device.configuration["make"] == d.configuration["make"] assert loaded_device.configuration["smart"] == d.configuration["smart"]
def test_weird_floats() -> None: for enum, expected in zip(WierdNum, ("Infinity", "-Infinity", "NaN")): assert sdjson.dumps(enum) == expected if not isnan(enum): assert float(sdjson.dumps(enum)) == enum assert sdjson.loads(sdjson.dumps(enum)) == enum else: assert isnan(float(sdjson.dumps(enum))) assert isnan(sdjson.loads(sdjson.dumps(enum)))
def test_weird_floats(): for enum, expected in zip(WierdNum, ('Infinity', '-Infinity', 'NaN')): assert sdjson.dumps(enum) == expected if not isnan(enum): assert float(sdjson.dumps(enum)) == enum assert sdjson.loads(sdjson.dumps(enum)) == enum else: assert isnan(float(sdjson.dumps(enum))) assert isnan(sdjson.loads(sdjson.dumps(enum)))
def test_dump_skipkeys() -> None: v = {b"invalid_key": False, "valid_key": True} with pytest.raises(TypeError): sdjson.dumps(v) s = sdjson.dumps(v, skipkeys=True) o = sdjson.loads(s) assert "valid_key" in o assert b"invalid_key" not in o
def test_highly_nested_objects_encoding(): # See #12051 l, d = [], {} for x in range(100000): l, d = [l], {'k': d} with pytest.raises(RecursionError): sdjson.dumps(l) with pytest.raises(RecursionError): sdjson.dumps(d)
def test_dump_skipkeys(): v = {b'invalid_key': False, 'valid_key': True} with pytest.raises(TypeError): sdjson.dumps(v) s = sdjson.dumps(v, skipkeys=True) o = sdjson.loads(s) assert 'valid_key' in o assert b'invalid_key' not in o
def test_indent(): 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 = sdjson.dumps(h) d2 = sdjson.dumps(h, indent=2, sort_keys=True, separators=(',', ': ')) d3 = sdjson.dumps(h, indent='\t', sort_keys=True, separators=(',', ': ')) d4 = sdjson.dumps(h, indent=2, sort_keys=True) d5 = sdjson.dumps(h, indent='\t', sort_keys=True) h1 = sdjson.loads(d1) h2 = sdjson.loads(d2) h3 = sdjson.loads(d3) assert h1 == h assert h2 == h assert h3 == h assert d2 == expect.expandtabs(2) assert d3 == expect assert d4 == d2 assert d5 == d3
def test_allow_nan(): for val in (float('inf'), float('-inf'), float('nan')): out = sdjson.dumps([val]) if val == val: # inf assert sdjson.loads(out) == [val] else: # nan res = sdjson.loads(out) assert len(res) == 1 assert res[0] != res[0] with pytest.raises(ValueError): sdjson.dumps([val], allow_nan=False)
def test_non_string_keys_dict() -> None: data = {'a': 1, (1, 2): 2} # TODO: if platform.python_implementation() == "PyPy": match_string = r"key \(1, 2\) is not a string" elif sys.version_info[:2] > (3, 6): match_string = "keys must be str, int, float, bool or None, not tuple" else: match_string = "keys must be a string" with pytest.raises(TypeError, match=match_string): sdjson.dumps(data)
def test_multiple_files(): from .glossia import thorn from .glossia import talon # Test that we get the expected output when encoding a Decimal assert sdjson.dumps(Decimal(1)) == '"1"' # Test that we get the expected output when encoding a Fraction assert sdjson.dumps(Fraction(2, 3)) == '"2/3"' # Cleanup sdjson.encoders.unregister(Decimal) sdjson.encoders.unregister(Fraction)
def test_allow_nan() -> None: for val in (float("inf"), float("-inf"), float("nan")): out = sdjson.dumps([val]) if val == val: # inf assert sdjson.loads(out) == [val] else: # nan res = sdjson.loads(out) assert len(res) == 1 assert res[0] != res[0] with pytest.raises( ValueError, match="Out of range float values are not JSON compliant"): sdjson.dumps([val], allow_nan=False)
def test_dictrecursion(): x = {} x["test"] = x try: sdjson.dumps(x) except ValueError: pass else: pytest.fail("didn't raise ValueError on dict recursion") x = {} y = {"a": x, "b": x} # ensure that the marker is cleared sdjson.dumps(x)
def test_highly_nested_objects_encoding() -> None: # See #12051 l: List[List] d: Dict[str, Dict] l, d = [], {} for x in range(100000): l, d = [l], {'k': d} with pytest.raises(RecursionError): sdjson.dumps(l) with pytest.raises(RecursionError): sdjson.dumps(d)
def test_fraction_str(): # Create and register a custom encoder for Fraction that turns it into a str @sdjson.encoders.register(Fraction) def encode_fraction_str(obj): return str(obj) assert sdjson.dumps(Fraction(13, 10)) == '"13/10"' assert sdjson.dumps(Fraction(3, 4)) == '"3/4"' assert sdjson.dumps(Fraction(9, 11)) == '"9/11"' assert sdjson.dumps(Fraction(140, 144)) == '"35/36"' assert sdjson.dumps(Fraction(2, 7)) == '"2/7"' # Cleanup sdjson.encoders.unregister(Fraction)
def test_fraction_float(): # Create and register a custom encoder for Fraction that turns it into a float @sdjson.encoders.register(Fraction) def encode_fraction_float(obj): return float(obj) assert sdjson.dumps(Fraction(13, 10)) == "1.3" assert sdjson.dumps(Fraction(3, 4)) == "0.75" assert sdjson.dumps(Fraction(9, 11)) == "0.8181818181818182" assert sdjson.dumps(Fraction(140, 144)) == "0.9722222222222222" assert sdjson.dumps(Fraction(2, 7)) == "0.2857142857142857" # Cleanup sdjson.encoders.unregister(Fraction)
def test_encode_null_character(): test_input = "31337 \x00 1337" output = sd_ujson.encode(test_input) assert test_input == sdjson.loads(output) assert output == sdjson.dumps(test_input) assert test_input == sd_ujson.decode(output) test_input = "\x00" output = sd_ujson.encode(test_input) assert test_input == sdjson.loads(output) assert output == sdjson.dumps(test_input) assert test_input == sd_ujson.decode(output) assert '" \\u0000\\r\\n "' == sd_ujson.dumps(" \u0000\r\n ")
def test_dictrecursion() -> None: x: Dict[str, Dict] = {} x["test"] = x try: sdjson.dumps(x) except ValueError: pass else: pytest.fail("didn't raise ValueError on dict recursion") x = {} y = {'a': x, 'b': x} # ensure that the marker is cleared sdjson.dumps(x)
def test_unregister() -> None: # Create and register a custom encoder for Decimal that turns it into a string @sdjson.encoders.register(Decimal) def encode_str(obj): return str(obj) # Test that we get the expected output from the first encoder assert sdjson.dumps(Decimal(1)) == '"1"' # Unregister that encoder sdjson.unregister_encoder(Decimal) # We should now get an error with pytest.raises(TypeError, match="Object of type [']*Decimal[']* is not JSON serializable") as e: sdjson.dumps(Decimal(2)) assert e.type is TypeError
def spectrum_search(self, mass_spec: MassSpectrum, n_hits: int = 5) -> List[SearchResult]: """ Perform a Quick Spectrum Search of the mass spectral library. :param mass_spec: The mass spectrum to search against the library. :param n_hits: The number of hits to return. :return: List of possible identities for the mass spectrum. """ if not isinstance(mass_spec, MassSpectrum): raise TypeError( "`mass_spec` must be a pyms.Spectrum.MassSpectrum object.") retry_count = 0 # Keep trying until it works while retry_count < 240: try: res = requests.post( f"http://localhost:5001/search/quick/?n_hits={n_hits}", json=sdjson.dumps(mass_spec), ) print(res.text) return hit_list_from_json(res.text) except requests.exceptions.ConnectionError: time.sleep(0.5) retry_count += 1 raise TimeoutError("Unable to communicate with the search server.")
def test_encode_to_utf8(): test_input = b"\xe6\x97\xa5\xd1\x88" test_input = test_input.decode("utf-8") enc = sd_ujson.encode(test_input, ensure_ascii=False) dec = sd_ujson.decode(enc) assert enc == sdjson.dumps(test_input, ensure_ascii=False) assert dec == sdjson.loads(enc)
def test_dict_keys(): s, b, h, r = BigNum e, p, t = FloatNum i, j, n = WierdNum d = { s: 'tiny', b: 'large', h: 'larger', r: 'largest', e: "Euler's number", p: 'pi', t: 'tau', i: 'Infinity', j: '-Infinity', n: 'NaN', } nd = sdjson.loads(sdjson.dumps(d)) assert nd[str(SMALL)] == 'tiny' assert nd[str(BIG)] == 'large' assert nd[str(HUGE)] == 'larger' assert nd[str(REALLY_HUGE)] == 'largest' assert nd[repr(E)] == "Euler's number" assert nd[repr(PI)] == 'pi' assert nd[repr(TAU)] == 'tau' assert nd['Infinity'] == 'Infinity' assert nd['-Infinity'] == '-Infinity' assert nd['NaN'] == 'NaN'
def full_search_with_ref_data( self, mass_spec: MassSpectrum, n_hits: int = 5, ) -> List[Tuple[SearchResult, ReferenceData]]: """ Perform a Full Spectrum Search of the mass spectral library, including reference data. :param mass_spec: The mass spectrum to search against the library. :param n_hits: The number of hits to return. :return: List of tuples consisting of the possible identities for the mass spectrum and the reference data from the library. """ if not isinstance(mass_spec, MassSpectrum): raise TypeError( "`mass_spec` must be a pyms.Spectrum.MassSpectrum object.") retry_count = 0 # Keep trying until it works while retry_count < 240: try: res = requests.post( f"http://localhost:5001/search/spectrum_with_ref_data/?n_hits={n_hits}", json=sdjson.dumps(mass_spec)) return hit_list_with_ref_data_from_json(res.text) except requests.exceptions.ConnectionError: time.sleep(0.5) retry_count += 1 raise TimeoutError("Unable to communicate with the search server.")
def check(indent, expected): d1 = sdjson.dumps(h, indent=indent) assert d1 == expected sio = StringIO() sdjson.dump(h, sio, indent=indent) assert sio.getvalue() == expected
def test_bytes_decode(): for encoding, bom in [ ('utf-8', codecs.BOM_UTF8), ('utf-16be', codecs.BOM_UTF16_BE), ('utf-16le', codecs.BOM_UTF16_LE), ('utf-32be', codecs.BOM_UTF32_BE), ('utf-32le', codecs.BOM_UTF32_LE), ]: data = ["a\xb5\u20ac\U0001d120"] encoded = sdjson.dumps(data).encode(encoding) assert sdjson.loads(bom + encoded) == data assert sdjson.loads(encoded) == data with pytest.raises(UnicodeDecodeError): sdjson.loads(b'["\x80"]') # RFC-7159 and ECMA-404 extend JSON to allow documents that # consist of only a string, which can present a special case # not covered by the encoding detection patterns specified in # RFC-4627 for utf-16-le (XX 00 XX 00). assert sdjson.loads('"\u2600"'.encode('utf-16-le')) == '\u2600' # Encoding detection for small (<4) bytes objects # is implemented as a special case. RFC-7159 and ECMA-404 # allow single codepoint JSON documents which are only two # bytes in utf-16 encodings w/o BOM. assert sdjson.loads(b'5\x00') == 5 assert sdjson.loads(b'\x007') == 7 assert sdjson.loads(b'57') == 57
def test_encode_mutated() -> None: a = [object()] * 10 def crasher(obj): del a[-1] assert sdjson.dumps(a, default=crasher) == "[null, null, null, null, null]"
def test_separators() -> None: 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 = sdjson.dumps(h) d2 = sdjson.dumps(h, indent=2, sort_keys=True, separators=(" ,", " : ")) h1 = sdjson.loads(d1) h2 = sdjson.loads(d2) assert h1 == h assert h2 == h assert d2 == expect
def test_double_long_issue(): sut = {"a": -4342969734183514} encoded = sdjson.dumps(sut) decoded = sdjson.loads(encoded) assert sut == decoded encoded = sd_ujson.encode(sut) decoded = sd_ujson.decode(encoded) assert sut == decoded
def test_double_long_decimal_issue(): sut = {"a": -12345678901234.56789012} encoded = sdjson.dumps(sut) decoded = sdjson.loads(encoded) assert sut == decoded encoded = sd_ujson.encode(sut) decoded = sd_ujson.decode(encoded) assert sut == decoded
def test_encode_symbols(): s = "\u273f\u2661\u273f" # Рю┐РЎАРю┐ encoded = sd_ujson.dumps(s) encoded_json = sdjson.dumps(s) assert len(encoded) == len(s) * 6 + 2 # 6 characters + quotes assert encoded == encoded_json decoded = sd_ujson.loads(encoded) assert s == decoded # sd_ujson outputs an UTF-8 encoded str object encoded = sd_ujson.dumps(s, ensure_ascii=False) # json outputs an unicode object encoded_json = sdjson.dumps(s, ensure_ascii=False) assert len(encoded) == len(s) + 2 # original length + quotes assert encoded == encoded_json decoded = sd_ujson.loads(encoded) assert s == decoded