work
This commit is contained in:
@@ -12,6 +12,7 @@ Main module __init__ file.
|
||||
|
||||
from .__metadata__ import __version__, __Summuary__, __Name__
|
||||
from .model import (
|
||||
DABFieldInfo,
|
||||
BaseAppliance,
|
||||
BaseFeature,
|
||||
DABModelException,
|
||||
|
||||
@@ -88,36 +88,50 @@ def _peel_annotated(t: Any) -> Any:
|
||||
return t
|
||||
|
||||
|
||||
def __check_annotation_definition__(_type) -> bool:
|
||||
def _check_annotation_definition(_type) -> bool:
|
||||
_type = _peel_annotated(_type)
|
||||
# handle Optional[] and Union[None,...]
|
||||
if (get_origin(_type) is Union or get_origin(_type) is UnionType) and type(None) in get_args(_type):
|
||||
return all([__check_annotation_definition__(_) for _ in get_args(_type) if _ is not type(None)])
|
||||
return all([_check_annotation_definition(_) for _ in get_args(_type) if _ is not type(None)])
|
||||
|
||||
# handle other Union[...]
|
||||
if get_origin(_type) is Union or get_origin(_type) is UnionType:
|
||||
return all([__check_annotation_definition__(_) for _ in get_args(_type)])
|
||||
return all([_check_annotation_definition(_) for _ in get_args(_type)])
|
||||
|
||||
# handle Dict[...]
|
||||
if get_origin(_type) is dict:
|
||||
inner = get_args(_type)
|
||||
if len(inner) != 2:
|
||||
raise IncompletelyAnnotatedField(f"Dict Annotation requires 2 inner definitions: {_type}")
|
||||
return _peel_annotated(inner[0]) in ALLOWED_MODEL_FIELDS_TYPES and __check_annotation_definition__(inner[1])
|
||||
return _peel_annotated(inner[0]) in ALLOWED_MODEL_FIELDS_TYPES and _check_annotation_definition(inner[1])
|
||||
|
||||
# handle Tuple[]
|
||||
if get_origin(_type) in [tuple]:
|
||||
inner_types = get_args(_type)
|
||||
if len(inner_types) == 0:
|
||||
raise IncompletelyAnnotatedField(f"Annotation requires inner definition: {_type}")
|
||||
if len(inner_types) == 2 and inner_types[1] is Ellipsis:
|
||||
return _check_annotation_definition(inner_types[0])
|
||||
return all([_check_annotation_definition(_) for _ in inner_types])
|
||||
|
||||
# handle Set[],Tuple[],FrozenSet[],List[]
|
||||
if get_origin(_type) in [set, frozenset, tuple, list]:
|
||||
inner_types = get_args(_type)
|
||||
if len(inner_types) == 0:
|
||||
raise IncompletelyAnnotatedField(f"Annotation requires inner definition: {_type}")
|
||||
return all([__check_annotation_definition__(_) for _ in inner_types])
|
||||
return all([_check_annotation_definition(_) for _ in inner_types])
|
||||
|
||||
if _type in ALLOWED_MODEL_FIELDS_TYPES:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Constraint: ...
|
||||
class BaseConstraint(Generic[TV_ALLOWED_MODEL_FIELDS_TYPES]):
|
||||
_bound_type: type
|
||||
|
||||
def __init__(self): ...
|
||||
|
||||
def check(self, value: TV_ALLOWED_MODEL_FIELDS_TYPES) -> bool: ...
|
||||
|
||||
|
||||
def _deepfreeze(value):
|
||||
@@ -132,38 +146,85 @@ def _deepfreeze(value):
|
||||
return value
|
||||
|
||||
|
||||
class DABFieldInfo:
|
||||
def __init__(self, *, doc: str = "", constraints: list[BaseConstraint] = []):
|
||||
self._doc: str = doc
|
||||
self._constraints: list[BaseConstraint] = constraints
|
||||
|
||||
@property
|
||||
def doc(self):
|
||||
return self._doc
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
return self._constraints
|
||||
|
||||
|
||||
class DABField(Generic[TV_ALLOWED_MODEL_FIELDS_TYPES]):
|
||||
def __init__(self, name: str, v: Optional[TV_ALLOWED_MODEL_FIELDS_TYPES], a: Any):
|
||||
self._constraints: List[Constraint] = []
|
||||
def __init__(self, name: str, v: Optional[TV_ALLOWED_MODEL_FIELDS_TYPES], a: Any, i: str):
|
||||
self._name: str = name
|
||||
self._source: Optional[type] = None
|
||||
self._default_value: Optional[TV_ALLOWED_MODEL_FIELDS_TYPES] = v
|
||||
self._value: Optional[TV_ALLOWED_MODEL_FIELDS_TYPES] = v
|
||||
self._annotations: Any = a
|
||||
self._documentation: str = ""
|
||||
|
||||
def add_documentation(self, d: str) -> None:
|
||||
self._documentation = d
|
||||
self._info: DABFieldInfo = i
|
||||
self._constraints: List[BaseConstraint] = i.constraints
|
||||
|
||||
def add_source(self, s: type) -> None:
|
||||
self._source = s
|
||||
|
||||
def add_constraint(self, c: Constraint) -> None:
|
||||
@property
|
||||
def doc(self):
|
||||
return self._info.doc
|
||||
|
||||
def add_constraint(self, c: BaseConstraint) -> None:
|
||||
self._constraints.append(c)
|
||||
|
||||
@property
|
||||
def constraints(self) -> list[BaseConstraint]:
|
||||
return self._info.constraints
|
||||
|
||||
@property
|
||||
def default_value(self):
|
||||
return _deepfreeze(self._default_value)
|
||||
|
||||
def update_value(self, v: Optional[TV_ALLOWED_MODEL_FIELDS_TYPES] = None) -> None:
|
||||
self._value = v
|
||||
|
||||
def render(self) -> TV_ALLOWED_MODEL_FIELDS_TYPES:
|
||||
@property
|
||||
def value(self):
|
||||
return _deepfreeze(self._value)
|
||||
|
||||
def render_default(self) -> TV_ALLOWED_MODEL_FIELDS_TYPES:
|
||||
return _deepfreeze(self._default_value)
|
||||
|
||||
def get_annotation(self) -> Any:
|
||||
@property
|
||||
def annotations(self) -> Any:
|
||||
return self._annotations
|
||||
|
||||
|
||||
class FrozenDABField(Generic[TV_ALLOWED_MODEL_FIELDS_TYPES]):
|
||||
def __init__(self, inner_field: DABField):
|
||||
self._inner_field = inner_field
|
||||
|
||||
@property
|
||||
def doc(self):
|
||||
return self._inner_field.doc
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
return _deepfreeze(self._inner_field.constraints)
|
||||
|
||||
@property
|
||||
def default_value(self):
|
||||
return self._inner_field.default_value
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._inner_field.value
|
||||
|
||||
@property
|
||||
def annotations(self) -> Any:
|
||||
return _deepfreeze(self._inner_field.annotations)
|
||||
|
||||
|
||||
class BaseMeta(type):
|
||||
def __new__(mcls, name, bases, namespace):
|
||||
# print("__NEW__ Defining:", name, "with keys:", list(namespace))
|
||||
@@ -198,12 +259,12 @@ class BaseMeta(type):
|
||||
# Modified fields
|
||||
if len(bases) == 1 and _fname in namespace["__DABSchema__"].keys():
|
||||
# print(f"Modified field: {_fname}")
|
||||
if _fname in namespace["__annotations__"]:
|
||||
if "__annotations__" in namespace and _fname in namespace["__annotations__"]:
|
||||
raise ReadOnlyFieldAnnotation("annotations cannot be modified on derived classes")
|
||||
try:
|
||||
check_type(
|
||||
_fvalue,
|
||||
namespace["__DABSchema__"][_fname].get_annotation(),
|
||||
namespace["__DABSchema__"][_fname].annotations,
|
||||
collection_check_strategy=CollectionCheckStrategy.ALL_ITEMS,
|
||||
)
|
||||
except TypeCheckError as exp:
|
||||
@@ -225,9 +286,22 @@ class BaseMeta(type):
|
||||
if isinstance(namespace["__annotations__"][_fname], str):
|
||||
namespace["__annotations__"][_fname] = _resolve_annotation(namespace["__annotations__"][_fname])
|
||||
|
||||
if not __check_annotation_definition__(namespace["__annotations__"][_fname]):
|
||||
if not _check_annotation_definition(namespace["__annotations__"][_fname]):
|
||||
raise InvalidFieldAnnotation(f"Field <{_fname}> has not an allowed or valid annotation.")
|
||||
|
||||
_finfo: Optional[DABFieldInfo] = DABFieldInfo()
|
||||
origin = get_origin(namespace["__annotations__"][_fname])
|
||||
name = getattr(origin, "__name__", "") or getattr(origin, "__qualname__", "") or str(origin)
|
||||
if "Annotated" in name:
|
||||
args = get_args(namespace["__annotations__"][_fname])
|
||||
if args:
|
||||
if len(args) > 2:
|
||||
raise InvalidFieldAnnotation(f"Field <{_fname}> had invalid Annotated value.")
|
||||
if len(args) == 2 and not isinstance(args[1], DABFieldInfo):
|
||||
raise InvalidFieldAnnotation(f"Only DABFieldInfo object is allowed as Annotated data.")
|
||||
|
||||
_finfo = args[1]
|
||||
|
||||
# print(f"annotation is: {namespace['__annotations__'][_fname]}")
|
||||
# check if value is valid
|
||||
try:
|
||||
@@ -238,8 +312,7 @@ class BaseMeta(type):
|
||||
raise InvalidFieldValue(
|
||||
f"Value of Field <{_fname}> is not of expected type {namespace['__annotations__'][_fname]}."
|
||||
) from exp
|
||||
new_fields[_fname] = DABField(_fname, _fvalue, namespace["__annotations__"][_fname])
|
||||
# namespace[_fname].add_documentation()
|
||||
new_fields[_fname] = DABField(_fname, _fvalue, namespace["__annotations__"][_fname], _finfo)
|
||||
|
||||
# removing modified fields from class (will add them back later)
|
||||
for _fname in new_fields.keys():
|
||||
@@ -279,9 +352,13 @@ class BaseMeta(type):
|
||||
obj = super().__call__(*args, **kw)
|
||||
|
||||
for _fname in cls.__DABSchema__.keys():
|
||||
setattr(obj, _fname, cls.__DABSchema__[_fname].render())
|
||||
setattr(obj, _fname, cls.__DABSchema__[_fname].value)
|
||||
# obj.__DABSchema__ = deepfreeze(obj.__DABSchema__)
|
||||
# setattr(obj, "__DABSchema__", deepfreeze(obj.__DABSchema__))
|
||||
inst_schema = dict()
|
||||
for _fname, _fvalue in cls.__DABSchema__.items():
|
||||
inst_schema[_fname] = FrozenDABField(_fvalue)
|
||||
setattr(obj, "__DABSchema__", inst_schema)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@@ -175,13 +175,6 @@ class TestConfigWithoutEnabledFlag(unittest.TestCase):
|
||||
class _(dm.BaseAppliance):
|
||||
_ = "default value"
|
||||
|
||||
def test_annotated(self):
|
||||
"""Testing first appliance level, and Field types (annotated one)"""
|
||||
|
||||
# class can be created if annotation is a string
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
StrVar: Annotated[str, "my string"] = "default value"
|
||||
|
||||
def test_optionnal(self):
|
||||
"""Testing first appliance level, and Field types (Optionnal annotations)"""
|
||||
|
||||
@@ -492,6 +485,7 @@ class TestConfigWithoutEnabledFlag(unittest.TestCase):
|
||||
testVar4: "Tuple[str,...]" = ("a", "c")
|
||||
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()
|
||||
@@ -502,7 +496,7 @@ class TestConfigWithoutEnabledFlag(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"))
|
||||
self.immutable_vars__test_field(app1, "testVar7", (1, "b"), (7, "h"))
|
||||
|
||||
# must work
|
||||
sorted(app1.testVar)
|
||||
@@ -527,6 +521,381 @@ class TestConfigWithoutEnabledFlag(unittest.TestCase):
|
||||
class _(dm.BaseAppliance):
|
||||
_: "Tuple" = (1, 2)
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "Tuple[int,...]" = (1, "a")
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "tuple[int,...]" = (1, "a")
|
||||
|
||||
def check_immutable_fields_schema(
|
||||
self, appliance: dm.BaseAppliance, field_name: str, expected_value: str, expected_default_value: str, expected_type: type
|
||||
):
|
||||
self.assertIn(field_name, appliance.__DABSchema__)
|
||||
self.assertIn("doc", dir(appliance.__DABSchema__[field_name]))
|
||||
self.assertEqual(appliance.__DABSchema__[field_name].doc, "")
|
||||
self.assertIn("annotations", dir(appliance.__DABSchema__[field_name]))
|
||||
self.assertEqual(appliance.__DABSchema__[field_name].annotations, expected_type)
|
||||
self.assertIn("value", dir(appliance.__DABSchema__[field_name]))
|
||||
self.assertEqual(appliance.__DABSchema__[field_name].value, expected_value)
|
||||
self.assertIn("default_value", dir(appliance.__DABSchema__[field_name]))
|
||||
self.assertEqual(appliance.__DABSchema__[field_name].default_value, expected_default_value)
|
||||
self.assertIn("constraints", dir(appliance.__DABSchema__[field_name]))
|
||||
self.assertEqual(appliance.__DABSchema__[field_name].constraints, ())
|
||||
|
||||
def test_immutable_fields_schema(self):
|
||||
"""Testing first appliance level, and Field types (annotated)"""
|
||||
|
||||
# class can be created
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
StrVar: "str" = "default value"
|
||||
StrVar2: "str" = "default value2"
|
||||
VarInt: "int" = 12
|
||||
VarInt2: "int" = 21
|
||||
VarFloat: "float" = 12.1
|
||||
VarFloat2: "float" = 21.2
|
||||
VarComplex: "complex" = complex(3, 5)
|
||||
VarComplex2: "complex" = complex(8, 6)
|
||||
VarBool: "bool" = True
|
||||
VarBool2: "bool" = False
|
||||
VarBytes: "bytes" = bytes.fromhex("2Ef0 F1f2 ")
|
||||
VarBytes2: "bytes" = bytes.fromhex("2ff0 F7f2 ")
|
||||
|
||||
app1 = Appliance1()
|
||||
|
||||
self.assertIn("__DABSchema__", dir(app1))
|
||||
self.assertIn("__DABSchema__", app1.__dict__)
|
||||
|
||||
self.check_immutable_fields_schema(app1, "StrVar", "default value", "default value", str)
|
||||
self.check_immutable_fields_schema(app1, "StrVar2", "default value2", "default value2", str)
|
||||
self.check_immutable_fields_schema(app1, "VarInt", 12, 12, int)
|
||||
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, "VarBool", True, True, bool)
|
||||
self.check_immutable_fields_schema(app1, "VarBool2", False, False, bool)
|
||||
self.check_immutable_fields_schema(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("2Ef0 F1f2 "), bytes)
|
||||
self.check_immutable_fields_schema(app1, "VarBytes2", bytes.fromhex("2ff0 F7f2 "), bytes.fromhex("2ff0 F7f2 "), bytes)
|
||||
|
||||
def test_container_field_schema(self):
|
||||
"""Testing first appliance level, and Field types (annotated)"""
|
||||
|
||||
# class can be created
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
ListStr: list[str] = ["val1", "val2"]
|
||||
ListStr2: "list[str]" = ["val3", "val4"]
|
||||
Dict1: dict[int, float] = {1: 1.1, 4: 7.6, 91: 23.6}
|
||||
Dict2: "dict[str, str]" = {"1": "1.1", "4": "7.6", "91": "23.6"}
|
||||
Tuple1: "tuple[str,...]" = ("a", "c")
|
||||
Tuple2: tuple[str, ...] = ("a", "b")
|
||||
FrozenSet1: frozenset[int] = frozenset({1, 2})
|
||||
FrozenSet2: "frozenset[int]" = frozenset({1, 2})
|
||||
Set1: set[int] = set({1, 2})
|
||||
Set2: "set[int]" = set({1, 2})
|
||||
|
||||
app1 = Appliance1()
|
||||
|
||||
self.assertIn("__DABSchema__", dir(app1))
|
||||
self.assertIn("__DABSchema__", 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, "Dict1", {1: 1.1, 4: 7.6, 91: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6}, dict[int, float])
|
||||
self.check_immutable_fields_schema(
|
||||
app1, "Dict2", {"1": "1.1", "4": "7.6", "91": "23.6"}, {"1": "1.1", "4": "7.6", "91": "23.6"}, dict[str, str]
|
||||
)
|
||||
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])
|
||||
|
||||
# same test with Typing types (list -> List ...)
|
||||
# class can be created
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
ListStr: List[str] = ["val1", "val2"]
|
||||
ListStr2: "List[str]" = ["val3", "val4"]
|
||||
Dict1: Dict[int, float] = {1: 1.1, 4: 7.6, 91: 23.6}
|
||||
Dict2: "Dict[str, str]" = {"1": "1.1", "4": "7.6", "91": "23.6"}
|
||||
Tuple1: "Tuple[str,...]" = ("a", "c")
|
||||
Tuple2: Tuple[str, ...] = ("a", "b")
|
||||
FrozenSet1: FrozenSet[int] = frozenset({1, 2})
|
||||
FrozenSet2: "FrozenSet[int]" = frozenset({1, 2})
|
||||
Set1: Set[int] = set({1, 2})
|
||||
Set2: "Set[int]" = set({1, 2})
|
||||
|
||||
app1 = Appliance1()
|
||||
|
||||
self.assertIn("__DABSchema__", dir(app1))
|
||||
self.assertIn("__DABSchema__", 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, "Dict1", {1: 1.1, 4: 7.6, 91: 23.6}, {1: 1.1, 4: 7.6, 91: 23.6}, Dict[int, float])
|
||||
self.check_immutable_fields_schema(
|
||||
app1, "Dict2", {"1": "1.1", "4": "7.6", "91": "23.6"}, {"1": "1.1", "4": "7.6", "91": "23.6"}, Dict[str, str]
|
||||
)
|
||||
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])
|
||||
|
||||
def test_immutable_fields_annotated(self):
|
||||
"""Testing first appliance level, and Field types (annotated)"""
|
||||
|
||||
# class can be created
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
StrVar: Annotated[str, dm.DABFieldInfo(doc="foo1")] = "default value"
|
||||
StrVar2: Annotated[str, dm.DABFieldInfo(doc="foo2")] = "default value2"
|
||||
VarInt: Annotated[int, dm.DABFieldInfo(doc="foo3")] = 12
|
||||
VarInt2: Annotated[int, dm.DABFieldInfo(doc="foo4")] = 21
|
||||
VarFloat: Annotated[float, dm.DABFieldInfo(doc="foo5")] = 12.1
|
||||
VarFloat2: Annotated[float, dm.DABFieldInfo(doc="foo6")] = 21.2
|
||||
VarComplex: Annotated[complex, dm.DABFieldInfo(doc="foo7")] = complex(3, 5)
|
||||
VarComplex2: Annotated[complex, dm.DABFieldInfo(doc="foo8")] = complex(8, 6)
|
||||
VarBool: Annotated[bool, dm.DABFieldInfo(doc="foo9")] = True
|
||||
VarBool2: Annotated[bool, dm.DABFieldInfo(doc="foo10")] = False
|
||||
VarBytes: Annotated[bytes, dm.DABFieldInfo(doc="foo11")] = bytes.fromhex("2Ef0 F1f2 ")
|
||||
VarBytes2: Annotated[bytes, dm.DABFieldInfo(doc="foo12")] = bytes.fromhex("2ff0 F7f2 ")
|
||||
|
||||
app1 = Appliance1()
|
||||
|
||||
self.immutable_vars__test_field(app1, "StrVar", "default value", "test")
|
||||
self.assertEqual(app1.__DABSchema__["StrVar"].doc, "foo1")
|
||||
self.immutable_vars__test_field(app1, "StrVar2", "default value2", "test2")
|
||||
self.assertEqual(app1.__DABSchema__["StrVar2"].doc, "foo2")
|
||||
self.immutable_vars__test_field(app1, "VarInt", 12, 13)
|
||||
self.assertEqual(app1.__DABSchema__["VarInt"].doc, "foo3")
|
||||
self.immutable_vars__test_field(app1, "VarInt2", 21, 22)
|
||||
self.assertEqual(app1.__DABSchema__["VarInt2"].doc, "foo4")
|
||||
self.immutable_vars__test_field(app1, "VarFloat", 12.1, 32)
|
||||
self.assertEqual(app1.__DABSchema__["VarFloat"].doc, "foo5")
|
||||
self.immutable_vars__test_field(app1, "VarFloat2", 21.2, 42)
|
||||
self.assertEqual(app1.__DABSchema__["VarFloat2"].doc, "foo6")
|
||||
self.immutable_vars__test_field(app1, "VarComplex", complex(3, 5), complex(1, 2))
|
||||
self.assertEqual(app1.__DABSchema__["VarComplex"].doc, "foo7")
|
||||
self.immutable_vars__test_field(app1, "VarComplex2", complex(8, 6), complex(3, 2))
|
||||
self.assertEqual(app1.__DABSchema__["VarComplex2"].doc, "foo8")
|
||||
self.immutable_vars__test_field(app1, "VarBool", True, False)
|
||||
self.assertEqual(app1.__DABSchema__["VarBool"].doc, "foo9")
|
||||
self.immutable_vars__test_field(app1, "VarBool2", False, True)
|
||||
self.assertEqual(app1.__DABSchema__["VarBool2"].doc, "foo10")
|
||||
self.immutable_vars__test_field(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("11f0 F1f2 "))
|
||||
self.assertEqual(app1.__DABSchema__["VarBytes"].doc, "foo11")
|
||||
self.immutable_vars__test_field(app1, "VarBytes2", bytes.fromhex("2ff0 F7f2 "), bytes.fromhex("11f0 F1e2 "))
|
||||
self.assertEqual(app1.__DABSchema__["VarBytes2"].doc, "foo12")
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldAnnotation):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: Annotated[str, "foo2"] = "default value2"
|
||||
|
||||
# annotation is parsed before the library can do anything, so the exception can only be TypeError
|
||||
with self.assertRaises(TypeError):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: Annotated[str] = "default value2"
|
||||
|
||||
def test_immutable_fields_inheritance(self):
|
||||
"""Testing first appliance level, and Field types (simple)"""
|
||||
|
||||
# class can be created
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
StrVar: str = "default value"
|
||||
StrVar2: str = "default value2"
|
||||
VarInt: int = 12
|
||||
VarInt2: int = 21
|
||||
VarFloat: float = 12.1
|
||||
VarFloat2: float = 21.2
|
||||
VarComplex: complex = complex(3, 5)
|
||||
VarComplex2: complex = complex(8, 6)
|
||||
VarBool: bool = True
|
||||
VarBool2: bool = False
|
||||
VarBytes: bytes = bytes.fromhex("2Ef0 F1f2 ")
|
||||
VarBytes2: bytes = bytes.fromhex("2ff0 F7f2 ")
|
||||
|
||||
class Appliance2(Appliance1):
|
||||
StrVar = "moded value"
|
||||
StrVar2 = "moded value2"
|
||||
VarInt = 54
|
||||
VarInt2 = 23
|
||||
VarFloat = 2.6
|
||||
VarFloat2 = 1.5
|
||||
VarComplex = complex(7, 1)
|
||||
VarComplex2 = complex(3, 0)
|
||||
VarBool = False
|
||||
VarBool2 = True
|
||||
VarBytes = bytes.fromhex("21f0 e1f2 ")
|
||||
VarBytes2 = bytes.fromhex("2df0 F672 ")
|
||||
|
||||
app1 = Appliance1()
|
||||
|
||||
self.immutable_vars__test_field(app1, "StrVar", "default value", "test")
|
||||
self.immutable_vars__test_field(app1, "StrVar2", "default value2", "test2")
|
||||
self.immutable_vars__test_field(app1, "VarInt", 12, 13)
|
||||
self.immutable_vars__test_field(app1, "VarInt2", 21, 22)
|
||||
self.immutable_vars__test_field(app1, "VarFloat", 12.1, 32)
|
||||
self.immutable_vars__test_field(app1, "VarFloat2", 21.2, 42)
|
||||
self.immutable_vars__test_field(app1, "VarComplex", complex(3, 5), complex(1, 2))
|
||||
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, "VarBytes2", bytes.fromhex("2ff0 F7f2 "), bytes.fromhex("11f0 F1e2 "))
|
||||
|
||||
self.check_immutable_fields_schema(app1, "StrVar", "default value", "default value", str)
|
||||
self.check_immutable_fields_schema(app1, "StrVar2", "default value2", "default value2", str)
|
||||
self.check_immutable_fields_schema(app1, "VarInt", 12, 12, int)
|
||||
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, "VarBool", True, True, bool)
|
||||
self.check_immutable_fields_schema(app1, "VarBool2", False, False, bool)
|
||||
self.check_immutable_fields_schema(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("2Ef0 F1f2 "), bytes)
|
||||
self.check_immutable_fields_schema(app1, "VarBytes2", bytes.fromhex("2ff0 F7f2 "), bytes.fromhex("2ff0 F7f2 "), bytes)
|
||||
|
||||
app2 = Appliance2()
|
||||
|
||||
self.immutable_vars__test_field(app2, "StrVar", "moded value", "test")
|
||||
self.immutable_vars__test_field(app2, "StrVar2", "moded value2", "test2")
|
||||
self.immutable_vars__test_field(app2, "VarInt", 54, 13)
|
||||
self.immutable_vars__test_field(app2, "VarInt2", 23, 22)
|
||||
self.immutable_vars__test_field(app2, "VarFloat", 2.6, 32)
|
||||
self.immutable_vars__test_field(app2, "VarFloat2", 1.5, 42)
|
||||
self.immutable_vars__test_field(app2, "VarComplex", complex(7, 1), complex(1, 2))
|
||||
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, "VarBytes2", bytes.fromhex("2df0 F672 "), bytes.fromhex("11f0 F1e2 "))
|
||||
|
||||
self.check_immutable_fields_schema(app2, "StrVar", "moded value", "default value", str)
|
||||
self.check_immutable_fields_schema(app2, "StrVar2", "moded value2", "default value2", str)
|
||||
self.check_immutable_fields_schema(app2, "VarInt", 54, 12, int)
|
||||
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, "VarBool", False, True, bool)
|
||||
self.check_immutable_fields_schema(app2, "VarBool2", True, False, bool)
|
||||
self.check_immutable_fields_schema(app2, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("2Ef0 F1f2 "), bytes)
|
||||
self.check_immutable_fields_schema(app2, "VarBytes2", bytes.fromhex("2df0 F672 "), bytes.fromhex("2ff0 F7f2 "), bytes)
|
||||
|
||||
class Appliance3(Appliance2):
|
||||
NewValue: str = "newval"
|
||||
|
||||
self.assertNotIn("NewValue", Appliance2.__DABSchema__)
|
||||
self.assertNotIn("NewValue", app2.__DABSchema__)
|
||||
self.assertNotIn("NewValue", Appliance1.__DABSchema__)
|
||||
self.assertNotIn("NewValue", app1.__DABSchema__)
|
||||
|
||||
app3 = Appliance3()
|
||||
self.immutable_vars__test_field(app3, "StrVar", "moded value", "test")
|
||||
self.immutable_vars__test_field(app3, "StrVar2", "moded value2", "test2")
|
||||
self.immutable_vars__test_field(app3, "VarInt", 54, 13)
|
||||
self.immutable_vars__test_field(app3, "VarInt2", 23, 22)
|
||||
self.immutable_vars__test_field(app3, "VarFloat", 2.6, 32)
|
||||
self.immutable_vars__test_field(app3, "VarFloat2", 1.5, 42)
|
||||
self.immutable_vars__test_field(app3, "VarComplex", complex(7, 1), complex(1, 2))
|
||||
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, "VarBytes2", bytes.fromhex("2df0 F672 "), bytes.fromhex("11f0 F1e2 "))
|
||||
self.immutable_vars__test_field(app3, "NewValue", "newval", "test")
|
||||
|
||||
self.check_immutable_fields_schema(app3, "StrVar", "moded value", "default value", str)
|
||||
self.check_immutable_fields_schema(app3, "StrVar2", "moded value2", "default value2", str)
|
||||
self.check_immutable_fields_schema(app3, "VarInt", 54, 12, int)
|
||||
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, "VarBool", False, True, bool)
|
||||
self.check_immutable_fields_schema(app3, "VarBool2", True, False, bool)
|
||||
self.check_immutable_fields_schema(app3, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("2Ef0 F1f2 "), bytes)
|
||||
self.check_immutable_fields_schema(app3, "VarBytes2", bytes.fromhex("2df0 F672 "), bytes.fromhex("2ff0 F7f2 "), bytes)
|
||||
self.check_immutable_fields_schema(app3, "NewValue", "newval", "newval", str)
|
||||
|
||||
self.immutable_vars__test_field(app1, "StrVar", "default value", "test")
|
||||
self.immutable_vars__test_field(app1, "StrVar2", "default value2", "test2")
|
||||
self.immutable_vars__test_field(app1, "VarInt", 12, 13)
|
||||
self.immutable_vars__test_field(app1, "VarInt2", 21, 22)
|
||||
self.immutable_vars__test_field(app1, "VarFloat", 12.1, 32)
|
||||
self.immutable_vars__test_field(app1, "VarFloat2", 21.2, 42)
|
||||
self.immutable_vars__test_field(app1, "VarComplex", complex(3, 5), complex(1, 2))
|
||||
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, "VarBytes2", bytes.fromhex("2ff0 F7f2 "), bytes.fromhex("11f0 F1e2 "))
|
||||
|
||||
self.check_immutable_fields_schema(app1, "StrVar", "default value", "default value", str)
|
||||
self.check_immutable_fields_schema(app1, "StrVar2", "default value2", "default value2", str)
|
||||
self.check_immutable_fields_schema(app1, "VarInt", 12, 12, int)
|
||||
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, "VarBool", True, True, bool)
|
||||
self.check_immutable_fields_schema(app1, "VarBool2", False, False, bool)
|
||||
self.check_immutable_fields_schema(app1, "VarBytes", bytes.fromhex("2Ef0 F1f2 "), bytes.fromhex("2Ef0 F1f2 "), bytes)
|
||||
self.check_immutable_fields_schema(app1, "VarBytes2", bytes.fromhex("2ff0 F7f2 "), bytes.fromhex("2ff0 F7f2 "), bytes)
|
||||
|
||||
self.immutable_vars__test_field(app2, "StrVar", "moded value", "test")
|
||||
self.immutable_vars__test_field(app2, "StrVar2", "moded value2", "test2")
|
||||
self.immutable_vars__test_field(app2, "VarInt", 54, 13)
|
||||
self.immutable_vars__test_field(app2, "VarInt2", 23, 22)
|
||||
self.immutable_vars__test_field(app2, "VarFloat", 2.6, 32)
|
||||
self.immutable_vars__test_field(app2, "VarFloat2", 1.5, 42)
|
||||
self.immutable_vars__test_field(app2, "VarComplex", complex(7, 1), complex(1, 2))
|
||||
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, "VarBytes2", bytes.fromhex("2df0 F672 "), bytes.fromhex("11f0 F1e2 "))
|
||||
|
||||
self.check_immutable_fields_schema(app2, "StrVar", "moded value", "default value", str)
|
||||
self.check_immutable_fields_schema(app2, "StrVar2", "moded value2", "default value2", str)
|
||||
self.check_immutable_fields_schema(app2, "VarInt", 54, 12, int)
|
||||
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, "VarBool", False, True, bool)
|
||||
self.check_immutable_fields_schema(app2, "VarBool2", True, False, bool)
|
||||
self.check_immutable_fields_schema(app2, "VarBytes", bytes.fromhex("21f0 e1f2 "), bytes.fromhex("2Ef0 F1f2 "), bytes)
|
||||
self.check_immutable_fields_schema(app2, "VarBytes2", bytes.fromhex("2df0 F672 "), bytes.fromhex("2ff0 F7f2 "), bytes)
|
||||
|
||||
with self.assertRaises(dm.ReadOnlyFieldAnnotation):
|
||||
|
||||
class _(Appliance1):
|
||||
StrVar: int = 12
|
||||
|
||||
with self.assertRaises(dm.ReadOnlyFieldAnnotation):
|
||||
|
||||
class _(Appliance3):
|
||||
NewValue: int = 12
|
||||
|
||||
with self.assertRaises(dm.ReadOnlyFieldAnnotation):
|
||||
|
||||
class _(Appliance3):
|
||||
StrVar: int = 12
|
||||
|
||||
|
||||
# ---------- main ----------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user