about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/anyio/abc
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/anyio/abc')
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/abc/__init__.py55
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/abc/_eventloop.py376
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/abc/_resources.py33
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/abc/_sockets.py194
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/abc/_streams.py203
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/abc/_subprocesses.py79
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/abc/_tasks.py101
-rw-r--r--.venv/lib/python3.12/site-packages/anyio/abc/_testing.py65
8 files changed, 1106 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/anyio/abc/__init__.py b/.venv/lib/python3.12/site-packages/anyio/abc/__init__.py
new file mode 100644
index 00000000..3d3b61cc
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/abc/__init__.py
@@ -0,0 +1,55 @@
+from __future__ import annotations
+
+from ._eventloop import AsyncBackend as AsyncBackend
+from ._resources import AsyncResource as AsyncResource
+from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket
+from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket
+from ._sockets import IPAddressType as IPAddressType
+from ._sockets import IPSockAddrType as IPSockAddrType
+from ._sockets import SocketAttribute as SocketAttribute
+from ._sockets import SocketListener as SocketListener
+from ._sockets import SocketStream as SocketStream
+from ._sockets import UDPPacketType as UDPPacketType
+from ._sockets import UDPSocket as UDPSocket
+from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType
+from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket
+from ._sockets import UNIXSocketStream as UNIXSocketStream
+from ._streams import AnyByteReceiveStream as AnyByteReceiveStream
+from ._streams import AnyByteSendStream as AnyByteSendStream
+from ._streams import AnyByteStream as AnyByteStream
+from ._streams import AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream
+from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream
+from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream
+from ._streams import ByteReceiveStream as ByteReceiveStream
+from ._streams import ByteSendStream as ByteSendStream
+from ._streams import ByteStream as ByteStream
+from ._streams import Listener as Listener
+from ._streams import ObjectReceiveStream as ObjectReceiveStream
+from ._streams import ObjectSendStream as ObjectSendStream
+from ._streams import ObjectStream as ObjectStream
+from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream
+from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream
+from ._streams import UnreliableObjectStream as UnreliableObjectStream
+from ._subprocesses import Process as Process
+from ._tasks import TaskGroup as TaskGroup
+from ._tasks import TaskStatus as TaskStatus
+from ._testing import TestRunner as TestRunner
+
+# Re-exported here, for backwards compatibility
+# isort: off
+from .._core._synchronization import (
+    CapacityLimiter as CapacityLimiter,
+    Condition as Condition,
+    Event as Event,
+    Lock as Lock,
+    Semaphore as Semaphore,
+)
+from .._core._tasks import CancelScope as CancelScope
+from ..from_thread import BlockingPortal as BlockingPortal
+
+# Re-export imports so they look like they live directly in this package
+for __value in list(locals().values()):
+    if getattr(__value, "__module__", "").startswith("anyio.abc."):
+        __value.__module__ = __name__
+
+del __value
diff --git a/.venv/lib/python3.12/site-packages/anyio/abc/_eventloop.py b/.venv/lib/python3.12/site-packages/anyio/abc/_eventloop.py
new file mode 100644
index 00000000..4cfce836
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/abc/_eventloop.py
@@ -0,0 +1,376 @@
+from __future__ import annotations
+
+import math
+import sys
+from abc import ABCMeta, abstractmethod
+from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
+from contextlib import AbstractContextManager
+from os import PathLike
+from signal import Signals
+from socket import AddressFamily, SocketKind, socket
+from typing import (
+    IO,
+    TYPE_CHECKING,
+    Any,
+    TypeVar,
+    Union,
+    overload,
+)
+
+if sys.version_info >= (3, 11):
+    from typing import TypeVarTuple, Unpack
+else:
+    from typing_extensions import TypeVarTuple, Unpack
+
+if sys.version_info >= (3, 10):
+    from typing import TypeAlias
+else:
+    from typing_extensions import TypeAlias
+
+if TYPE_CHECKING:
+    from _typeshed import HasFileno
+
+    from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore
+    from .._core._tasks import CancelScope
+    from .._core._testing import TaskInfo
+    from ..from_thread import BlockingPortal
+    from ._sockets import (
+        ConnectedUDPSocket,
+        ConnectedUNIXDatagramSocket,
+        IPSockAddrType,
+        SocketListener,
+        SocketStream,
+        UDPSocket,
+        UNIXDatagramSocket,
+        UNIXSocketStream,
+    )
+    from ._subprocesses import Process
+    from ._tasks import TaskGroup
+    from ._testing import TestRunner
+
+T_Retval = TypeVar("T_Retval")
+PosArgsT = TypeVarTuple("PosArgsT")
+StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"]
+
+
+class AsyncBackend(metaclass=ABCMeta):
+    @classmethod
+    @abstractmethod
+    def run(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+        args: tuple[Unpack[PosArgsT]],
+        kwargs: dict[str, Any],
+        options: dict[str, Any],
+    ) -> T_Retval:
+        """
+        Run the given coroutine function in an asynchronous event loop.
+
+        The current thread must not be already running an event loop.
+
+        :param func: a coroutine function
+        :param args: positional arguments to ``func``
+        :param kwargs: positional arguments to ``func``
+        :param options: keyword arguments to call the backend ``run()`` implementation
+            with
+        :return: the return value of the coroutine function
+        """
+
+    @classmethod
+    @abstractmethod
+    def current_token(cls) -> object:
+        """
+
+        :return:
+        """
+
+    @classmethod
+    @abstractmethod
+    def current_time(cls) -> float:
+        """
+        Return the current value of the event loop's internal clock.
+
+        :return: the clock value (seconds)
+        """
+
+    @classmethod
+    @abstractmethod
+    def cancelled_exception_class(cls) -> type[BaseException]:
+        """Return the exception class that is raised in a task if it's cancelled."""
+
+    @classmethod
+    @abstractmethod
+    async def checkpoint(cls) -> None:
+        """
+        Check if the task has been cancelled, and allow rescheduling of other tasks.
+
+        This is effectively the same as running :meth:`checkpoint_if_cancelled` and then
+        :meth:`cancel_shielded_checkpoint`.
+        """
+
+    @classmethod
+    async def checkpoint_if_cancelled(cls) -> None:
+        """
+        Check if the current task group has been cancelled.
+
+        This will check if the task has been cancelled, but will not allow other tasks
+        to be scheduled if not.
+
+        """
+        if cls.current_effective_deadline() == -math.inf:
+            await cls.checkpoint()
+
+    @classmethod
+    async def cancel_shielded_checkpoint(cls) -> None:
+        """
+        Allow the rescheduling of other tasks.
+
+        This will give other tasks the opportunity to run, but without checking if the
+        current task group has been cancelled, unlike with :meth:`checkpoint`.
+
+        """
+        with cls.create_cancel_scope(shield=True):
+            await cls.sleep(0)
+
+    @classmethod
+    @abstractmethod
+    async def sleep(cls, delay: float) -> None:
+        """
+        Pause the current task for the specified duration.
+
+        :param delay: the duration, in seconds
+        """
+
+    @classmethod
+    @abstractmethod
+    def create_cancel_scope(
+        cls, *, deadline: float = math.inf, shield: bool = False
+    ) -> CancelScope:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def current_effective_deadline(cls) -> float:
+        """
+        Return the nearest deadline among all the cancel scopes effective for the
+        current task.
+
+        :return:
+            - a clock value from the event loop's internal clock
+            - ``inf`` if there is no deadline in effect
+            - ``-inf`` if the current scope has been cancelled
+        :rtype: float
+        """
+
+    @classmethod
+    @abstractmethod
+    def create_task_group(cls) -> TaskGroup:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_event(cls) -> Event:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_lock(cls, *, fast_acquire: bool) -> Lock:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_semaphore(
+        cls,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> Semaphore:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def run_sync_in_worker_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], T_Retval],
+        args: tuple[Unpack[PosArgsT]],
+        abandon_on_cancel: bool = False,
+        limiter: CapacityLimiter | None = None,
+    ) -> T_Retval:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def check_cancelled(cls) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def run_async_from_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+        args: tuple[Unpack[PosArgsT]],
+        token: object,
+    ) -> T_Retval:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def run_sync_from_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], T_Retval],
+        args: tuple[Unpack[PosArgsT]],
+        token: object,
+    ) -> T_Retval:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_blocking_portal(cls) -> BlockingPortal:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def open_process(
+        cls,
+        command: StrOrBytesPath | Sequence[StrOrBytesPath],
+        *,
+        stdin: int | IO[Any] | None,
+        stdout: int | IO[Any] | None,
+        stderr: int | IO[Any] | None,
+        **kwargs: Any,
+    ) -> Process:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def connect_tcp(
+        cls, host: str, port: int, local_address: IPSockAddrType | None = None
+    ) -> SocketStream:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_tcp_listener(cls, sock: socket) -> SocketListener:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_unix_listener(cls, sock: socket) -> SocketListener:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def create_udp_socket(
+        cls,
+        family: AddressFamily,
+        local_address: IPSockAddrType | None,
+        remote_address: IPSockAddrType | None,
+        reuse_port: bool,
+    ) -> UDPSocket | ConnectedUDPSocket:
+        pass
+
+    @classmethod
+    @overload
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket, remote_path: None
+    ) -> UNIXDatagramSocket: ...
+
+    @classmethod
+    @overload
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket, remote_path: str | bytes
+    ) -> ConnectedUNIXDatagramSocket: ...
+
+    @classmethod
+    @abstractmethod
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket, remote_path: str | bytes | None
+    ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def getaddrinfo(
+        cls,
+        host: bytes | str | None,
+        port: str | int | None,
+        *,
+        family: int | AddressFamily = 0,
+        type: int | SocketKind = 0,
+        proto: int = 0,
+        flags: int = 0,
+    ) -> Sequence[
+        tuple[
+            AddressFamily,
+            SocketKind,
+            int,
+            str,
+            tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
+        ]
+    ]:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def getnameinfo(
+        cls, sockaddr: IPSockAddrType, flags: int = 0
+    ) -> tuple[str, str]:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wait_readable(cls, obj: HasFileno | int) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wait_writable(cls, obj: HasFileno | int) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def current_default_thread_limiter(cls) -> CapacityLimiter:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def open_signal_receiver(
+        cls, *signals: Signals
+    ) -> AbstractContextManager[AsyncIterator[Signals]]:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def get_current_task(cls) -> TaskInfo:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def get_running_tasks(cls) -> Sequence[TaskInfo]:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wait_all_tasks_blocked(cls) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
+        pass
diff --git a/.venv/lib/python3.12/site-packages/anyio/abc/_resources.py b/.venv/lib/python3.12/site-packages/anyio/abc/_resources.py
new file mode 100644
index 00000000..10df115a
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/abc/_resources.py
@@ -0,0 +1,33 @@
+from __future__ import annotations
+
+from abc import ABCMeta, abstractmethod
+from types import TracebackType
+from typing import TypeVar
+
+T = TypeVar("T")
+
+
+class AsyncResource(metaclass=ABCMeta):
+    """
+    Abstract base class for all closeable asynchronous resources.
+
+    Works as an asynchronous context manager which returns the instance itself on enter,
+    and calls :meth:`aclose` on exit.
+    """
+
+    __slots__ = ()
+
+    async def __aenter__(self: T) -> T:
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        await self.aclose()
+
+    @abstractmethod
+    async def aclose(self) -> None:
+        """Close the resource."""
diff --git a/.venv/lib/python3.12/site-packages/anyio/abc/_sockets.py b/.venv/lib/python3.12/site-packages/anyio/abc/_sockets.py
new file mode 100644
index 00000000..1c6a450c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/abc/_sockets.py
@@ -0,0 +1,194 @@
+from __future__ import annotations
+
+import socket
+from abc import abstractmethod
+from collections.abc import Callable, Collection, Mapping
+from contextlib import AsyncExitStack
+from io import IOBase
+from ipaddress import IPv4Address, IPv6Address
+from socket import AddressFamily
+from types import TracebackType
+from typing import Any, TypeVar, Union
+
+from .._core._typedattr import (
+    TypedAttributeProvider,
+    TypedAttributeSet,
+    typed_attribute,
+)
+from ._streams import ByteStream, Listener, UnreliableObjectStream
+from ._tasks import TaskGroup
+
+IPAddressType = Union[str, IPv4Address, IPv6Address]
+IPSockAddrType = tuple[str, int]
+SockAddrType = Union[IPSockAddrType, str]
+UDPPacketType = tuple[bytes, IPSockAddrType]
+UNIXDatagramPacketType = tuple[bytes, str]
+T_Retval = TypeVar("T_Retval")
+
+
+class _NullAsyncContextManager:
+    async def __aenter__(self) -> None:
+        pass
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> bool | None:
+        return None
+
+
+class SocketAttribute(TypedAttributeSet):
+    #: the address family of the underlying socket
+    family: AddressFamily = typed_attribute()
+    #: the local socket address of the underlying socket
+    local_address: SockAddrType = typed_attribute()
+    #: for IP addresses, the local port the underlying socket is bound to
+    local_port: int = typed_attribute()
+    #: the underlying stdlib socket object
+    raw_socket: socket.socket = typed_attribute()
+    #: the remote address the underlying socket is connected to
+    remote_address: SockAddrType = typed_attribute()
+    #: for IP addresses, the remote port the underlying socket is connected to
+    remote_port: int = typed_attribute()
+
+
+class _SocketProvider(TypedAttributeProvider):
+    @property
+    def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
+        from .._core._sockets import convert_ipv6_sockaddr as convert
+
+        attributes: dict[Any, Callable[[], Any]] = {
+            SocketAttribute.family: lambda: self._raw_socket.family,
+            SocketAttribute.local_address: lambda: convert(
+                self._raw_socket.getsockname()
+            ),
+            SocketAttribute.raw_socket: lambda: self._raw_socket,
+        }
+        try:
+            peername: tuple[str, int] | None = convert(self._raw_socket.getpeername())
+        except OSError:
+            peername = None
+
+        # Provide the remote address for connected sockets
+        if peername is not None:
+            attributes[SocketAttribute.remote_address] = lambda: peername
+
+        # Provide local and remote ports for IP based sockets
+        if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6):
+            attributes[SocketAttribute.local_port] = (
+                lambda: self._raw_socket.getsockname()[1]
+            )
+            if peername is not None:
+                remote_port = peername[1]
+                attributes[SocketAttribute.remote_port] = lambda: remote_port
+
+        return attributes
+
+    @property
+    @abstractmethod
+    def _raw_socket(self) -> socket.socket:
+        pass
+
+
+class SocketStream(ByteStream, _SocketProvider):
+    """
+    Transports bytes over a socket.
+
+    Supports all relevant extra attributes from :class:`~SocketAttribute`.
+    """
+
+
+class UNIXSocketStream(SocketStream):
+    @abstractmethod
+    async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
+        """
+        Send file descriptors along with a message to the peer.
+
+        :param message: a non-empty bytestring
+        :param fds: a collection of files (either numeric file descriptors or open file
+            or socket objects)
+        """
+
+    @abstractmethod
+    async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
+        """
+        Receive file descriptors along with a message from the peer.
+
+        :param msglen: length of the message to expect from the peer
+        :param maxfds: maximum number of file descriptors to expect from the peer
+        :return: a tuple of (message, file descriptors)
+        """
+
+
+class SocketListener(Listener[SocketStream], _SocketProvider):
+    """
+    Listens to incoming socket connections.
+
+    Supports all relevant extra attributes from :class:`~SocketAttribute`.
+    """
+
+    @abstractmethod
+    async def accept(self) -> SocketStream:
+        """Accept an incoming connection."""
+
+    async def serve(
+        self,
+        handler: Callable[[SocketStream], Any],
+        task_group: TaskGroup | None = None,
+    ) -> None:
+        from .. import create_task_group
+
+        async with AsyncExitStack() as stack:
+            if task_group is None:
+                task_group = await stack.enter_async_context(create_task_group())
+
+            while True:
+                stream = await self.accept()
+                task_group.start_soon(handler, stream)
+
+
+class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider):
+    """
+    Represents an unconnected UDP socket.
+
+    Supports all relevant extra attributes from :class:`~SocketAttribute`.
+    """
+
+    async def sendto(self, data: bytes, host: str, port: int) -> None:
+        """
+        Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))).
+
+        """
+        return await self.send((data, (host, port)))
+
+
+class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider):
+    """
+    Represents an connected UDP socket.
+
+    Supports all relevant extra attributes from :class:`~SocketAttribute`.
+    """
+
+
+class UNIXDatagramSocket(
+    UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider
+):
+    """
+    Represents an unconnected Unix datagram socket.
+
+    Supports all relevant extra attributes from :class:`~SocketAttribute`.
+    """
+
+    async def sendto(self, data: bytes, path: str) -> None:
+        """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, path))."""
+        return await self.send((data, path))
+
+
+class ConnectedUNIXDatagramSocket(UnreliableObjectStream[bytes], _SocketProvider):
+    """
+    Represents a connected Unix datagram socket.
+
+    Supports all relevant extra attributes from :class:`~SocketAttribute`.
+    """
diff --git a/.venv/lib/python3.12/site-packages/anyio/abc/_streams.py b/.venv/lib/python3.12/site-packages/anyio/abc/_streams.py
new file mode 100644
index 00000000..f11d97b5
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/abc/_streams.py
@@ -0,0 +1,203 @@
+from __future__ import annotations
+
+from abc import abstractmethod
+from collections.abc import Callable
+from typing import Any, Generic, TypeVar, Union
+
+from .._core._exceptions import EndOfStream
+from .._core._typedattr import TypedAttributeProvider
+from ._resources import AsyncResource
+from ._tasks import TaskGroup
+
+T_Item = TypeVar("T_Item")
+T_co = TypeVar("T_co", covariant=True)
+T_contra = TypeVar("T_contra", contravariant=True)
+
+
+class UnreliableObjectReceiveStream(
+    Generic[T_co], AsyncResource, TypedAttributeProvider
+):
+    """
+    An interface for receiving objects.
+
+    This interface makes no guarantees that the received messages arrive in the order in
+    which they were sent, or that no messages are missed.
+
+    Asynchronously iterating over objects of this type will yield objects matching the
+    given type parameter.
+    """
+
+    def __aiter__(self) -> UnreliableObjectReceiveStream[T_co]:
+        return self
+
+    async def __anext__(self) -> T_co:
+        try:
+            return await self.receive()
+        except EndOfStream:
+            raise StopAsyncIteration
+
+    @abstractmethod
+    async def receive(self) -> T_co:
+        """
+        Receive the next item.
+
+        :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly
+            closed
+        :raises ~anyio.EndOfStream: if this stream has been closed from the other end
+        :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable
+            due to external causes
+        """
+
+
+class UnreliableObjectSendStream(
+    Generic[T_contra], AsyncResource, TypedAttributeProvider
+):
+    """
+    An interface for sending objects.
+
+    This interface makes no guarantees that the messages sent will reach the
+    recipient(s) in the same order in which they were sent, or at all.
+    """
+
+    @abstractmethod
+    async def send(self, item: T_contra) -> None:
+        """
+        Send an item to the peer(s).
+
+        :param item: the item to send
+        :raises ~anyio.ClosedResourceError: if the send stream has been explicitly
+            closed
+        :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable
+            due to external causes
+        """
+
+
+class UnreliableObjectStream(
+    UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item]
+):
+    """
+    A bidirectional message stream which does not guarantee the order or reliability of
+    message delivery.
+    """
+
+
+class ObjectReceiveStream(UnreliableObjectReceiveStream[T_co]):
+    """
+    A receive message stream which guarantees that messages are received in the same
+    order in which they were sent, and that no messages are missed.
+    """
+
+
+class ObjectSendStream(UnreliableObjectSendStream[T_contra]):
+    """
+    A send message stream which guarantees that messages are delivered in the same order
+    in which they were sent, without missing any messages in the middle.
+    """
+
+
+class ObjectStream(
+    ObjectReceiveStream[T_Item],
+    ObjectSendStream[T_Item],
+    UnreliableObjectStream[T_Item],
+):
+    """
+    A bidirectional message stream which guarantees the order and reliability of message
+    delivery.
+    """
+
+    @abstractmethod
+    async def send_eof(self) -> None:
+        """
+        Send an end-of-file indication to the peer.
+
+        You should not try to send any further data to this stream after calling this
+        method. This method is idempotent (does nothing on successive calls).
+        """
+
+
+class ByteReceiveStream(AsyncResource, TypedAttributeProvider):
+    """
+    An interface for receiving bytes from a single peer.
+
+    Iterating this byte stream will yield a byte string of arbitrary length, but no more
+    than 65536 bytes.
+    """
+
+    def __aiter__(self) -> ByteReceiveStream:
+        return self
+
+    async def __anext__(self) -> bytes:
+        try:
+            return await self.receive()
+        except EndOfStream:
+            raise StopAsyncIteration
+
+    @abstractmethod
+    async def receive(self, max_bytes: int = 65536) -> bytes:
+        """
+        Receive at most ``max_bytes`` bytes from the peer.
+
+        .. note:: Implementers of this interface should not return an empty
+            :class:`bytes` object, and users should ignore them.
+
+        :param max_bytes: maximum number of bytes to receive
+        :return: the received bytes
+        :raises ~anyio.EndOfStream: if this stream has been closed from the other end
+        """
+
+
+class ByteSendStream(AsyncResource, TypedAttributeProvider):
+    """An interface for sending bytes to a single peer."""
+
+    @abstractmethod
+    async def send(self, item: bytes) -> None:
+        """
+        Send the given bytes to the peer.
+
+        :param item: the bytes to send
+        """
+
+
+class ByteStream(ByteReceiveStream, ByteSendStream):
+    """A bidirectional byte stream."""
+
+    @abstractmethod
+    async def send_eof(self) -> None:
+        """
+        Send an end-of-file indication to the peer.
+
+        You should not try to send any further data to this stream after calling this
+        method. This method is idempotent (does nothing on successive calls).
+        """
+
+
+#: Type alias for all unreliable bytes-oriented receive streams.
+AnyUnreliableByteReceiveStream = Union[
+    UnreliableObjectReceiveStream[bytes], ByteReceiveStream
+]
+#: Type alias for all unreliable bytes-oriented send streams.
+AnyUnreliableByteSendStream = Union[UnreliableObjectSendStream[bytes], ByteSendStream]
+#: Type alias for all unreliable bytes-oriented streams.
+AnyUnreliableByteStream = Union[UnreliableObjectStream[bytes], ByteStream]
+#: Type alias for all bytes-oriented receive streams.
+AnyByteReceiveStream = Union[ObjectReceiveStream[bytes], ByteReceiveStream]
+#: Type alias for all bytes-oriented send streams.
+AnyByteSendStream = Union[ObjectSendStream[bytes], ByteSendStream]
+#: Type alias for all bytes-oriented streams.
+AnyByteStream = Union[ObjectStream[bytes], ByteStream]
+
+
+class Listener(Generic[T_co], AsyncResource, TypedAttributeProvider):
+    """An interface for objects that let you accept incoming connections."""
+
+    @abstractmethod
+    async def serve(
+        self, handler: Callable[[T_co], Any], task_group: TaskGroup | None = None
+    ) -> None:
+        """
+        Accept incoming connections as they come in and start tasks to handle them.
+
+        :param handler: a callable that will be used to handle each accepted connection
+        :param task_group: the task group that will be used to start tasks for handling
+            each accepted connection (if omitted, an ad-hoc task group will be created)
+        """
diff --git a/.venv/lib/python3.12/site-packages/anyio/abc/_subprocesses.py b/.venv/lib/python3.12/site-packages/anyio/abc/_subprocesses.py
new file mode 100644
index 00000000..ce0564ce
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/abc/_subprocesses.py
@@ -0,0 +1,79 @@
+from __future__ import annotations
+
+from abc import abstractmethod
+from signal import Signals
+
+from ._resources import AsyncResource
+from ._streams import ByteReceiveStream, ByteSendStream
+
+
+class Process(AsyncResource):
+    """An asynchronous version of :class:`subprocess.Popen`."""
+
+    @abstractmethod
+    async def wait(self) -> int:
+        """
+        Wait until the process exits.
+
+        :return: the exit code of the process
+        """
+
+    @abstractmethod
+    def terminate(self) -> None:
+        """
+        Terminates the process, gracefully if possible.
+
+        On Windows, this calls ``TerminateProcess()``.
+        On POSIX systems, this sends ``SIGTERM`` to the process.
+
+        .. seealso:: :meth:`subprocess.Popen.terminate`
+        """
+
+    @abstractmethod
+    def kill(self) -> None:
+        """
+        Kills the process.
+
+        On Windows, this calls ``TerminateProcess()``.
+        On POSIX systems, this sends ``SIGKILL`` to the process.
+
+        .. seealso:: :meth:`subprocess.Popen.kill`
+        """
+
+    @abstractmethod
+    def send_signal(self, signal: Signals) -> None:
+        """
+        Send a signal to the subprocess.
+
+        .. seealso:: :meth:`subprocess.Popen.send_signal`
+
+        :param signal: the signal number (e.g. :data:`signal.SIGHUP`)
+        """
+
+    @property
+    @abstractmethod
+    def pid(self) -> int:
+        """The process ID of the process."""
+
+    @property
+    @abstractmethod
+    def returncode(self) -> int | None:
+        """
+        The return code of the process. If the process has not yet terminated, this will
+        be ``None``.
+        """
+
+    @property
+    @abstractmethod
+    def stdin(self) -> ByteSendStream | None:
+        """The stream for the standard input of the process."""
+
+    @property
+    @abstractmethod
+    def stdout(self) -> ByteReceiveStream | None:
+        """The stream for the standard output of the process."""
+
+    @property
+    @abstractmethod
+    def stderr(self) -> ByteReceiveStream | None:
+        """The stream for the standard error output of the process."""
diff --git a/.venv/lib/python3.12/site-packages/anyio/abc/_tasks.py b/.venv/lib/python3.12/site-packages/anyio/abc/_tasks.py
new file mode 100644
index 00000000..f6e5c40c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/abc/_tasks.py
@@ -0,0 +1,101 @@
+from __future__ import annotations
+
+import sys
+from abc import ABCMeta, abstractmethod
+from collections.abc import Awaitable, Callable
+from types import TracebackType
+from typing import TYPE_CHECKING, Any, Protocol, TypeVar, overload
+
+if sys.version_info >= (3, 11):
+    from typing import TypeVarTuple, Unpack
+else:
+    from typing_extensions import TypeVarTuple, Unpack
+
+if TYPE_CHECKING:
+    from .._core._tasks import CancelScope
+
+T_Retval = TypeVar("T_Retval")
+T_contra = TypeVar("T_contra", contravariant=True)
+PosArgsT = TypeVarTuple("PosArgsT")
+
+
+class TaskStatus(Protocol[T_contra]):
+    @overload
+    def started(self: TaskStatus[None]) -> None: ...
+
+    @overload
+    def started(self, value: T_contra) -> None: ...
+
+    def started(self, value: T_contra | None = None) -> None:
+        """
+        Signal that the task has started.
+
+        :param value: object passed back to the starter of the task
+        """
+
+
+class TaskGroup(metaclass=ABCMeta):
+    """
+    Groups several asynchronous tasks together.
+
+    :ivar cancel_scope: the cancel scope inherited by all child tasks
+    :vartype cancel_scope: CancelScope
+
+    .. note:: On asyncio, support for eager task factories is considered to be
+        **experimental**. In particular, they don't follow the usual semantics of new
+        tasks being scheduled on the next iteration of the event loop, and may thus
+        cause unexpected behavior in code that wasn't written with such semantics in
+        mind.
+    """
+
+    cancel_scope: CancelScope
+
+    @abstractmethod
+    def start_soon(
+        self,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[Any]],
+        *args: Unpack[PosArgsT],
+        name: object = None,
+    ) -> None:
+        """
+        Start a new task in this task group.
+
+        :param func: a coroutine function
+        :param args: positional arguments to call the function with
+        :param name: name of the task, for the purposes of introspection and debugging
+
+        .. versionadded:: 3.0
+        """
+
+    @abstractmethod
+    async def start(
+        self,
+        func: Callable[..., Awaitable[Any]],
+        *args: object,
+        name: object = None,
+    ) -> Any:
+        """
+        Start a new task and wait until it signals for readiness.
+
+        :param func: a coroutine function
+        :param args: positional arguments to call the function with
+        :param name: name of the task, for the purposes of introspection and debugging
+        :return: the value passed to ``task_status.started()``
+        :raises RuntimeError: if the task finishes without calling
+            ``task_status.started()``
+
+        .. versionadded:: 3.0
+        """
+
+    @abstractmethod
+    async def __aenter__(self) -> TaskGroup:
+        """Enter the task group context and allow starting new tasks."""
+
+    @abstractmethod
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> bool | None:
+        """Exit the task group context waiting for all tasks to finish."""
diff --git a/.venv/lib/python3.12/site-packages/anyio/abc/_testing.py b/.venv/lib/python3.12/site-packages/anyio/abc/_testing.py
new file mode 100644
index 00000000..7c50ed76
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/anyio/abc/_testing.py
@@ -0,0 +1,65 @@
+from __future__ import annotations
+
+import types
+from abc import ABCMeta, abstractmethod
+from collections.abc import AsyncGenerator, Callable, Coroutine, Iterable
+from typing import Any, TypeVar
+
+_T = TypeVar("_T")
+
+
+class TestRunner(metaclass=ABCMeta):
+    """
+    Encapsulates a running event loop. Every call made through this object will use the
+    same event loop.
+    """
+
+    def __enter__(self) -> TestRunner:
+        return self
+
+    @abstractmethod
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: types.TracebackType | None,
+    ) -> bool | None: ...
+
+    @abstractmethod
+    def run_asyncgen_fixture(
+        self,
+        fixture_func: Callable[..., AsyncGenerator[_T, Any]],
+        kwargs: dict[str, Any],
+    ) -> Iterable[_T]:
+        """
+        Run an async generator fixture.
+
+        :param fixture_func: the fixture function
+        :param kwargs: keyword arguments to call the fixture function with
+        :return: an iterator yielding the value yielded from the async generator
+        """
+
+    @abstractmethod
+    def run_fixture(
+        self,
+        fixture_func: Callable[..., Coroutine[Any, Any, _T]],
+        kwargs: dict[str, Any],
+    ) -> _T:
+        """
+        Run an async fixture.
+
+        :param fixture_func: the fixture function
+        :param kwargs: keyword arguments to call the fixture function with
+        :return: the return value of the fixture function
+        """
+
+    @abstractmethod
+    def run_test(
+        self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
+    ) -> None:
+        """
+        Run an async test function.
+
+        :param test_func: the test function
+        :param kwargs: keyword arguments to call the test function with
+        """