ImmutableVar perf optimizations (#3814)

* Use lru_cache on expensive typing-related functions

* Skip instantiation of VarData unless data was actually merged

* Revert "integration: bump listening timeout to 1800 seconds"

This reverts commit a94eedff6d.

* Revert "integration: bump listening timeout to 1200 seconds"

This reverts commit 86563b66a4.
This commit is contained in:
Masen Furer 2024-08-28 10:02:16 -07:00 committed by GitHub
parent 3fa9f1fc06
commit 8f396fc348
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 33 additions and 20 deletions

View File

@ -32,7 +32,7 @@ from typing import (
overload, overload,
) )
from typing_extensions import ParamSpec, get_origin, get_type_hints, override from typing_extensions import ParamSpec, get_type_hints, override
from reflex import constants from reflex import constants
from reflex.base import Base from reflex.base import Base
@ -40,6 +40,7 @@ from reflex.constants.colors import Color
from reflex.utils import console, imports, serializers, types from reflex.utils import console, imports, serializers, types
from reflex.utils.exceptions import VarDependencyError, VarTypeError, VarValueError from reflex.utils.exceptions import VarDependencyError, VarTypeError, VarValueError
from reflex.utils.format import format_state_name from reflex.utils.format import format_state_name
from reflex.utils.types import get_origin
from reflex.vars import ( from reflex.vars import (
ComputedVar, ComputedVar,
ImmutableVarData, ImmutableVarData,

View File

@ -19,11 +19,9 @@ from typing import (
overload, overload,
) )
from typing_extensions import get_origin
from reflex.utils import types from reflex.utils import types
from reflex.utils.exceptions import VarAttributeError from reflex.utils.exceptions import VarAttributeError
from reflex.utils.types import GenericType, get_attribute_access_type from reflex.utils.types import GenericType, get_attribute_access_type, get_origin
from reflex.vars import ImmutableVarData, Var, VarData from reflex.vars import ImmutableVarData, Var, VarData
from .base import ( from .base import (

View File

@ -22,11 +22,9 @@ from typing import (
overload, overload,
) )
from typing_extensions import get_origin
from reflex import constants from reflex import constants
from reflex.constants.base import REFLEX_VAR_OPENING_TAG from reflex.constants.base import REFLEX_VAR_OPENING_TAG
from reflex.utils.types import GenericType from reflex.utils.types import GenericType, get_origin
from reflex.vars import ( from reflex.vars import (
ImmutableVarData, ImmutableVarData,
Var, Var,

View File

@ -6,7 +6,7 @@ import contextlib
import inspect import inspect
import sys import sys
import types import types
from functools import cached_property, wraps from functools import cached_property, lru_cache, wraps
from typing import ( from typing import (
Any, Any,
Callable, Callable,
@ -21,9 +21,11 @@ from typing import (
Union, Union,
_GenericAlias, # type: ignore _GenericAlias, # type: ignore
get_args, get_args,
get_origin,
get_type_hints, get_type_hints,
) )
from typing import (
get_origin as get_origin_og,
)
import sqlalchemy import sqlalchemy
@ -133,6 +135,20 @@ class Unset:
return False return False
@lru_cache()
def get_origin(tp):
"""Get the origin of a class.
Args:
tp: The class to get the origin of.
Returns:
The origin of the class.
"""
return get_origin_og(tp)
@lru_cache()
def is_generic_alias(cls: GenericType) -> bool: def is_generic_alias(cls: GenericType) -> bool:
"""Check whether the class is a generic alias. """Check whether the class is a generic alias.
@ -157,6 +173,7 @@ def is_none(cls: GenericType) -> bool:
return cls is type(None) or cls is None return cls is type(None) or cls is None
@lru_cache()
def is_union(cls: GenericType) -> bool: def is_union(cls: GenericType) -> bool:
"""Check if a class is a Union. """Check if a class is a Union.
@ -169,6 +186,7 @@ def is_union(cls: GenericType) -> bool:
return get_origin(cls) in UnionTypes return get_origin(cls) in UnionTypes
@lru_cache()
def is_literal(cls: GenericType) -> bool: def is_literal(cls: GenericType) -> bool:
"""Check if a class is a Literal. """Check if a class is a Literal.
@ -314,6 +332,7 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
return None # Attribute is not accessible. return None # Attribute is not accessible.
@lru_cache()
def get_base_class(cls: GenericType) -> Type: def get_base_class(cls: GenericType) -> Type:
"""Get the base class of a class. """Get the base class of a class.

View File

@ -29,7 +29,6 @@ from typing import (
_GenericAlias, # type: ignore _GenericAlias, # type: ignore
cast, cast,
get_args, get_args,
get_origin,
get_type_hints, get_type_hints,
) )
@ -51,7 +50,7 @@ from reflex.utils.imports import (
ParsedImportDict, ParsedImportDict,
parse_imports, parse_imports,
) )
from reflex.utils.types import override from reflex.utils.types import get_origin, override
if TYPE_CHECKING: if TYPE_CHECKING:
from reflex.state import BaseState from reflex.state import BaseState
@ -182,15 +181,14 @@ class VarData(Base):
var_data.interpolations if isinstance(var_data, VarData) else [] var_data.interpolations if isinstance(var_data, VarData) else []
) )
return ( if state or _imports or hooks or interpolations:
cls( return cls(
state=state, state=state,
imports=_imports, imports=_imports,
hooks=hooks, hooks=hooks,
interpolations=interpolations, interpolations=interpolations,
) )
or None return None
)
def __bool__(self) -> bool: def __bool__(self) -> bool:
"""Check if the var data is non-empty. """Check if the var data is non-empty.
@ -302,14 +300,13 @@ class ImmutableVarData:
else {k: None for k in var_data.hooks} else {k: None for k in var_data.hooks}
) )
return ( if state or _imports or hooks:
ImmutableVarData( return ImmutableVarData(
state=state, state=state,
imports=_imports, imports=_imports,
hooks=hooks, hooks=hooks,
) )
or None return None
)
def __bool__(self) -> bool: def __bool__(self) -> bool:
"""Check if the var data is non-empty. """Check if the var data is non-empty.

View File

@ -34,4 +34,4 @@ if [ -f /proc/$pid/winpid ]; then
echo "Windows detected, passing winpid $pid to port waiter" echo "Windows detected, passing winpid $pid to port waiter"
fi fi
python scripts/wait_for_listening_port.py $check_ports --timeout=1800 --server-pid "$pid" python scripts/wait_for_listening_port.py $check_ports --timeout=900 --server-pid "$pid"