fix init_subclass for pydantic v2, add some missing type hints, format black

This commit is contained in:
Benedikt Bartscher 2024-03-01 14:55:34 +01:00
parent 80f02753ba
commit 37c360e786
No known key found for this signature in database
6 changed files with 39 additions and 18 deletions

View File

@ -283,7 +283,11 @@ class Component(BaseComponent, ABC):
continue
# unwrap Optional from field_type
field_type = typing.get_args(field_type)[0] if types.is_optional(field_type) else field_type
field_type = (
typing.get_args(field_type)[0]
if types.is_optional(field_type)
else field_type
)
# Check whether the key is a component prop.
if types._issubclass(field_type, Var):

View File

@ -100,13 +100,9 @@ class RadixThemesComponent(Component):
"""
component = super().create(*children, **props)
if component.library is None:
<<<<<<< HEAD
component.library = RadixThemesComponent.model_fields["library"].default
=======
component.library = RadixThemesComponent.model_fields[
"library"
].default
>>>>>>> f7035d9b (optionalize some Component props)
component.alias = "RadixThemes" + (
component.tag or component.__class__.__name__
)

View File

@ -113,7 +113,9 @@ class DropdownMenuContent(RadixThemesComponent):
avoid_collisions: Optional[Var[bool]] = None
# The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { "top": 20, "left": 20 }. Defaults to 0.
collision_padding: Optional[Var[Union[float, int, Dict[str, Union[float, int]]]]] = None
collision_padding: Optional[
Var[Union[float, int, Dict[str, Union[float, int]]]]
] = None
# The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. Defaults to 0.
arrow_padding: Optional[Var[Union[float, int]]] = None
@ -204,7 +206,9 @@ class DropdownMenuSubContent(RadixThemesComponent):
avoid_collisions: Optional[Var[bool]] = None
# The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { "top": 20, "left": 20 }. Defaults to 0.
collision_padding: Optional[Var[Union[float, int, Dict[str, Union[float, int]]]]] = None
collision_padding: Optional[
Var[Union[float, int, Dict[str, Union[float, int]]]]
] = None
# The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. Defaults to 0.
arrow_padding: Optional[Var[Union[float, int]]] = None

View File

@ -60,7 +60,9 @@ class Tooltip(RadixThemesComponent):
avoid_collisions: Optional[Var[bool]] = None
# The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { "top": 20, "left": 20 }. Defaults to 0.
collision_padding: Optional[Var[Union[float, int, Dict[str, Union[float, int]]]]] = None
collision_padding: Optional[
Var[Union[float, int, Dict[str, Union[float, int]]]]
] = None
# The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. Defaults to 0.
arrow_padding: Optional[Var[Union[float, int]]] = None

View File

@ -195,7 +195,7 @@ def _split_substate_key(substate_key: str) -> tuple[str, str]:
return token, state_name
class BaseState(Base, ABC, extra=pydantic.Extra.allow):
class BaseState(Base, ABC, extra="allow"):
"""The state of the app."""
# A map from the var name to the var.
@ -288,7 +288,11 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
kwargs["parent_state"] = parent_state
for prop_name, prop in self.base_vars.items():
if prop_name not in kwargs and self.model_fields[prop_name].is_required():
if (
prop_name not in kwargs
and prop_name in self.model_fields
and self.model_fields[prop_name].is_required()
):
kwargs[prop_name] = prop.get_default_value()
super().__init__(*args, **kwargs)
@ -362,7 +366,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
]
@classmethod
def __init_subclass__(cls, **kwargs):
def __pydantic_init_subclass__(cls, **kwargs: Any) -> None:
"""Do some magic for the subclass initialization.
Args:
@ -371,7 +375,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
Raises:
ValueError: If a substate class shadows another.
"""
super().__init_subclass__(**kwargs)
# super().__init_subclass__(**kwargs)
# Event handlers should not shadow builtin state methods.
cls._check_overridden_methods()
@ -486,6 +490,12 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
cls.event_handlers[name] = handler
setattr(cls, name, handler)
# Inherited vars are handled in __getattribute__, not by pydantic
for prop in cls.model_fields.copy():
if prop in cls.inherited_vars or prop in cls.inherited_backend_vars:
del cls.model_fields[prop]
cls.model_rebuild(force=True)
cls._init_var_dependency_dicts()
@staticmethod
@ -994,9 +1004,6 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
# If the state hasn't been initialized yet, return the default value.
if not super().__getattribute__("__dict__"):
return super().__getattribute__(name)
private_attrs = super().__getattribute__("__pydantic_private__")
if private_attrs is None:
return super().__getattribute__(name)
inherited_vars = {
**super().__getattribute__("inherited_vars"),
@ -1009,6 +1016,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
if parent_state is not None:
return getattr(parent_state, name)
private_attrs = super().__getattribute__("__pydantic_private__")
if private_attrs is None:
return super().__getattribute__(name)
backend_vars = private_attrs["_backend_vars"]
if name in backend_vars:
value = backend_vars[name]
@ -1088,7 +1098,9 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
# on the browser also resets the values on the backend.
fields = self.get_fields()
for prop_name in self.base_vars:
field = fields[prop_name]
if not (field := fields.get(prop_name)):
# inherited values are reset in the parent state
continue
if isinstance(field.default, ClientStorageBase) or (
isinstance(field.annotation, type)
and issubclass(field.annotation, ClientStorageBase)

View File

@ -37,7 +37,7 @@ class DictMutationTestState(BaseState):
self.details.pop("age")
# dict in list
address: List[Dict[str,str]] = [{"home": "home address"}, {"work": "work address"}]
address: List[Dict[str, str]] = [{"home": "home address"}, {"work": "work address"}]
def remove_home_address(self):
"""Remove the home address from dict in the list."""
@ -48,7 +48,10 @@ class DictMutationTestState(BaseState):
self.address[0]["street"] = "street address"
# nested dict
friend_in_nested_dict: Dict[str, Union[str, Dict[str,str]]] = {"name": "Nikhil", "friend": {"name": "Alek"}}
friend_in_nested_dict: Dict[str, Union[str, Dict[str, str]]] = {
"name": "Nikhil",
"friend": {"name": "Alek"},
}
def change_friend_name(self):
"""Change the friend's name in the nested dict."""