Skip to content

Commit 1b48419

Browse files
committed
First pass at restore state. **many** debug statements. Modules are saving!
1 parent b0bf3db commit 1b48419

File tree

9 files changed

+798
-437
lines changed

9 files changed

+798
-437
lines changed

shiny/_app.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import copy
44
import os
55
import secrets
6+
import warnings
67
from contextlib import AsyncExitStack, asynccontextmanager
78
from inspect import signature
89
from pathlib import Path
@@ -30,6 +31,11 @@
3031
from ._error import ErrorMiddleware
3132
from ._shinyenv import is_pyodide
3233
from ._utils import guess_mime_type, is_async_callable, sort_keys_length
34+
from .bookmark._restore_state import (
35+
RestoreContext,
36+
get_current_restore_context,
37+
restore_context,
38+
)
3339
from .html_dependencies import jquery_deps, require_deps, shiny_deps
3440
from .http_staticfiles import FileResponse, StaticFiles
3541
from .session._session import AppSession, Inputs, Outputs, Session, session_context
@@ -167,7 +173,7 @@ def __init__(
167173

168174
self._sessions: dict[str, AppSession] = {}
169175

170-
self._sessions_needing_flush: dict[int, AppSession] = {}
176+
# self._sessions_needing_flush: dict[int, AppSession] = {}
171177

172178
self._registered_dependencies: dict[str, HTMLDependency] = {}
173179
self._dependency_handler = starlette.routing.Router()
@@ -353,11 +359,41 @@ async def _on_root_request_cb(self, request: Request) -> Response:
353359
request for / occurs.
354360
"""
355361
ui: RenderedHTML
356-
if callable(self.ui):
357-
ui = self._render_page(self.ui(request), self.lib_prefix)
362+
# Create a restore context using query string
363+
# TODO: Barret implement how to get bookmark_store value
364+
# bookmarkStore <- getShinyOption("bookmarkStore", default = "disable")
365+
print("TODO: Figure this out")
366+
bookmark_store: str = "disable"
367+
bookmark_store: str = "query"
368+
369+
if bookmark_store == "disable":
370+
restore_ctx = RestoreContext()
358371
else:
359-
ui = self.ui
360-
return HTMLResponse(content=ui["html"])
372+
restore_ctx = await RestoreContext.from_query_string(request.url.query)
373+
374+
print(
375+
{
376+
"values": restore_ctx.as_state().values,
377+
"input": restore_ctx.as_state().input,
378+
}
379+
)
380+
381+
with restore_context(restore_ctx):
382+
if callable(self.ui):
383+
ui = self._render_page(self.ui(request), self.lib_prefix)
384+
else:
385+
# TODO: Why is this here as there's a with restore_context above?
386+
# TODO: Why not `if restore_ctx.active:`?
387+
cur_restore_ctx = get_current_restore_context()
388+
print("cur_restore_ctx", cur_restore_ctx)
389+
if cur_restore_ctx is not None and cur_restore_ctx.active:
390+
# TODO: See ?enableBookmarking
391+
warnings.warn(
392+
"Trying to restore saved app state, but UI code must be a function for this to work!"
393+
)
394+
395+
ui = self.ui
396+
return HTMLResponse(content=ui["html"])
361397

362398
async def _on_connect_cb(self, ws: starlette.websockets.WebSocket) -> None:
363399
"""

shiny/_namespaces.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88

99
class ResolvedId(str):
10+
_sep: str = "-" # Shared object for all instances
11+
1012
def __call__(self, id: Id) -> ResolvedId:
1113
if isinstance(id, ResolvedId):
1214
return id
@@ -16,7 +18,7 @@ def __call__(self, id: Id) -> ResolvedId:
1618
if self == "":
1719
return ResolvedId(id)
1820
else:
19-
return ResolvedId(self + "-" + id)
21+
return ResolvedId(str(self) + self._sep + id)
2022

2123

2224
Root: ResolvedId = ResolvedId("")

shiny/_utils.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -550,23 +550,26 @@ def count(self) -> int:
550550
return len(self._callbacks)
551551

552552

553+
CancelCallback = Callable[[], None]
554+
555+
553556
class AsyncCallbacks:
554557
def __init__(self) -> None:
555558
self._callbacks: dict[int, tuple[Callable[..., Awaitable[None]], bool]] = {}
556559
self._id: int = 0
557560

558561
def register(
559562
self, fn: Callable[..., Awaitable[None]], once: bool = False
560-
) -> Callable[[], None]:
563+
) -> CancelCallback:
561564
self._id += 1
562565
id = self._id
563566
self._callbacks[id] = (fn, once)
564567

565-
def _():
568+
def cancel_callback():
566569
if id in self._callbacks:
567570
del self._callbacks[id]
568571

569-
return _
572+
return cancel_callback
570573

571574
async def invoke(self, *args: Any, **kwargs: Any) -> None:
572575
# The list() wrapper is necessary to force collection of all the items before

shiny/bookmark/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
BookmarkProxy,
66
ShinySaveState,
77
)
8-
from ._save_state import SaveState
8+
from ._bookmark_state import BookmarkState
9+
from ._restore_state import RestoreContext, RestoreContextState
910

1011
__all__ = (
11-
"SaveState",
12+
# _bookmark
1213
"ShinySaveState",
1314
"Bookmark",
1415
"BookmarkApp",
1516
"BookmarkProxy",
1617
"BookmarkExpressStub",
18+
# _bookmark_state
19+
"BookmarkState",
20+
# _restore_state
21+
"RestoreContext",
22+
"RestoreContextState",
1723
)

0 commit comments

Comments
 (0)