11"""Reactive components"""
22
3- __all__ = ("Value" , "Calc" , "CalcAsync " , "calc " , "Effect" , "EffectAsync" , "effect " )
3+ __all__ = ("Value" , "Calc" , "Calc_ " , "CalcAsync_ " , "Effect" , "Effect_ " )
44
55import traceback
66from typing import (
@@ -68,7 +68,7 @@ def _set(self, value: T) -> bool:
6868CalcFunctionAsync = Callable [[], Awaitable [T ]]
6969
7070
71- class Calc (Generic [T ]):
71+ class Calc_ (Generic [T ]):
7272 def __init__ (
7373 self ,
7474 fn : CalcFunction [T ],
@@ -82,7 +82,7 @@ def __init__(
8282 # static type checker that it's synchronous. wrap_async() is smart -- if is
8383 # passed an async function, it will not change it.
8484 self ._fn : CalcFunctionAsync [T ] = _utils .wrap_async (fn )
85- self ._is_async : bool = False
85+ self ._is_async : bool = _utils . is_async_callable ( fn )
8686
8787 self ._dependents : Dependents = Dependents ()
8888 self ._invalidated : bool = True
@@ -96,11 +96,11 @@ def __init__(
9696 # the type checker doesn't know that MISSING is the only instance of
9797 # MISSING_TYPE; this saves us from casting later on.
9898 if isinstance (session , MISSING_TYPE ):
99- import shiny . session
99+ from .. session import get_current_session
100100
101101 # If no session is provided, autodetect the current session (this
102102 # could be None if outside of a session).
103- session = shiny . session . get_current_session ()
103+ session = get_current_session ()
104104 self ._session = session
105105
106106 # Use lists to hold (optional) value and error, instead of Optional[T],
@@ -139,9 +139,9 @@ async def update_value(self) -> None:
139139 was_running = self ._running
140140 self ._running = True
141141
142- import shiny . session
142+ from .. session import session_context
143143
144- with shiny . session . session_context (self ._session ):
144+ with session_context (self ._session ):
145145 try :
146146 with self ._ctx ():
147147 await self ._run_func ()
@@ -162,7 +162,7 @@ async def _run_func(self) -> None:
162162 self ._error .append (err )
163163
164164
165- class CalcAsync ( Calc [T ]):
165+ class CalcAsync_ ( Calc_ [T ]):
166166 def __init__ (
167167 self ,
168168 fn : CalcFunctionAsync [T ],
@@ -173,7 +173,6 @@ def __init__(
173173 raise TypeError (self .__class__ .__name__ + " requires an async function" )
174174
175175 super ().__init__ (cast (CalcFunction [T ], fn ), session = session )
176- self ._is_async = True
177176
178177 async def __call__ (self ) -> T :
179178 return await self .get_value ()
@@ -198,15 +197,15 @@ async def __call__(self) -> T:
198197# twice: once here, and once when we return a Calc object (which has a synchronous
199198# __call__ method) or CalcAsync object (which has an async __call__ method), and it
200199# works out.
201- def calc (
200+ def Calc (
202201 * , session : Union [MISSING_TYPE , "Session" , None ] = MISSING
203- ) -> Callable [[CalcFunction [T ]], Calc [T ]]:
204- def create_calc (fn : Union [CalcFunction [T ], CalcFunctionAsync [T ]]) -> Calc [T ]:
202+ ) -> Callable [[CalcFunction [T ]], Calc_ [T ]]:
203+ def create_calc (fn : Union [CalcFunction [T ], CalcFunctionAsync [T ]]) -> Calc_ [T ]:
205204 if _utils .is_async_callable (fn ):
206- return CalcAsync (fn , session = session )
205+ return CalcAsync_ (fn , session = session )
207206 else :
208207 fn = cast (CalcFunction [T ], fn )
209- return Calc (fn , session = session )
208+ return Calc_ (fn , session = session )
210209
211210 return create_calc
212211
@@ -219,10 +218,10 @@ def create_calc(fn: Union[CalcFunction[T], CalcFunctionAsync[T]]) -> Calc[T]:
219218EffectFunctionAsync = Callable [[], Awaitable [None ]]
220219
221220
222- class Effect :
221+ class Effect_ :
223222 def __init__ (
224223 self ,
225- fn : EffectFunction ,
224+ fn : Union [ EffectFunction , EffectFunctionAsync ] ,
226225 * ,
227226 suspended : bool = False ,
228227 priority : int = 0 ,
@@ -235,7 +234,8 @@ def __init__(
235234 # static type checker that it's synchronous. wrap_async() is smart -- if is
236235 # passed an async function, it will not change it.
237236 self ._fn : EffectFunctionAsync = _utils .wrap_async (fn )
238- self ._is_async : bool = False
237+ # This indicates whether the user's effect function (before wrapping) is async.
238+ self ._is_async : bool = _utils .is_async_callable (fn )
239239
240240 self ._priority : int = priority
241241 self ._suspended = suspended
@@ -251,11 +251,11 @@ def __init__(
251251 # the type checker doesn't know that MISSING is the only instance of
252252 # MISSING_TYPE; this saves us from casting later on.
253253 if isinstance (session , MISSING_TYPE ):
254- import shiny . session
254+ from .. session import get_current_session
255255
256256 # If no session is provided, autodetect the current session (this
257257 # could be None if outside of a session).
258- session = shiny . session . get_current_session ()
258+ session = get_current_session ()
259259 self ._session = session
260260
261261 if self ._session is not None :
@@ -302,9 +302,10 @@ async def on_flush_cb() -> None:
302302 async def run (self ) -> None :
303303 ctx = self ._create_context ()
304304 self ._exec_count += 1
305- import shiny .session
306305
307- with shiny .session .session_context (self ._session ):
306+ from ..session import session_context
307+
308+ with session_context (self ._session ):
308309 try :
309310 with ctx ():
310311 await self ._fn ()
@@ -360,51 +361,14 @@ def _on_session_ended_cb(self) -> None:
360361 self .destroy ()
361362
362363
363- class EffectAsync (Effect ):
364- def __init__ (
365- self ,
366- fn : EffectFunctionAsync ,
367- * ,
368- suspended : bool = False ,
369- priority : int = 0 ,
370- session : Union [MISSING_TYPE , "Session" , None ] = MISSING ,
371- ) -> None :
372- if not _utils .is_async_callable (fn ):
373- raise TypeError (self .__class__ .__name__ + " requires an async function" )
374-
375- super ().__init__ (
376- cast (EffectFunction , fn ),
377- suspended = suspended ,
378- session = session ,
379- priority = priority ,
380- )
381- self ._is_async = True
382-
383-
384- def effect (
364+ def Effect (
385365 * ,
386366 suspended : bool = False ,
387367 priority : int = 0 ,
388368 session : Union [MISSING_TYPE , "Session" , None ] = MISSING ,
389- ) -> Callable [[Union [EffectFunction , EffectFunctionAsync ]], Effect ]:
390- """[summary]
391-
392- Args:
393- priority : [description]. Defaults to 0.
394- session : [description]. Defaults to MISSING.
395-
396- Returns:
397- [description]
398- """
399-
400- def create_effect (fn : Union [EffectFunction , EffectFunctionAsync ]) -> Effect :
401- if _utils .is_async_callable (fn ):
402- fn = cast (EffectFunctionAsync , fn )
403- return EffectAsync (
404- fn , suspended = suspended , priority = priority , session = session
405- )
406- else :
407- fn = cast (EffectFunction , fn )
408- return Effect (fn , suspended = suspended , priority = priority , session = session )
369+ ) -> Callable [[Union [EffectFunction , EffectFunctionAsync ]], Effect_ ]:
370+ def create_effect (fn : Union [EffectFunction , EffectFunctionAsync ]) -> Effect_ :
371+ fn = cast (EffectFunction , fn )
372+ return Effect_ (fn , suspended = suspended , priority = priority , session = session )
409373
410374 return create_effect
0 commit comments