Skip to content

Commit 88155a7

Browse files
cache get_type_hints for heavy init subclass stuff - improve import performance (#6118)
* fix: cache get_type_hints for heavy init subclass stuff to improve import performance * fix: prefer tuple and improve mixin typing
1 parent 480d93b commit 88155a7

2 files changed

Lines changed: 13 additions & 14 deletions

File tree

reflex/state.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ def _get_computed_vars(cls) -> list[tuple[str, ComputedVar]]:
487487
"""
488488
return [
489489
(name, v)
490-
for mixin in [*cls._mixins(), cls]
490+
for mixin in (*cls._mixins(), cls)
491491
for name, v in mixin.__dict__.items()
492492
if is_computed_var(v) and name not in cls.inherited_vars
493493
]
@@ -569,14 +569,14 @@ def __init_subclass__(cls, mixin: bool = False, **kwargs):
569569

570570
new_backend_vars = {
571571
name: value if not isinstance(value, Field) else value.default_value()
572-
for mixin_cls in [*cls._mixins(), cls]
572+
for mixin_cls in (*cls._mixins(), cls)
573573
for name, value in list(mixin_cls.__dict__.items())
574574
if types.is_backend_base_variable(name, mixin_cls)
575575
}
576576
# Add annotated backend vars that may not have a default value.
577577
new_backend_vars.update({
578578
name: cls._get_var_default(name, annotation_value)
579-
for mixin_cls in [*cls._mixins(), cls]
579+
for mixin_cls in (*cls._mixins(), cls)
580580
for name, annotation_value in mixin_cls._get_type_hints().items()
581581
if name not in new_backend_vars
582582
and types.is_backend_base_variable(name, mixin_cls)
@@ -764,21 +764,21 @@ def computed_var_func(state: Self):
764764
return getattr(cls, unique_var_name)
765765

766766
@classmethod
767-
def _mixins(cls) -> list[type]:
767+
def _mixins(cls) -> tuple[type[BaseState], ...]:
768768
"""Get the mixin classes of the state.
769769
770770
Returns:
771771
The mixin classes of the state.
772772
"""
773-
return [
773+
return tuple(
774774
mixin
775775
for mixin in cls.__mro__
776776
if (
777777
mixin is not cls
778778
and issubclass(mixin, BaseState)
779779
and mixin._mixin is True
780780
)
781-
]
781+
)
782782

783783
@classmethod
784784
def _handle_local_def(cls):
@@ -796,6 +796,7 @@ def _handle_local_def(cls):
796796
cls.__module__ = reflex.istate.dynamic.__name__
797797

798798
@classmethod
799+
@functools.cache
799800
def _get_type_hints(cls) -> dict[str, Any]:
800801
"""Get the type hints for this class.
801802
@@ -898,8 +899,9 @@ def _check_overridden_basevars(cls):
898899
Raises:
899900
ComputedVarShadowsBaseVarsError: When a computed var shadows a base var.
900901
"""
902+
hints = cls._get_type_hints()
901903
for name, computed_var_ in cls._get_computed_vars():
902-
if name in get_type_hints(cls):
904+
if name in hints:
903905
msg = f"The computed var name `{computed_var_._js_expr}` shadows a base var in {cls.__module__}.{cls.__name__}; use a different name instead"
904906
raise ComputedVarShadowsBaseVarsError(msg)
905907

reflex/utils/types.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
StateVarTypes = (*PrimitiveTypes, Base, type(None))
5858

5959
if TYPE_CHECKING:
60+
from reflex.state import BaseState
6061
from reflex.vars.base import Var
6162

6263
VAR1 = TypeVar("VAR1", bound="Var")
@@ -902,12 +903,12 @@ def is_valid_var_type(type_: type) -> bool:
902903
)
903904

904905

905-
def is_backend_base_variable(name: str, cls: type) -> bool:
906+
def is_backend_base_variable(name: str, cls: type[BaseState]) -> bool:
906907
"""Check if this variable name correspond to a backend variable.
907908
908909
Args:
909910
name: The name of the variable to check
910-
cls: The class of the variable to check
911+
cls: The class of the variable to check (must be a BaseState subclass)
911912
912913
Returns:
913914
bool: The result of the check
@@ -924,11 +925,7 @@ def is_backend_base_variable(name: str, cls: type) -> bool:
924925
if name.startswith(f"_{cls.__name__}__"):
925926
return False
926927

927-
# Extract the namespace of the original module if defined (dynamic substates).
928-
if callable(getattr(cls, "_get_type_hints", None)):
929-
hints = cls._get_type_hints()
930-
else:
931-
hints = get_type_hints(cls)
928+
hints = cls._get_type_hints()
932929
if name in hints:
933930
hint = get_origin(hints[name])
934931
if hint == ClassVar:

0 commit comments

Comments
 (0)