From 9149bf33275a383413051009962f1b3e41b155b7 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 10 Jul 2026 19:39:30 +0000 Subject: [PATCH 1/2] perf: cache framework-path checks in console.deprecate frame walk console.deprecate resolved and compared every stack frame's path against ~300 excluded framework/stdlib roots on every call, even when the warning was already deduped -- 5-6ms per call. Deprecated properties on hot paths (e.g. RouterData.page) paid this on every access from an event handler. Cache the per-filename framework-root determination (module files do not move within a process), turning repeat calls into dict lookups: ~6ms -> ~0.04ms (~150x). Emission behavior is unchanged, including one warning per distinct user-code call site. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Sns7EuBPYvfGCxRSRZ1bUx --- .../src/reflex_base/utils/console.py | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/reflex-base/src/reflex_base/utils/console.py b/packages/reflex-base/src/reflex_base/utils/console.py index 962008e42e0..6d4d3bf16d8 100644 --- a/packages/reflex-base/src/reflex_base/utils/console.py +++ b/packages/reflex-base/src/reflex_base/utils/console.py @@ -4,6 +4,7 @@ import contextlib import datetime +import functools import inspect import os import shutil @@ -303,13 +304,30 @@ def _exclude_paths_from_frame_info() -> list[Path]: return exclude_roots -def _get_first_non_framework_frame() -> FrameType | None: - exclude_roots = _exclude_paths_from_frame_info() +@functools.cache +def _is_framework_filename(filename: str) -> bool: + """Check if a code filename belongs to an excluded framework/stdlib root. + + Cached per filename: module file locations do not move within a process, + but resolving a path and comparing it against every exclude root is far + too expensive to repeat for each frame on every deprecation check. + + Args: + filename: The ``co_filename`` of a frame's code object. + + Returns: + Whether the file lives under one of the excluded framework roots. + """ + frame_path = Path(filename).resolve() + return any( + frame_path.is_relative_to(root) for root in _exclude_paths_from_frame_info() + ) + +def _get_first_non_framework_frame() -> FrameType | None: frame = inspect.currentframe() while frame := frame and frame.f_back: - frame_path = Path(inspect.getfile(frame)).resolve() - if not any(frame_path.is_relative_to(root) for root in exclude_roots): + if not _is_framework_filename(frame.f_code.co_filename): break return frame From 6f922e7e2707369643a4eeeb68f63706d47276d0 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 10 Jul 2026 19:40:03 +0000 Subject: [PATCH 2/2] chore: add news fragment for #6736 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Sns7EuBPYvfGCxRSRZ1bUx --- packages/reflex-base/news/6736.performance.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/reflex-base/news/6736.performance.md diff --git a/packages/reflex-base/news/6736.performance.md b/packages/reflex-base/news/6736.performance.md new file mode 100644 index 00000000000..ff80caf8553 --- /dev/null +++ b/packages/reflex-base/news/6736.performance.md @@ -0,0 +1 @@ +Cache framework-path checks in `console.deprecate`'s call-stack walk, making repeat calls ~150x faster (deprecated attributes on hot paths, like `RouterData.page`, no longer cost multiple milliseconds per access).