Cache ComputedVar fixup for dynamic route vars (#952)

This commit is contained in:
Masen Furer 2023-05-06 12:44:50 -07:00 committed by GitHub
parent 9ea1a64d22
commit b4e534cc97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 2 deletions

View File

@ -484,7 +484,10 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
func = arglist_factory(param)
else:
continue
cls.computed_vars[param] = func.set_state(cls) # type: ignore
# link dynamically created ComputedVar to this state class for dep determination
func.__objclass__ = cls
func.fget.__name__ = param
cls.vars[param] = cls.computed_vars[param] = func.set_state(cls) # type: ignore
setattr(cls, param, func)
def __getattribute__(self, name: str) -> Any:
@ -537,7 +540,7 @@ class State(Base, ABC, extra=pydantic.Extra.allow):
super().__setattr__(name, value)
# Add the var to the dirty list.
if name in self.vars:
if name in self.vars or name in self.computed_var_dependencies:
self.dirty_vars.add(name)
self.mark_dirty()

View File

@ -857,6 +857,10 @@ class ComputedVar(Var, property):
Returns:
A set of variable names accessed by the given obj.
Raises:
RuntimeError: if this ComputedVar does not have a reference to the class
it is attached to. (Assign var.__objclass__ manually to workaround.)
"""
d = set()
if obj is None:
@ -876,6 +880,10 @@ class ComputedVar(Var, property):
if self_is_top_of_stack and instruction.opname == "LOAD_ATTR":
d.add(instruction.argval)
elif self_is_top_of_stack and instruction.opname == "LOAD_METHOD":
if not hasattr(self, "__objclass__"):
raise RuntimeError(
f"ComputedVar {self.name!r} is not bound to a State subclass.",
)
d.update(self.deps(obj=getattr(self.__objclass__, instruction.argval)))
self_is_top_of_stack = False
return d

View File

@ -105,6 +105,25 @@ def test_add_page_set_route(app: App, index_page, windows_platform: bool):
assert set(app.pages.keys()) == {"test"}
def test_add_page_set_route_dynamic(app: App, index_page, windows_platform: bool):
"""Test adding a page with dynamic route variable to an app.
Args:
app: The app to test.
index_page: The index page.
windows_platform: Whether the system is windows.
"""
route = "/test/[dynamic]"
if windows_platform:
route.lstrip("/").replace("/", "\\")
assert app.pages == {}
app.add_page(index_page, route=route)
assert set(app.pages.keys()) == {"test/[dynamic]"}
assert "dynamic" in app.state.computed_vars
assert app.state.computed_vars["dynamic"].deps() == {"router_data"}
assert "router_data" in app.state().computed_var_dependencies
def test_add_page_set_route_nested(app: App, index_page, windows_platform: bool):
"""Test adding a page to an app.