codestare.async_utils.nursery module¶
- class codestare.async_utils.nursery.ExcInfo(exc_type: Optional[Type[Exception]] = None, exc: Optional[Exception] = None, traceback: Optional[Any] = None)¶
Bases:
NamedTupleAs returned by
sys.exc_info()
- codestare.async_utils.nursery.mark_sentinel_task(task: Task) Task¶
The package keeps a global reference to all tasks marked as a sentinel task i.e. they will not be garbage collected even if they are finished. Those tasks will be stopped before other tasks if you set up the shutdown handling with this module. These tasks are used by the
TaskNurseryto trigger the nursery’s shutdown by simply canceling / stopping thesentinel_task.When a
shutdown()task is created (e.g. when a specific signal is received), all sentinel tasks will be stopped first – this will trigger the shutdown of allTaskNurserysthat were created in the running interpreter.- Parameters:
task – will be globally referenced to be shut down eventually
- Returns:
the task
- codestare.async_utils.nursery.handle_exception(loop: AbstractEventLoop, context) None¶
Calls the loops default exception handler, then creates a
shutdown()task for the loop. This is the default exception handler that is set up for a loop withsetup_shutdown_handling()if no other specific exception handler is set.- Parameters:
loop – event loop to shut down
context – meta information for
shutdown()task
- async codestare.async_utils.nursery.stop_task(task: Task) Any¶
Try to cancel the task, and await it – returns possible exceptions raised inside the task, e.g. the
asyncio.CancelledErrorraised by canceling the task prematurely.- Parameters:
task – task to stop, can’t be the current running task
- Returns:
result of task
- Raises:
ValueError – if the currently running task is passed
- codestare.async_utils.nursery.setup_shutdown_handling(loop: AbstractEventLoop) None¶
Add signal handling and exception handling for the loop. On Windows only
signal.SIGBREAKandsignal.SIGINTare usable, on Linux add handling forsignal.SIGHUP,signal.SIGTERMandsignal.SIGINT.Uses normal signal handlers using
signalexcept ofasyncio.loop.add_signal_handler()since the latter is not available on Windows systems.The signal handlers registered start a
shutdown()task for the passedloop. Also setshandle_exception()as the loop’s exception handler if no other handler is already set.- Parameters:
loop – event loop
- async codestare.async_utils.nursery.shutdown(loop: AbstractEventLoop, **kwargs) None¶
Await shutdown of the loop.
If the
shutdown()task is triggered by an exception from a task managed by aTaskNursery, the**kwargswill contain a reference to the nursery’ssentinel_taskin thecontextargument. If this is the case, this sentinel task will be stopped (usingstop_task()) which triggers trigger the shutdown handling of theTaskNursery.If the
shutdown()task is triggered by a signal handler, all tasksmarked as sentinel taskswill be stopped first, instead.Finally all tasks still running in the
loopwill be stopped. Then the loop will bestopped.- Parameters:
loop – event loop that needs to be stopped
**kwargs – meta information like received signal or exception context
- class codestare.async_utils.nursery.TaskNursery(name: str | Callable[[], str] | None = None, loop: asyncio.BaseEventLoop | None = None)¶
Bases:
AsyncExitStack,RegistryUse a
TaskNurseryto create and manage tasks, instead of using theasyncio.loop.create_task()method directly.All tasks created by a nursery receive a callback to execute when they finish, which will trigger a graceful shutdown of the event loop if necessary – this saves a lot of boilerplate code
Basically, a
TaskNurseryis acontextlib.AsyncExitStackthat gets closed when it’ssentinel_taskis cancelled. This means you can enter any number of async context managers with a nursery, and every one of them will be closed when the nursery shuts down.Creating a
TaskNurseryfor an event loop also sets up signal handling and exception handling for that loop, i.e. if a loop has an activeTaskNurseryexiting the interpreter forcefully (e.g.Ctrl+Cin the shell) will gracefully shut down all nurseries first.TaskNurseryis aRegistrywith unique attributenameby default, i.e. all instances need to have a unique name and can be referenced by name using theTaskNursery.registry>>> from codestare.async_utils import TaskNursery >>> import asyncio >>> loop = asyncio.get_event_loop_policy().get_event_loop() >>> nursery = TaskNursery(name="Foo", loop=loop) >>> TaskNursery.registry {'Foo': codestare.async_utils.nursery.TaskNursery(name='Foo', loop=<...>)}
- registry¶
Inherited from
codestare.async_utils.helper.Registry
- static add_shutdown_handling(loop: AbstractEventLoop) None¶
Add shutdown handling to the loop, once. Caches loops that were passed as argument to this method, additional calls with the same loop will be ignored.
- Parameters:
loop – gets shutdown handling applied with
setup_shutdown_handling()
- stop_task(task: Task)¶
Try to stop a task managed by this nursery using
stop_task()- Parameters:
task – should be stopped
- Returns:
result of
stop_task()- Raises:
ValueError – if the task is not managed by this nursery i.e. it was not created by
create_task()
- __init__(name: str | Callable[[], str] | None = None, loop: asyncio.BaseEventLoop | None = None)¶
Creates a nursery on the loop – or the current running loop.
- Parameters:
name – if a callable is used, the name can be dynamic
loop – if no loop is passed the running loop is used
- loop: BaseEventLoop¶
Event loop instance to start tasks in, either passed as
loopor current running loop
- sentinel_task: Task¶
Dummy task that does nothing but cancelling it triggers the closing of this
TaskNurseryi.e. all entered async contexts will be closed and all created tasks will be stopped.
- property name¶
Unique name of nursery, used as
Registrykey by default, see__unique_key_attr__. If a callable is passed as name during initialization, this callable is used to compute the name dynamically.
- property tasks¶
Reference to managed tasks
- pop_all() TaskNursery¶
Preserve the context stack by transferring it to a new instance.
- create_task(coro: Generator[_TaskYieldType, None, T] | Awaitable[T], **kwargs) asyncio.Task[T]¶
Tasks created with this method have a callback which runs when the task finishes and tries to retrieve the task result. If the task raised an error the
loopsexception handler is called with the exception info and a reference to this nursery’ssentinel_task. Typically, the exception handler ishandle_exception()(it is set as exception handler when theTaskNurseryis created for a loop without specific exception handler). It will cancel the sentinel task and trigger the nursery’s shutdown.- Parameters:
coro – Coroutine which should run inside the task
**kwargs – passed to
asyncio.loop.create_task()
- Returns:
reference to created task