Add a new `.trionics._tn` for "task nursery stuff"

Since I'd like to decouple the new "task-manager-nursery" lowlevel
primitives/abstractions from the higher-level
`TaskManagerNursery`-supporting API(s) and default per-task
supervision-strat and because `._mngr` is already purposed for
higher-level "on-top-of-nursery" patterns as it is.

Deats,
- move `maybe_open_nursery()` into the new mod.
- adjust the pkg-mod's import to the new sub-mod.
- also draft up this idea for an API which stacks `._beg.collapse_eg()`
  onto a nursery with the WIP name `open_loose_tn()` but more then
  likely i'll just discard this idea bc i think the explicit `@acm`
  stacking is more explicit/pythonic/up-front-grokable despite the extra
  LoC.
oco_supervisor_prototype
Tyler Goodlet 2025-05-07 21:08:05 -04:00
parent d6066705e3
commit 3acf69be8b
3 changed files with 97 additions and 29 deletions

View File

@ -21,7 +21,6 @@ Sugary patterns for trio + tractor designs.
from ._mngrs import ( from ._mngrs import (
gather_contexts as gather_contexts, gather_contexts as gather_contexts,
maybe_open_context as maybe_open_context, maybe_open_context as maybe_open_context,
maybe_open_nursery as maybe_open_nursery,
) )
from ._broadcast import ( from ._broadcast import (
AsyncReceiver as AsyncReceiver, AsyncReceiver as AsyncReceiver,
@ -33,3 +32,6 @@ from ._beg import (
collapse_eg as collapse_eg, collapse_eg as collapse_eg,
maybe_collapse_eg as maybe_collapse_eg, maybe_collapse_eg as maybe_collapse_eg,
) )
from ._tn import (
maybe_open_nursery as maybe_open_nursery,
)

View File

@ -23,7 +23,6 @@ from contextlib import (
asynccontextmanager as acm, asynccontextmanager as acm,
) )
import inspect import inspect
from types import ModuleType
from typing import ( from typing import (
Any, Any,
AsyncContextManager, AsyncContextManager,
@ -34,16 +33,12 @@ from typing import (
Optional, Optional,
Sequence, Sequence,
TypeVar, TypeVar,
TYPE_CHECKING,
) )
import trio import trio
from tractor._state import current_actor from tractor._state import current_actor
from tractor.log import get_logger from tractor.log import get_logger
if TYPE_CHECKING:
from tractor import ActorNursery
log = get_logger(__name__) log = get_logger(__name__)
@ -51,29 +46,6 @@ log = get_logger(__name__)
T = TypeVar("T") T = TypeVar("T")
@acm
async def maybe_open_nursery(
nursery: trio.Nursery|ActorNursery|None = None,
shield: bool = False,
lib: ModuleType = trio,
**kwargs, # proxy thru
) -> AsyncGenerator[trio.Nursery, Any]:
'''
Create a new nursery if None provided.
Blocks on exit as expected if no input nursery is provided.
'''
if nursery is not None:
yield nursery
else:
async with lib.open_nursery(**kwargs) as nursery:
nursery.cancel_scope.shield = shield
yield nursery
async def _enter_and_wait( async def _enter_and_wait(
mngr: AsyncContextManager[T], mngr: AsyncContextManager[T],
unwrapped: dict[int, T], unwrapped: dict[int, T],

View File

@ -0,0 +1,94 @@
# tractor: structured concurrent "actors".
# Copyright 2018-eternity Tyler Goodlet.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
`trio.Nursery` wrappers which we short-hand refer to as
`tn`: "task nursery".
(whereas we refer to `tractor.ActorNursery` as the short-hand `an`)
'''
from __future__ import annotations
from contextlib import (
asynccontextmanager as acm,
)
from types import ModuleType
from typing import (
Any,
AsyncGenerator,
TYPE_CHECKING,
)
import trio
from tractor.log import get_logger
# from ._beg import (
# collapse_eg,
# )
if TYPE_CHECKING:
from tractor import ActorNursery
log = get_logger(__name__)
# ??TODO? is this even a good idea??
# it's an extra LoC to stack `collapse_eg()` vs.
# a new/foreign/bad-std-named very thing wrapper..?
# -[ ] is there a better/simpler name?
# @acm
# async def open_loose_tn() -> trio.Nursery:
# '''
# Implements the equivalent of the old style loose eg raising
# task-nursery from `trio<=0.25.0` ,
# .. code-block:: python
# async with trio.open_nursery(
# strict_exception_groups=False,
# ) as tn:
# ...
# '''
# async with (
# collapse_eg(),
# trio.open_nursery() as tn,
# ):
# yield tn
@acm
async def maybe_open_nursery(
nursery: trio.Nursery|ActorNursery|None = None,
shield: bool = False,
lib: ModuleType = trio,
loose: bool = False,
**kwargs, # proxy thru
) -> AsyncGenerator[trio.Nursery, Any]:
'''
Create a new nursery if None provided.
Blocks on exit as expected if no input nursery is provided.
'''
if nursery is not None:
yield nursery
else:
async with lib.open_nursery(**kwargs) as tn:
tn.cancel_scope.shield = shield
yield tn