# dabmodel (c) by chacha # # dabmodel is licensed under a # Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License. # # You should have received a copy of the license along with this # work. If not, see . import unittest from os import chdir from pathlib import Path from typing import ( Any, Annotated, ) print(__name__) print(__package__) from src import dabmodel as dm testdir_path = Path(__file__).parent.resolve() chdir(testdir_path.parent.resolve()) def test_initializer_safe_testfc(): eval("print('hi')") class FeatureTest(unittest.TestCase): def setUp(self): print("\n->", unittest.TestCase.id(self)) def immutable_vars__test_field(self, obj: Any, name: str, default_value: Any, test_value: Any): # field is not in the class self.assertNotIn(name, dir(obj.__class__)) # field is in the object self.assertIn(name, dir(obj)) # field is in the schema self.assertIn(name, obj.__lam_schema__.keys()) # field is readable self.assertEqual(getattr(obj, name), default_value) # field is read only with self.assertRaises(dm.ReadOnlyField): setattr(obj, name, test_value) def test_simple(self): """Testing first appliance feature, and Field types (simple)""" # class can be created class Appliance1(dm.Appliance): VarStrOuter: str = "testvalue APPLIANCE" class Feature1(dm.Feature): VarStrInner: str = "testvalue FEATURE" app1 = Appliance1() self.assertIsInstance(Appliance1.__lam_schema__["VarStrOuter"], dm.LAMField) self.assertTrue(app1.__lam_schema__["VarStrOuter"].is_frozen()) self.assertIn("Feature1", app1.__lam_schema__["features"]) self.assertIn("VarStrInner", app1.__lam_schema__["features"]["Feature1"].__lam_schema__) self.assertIsInstance( app1.__lam_schema__["features"]["Feature1"].__lam_schema__["VarStrInner"], dm.LAMField, ) self.assertTrue(hasattr(app1, "Feature1")) self.assertTrue(app1.Feature1.frozen) print(app1) print(app1.Feature1) print(app1.Feature1.__lam_schema__["VarStrInner"]) self.assertTrue(app1.Feature1.__lam_schema__["VarStrInner"].is_frozen()) self.assertTrue(hasattr(app1.Feature1, "VarStrInner")) def test_inheritance(self): """Testing first appliance feature, and Field types (simple)""" # class can be created class Appliance1(dm.Appliance): VarStrOuter: str = "testvalue APPLIANCE1" class Feature1(dm.Feature): VarStrInner: str = "testvalue FEATURE1" VarInt: int = 42 print(dir(Appliance1)) class Appliance2(Appliance1): VarStrOuter = "testvalue APPLIANCE2" class Feature2(dm.Feature): VarStrInner: str = "testvalue FEATURE2" print(dir(Appliance2)) class Appliance3(Appliance2): VarStrOuter = "testvalue APPLIANCE3" class Feature1(Appliance1.Feature1): VarStrInner = "testvalue FEATURE1 modded" class Feature3(dm.Feature): VarStrInner: str = "testvalue FEATURE3" print(dir(Appliance3)) app1 = Appliance1() app2 = Appliance2() app3 = Appliance3() self.assertIsInstance(Appliance1.__lam_schema__["VarStrOuter"], dm.LAMField) self.assertTrue(app1.__lam_schema__["VarStrOuter"].is_frozen()) self.assertIn("Feature1", app1.__lam_schema__["features"]) self.assertIn("VarStrInner", app1.__lam_schema__["features"]["Feature1"].__lam_schema__) self.assertIsInstance( app1.__lam_schema__["features"]["Feature1"].__lam_schema__["VarStrInner"], dm.LAMField, ) self.assertTrue(hasattr(app1, "Feature1")) self.assertTrue(app1.Feature1.__lam_schema__["VarStrInner"].is_frozen()) self.assertTrue(hasattr(app1.Feature1, "VarStrInner")) self.assertEqual(app1.VarStrOuter, "testvalue APPLIANCE1") self.assertEqual(app1.Feature1.VarStrInner, "testvalue FEATURE1") self.assertEqual(app1.Feature1.VarInt, 42) self.assertEqual(app2.VarStrOuter, "testvalue APPLIANCE2") self.assertEqual(app2.Feature2.VarStrInner, "testvalue FEATURE2") self.assertEqual(app3.VarStrOuter, "testvalue APPLIANCE3") self.assertEqual(app3.Feature1.VarStrInner, "testvalue FEATURE1 modded") self.assertEqual(app3.Feature1.VarInt, 42) self.assertEqual(app3.Feature3.VarStrInner, "testvalue FEATURE3") class Appliance4(Appliance3): VarStrOuter = "testvalue APPLIANCE4" class Feature1(Appliance3.Feature1): VarStrInner = "testvalue FEATURE1 modded 3" def test_inheritance2(self): """Testing first appliance feature, and Field types (simple)""" # class can be created class Appliance1(dm.Appliance): class Feature1(dm.Feature): VarStrInner: str = "testvalue FEATURE1" # check cannot REdefine a feature from Feature with self.assertRaises(dm.InvalidFeatureInheritance): class Appliance2(Appliance1): class Feature1(dm.Feature): ... class Appliance2b(Appliance1): class Feature1(Appliance1.Feature1): ... # check only REdefine a feature from highest parent with self.assertRaises(dm.InvalidFeatureInheritance): class Appliance3(Appliance2b): class Feature1(Appliance1.Feature1): ... class Appliance3b(Appliance2b): class Feature1(Appliance2b.Feature1): ... app1 = Appliance1() app2 = Appliance2b() app3 = Appliance3b() self.assertEqual(app1.Feature1.VarStrInner, "testvalue FEATURE1") self.assertEqual(app2.Feature1.VarStrInner, "testvalue FEATURE1") self.assertEqual(app3.Feature1.VarStrInner, "testvalue FEATURE1") class Appliance4(Appliance3b): class Feature1(Appliance3b.Feature1): VarStrInner = "testvalue FEATURE4" self.assertEqual(app1.Feature1.VarStrInner, "testvalue FEATURE1") self.assertEqual(app2.Feature1.VarStrInner, "testvalue FEATURE1") self.assertEqual(app3.Feature1.VarStrInner, "testvalue FEATURE1") app4 = Appliance4() self.assertEqual(app1.Feature1.VarStrInner, "testvalue FEATURE1") self.assertEqual(app2.Feature1.VarStrInner, "testvalue FEATURE1") self.assertEqual(app3.Feature1.VarStrInner, "testvalue FEATURE1") self.assertEqual(app4.Feature1.VarStrInner, "testvalue FEATURE4") def test_inherit_declared(self): class App(dm.Appliance): class F1(dm.Feature): val: int = 1 class MyF1(App.F1): val = 2 val2: str = "toto" app = App(F1=MyF1) self.assertIsInstance(app.F1, MyF1) self.assertEqual(app.F1.val, 2) self.assertEqual(app.F1.val2, "toto") def test_override_declared(self): class App(dm.Appliance): class F1(dm.Feature): val: int = 1 val2: str = "toto" app = App(F1={"val": 42, "val2": "tata"}) self.assertEqual(app.F1.val, 42) self.assertEqual(app.F1.val2, "tata") def test_dict_override_type_error(self): class App(dm.Appliance): class F1(dm.Feature): val: int = 1 # wrong type for val → must raise InvalidFieldValue with self.assertRaises(dm.InvalidFieldValue): App(F1={"val": "not-an-int"}) def test_dict_override_nonexisting_field(self): class App(dm.Appliance): class F1(dm.Feature): val: int = 1 # field does not exist → must raise with self.assertRaises(dm.InvalidFieldValue): App(F1={"doesnotexist": 123}) def test_inheritance_with_extra_fields(self): class App(dm.Appliance): class F1(dm.Feature): val: int = 1 class MyF1(App.F1): val = 2 extra: str = "hello" app = App(F1=MyF1) self.assertEqual(app.F1.val, 2) self.assertEqual(app.F1.extra, "hello") def test_override_does_not_leak_between_instances(self): class App(dm.Appliance): class F1(dm.Feature): val: int = 1 app1 = App(F1={"val": 99}) app2 = App() self.assertEqual(app1.F1.val, 99) self.assertEqual(app2.F1.val, 1) def test_deepfreeze_nested_mixed_tuple_list(self): class App(dm.Appliance): data: tuple[list[int], tuple[int, list[int]]] = ([1, 2], (3, [4, 5])) app = App() # Top-level: must be tuple self.assertIsInstance(app.data, tuple) # First element of tuple: should have been frozen to tuple, not list self.assertIsInstance(app.data[0], tuple) # Nested second element: itself a tuple self.assertIsInstance(app.data[1], tuple) # Deepest element: inner list should also be frozen to tuple self.assertIsInstance(app.data[1][1], tuple) # Check immutability with self.assertRaises(TypeError): app.data[0] += (99,) # tuples are immutable with self.assertRaises(TypeError): app.data[1][1] += (42,) # inner tuple also immutable def test_inacurate_type(self): with self.assertRaises(dm.InvalidFieldAnnotation): class Appliance1(dm.Appliance): SomeVar: list = [] with self.assertRaises(dm.InvalidFieldAnnotation): class Appliance2(dm.Appliance): SomeVar: list[Any] = [] with self.assertRaises(dm.InvalidFieldAnnotation): class Appliance3(dm.Appliance): SomeVar: list[object] = [] with self.assertRaises(dm.InvalidFieldAnnotation): class Appliance4(dm.Appliance): SomeVar: dict = {} with self.assertRaises(dm.InvalidFieldAnnotation): class Appliance5(dm.Appliance): SomeVar: dict[str, Any] = {} with self.assertRaises(dm.InvalidFieldAnnotation): class Appliance6(dm.Appliance): SomeVar: dict[Any, Any] = {} with self.assertRaises(dm.InvalidFieldAnnotation): class Appliance7(dm.Appliance): SomeVar: dict[Any, str] = {} with self.assertRaises(dm.InvalidFieldAnnotation): class Appliance8(dm.Appliance): SomeVar: dict[str, object] = {} def test_cant_override_inherited_annotation(self): class App(dm.Appliance): class F1(dm.Feature): val: int = 1 with self.assertRaises(dm.ReadOnlyFieldAnnotation): class Extra(App.F1): val: str = "test" def test_fields_are_frozen_after_override(self): class App(dm.Appliance): class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" # dict override app1 = App(F={"nums": [9], "tag": "y"}) self.assertEqual(app1.F.nums, (9,)) self.assertEqual(app1.F.tag, "y") with self.assertRaises(AttributeError): app1.F.nums.append(3) # tuple # subclass override class F2(App.F): nums = [4, 5] app2 = App(F=F2) self.assertEqual(app2.F.nums, (4, 5)) with self.assertRaises(dm.ReadOnlyField): app2.F.nums += (6,) # still immutable def test_dict_partial_override_keeps_other_defaults(self): class App(dm.Appliance): class F(dm.Feature): a: int = 1 b: str = "k" app = App(F={"b": "z"}) self.assertEqual(app.F.a, 1) # default remains self.assertEqual(app.F.b, "z") # overridden def test_override_linear_chain(self): # Base appliance defines Feat1 class A(dm.Appliance): class Feat1(dm.Feature): x: int = 1 # ✅ Appliance B overrides Feat1 by subclassing A.Feat1 class B(A): class Feat1(A.Feat1): y: int = 2 self.assertTrue(issubclass(B.Feat1, A.Feat1)) # ✅ Appliance C overrides Feat1 again by subclassing B.Feat1 (not A.Feat1) class C(B): class Feat1(B.Feat1): z: int = 3 self.assertTrue(issubclass(C.Feat1, B.Feat1)) self.assertTrue(issubclass(C.Feat1, A.Feat1)) # ❌ Bad: D tries to override with a *fresh* Feature, not subclass of B.Feat1 with self.assertRaises(dm.InvalidFeatureInheritance): class D(B): class Feat1(dm.Feature): fail: str = "oops" # ❌ Bad: E tries to override with ancestor (A.Feat1) instead of B.Feat1 with self.assertRaises(dm.InvalidFeatureInheritance): class E(B): class Feat1(A.Feat1): fail: str = "oops" # ✅ New feature name in child is always fine class F(B): class Feat2(dm.Feature): other: str = "ok" self.assertTrue(hasattr(F, "Feat2")) def test_override_chain_runtime_replacement(self): # Build a linear chain: A -> B -> C for feature 'Feat1' class A(dm.Appliance): class Feat1(dm.Feature): x: int = 1 class B(A): class Feat1(A.Feat1): y: int = 2 class C(B): class Feat1(B.Feat1): z: int = 3 # ✅ OK: at instantiation of C, replacing Feat1 with a subclass of the LATEST (C.Feat1) class CFeat1Plus(C.Feat1): w: int = 4 c_ok = C(Feat1=CFeat1Plus) self.assertIsInstance(c_ok.Feat1, CFeat1Plus) self.assertEqual((c_ok.Feat1.x, c_ok.Feat1.y, c_ok.Feat1.z, c_ok.Feat1.w), (1, 2, 3, 4)) # ❌ Not OK: replacing with a subclass of the ancestor (A.Feat1) — must target latest (C.Feat1) class AFeat1Alt(A.Feat1): pass with self.assertRaises(dm.InvalidFieldValue): C(Feat1=AFeat1Alt) # ❌ Not OK: replacing with a subclass of the mid ancestor (B.Feat1) — still must target latest (C.Feat1) class BFeat1Alt(B.Feat1): pass with self.assertRaises(dm.InvalidFieldValue): C(Feat1=BFeat1Alt) def test_inheritance_tree_and_no_leakage(self): class A(dm.Appliance): class F1(dm.Feature): a: int = 1 class F2(dm.Feature): b: int = 2 # ✅ Child inherits both features automatically class B(A): c: str = "extra" b1 = B() self.assertIsInstance(b1.F1, A.F1) self.assertIsInstance(b1.F2, A.F2) self.assertEqual((b1.F1.a, b1.F2.b, b1.c), (1, 2, "extra")) # ✅ Override only F2, F1 should still come from A class C(B): class F2(B.F2): bb: int = 22 c1 = C() self.assertIsInstance(c1.F1, A.F1) # unchanged self.assertIsInstance(c1.F2, C.F2) # overridden self.assertEqual((c1.F1.a, c1.F2.b, c1.F2.bb), (1, 2, 22)) # ✅ No leakage: instances of B are not affected by C's override b2 = B() self.assertIsInstance(b2.F2, A.F2) self.assertFalse(hasattr(b2.F2, "bb")) # ✅ Adding a new feature in D is independent of previous appliances class D(C): class F3(dm.Feature): d: int = 3 d1 = D() self.assertIsInstance(d1.F1, A.F1) self.assertIsInstance(d1.F2, C.F2) self.assertIsInstance(d1.F3, D.F3) # ✅ No leakage: instances of A and B should not see F3 a1 = A() self.assertFalse(hasattr(a1, "F3")) b3 = B() self.assertFalse(hasattr(b3, "F3")) def test_appliance_inheritance_tree_isolation(self): class A(dm.Appliance): class F1(dm.Feature): a: int = 1 # Branch 1 overrides F1 class B(A): class F1(A.F1): b: int = 2 # Branch 2 also overrides F1 differently class C(A): class F1(A.F1): c: int = 3 # ✅ Instances of B use B.F1 b = B() self.assertIsInstance(b.F1, B.F1) print(b.F1) print(dir(b.F1)) self.assertEqual((b.F1.a, b.F1.b), (1, 2)) self.assertFalse(hasattr(b.F1, "c")) # ✅ Instances of C use C.F1 c = C() self.assertIsInstance(c.F1, C.F1) self.assertEqual((c.F1.a, c.F1.c), (1, 3)) self.assertFalse(hasattr(c.F1, "b")) # ✅ Base appliance A still uses its original feature a = A() self.assertIsInstance(a.F1, A.F1) self.assertEqual(a.F1.a, 1) self.assertFalse(hasattr(a.F1, "b")) self.assertFalse(hasattr(a.F1, "c")) # ✅ No leakage: B's override doesn't affect C and vice versa b2 = B() c2 = C() self.assertTrue(hasattr(b2.F1, "b")) self.assertFalse(hasattr(b2.F1, "c")) self.assertTrue(hasattr(c2.F1, "c")) self.assertFalse(hasattr(c2.F1, "b")) def test_appliance_inheritance_tree_runtime_attach_isolation(self): class A(dm.Appliance): class F1(dm.Feature): a: int = 1 class B(A): class F1(A.F1): b: int = 2 class C(A): class F1(A.F1): c: int = 3 # Define new runtime-attachable features class FextraB(B.F1): xb: int = 99 class FextraC(C.F1): xc: int = -99 # ✅ Attach to B at instantiation b = B(F1=FextraB) self.assertIsInstance(b.F1, FextraB) self.assertEqual((b.F1.a, b.F1.b, b.F1.xb), (1, 2, 99)) self.assertFalse(hasattr(b.F1, "c")) self.assertFalse(hasattr(b.F1, "xc")) # ✅ Attach to C at instantiation c = C(F1=FextraC) self.assertIsInstance(c.F1, FextraC) self.assertEqual((c.F1.a, c.F1.c, c.F1.xc), (1, 3, -99)) self.assertFalse(hasattr(c.F1, "b")) self.assertFalse(hasattr(c.F1, "xb")) # ✅ Base appliance still untouched a = A() self.assertIsInstance(a.F1, A.F1) self.assertEqual(a.F1.a, 1) self.assertFalse(hasattr(a.F1, "b")) self.assertFalse(hasattr(a.F1, "c")) self.assertFalse(hasattr(a.F1, "xb")) self.assertFalse(hasattr(a.F1, "xc")) # ✅ Repeated instantiations stay isolated b2 = B() c2 = C() self.assertIsInstance(b2.F1, B.F1) self.assertIsInstance(c2.F1, C.F1) self.assertFalse(hasattr(b2.F1, "xb")) self.assertFalse(hasattr(c2.F1, "xc")) def test_feature_dict_override_with_nested_containers(self): class App(dm.Appliance): class F1(dm.Feature): values: list[int] = [1, 2] app = App(F1={"values": [5, 6]}) self.assertEqual(app.F1.values, (5, 6)) # deepfreeze → tuple # Invalid type in list should fail with self.assertRaises(dm.InvalidFieldValue): App(F1={"values": [1, "oops"]}) def test_dict_override_with_unknown_key(self): class App(dm.Appliance): class F1(dm.Feature): a: int = 1 # Dict override with unknown field 'zzz' with self.assertRaises(dm.InvalidFieldValue): App(F1={"zzz": 42}) def test_schema_isolation_across_multiple_overrides(self): class App(dm.Appliance): class F1(dm.Feature): a: int = 1 class F1a(App.F1): a = 10 class F1b(App.F1): a = 20 app1 = App(F1=F1a) self.assertIsInstance(app1.F1, F1a) self.assertEqual(app1.F1.a, 10) app2 = App(F1=F1b) self.assertIsInstance(app2.F1, F1b) self.assertEqual(app2.F1.a, 20) # Original appliance schema must not be polluted app3 = App() self.assertIsInstance(app3.F1, App.F1) self.assertEqual(app3.F1.a, 1) def test_inheritance_with_annotated_fields(self): class App(dm.Appliance): class F1(dm.Feature): a: Annotated[int, dm.LAMFieldInfo(doc="field a")] = 1 # ✅ Subclass override must inherit from parent F1 class F1Ex(App.F1): b: str = "ok" app = App(F1=F1Ex) self.assertIsInstance(app.F1, F1Ex) self.assertEqual((app.F1.a, app.F1.b), (1, "ok")) # ❌ Wrong: fresh Feature under same name with self.assertRaises(dm.InvalidFeatureInheritance): class Bad(App): class F1(dm.Feature): fail: str = "oops" def test_initializer(self): class App(dm.Appliance): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" @classmethod def __initializer(cls): cls.F.tag = "test" cls.F.nums.append(3) self.assertEqual(App.F.tag, "test") self.assertEqual(App.F.nums, (1, 2, 3)) def test_initializer_nested(self): class App(dm.Appliance): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" @classmethod def __initializer(cls): cls.tag = "test" cls.nums.append(3) self.assertEqual(App.F.tag, "test") self.assertEqual(App.F.nums, (1, 2, 3)) def test_initializer_nested_dual(self): class App(dm.Appliance): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" @classmethod def __initializer(cls): cls.tag = "test1" cls.nums.append(3) @classmethod def __initializer(cls): cls.F.tag = "test2" cls.F.nums.append(4) self.assertEqual(App.F.tag, "test2") self.assertEqual(App.F.nums, (1, 2, 3, 4)) def test_container_frozen(self): class App(dm.Appliance): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" with self.assertRaises(AttributeError): App.F.nums.append(3) def test_container_class_mutable_validation(self): class App(dm.Appliance, options=(dm.ClassMutable)): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" App.F.nums.append("test") with self.assertRaises(dm.InvalidFieldValue): App.freeze_class() with self.assertRaises(dm.InvalidFieldValue): a = App() def test_container_object_mutable_validation(self): class App(dm.Appliance, options=(dm.ObjectMutable)): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" a = App() a.F.nums.append("test") with self.assertRaises(dm.InvalidFieldValue): a.freeze() def test_container_object_and_class_mutable_validation(self): class App(dm.Appliance, options=(dm.ClassMutable, dm.ObjectMutable)): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" App.F.nums.append("test") with self.assertRaises(dm.InvalidFieldValue): a = App() with self.assertRaises(dm.InvalidFieldValue): App.freeze_class() def test_nested_element_container_object_and_class_mutable(self): class E(dm.Element): val: str = "testelem" i: list[int] = [1] class App(dm.Appliance, options=(dm.ClassMutable, dm.ObjectMutable)): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" e: E = E(val="modified") App.F.e.i.append(21) self.assertEquals(App.F.e.i, [1, 21]) App.freeze_class() with self.assertRaises(AttributeError): App.F.e.i.append(22) a = App() self.assertEquals(a.F.e.i, [1, 21]) a.F.e.i.append(28) self.assertEquals(a.F.e.i, [1, 21, 28]) a.freeze() self.assertEquals(a.F.e.i, (1, 21, 28)) with self.assertRaises(AttributeError): a.F.e.i.append(23) self.assertEquals(a.F.e.i, (1, 21, 28)) def test_nested_element_container_object_and_class_mutable_validation(self): class E(dm.Element): val: str = "testelem" i: list[int] = [1] class App(dm.Appliance, options=(dm.ClassMutable, dm.ObjectMutable)): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" e: E = E(val="modified") App.F.e.i.append("test") with self.assertRaises(dm.InvalidFieldValue): a = App() def test_nested_element_container_object_and_class_mutable_validation2(self): class E(dm.Element): val: str = "testelem" i: list[int] = [1] class App(dm.Appliance, options=(dm.ClassMutable, dm.ObjectMutable)): integ: int = 18 class F(dm.Feature): nums: list[int] = [1, 2] tag: str = "x" e: E = E(val="modified") a = App() a.F.e.i.append("test") with self.assertRaises(dm.InvalidFieldValue): a.freeze() # ---------- main ---------- if __name__ == "__main__": unittest.main()