Skip to content

Commit 3df0026

Browse files
committed
Move files around. Add shiny.bookmark. set_save_dir() and set_restore_dir()
1 parent 9f15505 commit 3df0026

File tree

12 files changed

+222
-100
lines changed

12 files changed

+222
-100
lines changed

shiny/_app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
from ._error import ErrorMiddleware
3232
from ._shinyenv import is_pyodide
3333
from ._utils import guess_mime_type, is_async_callable, sort_keys_length
34-
from .bookmark._globals import BookmarkStore
3534
from .bookmark._restore_state import (
3635
RestoreContext,
3736
get_current_restore_context,
3837
restore_context,
3938
)
39+
from .bookmark._types import BookmarkStore
4040
from .html_dependencies import jquery_deps, require_deps, shiny_deps
4141
from .http_staticfiles import FileResponse, StaticFiles
4242
from .session._session import AppSession, Inputs, Outputs, Session, session_context

shiny/bookmark/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from . import _globals as globals
21
from ._bookmark import (
32
Bookmark,
43
BookmarkApp,
@@ -7,11 +6,10 @@
76
ShinySaveState,
87
)
98
from ._button import input_bookmark_button
9+
from ._external import set_load_dir, set_save_dir
1010
from ._restore_state import RestoreContext, RestoreContextState, restore_input
1111

1212
__all__ = (
13-
# _globals
14-
"globals",
1513
# _bookmark
1614
"ShinySaveState",
1715
"Bookmark",
@@ -20,6 +18,9 @@
2018
"BookmarkExpressStub",
2119
# _button
2220
"input_bookmark_button",
21+
# _external
22+
"set_save_dir",
23+
"set_load_dir",
2324
# _restore_state
2425
"RestoreContext",
2526
"RestoreContextState",

shiny/bookmark/_bookmark.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77

88
from .._utils import AsyncCallbacks, CancelCallback, wrap_async
99
from ..types import MISSING, MISSING_TYPE
10-
from . import _globals as bookmark_globals
1110
from ._button import BOOKMARK_ID
12-
from ._globals import BookmarkStore
1311
from ._restore_state import RestoreContextState
1412
from ._save_state import ShinySaveState
13+
from ._types import BookmarkStore
1514

1615
# TODO: Barret - Bookmark state
1716
# bookmark -> save/load interface
@@ -590,9 +589,12 @@ async def _scoped_on_bookmark(self, root_state: ShinySaveState) -> None:
590589
)
591590

592591
# Make subdir for scope
592+
# TODO-barret; Is this for uploaded files?!?
593593
if root_state.dir is not None:
594594
scope_subpath = self._ns
595595
scoped_state.dir = Path(root_state.dir) / scope_subpath
596+
scoped_state.dir.mkdir(parents=True, exist_ok=True)
597+
596598
if not scoped_state.dir.exists():
597599
raise FileNotFoundError(
598600
f"Scope directory could not be created for {scope_subpath}"
@@ -653,13 +655,6 @@ async def do_bookmark(self) -> None:
653655
def store(self) -> BookmarkStore:
654656
return self._root_bookmark.store
655657

656-
@store.setter
657-
def store( # pyright: ignore[reportIncompatibleVariableOverride]
658-
self,
659-
value: BookmarkStore,
660-
) -> None:
661-
self._root_bookmark.store = value
662-
663658
def on_restore(
664659
self,
665660
callback: (

shiny/bookmark/_bookmark_state.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ async def local_save_dir(id: str) -> Path:
1616
return state_dir
1717

1818

19-
async def local_load_dir(id: str) -> Path:
19+
async def local_restore_dir(id: str) -> Path:
2020
return _local_dir(id)

shiny/bookmark/_button.py

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,59 +9,59 @@
99
BOOKMARK_ID = "._bookmark_"
1010

1111

12-
#' Create a button for bookmarking/sharing
13-
#'
14-
#' A `bookmarkButton` is a [actionButton()] with a default label
15-
#' that consists of a link icon and the text "Bookmark...". It is meant to be
16-
#' used for bookmarking state.
17-
#'
18-
#' @inheritParams actionButton
19-
#' @param title A tooltip that is shown when the mouse cursor hovers over the
20-
#' button.
21-
#' @param id An ID for the bookmark button. The only time it is necessary to set
22-
#' the ID unless you have more than one bookmark button in your application.
23-
#' If you specify an input ID, it should be excluded from bookmarking with
24-
#' [setBookmarkExclude()], and you must create an observer that
25-
#' does the bookmarking when the button is pressed. See the examples below.
26-
#'
27-
#' @seealso [enableBookmarking()] for more examples.
28-
#'
29-
#' @examples
30-
#' ## Only run these examples in interactive sessions
31-
#' if (interactive()) {
32-
#'
33-
#' # This example shows how to use multiple bookmark buttons. If you only need
34-
#' # a single bookmark button, see examples in ?enableBookmarking.
35-
#' ui <- function(request) {
36-
#' fluidPage(
37-
#' tabsetPanel(id = "tabs",
38-
#' tabPanel("One",
39-
#' checkboxInput("chk1", "Checkbox 1"),
40-
#' bookmarkButton(id = "bookmark1")
41-
#' ),
42-
#' tabPanel("Two",
43-
#' checkboxInput("chk2", "Checkbox 2"),
44-
#' bookmarkButton(id = "bookmark2")
45-
#' )
46-
#' )
47-
#' )
48-
#' }
49-
#' server <- function(input, output, session) {
50-
#' # Need to exclude the buttons from themselves being bookmarked
51-
#' setBookmarkExclude(c("bookmark1", "bookmark2"))
52-
#'
53-
#' # Trigger bookmarking with either button
54-
#' observeEvent(input$bookmark1, {
55-
#' session$doBookmark()
56-
#' })
57-
#' observeEvent(input$bookmark2, {
58-
#' session$doBookmark()
59-
#' })
60-
#' }
61-
#' enableBookmarking(store = "url")
62-
#' shinyApp(ui, server)
63-
#' }
64-
#' @export
12+
# ' Create a button for bookmarking/sharing
13+
# '
14+
# ' A `bookmarkButton` is a [actionButton()] with a default label
15+
# ' that consists of a link icon and the text "Bookmark...". It is meant to be
16+
# ' used for bookmarking state.
17+
# '
18+
# ' @inheritParams actionButton
19+
# ' @param title A tooltip that is shown when the mouse cursor hovers over the
20+
# ' button.
21+
# ' @param id An ID for the bookmark button. The only time it is necessary to set
22+
# ' the ID unless you have more than one bookmark button in your application.
23+
# ' If you specify an input ID, it should be excluded from bookmarking with
24+
# ' [setBookmarkExclude()], and you must create an observer that
25+
# ' does the bookmarking when the button is pressed. See the examples below.
26+
# '
27+
# ' @seealso [enableBookmarking()] for more examples.
28+
# '
29+
# ' @examples
30+
# ' ## Only run these examples in interactive sessions
31+
# ' if (interactive()) {
32+
# '
33+
# ' # This example shows how to use multiple bookmark buttons. If you only need
34+
# ' # a single bookmark button, see examples in ?enableBookmarking.
35+
# ' ui <- function(request) {
36+
# ' fluidPage(
37+
# ' tabsetPanel(id = "tabs",
38+
# ' tabPanel("One",
39+
# ' checkboxInput("chk1", "Checkbox 1"),
40+
# ' bookmarkButton(id = "bookmark1")
41+
# ' ),
42+
# ' tabPanel("Two",
43+
# ' checkboxInput("chk2", "Checkbox 2"),
44+
# ' bookmarkButton(id = "bookmark2")
45+
# ' )
46+
# ' )
47+
# ' )
48+
# ' }
49+
# ' server <- function(input, output, session) {
50+
# ' # Need to exclude the buttons from themselves being bookmarked
51+
# ' setBookmarkExclude(c("bookmark1", "bookmark2"))
52+
# '
53+
# ' # Trigger bookmarking with either button
54+
# ' observeEvent(input$bookmark1, {
55+
# ' session$doBookmark()
56+
# ' })
57+
# ' observeEvent(input$bookmark2, {
58+
# ' session$doBookmark()
59+
# ' })
60+
# ' }
61+
# ' enableBookmarking(store = "url")
62+
# ' shinyApp(ui, server)
63+
# ' }
64+
# ' @export
6565
def input_bookmark_button(
6666
label: TagChild = "Bookmark...",
6767
*,

shiny/bookmark/_external.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
from typing import Awaitable, Callable, Literal, TypeVar
5+
6+
from .._utils import wrap_async
7+
from ..types import MISSING, MISSING_TYPE
8+
from ._types import GetBookmarkRestoreDir, GetBookmarkSaveDir
9+
10+
BookmarkStore = Literal["url", "server", "disable"]
11+
12+
13+
# WARNING! This file contains global state!
14+
# During App initialization, the save_dir and restore_dir functions are conventionally set
15+
# to read-only on the App.
16+
17+
# The set methods below are used to set the save_dir and restore_dir locations for locations like Connect or SSP.
18+
# Ex:
19+
# ```python
20+
# @shiny.bookmark.set_save_dir
21+
# def connect_save_shiny_bookmark(id: str) -> Path:
22+
# path = Path("connect") / id
23+
# path.mkdir(parents=True, exist_ok=True)
24+
# return path
25+
# @shiny.bookmark.set_restore_dir
26+
# def connect_restore_shiny_bookmark(id: str) -> Path:
27+
# return Path("connect") / id
28+
# ```
29+
30+
31+
_bookmark_save_dir: GetBookmarkSaveDir | MISSING_TYPE = MISSING
32+
_bookmark_restore_dir: GetBookmarkRestoreDir | MISSING_TYPE = MISSING
33+
34+
35+
GetBookmarkDirT = TypeVar(
36+
"GetBookmarkDirT",
37+
bound=Callable[[str], Awaitable[Path]] | Callable[[str], Awaitable[Path]],
38+
)
39+
40+
41+
def set_save_dir(fn: GetBookmarkDirT) -> GetBookmarkDirT:
42+
"""TODO: Barret document"""
43+
global _bookmark_save_dir
44+
45+
_bookmark_save_dir = wrap_async(fn)
46+
return fn
47+
48+
49+
def set_restore_dir(fn: GetBookmarkDirT) -> GetBookmarkDirT:
50+
"""TODO: Barret document"""
51+
global _bookmark_restore_dir
52+
53+
_bookmark_restore_dir = wrap_async(fn)
54+
return fn

shiny/bookmark/_globals.py

Lines changed: 0 additions & 17 deletions
This file was deleted.

shiny/bookmark/_restore_state.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
from shiny.types import MISSING_TYPE
1212

13-
from . import _globals as bookmark_globals
14-
from ._bookmark_state import local_load_dir
15-
from ._globals import BookmarkLoadDir
13+
from . import _external as bookmark_external
14+
from ._bookmark_state import local_restore_dir
15+
from ._types import GetBookmarkRestoreDir
1616
from ._utils import from_json_str, is_hosted
1717

1818

@@ -59,6 +59,7 @@ def _state_within_namespace(self, prefix: str) -> "RestoreContextState":
5959
if self._name_has_namespace(name, prefix)
6060
}
6161

62+
# TODO-barret; Is this for bookmarking?!?
6263
dir = self.dir
6364
if dir is not None:
6465
dir = dir / prefix
@@ -187,9 +188,9 @@ async def _load_state_qs(self, query_string: str) -> None:
187188

188189
id = id[0]
189190

190-
load_bookmark_fn: BookmarkLoadDir | None = None
191-
if not isinstance(bookmark_globals.bookmark_load_dir, MISSING_TYPE):
192-
load_bookmark_fn = bookmark_globals.bookmark_load_dir
191+
load_bookmark_fn: GetBookmarkRestoreDir | None = None
192+
if not isinstance(bookmark_external._bookmark_restore_dir, MISSING_TYPE):
193+
load_bookmark_fn = bookmark_external._bookmark_restore_dir
193194

194195
if load_bookmark_fn is None:
195196
if is_hosted():
@@ -199,7 +200,7 @@ async def _load_state_qs(self, query_string: str) -> None:
199200
)
200201
else:
201202
# We're running Shiny locally.
202-
load_bookmark_fn = local_load_dir
203+
load_bookmark_fn = local_restore_dir
203204

204205
# Load the state from disk.
205206
self.dir = Path(await load_bookmark_fn(id))
@@ -401,7 +402,6 @@ def restore_input(id: str, default: Any) -> Any:
401402
default
402403
A default value to use, if there's no value to restore.
403404
"""
404-
# print("\n", "restore_input-1", id, default, "\n")
405405
# Will run even if the domain is missing
406406
if not has_current_restore_context():
407407
return default

shiny/bookmark/_save_state.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
from .._utils import private_random_id
99
from ..reactive import isolate
1010
from ..types import MISSING_TYPE
11-
from . import _globals as bookmark_globals
11+
from . import _external as bookmark_external
1212
from ._bookmark_state import local_save_dir
13-
from ._globals import BookmarkSaveDir
13+
from ._types import GetBookmarkSaveDir
1414
from ._utils import is_hosted, to_json_str
1515

1616
# TODO: Barret - Set / Load SaveState for Connect. Ex: Connect https://github.com/posit-dev/connect/blob/8de330aec6a61cf21e160b5081d08a1d3d7e8129/R/connect.R#L915
@@ -76,9 +76,9 @@ async def _save_state(self) -> str:
7676
# to `self.dir`.
7777

7878
# This will be defined by the hosting environment if it supports bookmarking.
79-
save_bookmark_fn: BookmarkSaveDir | None = None
80-
if not isinstance(bookmark_globals.bookmark_save_dir, MISSING_TYPE):
81-
save_bookmark_fn = bookmark_globals.bookmark_save_dir
79+
save_bookmark_fn: GetBookmarkSaveDir | None = None
80+
if not isinstance(bookmark_external._bookmark_save_dir, MISSING_TYPE):
81+
save_bookmark_fn = bookmark_external._bookmark_save_dir
8282

8383
if save_bookmark_fn is None:
8484
if is_hosted():
@@ -99,6 +99,7 @@ async def _save_state(self) -> str:
9999
state_dir=self.dir,
100100
)
101101
assert self.dir is not None
102+
102103
with open(self.dir / "input.pickle", "wb") as f:
103104
pickle.dump(input_values_json, f)
104105

0 commit comments

Comments
 (0)