eptm_dashboard/.venv/lib/python3.12/site-packages/reflex_base/components/field.py

183 lines
5.8 KiB
Python

"""Shared field infrastructure for components and props."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import _MISSING_TYPE, MISSING
from typing import Annotated, Any, Generic, TypeVar, get_origin
from reflex_base.utils import types
from reflex_base.utils.compat import annotations_from_namespace
FIELD_TYPE = TypeVar("FIELD_TYPE")
class BaseField(Generic[FIELD_TYPE]):
"""Base field class used by internal metadata classes."""
def __init__(
self,
default: FIELD_TYPE | _MISSING_TYPE = MISSING,
default_factory: Callable[[], FIELD_TYPE] | None = None,
annotated_type: type[Any] | _MISSING_TYPE = MISSING,
) -> None:
"""Initialize the field.
Args:
default: The default value for the field.
default_factory: The default factory for the field.
annotated_type: The annotated type for the field.
"""
self.default = default
self.default_factory = default_factory
self.outer_type_ = self.annotated_type = annotated_type
# Process type annotation
type_origin = get_origin(annotated_type) or annotated_type
if type_origin is Annotated:
type_origin = annotated_type.__origin__ # pyright: ignore [reportAttributeAccessIssue]
# For Annotated types, use the actual type inside the annotation
self.type_ = annotated_type
else:
# For other types (including Union), preserve the original type
self.type_ = annotated_type
self.type_origin = type_origin
def default_value(self) -> FIELD_TYPE:
"""Get the default value for the field.
Returns:
The default value for the field.
Raises:
ValueError: If no default value or factory is provided.
"""
if self.default is not MISSING:
return self.default
if self.default_factory is not None:
return self.default_factory()
msg = "No default value or factory provided."
raise ValueError(msg)
class FieldBasedMeta(type):
"""Shared metaclass for field-based classes like components and props.
Provides common field inheritance and processing logic for both
PropsBaseMeta and BaseComponentMeta.
"""
def __new__(
cls, name: str, bases: tuple[type, ...], namespace: dict[str, Any]
) -> type:
"""Create a new field-based class.
Args:
name: The name of the class.
bases: The base classes.
namespace: The class namespace.
Returns:
The new class.
"""
# Collect inherited fields from base classes
inherited_fields = cls._collect_inherited_fields(bases)
# Get annotations from the namespace
annotations = cls._resolve_annotations(namespace, name)
# Process field overrides (fields with values but no annotations)
own_fields = cls._process_field_overrides(
namespace, annotations, inherited_fields
)
# Process annotated fields
own_fields.update(
cls._process_annotated_fields(namespace, annotations, inherited_fields)
)
# Finalize fields and store on class
cls._finalize_fields(namespace, inherited_fields, own_fields)
return super().__new__(cls, name, bases, namespace)
@classmethod
def _collect_inherited_fields(cls, bases: tuple[type, ...]) -> dict[str, Any]:
inherited_fields: dict[str, Any] = {}
# Collect inherited fields from base classes
for base in bases[::-1]:
if hasattr(base, "_inherited_fields"):
inherited_fields.update(base._inherited_fields)
for base in bases[::-1]:
if hasattr(base, "_own_fields"):
inherited_fields.update(base._own_fields)
return inherited_fields
@classmethod
def _resolve_annotations(
cls, namespace: dict[str, Any], name: str
) -> dict[str, Any]:
return types.resolve_annotations(
annotations_from_namespace(namespace),
namespace["__module__"],
)
@classmethod
def _process_field_overrides(
cls,
namespace: dict[str, Any],
annotations: dict[str, Any],
inherited_fields: dict[str, Any],
) -> dict[str, Any]:
own_fields: dict[str, Any] = {}
for key, value in namespace.items():
if key not in annotations and key in inherited_fields:
inherited_field = inherited_fields[key]
new_field = cls._create_field(
annotated_type=inherited_field.annotated_type,
default=value,
default_factory=None,
)
own_fields[key] = new_field
return own_fields
@classmethod
def _process_annotated_fields(
cls,
namespace: dict[str, Any],
annotations: dict[str, Any],
inherited_fields: dict[str, Any],
) -> dict[str, Any]:
raise NotImplementedError
@classmethod
def _create_field(
cls,
annotated_type: Any,
default: Any = MISSING,
default_factory: Callable[[], Any] | None = None,
) -> Any:
raise NotImplementedError
@classmethod
def _finalize_fields(
cls,
namespace: dict[str, Any],
inherited_fields: dict[str, Any],
own_fields: dict[str, Any],
) -> None:
# Combine all fields
all_fields = inherited_fields | own_fields
# Set field names for compatibility
for field_name, field in all_fields.items():
field._name = field_name
# Store field mappings on the class
namespace["_own_fields"] = own_fields
namespace["_inherited_fields"] = inherited_fields
namespace["_fields"] = all_fields