22
33import asyncio
44import inspect
5+ import weakref
56from functools import wraps
67from pathlib import Path
78from typing import TYPE_CHECKING , Any , Callable
@@ -30,13 +31,15 @@ def __init__(self,
3031 response_timeout : float = 3.0 ,
3132 reconnect_timeout : float | None = None ,
3233 api_router : APIRouter | None = None ,
34+ shared : bool = False ,
3335 ** kwargs : Any ,
3436 ) -> None :
3537 """Page
3638
3739 This decorator marks a function to be a page builder.
38- Each user accessing the given route will see a new instance of the page.
40+ By default, each user accessing the given route will see a new instance of the page.
3941 This means it is private to the user and not shared with others.
42+ If ``shared`` is True, all users will see and interact with the same page instance.
4043
4144 Notes:
4245
@@ -56,6 +59,7 @@ def __init__(self,
5659 :param response_timeout: maximum time for the decorated function to build the page (default: 3.0 seconds)
5760 :param reconnect_timeout: maximum time the server waits for the browser to reconnect (defaults to `reconnect_timeout` argument of `run` command))
5861 :param api_router: APIRouter instance to use, can be left `None` to use the default
62+ :param shared: whether all users should see the same page instance (default: ``False``)
5963 :param kwargs: additional keyword arguments passed to FastAPI's @app.get method
6064 """
6165 self ._path = path
@@ -68,6 +72,8 @@ def __init__(self,
6872 self .kwargs = kwargs
6973 self .api_router = api_router or core .app .router
7074 self .reconnect_timeout = reconnect_timeout
75+ self ._shared = shared
76+ self ._shared_client : weakref .ref [Client ] | None = None
7177
7278 create_favicon_route (self .path , favicon )
7379
@@ -152,7 +158,15 @@ async def decorated(*dec_args, **dec_kwargs) -> Response:
152158 request = dec_kwargs ['request' ]
153159 # NOTE cleaning up the keyword args so the signature is consistent with "func" again
154160 dec_kwargs = {k : v for k , v in dec_kwargs .items () if k in parameters_of_decorated_func }
161+
162+ if self ._shared and self ._shared_client and (client := self ._shared_client ()):
163+ client ._request = request # pylint: disable=protected-access
164+ binding ._refresh_step () # pylint: disable=protected-access
165+ return client .build_response (request )
166+
155167 with Client (self , request = request ) as client :
168+ if self ._shared :
169+ self ._shared_client = weakref .ref (client )
156170 if any (p .name == 'client' for p in inspect .signature (func ).parameters .values ()):
157171 dec_kwargs ['client' ] = client
158172 try :
0 commit comments