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:
Masen Furer 2024-03-06 10:42:20 -08:00 committed by GitHub
parent 2125701c2d
commit 03aa28320a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 34 additions and 26 deletions

View File

@ -30,6 +30,26 @@ from reflex import constants
from reflex.base import Base
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.
GenericType = Union[Type, _GenericAlias]
@ -75,22 +95,7 @@ def is_generic_alias(cls: GenericType) -> bool:
Returns:
Whether the class is a generic alias.
"""
# For older versions of Python.
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
return isinstance(cls, GenericAliasTypes)
def is_union(cls: GenericType) -> bool:
@ -102,11 +107,7 @@ def is_union(cls: GenericType) -> bool:
Returns:
Whether the class is a Union.
"""
# UnionType added in py3.10
if not hasattr(types, "UnionType"):
return get_origin(cls) is Union
return get_origin(cls) in [Union, types.UnionType]
return get_origin(cls) in UnionTypes
def is_literal(cls: GenericType) -> bool:

View File

@ -229,6 +229,13 @@ def _encode_var(value: Var) -> str:
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]:
"""Decode the state name from a formatted var.
@ -240,6 +247,10 @@ def _decode_var(value: str) -> tuple[VarData | None, str]:
"""
var_datas = []
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
# Initialize some methods for reading json.
@ -251,12 +262,8 @@ def _decode_var(value: str) -> tuple[VarData | None, str]:
except json.decoder.JSONDecodeError:
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.
while m := pattern.search(value):
while m := _decode_var_pattern.search(value):
start, end = m.span()
value = value[:start] + value[end:]