From 6d38f3b78b963ea8cc76430fc5d6a7600bbd07ed Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Thu, 18 Dec 2025 18:17:50 -0800 Subject: [PATCH] DependencyTracker: only handle STORE_FAST for the GETTING_IMPORT status STORE_FAST handling is not generally correct outside of the specific case of dealing with imports. So avoid resetting the stack or other issues when we're not importing. --- reflex/vars/dep_tracking.py | 8 +++++++- tests/units/vars/test_dep_tracking.py | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/reflex/vars/dep_tracking.py b/reflex/vars/dep_tracking.py index ebdfc43572d..2315eb9f814 100644 --- a/reflex/vars/dep_tracking.py +++ b/reflex/vars/dep_tracking.py @@ -46,6 +46,7 @@ class ScanStatus(enum.Enum): GETTING_STATE = enum.auto() GETTING_STATE_POST_AWAIT = enum.auto() GETTING_VAR = enum.auto() + GETTING_IMPORT = enum.auto() class UntrackedLocalVarError(VarValueError): @@ -446,6 +447,7 @@ def _populate_dependencies(self) -> None: ) ) elif instruction.opname == "IMPORT_NAME" and instruction.argval is not None: + self.scan_status = ScanStatus.GETTING_IMPORT self._last_import_name = instruction.argval importlib.import_module(instruction.argval) top_module_name = instruction.argval.split(".")[0] @@ -472,7 +474,11 @@ def _populate_dependencies(self) -> None: ) # If we see a STORE_FAST, we can assign the top of stack to an aliased name. self.top_of_stack = instruction.argval - elif instruction.opname == "STORE_FAST" and self.top_of_stack is not None: + elif ( + self.scan_status == ScanStatus.GETTING_IMPORT + and instruction.opname == "STORE_FAST" + and self.top_of_stack is not None + ): self.tracked_locals[instruction.argval] = self.tracked_locals.pop( self.top_of_stack ) diff --git a/tests/units/vars/test_dep_tracking.py b/tests/units/vars/test_dep_tracking.py index 99bbd0ef467..1acd5f864bc 100644 --- a/tests/units/vars/test_dep_tracking.py +++ b/tests/units/vars/test_dep_tracking.py @@ -271,6 +271,22 @@ async def get_state_imported_global(self: DependencyTestState): assert tracker.dependencies == expected_deps +def test_nested_function(): + """Test tracking dependencies in nested functions.""" + + def func_with_nested(self: DependencyTestState): + async def inner(): # noqa: RUF029 + if self.board: + pass + + return self.count + + tracker = DependencyTracker(func_with_nested, DependencyTestState) + + expected_deps = {DependencyTestState.get_full_name(): {"board", "count"}} + assert tracker.dependencies == expected_deps + + @pytest.mark.skipif( sys.version_info < (3, 11), reason="Requires Python 3.11+ for positions" )