diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a30e3de..d4e3bcda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog ## Next Version +## 1.0.1 - 13/10/2021 +### Fixed +- Decrement refcount for numpy `PyArrayInterface`. by [@ilj](https://github.com/ijl/orjson/commit/4c312a82f5215ff71eed5bd09d28fa004999299b). +- Fix serialization of dataclass inheriting from `abc.ABC` and using `__slots__`. by [@ilj](https://github.com/ijl/orjson/commit/4c312a82f5215ff71eed5bd09d28fa004999299b) +### Changed +- Updated dependencies. +- `find_str_kind` test for 4-byte before latin1. by [@ilj](https://github.com/ijl/orjson/commit/05860e1a2ea3e8f90823d6a59e5fc9929a8692b5) ## 1.0.0 - 31/8/2021 ### Changed - Aligned to orjson's flags and features of SIMD. Didn't include the stable compilation part as seems unnecessary. diff --git a/Cargo.lock b/Cargo.lock index 865dbfae..29cd3680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ahash" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +checksum = "991984e3fd003e7ba02eb724f87a0f997b78677c46c0e91f8424ad7394c9886a" dependencies = [ "getrandom", "once_cell", @@ -87,9 +87,9 @@ checksum = "3094308123a0e9fd59659ce45e22de9f53fc1d2ac6e1feb9fef988e4f76cad77" [[package]] name = "instant" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd" dependencies = [ "cfg-if 1.0.0", ] @@ -102,9 +102,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "libc" -version = "0.2.101" +version = "0.2.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" [[package]] name = "libm" @@ -138,7 +138,7 @@ checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "ormsgpack" -version = "1.0.0" +version = "1.0.1" dependencies = [ "ahash", "associative-cache", @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "packed_simd_2" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e64858a2d3733fdd61adfdd6da89aa202f7ff0e741d2fc7ed1e452ba9dc99d7" +checksum = "71c0c06716cfc81616fa8e22b721ce92fecd594508bc0eb3d04ae3ef35ac10c5" dependencies = [ "cfg-if 0.1.10", "libm", @@ -194,9 +194,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a192cd06356bb941c663c969a7f3e27c7c8e187efe772c1406a447f122443f71" +checksum = "35100f9347670a566a67aa623369293703322bb9db77d99d7df7313b575ae0c8" dependencies = [ "cfg-if 1.0.0", "libc", @@ -206,9 +206,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650911ce22a793e9af67a0a880741ab1519e4f84740642716cbe83e129d17a2e" +checksum = "d12961738cacbd7f91b7c43bc25cfeeaa2698ad07a04b3be0aa88b950865738f" dependencies = [ "once_cell", ] @@ -269,9 +269,9 @@ checksum = "c970da16e7c682fa90a261cf0724dee241c9f7831635ecc4e988ae8f3b505559" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "version_check" diff --git a/Cargo.toml b/Cargo.toml index 4dc9f0a4..491570d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ormsgpack" -version = "1.0.0" +version = "1.0.1" authors = ["Aviram Hassan "] description = "Fast, correct Python msgpack library supporting dataclasses, datetimes, and numpy" edition = "2018" @@ -44,11 +44,11 @@ encoding_rs = { version = "0.8", default_features = false } inlinable_string = { version = "0.1" } itoa = { version = "0.4", default_features = false } once_cell = { version = "1", default_features = false } -pyo3 = { version = "^0.14.1", default_features = false, features = ["extension-module"]} +pyo3 = { version = "^0.14.5", default_features = false, features = ["extension-module"]} ryu = { version = "1", default_features = false } serde = { version = "1", default_features = false } simdutf8 = { version = "0.1", default_features = false, features = ["std"] } -smallvec = { version = "^1.6", default_features = false, features = ["union", "write"] } +smallvec = { version = "^1.7", default_features = false, features = ["union", "write"] } rmp = { version = "^0.8.10"} rmp-serde = {version = "^0.15.4"} diff --git a/src/serialize/numpy.rs b/src/serialize/numpy.rs index 15611d29..67119fc0 100644 --- a/src/serialize/numpy.rs +++ b/src/serialize/numpy.rs @@ -207,7 +207,8 @@ impl<'a> NumpyArray { impl Drop for NumpyArray { fn drop(&mut self) { if self.depth == 0 { - ffi!(Py_XDECREF(self.capsule as *mut pyo3::ffi::PyObject)) + ffi!(Py_DECREF(self.array as *mut pyo3::ffi::PyObject)); + ffi!(Py_DECREF(self.capsule as *mut pyo3::ffi::PyObject)); } } } diff --git a/src/serialize/serializer.rs b/src/serialize/serializer.rs index d2b2c035..4ff09d0d 100644 --- a/src/serialize/serializer.rs +++ b/src/serialize/serializer.rs @@ -249,7 +249,10 @@ impl<'p> Serialize for PyObjectSerializer { err!(RECURSION_LIMIT_REACHED) } let dict = ffi!(PyObject_GetAttr(self.ptr, DICT_STR)); - if unlikely!(dict.is_null()) { + let ob_type = ob_type!(self.ptr); + if unlikely!( + dict.is_null() || ffi!(PyDict_Contains((*ob_type).tp_dict, SLOTS_STR)) == 1 + ) { unsafe { pyo3::ffi::PyErr_Clear() }; DataclassFallbackSerializer::new( self.ptr, diff --git a/src/typeref.rs b/src/typeref.rs index 77cbd6b1..87463bc6 100644 --- a/src/typeref.rs +++ b/src/typeref.rs @@ -52,6 +52,7 @@ pub static mut EMPTY_UNICODE: *mut PyObject = 0 as *mut PyObject; pub static mut DST_STR: *mut PyObject = 0 as *mut PyObject; pub static mut DICT_STR: *mut PyObject = 0 as *mut PyObject; pub static mut DATACLASS_FIELDS_STR: *mut PyObject = 0 as *mut PyObject; +pub static mut SLOTS_STR: *mut PyObject = 0 as *mut PyObject; pub static mut PYDANTIC_FIELDS_STR: *mut PyObject = 0 as *mut PyObject; pub static mut FIELD_TYPE_STR: *mut PyObject = 0 as *mut PyObject; pub static mut ARRAY_STRUCT_STR: *mut PyObject = 0 as *mut PyObject; @@ -120,6 +121,7 @@ pub fn init_typerefs() { DICT_STR = PyUnicode_InternFromString("__dict__\0".as_ptr() as *const c_char); DATACLASS_FIELDS_STR = PyUnicode_InternFromString("__dataclass_fields__\0".as_ptr() as *const c_char); + SLOTS_STR = PyUnicode_InternFromString("__slots__\0".as_ptr() as *const c_char); PYDANTIC_FIELDS_STR = PyUnicode_InternFromString("__fields__\0".as_ptr() as *const c_char); FIELD_TYPE_STR = PyUnicode_InternFromString("_field_type\0".as_ptr() as *const c_char); ARRAY_STRUCT_STR = diff --git a/src/unicode.rs b/src/unicode.rs index d3134b1e..14dd8396 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -51,11 +51,11 @@ enum PyUnicodeKind { fn find_str_kind(buf: &str, num_chars: usize) -> PyUnicodeKind { if buf.len() == num_chars { PyUnicodeKind::Ascii + } else if is_four_byte(buf) { + PyUnicodeKind::FourByte } else if encoding_rs::mem::is_str_latin1(buf) { // fails fast, no obvious effect on CJK PyUnicodeKind::OneByte - } else if is_four_byte(buf) { - PyUnicodeKind::FourByte } else { PyUnicodeKind::TwoByte } diff --git a/tests/test_dataclass.py b/tests/test_dataclass.py index 38d9ee81..3231d55a 100644 --- a/tests/test_dataclass.py +++ b/tests/test_dataclass.py @@ -1,5 +1,5 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) - +import abc import uuid from dataclasses import InitVar, asdict, dataclass, field from enum import Enum @@ -96,6 +96,22 @@ def __post_init__(self, a: str, b: str): self._other = 1 self.ab = f"{a} {b}" +class AbstractBase(abc.ABC): + @abc.abstractmethod + def key(self): + raise NotImplementedError + + +@dataclass(frozen=True) +class ConcreteAbc(AbstractBase): + + __slots__ = ("attr",) + + attr: float + + def key(self): + return "dkjf" + def test_dataclass(): """ @@ -260,3 +276,8 @@ def default(obj): assert ormsgpack.packb( obj, option=ormsgpack.OPT_PASSTHROUGH_DATACLASS, default=default ) == msgpack.packb({"name": "a", "number": 1}) + + +def test_dataclass_abc(): + obj = ConcreteAbc(1.0) + assert ormsgpack.packb(obj) == msgpack.packb({"attr": 1.0})