1515if TYPE_CHECKING :
1616 from ..express ._stub_session import ExpressStubSession
1717 from ..module import ResolvedId
18- from ..session ._session import AppSession , SessionProxy
18+ from ..session ._session import AppSession , Session , SessionProxy
1919 from . import RestoreContext
2020else :
2121 from typing import Any
2222
2323 RestoreContext = Any
2424 SessionProxy = Any
25+ Session = Any
2526 AppSession = Any
2627 ResolvedId = Any
2728 ExpressStubSession = Any
@@ -217,22 +218,26 @@ async def do_bookmark(self) -> None:
217218
218219
219220class BookmarkApp (Bookmark ):
220- _session : AppSession
221+ _root_session : AppSession
221222 """
222- The root session object (most likely a `AppSession` object) .
223+ The root session object.
223224 """
225+
224226 _restore_context_value : RestoreContext
225227 """
226228 Placeholder value that should only be manually set within the session's `init` websocket message.
227229 """
228230
229- def __init__ (self , session : AppSession ):
231+ def __init__ (self , root_session : AppSession ):
230232 from ..session ._session import AppSession
231233
232- assert isinstance (session , AppSession )
234+ assert isinstance (root_session , AppSession )
233235 super ().__init__ ()
234236
235- self ._session = session
237+ self ._root_session = root_session
238+
239+ # # Do not set it to avoid supporting a `None` type.
240+ # # Instead, only use it after it's been set.
236241 # self._restore_context_value = None
237242
238243 # Making this a read only property as app authors will not be able to change how the
@@ -241,7 +246,7 @@ def __init__(self, session: AppSession):
241246 @property
242247 def store (self ) -> BookmarkStore :
243248
244- return self ._session .app .bookmark_store
249+ return self ._root_session .app .bookmark_store
245250
246251 @property
247252 def _restore_context (self ) -> RestoreContext | None :
@@ -269,19 +274,19 @@ def _create_effects(self) -> None:
269274 if self .store == "disable" :
270275 return
271276
272- session = self ._session
277+ root_session = self ._root_session
273278
274279 from .. import reactive
275280 from ..session import session_context
276281 from ..ui ._notification import notification_show
277282
278- with session_context (session ):
283+ with session_context (root_session ):
279284
280285 # Fires when the bookmark button is clicked.
281286 @reactive .effect
282- @reactive .event (session .input [BOOKMARK_ID ])
287+ @reactive .event (root_session .input [BOOKMARK_ID ])
283288 async def _ ():
284- await session .bookmark ()
289+ await root_session .bookmark ()
285290
286291 # If there was an error initializing the current restore context, show
287292 # notification in the client.
@@ -292,6 +297,7 @@ def init_error_message():
292297 f"Error in RestoreContext initialization: { self ._restore_context ._init_error_msg } " ,
293298 duration = None ,
294299 type = "error" ,
300+ session = root_session ,
295301 )
296302
297303 # Run the on_restore function at the beginning of the flush cycle, but after
@@ -301,7 +307,7 @@ async def invoke_on_restore_callbacks():
301307 if self ._on_restore_callbacks .count () == 0 :
302308 return
303309
304- with session_context (session ):
310+ with session_context (root_session ):
305311
306312 try :
307313 # ?withLogErrors
@@ -322,12 +328,12 @@ async def invoke_on_restore_callbacks():
322328
323329 # Run the on_restored function after the flush cycle completes and
324330 # information is sent to the client.
325- @session .on_flushed
331+ @root_session .on_flushed
326332 async def invoke_on_restored_callbacks ():
327333 if self ._on_restored_callbacks .count () == 0 :
328334 return
329335
330- with session_context (session ):
336+ with session_context (root_session ):
331337 try :
332338 with reactive .isolate ():
333339 if self ._restore_context and self ._restore_context .active :
@@ -385,7 +391,7 @@ async def update_query_string(
385391 ) -> None :
386392 if mode not in {"replace" , "push" }:
387393 raise ValueError (f"Invalid mode: { mode } " )
388- await self ._session ._send_message (
394+ await self ._root_session ._send_message (
389395 {
390396 "updateQueryString" : {
391397 "queryString" : query_string ,
@@ -414,17 +420,17 @@ async def get_bookmark_url(self) -> str | None:
414420 from ..session import session_context
415421
416422 async def root_state_on_save (state : BookmarkState ) -> None :
417- with session_context (self ._session ):
423+ with session_context (self ._root_session ):
418424 await self ._on_bookmark_callbacks .invoke (state )
419425
420426 root_state = BookmarkState (
421- input = self ._session .input ,
427+ input = self ._root_session .input ,
422428 exclude = self ._get_bookmark_exclude (),
423429 on_save = root_state_on_save ,
424430 )
425431
426432 if self .store == "server" :
427- query_string = await root_state ._save_state (app = self ._session .app )
433+ query_string = await root_state ._save_state (app = self ._root_session .app )
428434 elif self .store == "url" :
429435 query_string = await root_state ._encode_state ()
430436 # # Can we have browser storage?
@@ -436,7 +442,7 @@ async def root_state_on_save(state: BookmarkState) -> None:
436442 else :
437443 raise ValueError ("Unknown bookmark store: " + self .store )
438444
439- clientdata = self ._session .clientdata
445+ clientdata = self ._root_session .clientdata
440446
441447 port = str (clientdata .url_port ())
442448 full_url = "" .join (
@@ -477,7 +483,7 @@ async def do_bookmark(self) -> None:
477483 # If on_bookmarked callback was provided, invoke it; if not call
478484 # the default.
479485 if self ._on_bookmarked_callbacks .count () > 0 :
480- with session_context (self ._session ):
486+ with session_context (self ._root_session ):
481487 await self ._on_bookmarked_callbacks .invoke (full_url )
482488 else :
483489 # `session.bookmark.show_modal(url)`
@@ -497,7 +503,12 @@ async def do_bookmark(self) -> None:
497503class BookmarkProxy (Bookmark ):
498504
499505 _ns : ResolvedId
500- _session : SessionProxy
506+ _proxy_session : SessionProxy
507+ _root_session : Session
508+
509+ @property
510+ def _root_bookmark (self ) -> Bookmark :
511+ return self ._root_session .bookmark
501512
502513 def __init__ (self , session_proxy : SessionProxy ):
503514 from ..session ._session import SessionProxy
@@ -506,10 +517,11 @@ def __init__(self, session_proxy: SessionProxy):
506517 super ().__init__ ()
507518
508519 self ._ns = session_proxy .ns
509- self ._session = session_proxy
520+ self ._proxy_session = session_proxy
521+ self ._root_session = session_proxy ._root_session
510522
511523 # Maybe `._get_bookmark_exclude()` should be used instead of`proxy_exclude_fns`?
512- self ._session . _parent . bookmark ._on_get_exclude .append (
524+ self ._root_bookmark ._on_get_exclude .append (
513525 lambda : [str (self ._ns (name )) for name in self .exclude ]
514526 )
515527
@@ -519,37 +531,37 @@ def __init__(self, session_proxy: SessionProxy):
519531
520532 # The goal of this method is to save the scope's values. All namespaced inputs
521533 # will already exist within the `root_state`.
522- self ._session . _parent . bookmark .on_bookmark (self ._scoped_on_bookmark )
534+ self ._root_bookmark .on_bookmark (self ._scoped_on_bookmark )
523535
524536 from ..session import session_context
525537
526- @self ._session . _parent . bookmark .on_bookmarked
538+ @self ._root_bookmark .on_bookmarked
527539 async def scoped_on_bookmarked (url : str ) -> None :
528540 if self ._on_bookmarked_callbacks .count () == 0 :
529541 return
530542
531- with session_context (self ._session ):
543+ with session_context (self ._proxy_session ):
532544 await self ._on_bookmarked_callbacks .invoke (url )
533545
534546 ns_prefix = str (self ._ns + self ._ns ._sep )
535547
536- @self ._session . _parent . bookmark .on_restore
548+ @self ._root_bookmark .on_restore
537549 async def scoped_on_restore (restore_state : RestoreState ) -> None :
538550 if self ._on_restore_callbacks .count () == 0 :
539551 return
540552
541553 scoped_restore_state = restore_state ._state_within_namespace (ns_prefix )
542554
543- with session_context (self ._session ):
555+ with session_context (self ._proxy_session ):
544556 await self ._on_restore_callbacks .invoke (scoped_restore_state )
545557
546- @self ._session . _parent . bookmark .on_restored
558+ @self ._root_bookmark .on_restored
547559 async def scoped_on_restored (restore_state : RestoreState ) -> None :
548560 if self ._on_restored_callbacks .count () == 0 :
549561 return
550562
551563 scoped_restore_state = restore_state ._state_within_namespace (ns_prefix )
552- with session_context (self ._session ):
564+ with session_context (self ._proxy_session ):
553565 await self ._on_restored_callbacks .invoke (scoped_restore_state )
554566
555567 async def _scoped_on_bookmark (self , root_state : BookmarkState ) -> None :
@@ -560,7 +572,7 @@ async def _scoped_on_bookmark(self, root_state: BookmarkState) -> None:
560572 from ..bookmark ._bookmark import BookmarkState
561573
562574 scoped_state = BookmarkState (
563- input = self ._session .input ,
575+ input = self ._proxy_session .input ,
564576 exclude = self .exclude ,
565577 on_save = None ,
566578 )
@@ -580,7 +592,7 @@ async def _scoped_on_bookmark(self, root_state: BookmarkState) -> None:
580592 # Invoke the callback on the scopeState object
581593 from ..session import session_context
582594
583- with session_context (self ._session ):
595+ with session_context (self ._proxy_session ):
584596 await self ._on_bookmark_callbacks .invoke (scoped_state )
585597
586598 # Copy `values` from scoped_state to root_state (adding namespace)
@@ -592,22 +604,22 @@ async def _scoped_on_bookmark(self, root_state: BookmarkState) -> None:
592604
593605 @property
594606 def store (self ) -> BookmarkStore :
595- return self ._session . _parent . bookmark .store
607+ return self ._root_bookmark .store
596608
597609 @property
598610 def _restore_context (self ) -> RestoreContext | None :
599- return self ._session . _parent . bookmark ._restore_context
611+ return self ._root_bookmark ._restore_context
600612
601613 async def update_query_string (
602614 self , query_string : str , mode : Literal ["replace" , "push" ] = "replace"
603615 ) -> None :
604- await self ._session . _parent . bookmark .update_query_string (query_string , mode )
616+ await self ._root_bookmark .update_query_string (query_string , mode )
605617
606618 async def get_bookmark_url (self ) -> str | None :
607- return await self ._session . _parent . bookmark .get_bookmark_url ()
619+ return await self ._root_bookmark .get_bookmark_url ()
608620
609621 async def do_bookmark (self ) -> None :
610- await self ._session . _parent . bookmark .do_bookmark ()
622+ await self ._root_bookmark .do_bookmark ()
611623
612624
613625class BookmarkExpressStub (Bookmark ):
0 commit comments