Compare commits

...

5 Commits

Author SHA1 Message Date
cclecle
85a2ca2753 work 2025-10-12 22:45:56 +02:00
chacha
df50632458 work 2025-09-29 21:14:24 +02:00
cclecle
25d5339946 work 2025-09-28 21:18:35 +02:00
cclecle
6efd914de1 non finished work 2025-09-28 17:33:34 +02:00
cclecle
2e81b3f0e6 work 2025-09-27 23:58:47 +02:00
10 changed files with 455 additions and 279 deletions

View File

@@ -2,14 +2,14 @@ from typing import Any, Union, Optional, List, Dict, Tuple, Set, FrozenSet, Anno
from types import SimpleNamespace
import math
ALLOWED_MODEL_FIELDS_TYPES: tuple[type[Any], ...] = (
ALLOWED_MODEL_FIELDS_TYPES: set[type[Any], ...] = {
str,
int,
float,
complex,
bool,
bytes,
)
}
ALLOWED_ANNOTATIONS: dict[str, Any] = {
"Union": Union,

View File

@@ -80,30 +80,30 @@ class ReadOnlyFieldAnnotation(AttributeError, DABModelException):
"""
class InvalidFieldValue(AttributeError, DABModelException):
class SchemaViolation(AttributeError, DABModelException):
"""SchemaViolation Exception class
The Element Schema is not respected
"""
class InvalidFieldValue(SchemaViolation):
"""InvalidFieldValue Exception class
The Field value is invalid
"""
class NonExistingField(SchemaViolation):
"""NonExistingField Exception class
The given Field is non existing
"""
class InvalidFieldName(AttributeError, DABModelException):
"""InvalidFieldName Exception class
The Field name is invalid
"""
class NonExistingField(AttributeError, DABModelException):
"""NonExistingField Exception class
The given Field is non existing
"""
class SchemaViolation(AttributeError, DABModelException):
"""SchemaViolation Exception class
The Element Schema is not respected
"""
class ImportForbidden(DABModelException):
"""ImportForbidden Exception class
Imports are forbidden

View File

@@ -1,4 +1,4 @@
from typing import Generic, TypeVar, Dict, Protocol, runtime_checkable
from typing import Generic, TypeVar, Dict, Protocol, runtime_checkable, Self
TV_Freezable = TypeVar("TV_Freezable")
@@ -7,9 +7,7 @@ TV_Freezable = TypeVar("TV_Freezable")
@runtime_checkable
class FreezableElement(Protocol, Generic[TV_Freezable]):
def clone_as_mutable_variant(
self, *, deep: bool = True, _memo: Dict[int, TV_Freezable] | None = None
) -> TV_Freezable:
def clone_as_mutable_variant(self, *, deep: bool = True, _memo: Dict[int, Self] | None = None) -> Self:
pass
def freeze(self, force: bool = False) -> None:
@@ -23,7 +21,7 @@ class FreezableElement(Protocol, Generic[TV_Freezable]):
pass
@classmethod
def validate_schema_class(self) -> None:
def validate_schema_class(cls) -> None:
pass
@classmethod

View File

@@ -1,4 +1,4 @@
from typing import Generic, TypeVar, Optional, Any, Self
from typing import Generic, TypeVar, Optional, Any, Self, Annotated, get_origin, get_args
from typeguard import check_type, CollectionCheckStrategy, TypeCheckError
from copy import deepcopy
from .lam_field_info import LAMFieldInfo
@@ -13,19 +13,29 @@ TV_LABField = TypeVar("TV_LABField")
class LAMField(Generic[TV_LABField]):
"""This class describe a Field in Schema"""
def __init__(self, name: str, val: Optional[TV_LABField], a: Any, i: LAMFieldInfo):
def __init__(self, name: str, val: Optional[TV_LABField], ann: Any, i: LAMFieldInfo):
self._default_value: Optional[TV_LABField]
self._value: Optional[TV_LABField]
self.__annotations: Any
self.__name: str = name
self.__source: Optional[type] = None
self.__info: LAMFieldInfo = deepcopy(i)
self.__annotations: Any = LAMdeepfreeze(a)
self._set_annotations(ann)
self.__frozen: bool = False
self._frozen_value: Any = None
self.__frozen_value_set: True = False
self.validate(val)
self._init_value(val)
def _set_annotations(self, ann: Any) -> None:
_origin = get_origin(ann) or ann
_args = get_args(ann)
if _origin is Annotated:
self.__annotations: Any = LAMdeepfreeze(_args[0])
else:
self.__annotations: Any = LAMdeepfreeze(ann)
def _init_value(self, val: Optional[TV_LABField | FreezableElement]):
self._default_value: Optional[TV_LABField] = deepcopy(val)
self._value: Optional[TV_LABField] = val
@@ -41,7 +51,7 @@ class LAMField(Generic[TV_LABField]):
self.__frozen = True
def clone_unfrozen(self) -> Self:
field = LAMField(self.__name, self._default_value, self.__annotations, self.__info)
field = LAMFieldFactory.create_field(self.__name, self._default_value, self.__annotations, self.__info)
field.update_value(self._value)
return field
@@ -159,6 +169,8 @@ class LAMFieldFactory:
@staticmethod
def create_field(name: str, val: Optional[TV_LABField], anno: Any, info: LAMFieldInfo) -> LAMField:
if isinstance(val, FreezableElement):
print(f"Spawn LAMField_Element {name} !!!")
return LAMField_Element(name, val, anno, info)
else:
print(f"Spawn LAMField {name} !!!")
return LAMField(name, val, anno, info)

View File

@@ -1,4 +1,4 @@
from typing import Optional, TypeVar, get_origin, get_args, Any, Type, Union, Dict
from typing import Optional, TypeVar, get_origin, get_args, Any, Type, Union, Dict, Annotated
from types import FunctionType, UnionType, new_class
from copy import deepcopy, copy
@@ -9,8 +9,8 @@ import inspect, ast, textwrap
from typeguard import check_type, TypeCheckError, CollectionCheckStrategy
from frozendict import frozendict
from ..tools import _resolve_annotation, _peel_annotated
from ..lam_field.lam_field import LAMFieldFactory, LAMField
from ..tools import _resolve_annotation
from ..lam_field.lam_field import LAMFieldFactory, LAMField, LAMField_Element
from ..lam_field.lam_field_info import LAMFieldInfo
from ..defines import ALLOWED_HELPERS_MATH, ALLOWED_HELPERS_DEFAULT, ALLOWED_MODEL_FIELDS_TYPES
@@ -176,43 +176,48 @@ class IFeature(IBaseElement): ...
class IAppliance(IBaseElement): ...
def _check_annotation_definition( # pylint: disable=too-complex,too-many-return-statements
_type,
):
# print(f"_type={_type}")
_type = _peel_annotated(_type)
def _check_annotation_definition(_type, first_layer: bool = True): # pylint: disable=too-complex,too-many-return-statements
print(f"_type={_type}, {first_layer}")
_origin = get_origin(_type) or _type
_args = get_args(_type)
# handle Optional[] and Union[None,...]
if (_origin is Union or _origin is UnionType) and type(None) in _args:
return all(_check_annotation_definition(_) for _ in get_args(_type) if _ is not type(None))
# handle Annotated[,]
if _origin is Annotated:
if not first_layer:
raise UnsupportedFieldType("Annotated[] is only supported as parent annotation")
return _check_annotation_definition(_args[0], False)
# handle other Union[...]
# handle Optional[] and Union[None,...]
if _origin is Union or _origin is UnionType:
return all(_check_annotation_definition(_) for _ in _args)
if (len(_args) != 2) or (type(None) not in list(_args)) or (not first_layer):
raise UnsupportedFieldType(
"Union[] is only supported to implement Optional (takes 2 parameters) and is only supported as parent annotation"
)
return any(_check_annotation_definition(_, False) for _ in get_args(_type) if _ is not type(None))
# handle Dict[...]
if _origin is dict:
if len(_args) != 2:
raise IncompletelyAnnotatedField(f"Dict Annotation requires 2 inner definitions: {_type}")
if not _peel_annotated(_args[0]) in ALLOWED_MODEL_FIELDS_TYPES:
if not _args[0] in ALLOWED_MODEL_FIELDS_TYPES:
raise IncompletelyAnnotatedField(f"Dict Key must be simple builtin: {_type}")
return _check_annotation_definition(_args[1])
# return _check_annotation_definition(_args[1], False)
return any(_check_annotation_definition(_, False) for _ in _args)
# handle Tuple[]
if _origin is tuple:
if len(_args) == 0:
raise IncompletelyAnnotatedField(f"Annotation requires inner definition: {_type}")
if len(_args) == 2 and _args[1] is Ellipsis:
return _check_annotation_definition(_args[0])
return all(_check_annotation_definition(_) for _ in _args)
return _check_annotation_definition(_args[0], False)
return any(_check_annotation_definition(_, False) for _ in _args)
# handle Set[],Tuple[],FrozenSet[],List[]
if _origin in [set, frozenset, tuple, list]:
if len(_args) == 0:
raise IncompletelyAnnotatedField(f"Annotation requires inner definition: {_type}")
return all(_check_annotation_definition(_) for _ in _args)
return any(_check_annotation_definition(_, False) for _ in _args)
if isinstance(_origin, type):
if issubclass(_origin, IElement):
@@ -220,9 +225,9 @@ def _check_annotation_definition( # pylint: disable=too-complex,too-many-return
elif issubclass(_origin, IAppliance):
raise UnsupportedFieldType(f"Nested Appliance are not supported: {_type}")
if _type in ALLOWED_MODEL_FIELDS_TYPES:
if _origin in ALLOWED_MODEL_FIELDS_TYPES:
return
raise UnsupportedFieldType(_type)
raise UnsupportedFieldType(_origin)
def _check_initializer_safety(func) -> None:
@@ -736,8 +741,7 @@ class _MetaElement(type):
if not cls.__lam_class_mutable__:
raise ReadOnlyField(f"Class is immutable.")
field = cls.__lam_schema__[name]
field.update_value(value)
cls.__lam_schema__[name].update_value(value)
return
def __getattr__(cls, name) -> Any:
@@ -747,6 +751,8 @@ class _MetaElement(type):
def __call__(cls: Type, *args: Any, **kw: Any): # intentionally untyped
"""BaseElement new instance"""
cls.validate_schema_class()
obj = super().__call__(*args)
# create a dict to pass contextual arg onto the stack (multithread safe class init)
@@ -786,13 +792,35 @@ class _MetaElement(type):
"""
# --- field overrides (unchanged) ---
print("!!!???????")
for k, v in list(kwargs.items()):
if k in obj.__lam_schema__: # regular field
obj.__lam_schema__[k].update_value(v)
if not obj.__lam_object_mutable__:
object.__setattr__(obj, k, obj.__lam_schema__[k].frozen_value)
print(f"??????? {k} {v}")
print(obj.__lam_schema__[k])
if isinstance(obj.__lam_schema__[k], LAMField_Element):
valid_val = True
try:
obj.__lam_schema__[k].validate(v)
except InvalidFieldValue:
valid_val = False
if valid_val:
obj.__lam_schema__[k].update_value(v)
if not obj.__lam_object_mutable__:
object.__setattr__(obj, k, obj.__lam_schema__[k].frozen_value)
else:
object.__setattr__(obj, k, obj.__lam_schema__[k].value)
elif isinstance(v, dict):
raise RuntimeError("initializing Elem with dict is not supported yet")
else:
raise InvalidFieldValue(f"Element override for '{k}' must be a Feature subclass or dict, got {type(v)}")
else:
object.__setattr__(obj, k, obj.__lam_schema__[k].value)
obj.__lam_schema__[k].update_value(v)
if not obj.__lam_object_mutable__:
object.__setattr__(obj, k, obj.__lam_schema__[k].frozen_value)
else:
object.__setattr__(obj, k, obj.__lam_schema__[k].value)
kwargs.pop(k)
if kwargs:

View File

@@ -1,16 +1,36 @@
"""library's internal tools"""
from typing import Any, get_origin, get_args
from collections import ChainMap
from typing import (
Any,
Annotated,
get_origin,
get_args,
Union,
Self,
Optional,
List,
Dict,
Tuple,
Set,
FrozenSet,
Mapping,
Callable,
)
import typing
from dataclasses import dataclass
from types import UnionType, NoneType
import types
from uuid import UUID
from datetime import datetime
import json
import inspect
from frozendict import deepfreeze
from .defines import (
ALLOWED_ANNOTATIONS,
)
from frozendict import deepfreeze, frozendict
from .defines import ALLOWED_ANNOTATIONS, ALLOWED_MODEL_FIELDS_TYPES
from .exception import IncompletelyAnnotatedField, UnsupportedFieldType
class LAMJSONEncoder(json.JSONEncoder):
@@ -48,20 +68,6 @@ def is_data_attribute(name: str, value: any) -> bool:
return True
def _peel_annotated(t: Any) -> Any:
# If you ever allow Annotated[T, ...], peel to T
while True:
origin = get_origin(t)
if origin is None:
return t
name = getattr(origin, "__name__", "") or getattr(origin, "__qualname__", "") or str(origin)
if "Annotated" in name:
args = get_args(t)
t = args[0] if args else t
else:
return t
def _resolve_annotation(ann):
if isinstance(ann, str):
# Safe eval against a **whitelist** only

View File

@@ -0,0 +1,53 @@
# 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 <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
import unittest
from typing import Annotated, Union, Optional
import sys
import subprocess
from os import chdir, environ
from pathlib import Path
print(__name__)
print(__package__)
from src import dabmodel as dm
testdir_path = Path(__file__).parent.resolve()
chdir(testdir_path.parent.resolve())
class AnnotationsWalkerTest(unittest.TestCase):
def setUp(self):
print("\n->", unittest.TestCase.id(self))
def test_validate(self):
ann = dict[int, list[int]] | dict[int, list[int | str]]
val = {1: [2], 2: ["a", [1]]}
res = dm.tools.AnnotationWalker(ann, (dm.tools.HorizontalValidationTrigger(val),))
res.run()
def test_simple(self):
print(isinstance(None, type(None)))
print("\n== From OBJs ==")
res = dm.tools.AnnotationWalker(Annotated[Optional[dict[int, list[str]]], "comment"], (dm.tools.LAMSchemaValidation(),))
print(f"res={res.run()}")
print("\n== From STRING ==")
res = dm.tools.AnnotationWalker('Annotated[Optional[dict[int, list[str]]], "comment"]', (dm.tools.LAMSchemaValidation(),))
print(f"res={res.run()}")
res = dm.tools.AnnotationWalker(Annotated[Optional[dict[int, list[None]]], "comment"], (dm.tools.LAMSchemaValidation(),))
print(f"res={res.run()}")
# ---------- main ----------
if __name__ == "__main__":
unittest.main()

View File

@@ -88,9 +88,7 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app1, "VarComplex2", complex(8, 6), complex(3, 2))
self.immutable_vars__test_field(app1, "VarBool", True, False)
self.immutable_vars__test_field(app1, "VarBool2", False, True)
self.immutable_vars__test_field(
app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 ")
)
self.immutable_vars__test_field(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 "))
self.immutable_vars__test_field(
app1,
"VarBytes2",
@@ -158,9 +156,7 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app1, "VarComplex2", complex(8, 6), complex(3, 2))
self.immutable_vars__test_field(app1, "VarBool", True, False)
self.immutable_vars__test_field(app1, "VarBool2", False, True)
self.immutable_vars__test_field(
app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 ")
)
self.immutable_vars__test_field(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 "))
self.immutable_vars__test_field(
app1,
"VarBytes2",
@@ -255,7 +251,6 @@ class ApplianceTest(unittest.TestCase):
testVar4: "Set[str]" = {"a", "c"}
testVar5: set[str] = {"a", "b"}
testVar6: "set[str]" = {"a", "b"}
testVar7: set[int | str] = {1, 2, "abcd", "efg"}
app1 = Appliance1()
self.immutable_vars__test_field(app1, "testVar", {1, 2}, {1, 5})
@@ -267,7 +262,6 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app1, "testVar4", {"a", "c"}, {"h", "e"})
self.immutable_vars__test_field(app1, "testVar5", {"a", "b"}, {"h", "c"})
self.immutable_vars__test_field(app1, "testVar6", {"a", "b"}, {"h", "c"})
self.immutable_vars__test_field(app1, "testVar7", {1, 2, "abcd", "efg"}, {"h", "c"})
# must work
sorted(app1.testVar)
@@ -334,7 +328,6 @@ class ApplianceTest(unittest.TestCase):
testVar4: "frozenset[str]" = frozenset({"a", "c"})
testVar5: FrozenSet[int] = frozenset({1, 2})
testVar6: "FrozenSet[int]" = frozenset({1, 2})
testVar7: FrozenSet[int | str] = frozenset({1, 2, "abcd", "efg"})
app1 = Appliance1()
self.immutable_vars__test_field(app1, "testVar", {1, 2}, {1, 5})
@@ -346,7 +339,6 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app1, "testVar4", {"a", "c"}, {"h", "e"})
self.immutable_vars__test_field(app1, "testVar5", {1, 2}, {1, 5})
self.immutable_vars__test_field(app1, "testVar6", {1, 2}, {1, 5})
self.immutable_vars__test_field(app1, "testVar7", {1, 2, "abcd", "efg"}, {1, 5})
# must work
sorted(app1.testVar)
@@ -410,7 +402,6 @@ class ApplianceTest(unittest.TestCase):
testVar4: "List[str]" = ["a", "c"]
testVar5: list[str] = ["a", "b"]
testVar6: "list[str]" = ["a", "b"]
testVar7: List[Union[int, str]] = [1, 2, 3, "one", "two", "three"]
app1 = Appliance1()
# Note: lists are converted to tuples
@@ -420,9 +411,6 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app1, "testVar4", ("a", "c"), ["h", "e"])
self.immutable_vars__test_field(app1, "testVar5", ("a", "b"), ["h", "c"])
self.immutable_vars__test_field(app1, "testVar6", ("a", "b"), ["h", "c"])
self.immutable_vars__test_field(
app1, "testVar7", (1, 2, 3, "one", "two", "three"), ["h", "c"]
)
# must work
sorted(app1.testVar)
@@ -518,7 +506,6 @@ class ApplianceTest(unittest.TestCase):
testVar5: tuple[str, ...] = ("a", "b")
testVar6: "tuple[str,...]" = ("a", "b")
testVar7: Tuple[int, str] = (1, "b")
# testVar7: Tuple[Union[int, str]] = (1, 2, 3, "one", "two", "three")
app1 = Appliance1()
@@ -612,12 +599,8 @@ class ApplianceTest(unittest.TestCase):
self.check_immutable_fields_schema(app1, "VarInt2", 21, 21, int)
self.check_immutable_fields_schema(app1, "VarFloat", 12.1, 12.1, float)
self.check_immutable_fields_schema(app1, "VarFloat2", 21.2, 21.2, float)
self.check_immutable_fields_schema(
app1, "VarComplex", complex(3, 5), complex(3, 5), complex
)
self.check_immutable_fields_schema(
app1, "VarComplex2", complex(8, 6), complex(8, 6), complex
)
self.check_immutable_fields_schema(app1, "VarComplex", complex(3, 5), complex(3, 5), complex)
self.check_immutable_fields_schema(app1, "VarComplex2", complex(8, 6), complex(8, 6), complex)
self.check_immutable_fields_schema(app1, "VarBool", True, True, bool)
self.check_immutable_fields_schema(app1, "VarBool2", False, False, bool)
self.check_immutable_fields_schema(
@@ -656,12 +639,8 @@ class ApplianceTest(unittest.TestCase):
self.assertIn("__lam_schema__", dir(app1))
self.assertIn("__lam_schema__", app1.__dict__)
self.check_immutable_fields_schema(
app1, "ListStr", ("val1", "val2"), ("val1", "val2"), list[str]
)
self.check_immutable_fields_schema(
app1, "ListStr2", ("val3", "val4"), ("val3", "val4"), list[str]
)
self.check_immutable_fields_schema(app1, "ListStr", ("val1", "val2"), ("val1", "val2"), list[str])
self.check_immutable_fields_schema(app1, "ListStr2", ("val3", "val4"), ("val3", "val4"), list[str])
self.check_immutable_fields_schema(
app1,
"Dict1",
@@ -678,18 +657,10 @@ class ApplianceTest(unittest.TestCase):
)
self.check_immutable_fields_schema(app1, "Tuple1", ("a", "c"), ("a", "c"), tuple[str, ...])
self.check_immutable_fields_schema(app1, "Tuple2", ("a", "b"), ("a", "b"), tuple[str, ...])
self.check_immutable_fields_schema(
app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), frozenset[int]
)
self.check_immutable_fields_schema(
app1, "FrozenSet2", frozenset({1, 2}), frozenset({1, 2}), frozenset[int]
)
self.check_immutable_fields_schema(
app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), set[int]
)
self.check_immutable_fields_schema(
app1, "Set2", frozenset({1, 2}), frozenset({1, 2}), set[int]
)
self.check_immutable_fields_schema(app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), frozenset[int])
self.check_immutable_fields_schema(app1, "FrozenSet2", frozenset({1, 2}), frozenset({1, 2}), frozenset[int])
self.check_immutable_fields_schema(app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), set[int])
self.check_immutable_fields_schema(app1, "Set2", frozenset({1, 2}), frozenset({1, 2}), set[int])
# same test with Typing types (list -> List ...)
# class can be created
@@ -710,12 +681,8 @@ class ApplianceTest(unittest.TestCase):
self.assertIn("__lam_schema__", dir(app1))
self.assertIn("__lam_schema__", app1.__dict__)
self.check_immutable_fields_schema(
app1, "ListStr", ("val1", "val2"), ("val1", "val2"), List[str]
)
self.check_immutable_fields_schema(
app1, "ListStr2", ("val3", "val4"), ("val3", "val4"), List[str]
)
self.check_immutable_fields_schema(app1, "ListStr", ("val1", "val2"), ("val1", "val2"), List[str])
self.check_immutable_fields_schema(app1, "ListStr2", ("val3", "val4"), ("val3", "val4"), List[str])
self.check_immutable_fields_schema(
app1,
"Dict1",
@@ -732,18 +699,10 @@ class ApplianceTest(unittest.TestCase):
)
self.check_immutable_fields_schema(app1, "Tuple1", ("a", "c"), ("a", "c"), Tuple[str, ...])
self.check_immutable_fields_schema(app1, "Tuple2", ("a", "b"), ("a", "b"), Tuple[str, ...])
self.check_immutable_fields_schema(
app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), FrozenSet[int]
)
self.check_immutable_fields_schema(
app1, "FrozenSet2", frozenset({1, 2}), frozenset({1, 2}), FrozenSet[int]
)
self.check_immutable_fields_schema(
app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), Set[int]
)
self.check_immutable_fields_schema(
app1, "Set2", frozenset({1, 2}), frozenset({1, 2}), Set[int]
)
self.check_immutable_fields_schema(app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), FrozenSet[int])
self.check_immutable_fields_schema(app1, "FrozenSet2", frozenset({1, 2}), frozenset({1, 2}), FrozenSet[int])
self.check_immutable_fields_schema(app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), Set[int])
self.check_immutable_fields_schema(app1, "Set2", frozenset({1, 2}), frozenset({1, 2}), Set[int])
def test_immutable_fields_annotated(self):
"""Testing first appliance level, and Field types (annotated)"""
@@ -785,9 +744,7 @@ class ApplianceTest(unittest.TestCase):
self.assertEqual(app1.__lam_schema__["VarBool"].doc, "foo9")
self.immutable_vars__test_field(app1, "VarBool2", False, True)
self.assertEqual(app1.__lam_schema__["VarBool2"].doc, "foo10")
self.immutable_vars__test_field(
app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 ")
)
self.immutable_vars__test_field(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 "))
self.assertEqual(app1.__lam_schema__["VarBytes"].doc, "foo11")
self.immutable_vars__test_field(
app1,
@@ -852,9 +809,7 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app1, "VarComplex2", complex(8, 6), complex(3, 2))
self.immutable_vars__test_field(app1, "VarBool", True, False)
self.immutable_vars__test_field(app1, "VarBool2", False, True)
self.immutable_vars__test_field(
app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 ")
)
self.immutable_vars__test_field(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 "))
self.immutable_vars__test_field(
app1,
"VarBytes2",
@@ -868,12 +823,8 @@ class ApplianceTest(unittest.TestCase):
self.check_immutable_fields_schema(app1, "VarInt2", 21, 21, int)
self.check_immutable_fields_schema(app1, "VarFloat", 12.1, 12.1, float)
self.check_immutable_fields_schema(app1, "VarFloat2", 21.2, 21.2, float)
self.check_immutable_fields_schema(
app1, "VarComplex", complex(3, 5), complex(3, 5), complex
)
self.check_immutable_fields_schema(
app1, "VarComplex2", complex(8, 6), complex(8, 6), complex
)
self.check_immutable_fields_schema(app1, "VarComplex", complex(3, 5), complex(3, 5), complex)
self.check_immutable_fields_schema(app1, "VarComplex2", complex(8, 6), complex(8, 6), complex)
self.check_immutable_fields_schema(app1, "VarBool", True, True, bool)
self.check_immutable_fields_schema(app1, "VarBool2", False, False, bool)
self.check_immutable_fields_schema(
@@ -903,9 +854,7 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app2, "VarComplex2", complex(3, 0), complex(3, 2))
self.immutable_vars__test_field(app2, "VarBool", False, False)
self.immutable_vars__test_field(app2, "VarBool2", True, True)
self.immutable_vars__test_field(
app2, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("11f0 F1f2 ")
)
self.immutable_vars__test_field(app2, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("11f0 F1f2 "))
self.immutable_vars__test_field(
app2,
"VarBytes2",
@@ -919,12 +868,8 @@ class ApplianceTest(unittest.TestCase):
self.check_immutable_fields_schema(app2, "VarInt2", 23, 21, int)
self.check_immutable_fields_schema(app2, "VarFloat", 2.6, 12.1, float)
self.check_immutable_fields_schema(app2, "VarFloat2", 1.5, 21.2, float)
self.check_immutable_fields_schema(
app2, "VarComplex", complex(7, 1), complex(3, 5), complex
)
self.check_immutable_fields_schema(
app2, "VarComplex2", complex(3, 0), complex(8, 6), complex
)
self.check_immutable_fields_schema(app2, "VarComplex", complex(7, 1), complex(3, 5), complex)
self.check_immutable_fields_schema(app2, "VarComplex2", complex(3, 0), complex(8, 6), complex)
self.check_immutable_fields_schema(app2, "VarBool", False, True, bool)
self.check_immutable_fields_schema(app2, "VarBool2", True, False, bool)
self.check_immutable_fields_schema(
@@ -961,9 +906,7 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app3, "VarComplex2", complex(3, 0), complex(3, 2))
self.immutable_vars__test_field(app3, "VarBool", False, False)
self.immutable_vars__test_field(app3, "VarBool2", True, True)
self.immutable_vars__test_field(
app3, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("11f0 F1f2 ")
)
self.immutable_vars__test_field(app3, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("11f0 F1f2 "))
self.immutable_vars__test_field(
app3,
"VarBytes2",
@@ -978,12 +921,8 @@ class ApplianceTest(unittest.TestCase):
self.check_immutable_fields_schema(app3, "VarInt2", 23, 21, int)
self.check_immutable_fields_schema(app3, "VarFloat", 2.6, 12.1, float)
self.check_immutable_fields_schema(app3, "VarFloat2", 1.5, 21.2, float)
self.check_immutable_fields_schema(
app3, "VarComplex", complex(7, 1), complex(3, 5), complex
)
self.check_immutable_fields_schema(
app3, "VarComplex2", complex(3, 0), complex(8, 6), complex
)
self.check_immutable_fields_schema(app3, "VarComplex", complex(7, 1), complex(3, 5), complex)
self.check_immutable_fields_schema(app3, "VarComplex2", complex(3, 0), complex(8, 6), complex)
self.check_immutable_fields_schema(app3, "VarBool", False, True, bool)
self.check_immutable_fields_schema(app3, "VarBool2", True, False, bool)
self.check_immutable_fields_schema(
@@ -1012,9 +951,7 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app1, "VarComplex2", complex(8, 6), complex(3, 2))
self.immutable_vars__test_field(app1, "VarBool", True, False)
self.immutable_vars__test_field(app1, "VarBool2", False, True)
self.immutable_vars__test_field(
app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 ")
)
self.immutable_vars__test_field(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 "))
self.immutable_vars__test_field(
app1,
"VarBytes2",
@@ -1028,12 +965,8 @@ class ApplianceTest(unittest.TestCase):
self.check_immutable_fields_schema(app1, "VarInt2", 21, 21, int)
self.check_immutable_fields_schema(app1, "VarFloat", 12.1, 12.1, float)
self.check_immutable_fields_schema(app1, "VarFloat2", 21.2, 21.2, float)
self.check_immutable_fields_schema(
app1, "VarComplex", complex(3, 5), complex(3, 5), complex
)
self.check_immutable_fields_schema(
app1, "VarComplex2", complex(8, 6), complex(8, 6), complex
)
self.check_immutable_fields_schema(app1, "VarComplex", complex(3, 5), complex(3, 5), complex)
self.check_immutable_fields_schema(app1, "VarComplex2", complex(8, 6), complex(8, 6), complex)
self.check_immutable_fields_schema(app1, "VarBool", True, True, bool)
self.check_immutable_fields_schema(app1, "VarBool2", False, False, bool)
self.check_immutable_fields_schema(
@@ -1061,9 +994,7 @@ class ApplianceTest(unittest.TestCase):
self.immutable_vars__test_field(app2, "VarComplex2", complex(3, 0), complex(3, 2))
self.immutable_vars__test_field(app2, "VarBool", False, False)
self.immutable_vars__test_field(app2, "VarBool2", True, True)
self.immutable_vars__test_field(
app2, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("11f0 F1f2 ")
)
self.immutable_vars__test_field(app2, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("11f0 F1f2 "))
self.immutable_vars__test_field(
app2,
"VarBytes2",
@@ -1077,12 +1008,8 @@ class ApplianceTest(unittest.TestCase):
self.check_immutable_fields_schema(app2, "VarInt2", 23, 21, int)
self.check_immutable_fields_schema(app2, "VarFloat", 2.6, 12.1, float)
self.check_immutable_fields_schema(app2, "VarFloat2", 1.5, 21.2, float)
self.check_immutable_fields_schema(
app2, "VarComplex", complex(7, 1), complex(3, 5), complex
)
self.check_immutable_fields_schema(
app2, "VarComplex2", complex(3, 0), complex(8, 6), complex
)
self.check_immutable_fields_schema(app2, "VarComplex", complex(7, 1), complex(3, 5), complex)
self.check_immutable_fields_schema(app2, "VarComplex2", complex(3, 0), complex(8, 6), complex)
self.check_immutable_fields_schema(app2, "VarBool", False, True, bool)
self.check_immutable_fields_schema(app2, "VarBool2", True, False, bool)
self.check_immutable_fields_schema(
@@ -1137,16 +1064,12 @@ class ApplianceTest(unittest.TestCase):
app1 = Appliance1()
self.immutable_vars__test_field(app1, "ListStr", ("val1", "val2"), ["val2", "val3"])
self.immutable_vars__test_field(
app1, "Dict1", {1: 1.1, 4: 7.6, 91: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6}
)
self.immutable_vars__test_field(app1, "Dict1", {1: 1.1, 4: 7.6, 91: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6})
self.immutable_vars__test_field(app1, "Tuple1", ("a", "c"), ("h", "r"))
self.immutable_vars__test_field(app1, "FrozenSet1", frozenset({1, 2}), frozenset({4, 0}))
self.immutable_vars__test_field(app1, "Set1", frozenset({1, 2}), set({4, 0}))
self.check_immutable_fields_schema(
app1, "ListStr", ("val1", "val2"), ("val1", "val2"), list[str]
)
self.check_immutable_fields_schema(app1, "ListStr", ("val1", "val2"), ("val1", "val2"), list[str])
self.check_immutable_fields_schema(
app1,
"Dict1",
@@ -1155,26 +1078,18 @@ class ApplianceTest(unittest.TestCase):
dict[int, float],
)
self.check_immutable_fields_schema(app1, "Tuple1", ("a", "c"), ("a", "c"), tuple[str, ...])
self.check_immutable_fields_schema(
app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), frozenset[int]
)
self.check_immutable_fields_schema(
app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), set[int]
)
self.check_immutable_fields_schema(app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), frozenset[int])
self.check_immutable_fields_schema(app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), set[int])
app2 = Appliance2()
self.immutable_vars__test_field(app2, "ListStr", ("mod val1", "mod val2"), ["val2", "val3"])
self.immutable_vars__test_field(
app2, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6}
)
self.immutable_vars__test_field(app2, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6})
self.immutable_vars__test_field(app2, "Tuple1", ("aa", "cc"), ("h", "r"))
self.immutable_vars__test_field(app2, "FrozenSet1", frozenset({14, 27}), frozenset({4, 0}))
self.immutable_vars__test_field(app2, "Set1", frozenset({1, 20}), set({4, 0}))
self.check_immutable_fields_schema(
app2, "ListStr", ("mod val1", "mod val2"), ("val1", "val2"), list[str]
)
self.check_immutable_fields_schema(app2, "ListStr", ("mod val1", "mod val2"), ("val1", "val2"), list[str])
self.check_immutable_fields_schema(
app2,
"Dict1",
@@ -1182,27 +1097,17 @@ class ApplianceTest(unittest.TestCase):
{1: 1.1, 4: 7.6, 91: 23.6},
dict[int, float],
)
self.check_immutable_fields_schema(
app2, "Tuple1", ("aa", "cc"), ("a", "c"), tuple[str, ...]
)
self.check_immutable_fields_schema(
app2, "FrozenSet1", frozenset({14, 27}), frozenset({1, 2}), frozenset[int]
)
self.check_immutable_fields_schema(
app2, "Set1", frozenset({1, 20}), frozenset({1, 2}), set[int]
)
self.check_immutable_fields_schema(app2, "Tuple1", ("aa", "cc"), ("a", "c"), tuple[str, ...])
self.check_immutable_fields_schema(app2, "FrozenSet1", frozenset({14, 27}), frozenset({1, 2}), frozenset[int])
self.check_immutable_fields_schema(app2, "Set1", frozenset({1, 20}), frozenset({1, 2}), set[int])
self.immutable_vars__test_field(app1, "ListStr", ("val1", "val2"), ["val2", "val3"])
self.immutable_vars__test_field(
app1, "Dict1", {1: 1.1, 4: 7.6, 91: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6}
)
self.immutable_vars__test_field(app1, "Dict1", {1: 1.1, 4: 7.6, 91: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6})
self.immutable_vars__test_field(app1, "Tuple1", ("a", "c"), ("h", "r"))
self.immutable_vars__test_field(app1, "FrozenSet1", frozenset({1, 2}), frozenset({4, 0}))
self.immutable_vars__test_field(app1, "Set1", frozenset({1, 2}), set({4, 0}))
self.check_immutable_fields_schema(
app1, "ListStr", ("val1", "val2"), ("val1", "val2"), list[str]
)
self.check_immutable_fields_schema(app1, "ListStr", ("val1", "val2"), ("val1", "val2"), list[str])
self.check_immutable_fields_schema(
app1,
"Dict1",
@@ -1211,12 +1116,8 @@ class ApplianceTest(unittest.TestCase):
dict[int, float],
)
self.check_immutable_fields_schema(app1, "Tuple1", ("a", "c"), ("a", "c"), tuple[str, ...])
self.check_immutable_fields_schema(
app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), frozenset[int]
)
self.check_immutable_fields_schema(
app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), set[int]
)
self.check_immutable_fields_schema(app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), frozenset[int])
self.check_immutable_fields_schema(app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), set[int])
# class can be created
class Appliance3(Appliance2):
@@ -1229,28 +1130,18 @@ class ApplianceTest(unittest.TestCase):
app3 = Appliance3()
self.immutable_vars__test_field(app3, "ListStr", ("mod val1", "mod val2"), ["val2", "val3"])
self.immutable_vars__test_field(
app3, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6}
)
self.immutable_vars__test_field(app3, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6})
self.immutable_vars__test_field(app3, "Tuple1", ("aa", "cc"), ("h", "r"))
self.immutable_vars__test_field(app3, "FrozenSet1", frozenset({14, 27}), frozenset({4, 0}))
self.immutable_vars__test_field(app3, "Set1", frozenset({1, 20}), set({4, 0}))
self.immutable_vars__test_field(
app3, "ListStr2", ("mod val3", "mod val3"), ["mod val3", "mod val3"]
)
self.immutable_vars__test_field(
app3, "Dict2", {9: 8.1, 5: 98.6, 551: 3.6}, {9: 8.1, 5: 98.6, 551: 3.6}
)
self.immutable_vars__test_field(app3, "ListStr2", ("mod val3", "mod val3"), ["mod val3", "mod val3"])
self.immutable_vars__test_field(app3, "Dict2", {9: 8.1, 5: 98.6, 551: 3.6}, {9: 8.1, 5: 98.6, 551: 3.6})
self.immutable_vars__test_field(app3, "Tuple2", ("aaa", "ccc"), ("aaa", "ccc"))
self.immutable_vars__test_field(
app3, "FrozenSet2", frozenset({114, 127}), frozenset({114, 127})
)
self.immutable_vars__test_field(app3, "FrozenSet2", frozenset({114, 127}), frozenset({114, 127}))
self.immutable_vars__test_field(app3, "Set2", frozenset({10, 250}), set({10, 250}))
self.check_immutable_fields_schema(
app3, "ListStr", ("mod val1", "mod val2"), ("val1", "val2"), list[str]
)
self.check_immutable_fields_schema(app3, "ListStr", ("mod val1", "mod val2"), ("val1", "val2"), list[str])
self.check_immutable_fields_schema(
app3,
"Dict1",
@@ -1258,15 +1149,9 @@ class ApplianceTest(unittest.TestCase):
{1: 1.1, 4: 7.6, 91: 23.6},
dict[int, float],
)
self.check_immutable_fields_schema(
app3, "Tuple1", ("aa", "cc"), ("a", "c"), tuple[str, ...]
)
self.check_immutable_fields_schema(
app3, "FrozenSet1", frozenset({14, 27}), frozenset({1, 2}), frozenset[int]
)
self.check_immutable_fields_schema(
app3, "Set1", frozenset({1, 20}), frozenset({1, 2}), set[int]
)
self.check_immutable_fields_schema(app3, "Tuple1", ("aa", "cc"), ("a", "c"), tuple[str, ...])
self.check_immutable_fields_schema(app3, "FrozenSet1", frozenset({14, 27}), frozenset({1, 2}), frozenset[int])
self.check_immutable_fields_schema(app3, "Set1", frozenset({1, 20}), frozenset({1, 2}), set[int])
self.check_immutable_fields_schema(
app3,
@@ -1282,9 +1167,7 @@ class ApplianceTest(unittest.TestCase):
{9: 8.1, 5: 98.6, 551: 3.6},
dict[int, float],
)
self.check_immutable_fields_schema(
app3, "Tuple2", ("aaa", "ccc"), ("aaa", "ccc"), tuple[str, ...]
)
self.check_immutable_fields_schema(app3, "Tuple2", ("aaa", "ccc"), ("aaa", "ccc"), tuple[str, ...])
self.check_immutable_fields_schema(
app3,
"FrozenSet2",
@@ -1292,21 +1175,15 @@ class ApplianceTest(unittest.TestCase):
frozenset({114, 127}),
frozenset[int],
)
self.check_immutable_fields_schema(
app3, "Set2", frozenset({10, 250}), frozenset({10, 250}), set[int]
)
self.check_immutable_fields_schema(app3, "Set2", frozenset({10, 250}), frozenset({10, 250}), set[int])
self.immutable_vars__test_field(app2, "ListStr", ("mod val1", "mod val2"), ["val2", "val3"])
self.immutable_vars__test_field(
app2, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6}
)
self.immutable_vars__test_field(app2, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6})
self.immutable_vars__test_field(app2, "Tuple1", ("aa", "cc"), ("h", "r"))
self.immutable_vars__test_field(app2, "FrozenSet1", frozenset({14, 27}), frozenset({4, 0}))
self.immutable_vars__test_field(app2, "Set1", frozenset({1, 20}), set({4, 0}))
self.check_immutable_fields_schema(
app2, "ListStr", ("mod val1", "mod val2"), ("val1", "val2"), list[str]
)
self.check_immutable_fields_schema(app2, "ListStr", ("mod val1", "mod val2"), ("val1", "val2"), list[str])
self.check_immutable_fields_schema(
app2,
"Dict1",
@@ -1314,27 +1191,17 @@ class ApplianceTest(unittest.TestCase):
{1: 1.1, 4: 7.6, 91: 23.6},
dict[int, float],
)
self.check_immutable_fields_schema(
app2, "Tuple1", ("aa", "cc"), ("a", "c"), tuple[str, ...]
)
self.check_immutable_fields_schema(
app2, "FrozenSet1", frozenset({14, 27}), frozenset({1, 2}), frozenset[int]
)
self.check_immutable_fields_schema(
app2, "Set1", frozenset({1, 20}), frozenset({1, 2}), set[int]
)
self.check_immutable_fields_schema(app2, "Tuple1", ("aa", "cc"), ("a", "c"), tuple[str, ...])
self.check_immutable_fields_schema(app2, "FrozenSet1", frozenset({14, 27}), frozenset({1, 2}), frozenset[int])
self.check_immutable_fields_schema(app2, "Set1", frozenset({1, 20}), frozenset({1, 2}), set[int])
self.immutable_vars__test_field(app1, "ListStr", ("val1", "val2"), ["val2", "val3"])
self.immutable_vars__test_field(
app1, "Dict1", {1: 1.1, 4: 7.6, 91: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6}
)
self.immutable_vars__test_field(app1, "Dict1", {1: 1.1, 4: 7.6, 91: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6})
self.immutable_vars__test_field(app1, "Tuple1", ("a", "c"), ("h", "r"))
self.immutable_vars__test_field(app1, "FrozenSet1", frozenset({1, 2}), frozenset({4, 0}))
self.immutable_vars__test_field(app1, "Set1", frozenset({1, 2}), set({4, 0}))
self.check_immutable_fields_schema(
app1, "ListStr", ("val1", "val2"), ("val1", "val2"), list[str]
)
self.check_immutable_fields_schema(app1, "ListStr", ("val1", "val2"), ("val1", "val2"), list[str])
self.check_immutable_fields_schema(
app1,
"Dict1",
@@ -1343,12 +1210,8 @@ class ApplianceTest(unittest.TestCase):
dict[int, float],
)
self.check_immutable_fields_schema(app1, "Tuple1", ("a", "c"), ("a", "c"), tuple[str, ...])
self.check_immutable_fields_schema(
app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), frozenset[int]
)
self.check_immutable_fields_schema(
app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), set[int]
)
self.check_immutable_fields_schema(app1, "FrozenSet1", frozenset({1, 2}), frozenset({1, 2}), frozenset[int])
self.check_immutable_fields_schema(app1, "Set1", frozenset({1, 2}), frozenset({1, 2}), set[int])
def test_initializer(self):
"""Testing first appliance level, and Field types (simple)"""
@@ -1804,34 +1667,37 @@ class ApplianceTest(unittest.TestCase):
def test_deepfreeze_nested_dict_list_set(self):
class App(dm.Appliance):
data: dict[str, list[int] | set[str] | dict[str, list[int] | set[str]]] = {
"numbers": [1, 2, 3],
data: dict[str, list[int]] = {"numbers": [1, 2, 3]}
data2: dict[str, set[str]] = {
"letters": {"a", "b", "c"},
"mixed": {"x": [4, 5], "y": {"z"}},
}
data3: dict[str, dict[str, list[int]]] = {
"mixed": {"x": [4, 5]},
}
app = App()
# Top-level: should be frozendict
self.assertEqual(type(app.data).__name__, "frozendict")
self.assertEqual(type(app.data2).__name__, "frozendict")
self.assertEqual(type(app.data3).__name__, "frozendict")
# Lists must be frozen to tuple
self.assertIsInstance(app.data["numbers"], tuple)
self.assertIsInstance(app.data["mixed"]["x"], tuple)
self.assertIsInstance(app.data3["mixed"]["x"], tuple)
# Sets must be frozen to frozenset
self.assertIsInstance(app.data["letters"], frozenset)
self.assertIsInstance(app.data["mixed"]["y"], frozenset)
self.assertIsInstance(app.data2["letters"], frozenset)
# Check immutability
with self.assertRaises(TypeError):
app.data["numbers"] += (99,)
with self.assertRaises(AttributeError):
app.data["letters"].add("d")
app.data2["letters"].add("d")
with self.assertRaises(TypeError):
app.data["mixed"]["x"] += (6,)
app.data3["mixed"]["x"] += (6,)
def test_unknown_parameters_raise(self):
class App(dm.Appliance):

View File

@@ -7,7 +7,7 @@
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
import unittest
from typing import Annotated, Union
import sys
import subprocess
from os import chdir, environ
@@ -801,6 +801,60 @@ class ElementTest(unittest.TestCase):
self.assertIsInstance(_elemB.el2, type(elemB.el1))
self.assertIsInstance(_elemB.el2, type(_elemA.el1))
def test_element_mutable_invalid_instance_override_container(self):
class Elem(dm.Element, options=(dm.ClassMutable, dm.ObjectMutable)):
val: list[int] = []
with self.assertRaises(dm.InvalidFieldValue):
Elem(val=["test"])
def test_element_mutable_invalid_instance_override_container_nested(self):
class ElemInner(dm.Element, options=(dm.ClassMutable, dm.ObjectMutable)):
val: list[int] = []
class ElemOuter(dm.Element, options=(dm.ClassMutable, dm.ObjectMutable)):
inner: ElemInner = ElemInner()
# with self.assertRaises(dm.InvalidFieldValue):
elem = ElemOuter(inner={"val": [1, 2, 3]})
self.assertEqual(elem.inner.val, [1, 2, 3])
def test_class_protocol(self):
self.assertIsInstance(dm.base_element.BaseElement, dm.interfaces.FreezableElement)
def test_wrong_annotated(self):
with self.assertRaises(dm.UnsupportedFieldType):
class Elem(dm.Appliance):
StrVar: list[Annotated[str, dm.LAMFieldInfo(doc="foo1")]] = ["default value"]
def test_wrong_annotation_union(self):
with self.assertRaises(dm.UnsupportedFieldType):
class Elem(dm.Appliance):
StrVar: str | int = "test"
with self.assertRaises(dm.UnsupportedFieldType):
class Elem(dm.Appliance):
StrVar: list[str | int] = "test"
with self.assertRaises(dm.UnsupportedFieldType):
class Elem(dm.Appliance):
StrVar: list[None | int] = "test"
def test_annotation_union(self):
class Elem(dm.Appliance):
strvar1: str | None = "test"
strvar1: str | None = None
ivar1: Union[int, None] = 12
ivar2: Union[int, None] = None
# ---------- main ----------

View File

@@ -664,6 +664,165 @@ class FeatureTest(unittest.TestCase):
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 ----------