diff --git a/src/trame_dataclass/v2.py b/src/trame_dataclass/v2.py index d7b96fa..fc2b48d 100644 --- a/src/trame_dataclass/v2.py +++ b/src/trame_dataclass/v2.py @@ -139,12 +139,15 @@ def _setup_class_fields(owner): "CLIENT_ONLY_NAMES", "CLIENT_DEEP_REACTIVE", ]: - if not hasattr(owner, key): - setattr(owner, key, set()) + if key not in owner.__dict__: + parent_set = getattr(owner, key, set()) + setattr(owner, key, set(parent_set)) + # dict for key in ["ENCODERS", "TYPE_CHECKING"]: - if not hasattr(owner, key): - setattr(owner, key, {}) + if key not in owner.__dict__: + parent_dict = getattr(owner, key, {}) + setattr(owner, key, dict(parent_dict)) def check_forward_ref(ref_name): diff --git a/tests/test_inheritance_v2.py b/tests/test_inheritance_v2.py new file mode 100644 index 0000000..7dba3d1 --- /dev/null +++ b/tests/test_inheritance_v2.py @@ -0,0 +1,67 @@ +from trame_dataclass.v2 import ( + StateDataModel, + Sync, +) + + +def test_inheritance_field_names(): + class Simple(StateDataModel): + a = Sync(int, 1) + b = Sync(int, 2) + + class Complex(Simple): + c = Sync(int, 3) + + assert "a" in Complex.FIELD_NAMES + assert "b" in Complex.FIELD_NAMES + assert "c" in Complex.FIELD_NAMES + + assert "c" not in Simple.FIELD_NAMES + + +def test_inheritance_runtime_behavior(): + class Simple(StateDataModel): + a = Sync(int, 10) + + class Complex(Simple): + b = Sync(int, 20) + + simple_obj = Simple() + assert isinstance(simple_obj, Simple) + assert not isinstance(simple_obj, Complex) + + complex_obj = Complex() + assert isinstance(complex_obj, Simple) + assert isinstance(complex_obj, Complex) + + assert simple_obj.a == 10 + assert complex_obj.a == 10 + assert complex_obj.b == 20 + + simple_obj.a = 15 + complex_obj.a = 5 + complex_obj.b = 25 + + assert simple_obj.a == 15 + assert complex_obj.a == 5 + assert complex_obj.b == 25 + + +def test_inheritance_field_isolation(): + class A(StateDataModel): + x = Sync(int, 1) + + class B(A): + y = Sync(int, 2) + + class C(A): + z = Sync(int, 3) + + # B and C should not share mutations + assert "y" in B.FIELD_NAMES + assert "y" not in A.FIELD_NAMES + assert "y" not in C.FIELD_NAMES + + assert "z" in C.FIELD_NAMES + assert "z" not in A.FIELD_NAMES + assert "z" not in B.FIELD_NAMES