diff --git a/src/dabmodel/model.py b/src/dabmodel/model.py index ffc32ae..87ddc32 100644 --- a/src/dabmodel/model.py +++ b/src/dabmodel/model.py @@ -55,13 +55,12 @@ def DABField(default: Any = PydanticUndefined, *, final: bool | None = _Unset, f T_BaseElement = TypeVar("T_BaseElement", bound="BaseElement") T_BaseElement_ConfigMethod_Arg: TypeAlias = dict[str, Any] T_BaseElement_ConfigMethod: TypeAlias = "classmethod[T_BaseElement, [T_BaseElement_ConfigMethod_Arg], T_BaseElement_ConfigMethod_Arg]" -T_BaseElement_ConfigMethod_OrderedSet: TypeAlias = dict[T_BaseElement_ConfigMethod, None] class ConfigElement: def __init__(self) -> None: - self.default_values_override_methods: T_BaseElement_ConfigMethod_OrderedSet = {} - self.main_build_method: T_BaseElement_ConfigMethod_OrderedSet = {} + self.default_values_override_methods: dict[T_BaseElement_ConfigMethod, None] = {} + self.main_build_method: dict[T_BaseElement_ConfigMethod, None] = {} def __copy__(self) -> Self: # we cannot deepcopy because of classmethods, so we do a manual enhanced copy @@ -131,6 +130,7 @@ class BaseElement( validate_assignment=True, # revalidate_instances="subclass-instances", # pydantic issue #10681 validate_default=True, + extra="forbid", metaclass=BaseElementMeta, ): class Config: @@ -154,12 +154,19 @@ class BaseElement( assert not runtype_issubclass( field_val.annotation, BaseFeature ), "Features can only be in Appliance's features[] dict attribute" + """ + if field_key == "features": + cls._saved_default_value[field_key] = dict() + for feat_key, feat_value in field_val.items(): + cls._saved_default_value[field_key][feat_key] = feat_value.dict() + """ if field_val.default != PydanticUndefined: cls._saved_default_value[field_key] = deepcopy(field_val.default) for method, _ in cls._config_element.default_values_override_methods.items(): method.__func__(cls, cls._saved_default_value) cls._default_values_override_hook__input_apply__(values) + return cls._saved_default_value @classmethod @@ -177,10 +184,12 @@ class BaseFeature(BaseElement, ABC): cls, values: T_BaseElement_ConfigMethod_Arg, ): + print(f"BaseFeature._default_values_override_hook__input_apply__ {cls}") # applying user-defined values for attr_key, attr_val in values.items(): assert attr_key in cls.model_fields, f"given feature attribute does not exist ({attr_key})" cls._saved_default_value[attr_key] = attr_val + print(f"BaseFeature._default_values_override_hook__input_apply__ {cls} DONE") def default_values_override(func: T_BaseElement_ConfigMethod) -> T_BaseElement_ConfigMethod: @@ -219,7 +228,7 @@ class BaseAppliance(Generic[T_Feature], BaseElement, ABC): @NoInstanceMethod @classmethod def add_feature(cls, feat: T_Feature): - cls._saved_default_value["features"][type(feat).__name__] = feat + cls._saved_default_value["features"][type(feat).__name__] = feat.dict() @NoInstanceMethod @classmethod @@ -237,12 +246,14 @@ class BaseAppliance(Generic[T_Feature], BaseElement, ABC): cls, values: T_BaseElement_ConfigMethod_Arg, ): + print(f"BaseAppliance._default_values_override_hook__input_apply__ {cls}") # applying user-defined values for attr_key, attr_val in values.items(): if attr_key == "features": if cls._saved_default_value["features"] is None: cls._saved_default_value["features"] = {} for feature_key, feature_val in attr_val.items(): + print(f"searching feature: {feature_key}") assert hasattr(cls, feature_key), f"feature not found ({feature_key})" cls_feature = getattr(cls, feature_key) assert ( @@ -253,3 +264,4 @@ class BaseAppliance(Generic[T_Feature], BaseElement, ABC): else: assert attr_key in cls.model_fields, f"given attribute does not exist ({attr_key})" cls._saved_default_value[attr_key] = attr_val + print(f"BaseAppliance._default_values_override_hook__input_apply__ {cls} DONE") diff --git a/test/test_model.py b/test/test_model.py index 26aa631..74ae1ed 100644 --- a/test/test_model.py +++ b/test/test_model.py @@ -85,6 +85,7 @@ class MyAppliance2(MyAppliance): values["template_long_name"] = "My appliance template 2 !!" values["template_description"] = """A very nice Appliance 2""" cls.del_feature(MyAppliance.MyFeature) + # values["features"]["MyFeature2"].template_description = """Override feature desc""" class MyAppliance3(dabmodel.BaseAppliance): @@ -135,8 +136,9 @@ class MyAppliance3(dabmodel.BaseAppliance): class MyAppliance4(MyAppliance): class MyFeature8(dabmodel.BaseFeature): - # testtt: Annotated[MyAppliance.MyFeature, Field(MyAppliance.MyFeature())] # error case - test_integer_10: Annotated[int, dabmodel.DABField(3189, ge=0)] + # testtt: Annotated[MyAppliance.MyFeature, Field(MyAppliance.MyFeature())] # error case (nested feature) + # test_integer_10: Annotated[int, dabmodel.DABField(3189, ge=0, toto="tata")] # error case (extra field) + test_integer_10: Annotated[int, dabmodel.DABField(3189, ge=0, toto="tata")] @dabmodel.default_values_override @classmethod @@ -146,9 +148,10 @@ class MyAppliance4(MyAppliance): values["template_short_name"] = "my-feature-8" values["template_long_name"] = "My appliance template 8 !!" values["template_description"] = """A very nice Appliance 8""" - values["test_integer_2"] = 951753 + values["test_integer_10"] = 951753 + # values["tete"] = 1 # error case (extra field in feature) - # testtt: Annotated[MyAppliance.MyFeature, Field(MyAppliance.MyFeature())] # error case + # testtt: Annotated[MyAppliance.MyFeature, Field(MyAppliance.MyFeature())] # error case (feature not in features[] list) @dabmodel.default_values_override @classmethod