work
This commit is contained in:
@@ -30,4 +30,5 @@ from .model import (
|
||||
FunctionForbidden,
|
||||
FrozenDABField,
|
||||
InvalidFeatureInheritance,
|
||||
FeatureNotBound,
|
||||
)
|
||||
|
||||
@@ -21,7 +21,7 @@ from typing import (
|
||||
Callable,
|
||||
Type,
|
||||
)
|
||||
from types import UnionType, FunctionType, SimpleNamespace
|
||||
from types import UnionType, FunctionType, SimpleNamespace, MethodType
|
||||
from copy import deepcopy, copy
|
||||
|
||||
# from pprint import pprint
|
||||
@@ -151,6 +151,10 @@ class FunctionForbidden(DABModelException):
|
||||
function call are forbidden
|
||||
"""
|
||||
|
||||
class FeatureNotBound(DABModelException):
|
||||
"""FeatureNotBound Exception class
|
||||
a Feature must be bound to an Appliance
|
||||
"""
|
||||
|
||||
ALLOWED_HELPERS_MATH = SimpleNamespace(
|
||||
sqrt=math.sqrt,
|
||||
@@ -516,10 +520,12 @@ class BaseMeta(type):
|
||||
initializer_name = "__initializer"
|
||||
else:
|
||||
initializer_name = f"_{name}__initializer"
|
||||
elif _fname.startswith("__"):
|
||||
elif _fname.startswith("_"):
|
||||
pass
|
||||
elif isinstance(_fvalue, classmethod):
|
||||
pass
|
||||
else:
|
||||
# print(f"Parsing Field: {_fname} / {_fvalue}")
|
||||
print(f"Parsing Field: {_fname} / {_fvalue}")
|
||||
if len(bases) == 1 and _fname in namespace["__DABSchema__"].keys(): # Modified fields
|
||||
mcs.pre_processing_modified_fields(name, bases, namespace, _fname, _fvalue, extensions)
|
||||
else: # New fieds
|
||||
@@ -705,14 +711,25 @@ class BaseElement(metaclass=BaseMeta):
|
||||
"""
|
||||
|
||||
class BaseMetaFeature(BaseMeta):
|
||||
pass
|
||||
def __call__(cls: Type, *args: Any, **kw: Any): # intentionally untyped
|
||||
"""BaseFeature new instance"""
|
||||
|
||||
if cls._BoundAppliance is None:
|
||||
raise FeatureNotBound()
|
||||
|
||||
obj = super().__call__(*args, **kw)
|
||||
|
||||
|
||||
return obj
|
||||
|
||||
class BaseFeature(BaseElement,metaclass=BaseMetaFeature):
|
||||
"""BaseFeature class
|
||||
Base class for Appliance's Features.
|
||||
Features are optional traits of an appliance.
|
||||
"""
|
||||
_BoundAppliance:"Optional[Type[BaseAppliance]]" = None
|
||||
Enabled:bool=False
|
||||
|
||||
|
||||
class BaseMetaAppliance(BaseMeta):
|
||||
|
||||
@@ -761,11 +778,13 @@ class BaseMetaAppliance(BaseMeta):
|
||||
super().save_values(cls,name,bases,namespace,extensions)
|
||||
|
||||
for _ftname,_ftvalue in extensions["modified_features"].items():
|
||||
_ftvalue._BoundAppliance = cls
|
||||
cls.__DABSchema__["features"][_ftname] = _ftvalue
|
||||
for _ftname,_ftvalue in extensions["new_features"].items():
|
||||
_ftvalue._BoundAppliance = cls
|
||||
cls.__DABSchema__["features"][_ftname] = _ftvalue
|
||||
|
||||
def modify_object(cls:Type, obj,extensions : dict[str,Any]): # intentionally untyped
|
||||
def modify_object(cls:Type, obj, extensions : dict[str,Any]): # intentionally untyped
|
||||
for _ftname,_ftvalue in cls.__DABSchema__["features"].items():
|
||||
instft = _ftvalue()
|
||||
object.__setattr__(obj, _ftname,instft )
|
||||
|
||||
@@ -16,6 +16,7 @@ import textwrap
|
||||
from typing import List, Optional, Dict, Union, Tuple, Set, FrozenSet, TypeVar, Generic, Any, Annotated
|
||||
from pprint import pprint
|
||||
from frozendict import frozendict
|
||||
import math
|
||||
|
||||
print(__name__)
|
||||
print(__package__)
|
||||
@@ -84,32 +85,32 @@ class MainTests(unittest.TestCase):
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: str = 12
|
||||
test: str = 12
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: int = "value"
|
||||
test: int = "value"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: float = "value"
|
||||
test: float = "value"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: complex = "value"
|
||||
test: complex = "value"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: bool = "value"
|
||||
test: bool = "value"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: bytes = "value"
|
||||
test: bytes = "value"
|
||||
|
||||
def test_annotation(self):
|
||||
"""Testing first appliance level, and Field types (simple annotations)"""
|
||||
@@ -147,38 +148,38 @@ class MainTests(unittest.TestCase):
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "str" = 12
|
||||
test: "str" = 12
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "int" = "value"
|
||||
test: "int" = "value"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "float" = "value"
|
||||
test: "float" = "value"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "complex" = "value"
|
||||
test: "complex" = "value"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "bool" = "value"
|
||||
test: "bool" = "value"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "bytes" = "value"
|
||||
test: "bytes" = "value"
|
||||
|
||||
# class cannot be created if not annotated field
|
||||
with self.assertRaises(dm.NotAnnotatedField):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_ = "default value"
|
||||
test = "default value"
|
||||
|
||||
def test_optionnal(self):
|
||||
"""Testing first appliance level, and Field types (Optionnal annotations)"""
|
||||
@@ -415,22 +416,22 @@ class MainTests(unittest.TestCase):
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: List[int] = ["a"]
|
||||
test: List[int] = ["a"]
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "List[int]" = ["a"]
|
||||
test: "List[int]" = ["a"]
|
||||
|
||||
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: List = [1, 2]
|
||||
test: List = [1, 2]
|
||||
|
||||
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "List" = [1, 2]
|
||||
test: "List" = [1, 2]
|
||||
|
||||
def test_containers__dict(self):
|
||||
"""Testing first appliance level, and Field types (Dict)"""
|
||||
@@ -455,29 +456,29 @@ class MainTests(unittest.TestCase):
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: Dict[int, str] = {1: 64, 2: "b"}
|
||||
test: Dict[int, str] = {1: 64, 2: "b"}
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "Dict[int, str]" = {1: 64, 2: "b"}
|
||||
test: "Dict[int, str]" = {1: 64, 2: "b"}
|
||||
|
||||
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: Dict = {1: 64, 2: "b"}
|
||||
test: 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"}
|
||||
test: 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"}
|
||||
test: "Dict[int]" = {1: 64, 2: "b"}
|
||||
|
||||
def test_containers__tuple(self):
|
||||
"""Testing first appliance level, and Field types (Tuple)"""
|
||||
@@ -509,32 +510,32 @@ class MainTests(unittest.TestCase):
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: Tuple[int] = "a"
|
||||
test: Tuple[int] = "a"
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "Tuple[int]" = "a"
|
||||
test: "Tuple[int]" = "a"
|
||||
|
||||
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: Tuple = (1, 2)
|
||||
test: Tuple = (1, 2)
|
||||
|
||||
with self.assertRaises(dm.IncompletelyAnnotatedField):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "Tuple" = (1, 2)
|
||||
test: "Tuple" = (1, 2)
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "Tuple[int,...]" = (1, "a")
|
||||
test: "Tuple[int,...]" = (1, "a")
|
||||
|
||||
with self.assertRaises(dm.InvalidFieldValue):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: "tuple[int,...]" = (1, "a")
|
||||
test: "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
|
||||
@@ -701,13 +702,13 @@ class MainTests(unittest.TestCase):
|
||||
with self.assertRaises(dm.InvalidFieldAnnotation):
|
||||
|
||||
class _(dm.BaseAppliance):
|
||||
_: Annotated[str, "foo2"] = "default value2"
|
||||
test: 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"
|
||||
test: Annotated[str] = "default value2"
|
||||
|
||||
def test_immutable_fields_inheritance(self):
|
||||
"""Testing first appliance level, and Field types (simple)"""
|
||||
@@ -1177,9 +1178,7 @@ class MainTests(unittest.TestCase):
|
||||
|
||||
def test_feature(self):
|
||||
"""Testing first appliance feature, and Field types (simple)"""
|
||||
|
||||
|
||||
|
||||
|
||||
# class can be created
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
VarStrOuter: str = "testvalue APPLIANCE"
|
||||
@@ -1198,8 +1197,6 @@ class MainTests(unittest.TestCase):
|
||||
|
||||
def test_feature_inheritance(self):
|
||||
"""Testing first appliance feature, and Field types (simple)"""
|
||||
|
||||
|
||||
|
||||
# class can be created
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
@@ -1322,7 +1319,6 @@ class MainTests(unittest.TestCase):
|
||||
class Appliance4(Appliance3):
|
||||
VarStr = "testvalue moded"
|
||||
|
||||
|
||||
app4 = Appliance4()
|
||||
|
||||
self.assertEqual(app1.VarStr,"testvalue1")
|
||||
@@ -1333,10 +1329,31 @@ class MainTests(unittest.TestCase):
|
||||
app1b = Appliance1()
|
||||
app2b = Appliance2()
|
||||
app3b = Appliance3()
|
||||
|
||||
self.assertEqual(app1b.VarStr,"testvalue1")
|
||||
self.assertEqual(app2b.VarStr,"testvalue1")
|
||||
self.assertEqual(app3b.VarStr,"testvalue1")
|
||||
|
||||
def test_feature_register(self):
|
||||
"""Testing first appliance feature, and Field types (simple)"""
|
||||
|
||||
# class can be created
|
||||
class Appliance1(dm.BaseAppliance):
|
||||
pass
|
||||
|
||||
class Feature1(dm.BaseFeature):
|
||||
_BoundAppliance = Appliance1
|
||||
VarStrInner: str = "testvalue FEATURE1"
|
||||
|
||||
print(dir(Feature1))
|
||||
|
||||
def test_feature_register_defect(self):
|
||||
|
||||
class Feature1(dm.BaseFeature):
|
||||
pass
|
||||
with self.assertRaises(dm.FeatureNotBound):
|
||||
feat1 = Feature1()
|
||||
|
||||
# ---------- main ----------
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user