This commit is contained in:
chacha
2025-09-18 00:32:32 +02:00
parent f6e581381d
commit 3e0defc574
3 changed files with 78 additions and 41 deletions

View File

@@ -30,4 +30,5 @@ from .model import (
FunctionForbidden,
FrozenDABField,
InvalidFeatureInheritance,
FeatureNotBound,
)

View File

@@ -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 )

View File

@@ -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__":