1183 lines
56 KiB
Python
1183 lines
56 KiB
Python
# 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
|
|
|
|
import sys
|
|
import subprocess
|
|
from os import chdir, environ
|
|
from pathlib import Path
|
|
import textwrap
|
|
from typing import List, Optional, Dict, Union, Tuple, Set, FrozenSet, TypeVar, Generic, Any, Annotated
|
|
from pprint import pprint
|
|
from frozendict import frozendict
|
|
|
|
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 TestConfigWithoutEnabledFlag(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.__DABSchema__.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_immutable_fields(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 ")
|
|
|
|
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 "))
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: str = 12
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: int = "value"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: float = "value"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: complex = "value"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: bool = "value"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: bytes = "value"
|
|
|
|
def test_annotation(self):
|
|
"""Testing first appliance level, and Field types (simple annotations)"""
|
|
|
|
# class can be created if annotation is a string
|
|
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.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 "))
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "str" = 12
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "int" = "value"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "float" = "value"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "complex" = "value"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "bool" = "value"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "bytes" = "value"
|
|
|
|
# class cannot be created if not annotated field
|
|
with self.assertRaises(dm.NotAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_ = "default value"
|
|
|
|
def test_optionnal(self):
|
|
"""Testing first appliance level, and Field types (Optionnal annotations)"""
|
|
|
|
# class can be created with Optionnal (and variant)
|
|
class Appliance1(dm.BaseAppliance):
|
|
StrVar: Optional[str] = "default value"
|
|
StrVar2: Optional[str]
|
|
StrVar3: Union[None | str] = "default value"
|
|
StrVar4: Union[None | str]
|
|
StrVar5: None | str = "default value"
|
|
StrVar6: None | str
|
|
|
|
app1 = Appliance1()
|
|
|
|
self.immutable_vars__test_field(app1, "StrVar", "default value", "123")
|
|
self.immutable_vars__test_field(app1, "StrVar2", None, "123")
|
|
self.immutable_vars__test_field(app1, "StrVar3", "default value", "123")
|
|
self.immutable_vars__test_field(app1, "StrVar4", None, "123")
|
|
self.immutable_vars__test_field(app1, "StrVar5", "default value", "123")
|
|
self.immutable_vars__test_field(app1, "StrVar6", None, "123")
|
|
|
|
# class can be created with Optionnal (and variant), as string annotation
|
|
class Appliance2(dm.BaseAppliance):
|
|
StrVar: "Optional[str]" = "default value"
|
|
StrVar2: "Optional[str]"
|
|
StrVar3: "Union[None | str]" = "default value"
|
|
StrVar4: "Union[None | str]"
|
|
StrVar5: "None | str" = "default value"
|
|
StrVar6: "None | str"
|
|
|
|
app2 = Appliance2()
|
|
|
|
self.immutable_vars__test_field(app2, "StrVar", "default value", "123")
|
|
self.immutable_vars__test_field(app2, "StrVar2", None, "123")
|
|
self.immutable_vars__test_field(app2, "StrVar3", "default value", "123")
|
|
self.immutable_vars__test_field(app2, "StrVar4", None, "123")
|
|
self.immutable_vars__test_field(app2, "StrVar5", "default value", "123")
|
|
self.immutable_vars__test_field(app2, "StrVar6", None, "123")
|
|
|
|
# @unittest.skip
|
|
def test_containers__set(self):
|
|
"""Testing first appliance level, and Field types (Set)"""
|
|
|
|
# class can be created with set
|
|
class Appliance1(dm.BaseAppliance):
|
|
testVar: Set[int] = {1, 2}
|
|
testVar2: Set[str] = {"a", "b"}
|
|
testVar3: Set[float] = {0.5, 0.456, 12}
|
|
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})
|
|
self.assertEqual(app1.testVar, {2, 1})
|
|
self.immutable_vars__test_field(app1, "testVar2", {"a", "b"}, {"h", "c"})
|
|
self.assertEqual(app1.testVar2, {"b", "a"})
|
|
self.immutable_vars__test_field(app1, "testVar3", {0.5, 0.456, 12}, {0.9, 0.4156, 11})
|
|
self.assertEqual(app1.testVar3, {0.456, 0.5, 12})
|
|
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)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
app1.testVar.add(3)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
app1.testVar4.add("coucou")
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: Set[int] = {"a"}
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "Set[int]" = {"a"}
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: Set = {1, 2}
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "Set" = {1, 2}
|
|
|
|
# Hacky part !
|
|
# set() are randomly ordered, and typeguard can be configured to only check 1st element of containers.
|
|
# we need to make sure it is properly configured, so we are expecting it to detect wrong type at any element
|
|
# this is why we need to run the code multiple time with a new interpreter that will use a different random seed
|
|
code = textwrap.dedent(
|
|
r"""
|
|
from src import dabmodel as dm
|
|
from typing import Set
|
|
try:
|
|
class Yours(dm.BaseAppliance):
|
|
My1: Set[int] = {99, 1, 3, "a", 5,6}
|
|
except dm.InvalidFieldValue as ex:
|
|
raise SystemExit(2)
|
|
raise SystemExit(0)
|
|
|
|
"""
|
|
)
|
|
|
|
for i in range(15):
|
|
env = environ.copy()
|
|
env["PYTHONHASHSEED"] = str(i)
|
|
res = subprocess.run([sys.executable, "-c", code], env=env)
|
|
self.assertEqual(res.returncode, 2)
|
|
|
|
# @unittest.skip
|
|
def test_containers__frozenset(self):
|
|
"""Testing first appliance level, and Field types (FrozenSet)"""
|
|
|
|
# class can be created with set
|
|
class Appliance1(dm.BaseAppliance):
|
|
testVar: frozenset[int] = frozenset({1, 2})
|
|
testVar2: frozenset[str] = frozenset({"a", "b"})
|
|
testVar3: frozenset[float] = frozenset({0.5, 0.456, 12})
|
|
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})
|
|
self.assertEqual(app1.testVar, {2, 1})
|
|
self.immutable_vars__test_field(app1, "testVar2", {"a", "b"}, {"h", "c"})
|
|
self.assertEqual(app1.testVar2, {"b", "a"})
|
|
self.immutable_vars__test_field(app1, "testVar3", {0.5, 0.456, 12}, {0.9, 0.4156, 11})
|
|
self.assertEqual(app1.testVar3, {0.456, 0.5, 12})
|
|
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)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
app1.testVar.add(3)
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: FrozenSet[int] = {"a"}
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "FrozenSet[int]" = {"a"}
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: FrozenSet = {1, 2}
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "FrozenSet" = {1, 2}
|
|
|
|
# Hacky part !
|
|
# set() are randomly ordered, and typeguard can be configured to only check 1st element of containers.
|
|
# we need to make sure it is properly configured, so we are expecting it to detect wrong type at any element
|
|
# this is why we need to run the code multiple time with a new interpreter that will use a different random seed
|
|
code = textwrap.dedent(
|
|
r"""
|
|
from src import dabmodel as dm
|
|
from typing import FrozenSet
|
|
try:
|
|
class Yours(dm.BaseAppliance):
|
|
My1: FrozenSet[int] = frozenset({99, 1, 3, "a", 5,6})
|
|
except dm.InvalidFieldValue as ex:
|
|
raise SystemExit(2)
|
|
raise SystemExit(0)
|
|
|
|
"""
|
|
)
|
|
|
|
for i in range(15):
|
|
env = environ.copy()
|
|
env["PYTHONHASHSEED"] = str(i)
|
|
res = subprocess.run([sys.executable, "-c", code], env=env)
|
|
self.assertEqual(res.returncode, 2)
|
|
|
|
def test_containers__list(self):
|
|
"""Testing first appliance level, and Field types (List)"""
|
|
|
|
# class can be created with list
|
|
class Appliance1(dm.BaseAppliance):
|
|
testVar: List[int] = [1, 2]
|
|
testVar2: List[str] = ["a", "b"]
|
|
testVar3: List[float] = [0.5, 0.456, 12]
|
|
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
|
|
self.immutable_vars__test_field(app1, "testVar", (1, 2), [1, 5])
|
|
self.immutable_vars__test_field(app1, "testVar2", ("a", "b"), ["h", "c"])
|
|
self.immutable_vars__test_field(app1, "testVar3", (0.5, 0.456, 12), [0.9, 0.4156, 11])
|
|
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)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
app1.testVar.append(3)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
app1.testVar.pop()
|
|
|
|
with self.assertRaises(AttributeError):
|
|
app1.testVar.sort()
|
|
|
|
with self.assertRaises(AttributeError):
|
|
app1.testVar4.append("coucou")
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: List[int] = ["a"]
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "List[int]" = ["a"]
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: List = [1, 2]
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "List" = [1, 2]
|
|
|
|
def test_containers__dict(self):
|
|
"""Testing first appliance level, and Field types (Dict)"""
|
|
|
|
# class can be created with dict
|
|
class Appliance1(dm.BaseAppliance):
|
|
testVar: Dict[int, str] = {1: "a", 2: "b"}
|
|
testVar2: "Dict[int, str]" = {1: "c", 99: "d"}
|
|
|
|
app1 = Appliance1()
|
|
self.immutable_vars__test_field(app1, "testVar", {1: "a", 2: "b"}, {1: "", 99: "i"})
|
|
self.immutable_vars__test_field(app1, "testVar2", {1: "c", 99: "d"}, {10: "", 50: "i"})
|
|
|
|
# TODO: wrap exception type
|
|
with self.assertRaises(TypeError):
|
|
app1.testVar[58] = "aaa"
|
|
|
|
# TODO: wrap exception type
|
|
with self.assertRaises(TypeError):
|
|
app1.testVar[1] = "ggg"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: Dict[int, str] = {1: 64, 2: "b"}
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "Dict[int, str]" = {1: 64, 2: "b"}
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: Dict = {1: 64, 2: "b"}
|
|
|
|
# annotation is parsed before the library can do anything, so the exception can only be TypeError
|
|
with self.assertRaises(TypeError):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: Dict[int] = {1: 64, 2: "b"}
|
|
|
|
# annotation is parsed before the library can do anything, so the exception can only be TypeError
|
|
with self.assertRaises(TypeError):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "Dict[int]" = {1: 64, 2: "b"}
|
|
|
|
def test_containers__tuple(self):
|
|
"""Testing first appliance level, and Field types (Tuple)"""
|
|
|
|
# class can be created with list
|
|
class Appliance1(dm.BaseAppliance):
|
|
testVar: Tuple[int, ...] = (1, 2)
|
|
testVar2: Tuple[str, ...] = ("a", "b")
|
|
testVar3: Tuple[float, ...] = (0.5, 0.456, 12)
|
|
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()
|
|
|
|
self.immutable_vars__test_field(app1, "testVar", (1, 2), (1, 5))
|
|
self.immutable_vars__test_field(app1, "testVar2", ("a", "b"), ("h", "c"))
|
|
self.immutable_vars__test_field(app1, "testVar3", (0.5, 0.456, 12), (0.9, 0.4156, 11))
|
|
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, "b"), (7, "h"))
|
|
|
|
# must work
|
|
sorted(app1.testVar)
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: Tuple[int] = "a"
|
|
|
|
with self.assertRaises(dm.InvalidFieldValue):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: "Tuple[int]" = "a"
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: Tuple = (1, 2)
|
|
|
|
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
|
|
|
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
|
|
|
|
def test_containers_field_inheritance(self):
|
|
"""Testing first appliance level, and Field types (annotated)"""
|
|
|
|
# class can be created
|
|
class Appliance1(dm.BaseAppliance):
|
|
ListStr: list[str] = ["val1", "val2"]
|
|
Dict1: dict[int, float] = {1: 1.1, 4: 7.6, 91: 23.6}
|
|
Tuple1: "tuple[str,...]" = ("a", "c")
|
|
FrozenSet1: frozenset[int] = frozenset({1, 2})
|
|
Set1: set[int] = set({1, 2})
|
|
|
|
# class can be created
|
|
class Appliance2(Appliance1):
|
|
ListStr = ["mod val1", "mod val2"]
|
|
Dict1 = {4: 1.1, 9: 7.6, 51: 23.6}
|
|
Tuple1 = ("aa", "cc")
|
|
FrozenSet1 = frozenset({14, 27})
|
|
Set1 = set({1, 20})
|
|
|
|
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, "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, "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, "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])
|
|
|
|
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, "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, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {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.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, "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, "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, "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])
|
|
|
|
# class can be created
|
|
class Appliance3(Appliance2):
|
|
ListStr2: list[str] = ["mod val3", "mod val3"]
|
|
Dict2: dict[int, float] = {9: 8.1, 5: 98.6, 551: 3.6}
|
|
Tuple2: "tuple[str,...]" = ("aaa", "ccc")
|
|
FrozenSet2: frozenset[int] = frozenset({114, 127})
|
|
Set2: set[int] = set({10, 250})
|
|
|
|
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, "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, "Tuple2", ("aaa", "ccc"), ("aaa", "ccc"))
|
|
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, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {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, "ListStr2", ("mod val3", "mod val3"), ("mod val3", "mod val3"), list[str])
|
|
self.check_immutable_fields_schema(app3, "Dict2", {9: 8.1, 5: 98.6, 551: 3.6}, {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, "FrozenSet2", frozenset({114, 127}), frozenset({114, 127}), frozenset[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, "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, "Dict1", {4: 1.1, 9: 7.6, 51: 23.6}, {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.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, "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, "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, "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])
|
|
|
|
def test_initializer(self):
|
|
"""Testing first appliance level, and Field types (simple)"""
|
|
|
|
# class can be created
|
|
class Appliance1(dm.BaseAppliance):
|
|
VarInt: int = 12
|
|
VarInt2: int = 21
|
|
list1: list[int] = [1]
|
|
set1: set[float] = {1.43}
|
|
set2: set[float] = {5.43}
|
|
VarStr1: str = "abcd"
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
|
|
cls.VarInt2 = cls.VarInt + 1
|
|
cls.list1.append(2)
|
|
cls.set2 = cls.set1 | {1234}
|
|
cls.set1 = {0}
|
|
cls.VarStr1 = cls.VarStr1.upper()
|
|
|
|
app1 = Appliance1()
|
|
|
|
self.assertEqual(app1.VarInt, 12)
|
|
self.assertEqual(app1.VarInt2, 13)
|
|
self.assertEqual(app1.set1, frozenset({0}))
|
|
self.assertEqual(app1.set2, frozenset((1.43, 1234)))
|
|
self.assertEqual(app1.VarStr1, "ABCD")
|
|
|
|
# class can be created
|
|
class _(dm.BaseAppliance):
|
|
VarInt: int = 41
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
|
|
cls.VarInt = cls.VarInt + 1
|
|
|
|
app2 = _()
|
|
self.assertEqual(app2.VarInt, 42)
|
|
|
|
def test_initializer_safe(self):
|
|
|
|
with self.assertRaises(dm.ImportForbidden):
|
|
|
|
class test(dm.BaseAppliance):
|
|
_: int = 0
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
import pprint
|
|
|
|
with self.assertRaises(NameError):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: int = 0
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
eval("2 ** 8")
|
|
|
|
with self.assertRaises(NameError):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: int = 0
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
open("foo")
|
|
|
|
with self.assertRaises(NameError):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: int = 0
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
exec("exit()")
|
|
|
|
with self.assertRaises(NameError):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: int = 0
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
compile("print(55)", "test", "eval")
|
|
|
|
with self.assertRaises(NameError):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: int = 0
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
compile("print(55)", "test", "eval")
|
|
|
|
with self.assertRaises(dm.FunctionForbidden):
|
|
|
|
def testfc():
|
|
eval("print('test')")
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: int = 0
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
testfc()
|
|
|
|
# class can be created
|
|
class Appliance2(dm.BaseAppliance):
|
|
VarInt: int = -56
|
|
VarInt2: int = 0
|
|
VarInt3: int = 0
|
|
VarInt4: int = 0
|
|
VarInt5: int = 0
|
|
VarFloat: float = 1.23
|
|
list1: list[int] = [1, 2, 0, 4]
|
|
list2: Optional[list[int]] = None
|
|
list3: Optional[list[int]] = None
|
|
set1: set[float] = {1.43}
|
|
set2: set[float] = {5.43}
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
cls.VarInt2 = abs(cls.VarInt)
|
|
cls.VarFloat = round(cls.VarFloat)
|
|
cls.VarInt = min(cls.list1)
|
|
cls.VarInt3 = max(cls.list1)
|
|
cls.VarInt4 = sum(cls.list1)
|
|
cls.VarInt5 = len(cls.list1)
|
|
cls.list2 = sorted(cls.list1)
|
|
cls.list3 = []
|
|
for i in range(5):
|
|
cls.list3.append(i)
|
|
cls.set2 = {math.ceil(list(cls.set1)[0])}
|
|
|
|
app2 = Appliance2()
|
|
self.assertEqual(app2.VarInt2, 56)
|
|
self.assertEqual(app2.VarFloat, 1)
|
|
self.assertEqual(app2.VarInt, 0)
|
|
self.assertEqual(app2.VarInt3, 4)
|
|
self.assertEqual(app2.VarInt4, 7)
|
|
self.assertEqual(app2.VarInt5, 4)
|
|
self.assertEqual(app2.list2, (0, 1, 2, 4))
|
|
self.assertEqual(app2.list3, (0, 1, 2, 3, 4))
|
|
self.assertEqual(app2.set2, {2})
|
|
|
|
with self.assertRaises(NameError):
|
|
|
|
class _(dm.BaseAppliance):
|
|
_: int = 0
|
|
|
|
@classmethod
|
|
def __initializer(cls):
|
|
test_initializer_safe_testfc()
|
|
|
|
|
|
# ---------- main ----------
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|