Perf improvements (part 1) (#2779)
* types: remove runtime imports from `is_generic_alias` Reduce try/except contexts for better performance. * _decode_var optimizations: * compile the regex once at module scope * fast path string scan for REFLEX_VAR_OPENING_TAG before doing more complex logic * Avoid repeated `hasattr` check in `is_union` `is_union` gets called a lot, and the hasattr check can be resolved at import time for better performance.
This commit is contained in:
parent
2125701c2d
commit
03aa28320a
@ -30,6 +30,26 @@ from reflex import constants
|
|||||||
from reflex.base import Base
|
from reflex.base import Base
|
||||||
from reflex.utils import serializers
|
from reflex.utils import serializers
|
||||||
|
|
||||||
|
# Potential GenericAlias types for isinstance checks.
|
||||||
|
GenericAliasTypes = [_GenericAlias]
|
||||||
|
|
||||||
|
with contextlib.suppress(ImportError):
|
||||||
|
# For newer versions of Python.
|
||||||
|
from types import GenericAlias # type: ignore
|
||||||
|
|
||||||
|
GenericAliasTypes.append(GenericAlias)
|
||||||
|
|
||||||
|
with contextlib.suppress(ImportError):
|
||||||
|
# For older versions of Python.
|
||||||
|
from typing import _SpecialGenericAlias # type: ignore
|
||||||
|
|
||||||
|
GenericAliasTypes.append(_SpecialGenericAlias)
|
||||||
|
|
||||||
|
GenericAliasTypes = tuple(GenericAliasTypes)
|
||||||
|
|
||||||
|
# Potential Union types for isinstance checks (UnionType added in py3.10).
|
||||||
|
UnionTypes = (Union, types.UnionType) if hasattr(types, "UnionType") else (Union,)
|
||||||
|
|
||||||
# Union of generic types.
|
# Union of generic types.
|
||||||
GenericType = Union[Type, _GenericAlias]
|
GenericType = Union[Type, _GenericAlias]
|
||||||
|
|
||||||
@ -75,22 +95,7 @@ def is_generic_alias(cls: GenericType) -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
Whether the class is a generic alias.
|
Whether the class is a generic alias.
|
||||||
"""
|
"""
|
||||||
# For older versions of Python.
|
return isinstance(cls, GenericAliasTypes)
|
||||||
if isinstance(cls, _GenericAlias):
|
|
||||||
return True
|
|
||||||
|
|
||||||
with contextlib.suppress(ImportError):
|
|
||||||
from typing import _SpecialGenericAlias # type: ignore
|
|
||||||
|
|
||||||
if isinstance(cls, _SpecialGenericAlias):
|
|
||||||
return True
|
|
||||||
# For newer versions of Python.
|
|
||||||
try:
|
|
||||||
from types import GenericAlias # type: ignore
|
|
||||||
|
|
||||||
return isinstance(cls, GenericAlias)
|
|
||||||
except ImportError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_union(cls: GenericType) -> bool:
|
def is_union(cls: GenericType) -> bool:
|
||||||
@ -102,11 +107,7 @@ def is_union(cls: GenericType) -> bool:
|
|||||||
Returns:
|
Returns:
|
||||||
Whether the class is a Union.
|
Whether the class is a Union.
|
||||||
"""
|
"""
|
||||||
# UnionType added in py3.10
|
return get_origin(cls) in UnionTypes
|
||||||
if not hasattr(types, "UnionType"):
|
|
||||||
return get_origin(cls) is Union
|
|
||||||
|
|
||||||
return get_origin(cls) in [Union, types.UnionType]
|
|
||||||
|
|
||||||
|
|
||||||
def is_literal(cls: GenericType) -> bool:
|
def is_literal(cls: GenericType) -> bool:
|
||||||
|
@ -229,6 +229,13 @@ def _encode_var(value: Var) -> str:
|
|||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
# Compile regex for finding reflex var tags.
|
||||||
|
_decode_var_pattern_re = (
|
||||||
|
rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
|
||||||
|
)
|
||||||
|
_decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
def _decode_var(value: str) -> tuple[VarData | None, str]:
|
def _decode_var(value: str) -> tuple[VarData | None, str]:
|
||||||
"""Decode the state name from a formatted var.
|
"""Decode the state name from a formatted var.
|
||||||
|
|
||||||
@ -240,6 +247,10 @@ def _decode_var(value: str) -> tuple[VarData | None, str]:
|
|||||||
"""
|
"""
|
||||||
var_datas = []
|
var_datas = []
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
|
# fast path if there is no encoded VarData
|
||||||
|
if constants.REFLEX_VAR_OPENING_TAG not in value:
|
||||||
|
return None, value
|
||||||
|
|
||||||
offset = 0
|
offset = 0
|
||||||
|
|
||||||
# Initialize some methods for reading json.
|
# Initialize some methods for reading json.
|
||||||
@ -251,12 +262,8 @@ def _decode_var(value: str) -> tuple[VarData | None, str]:
|
|||||||
except json.decoder.JSONDecodeError:
|
except json.decoder.JSONDecodeError:
|
||||||
return var_data_config.json_loads(var_data_config.json_loads(f'"{s}"'))
|
return var_data_config.json_loads(var_data_config.json_loads(f'"{s}"'))
|
||||||
|
|
||||||
# Compile regex for finding reflex var tags.
|
|
||||||
pattern_re = rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
|
|
||||||
pattern = re.compile(pattern_re, flags=re.DOTALL)
|
|
||||||
|
|
||||||
# Find all tags.
|
# Find all tags.
|
||||||
while m := pattern.search(value):
|
while m := _decode_var_pattern.search(value):
|
||||||
start, end = m.span()
|
start, end = m.span()
|
||||||
value = value[:start] + value[end:]
|
value = value[:start] + value[end:]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user