def test_encode_no_default(self): class Foo: pass with pytest.raises( TypeError, match="Encoding objects of type Foo is unsupported"): msgspec.encode(Foo())
def test_encode_default_errors(self): def default(x): raise TypeError("bad") orig_refcount = sys.getrefcount(default) with pytest.raises(TypeError, match="bad"): msgspec.encode(object(), default=default) assert sys.getrefcount(default) == orig_refcount
def test_encode_default(self): unsupported = object() def default(x): assert x is unsupported return "hello" orig_refcount = sys.getrefcount(default) res = msgspec.encode(unsupported, default=default) assert msgspec.encode("hello") == res assert sys.getrefcount(default) == orig_refcount
def test_encode_parse_arguments_errors(self): with pytest.raises(TypeError, match="Missing 1 required argument"): msgspec.encode() with pytest.raises(TypeError, match="Extra positional arguments"): msgspec.encode(1, lambda x: None) with pytest.raises(TypeError, match="Extra positional arguments"): msgspec.encode(1, 2, 3) with pytest.raises(TypeError, match="Invalid keyword argument 'bad'"): msgspec.encode(1, bad=1) with pytest.raises(TypeError, match="Extra keyword arguments"): msgspec.encode(1, default=lambda x: None, extra="extra")
def test_roundtrip_typed_decoder(self, size): dec = msgspec.Decoder(msgspec.Ext) ext = msgspec.Ext(5, b"x" * size) buf = msgspec.encode(ext) out = dec.decode(buf) assert out == ext
def check_Decoder_decode_any() -> None: dec = msgspec.Decoder() b = msgspec.encode([1, 2, 3]) o = dec.decode(b) reveal_type(dec) # assert "Decoder" in typ and "Any" in typ reveal_type(o) # assert "Any" in typ
def test_serialize_compatibility(self, size): msgpack = pytest.importorskip("msgpack") data = b"x" * size code = 5 msgspec_bytes = msgspec.encode(msgspec.Ext(code, data)) msgpack_bytes = msgpack.dumps(msgpack.ExtType(code, data)) assert msgspec_bytes == msgpack_bytes
def test_roundtrip(self, size): data = b"x" * size code = 5 buf = msgspec.encode(msgspec.Ext(code, data)) out = msgspec.decode(buf) assert out.code == code assert out.data == data
def test_typed_decoder_skips_ext_hook(self): def ext_hook(code, data): assert False, "shouldn't ever get called" msg = [None, msgspec.Ext(1, b"test")] dec = msgspec.Decoder(List[Optional[msgspec.Ext]]) buf = msgspec.encode(msg) out = dec.decode(buf) assert out == msg
def check_Decoder_decode_type_comment() -> None: dec = msgspec.Decoder() # type: msgspec.Decoder[List[int]] b = msgspec.encode([1, 2, 3]) o = dec.decode(b) reveal_type( dec ) # assert "Decoder" in typ and ("List" in typ or "list" in typ) and "int" in typ reveal_type(o) # assert ("List" in typ or "list" in typ) and "int" in typ
def test_decode_hashable_struct_in_key(self): class Test(msgspec.Struct): data: List[int] def __hash__(self): return hash(tuple(self.data)) orig = {(1, Test([1, 2])): [1, 2]} data = msgspec.encode(orig) out = msgspec.Decoder(Dict[Tuple[int, Test], List[int]]).decode(data) assert orig == out
def test_decoder_ext_hook_raises(self): class CustomError(Exception): pass def ext_hook(code, buf): raise CustomError msg = msgspec.encode(range(5), default=lambda x: msgspec.Ext(1, b"test")) with pytest.raises(CustomError): msgspec.decode(msg, ext_hook=ext_hook)
def test_decoder_ext_hook(self, use_function): obj = {"x": range(10)} exp_buf = pickle.dumps(range(10)) def default(x): return msgspec.Ext(5, pickle.dumps(x)) def ext_hook(code, buf): assert isinstance(buf, memoryview) assert bytes(buf) == exp_buf assert code == 5 return pickle.loads(buf) msg = msgspec.encode(obj, default=default) if use_function: out = msgspec.decode(msg, ext_hook=ext_hook) else: dec = msgspec.Decoder(ext_hook=ext_hook) out = dec.decode(msg) assert out == obj
def test_encode_large_object(self): """Check that buffer resize works""" data = b"x" * 4097 dec = msgspec.Decoder() assert dec.decode(msgspec.encode(data)) == data
def test_decode_tuple_dict_keys_as_tuples(self): orig = {(1, 2): [1, 2, [3, 4]], (1, (2, 3)): [4, 5, 6]} data = msgspec.encode(orig) out = msgspec.decode(data) assert orig == out
def test_decode_dict_key_status_forwarded_through_typed_tuples(self, typ): orig = {(1, (2, 3)): [1, 2, 3]} data = msgspec.encode(orig) out = msgspec.Decoder(typ).decode(data) assert orig == out
def test_serialize_other_types(self, typ): buf = b"test" a = msgspec.encode(msgspec.Ext(1, buf)) b = msgspec.encode(msgspec.Ext(1, typ(buf))) assert a == b
def test_decode_tuple_set_keys_as_tuples(self): orig = {(1, 2), (3, (4, 5)), 6} data = msgspec.encode(orig) out = msgspec.decode(data, type=set) assert orig == out
def test_encode_error(self): with pytest.raises(TypeError): msgspec.encode(object())
def check_encode_default() -> None: msgspec.encode(object(), default=lambda x: None)
def check_decode_any() -> None: b = msgspec.encode([1, 2, 3]) o = msgspec.decode(b) reveal_type(o) # assert "Any" in typ
def test_ext_typed_decoder_error(self): dec = msgspec.Decoder(msgspec.Ext) with pytest.raises(msgspec.DecodingError, match="expected `Ext`"): assert dec.decode(msgspec.encode(1))
def test_encode(self): dec = msgspec.Decoder() assert dec.decode(msgspec.encode(1)) == 1
def test_decoder_ext_hook_bad_signature(self): msg = msgspec.encode(range(5), default=lambda x: msgspec.Ext(1, b"test")) with pytest.raises(TypeError): msgspec.decode(msg, ext_hook=lambda: None)
def check_decode_typed() -> None: b = msgspec.encode([1, 2, 3]) o = msgspec.decode(b, type=List[int]) reveal_type(o) # assert ("List" in typ or "list" in typ) and "int" in typ
def setup(self): self.buf = msgspec.encode([1, 2, 3])
def check_encode() -> None: b = msgspec.encode([1, 2, 3]) reveal_type(b) # assert "bytes" in typ