GitHub

CloseableScope

API reference for CloseableScope.

A scope that can be closed. Use through the Scope tag.

Finalizers are keyed, so whatever registered one can take it back when it no longer needs it: a child scope leaves its parent when it closes, and a fork_scoped fiber leaves its scope when it exits. A "parallel" scope runs its finalizers concurrently on close.

Attributes

AttributeTypeDescription
finalizer_countint

How many finalizers are registered and not yet run.

is_emptybool

Open with no finalizers, so it can be handed on for reuse (Effect's Empty state). A closed scope is never empty.

is_closedbool

Whether close has started (later finalizers run at once).

Functions

__init__

__init__(strategy='sequential') -> None
ParameterTypeDescription
strategyStrategy = 'sequential'
def __init__(self, strategy: Strategy = "sequential") -> None:
    self._strategy: Strategy = strategy
    self._finalizers: dict[object, Finalizer] = {}
    self._closed: Exit[Any, Any] | None = None
    self._parent: CloseableScope | None = None

add_finalizer

add_finalizer(f) -> Effect[None]

Register f to run on close, with the services in scope now. If the scope is already closed, f runs immediately.

ParameterTypeDescription
fCallable[[Exit[Any, Any]], Effect[object, Never, Any]]

Returns Effect[None]

def add_finalizer(
    self, f: Callable[[Exit[Any, Any]], Effect[object, Never, Any]]
) -> Effect[None]:
    """Register ``f`` to run on close, with the services in scope now.
    If the scope is already closed, ``f`` runs immediately."""

    def body(fiber: Fiber[Any, Any]) -> Effect[None]:
        ctx = fiber._context

        # As Effect's ``provideContext``: the closing fiber's services,
        # overridden by those in scope at registration.
        def finalizer(ex: Exit[Any, Any]) -> Effect[object, Never, Any]:
            return _Locally(_call_user(f, ex), lambda current: current.merge(ctx))

        if self._closed is not None:
            return finalizer(self._closed).as_void()
        self._add(object(), finalizer)
        return _Succeed(None)

    return _WithFiber(body)

close

close(ex) -> Effect[None]

Run every finalizer, last added first (all at once in a parallel scope). Closing twice is a no-op.

ParameterTypeDescription
exExit[Any, Any]

Returns Effect[None]

def close(self, ex: Exit[Any, Any]) -> Effect[None]:
    """Run every finalizer, last added first (all at once in a parallel
    scope). Closing twice is a no-op."""

    # Uninterruptible before the scope is marked closed, so an interrupt
    # can't land between marking it and running its finalizers.
    return _Suspend(lambda: self.close_unsafe(ex) or _Succeed(None)).uninterruptible()

close_unsafe

close_unsafe(ex) -> Effect[None] | None

Mark the scope closed now and return the effect that runs its finalizers, or None if it was closed already or had none. The caller must run the effect uninterruptibly (Effect's closeUnsafe).

ParameterTypeDescription
exExit[Any, Any]

Returns Effect[None] | None

def close_unsafe(self, ex: Exit[Any, Any]) -> Effect[None] | None:
    """Mark the scope closed now and return the effect that runs its
    finalizers, or ``None`` if it was closed already or had none. The
    caller must run the effect uninterruptibly (Effect's ``closeUnsafe``)."""
    if self._closed is not None:
        return None
    self._closed = ex
    if self._parent is not None:
        self._parent._remove(self)
    if not self._finalizers:
        return None
    entries = list(reversed(self._finalizers.items()))
    self._finalizers = {}
    run = _run_parallel if self._strategy == "parallel" else _run_sequential
    return run(entries, ex)

fork

fork(strategy='sequential') -> Effect[CloseableScope]

A child scope, closed when this one closes (if not before). The child of a closed scope starts closed.

ParameterTypeDescription
strategyStrategy = 'sequential'

Returns Effect[CloseableScope]

def fork(self, strategy: Strategy = "sequential") -> Effect[CloseableScope]:
    """A child scope, closed when this one closes (if not before). The
    child of a closed scope starts closed."""

    return _Sync(lambda: self._fork_now(strategy))