Skip to content

Commit

Permalink
Fix serialization of dataclass inheriting from abc.ABC and using __sl…
Browse files Browse the repository at this point in the history
…ots__
  • Loading branch information
ijl committed Oct 1, 2021
1 parent d52f2c9 commit 4c312a8
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/serialize/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,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,
Expand Down
2 changes: 2 additions & 0 deletions src/typeref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,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 FIELD_TYPE_STR: *mut PyObject = 0 as *mut PyObject;
pub static mut ARRAY_STRUCT_STR: *mut PyObject = 0 as *mut PyObject;
pub static mut DTYPE_STR: *mut PyObject = 0 as *mut PyObject;
Expand Down Expand Up @@ -122,6 +123,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);
FIELD_TYPE_STR = PyUnicode_InternFromString("_field_type\0".as_ptr() as *const c_char);
ARRAY_STRUCT_STR =
pyo3::ffi::PyUnicode_InternFromString("__array_struct__\0".as_ptr() as *const c_char);
Expand Down
24 changes: 24 additions & 0 deletions test/test_dataclass.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import abc
import unittest
import uuid
from dataclasses import InitVar, asdict, dataclass, field
Expand Down Expand Up @@ -95,6 +96,23 @@ def __post_init__(self, a: str, b: str):
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"


class DataclassTests(unittest.TestCase):
def test_dataclass(self):
"""
Expand Down Expand Up @@ -291,3 +309,9 @@ def default(obj):
orjson.dumps(obj, option=orjson.OPT_PASSTHROUGH_DATACLASS, default=default),
b'{"name":"a","number":1}',
)


class AbstractDataclassTests(unittest.TestCase):
def test_dataclass_abc(self):
obj = ConcreteAbc(1.0)
self.assertEqual(orjson.dumps(obj), b'{"attr":1.0}')

0 comments on commit 4c312a8

Please sign in to comment.