czty commited on
Commit
d20eb70
·
verified ·
1 Parent(s): 1f4762d

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/__init__.py +111 -0
  2. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_backends/__init__.py +0 -0
  3. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_backends/_asyncio.py +0 -0
  4. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_backends/_trio.py +1343 -0
  5. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/__init__.py +0 -0
  6. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_asyncio_selector_thread.py +167 -0
  7. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_contextmanagers.py +200 -0
  8. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_eventloop.py +234 -0
  9. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_exceptions.py +156 -0
  10. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_fileio.py +799 -0
  11. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_resources.py +18 -0
  12. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_signals.py +29 -0
  13. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_sockets.py +1003 -0
  14. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_streams.py +52 -0
  15. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_subprocesses.py +196 -0
  16. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_synchronization.py +757 -0
  17. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_tasks.py +173 -0
  18. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_tempfile.py +613 -0
  19. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_testing.py +82 -0
  20. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_typedattr.py +81 -0
  21. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/__init__.py +58 -0
  22. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_eventloop.py +409 -0
  23. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_resources.py +33 -0
  24. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_sockets.py +399 -0
  25. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_streams.py +233 -0
  26. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_subprocesses.py +79 -0
  27. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_tasks.py +117 -0
  28. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_testing.py +65 -0
  29. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/from_thread.py +578 -0
  30. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/functools.py +409 -0
  31. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/lowlevel.py +196 -0
  32. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/py.typed +0 -0
  33. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/pytest_plugin.py +363 -0
  34. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/__init__.py +0 -0
  35. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/buffered.py +188 -0
  36. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/file.py +154 -0
  37. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/memory.py +325 -0
  38. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/stapled.py +147 -0
  39. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/text.py +176 -0
  40. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/tls.py +421 -0
  41. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/to_interpreter.py +246 -0
  42. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/to_process.py +266 -0
  43. bioagent-bench/.venv/lib/python3.14/site-packages/anyio/to_thread.py +78 -0
  44. bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/INSTALLER +1 -0
  45. bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/METADATA +78 -0
  46. bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/RECORD +12 -0
  47. bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/REQUESTED +0 -0
  48. bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/WHEEL +5 -0
  49. bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/licenses/LICENSE +20 -0
  50. bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/top_level.txt +1 -0
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/__init__.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from ._core._contextmanagers import AsyncContextManagerMixin as AsyncContextManagerMixin
4
+ from ._core._contextmanagers import ContextManagerMixin as ContextManagerMixin
5
+ from ._core._eventloop import current_time as current_time
6
+ from ._core._eventloop import get_all_backends as get_all_backends
7
+ from ._core._eventloop import get_available_backends as get_available_backends
8
+ from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class
9
+ from ._core._eventloop import run as run
10
+ from ._core._eventloop import sleep as sleep
11
+ from ._core._eventloop import sleep_forever as sleep_forever
12
+ from ._core._eventloop import sleep_until as sleep_until
13
+ from ._core._exceptions import BrokenResourceError as BrokenResourceError
14
+ from ._core._exceptions import BrokenWorkerInterpreter as BrokenWorkerInterpreter
15
+ from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess
16
+ from ._core._exceptions import BusyResourceError as BusyResourceError
17
+ from ._core._exceptions import ClosedResourceError as ClosedResourceError
18
+ from ._core._exceptions import ConnectionFailed as ConnectionFailed
19
+ from ._core._exceptions import DelimiterNotFound as DelimiterNotFound
20
+ from ._core._exceptions import EndOfStream as EndOfStream
21
+ from ._core._exceptions import IncompleteRead as IncompleteRead
22
+ from ._core._exceptions import NoEventLoopError as NoEventLoopError
23
+ from ._core._exceptions import RunFinishedError as RunFinishedError
24
+ from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError
25
+ from ._core._exceptions import WouldBlock as WouldBlock
26
+ from ._core._fileio import AsyncFile as AsyncFile
27
+ from ._core._fileio import Path as Path
28
+ from ._core._fileio import open_file as open_file
29
+ from ._core._fileio import wrap_file as wrap_file
30
+ from ._core._resources import aclose_forcefully as aclose_forcefully
31
+ from ._core._signals import open_signal_receiver as open_signal_receiver
32
+ from ._core._sockets import TCPConnectable as TCPConnectable
33
+ from ._core._sockets import UNIXConnectable as UNIXConnectable
34
+ from ._core._sockets import as_connectable as as_connectable
35
+ from ._core._sockets import connect_tcp as connect_tcp
36
+ from ._core._sockets import connect_unix as connect_unix
37
+ from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket
38
+ from ._core._sockets import (
39
+ create_connected_unix_datagram_socket as create_connected_unix_datagram_socket,
40
+ )
41
+ from ._core._sockets import create_tcp_listener as create_tcp_listener
42
+ from ._core._sockets import create_udp_socket as create_udp_socket
43
+ from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket
44
+ from ._core._sockets import create_unix_listener as create_unix_listener
45
+ from ._core._sockets import getaddrinfo as getaddrinfo
46
+ from ._core._sockets import getnameinfo as getnameinfo
47
+ from ._core._sockets import notify_closing as notify_closing
48
+ from ._core._sockets import wait_readable as wait_readable
49
+ from ._core._sockets import wait_socket_readable as wait_socket_readable
50
+ from ._core._sockets import wait_socket_writable as wait_socket_writable
51
+ from ._core._sockets import wait_writable as wait_writable
52
+ from ._core._streams import create_memory_object_stream as create_memory_object_stream
53
+ from ._core._subprocesses import open_process as open_process
54
+ from ._core._subprocesses import run_process as run_process
55
+ from ._core._synchronization import CapacityLimiter as CapacityLimiter
56
+ from ._core._synchronization import (
57
+ CapacityLimiterStatistics as CapacityLimiterStatistics,
58
+ )
59
+ from ._core._synchronization import Condition as Condition
60
+ from ._core._synchronization import ConditionStatistics as ConditionStatistics
61
+ from ._core._synchronization import Event as Event
62
+ from ._core._synchronization import EventStatistics as EventStatistics
63
+ from ._core._synchronization import Lock as Lock
64
+ from ._core._synchronization import LockStatistics as LockStatistics
65
+ from ._core._synchronization import ResourceGuard as ResourceGuard
66
+ from ._core._synchronization import Semaphore as Semaphore
67
+ from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics
68
+ from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED
69
+ from ._core._tasks import CancelScope as CancelScope
70
+ from ._core._tasks import create_task_group as create_task_group
71
+ from ._core._tasks import current_effective_deadline as current_effective_deadline
72
+ from ._core._tasks import fail_after as fail_after
73
+ from ._core._tasks import move_on_after as move_on_after
74
+ from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile
75
+ from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile
76
+ from ._core._tempfile import TemporaryDirectory as TemporaryDirectory
77
+ from ._core._tempfile import TemporaryFile as TemporaryFile
78
+ from ._core._tempfile import gettempdir as gettempdir
79
+ from ._core._tempfile import gettempdirb as gettempdirb
80
+ from ._core._tempfile import mkdtemp as mkdtemp
81
+ from ._core._tempfile import mkstemp as mkstemp
82
+ from ._core._testing import TaskInfo as TaskInfo
83
+ from ._core._testing import get_current_task as get_current_task
84
+ from ._core._testing import get_running_tasks as get_running_tasks
85
+ from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked
86
+ from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider
87
+ from ._core._typedattr import TypedAttributeSet as TypedAttributeSet
88
+ from ._core._typedattr import typed_attribute as typed_attribute
89
+
90
+ # Re-export imports so they look like they live directly in this package
91
+ for __value in list(locals().values()):
92
+ if getattr(__value, "__module__", "").startswith("anyio."):
93
+ __value.__module__ = __name__
94
+
95
+
96
+ del __value
97
+
98
+
99
+ def __getattr__(attr: str) -> type[BrokenWorkerInterpreter]:
100
+ """Support deprecated aliases."""
101
+ if attr == "BrokenWorkerIntepreter":
102
+ import warnings
103
+
104
+ warnings.warn(
105
+ "The 'BrokenWorkerIntepreter' alias is deprecated, use 'BrokenWorkerInterpreter' instead.",
106
+ DeprecationWarning,
107
+ stacklevel=2,
108
+ )
109
+ return BrokenWorkerInterpreter
110
+
111
+ raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_backends/__init__.py ADDED
File without changes
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_backends/_asyncio.py ADDED
The diff for this file is too large to render. See raw diff
 
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_backends/_trio.py ADDED
@@ -0,0 +1,1343 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import array
4
+ import math
5
+ import os
6
+ import socket
7
+ import sys
8
+ import types
9
+ import weakref
10
+ from collections.abc import (
11
+ AsyncGenerator,
12
+ AsyncIterator,
13
+ Awaitable,
14
+ Callable,
15
+ Collection,
16
+ Coroutine,
17
+ Iterable,
18
+ Sequence,
19
+ )
20
+ from contextlib import AbstractContextManager
21
+ from dataclasses import dataclass
22
+ from io import IOBase
23
+ from os import PathLike
24
+ from signal import Signals
25
+ from socket import AddressFamily, SocketKind
26
+ from types import TracebackType
27
+ from typing import (
28
+ IO,
29
+ TYPE_CHECKING,
30
+ Any,
31
+ Generic,
32
+ NoReturn,
33
+ ParamSpec,
34
+ TypeVar,
35
+ cast,
36
+ overload,
37
+ )
38
+
39
+ import trio.from_thread
40
+ import trio.lowlevel
41
+ from outcome import Error, Outcome, Value
42
+ from trio.lowlevel import (
43
+ current_root_task,
44
+ current_task,
45
+ notify_closing,
46
+ wait_readable,
47
+ wait_writable,
48
+ )
49
+ from trio.socket import SocketType as TrioSocketType
50
+ from trio.to_thread import run_sync
51
+
52
+ from .. import (
53
+ CapacityLimiterStatistics,
54
+ EventStatistics,
55
+ LockStatistics,
56
+ RunFinishedError,
57
+ TaskInfo,
58
+ WouldBlock,
59
+ abc,
60
+ )
61
+ from .._core._eventloop import claim_worker_thread
62
+ from .._core._exceptions import (
63
+ BrokenResourceError,
64
+ BusyResourceError,
65
+ ClosedResourceError,
66
+ EndOfStream,
67
+ )
68
+ from .._core._sockets import convert_ipv6_sockaddr
69
+ from .._core._streams import create_memory_object_stream
70
+ from .._core._synchronization import (
71
+ CapacityLimiter as BaseCapacityLimiter,
72
+ )
73
+ from .._core._synchronization import Event as BaseEvent
74
+ from .._core._synchronization import Lock as BaseLock
75
+ from .._core._synchronization import (
76
+ ResourceGuard,
77
+ SemaphoreStatistics,
78
+ )
79
+ from .._core._synchronization import Semaphore as BaseSemaphore
80
+ from .._core._tasks import CancelScope as BaseCancelScope
81
+ from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType
82
+ from ..abc._eventloop import AsyncBackend, StrOrBytesPath
83
+ from ..streams.memory import MemoryObjectSendStream
84
+
85
+ if TYPE_CHECKING:
86
+ from _typeshed import FileDescriptorLike
87
+
88
+ if sys.version_info >= (3, 11):
89
+ from typing import TypeVarTuple, Unpack
90
+ else:
91
+ from exceptiongroup import BaseExceptionGroup
92
+ from typing_extensions import TypeVarTuple, Unpack
93
+
94
+ T = TypeVar("T")
95
+ T_Retval = TypeVar("T_Retval")
96
+ T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType)
97
+ PosArgsT = TypeVarTuple("PosArgsT")
98
+ P = ParamSpec("P")
99
+
100
+
101
+ #
102
+ # Event loop
103
+ #
104
+
105
+ RunVar = trio.lowlevel.RunVar
106
+
107
+
108
+ #
109
+ # Timeouts and cancellation
110
+ #
111
+
112
+
113
+ class CancelScope(BaseCancelScope):
114
+ def __new__(
115
+ cls, original: trio.CancelScope | None = None, **kwargs: object
116
+ ) -> CancelScope:
117
+ return object.__new__(cls)
118
+
119
+ def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None:
120
+ self.__original = original or trio.CancelScope(**kwargs)
121
+
122
+ def __enter__(self) -> CancelScope:
123
+ self.__original.__enter__()
124
+ return self
125
+
126
+ def __exit__(
127
+ self,
128
+ exc_type: type[BaseException] | None,
129
+ exc_val: BaseException | None,
130
+ exc_tb: TracebackType | None,
131
+ ) -> bool:
132
+ return self.__original.__exit__(exc_type, exc_val, exc_tb)
133
+
134
+ def cancel(self, reason: str | None = None) -> None:
135
+ self.__original.cancel(reason)
136
+
137
+ @property
138
+ def deadline(self) -> float:
139
+ return self.__original.deadline
140
+
141
+ @deadline.setter
142
+ def deadline(self, value: float) -> None:
143
+ self.__original.deadline = value
144
+
145
+ @property
146
+ def cancel_called(self) -> bool:
147
+ return self.__original.cancel_called
148
+
149
+ @property
150
+ def cancelled_caught(self) -> bool:
151
+ return self.__original.cancelled_caught
152
+
153
+ @property
154
+ def shield(self) -> bool:
155
+ return self.__original.shield
156
+
157
+ @shield.setter
158
+ def shield(self, value: bool) -> None:
159
+ self.__original.shield = value
160
+
161
+
162
+ #
163
+ # Task groups
164
+ #
165
+
166
+
167
+ class TaskGroup(abc.TaskGroup):
168
+ def __init__(self) -> None:
169
+ self._active = False
170
+ self._nursery_manager = trio.open_nursery(strict_exception_groups=True)
171
+ self.cancel_scope = None # type: ignore[assignment]
172
+
173
+ async def __aenter__(self) -> TaskGroup:
174
+ self._active = True
175
+ self._nursery = await self._nursery_manager.__aenter__()
176
+ self.cancel_scope = CancelScope(self._nursery.cancel_scope)
177
+ return self
178
+
179
+ async def __aexit__(
180
+ self,
181
+ exc_type: type[BaseException] | None,
182
+ exc_val: BaseException | None,
183
+ exc_tb: TracebackType | None,
184
+ ) -> bool:
185
+ try:
186
+ # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type
187
+ return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) # type: ignore[return-value]
188
+ except BaseExceptionGroup as exc:
189
+ if not exc.split(trio.Cancelled)[1]:
190
+ raise trio.Cancelled._create() from exc
191
+
192
+ raise
193
+ finally:
194
+ del exc_val, exc_tb
195
+ self._active = False
196
+
197
+ def start_soon(
198
+ self,
199
+ func: Callable[[Unpack[PosArgsT]], Awaitable[Any]],
200
+ *args: Unpack[PosArgsT],
201
+ name: object = None,
202
+ ) -> None:
203
+ if not self._active:
204
+ raise RuntimeError(
205
+ "This task group is not active; no new tasks can be started."
206
+ )
207
+
208
+ self._nursery.start_soon(func, *args, name=name)
209
+
210
+ async def start(
211
+ self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None
212
+ ) -> Any:
213
+ if not self._active:
214
+ raise RuntimeError(
215
+ "This task group is not active; no new tasks can be started."
216
+ )
217
+
218
+ return await self._nursery.start(func, *args, name=name)
219
+
220
+
221
+ #
222
+ # Subprocesses
223
+ #
224
+
225
+
226
+ @dataclass(eq=False)
227
+ class ReceiveStreamWrapper(abc.ByteReceiveStream):
228
+ _stream: trio.abc.ReceiveStream
229
+
230
+ async def receive(self, max_bytes: int | None = None) -> bytes:
231
+ try:
232
+ data = await self._stream.receive_some(max_bytes)
233
+ except trio.ClosedResourceError as exc:
234
+ raise ClosedResourceError from exc.__cause__
235
+ except trio.BrokenResourceError as exc:
236
+ raise BrokenResourceError from exc.__cause__
237
+
238
+ if data:
239
+ return bytes(data)
240
+ else:
241
+ raise EndOfStream
242
+
243
+ async def aclose(self) -> None:
244
+ await self._stream.aclose()
245
+
246
+
247
+ @dataclass(eq=False)
248
+ class SendStreamWrapper(abc.ByteSendStream):
249
+ _stream: trio.abc.SendStream
250
+
251
+ async def send(self, item: bytes) -> None:
252
+ try:
253
+ await self._stream.send_all(item)
254
+ except trio.ClosedResourceError as exc:
255
+ raise ClosedResourceError from exc.__cause__
256
+ except trio.BrokenResourceError as exc:
257
+ raise BrokenResourceError from exc.__cause__
258
+
259
+ async def aclose(self) -> None:
260
+ await self._stream.aclose()
261
+
262
+
263
+ @dataclass(eq=False)
264
+ class Process(abc.Process):
265
+ _process: trio.Process
266
+ _stdin: abc.ByteSendStream | None
267
+ _stdout: abc.ByteReceiveStream | None
268
+ _stderr: abc.ByteReceiveStream | None
269
+
270
+ async def aclose(self) -> None:
271
+ with CancelScope(shield=True):
272
+ if self._stdin:
273
+ await self._stdin.aclose()
274
+ if self._stdout:
275
+ await self._stdout.aclose()
276
+ if self._stderr:
277
+ await self._stderr.aclose()
278
+
279
+ try:
280
+ await self.wait()
281
+ except BaseException:
282
+ self.kill()
283
+ with CancelScope(shield=True):
284
+ await self.wait()
285
+ raise
286
+
287
+ async def wait(self) -> int:
288
+ return await self._process.wait()
289
+
290
+ def terminate(self) -> None:
291
+ self._process.terminate()
292
+
293
+ def kill(self) -> None:
294
+ self._process.kill()
295
+
296
+ def send_signal(self, signal: Signals) -> None:
297
+ self._process.send_signal(signal)
298
+
299
+ @property
300
+ def pid(self) -> int:
301
+ return self._process.pid
302
+
303
+ @property
304
+ def returncode(self) -> int | None:
305
+ return self._process.returncode
306
+
307
+ @property
308
+ def stdin(self) -> abc.ByteSendStream | None:
309
+ return self._stdin
310
+
311
+ @property
312
+ def stdout(self) -> abc.ByteReceiveStream | None:
313
+ return self._stdout
314
+
315
+ @property
316
+ def stderr(self) -> abc.ByteReceiveStream | None:
317
+ return self._stderr
318
+
319
+
320
+ class _ProcessPoolShutdownInstrument(trio.abc.Instrument):
321
+ def after_run(self) -> None:
322
+ super().after_run()
323
+
324
+
325
+ current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar(
326
+ "current_default_worker_process_limiter"
327
+ )
328
+
329
+
330
+ async def _shutdown_process_pool(workers: set[abc.Process]) -> None:
331
+ try:
332
+ await trio.sleep(math.inf)
333
+ except trio.Cancelled:
334
+ for process in workers:
335
+ if process.returncode is None:
336
+ process.kill()
337
+
338
+ with CancelScope(shield=True):
339
+ for process in workers:
340
+ await process.aclose()
341
+
342
+
343
+ #
344
+ # Sockets and networking
345
+ #
346
+
347
+
348
+ class _TrioSocketMixin(Generic[T_SockAddr]):
349
+ def __init__(self, trio_socket: TrioSocketType) -> None:
350
+ self._trio_socket = trio_socket
351
+ self._closed = False
352
+
353
+ def _check_closed(self) -> None:
354
+ if self._closed:
355
+ raise ClosedResourceError
356
+ if self._trio_socket.fileno() < 0:
357
+ raise BrokenResourceError
358
+
359
+ @property
360
+ def _raw_socket(self) -> socket.socket:
361
+ return self._trio_socket._sock # type: ignore[attr-defined]
362
+
363
+ async def aclose(self) -> None:
364
+ if self._trio_socket.fileno() >= 0:
365
+ self._closed = True
366
+ self._trio_socket.close()
367
+
368
+ def _convert_socket_error(self, exc: BaseException) -> NoReturn:
369
+ if isinstance(exc, trio.ClosedResourceError):
370
+ raise ClosedResourceError from exc
371
+ elif self._trio_socket.fileno() < 0 and self._closed:
372
+ raise ClosedResourceError from None
373
+ elif isinstance(exc, OSError):
374
+ raise BrokenResourceError from exc
375
+ else:
376
+ raise exc
377
+
378
+
379
+ class SocketStream(_TrioSocketMixin, abc.SocketStream):
380
+ def __init__(self, trio_socket: TrioSocketType) -> None:
381
+ super().__init__(trio_socket)
382
+ self._receive_guard = ResourceGuard("reading from")
383
+ self._send_guard = ResourceGuard("writing to")
384
+
385
+ async def receive(self, max_bytes: int = 65536) -> bytes:
386
+ with self._receive_guard:
387
+ try:
388
+ data = await self._trio_socket.recv(max_bytes)
389
+ except BaseException as exc:
390
+ self._convert_socket_error(exc)
391
+
392
+ if data:
393
+ return data
394
+ else:
395
+ raise EndOfStream
396
+
397
+ async def send(self, item: bytes) -> None:
398
+ with self._send_guard:
399
+ view = memoryview(item)
400
+ while view:
401
+ try:
402
+ bytes_sent = await self._trio_socket.send(view)
403
+ except BaseException as exc:
404
+ self._convert_socket_error(exc)
405
+
406
+ view = view[bytes_sent:]
407
+
408
+ async def send_eof(self) -> None:
409
+ self._trio_socket.shutdown(socket.SHUT_WR)
410
+
411
+
412
+ class UNIXSocketStream(SocketStream, abc.UNIXSocketStream):
413
+ async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
414
+ if not isinstance(msglen, int) or msglen < 0:
415
+ raise ValueError("msglen must be a non-negative integer")
416
+ if not isinstance(maxfds, int) or maxfds < 1:
417
+ raise ValueError("maxfds must be a positive integer")
418
+
419
+ fds = array.array("i")
420
+ await trio.lowlevel.checkpoint()
421
+ with self._receive_guard:
422
+ while True:
423
+ try:
424
+ message, ancdata, flags, addr = await self._trio_socket.recvmsg(
425
+ msglen, socket.CMSG_LEN(maxfds * fds.itemsize)
426
+ )
427
+ except BaseException as exc:
428
+ self._convert_socket_error(exc)
429
+ else:
430
+ if not message and not ancdata:
431
+ raise EndOfStream
432
+
433
+ break
434
+
435
+ for cmsg_level, cmsg_type, cmsg_data in ancdata:
436
+ if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS:
437
+ raise RuntimeError(
438
+ f"Received unexpected ancillary data; message = {message!r}, "
439
+ f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}"
440
+ )
441
+
442
+ fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
443
+
444
+ return message, list(fds)
445
+
446
+ async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
447
+ if not message:
448
+ raise ValueError("message must not be empty")
449
+ if not fds:
450
+ raise ValueError("fds must not be empty")
451
+
452
+ filenos: list[int] = []
453
+ for fd in fds:
454
+ if isinstance(fd, int):
455
+ filenos.append(fd)
456
+ elif isinstance(fd, IOBase):
457
+ filenos.append(fd.fileno())
458
+
459
+ fdarray = array.array("i", filenos)
460
+ await trio.lowlevel.checkpoint()
461
+ with self._send_guard:
462
+ while True:
463
+ try:
464
+ await self._trio_socket.sendmsg(
465
+ [message],
466
+ [
467
+ (
468
+ socket.SOL_SOCKET,
469
+ socket.SCM_RIGHTS,
470
+ fdarray,
471
+ )
472
+ ],
473
+ )
474
+ break
475
+ except BaseException as exc:
476
+ self._convert_socket_error(exc)
477
+
478
+
479
+ class TCPSocketListener(_TrioSocketMixin, abc.SocketListener):
480
+ def __init__(self, raw_socket: socket.socket):
481
+ super().__init__(trio.socket.from_stdlib_socket(raw_socket))
482
+ self._accept_guard = ResourceGuard("accepting connections from")
483
+
484
+ async def accept(self) -> SocketStream:
485
+ with self._accept_guard:
486
+ try:
487
+ trio_socket, _addr = await self._trio_socket.accept()
488
+ except BaseException as exc:
489
+ self._convert_socket_error(exc)
490
+
491
+ trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
492
+ return SocketStream(trio_socket)
493
+
494
+
495
+ class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener):
496
+ def __init__(self, raw_socket: socket.socket):
497
+ super().__init__(trio.socket.from_stdlib_socket(raw_socket))
498
+ self._accept_guard = ResourceGuard("accepting connections from")
499
+
500
+ async def accept(self) -> UNIXSocketStream:
501
+ with self._accept_guard:
502
+ try:
503
+ trio_socket, _addr = await self._trio_socket.accept()
504
+ except BaseException as exc:
505
+ self._convert_socket_error(exc)
506
+
507
+ return UNIXSocketStream(trio_socket)
508
+
509
+
510
+ class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket):
511
+ def __init__(self, trio_socket: TrioSocketType) -> None:
512
+ super().__init__(trio_socket)
513
+ self._receive_guard = ResourceGuard("reading from")
514
+ self._send_guard = ResourceGuard("writing to")
515
+
516
+ async def receive(self) -> tuple[bytes, IPSockAddrType]:
517
+ with self._receive_guard:
518
+ try:
519
+ data, addr = await self._trio_socket.recvfrom(65536)
520
+ return data, convert_ipv6_sockaddr(addr)
521
+ except BaseException as exc:
522
+ self._convert_socket_error(exc)
523
+
524
+ async def send(self, item: UDPPacketType) -> None:
525
+ with self._send_guard:
526
+ try:
527
+ await self._trio_socket.sendto(*item)
528
+ except BaseException as exc:
529
+ self._convert_socket_error(exc)
530
+
531
+
532
+ class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket):
533
+ def __init__(self, trio_socket: TrioSocketType) -> None:
534
+ super().__init__(trio_socket)
535
+ self._receive_guard = ResourceGuard("reading from")
536
+ self._send_guard = ResourceGuard("writing to")
537
+
538
+ async def receive(self) -> bytes:
539
+ with self._receive_guard:
540
+ try:
541
+ return await self._trio_socket.recv(65536)
542
+ except BaseException as exc:
543
+ self._convert_socket_error(exc)
544
+
545
+ async def send(self, item: bytes) -> None:
546
+ with self._send_guard:
547
+ try:
548
+ await self._trio_socket.send(item)
549
+ except BaseException as exc:
550
+ self._convert_socket_error(exc)
551
+
552
+
553
+ class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket):
554
+ def __init__(self, trio_socket: TrioSocketType) -> None:
555
+ super().__init__(trio_socket)
556
+ self._receive_guard = ResourceGuard("reading from")
557
+ self._send_guard = ResourceGuard("writing to")
558
+
559
+ async def receive(self) -> UNIXDatagramPacketType:
560
+ with self._receive_guard:
561
+ try:
562
+ data, addr = await self._trio_socket.recvfrom(65536)
563
+ return data, addr
564
+ except BaseException as exc:
565
+ self._convert_socket_error(exc)
566
+
567
+ async def send(self, item: UNIXDatagramPacketType) -> None:
568
+ with self._send_guard:
569
+ try:
570
+ await self._trio_socket.sendto(*item)
571
+ except BaseException as exc:
572
+ self._convert_socket_error(exc)
573
+
574
+
575
+ class ConnectedUNIXDatagramSocket(
576
+ _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket
577
+ ):
578
+ def __init__(self, trio_socket: TrioSocketType) -> None:
579
+ super().__init__(trio_socket)
580
+ self._receive_guard = ResourceGuard("reading from")
581
+ self._send_guard = ResourceGuard("writing to")
582
+
583
+ async def receive(self) -> bytes:
584
+ with self._receive_guard:
585
+ try:
586
+ return await self._trio_socket.recv(65536)
587
+ except BaseException as exc:
588
+ self._convert_socket_error(exc)
589
+
590
+ async def send(self, item: bytes) -> None:
591
+ with self._send_guard:
592
+ try:
593
+ await self._trio_socket.send(item)
594
+ except BaseException as exc:
595
+ self._convert_socket_error(exc)
596
+
597
+
598
+ #
599
+ # Synchronization
600
+ #
601
+
602
+
603
+ class Event(BaseEvent):
604
+ def __new__(cls) -> Event:
605
+ return object.__new__(cls)
606
+
607
+ def __init__(self) -> None:
608
+ self.__original = trio.Event()
609
+
610
+ def is_set(self) -> bool:
611
+ return self.__original.is_set()
612
+
613
+ async def wait(self) -> None:
614
+ return await self.__original.wait()
615
+
616
+ def statistics(self) -> EventStatistics:
617
+ orig_statistics = self.__original.statistics()
618
+ return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting)
619
+
620
+ def set(self) -> None:
621
+ self.__original.set()
622
+
623
+
624
+ class Lock(BaseLock):
625
+ def __new__(cls, *, fast_acquire: bool = False) -> Lock:
626
+ return object.__new__(cls)
627
+
628
+ def __init__(self, *, fast_acquire: bool = False) -> None:
629
+ self._fast_acquire = fast_acquire
630
+ self.__original = trio.Lock()
631
+
632
+ @staticmethod
633
+ def _convert_runtime_error_msg(exc: RuntimeError) -> None:
634
+ if exc.args == ("attempt to re-acquire an already held Lock",):
635
+ exc.args = ("Attempted to acquire an already held Lock",)
636
+
637
+ async def acquire(self) -> None:
638
+ if not self._fast_acquire:
639
+ try:
640
+ await self.__original.acquire()
641
+ except RuntimeError as exc:
642
+ self._convert_runtime_error_msg(exc)
643
+ raise
644
+
645
+ return
646
+
647
+ # This is the "fast path" where we don't let other tasks run
648
+ await trio.lowlevel.checkpoint_if_cancelled()
649
+ try:
650
+ self.__original.acquire_nowait()
651
+ except trio.WouldBlock:
652
+ await self.__original._lot.park()
653
+ except RuntimeError as exc:
654
+ self._convert_runtime_error_msg(exc)
655
+ raise
656
+
657
+ def acquire_nowait(self) -> None:
658
+ try:
659
+ self.__original.acquire_nowait()
660
+ except trio.WouldBlock:
661
+ raise WouldBlock from None
662
+ except RuntimeError as exc:
663
+ self._convert_runtime_error_msg(exc)
664
+ raise
665
+
666
+ def locked(self) -> bool:
667
+ return self.__original.locked()
668
+
669
+ def release(self) -> None:
670
+ self.__original.release()
671
+
672
+ def statistics(self) -> LockStatistics:
673
+ orig_statistics = self.__original.statistics()
674
+ owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None
675
+ return LockStatistics(
676
+ orig_statistics.locked, owner, orig_statistics.tasks_waiting
677
+ )
678
+
679
+
680
+ class Semaphore(BaseSemaphore):
681
+ def __new__(
682
+ cls,
683
+ initial_value: int,
684
+ *,
685
+ max_value: int | None = None,
686
+ fast_acquire: bool = False,
687
+ ) -> Semaphore:
688
+ return object.__new__(cls)
689
+
690
+ def __init__(
691
+ self,
692
+ initial_value: int,
693
+ *,
694
+ max_value: int | None = None,
695
+ fast_acquire: bool = False,
696
+ ) -> None:
697
+ super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
698
+ self.__original = trio.Semaphore(initial_value, max_value=max_value)
699
+
700
+ async def acquire(self) -> None:
701
+ if not self._fast_acquire:
702
+ await self.__original.acquire()
703
+ return
704
+
705
+ # This is the "fast path" where we don't let other tasks run
706
+ await trio.lowlevel.checkpoint_if_cancelled()
707
+ try:
708
+ self.__original.acquire_nowait()
709
+ except trio.WouldBlock:
710
+ await self.__original._lot.park()
711
+
712
+ def acquire_nowait(self) -> None:
713
+ try:
714
+ self.__original.acquire_nowait()
715
+ except trio.WouldBlock:
716
+ raise WouldBlock from None
717
+
718
+ @property
719
+ def max_value(self) -> int | None:
720
+ return self.__original.max_value
721
+
722
+ @property
723
+ def value(self) -> int:
724
+ return self.__original.value
725
+
726
+ def release(self) -> None:
727
+ self.__original.release()
728
+
729
+ def statistics(self) -> SemaphoreStatistics:
730
+ orig_statistics = self.__original.statistics()
731
+ return SemaphoreStatistics(orig_statistics.tasks_waiting)
732
+
733
+
734
+ class CapacityLimiter(BaseCapacityLimiter):
735
+ def __new__(
736
+ cls,
737
+ total_tokens: float | None = None,
738
+ *,
739
+ original: trio.CapacityLimiter | None = None,
740
+ ) -> CapacityLimiter:
741
+ return object.__new__(cls)
742
+
743
+ def __init__(
744
+ self,
745
+ total_tokens: float | None = None,
746
+ *,
747
+ original: trio.CapacityLimiter | None = None,
748
+ ) -> None:
749
+ if original is not None:
750
+ self.__original = original
751
+ else:
752
+ assert total_tokens is not None
753
+ self.__original = trio.CapacityLimiter(total_tokens)
754
+
755
+ async def __aenter__(self) -> None:
756
+ return await self.__original.__aenter__()
757
+
758
+ async def __aexit__(
759
+ self,
760
+ exc_type: type[BaseException] | None,
761
+ exc_val: BaseException | None,
762
+ exc_tb: TracebackType | None,
763
+ ) -> None:
764
+ await self.__original.__aexit__(exc_type, exc_val, exc_tb)
765
+
766
+ @property
767
+ def total_tokens(self) -> float:
768
+ return self.__original.total_tokens
769
+
770
+ @total_tokens.setter
771
+ def total_tokens(self, value: float) -> None:
772
+ self.__original.total_tokens = value
773
+
774
+ @property
775
+ def borrowed_tokens(self) -> int:
776
+ return self.__original.borrowed_tokens
777
+
778
+ @property
779
+ def available_tokens(self) -> float:
780
+ return self.__original.available_tokens
781
+
782
+ def acquire_nowait(self) -> None:
783
+ self.__original.acquire_nowait()
784
+
785
+ def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
786
+ self.__original.acquire_on_behalf_of_nowait(borrower)
787
+
788
+ async def acquire(self) -> None:
789
+ await self.__original.acquire()
790
+
791
+ async def acquire_on_behalf_of(self, borrower: object) -> None:
792
+ await self.__original.acquire_on_behalf_of(borrower)
793
+
794
+ def release(self) -> None:
795
+ return self.__original.release()
796
+
797
+ def release_on_behalf_of(self, borrower: object) -> None:
798
+ return self.__original.release_on_behalf_of(borrower)
799
+
800
+ def statistics(self) -> CapacityLimiterStatistics:
801
+ orig = self.__original.statistics()
802
+ return CapacityLimiterStatistics(
803
+ borrowed_tokens=orig.borrowed_tokens,
804
+ total_tokens=orig.total_tokens,
805
+ borrowers=tuple(orig.borrowers),
806
+ tasks_waiting=orig.tasks_waiting,
807
+ )
808
+
809
+
810
+ _capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper")
811
+
812
+
813
+ #
814
+ # Signal handling
815
+ #
816
+
817
+
818
+ class _SignalReceiver:
819
+ _iterator: AsyncIterator[int]
820
+
821
+ def __init__(self, signals: tuple[Signals, ...]):
822
+ self._signals = signals
823
+
824
+ def __enter__(self) -> _SignalReceiver:
825
+ self._cm = trio.open_signal_receiver(*self._signals)
826
+ self._iterator = self._cm.__enter__()
827
+ return self
828
+
829
+ def __exit__(
830
+ self,
831
+ exc_type: type[BaseException] | None,
832
+ exc_val: BaseException | None,
833
+ exc_tb: TracebackType | None,
834
+ ) -> bool | None:
835
+ return self._cm.__exit__(exc_type, exc_val, exc_tb)
836
+
837
+ def __aiter__(self) -> _SignalReceiver:
838
+ return self
839
+
840
+ async def __anext__(self) -> Signals:
841
+ signum = await self._iterator.__anext__()
842
+ return Signals(signum)
843
+
844
+
845
+ #
846
+ # Testing and debugging
847
+ #
848
+
849
+
850
+ class TestRunner(abc.TestRunner):
851
+ def __init__(self, **options: Any) -> None:
852
+ from queue import Queue
853
+
854
+ self._call_queue: Queue[Callable[[], object]] = Queue()
855
+ self._send_stream: MemoryObjectSendStream | None = None
856
+ self._options = options
857
+
858
+ def __exit__(
859
+ self,
860
+ exc_type: type[BaseException] | None,
861
+ exc_val: BaseException | None,
862
+ exc_tb: types.TracebackType | None,
863
+ ) -> None:
864
+ if self._send_stream:
865
+ self._send_stream.close()
866
+ while self._send_stream is not None:
867
+ self._call_queue.get()()
868
+
869
+ async def _run_tests_and_fixtures(self) -> None:
870
+ self._send_stream, receive_stream = create_memory_object_stream(1)
871
+ with receive_stream:
872
+ async for coro, outcome_holder in receive_stream:
873
+ try:
874
+ retval = await coro
875
+ except BaseException as exc:
876
+ outcome_holder.append(Error(exc))
877
+ else:
878
+ outcome_holder.append(Value(retval))
879
+
880
+ def _main_task_finished(self, outcome: object) -> None:
881
+ self._send_stream = None
882
+
883
+ def _call_in_runner_task(
884
+ self,
885
+ func: Callable[P, Awaitable[T_Retval]],
886
+ /,
887
+ *args: P.args,
888
+ **kwargs: P.kwargs,
889
+ ) -> T_Retval:
890
+ if self._send_stream is None:
891
+ trio.lowlevel.start_guest_run(
892
+ self._run_tests_and_fixtures,
893
+ run_sync_soon_threadsafe=self._call_queue.put,
894
+ done_callback=self._main_task_finished,
895
+ **self._options,
896
+ )
897
+ while self._send_stream is None:
898
+ self._call_queue.get()()
899
+
900
+ outcome_holder: list[Outcome] = []
901
+ self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder))
902
+ while not outcome_holder:
903
+ self._call_queue.get()()
904
+
905
+ return outcome_holder[0].unwrap()
906
+
907
+ def run_asyncgen_fixture(
908
+ self,
909
+ fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]],
910
+ kwargs: dict[str, Any],
911
+ ) -> Iterable[T_Retval]:
912
+ asyncgen = fixture_func(**kwargs)
913
+ fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None)
914
+
915
+ yield fixturevalue
916
+
917
+ try:
918
+ self._call_in_runner_task(asyncgen.asend, None)
919
+ except StopAsyncIteration:
920
+ pass
921
+ else:
922
+ self._call_in_runner_task(asyncgen.aclose)
923
+ raise RuntimeError("Async generator fixture did not stop")
924
+
925
+ def run_fixture(
926
+ self,
927
+ fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]],
928
+ kwargs: dict[str, Any],
929
+ ) -> T_Retval:
930
+ return self._call_in_runner_task(fixture_func, **kwargs)
931
+
932
+ def run_test(
933
+ self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
934
+ ) -> None:
935
+ self._call_in_runner_task(test_func, **kwargs)
936
+
937
+
938
+ class TrioTaskInfo(TaskInfo):
939
+ def __init__(self, task: trio.lowlevel.Task):
940
+ parent_id = None
941
+ if task.parent_nursery and task.parent_nursery.parent_task:
942
+ parent_id = id(task.parent_nursery.parent_task)
943
+
944
+ super().__init__(id(task), parent_id, task.name, task.coro)
945
+ self._task = weakref.proxy(task)
946
+
947
+ def has_pending_cancellation(self) -> bool:
948
+ try:
949
+ return self._task._cancel_status.effectively_cancelled
950
+ except ReferenceError:
951
+ # If the task is no longer around, it surely doesn't have a cancellation
952
+ # pending
953
+ return False
954
+
955
+
956
+ class TrioBackend(AsyncBackend):
957
+ @classmethod
958
+ def run(
959
+ cls,
960
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
961
+ args: tuple[Unpack[PosArgsT]],
962
+ kwargs: dict[str, Any],
963
+ options: dict[str, Any],
964
+ ) -> T_Retval:
965
+ return trio.run(func, *args)
966
+
967
+ @classmethod
968
+ def current_token(cls) -> object:
969
+ return trio.lowlevel.current_trio_token()
970
+
971
+ @classmethod
972
+ def current_time(cls) -> float:
973
+ return trio.current_time()
974
+
975
+ @classmethod
976
+ def cancelled_exception_class(cls) -> type[BaseException]:
977
+ return trio.Cancelled
978
+
979
+ @classmethod
980
+ async def checkpoint(cls) -> None:
981
+ await trio.lowlevel.checkpoint()
982
+
983
+ @classmethod
984
+ async def checkpoint_if_cancelled(cls) -> None:
985
+ await trio.lowlevel.checkpoint_if_cancelled()
986
+
987
+ @classmethod
988
+ async def cancel_shielded_checkpoint(cls) -> None:
989
+ await trio.lowlevel.cancel_shielded_checkpoint()
990
+
991
+ @classmethod
992
+ async def sleep(cls, delay: float) -> None:
993
+ await trio.sleep(delay)
994
+
995
+ @classmethod
996
+ def create_cancel_scope(
997
+ cls, *, deadline: float = math.inf, shield: bool = False
998
+ ) -> abc.CancelScope:
999
+ return CancelScope(deadline=deadline, shield=shield)
1000
+
1001
+ @classmethod
1002
+ def current_effective_deadline(cls) -> float:
1003
+ return trio.current_effective_deadline()
1004
+
1005
+ @classmethod
1006
+ def create_task_group(cls) -> abc.TaskGroup:
1007
+ return TaskGroup()
1008
+
1009
+ @classmethod
1010
+ def create_event(cls) -> abc.Event:
1011
+ return Event()
1012
+
1013
+ @classmethod
1014
+ def create_lock(cls, *, fast_acquire: bool) -> Lock:
1015
+ return Lock(fast_acquire=fast_acquire)
1016
+
1017
+ @classmethod
1018
+ def create_semaphore(
1019
+ cls,
1020
+ initial_value: int,
1021
+ *,
1022
+ max_value: int | None = None,
1023
+ fast_acquire: bool = False,
1024
+ ) -> abc.Semaphore:
1025
+ return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire)
1026
+
1027
+ @classmethod
1028
+ def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
1029
+ return CapacityLimiter(total_tokens)
1030
+
1031
+ @classmethod
1032
+ async def run_sync_in_worker_thread(
1033
+ cls,
1034
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
1035
+ args: tuple[Unpack[PosArgsT]],
1036
+ abandon_on_cancel: bool = False,
1037
+ limiter: abc.CapacityLimiter | None = None,
1038
+ ) -> T_Retval:
1039
+ def wrapper() -> T_Retval:
1040
+ with claim_worker_thread(TrioBackend, token):
1041
+ return func(*args)
1042
+
1043
+ token = TrioBackend.current_token()
1044
+ return await run_sync(
1045
+ wrapper,
1046
+ abandon_on_cancel=abandon_on_cancel,
1047
+ limiter=cast(trio.CapacityLimiter, limiter),
1048
+ )
1049
+
1050
+ @classmethod
1051
+ def check_cancelled(cls) -> None:
1052
+ trio.from_thread.check_cancelled()
1053
+
1054
+ @classmethod
1055
+ def run_async_from_thread(
1056
+ cls,
1057
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
1058
+ args: tuple[Unpack[PosArgsT]],
1059
+ token: object,
1060
+ ) -> T_Retval:
1061
+ trio_token = cast("trio.lowlevel.TrioToken | None", token)
1062
+ try:
1063
+ return trio.from_thread.run(func, *args, trio_token=trio_token)
1064
+ except trio.RunFinishedError:
1065
+ raise RunFinishedError from None
1066
+
1067
+ @classmethod
1068
+ def run_sync_from_thread(
1069
+ cls,
1070
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
1071
+ args: tuple[Unpack[PosArgsT]],
1072
+ token: object,
1073
+ ) -> T_Retval:
1074
+ trio_token = cast("trio.lowlevel.TrioToken | None", token)
1075
+ try:
1076
+ return trio.from_thread.run_sync(func, *args, trio_token=trio_token)
1077
+ except trio.RunFinishedError:
1078
+ raise RunFinishedError from None
1079
+
1080
+ @classmethod
1081
+ async def open_process(
1082
+ cls,
1083
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
1084
+ *,
1085
+ stdin: int | IO[Any] | None,
1086
+ stdout: int | IO[Any] | None,
1087
+ stderr: int | IO[Any] | None,
1088
+ **kwargs: Any,
1089
+ ) -> Process:
1090
+ def convert_item(item: StrOrBytesPath) -> str:
1091
+ str_or_bytes = os.fspath(item)
1092
+ if isinstance(str_or_bytes, str):
1093
+ return str_or_bytes
1094
+ else:
1095
+ return os.fsdecode(str_or_bytes)
1096
+
1097
+ if isinstance(command, (str, bytes, PathLike)):
1098
+ process = await trio.lowlevel.open_process(
1099
+ convert_item(command),
1100
+ stdin=stdin,
1101
+ stdout=stdout,
1102
+ stderr=stderr,
1103
+ shell=True,
1104
+ **kwargs,
1105
+ )
1106
+ else:
1107
+ process = await trio.lowlevel.open_process(
1108
+ [convert_item(item) for item in command],
1109
+ stdin=stdin,
1110
+ stdout=stdout,
1111
+ stderr=stderr,
1112
+ shell=False,
1113
+ **kwargs,
1114
+ )
1115
+
1116
+ stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None
1117
+ stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None
1118
+ stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None
1119
+ return Process(process, stdin_stream, stdout_stream, stderr_stream)
1120
+
1121
+ @classmethod
1122
+ def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None:
1123
+ trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers)
1124
+
1125
+ @classmethod
1126
+ async def connect_tcp(
1127
+ cls, host: str, port: int, local_address: IPSockAddrType | None = None
1128
+ ) -> SocketStream:
1129
+ family = socket.AF_INET6 if ":" in host else socket.AF_INET
1130
+ trio_socket = trio.socket.socket(family)
1131
+ trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
1132
+ if local_address:
1133
+ await trio_socket.bind(local_address)
1134
+
1135
+ try:
1136
+ await trio_socket.connect((host, port))
1137
+ except BaseException:
1138
+ trio_socket.close()
1139
+ raise
1140
+
1141
+ return SocketStream(trio_socket)
1142
+
1143
+ @classmethod
1144
+ async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream:
1145
+ trio_socket = trio.socket.socket(socket.AF_UNIX)
1146
+ try:
1147
+ await trio_socket.connect(path)
1148
+ except BaseException:
1149
+ trio_socket.close()
1150
+ raise
1151
+
1152
+ return UNIXSocketStream(trio_socket)
1153
+
1154
+ @classmethod
1155
+ def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener:
1156
+ return TCPSocketListener(sock)
1157
+
1158
+ @classmethod
1159
+ def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener:
1160
+ return UNIXSocketListener(sock)
1161
+
1162
+ @classmethod
1163
+ async def create_udp_socket(
1164
+ cls,
1165
+ family: socket.AddressFamily,
1166
+ local_address: IPSockAddrType | None,
1167
+ remote_address: IPSockAddrType | None,
1168
+ reuse_port: bool,
1169
+ ) -> UDPSocket | ConnectedUDPSocket:
1170
+ trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM)
1171
+
1172
+ if reuse_port:
1173
+ trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
1174
+
1175
+ if local_address:
1176
+ await trio_socket.bind(local_address)
1177
+
1178
+ if remote_address:
1179
+ await trio_socket.connect(remote_address)
1180
+ return ConnectedUDPSocket(trio_socket)
1181
+ else:
1182
+ return UDPSocket(trio_socket)
1183
+
1184
+ @classmethod
1185
+ @overload
1186
+ async def create_unix_datagram_socket(
1187
+ cls, raw_socket: socket.socket, remote_path: None
1188
+ ) -> abc.UNIXDatagramSocket: ...
1189
+
1190
+ @classmethod
1191
+ @overload
1192
+ async def create_unix_datagram_socket(
1193
+ cls, raw_socket: socket.socket, remote_path: str | bytes
1194
+ ) -> abc.ConnectedUNIXDatagramSocket: ...
1195
+
1196
+ @classmethod
1197
+ async def create_unix_datagram_socket(
1198
+ cls, raw_socket: socket.socket, remote_path: str | bytes | None
1199
+ ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket:
1200
+ trio_socket = trio.socket.from_stdlib_socket(raw_socket)
1201
+
1202
+ if remote_path:
1203
+ await trio_socket.connect(remote_path)
1204
+ return ConnectedUNIXDatagramSocket(trio_socket)
1205
+ else:
1206
+ return UNIXDatagramSocket(trio_socket)
1207
+
1208
+ @classmethod
1209
+ async def getaddrinfo(
1210
+ cls,
1211
+ host: bytes | str | None,
1212
+ port: str | int | None,
1213
+ *,
1214
+ family: int | AddressFamily = 0,
1215
+ type: int | SocketKind = 0,
1216
+ proto: int = 0,
1217
+ flags: int = 0,
1218
+ ) -> Sequence[
1219
+ tuple[
1220
+ AddressFamily,
1221
+ SocketKind,
1222
+ int,
1223
+ str,
1224
+ tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
1225
+ ]
1226
+ ]:
1227
+ return await trio.socket.getaddrinfo(host, port, family, type, proto, flags)
1228
+
1229
+ @classmethod
1230
+ async def getnameinfo(
1231
+ cls, sockaddr: IPSockAddrType, flags: int = 0
1232
+ ) -> tuple[str, str]:
1233
+ return await trio.socket.getnameinfo(sockaddr, flags)
1234
+
1235
+ @classmethod
1236
+ async def wait_readable(cls, obj: FileDescriptorLike) -> None:
1237
+ try:
1238
+ await wait_readable(obj)
1239
+ except trio.ClosedResourceError as exc:
1240
+ raise ClosedResourceError().with_traceback(exc.__traceback__) from None
1241
+ except trio.BusyResourceError:
1242
+ raise BusyResourceError("reading from") from None
1243
+
1244
+ @classmethod
1245
+ async def wait_writable(cls, obj: FileDescriptorLike) -> None:
1246
+ try:
1247
+ await wait_writable(obj)
1248
+ except trio.ClosedResourceError as exc:
1249
+ raise ClosedResourceError().with_traceback(exc.__traceback__) from None
1250
+ except trio.BusyResourceError:
1251
+ raise BusyResourceError("writing to") from None
1252
+
1253
+ @classmethod
1254
+ def notify_closing(cls, obj: FileDescriptorLike) -> None:
1255
+ notify_closing(obj)
1256
+
1257
+ @classmethod
1258
+ async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener:
1259
+ return TCPSocketListener(sock)
1260
+
1261
+ @classmethod
1262
+ async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream:
1263
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1264
+ return SocketStream(trio_sock)
1265
+
1266
+ @classmethod
1267
+ async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream:
1268
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1269
+ return UNIXSocketStream(trio_sock)
1270
+
1271
+ @classmethod
1272
+ async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket:
1273
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1274
+ return UDPSocket(trio_sock)
1275
+
1276
+ @classmethod
1277
+ async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket:
1278
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1279
+ return ConnectedUDPSocket(trio_sock)
1280
+
1281
+ @classmethod
1282
+ async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket:
1283
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1284
+ return UNIXDatagramSocket(trio_sock)
1285
+
1286
+ @classmethod
1287
+ async def wrap_connected_unix_datagram_socket(
1288
+ cls, sock: socket.socket
1289
+ ) -> ConnectedUNIXDatagramSocket:
1290
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1291
+ return ConnectedUNIXDatagramSocket(trio_sock)
1292
+
1293
+ @classmethod
1294
+ def current_default_thread_limiter(cls) -> CapacityLimiter:
1295
+ try:
1296
+ return _capacity_limiter_wrapper.get()
1297
+ except LookupError:
1298
+ limiter = CapacityLimiter(
1299
+ original=trio.to_thread.current_default_thread_limiter()
1300
+ )
1301
+ _capacity_limiter_wrapper.set(limiter)
1302
+ return limiter
1303
+
1304
+ @classmethod
1305
+ def open_signal_receiver(
1306
+ cls, *signals: Signals
1307
+ ) -> AbstractContextManager[AsyncIterator[Signals]]:
1308
+ return _SignalReceiver(signals)
1309
+
1310
+ @classmethod
1311
+ def get_current_task(cls) -> TaskInfo:
1312
+ task = current_task()
1313
+ return TrioTaskInfo(task)
1314
+
1315
+ @classmethod
1316
+ def get_running_tasks(cls) -> Sequence[TaskInfo]:
1317
+ root_task = current_root_task()
1318
+ assert root_task
1319
+ task_infos = [TrioTaskInfo(root_task)]
1320
+ nurseries = root_task.child_nurseries
1321
+ while nurseries:
1322
+ new_nurseries: list[trio.Nursery] = []
1323
+ for nursery in nurseries:
1324
+ for task in nursery.child_tasks:
1325
+ task_infos.append(TrioTaskInfo(task))
1326
+ new_nurseries.extend(task.child_nurseries)
1327
+
1328
+ nurseries = new_nurseries
1329
+
1330
+ return task_infos
1331
+
1332
+ @classmethod
1333
+ async def wait_all_tasks_blocked(cls) -> None:
1334
+ from trio.testing import wait_all_tasks_blocked
1335
+
1336
+ await wait_all_tasks_blocked()
1337
+
1338
+ @classmethod
1339
+ def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
1340
+ return TestRunner(**options)
1341
+
1342
+
1343
+ backend_class = TrioBackend
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/__init__.py ADDED
File without changes
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_asyncio_selector_thread.py ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import socket
5
+ import threading
6
+ from collections.abc import Callable
7
+ from selectors import EVENT_READ, EVENT_WRITE, DefaultSelector
8
+ from typing import TYPE_CHECKING, Any
9
+
10
+ if TYPE_CHECKING:
11
+ from _typeshed import FileDescriptorLike
12
+
13
+ _selector_lock = threading.Lock()
14
+ _selector: Selector | None = None
15
+
16
+
17
+ class Selector:
18
+ def __init__(self) -> None:
19
+ self._thread = threading.Thread(target=self.run, name="AnyIO socket selector")
20
+ self._selector = DefaultSelector()
21
+ self._send, self._receive = socket.socketpair()
22
+ self._send.setblocking(False)
23
+ self._receive.setblocking(False)
24
+ # This somewhat reduces the amount of memory wasted queueing up data
25
+ # for wakeups. With these settings, maximum number of 1-byte sends
26
+ # before getting BlockingIOError:
27
+ # Linux 4.8: 6
28
+ # macOS (darwin 15.5): 1
29
+ # Windows 10: 525347
30
+ # Windows you're weird. (And on Windows setting SNDBUF to 0 makes send
31
+ # blocking, even on non-blocking sockets, so don't do that.)
32
+ self._receive.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1)
33
+ self._send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1)
34
+ # On Windows this is a TCP socket so this might matter. On other
35
+ # platforms this fails b/c AF_UNIX sockets aren't actually TCP.
36
+ try:
37
+ self._send.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
38
+ except OSError:
39
+ pass
40
+
41
+ self._selector.register(self._receive, EVENT_READ)
42
+ self._closed = False
43
+
44
+ def start(self) -> None:
45
+ self._thread.start()
46
+ threading._register_atexit(self._stop) # type: ignore[attr-defined]
47
+
48
+ def _stop(self) -> None:
49
+ global _selector
50
+ self._closed = True
51
+ self._notify_self()
52
+ self._send.close()
53
+ self._thread.join()
54
+ self._selector.unregister(self._receive)
55
+ self._receive.close()
56
+ self._selector.close()
57
+ _selector = None
58
+ assert not self._selector.get_map(), (
59
+ "selector still has registered file descriptors after shutdown"
60
+ )
61
+
62
+ def _notify_self(self) -> None:
63
+ try:
64
+ self._send.send(b"\x00")
65
+ except BlockingIOError:
66
+ pass
67
+
68
+ def add_reader(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None:
69
+ loop = asyncio.get_running_loop()
70
+ try:
71
+ key = self._selector.get_key(fd)
72
+ except KeyError:
73
+ self._selector.register(fd, EVENT_READ, {EVENT_READ: (loop, callback)})
74
+ else:
75
+ if EVENT_READ in key.data:
76
+ raise ValueError(
77
+ "this file descriptor is already registered for reading"
78
+ )
79
+
80
+ key.data[EVENT_READ] = loop, callback
81
+ self._selector.modify(fd, key.events | EVENT_READ, key.data)
82
+
83
+ self._notify_self()
84
+
85
+ def add_writer(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None:
86
+ loop = asyncio.get_running_loop()
87
+ try:
88
+ key = self._selector.get_key(fd)
89
+ except KeyError:
90
+ self._selector.register(fd, EVENT_WRITE, {EVENT_WRITE: (loop, callback)})
91
+ else:
92
+ if EVENT_WRITE in key.data:
93
+ raise ValueError(
94
+ "this file descriptor is already registered for writing"
95
+ )
96
+
97
+ key.data[EVENT_WRITE] = loop, callback
98
+ self._selector.modify(fd, key.events | EVENT_WRITE, key.data)
99
+
100
+ self._notify_self()
101
+
102
+ def remove_reader(self, fd: FileDescriptorLike) -> bool:
103
+ try:
104
+ key = self._selector.get_key(fd)
105
+ except KeyError:
106
+ return False
107
+
108
+ if new_events := key.events ^ EVENT_READ:
109
+ del key.data[EVENT_READ]
110
+ self._selector.modify(fd, new_events, key.data)
111
+ else:
112
+ self._selector.unregister(fd)
113
+
114
+ return True
115
+
116
+ def remove_writer(self, fd: FileDescriptorLike) -> bool:
117
+ try:
118
+ key = self._selector.get_key(fd)
119
+ except KeyError:
120
+ return False
121
+
122
+ if new_events := key.events ^ EVENT_WRITE:
123
+ del key.data[EVENT_WRITE]
124
+ self._selector.modify(fd, new_events, key.data)
125
+ else:
126
+ self._selector.unregister(fd)
127
+
128
+ return True
129
+
130
+ def run(self) -> None:
131
+ while not self._closed:
132
+ for key, events in self._selector.select():
133
+ if key.fileobj is self._receive:
134
+ try:
135
+ while self._receive.recv(4096):
136
+ pass
137
+ except BlockingIOError:
138
+ pass
139
+
140
+ continue
141
+
142
+ if events & EVENT_READ:
143
+ loop, callback = key.data[EVENT_READ]
144
+ self.remove_reader(key.fd)
145
+ try:
146
+ loop.call_soon_threadsafe(callback)
147
+ except RuntimeError:
148
+ pass # the loop was already closed
149
+
150
+ if events & EVENT_WRITE:
151
+ loop, callback = key.data[EVENT_WRITE]
152
+ self.remove_writer(key.fd)
153
+ try:
154
+ loop.call_soon_threadsafe(callback)
155
+ except RuntimeError:
156
+ pass # the loop was already closed
157
+
158
+
159
+ def get_selector() -> Selector:
160
+ global _selector
161
+
162
+ with _selector_lock:
163
+ if _selector is None:
164
+ _selector = Selector()
165
+ _selector.start()
166
+
167
+ return _selector
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_contextmanagers.py ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+ from contextlib import AbstractAsyncContextManager, AbstractContextManager
5
+ from inspect import isasyncgen, iscoroutine, isgenerator
6
+ from types import TracebackType
7
+ from typing import Protocol, TypeVar, cast, final
8
+
9
+ _T_co = TypeVar("_T_co", covariant=True)
10
+ _ExitT_co = TypeVar("_ExitT_co", covariant=True, bound="bool | None")
11
+
12
+
13
+ class _SupportsCtxMgr(Protocol[_T_co, _ExitT_co]):
14
+ def __contextmanager__(self) -> AbstractContextManager[_T_co, _ExitT_co]: ...
15
+
16
+
17
+ class _SupportsAsyncCtxMgr(Protocol[_T_co, _ExitT_co]):
18
+ def __asynccontextmanager__(
19
+ self,
20
+ ) -> AbstractAsyncContextManager[_T_co, _ExitT_co]: ...
21
+
22
+
23
+ class ContextManagerMixin:
24
+ """
25
+ Mixin class providing context manager functionality via a generator-based
26
+ implementation.
27
+
28
+ This class allows you to implement a context manager via :meth:`__contextmanager__`
29
+ which should return a generator. The mechanics are meant to mirror those of
30
+ :func:`@contextmanager <contextlib.contextmanager>`.
31
+
32
+ .. note:: Classes using this mix-in are not reentrant as context managers, meaning
33
+ that once you enter it, you can't re-enter before first exiting it.
34
+
35
+ .. seealso:: :doc:`contextmanagers`
36
+ """
37
+
38
+ __cm: AbstractContextManager[object, bool | None] | None = None
39
+
40
+ @final
41
+ def __enter__(self: _SupportsCtxMgr[_T_co, bool | None]) -> _T_co:
42
+ # Needed for mypy to assume self still has the __cm member
43
+ assert isinstance(self, ContextManagerMixin)
44
+ if self.__cm is not None:
45
+ raise RuntimeError(
46
+ f"this {self.__class__.__qualname__} has already been entered"
47
+ )
48
+
49
+ cm = self.__contextmanager__()
50
+ if not isinstance(cm, AbstractContextManager):
51
+ if isgenerator(cm):
52
+ raise TypeError(
53
+ "__contextmanager__() returned a generator object instead of "
54
+ "a context manager. Did you forget to add the @contextmanager "
55
+ "decorator?"
56
+ )
57
+
58
+ raise TypeError(
59
+ f"__contextmanager__() did not return a context manager object, "
60
+ f"but {cm.__class__!r}"
61
+ )
62
+
63
+ if cm is self:
64
+ raise TypeError(
65
+ f"{self.__class__.__qualname__}.__contextmanager__() returned "
66
+ f"self. Did you forget to add the @contextmanager decorator and a "
67
+ f"'yield' statement?"
68
+ )
69
+
70
+ value = cm.__enter__()
71
+ self.__cm = cm
72
+ return value
73
+
74
+ @final
75
+ def __exit__(
76
+ self: _SupportsCtxMgr[object, _ExitT_co],
77
+ exc_type: type[BaseException] | None,
78
+ exc_val: BaseException | None,
79
+ exc_tb: TracebackType | None,
80
+ ) -> _ExitT_co:
81
+ # Needed for mypy to assume self still has the __cm member
82
+ assert isinstance(self, ContextManagerMixin)
83
+ if self.__cm is None:
84
+ raise RuntimeError(
85
+ f"this {self.__class__.__qualname__} has not been entered yet"
86
+ )
87
+
88
+ # Prevent circular references
89
+ cm = self.__cm
90
+ del self.__cm
91
+
92
+ return cast(_ExitT_co, cm.__exit__(exc_type, exc_val, exc_tb))
93
+
94
+ @abstractmethod
95
+ def __contextmanager__(self) -> AbstractContextManager[object, bool | None]:
96
+ """
97
+ Implement your context manager logic here.
98
+
99
+ This method **must** be decorated with
100
+ :func:`@contextmanager <contextlib.contextmanager>`.
101
+
102
+ .. note:: Remember that the ``yield`` will raise any exception raised in the
103
+ enclosed context block, so use a ``finally:`` block to clean up resources!
104
+
105
+ :return: a context manager object
106
+ """
107
+
108
+
109
+ class AsyncContextManagerMixin:
110
+ """
111
+ Mixin class providing async context manager functionality via a generator-based
112
+ implementation.
113
+
114
+ This class allows you to implement a context manager via
115
+ :meth:`__asynccontextmanager__`. The mechanics are meant to mirror those of
116
+ :func:`@asynccontextmanager <contextlib.asynccontextmanager>`.
117
+
118
+ .. note:: Classes using this mix-in are not reentrant as context managers, meaning
119
+ that once you enter it, you can't re-enter before first exiting it.
120
+
121
+ .. seealso:: :doc:`contextmanagers`
122
+ """
123
+
124
+ __cm: AbstractAsyncContextManager[object, bool | None] | None = None
125
+
126
+ @final
127
+ async def __aenter__(self: _SupportsAsyncCtxMgr[_T_co, bool | None]) -> _T_co:
128
+ # Needed for mypy to assume self still has the __cm member
129
+ assert isinstance(self, AsyncContextManagerMixin)
130
+ if self.__cm is not None:
131
+ raise RuntimeError(
132
+ f"this {self.__class__.__qualname__} has already been entered"
133
+ )
134
+
135
+ cm = self.__asynccontextmanager__()
136
+ if not isinstance(cm, AbstractAsyncContextManager):
137
+ if isasyncgen(cm):
138
+ raise TypeError(
139
+ "__asynccontextmanager__() returned an async generator instead of "
140
+ "an async context manager. Did you forget to add the "
141
+ "@asynccontextmanager decorator?"
142
+ )
143
+ elif iscoroutine(cm):
144
+ cm.close()
145
+ raise TypeError(
146
+ "__asynccontextmanager__() returned a coroutine object instead of "
147
+ "an async context manager. Did you forget to add the "
148
+ "@asynccontextmanager decorator and a 'yield' statement?"
149
+ )
150
+
151
+ raise TypeError(
152
+ f"__asynccontextmanager__() did not return an async context manager, "
153
+ f"but {cm.__class__!r}"
154
+ )
155
+
156
+ if cm is self:
157
+ raise TypeError(
158
+ f"{self.__class__.__qualname__}.__asynccontextmanager__() returned "
159
+ f"self. Did you forget to add the @asynccontextmanager decorator and a "
160
+ f"'yield' statement?"
161
+ )
162
+
163
+ value = await cm.__aenter__()
164
+ self.__cm = cm
165
+ return value
166
+
167
+ @final
168
+ async def __aexit__(
169
+ self: _SupportsAsyncCtxMgr[object, _ExitT_co],
170
+ exc_type: type[BaseException] | None,
171
+ exc_val: BaseException | None,
172
+ exc_tb: TracebackType | None,
173
+ ) -> _ExitT_co:
174
+ assert isinstance(self, AsyncContextManagerMixin)
175
+ if self.__cm is None:
176
+ raise RuntimeError(
177
+ f"this {self.__class__.__qualname__} has not been entered yet"
178
+ )
179
+
180
+ # Prevent circular references
181
+ cm = self.__cm
182
+ del self.__cm
183
+
184
+ return cast(_ExitT_co, await cm.__aexit__(exc_type, exc_val, exc_tb))
185
+
186
+ @abstractmethod
187
+ def __asynccontextmanager__(
188
+ self,
189
+ ) -> AbstractAsyncContextManager[object, bool | None]:
190
+ """
191
+ Implement your async context manager logic here.
192
+
193
+ This method **must** be decorated with
194
+ :func:`@asynccontextmanager <contextlib.asynccontextmanager>`.
195
+
196
+ .. note:: Remember that the ``yield`` will raise any exception raised in the
197
+ enclosed context block, so use a ``finally:`` block to clean up resources!
198
+
199
+ :return: an async context manager object
200
+ """
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_eventloop.py ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ import sys
5
+ import threading
6
+ from collections.abc import Awaitable, Callable, Generator
7
+ from contextlib import contextmanager
8
+ from contextvars import Token
9
+ from importlib import import_module
10
+ from typing import TYPE_CHECKING, Any, TypeVar
11
+
12
+ from ._exceptions import NoEventLoopError
13
+
14
+ if sys.version_info >= (3, 11):
15
+ from typing import TypeVarTuple, Unpack
16
+ else:
17
+ from typing_extensions import TypeVarTuple, Unpack
18
+
19
+ sniffio: Any
20
+ try:
21
+ import sniffio
22
+ except ModuleNotFoundError:
23
+ sniffio = None
24
+
25
+ if TYPE_CHECKING:
26
+ from ..abc import AsyncBackend
27
+
28
+ # This must be updated when new backends are introduced
29
+ BACKENDS = "asyncio", "trio"
30
+
31
+ T_Retval = TypeVar("T_Retval")
32
+ PosArgsT = TypeVarTuple("PosArgsT")
33
+
34
+ threadlocals = threading.local()
35
+ loaded_backends: dict[str, type[AsyncBackend]] = {}
36
+
37
+
38
+ def run(
39
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
40
+ *args: Unpack[PosArgsT],
41
+ backend: str = "asyncio",
42
+ backend_options: dict[str, Any] | None = None,
43
+ ) -> T_Retval:
44
+ """
45
+ Run the given coroutine function in an asynchronous event loop.
46
+
47
+ The current thread must not be already running an event loop.
48
+
49
+ :param func: a coroutine function
50
+ :param args: positional arguments to ``func``
51
+ :param backend: name of the asynchronous event loop implementation – currently
52
+ either ``asyncio`` or ``trio``
53
+ :param backend_options: keyword arguments to call the backend ``run()``
54
+ implementation with (documented :ref:`here <backend options>`)
55
+ :return: the return value of the coroutine function
56
+ :raises RuntimeError: if an asynchronous event loop is already running in this
57
+ thread
58
+ :raises LookupError: if the named backend is not found
59
+
60
+ """
61
+ if asynclib_name := current_async_library():
62
+ raise RuntimeError(f"Already running {asynclib_name} in this thread")
63
+
64
+ try:
65
+ async_backend = get_async_backend(backend)
66
+ except ImportError as exc:
67
+ raise LookupError(f"No such backend: {backend}") from exc
68
+
69
+ token = None
70
+ if asynclib_name is None:
71
+ # Since we're in control of the event loop, we can cache the name of the async
72
+ # library
73
+ token = set_current_async_library(backend)
74
+
75
+ try:
76
+ backend_options = backend_options or {}
77
+ return async_backend.run(func, args, {}, backend_options)
78
+ finally:
79
+ reset_current_async_library(token)
80
+
81
+
82
+ async def sleep(delay: float) -> None:
83
+ """
84
+ Pause the current task for the specified duration.
85
+
86
+ :param delay: the duration, in seconds
87
+
88
+ """
89
+ return await get_async_backend().sleep(delay)
90
+
91
+
92
+ async def sleep_forever() -> None:
93
+ """
94
+ Pause the current task until it's cancelled.
95
+
96
+ This is a shortcut for ``sleep(math.inf)``.
97
+
98
+ .. versionadded:: 3.1
99
+
100
+ """
101
+ await sleep(math.inf)
102
+
103
+
104
+ async def sleep_until(deadline: float) -> None:
105
+ """
106
+ Pause the current task until the given time.
107
+
108
+ :param deadline: the absolute time to wake up at (according to the internal
109
+ monotonic clock of the event loop)
110
+
111
+ .. versionadded:: 3.1
112
+
113
+ """
114
+ now = current_time()
115
+ await sleep(max(deadline - now, 0))
116
+
117
+
118
+ def current_time() -> float:
119
+ """
120
+ Return the current value of the event loop's internal clock.
121
+
122
+ :return: the clock value (seconds)
123
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
124
+ current thread
125
+
126
+ """
127
+ return get_async_backend().current_time()
128
+
129
+
130
+ def get_all_backends() -> tuple[str, ...]:
131
+ """Return a tuple of the names of all built-in backends."""
132
+ return BACKENDS
133
+
134
+
135
+ def get_available_backends() -> tuple[str, ...]:
136
+ """
137
+ Test for the availability of built-in backends.
138
+
139
+ :return a tuple of the built-in backend names that were successfully imported
140
+
141
+ .. versionadded:: 4.12
142
+
143
+ """
144
+ available_backends: list[str] = []
145
+ for backend_name in get_all_backends():
146
+ try:
147
+ get_async_backend(backend_name)
148
+ except ImportError:
149
+ continue
150
+
151
+ available_backends.append(backend_name)
152
+
153
+ return tuple(available_backends)
154
+
155
+
156
+ def get_cancelled_exc_class() -> type[BaseException]:
157
+ """
158
+ Return the current async library's cancellation exception class.
159
+
160
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
161
+ current thread
162
+
163
+ """
164
+ return get_async_backend().cancelled_exception_class()
165
+
166
+
167
+ #
168
+ # Private API
169
+ #
170
+
171
+
172
+ @contextmanager
173
+ def claim_worker_thread(
174
+ backend_class: type[AsyncBackend], token: object
175
+ ) -> Generator[Any, None, None]:
176
+ from ..lowlevel import EventLoopToken
177
+
178
+ threadlocals.current_token = EventLoopToken(backend_class, token)
179
+ try:
180
+ yield
181
+ finally:
182
+ del threadlocals.current_token
183
+
184
+
185
+ def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]:
186
+ if asynclib_name is None:
187
+ asynclib_name = current_async_library()
188
+ if not asynclib_name:
189
+ raise NoEventLoopError(
190
+ f"Not currently running on any asynchronous event loop. "
191
+ f"Available async backends: {', '.join(get_all_backends())}"
192
+ )
193
+
194
+ # We use our own dict instead of sys.modules to get the already imported back-end
195
+ # class because the appropriate modules in sys.modules could potentially be only
196
+ # partially initialized
197
+ try:
198
+ return loaded_backends[asynclib_name]
199
+ except KeyError:
200
+ module = import_module(f"anyio._backends._{asynclib_name}")
201
+ loaded_backends[asynclib_name] = module.backend_class
202
+ return module.backend_class
203
+
204
+
205
+ def current_async_library() -> str | None:
206
+ if sniffio is None:
207
+ # If sniffio is not installed, we assume we're either running asyncio or nothing
208
+ import asyncio
209
+
210
+ try:
211
+ asyncio.get_running_loop()
212
+ return "asyncio"
213
+ except RuntimeError:
214
+ pass
215
+ else:
216
+ try:
217
+ return sniffio.current_async_library()
218
+ except sniffio.AsyncLibraryNotFoundError:
219
+ pass
220
+
221
+ return None
222
+
223
+
224
+ def set_current_async_library(asynclib_name: str | None) -> Token | None:
225
+ # no-op if sniffio is not installed
226
+ if sniffio is None:
227
+ return None
228
+
229
+ return sniffio.current_async_library_cvar.set(asynclib_name)
230
+
231
+
232
+ def reset_current_async_library(token: Token | None) -> None:
233
+ if token is not None:
234
+ sniffio.current_async_library_cvar.reset(token)
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_exceptions.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from collections.abc import Generator
5
+ from textwrap import dedent
6
+ from typing import Any
7
+
8
+ if sys.version_info < (3, 11):
9
+ from exceptiongroup import BaseExceptionGroup
10
+
11
+
12
+ class BrokenResourceError(Exception):
13
+ """
14
+ Raised when trying to use a resource that has been rendered unusable due to external
15
+ causes (e.g. a send stream whose peer has disconnected).
16
+ """
17
+
18
+
19
+ class BrokenWorkerProcess(Exception):
20
+ """
21
+ Raised by :meth:`~anyio.to_process.run_sync` if the worker process terminates abruptly or
22
+ otherwise misbehaves.
23
+ """
24
+
25
+
26
+ class BrokenWorkerInterpreter(Exception):
27
+ """
28
+ Raised by :meth:`~anyio.to_interpreter.run_sync` if an unexpected exception is
29
+ raised in the subinterpreter.
30
+ """
31
+
32
+ def __init__(self, excinfo: Any):
33
+ # This was adapted from concurrent.futures.interpreter.ExecutionFailed
34
+ msg = excinfo.formatted
35
+ if not msg:
36
+ if excinfo.type and excinfo.msg:
37
+ msg = f"{excinfo.type.__name__}: {excinfo.msg}"
38
+ else:
39
+ msg = excinfo.type.__name__ or excinfo.msg
40
+
41
+ super().__init__(msg)
42
+ self.excinfo = excinfo
43
+
44
+ def __str__(self) -> str:
45
+ try:
46
+ formatted = self.excinfo.errdisplay
47
+ except Exception:
48
+ return super().__str__()
49
+ else:
50
+ return dedent(
51
+ f"""
52
+ {super().__str__()}
53
+
54
+ Uncaught in the interpreter:
55
+
56
+ {formatted}
57
+ """.strip()
58
+ )
59
+
60
+
61
+ class BusyResourceError(Exception):
62
+ """
63
+ Raised when two tasks are trying to read from or write to the same resource
64
+ concurrently.
65
+ """
66
+
67
+ def __init__(self, action: str):
68
+ super().__init__(f"Another task is already {action} this resource")
69
+
70
+
71
+ class ClosedResourceError(Exception):
72
+ """Raised when trying to use a resource that has been closed."""
73
+
74
+
75
+ class ConnectionFailed(OSError):
76
+ """
77
+ Raised when a connection attempt fails.
78
+
79
+ .. note:: This class inherits from :exc:`OSError` for backwards compatibility.
80
+ """
81
+
82
+
83
+ def iterate_exceptions(
84
+ exception: BaseException,
85
+ ) -> Generator[BaseException, None, None]:
86
+ if isinstance(exception, BaseExceptionGroup):
87
+ for exc in exception.exceptions:
88
+ yield from iterate_exceptions(exc)
89
+ else:
90
+ yield exception
91
+
92
+
93
+ class DelimiterNotFound(Exception):
94
+ """
95
+ Raised during
96
+ :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the
97
+ maximum number of bytes has been read without the delimiter being found.
98
+ """
99
+
100
+ def __init__(self, max_bytes: int) -> None:
101
+ super().__init__(
102
+ f"The delimiter was not found among the first {max_bytes} bytes"
103
+ )
104
+
105
+
106
+ class EndOfStream(Exception):
107
+ """
108
+ Raised when trying to read from a stream that has been closed from the other end.
109
+ """
110
+
111
+
112
+ class IncompleteRead(Exception):
113
+ """
114
+ Raised during
115
+ :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or
116
+ :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the
117
+ connection is closed before the requested amount of bytes has been read.
118
+ """
119
+
120
+ def __init__(self) -> None:
121
+ super().__init__(
122
+ "The stream was closed before the read operation could be completed"
123
+ )
124
+
125
+
126
+ class TypedAttributeLookupError(LookupError):
127
+ """
128
+ Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute
129
+ is not found and no default value has been given.
130
+ """
131
+
132
+
133
+ class WouldBlock(Exception):
134
+ """Raised by ``X_nowait`` functions if ``X()`` would block."""
135
+
136
+
137
+ class NoEventLoopError(RuntimeError):
138
+ """
139
+ Raised by several functions that require an event loop to be running in the current
140
+ thread when there is no running event loop.
141
+
142
+ This is also raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync`
143
+ if not calling from an AnyIO worker thread, and no ``token`` was passed.
144
+ """
145
+
146
+
147
+ class RunFinishedError(RuntimeError):
148
+ """
149
+ Raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` if the event
150
+ loop associated with the explicitly passed token has already finished.
151
+ """
152
+
153
+ def __init__(self) -> None:
154
+ super().__init__(
155
+ "The event loop associated with the given token has already finished"
156
+ )
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_fileio.py ADDED
@@ -0,0 +1,799 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import pathlib
5
+ import sys
6
+ from collections.abc import (
7
+ AsyncIterator,
8
+ Callable,
9
+ Iterable,
10
+ Iterator,
11
+ Sequence,
12
+ )
13
+ from dataclasses import dataclass
14
+ from functools import partial
15
+ from os import PathLike
16
+ from typing import (
17
+ IO,
18
+ TYPE_CHECKING,
19
+ Any,
20
+ AnyStr,
21
+ ClassVar,
22
+ Final,
23
+ Generic,
24
+ overload,
25
+ )
26
+
27
+ from .. import to_thread
28
+ from ..abc import AsyncResource
29
+
30
+ if TYPE_CHECKING:
31
+ from types import ModuleType
32
+
33
+ from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
34
+ else:
35
+ ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object
36
+
37
+
38
+ class AsyncFile(AsyncResource, Generic[AnyStr]):
39
+ """
40
+ An asynchronous file object.
41
+
42
+ This class wraps a standard file object and provides async friendly versions of the
43
+ following blocking methods (where available on the original file object):
44
+
45
+ * read
46
+ * read1
47
+ * readline
48
+ * readlines
49
+ * readinto
50
+ * readinto1
51
+ * write
52
+ * writelines
53
+ * truncate
54
+ * seek
55
+ * tell
56
+ * flush
57
+
58
+ All other methods are directly passed through.
59
+
60
+ This class supports the asynchronous context manager protocol which closes the
61
+ underlying file at the end of the context block.
62
+
63
+ This class also supports asynchronous iteration::
64
+
65
+ async with await open_file(...) as f:
66
+ async for line in f:
67
+ print(line)
68
+ """
69
+
70
+ def __init__(self, fp: IO[AnyStr]) -> None:
71
+ self._fp: Any = fp
72
+
73
+ def __getattr__(self, name: str) -> object:
74
+ return getattr(self._fp, name)
75
+
76
+ @property
77
+ def wrapped(self) -> IO[AnyStr]:
78
+ """The wrapped file object."""
79
+ return self._fp
80
+
81
+ async def __aiter__(self) -> AsyncIterator[AnyStr]:
82
+ while True:
83
+ line = await self.readline()
84
+ if line:
85
+ yield line
86
+ else:
87
+ break
88
+
89
+ async def aclose(self) -> None:
90
+ return await to_thread.run_sync(self._fp.close)
91
+
92
+ async def read(self, size: int = -1) -> AnyStr:
93
+ return await to_thread.run_sync(self._fp.read, size)
94
+
95
+ async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes:
96
+ return await to_thread.run_sync(self._fp.read1, size)
97
+
98
+ async def readline(self) -> AnyStr:
99
+ return await to_thread.run_sync(self._fp.readline)
100
+
101
+ async def readlines(self) -> list[AnyStr]:
102
+ return await to_thread.run_sync(self._fp.readlines)
103
+
104
+ async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
105
+ return await to_thread.run_sync(self._fp.readinto, b)
106
+
107
+ async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
108
+ return await to_thread.run_sync(self._fp.readinto1, b)
109
+
110
+ @overload
111
+ async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ...
112
+
113
+ @overload
114
+ async def write(self: AsyncFile[str], b: str) -> int: ...
115
+
116
+ async def write(self, b: ReadableBuffer | str) -> int:
117
+ return await to_thread.run_sync(self._fp.write, b)
118
+
119
+ @overload
120
+ async def writelines(
121
+ self: AsyncFile[bytes], lines: Iterable[ReadableBuffer]
122
+ ) -> None: ...
123
+
124
+ @overload
125
+ async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ...
126
+
127
+ async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None:
128
+ return await to_thread.run_sync(self._fp.writelines, lines)
129
+
130
+ async def truncate(self, size: int | None = None) -> int:
131
+ return await to_thread.run_sync(self._fp.truncate, size)
132
+
133
+ async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
134
+ return await to_thread.run_sync(self._fp.seek, offset, whence)
135
+
136
+ async def tell(self) -> int:
137
+ return await to_thread.run_sync(self._fp.tell)
138
+
139
+ async def flush(self) -> None:
140
+ return await to_thread.run_sync(self._fp.flush)
141
+
142
+
143
+ @overload
144
+ async def open_file(
145
+ file: str | PathLike[str] | int,
146
+ mode: OpenBinaryMode,
147
+ buffering: int = ...,
148
+ encoding: str | None = ...,
149
+ errors: str | None = ...,
150
+ newline: str | None = ...,
151
+ closefd: bool = ...,
152
+ opener: Callable[[str, int], int] | None = ...,
153
+ ) -> AsyncFile[bytes]: ...
154
+
155
+
156
+ @overload
157
+ async def open_file(
158
+ file: str | PathLike[str] | int,
159
+ mode: OpenTextMode = ...,
160
+ buffering: int = ...,
161
+ encoding: str | None = ...,
162
+ errors: str | None = ...,
163
+ newline: str | None = ...,
164
+ closefd: bool = ...,
165
+ opener: Callable[[str, int], int] | None = ...,
166
+ ) -> AsyncFile[str]: ...
167
+
168
+
169
+ async def open_file(
170
+ file: str | PathLike[str] | int,
171
+ mode: str = "r",
172
+ buffering: int = -1,
173
+ encoding: str | None = None,
174
+ errors: str | None = None,
175
+ newline: str | None = None,
176
+ closefd: bool = True,
177
+ opener: Callable[[str, int], int] | None = None,
178
+ ) -> AsyncFile[Any]:
179
+ """
180
+ Open a file asynchronously.
181
+
182
+ The arguments are exactly the same as for the builtin :func:`open`.
183
+
184
+ :return: an asynchronous file object
185
+
186
+ """
187
+ fp = await to_thread.run_sync(
188
+ open, file, mode, buffering, encoding, errors, newline, closefd, opener
189
+ )
190
+ return AsyncFile(fp)
191
+
192
+
193
+ def wrap_file(file: IO[AnyStr]) -> AsyncFile[AnyStr]:
194
+ """
195
+ Wrap an existing file as an asynchronous file.
196
+
197
+ :param file: an existing file-like object
198
+ :return: an asynchronous file object
199
+
200
+ """
201
+ return AsyncFile(file)
202
+
203
+
204
+ @dataclass(eq=False)
205
+ class _PathIterator(AsyncIterator["Path"]):
206
+ iterator: Iterator[PathLike[str]]
207
+
208
+ async def __anext__(self) -> Path:
209
+ nextval = await to_thread.run_sync(
210
+ next, self.iterator, None, abandon_on_cancel=True
211
+ )
212
+ if nextval is None:
213
+ raise StopAsyncIteration from None
214
+
215
+ return Path(nextval)
216
+
217
+
218
+ class Path:
219
+ """
220
+ An asynchronous version of :class:`pathlib.Path`.
221
+
222
+ This class cannot be substituted for :class:`pathlib.Path` or
223
+ :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike`
224
+ interface.
225
+
226
+ It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for
227
+ the deprecated :meth:`~pathlib.Path.link_to` method.
228
+
229
+ Some methods may be unavailable or have limited functionality, based on the Python
230
+ version:
231
+
232
+ * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later)
233
+ * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later)
234
+ * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later)
235
+ * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later)
236
+ * :attr:`~pathlib.Path.info` (available on Python 3.14 or later)
237
+ * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later)
238
+ * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only
239
+ available on Python 3.13 or later)
240
+ * :meth:`~pathlib.Path.move` (available on Python 3.14 or later)
241
+ * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later)
242
+ * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available
243
+ on Python 3.12 or later)
244
+ * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later)
245
+
246
+ Any methods that do disk I/O need to be awaited on. These methods are:
247
+
248
+ * :meth:`~pathlib.Path.absolute`
249
+ * :meth:`~pathlib.Path.chmod`
250
+ * :meth:`~pathlib.Path.cwd`
251
+ * :meth:`~pathlib.Path.exists`
252
+ * :meth:`~pathlib.Path.expanduser`
253
+ * :meth:`~pathlib.Path.group`
254
+ * :meth:`~pathlib.Path.hardlink_to`
255
+ * :meth:`~pathlib.Path.home`
256
+ * :meth:`~pathlib.Path.is_block_device`
257
+ * :meth:`~pathlib.Path.is_char_device`
258
+ * :meth:`~pathlib.Path.is_dir`
259
+ * :meth:`~pathlib.Path.is_fifo`
260
+ * :meth:`~pathlib.Path.is_file`
261
+ * :meth:`~pathlib.Path.is_junction`
262
+ * :meth:`~pathlib.Path.is_mount`
263
+ * :meth:`~pathlib.Path.is_socket`
264
+ * :meth:`~pathlib.Path.is_symlink`
265
+ * :meth:`~pathlib.Path.lchmod`
266
+ * :meth:`~pathlib.Path.lstat`
267
+ * :meth:`~pathlib.Path.mkdir`
268
+ * :meth:`~pathlib.Path.open`
269
+ * :meth:`~pathlib.Path.owner`
270
+ * :meth:`~pathlib.Path.read_bytes`
271
+ * :meth:`~pathlib.Path.read_text`
272
+ * :meth:`~pathlib.Path.readlink`
273
+ * :meth:`~pathlib.Path.rename`
274
+ * :meth:`~pathlib.Path.replace`
275
+ * :meth:`~pathlib.Path.resolve`
276
+ * :meth:`~pathlib.Path.rmdir`
277
+ * :meth:`~pathlib.Path.samefile`
278
+ * :meth:`~pathlib.Path.stat`
279
+ * :meth:`~pathlib.Path.symlink_to`
280
+ * :meth:`~pathlib.Path.touch`
281
+ * :meth:`~pathlib.Path.unlink`
282
+ * :meth:`~pathlib.Path.walk`
283
+ * :meth:`~pathlib.Path.write_bytes`
284
+ * :meth:`~pathlib.Path.write_text`
285
+
286
+ Additionally, the following methods return an async iterator yielding
287
+ :class:`~.Path` objects:
288
+
289
+ * :meth:`~pathlib.Path.glob`
290
+ * :meth:`~pathlib.Path.iterdir`
291
+ * :meth:`~pathlib.Path.rglob`
292
+ """
293
+
294
+ __slots__ = "_path", "__weakref__"
295
+
296
+ __weakref__: Any
297
+
298
+ def __init__(self, *args: str | PathLike[str]) -> None:
299
+ self._path: Final[pathlib.Path] = pathlib.Path(*args)
300
+
301
+ def __fspath__(self) -> str:
302
+ return self._path.__fspath__()
303
+
304
+ if sys.version_info >= (3, 15):
305
+
306
+ def __vfspath__(self) -> str:
307
+ return self._path.__vfspath__()
308
+
309
+ def __str__(self) -> str:
310
+ return self._path.__str__()
311
+
312
+ def __repr__(self) -> str:
313
+ return f"{self.__class__.__name__}({self.as_posix()!r})"
314
+
315
+ def __bytes__(self) -> bytes:
316
+ return self._path.__bytes__()
317
+
318
+ def __hash__(self) -> int:
319
+ return self._path.__hash__()
320
+
321
+ def __eq__(self, other: object) -> bool:
322
+ target = other._path if isinstance(other, Path) else other
323
+ return self._path.__eq__(target)
324
+
325
+ def __lt__(self, other: pathlib.PurePath | Path) -> bool:
326
+ target = other._path if isinstance(other, Path) else other
327
+ return self._path.__lt__(target)
328
+
329
+ def __le__(self, other: pathlib.PurePath | Path) -> bool:
330
+ target = other._path if isinstance(other, Path) else other
331
+ return self._path.__le__(target)
332
+
333
+ def __gt__(self, other: pathlib.PurePath | Path) -> bool:
334
+ target = other._path if isinstance(other, Path) else other
335
+ return self._path.__gt__(target)
336
+
337
+ def __ge__(self, other: pathlib.PurePath | Path) -> bool:
338
+ target = other._path if isinstance(other, Path) else other
339
+ return self._path.__ge__(target)
340
+
341
+ def __truediv__(self, other: str | PathLike[str]) -> Path:
342
+ return Path(self._path / other)
343
+
344
+ def __rtruediv__(self, other: str | PathLike[str]) -> Path:
345
+ return Path(other) / self
346
+
347
+ @property
348
+ def parts(self) -> tuple[str, ...]:
349
+ return self._path.parts
350
+
351
+ @property
352
+ def drive(self) -> str:
353
+ return self._path.drive
354
+
355
+ @property
356
+ def root(self) -> str:
357
+ return self._path.root
358
+
359
+ @property
360
+ def anchor(self) -> str:
361
+ return self._path.anchor
362
+
363
+ @property
364
+ def parents(self) -> Sequence[Path]:
365
+ return tuple(Path(p) for p in self._path.parents)
366
+
367
+ @property
368
+ def parent(self) -> Path:
369
+ return Path(self._path.parent)
370
+
371
+ @property
372
+ def name(self) -> str:
373
+ return self._path.name
374
+
375
+ @property
376
+ def suffix(self) -> str:
377
+ return self._path.suffix
378
+
379
+ @property
380
+ def suffixes(self) -> list[str]:
381
+ return self._path.suffixes
382
+
383
+ @property
384
+ def stem(self) -> str:
385
+ return self._path.stem
386
+
387
+ async def absolute(self) -> Path:
388
+ path = await to_thread.run_sync(self._path.absolute)
389
+ return Path(path)
390
+
391
+ def as_posix(self) -> str:
392
+ return self._path.as_posix()
393
+
394
+ def as_uri(self) -> str:
395
+ return self._path.as_uri()
396
+
397
+ if sys.version_info >= (3, 13):
398
+ parser: ClassVar[ModuleType] = pathlib.Path.parser
399
+
400
+ @classmethod
401
+ def from_uri(cls, uri: str) -> Path:
402
+ return Path(pathlib.Path.from_uri(uri))
403
+
404
+ def full_match(
405
+ self, path_pattern: str, *, case_sensitive: bool | None = None
406
+ ) -> bool:
407
+ return self._path.full_match(path_pattern, case_sensitive=case_sensitive)
408
+
409
+ def match(
410
+ self, path_pattern: str, *, case_sensitive: bool | None = None
411
+ ) -> bool:
412
+ return self._path.match(path_pattern, case_sensitive=case_sensitive)
413
+ else:
414
+
415
+ def match(self, path_pattern: str) -> bool:
416
+ return self._path.match(path_pattern)
417
+
418
+ if sys.version_info >= (3, 14):
419
+
420
+ @property
421
+ def info(self) -> Any: # TODO: add return type annotation when Typeshed gets it
422
+ return self._path.info
423
+
424
+ async def copy(
425
+ self,
426
+ target: str | os.PathLike[str],
427
+ *,
428
+ follow_symlinks: bool = True,
429
+ preserve_metadata: bool = False,
430
+ ) -> Path:
431
+ func = partial(
432
+ self._path.copy,
433
+ follow_symlinks=follow_symlinks,
434
+ preserve_metadata=preserve_metadata,
435
+ )
436
+ return Path(await to_thread.run_sync(func, pathlib.Path(target)))
437
+
438
+ async def copy_into(
439
+ self,
440
+ target_dir: str | os.PathLike[str],
441
+ *,
442
+ follow_symlinks: bool = True,
443
+ preserve_metadata: bool = False,
444
+ ) -> Path:
445
+ func = partial(
446
+ self._path.copy_into,
447
+ follow_symlinks=follow_symlinks,
448
+ preserve_metadata=preserve_metadata,
449
+ )
450
+ return Path(await to_thread.run_sync(func, pathlib.Path(target_dir)))
451
+
452
+ async def move(self, target: str | os.PathLike[str]) -> Path:
453
+ # Upstream does not handle anyio.Path properly as a PathLike
454
+ target = pathlib.Path(target)
455
+ return Path(await to_thread.run_sync(self._path.move, target))
456
+
457
+ async def move_into(
458
+ self,
459
+ target_dir: str | os.PathLike[str],
460
+ ) -> Path:
461
+ return Path(await to_thread.run_sync(self._path.move_into, target_dir))
462
+
463
+ def is_relative_to(self, other: str | PathLike[str]) -> bool:
464
+ try:
465
+ self.relative_to(other)
466
+ return True
467
+ except ValueError:
468
+ return False
469
+
470
+ async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None:
471
+ func = partial(os.chmod, follow_symlinks=follow_symlinks)
472
+ return await to_thread.run_sync(func, self._path, mode)
473
+
474
+ @classmethod
475
+ async def cwd(cls) -> Path:
476
+ path = await to_thread.run_sync(pathlib.Path.cwd)
477
+ return cls(path)
478
+
479
+ async def exists(self) -> bool:
480
+ return await to_thread.run_sync(self._path.exists, abandon_on_cancel=True)
481
+
482
+ async def expanduser(self) -> Path:
483
+ return Path(
484
+ await to_thread.run_sync(self._path.expanduser, abandon_on_cancel=True)
485
+ )
486
+
487
+ if sys.version_info < (3, 12):
488
+ # Python 3.11 and earlier
489
+ def glob(self, pattern: str) -> AsyncIterator[Path]:
490
+ gen = self._path.glob(pattern)
491
+ return _PathIterator(gen)
492
+ elif (3, 12) <= sys.version_info < (3, 13):
493
+ # changed in Python 3.12:
494
+ # - The case_sensitive parameter was added.
495
+ def glob(
496
+ self,
497
+ pattern: str,
498
+ *,
499
+ case_sensitive: bool | None = None,
500
+ ) -> AsyncIterator[Path]:
501
+ gen = self._path.glob(pattern, case_sensitive=case_sensitive)
502
+ return _PathIterator(gen)
503
+ elif sys.version_info >= (3, 13):
504
+ # Changed in Python 3.13:
505
+ # - The recurse_symlinks parameter was added.
506
+ # - The pattern parameter accepts a path-like object.
507
+ def glob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
508
+ self,
509
+ pattern: str | PathLike[str],
510
+ *,
511
+ case_sensitive: bool | None = None,
512
+ recurse_symlinks: bool = False,
513
+ ) -> AsyncIterator[Path]:
514
+ gen = self._path.glob(
515
+ pattern, # type: ignore[arg-type]
516
+ case_sensitive=case_sensitive,
517
+ recurse_symlinks=recurse_symlinks,
518
+ )
519
+ return _PathIterator(gen)
520
+
521
+ async def group(self) -> str:
522
+ return await to_thread.run_sync(self._path.group, abandon_on_cancel=True)
523
+
524
+ async def hardlink_to(
525
+ self, target: str | bytes | PathLike[str] | PathLike[bytes]
526
+ ) -> None:
527
+ if isinstance(target, Path):
528
+ target = target._path
529
+
530
+ await to_thread.run_sync(os.link, target, self)
531
+
532
+ @classmethod
533
+ async def home(cls) -> Path:
534
+ home_path = await to_thread.run_sync(pathlib.Path.home)
535
+ return cls(home_path)
536
+
537
+ def is_absolute(self) -> bool:
538
+ return self._path.is_absolute()
539
+
540
+ async def is_block_device(self) -> bool:
541
+ return await to_thread.run_sync(
542
+ self._path.is_block_device, abandon_on_cancel=True
543
+ )
544
+
545
+ async def is_char_device(self) -> bool:
546
+ return await to_thread.run_sync(
547
+ self._path.is_char_device, abandon_on_cancel=True
548
+ )
549
+
550
+ async def is_dir(self) -> bool:
551
+ return await to_thread.run_sync(self._path.is_dir, abandon_on_cancel=True)
552
+
553
+ async def is_fifo(self) -> bool:
554
+ return await to_thread.run_sync(self._path.is_fifo, abandon_on_cancel=True)
555
+
556
+ async def is_file(self) -> bool:
557
+ return await to_thread.run_sync(self._path.is_file, abandon_on_cancel=True)
558
+
559
+ if sys.version_info >= (3, 12):
560
+
561
+ async def is_junction(self) -> bool:
562
+ return await to_thread.run_sync(self._path.is_junction)
563
+
564
+ async def is_mount(self) -> bool:
565
+ return await to_thread.run_sync(
566
+ os.path.ismount, self._path, abandon_on_cancel=True
567
+ )
568
+
569
+ if sys.version_info < (3, 15):
570
+
571
+ def is_reserved(self) -> bool:
572
+ return self._path.is_reserved()
573
+
574
+ async def is_socket(self) -> bool:
575
+ return await to_thread.run_sync(self._path.is_socket, abandon_on_cancel=True)
576
+
577
+ async def is_symlink(self) -> bool:
578
+ return await to_thread.run_sync(self._path.is_symlink, abandon_on_cancel=True)
579
+
580
+ async def iterdir(self) -> AsyncIterator[Path]:
581
+ gen = (
582
+ self._path.iterdir()
583
+ if sys.version_info < (3, 13)
584
+ else await to_thread.run_sync(self._path.iterdir, abandon_on_cancel=True)
585
+ )
586
+ async for path in _PathIterator(gen):
587
+ yield path
588
+
589
+ def joinpath(self, *args: str | PathLike[str]) -> Path:
590
+ return Path(self._path.joinpath(*args))
591
+
592
+ async def lchmod(self, mode: int) -> None:
593
+ await to_thread.run_sync(self._path.lchmod, mode)
594
+
595
+ async def lstat(self) -> os.stat_result:
596
+ return await to_thread.run_sync(self._path.lstat, abandon_on_cancel=True)
597
+
598
+ async def mkdir(
599
+ self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
600
+ ) -> None:
601
+ await to_thread.run_sync(self._path.mkdir, mode, parents, exist_ok)
602
+
603
+ @overload
604
+ async def open(
605
+ self,
606
+ mode: OpenBinaryMode,
607
+ buffering: int = ...,
608
+ encoding: str | None = ...,
609
+ errors: str | None = ...,
610
+ newline: str | None = ...,
611
+ ) -> AsyncFile[bytes]: ...
612
+
613
+ @overload
614
+ async def open(
615
+ self,
616
+ mode: OpenTextMode = ...,
617
+ buffering: int = ...,
618
+ encoding: str | None = ...,
619
+ errors: str | None = ...,
620
+ newline: str | None = ...,
621
+ ) -> AsyncFile[str]: ...
622
+
623
+ async def open(
624
+ self,
625
+ mode: str = "r",
626
+ buffering: int = -1,
627
+ encoding: str | None = None,
628
+ errors: str | None = None,
629
+ newline: str | None = None,
630
+ ) -> AsyncFile[Any]:
631
+ fp = await to_thread.run_sync(
632
+ self._path.open, mode, buffering, encoding, errors, newline
633
+ )
634
+ return AsyncFile(fp)
635
+
636
+ async def owner(self) -> str:
637
+ return await to_thread.run_sync(self._path.owner, abandon_on_cancel=True)
638
+
639
+ async def read_bytes(self) -> bytes:
640
+ return await to_thread.run_sync(self._path.read_bytes)
641
+
642
+ async def read_text(
643
+ self, encoding: str | None = None, errors: str | None = None
644
+ ) -> str:
645
+ return await to_thread.run_sync(self._path.read_text, encoding, errors)
646
+
647
+ if sys.version_info >= (3, 12):
648
+
649
+ def relative_to(
650
+ self, *other: str | PathLike[str], walk_up: bool = False
651
+ ) -> Path:
652
+ # relative_to() should work with any PathLike but it doesn't
653
+ others = [pathlib.Path(other) for other in other]
654
+ return Path(self._path.relative_to(*others, walk_up=walk_up))
655
+
656
+ else:
657
+
658
+ def relative_to(self, *other: str | PathLike[str]) -> Path:
659
+ return Path(self._path.relative_to(*other))
660
+
661
+ async def readlink(self) -> Path:
662
+ target = await to_thread.run_sync(os.readlink, self._path)
663
+ return Path(target)
664
+
665
+ async def rename(self, target: str | pathlib.PurePath | Path) -> Path:
666
+ if isinstance(target, Path):
667
+ target = target._path
668
+
669
+ await to_thread.run_sync(self._path.rename, target)
670
+ return Path(target)
671
+
672
+ async def replace(self, target: str | pathlib.PurePath | Path) -> Path:
673
+ if isinstance(target, Path):
674
+ target = target._path
675
+
676
+ await to_thread.run_sync(self._path.replace, target)
677
+ return Path(target)
678
+
679
+ async def resolve(self, strict: bool = False) -> Path:
680
+ func = partial(self._path.resolve, strict=strict)
681
+ return Path(await to_thread.run_sync(func, abandon_on_cancel=True))
682
+
683
+ if sys.version_info < (3, 12):
684
+ # Pre Python 3.12
685
+ def rglob(self, pattern: str) -> AsyncIterator[Path]:
686
+ gen = self._path.rglob(pattern)
687
+ return _PathIterator(gen)
688
+ elif (3, 12) <= sys.version_info < (3, 13):
689
+ # Changed in Python 3.12:
690
+ # - The case_sensitive parameter was added.
691
+ def rglob(
692
+ self, pattern: str, *, case_sensitive: bool | None = None
693
+ ) -> AsyncIterator[Path]:
694
+ gen = self._path.rglob(pattern, case_sensitive=case_sensitive)
695
+ return _PathIterator(gen)
696
+ elif sys.version_info >= (3, 13):
697
+ # Changed in Python 3.13:
698
+ # - The recurse_symlinks parameter was added.
699
+ # - The pattern parameter accepts a path-like object.
700
+ def rglob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
701
+ self,
702
+ pattern: str | PathLike[str],
703
+ *,
704
+ case_sensitive: bool | None = None,
705
+ recurse_symlinks: bool = False,
706
+ ) -> AsyncIterator[Path]:
707
+ gen = self._path.rglob(
708
+ pattern, # type: ignore[arg-type]
709
+ case_sensitive=case_sensitive,
710
+ recurse_symlinks=recurse_symlinks,
711
+ )
712
+ return _PathIterator(gen)
713
+
714
+ async def rmdir(self) -> None:
715
+ await to_thread.run_sync(self._path.rmdir)
716
+
717
+ async def samefile(self, other_path: str | PathLike[str]) -> bool:
718
+ if isinstance(other_path, Path):
719
+ other_path = other_path._path
720
+
721
+ return await to_thread.run_sync(
722
+ self._path.samefile, other_path, abandon_on_cancel=True
723
+ )
724
+
725
+ async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result:
726
+ func = partial(os.stat, follow_symlinks=follow_symlinks)
727
+ return await to_thread.run_sync(func, self._path, abandon_on_cancel=True)
728
+
729
+ async def symlink_to(
730
+ self,
731
+ target: str | bytes | PathLike[str] | PathLike[bytes],
732
+ target_is_directory: bool = False,
733
+ ) -> None:
734
+ if isinstance(target, Path):
735
+ target = target._path
736
+
737
+ await to_thread.run_sync(self._path.symlink_to, target, target_is_directory)
738
+
739
+ async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
740
+ await to_thread.run_sync(self._path.touch, mode, exist_ok)
741
+
742
+ async def unlink(self, missing_ok: bool = False) -> None:
743
+ try:
744
+ await to_thread.run_sync(self._path.unlink)
745
+ except FileNotFoundError:
746
+ if not missing_ok:
747
+ raise
748
+
749
+ if sys.version_info >= (3, 12):
750
+
751
+ async def walk(
752
+ self,
753
+ top_down: bool = True,
754
+ on_error: Callable[[OSError], object] | None = None,
755
+ follow_symlinks: bool = False,
756
+ ) -> AsyncIterator[tuple[Path, list[str], list[str]]]:
757
+ def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None:
758
+ try:
759
+ return next(gen)
760
+ except StopIteration:
761
+ return None
762
+
763
+ gen = self._path.walk(top_down, on_error, follow_symlinks)
764
+ while True:
765
+ value = await to_thread.run_sync(get_next_value)
766
+ if value is None:
767
+ return
768
+
769
+ root, dirs, paths = value
770
+ yield Path(root), dirs, paths
771
+
772
+ def with_name(self, name: str) -> Path:
773
+ return Path(self._path.with_name(name))
774
+
775
+ def with_stem(self, stem: str) -> Path:
776
+ return Path(self._path.with_name(stem + self._path.suffix))
777
+
778
+ def with_suffix(self, suffix: str) -> Path:
779
+ return Path(self._path.with_suffix(suffix))
780
+
781
+ def with_segments(self, *pathsegments: str | PathLike[str]) -> Path:
782
+ return Path(*pathsegments)
783
+
784
+ async def write_bytes(self, data: bytes) -> int:
785
+ return await to_thread.run_sync(self._path.write_bytes, data)
786
+
787
+ async def write_text(
788
+ self,
789
+ data: str,
790
+ encoding: str | None = None,
791
+ errors: str | None = None,
792
+ newline: str | None = None,
793
+ ) -> int:
794
+ return await to_thread.run_sync(
795
+ self._path.write_text, data, encoding, errors, newline
796
+ )
797
+
798
+
799
+ PathLike.register(Path)
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_resources.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from ..abc import AsyncResource
4
+ from ._tasks import CancelScope
5
+
6
+
7
+ async def aclose_forcefully(resource: AsyncResource) -> None:
8
+ """
9
+ Close an asynchronous resource in a cancelled scope.
10
+
11
+ Doing this closes the resource without waiting on anything.
12
+
13
+ :param resource: the resource to close
14
+
15
+ """
16
+ with CancelScope() as scope:
17
+ scope.cancel()
18
+ await resource.aclose()
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_signals.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import AsyncIterator
4
+ from contextlib import AbstractContextManager
5
+ from signal import Signals
6
+
7
+ from ._eventloop import get_async_backend
8
+
9
+
10
+ def open_signal_receiver(
11
+ *signals: Signals,
12
+ ) -> AbstractContextManager[AsyncIterator[Signals]]:
13
+ """
14
+ Start receiving operating system signals.
15
+
16
+ :param signals: signals to receive (e.g. ``signal.SIGINT``)
17
+ :return: an asynchronous context manager for an asynchronous iterator which yields
18
+ signal numbers
19
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
20
+ current thread
21
+
22
+ .. warning:: Windows does not support signals natively so it is best to avoid
23
+ relying on this in cross-platform applications.
24
+
25
+ .. warning:: On asyncio, this permanently replaces any previous signal handler for
26
+ the given signals, as set via :meth:`~asyncio.loop.add_signal_handler`.
27
+
28
+ """
29
+ return get_async_backend().open_signal_receiver(*signals)
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_sockets.py ADDED
@@ -0,0 +1,1003 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import errno
4
+ import os
5
+ import socket
6
+ import ssl
7
+ import stat
8
+ import sys
9
+ from collections.abc import Awaitable
10
+ from dataclasses import dataclass
11
+ from ipaddress import IPv4Address, IPv6Address, ip_address
12
+ from os import PathLike, chmod
13
+ from socket import AddressFamily, SocketKind
14
+ from typing import TYPE_CHECKING, Any, Literal, cast, overload
15
+
16
+ from .. import ConnectionFailed, to_thread
17
+ from ..abc import (
18
+ ByteStreamConnectable,
19
+ ConnectedUDPSocket,
20
+ ConnectedUNIXDatagramSocket,
21
+ IPAddressType,
22
+ IPSockAddrType,
23
+ SocketListener,
24
+ SocketStream,
25
+ UDPSocket,
26
+ UNIXDatagramSocket,
27
+ UNIXSocketStream,
28
+ )
29
+ from ..streams.stapled import MultiListener
30
+ from ..streams.tls import TLSConnectable, TLSStream
31
+ from ._eventloop import get_async_backend
32
+ from ._resources import aclose_forcefully
33
+ from ._synchronization import Event
34
+ from ._tasks import create_task_group, move_on_after
35
+
36
+ if TYPE_CHECKING:
37
+ from _typeshed import FileDescriptorLike
38
+ else:
39
+ FileDescriptorLike = object
40
+
41
+ if sys.version_info < (3, 11):
42
+ from exceptiongroup import ExceptionGroup
43
+
44
+ if sys.version_info >= (3, 12):
45
+ from typing import override
46
+ else:
47
+ from typing_extensions import override
48
+
49
+ if sys.version_info < (3, 13):
50
+ from typing_extensions import deprecated
51
+ else:
52
+ from warnings import deprecated
53
+
54
+ IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41) # https://bugs.python.org/issue29515
55
+
56
+ AnyIPAddressFamily = Literal[
57
+ AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6
58
+ ]
59
+ IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6]
60
+
61
+
62
+ # tls_hostname given
63
+ @overload
64
+ async def connect_tcp(
65
+ remote_host: IPAddressType,
66
+ remote_port: int,
67
+ *,
68
+ local_host: IPAddressType | None = ...,
69
+ ssl_context: ssl.SSLContext | None = ...,
70
+ tls_standard_compatible: bool = ...,
71
+ tls_hostname: str,
72
+ happy_eyeballs_delay: float = ...,
73
+ ) -> TLSStream: ...
74
+
75
+
76
+ # ssl_context given
77
+ @overload
78
+ async def connect_tcp(
79
+ remote_host: IPAddressType,
80
+ remote_port: int,
81
+ *,
82
+ local_host: IPAddressType | None = ...,
83
+ ssl_context: ssl.SSLContext,
84
+ tls_standard_compatible: bool = ...,
85
+ tls_hostname: str | None = ...,
86
+ happy_eyeballs_delay: float = ...,
87
+ ) -> TLSStream: ...
88
+
89
+
90
+ # tls=True
91
+ @overload
92
+ async def connect_tcp(
93
+ remote_host: IPAddressType,
94
+ remote_port: int,
95
+ *,
96
+ local_host: IPAddressType | None = ...,
97
+ tls: Literal[True],
98
+ ssl_context: ssl.SSLContext | None = ...,
99
+ tls_standard_compatible: bool = ...,
100
+ tls_hostname: str | None = ...,
101
+ happy_eyeballs_delay: float = ...,
102
+ ) -> TLSStream: ...
103
+
104
+
105
+ # tls=False
106
+ @overload
107
+ async def connect_tcp(
108
+ remote_host: IPAddressType,
109
+ remote_port: int,
110
+ *,
111
+ local_host: IPAddressType | None = ...,
112
+ tls: Literal[False],
113
+ ssl_context: ssl.SSLContext | None = ...,
114
+ tls_standard_compatible: bool = ...,
115
+ tls_hostname: str | None = ...,
116
+ happy_eyeballs_delay: float = ...,
117
+ ) -> SocketStream: ...
118
+
119
+
120
+ # No TLS arguments
121
+ @overload
122
+ async def connect_tcp(
123
+ remote_host: IPAddressType,
124
+ remote_port: int,
125
+ *,
126
+ local_host: IPAddressType | None = ...,
127
+ happy_eyeballs_delay: float = ...,
128
+ ) -> SocketStream: ...
129
+
130
+
131
+ async def connect_tcp(
132
+ remote_host: IPAddressType,
133
+ remote_port: int,
134
+ *,
135
+ local_host: IPAddressType | None = None,
136
+ tls: bool = False,
137
+ ssl_context: ssl.SSLContext | None = None,
138
+ tls_standard_compatible: bool = True,
139
+ tls_hostname: str | None = None,
140
+ happy_eyeballs_delay: float = 0.25,
141
+ ) -> SocketStream | TLSStream:
142
+ """
143
+ Connect to a host using the TCP protocol.
144
+
145
+ This function implements the stateless version of the Happy Eyeballs algorithm (RFC
146
+ 6555). If ``remote_host`` is a host name that resolves to multiple IP addresses,
147
+ each one is tried until one connection attempt succeeds. If the first attempt does
148
+ not connected within 250 milliseconds, a second attempt is started using the next
149
+ address in the list, and so on. On IPv6 enabled systems, an IPv6 address (if
150
+ available) is tried first.
151
+
152
+ When the connection has been established, a TLS handshake will be done if either
153
+ ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``.
154
+
155
+ :param remote_host: the IP address or host name to connect to
156
+ :param remote_port: port on the target host to connect to
157
+ :param local_host: the interface address or name to bind the socket to before
158
+ connecting
159
+ :param tls: ``True`` to do a TLS handshake with the connected stream and return a
160
+ :class:`~anyio.streams.tls.TLSStream` instead
161
+ :param ssl_context: the SSL context object to use (if omitted, a default context is
162
+ created)
163
+ :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake
164
+ before closing the stream and requires that the server does this as well.
165
+ Otherwise, :exc:`~ssl.SSLEOFError` may be raised during reads from the stream.
166
+ Some protocols, such as HTTP, require this option to be ``False``.
167
+ See :meth:`~ssl.SSLContext.wrap_socket` for details.
168
+ :param tls_hostname: host name to check the server certificate against (defaults to
169
+ the value of ``remote_host``)
170
+ :param happy_eyeballs_delay: delay (in seconds) before starting the next connection
171
+ attempt
172
+ :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream
173
+ :raises ConnectionFailed: if the connection fails
174
+
175
+ """
176
+ # Placed here due to https://github.com/python/mypy/issues/7057
177
+ connected_stream: SocketStream | None = None
178
+
179
+ async def try_connect(remote_host: str, event: Event) -> None:
180
+ nonlocal connected_stream
181
+ try:
182
+ stream = await asynclib.connect_tcp(remote_host, remote_port, local_address)
183
+ except OSError as exc:
184
+ oserrors.append(exc)
185
+ return
186
+ else:
187
+ if connected_stream is None:
188
+ connected_stream = stream
189
+ tg.cancel_scope.cancel()
190
+ else:
191
+ await stream.aclose()
192
+ finally:
193
+ event.set()
194
+
195
+ asynclib = get_async_backend()
196
+ local_address: IPSockAddrType | None = None
197
+ family = socket.AF_UNSPEC
198
+ if local_host:
199
+ gai_res = await getaddrinfo(str(local_host), None)
200
+ family, *_, local_address = gai_res[0]
201
+
202
+ target_host = str(remote_host)
203
+ try:
204
+ addr_obj = ip_address(remote_host)
205
+ except ValueError:
206
+ addr_obj = None
207
+
208
+ if addr_obj is not None:
209
+ if isinstance(addr_obj, IPv6Address):
210
+ target_addrs = [(socket.AF_INET6, addr_obj.compressed)]
211
+ else:
212
+ target_addrs = [(socket.AF_INET, addr_obj.compressed)]
213
+ else:
214
+ # getaddrinfo() will raise an exception if name resolution fails
215
+ gai_res = await getaddrinfo(
216
+ target_host, remote_port, family=family, type=socket.SOCK_STREAM
217
+ )
218
+
219
+ # Organize the list so that the first address is an IPv6 address (if available)
220
+ # and the second one is an IPv4 addresses. The rest can be in whatever order.
221
+ v6_found = v4_found = False
222
+ target_addrs = []
223
+ for af, *_, sa in gai_res:
224
+ if af == socket.AF_INET6 and not v6_found:
225
+ v6_found = True
226
+ target_addrs.insert(0, (af, sa[0]))
227
+ elif af == socket.AF_INET and not v4_found and v6_found:
228
+ v4_found = True
229
+ target_addrs.insert(1, (af, sa[0]))
230
+ else:
231
+ target_addrs.append((af, sa[0]))
232
+
233
+ oserrors: list[OSError] = []
234
+ try:
235
+ async with create_task_group() as tg:
236
+ for _af, addr in target_addrs:
237
+ event = Event()
238
+ tg.start_soon(try_connect, addr, event)
239
+ with move_on_after(happy_eyeballs_delay):
240
+ await event.wait()
241
+
242
+ if connected_stream is None:
243
+ cause = (
244
+ oserrors[0]
245
+ if len(oserrors) == 1
246
+ else ExceptionGroup("multiple connection attempts failed", oserrors)
247
+ )
248
+ raise OSError("All connection attempts failed") from cause
249
+ finally:
250
+ oserrors.clear()
251
+
252
+ if tls or tls_hostname or ssl_context:
253
+ try:
254
+ return await TLSStream.wrap(
255
+ connected_stream,
256
+ server_side=False,
257
+ hostname=tls_hostname or str(remote_host),
258
+ ssl_context=ssl_context,
259
+ standard_compatible=tls_standard_compatible,
260
+ )
261
+ except BaseException:
262
+ await aclose_forcefully(connected_stream)
263
+ raise
264
+
265
+ return connected_stream
266
+
267
+
268
+ async def connect_unix(path: str | bytes | PathLike[Any]) -> UNIXSocketStream:
269
+ """
270
+ Connect to the given UNIX socket.
271
+
272
+ Not available on Windows.
273
+
274
+ :param path: path to the socket
275
+ :return: a socket stream object
276
+ :raises ConnectionFailed: if the connection fails
277
+
278
+ """
279
+ path = os.fspath(path)
280
+ return await get_async_backend().connect_unix(path)
281
+
282
+
283
+ async def create_tcp_listener(
284
+ *,
285
+ local_host: IPAddressType | None = None,
286
+ local_port: int = 0,
287
+ family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC,
288
+ backlog: int = 65536,
289
+ reuse_port: bool = False,
290
+ ) -> MultiListener[SocketStream]:
291
+ """
292
+ Create a TCP socket listener.
293
+
294
+ :param local_port: port number to listen on
295
+ :param local_host: IP address of the interface to listen on. If omitted, listen on
296
+ all IPv4 and IPv6 interfaces. To listen on all interfaces on a specific address
297
+ family, use ``0.0.0.0`` for IPv4 or ``::`` for IPv6.
298
+ :param family: address family (used if ``local_host`` was omitted)
299
+ :param backlog: maximum number of queued incoming connections (up to a maximum of
300
+ 2**16, or 65536)
301
+ :param reuse_port: ``True`` to allow multiple sockets to bind to the same
302
+ address/port (not supported on Windows)
303
+ :return: a multi-listener object containing one or more socket listeners
304
+ :raises OSError: if there's an error creating a socket, or binding to one or more
305
+ interfaces failed
306
+
307
+ """
308
+ asynclib = get_async_backend()
309
+ backlog = min(backlog, 65536)
310
+ local_host = str(local_host) if local_host is not None else None
311
+
312
+ def setup_raw_socket(
313
+ fam: AddressFamily,
314
+ bind_addr: tuple[str, int] | tuple[str, int, int, int],
315
+ *,
316
+ v6only: bool = True,
317
+ ) -> socket.socket:
318
+ sock = socket.socket(fam)
319
+ try:
320
+ sock.setblocking(False)
321
+
322
+ if fam == AddressFamily.AF_INET6:
323
+ sock.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, v6only)
324
+
325
+ # For Windows, enable exclusive address use. For others, enable address
326
+ # reuse.
327
+ if sys.platform == "win32":
328
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
329
+ else:
330
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
331
+
332
+ if reuse_port:
333
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
334
+
335
+ # Workaround for #554
336
+ if fam == socket.AF_INET6 and "%" in bind_addr[0]:
337
+ addr, scope_id = bind_addr[0].split("%", 1)
338
+ bind_addr = (addr, bind_addr[1], 0, int(scope_id))
339
+
340
+ sock.bind(bind_addr)
341
+ sock.listen(backlog)
342
+ except BaseException:
343
+ sock.close()
344
+ raise
345
+
346
+ return sock
347
+
348
+ # We passing type=0 on non-Windows platforms as a workaround for a uvloop bug
349
+ # where we don't get the correct scope ID for IPv6 link-local addresses when passing
350
+ # type=socket.SOCK_STREAM to getaddrinfo():
351
+ # https://github.com/MagicStack/uvloop/issues/539
352
+ gai_res = await getaddrinfo(
353
+ local_host,
354
+ local_port,
355
+ family=family,
356
+ type=socket.SOCK_STREAM if sys.platform == "win32" else 0,
357
+ flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
358
+ )
359
+
360
+ # The set comprehension is here to work around a glibc bug:
361
+ # https://sourceware.org/bugzilla/show_bug.cgi?id=14969
362
+ sockaddrs = sorted({res for res in gai_res if res[1] == SocketKind.SOCK_STREAM})
363
+
364
+ # Special case for dual-stack binding on the "any" interface
365
+ if (
366
+ local_host is None
367
+ and family == AddressFamily.AF_UNSPEC
368
+ and socket.has_dualstack_ipv6()
369
+ and any(fam == AddressFamily.AF_INET6 for fam, *_ in gai_res)
370
+ ):
371
+ raw_socket = setup_raw_socket(
372
+ AddressFamily.AF_INET6, ("::", local_port), v6only=False
373
+ )
374
+ listener = asynclib.create_tcp_listener(raw_socket)
375
+ return MultiListener([listener])
376
+
377
+ errors: list[OSError] = []
378
+ try:
379
+ for _ in range(len(sockaddrs)):
380
+ listeners: list[SocketListener] = []
381
+ bound_ephemeral_port = local_port
382
+ try:
383
+ for fam, *_, sockaddr in sockaddrs:
384
+ sockaddr = sockaddr[0], bound_ephemeral_port, *sockaddr[2:]
385
+ raw_socket = setup_raw_socket(fam, sockaddr)
386
+
387
+ # Store the assigned port if an ephemeral port was requested, so
388
+ # we'll bind to the same port on all interfaces
389
+ if local_port == 0 and len(gai_res) > 1:
390
+ bound_ephemeral_port = raw_socket.getsockname()[1]
391
+
392
+ listeners.append(asynclib.create_tcp_listener(raw_socket))
393
+ except BaseException as exc:
394
+ for listener in listeners:
395
+ await listener.aclose()
396
+
397
+ # If an ephemeral port was requested but binding the assigned port
398
+ # failed for another interface, rotate the address list and try again
399
+ if (
400
+ isinstance(exc, OSError)
401
+ and exc.errno == errno.EADDRINUSE
402
+ and local_port == 0
403
+ and bound_ephemeral_port
404
+ ):
405
+ errors.append(exc)
406
+ sockaddrs.append(sockaddrs.pop(0))
407
+ continue
408
+
409
+ raise
410
+
411
+ return MultiListener(listeners)
412
+
413
+ raise OSError(
414
+ f"Could not create {len(sockaddrs)} listeners with a consistent port"
415
+ ) from ExceptionGroup("Several bind attempts failed", errors)
416
+ finally:
417
+ del errors # Prevent reference cycles
418
+
419
+
420
+ async def create_unix_listener(
421
+ path: str | bytes | PathLike[Any],
422
+ *,
423
+ mode: int | None = None,
424
+ backlog: int = 65536,
425
+ ) -> SocketListener:
426
+ """
427
+ Create a UNIX socket listener.
428
+
429
+ Not available on Windows.
430
+
431
+ :param path: path of the socket
432
+ :param mode: permissions to set on the socket
433
+ :param backlog: maximum number of queued incoming connections (up to a maximum of
434
+ 2**16, or 65536)
435
+ :return: a listener object
436
+
437
+ .. versionchanged:: 3.0
438
+ If a socket already exists on the file system in the given path, it will be
439
+ removed first.
440
+
441
+ """
442
+ backlog = min(backlog, 65536)
443
+ raw_socket = await setup_unix_local_socket(path, mode, socket.SOCK_STREAM)
444
+ try:
445
+ raw_socket.listen(backlog)
446
+ return get_async_backend().create_unix_listener(raw_socket)
447
+ except BaseException:
448
+ raw_socket.close()
449
+ raise
450
+
451
+
452
+ async def create_udp_socket(
453
+ family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC,
454
+ *,
455
+ local_host: IPAddressType | None = None,
456
+ local_port: int = 0,
457
+ reuse_port: bool = False,
458
+ ) -> UDPSocket:
459
+ """
460
+ Create a UDP socket.
461
+
462
+ If ``port`` has been given, the socket will be bound to this port on the local
463
+ machine, making this socket suitable for providing UDP based services.
464
+
465
+ :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically
466
+ determined from ``local_host`` if omitted
467
+ :param local_host: IP address or host name of the local interface to bind to
468
+ :param local_port: local port to bind to
469
+ :param reuse_port: ``True`` to allow multiple sockets to bind to the same
470
+ address/port (not supported on Windows)
471
+ :return: a UDP socket
472
+
473
+ """
474
+ if family is AddressFamily.AF_UNSPEC and not local_host:
475
+ raise ValueError('Either "family" or "local_host" must be given')
476
+
477
+ if local_host:
478
+ gai_res = await getaddrinfo(
479
+ str(local_host),
480
+ local_port,
481
+ family=family,
482
+ type=socket.SOCK_DGRAM,
483
+ flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
484
+ )
485
+ family = cast(AnyIPAddressFamily, gai_res[0][0])
486
+ local_address = gai_res[0][-1]
487
+ elif family is AddressFamily.AF_INET6:
488
+ local_address = ("::", 0)
489
+ else:
490
+ local_address = ("0.0.0.0", 0)
491
+
492
+ sock = await get_async_backend().create_udp_socket(
493
+ family, local_address, None, reuse_port
494
+ )
495
+ return cast(UDPSocket, sock)
496
+
497
+
498
+ async def create_connected_udp_socket(
499
+ remote_host: IPAddressType,
500
+ remote_port: int,
501
+ *,
502
+ family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC,
503
+ local_host: IPAddressType | None = None,
504
+ local_port: int = 0,
505
+ reuse_port: bool = False,
506
+ ) -> ConnectedUDPSocket:
507
+ """
508
+ Create a connected UDP socket.
509
+
510
+ Connected UDP sockets can only communicate with the specified remote host/port, an
511
+ any packets sent from other sources are dropped.
512
+
513
+ :param remote_host: remote host to set as the default target
514
+ :param remote_port: port on the remote host to set as the default target
515
+ :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically
516
+ determined from ``local_host`` or ``remote_host`` if omitted
517
+ :param local_host: IP address or host name of the local interface to bind to
518
+ :param local_port: local port to bind to
519
+ :param reuse_port: ``True`` to allow multiple sockets to bind to the same
520
+ address/port (not supported on Windows)
521
+ :return: a connected UDP socket
522
+
523
+ """
524
+ local_address = None
525
+ if local_host:
526
+ gai_res = await getaddrinfo(
527
+ str(local_host),
528
+ local_port,
529
+ family=family,
530
+ type=socket.SOCK_DGRAM,
531
+ flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
532
+ )
533
+ family = cast(AnyIPAddressFamily, gai_res[0][0])
534
+ local_address = gai_res[0][-1]
535
+
536
+ gai_res = await getaddrinfo(
537
+ str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM
538
+ )
539
+ family = cast(AnyIPAddressFamily, gai_res[0][0])
540
+ remote_address = gai_res[0][-1]
541
+
542
+ sock = await get_async_backend().create_udp_socket(
543
+ family, local_address, remote_address, reuse_port
544
+ )
545
+ return cast(ConnectedUDPSocket, sock)
546
+
547
+
548
+ async def create_unix_datagram_socket(
549
+ *,
550
+ local_path: None | str | bytes | PathLike[Any] = None,
551
+ local_mode: int | None = None,
552
+ ) -> UNIXDatagramSocket:
553
+ """
554
+ Create a UNIX datagram socket.
555
+
556
+ Not available on Windows.
557
+
558
+ If ``local_path`` has been given, the socket will be bound to this path, making this
559
+ socket suitable for receiving datagrams from other processes. Other processes can
560
+ send datagrams to this socket only if ``local_path`` is set.
561
+
562
+ If a socket already exists on the file system in the ``local_path``, it will be
563
+ removed first.
564
+
565
+ :param local_path: the path on which to bind to
566
+ :param local_mode: permissions to set on the local socket
567
+ :return: a UNIX datagram socket
568
+
569
+ """
570
+ raw_socket = await setup_unix_local_socket(
571
+ local_path, local_mode, socket.SOCK_DGRAM
572
+ )
573
+ return await get_async_backend().create_unix_datagram_socket(raw_socket, None)
574
+
575
+
576
+ async def create_connected_unix_datagram_socket(
577
+ remote_path: str | bytes | PathLike[Any],
578
+ *,
579
+ local_path: None | str | bytes | PathLike[Any] = None,
580
+ local_mode: int | None = None,
581
+ ) -> ConnectedUNIXDatagramSocket:
582
+ """
583
+ Create a connected UNIX datagram socket.
584
+
585
+ Connected datagram sockets can only communicate with the specified remote path.
586
+
587
+ If ``local_path`` has been given, the socket will be bound to this path, making
588
+ this socket suitable for receiving datagrams from other processes. Other processes
589
+ can send datagrams to this socket only if ``local_path`` is set.
590
+
591
+ If a socket already exists on the file system in the ``local_path``, it will be
592
+ removed first.
593
+
594
+ :param remote_path: the path to set as the default target
595
+ :param local_path: the path on which to bind to
596
+ :param local_mode: permissions to set on the local socket
597
+ :return: a connected UNIX datagram socket
598
+
599
+ """
600
+ remote_path = os.fspath(remote_path)
601
+ raw_socket = await setup_unix_local_socket(
602
+ local_path, local_mode, socket.SOCK_DGRAM
603
+ )
604
+ return await get_async_backend().create_unix_datagram_socket(
605
+ raw_socket, remote_path
606
+ )
607
+
608
+
609
+ async def getaddrinfo(
610
+ host: bytes | str | None,
611
+ port: str | int | None,
612
+ *,
613
+ family: int | AddressFamily = 0,
614
+ type: int | SocketKind = 0,
615
+ proto: int = 0,
616
+ flags: int = 0,
617
+ ) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int]]]:
618
+ """
619
+ Look up a numeric IP address given a host name.
620
+
621
+ Internationalized domain names are translated according to the (non-transitional)
622
+ IDNA 2008 standard.
623
+
624
+ .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of
625
+ (host, port), unlike what :func:`socket.getaddrinfo` does.
626
+
627
+ :param host: host name
628
+ :param port: port number
629
+ :param family: socket family (`'AF_INET``, ...)
630
+ :param type: socket type (``SOCK_STREAM``, ...)
631
+ :param proto: protocol number
632
+ :param flags: flags to pass to upstream ``getaddrinfo()``
633
+ :return: list of tuples containing (family, type, proto, canonname, sockaddr)
634
+
635
+ .. seealso:: :func:`socket.getaddrinfo`
636
+
637
+ """
638
+ # Handle unicode hostnames
639
+ if isinstance(host, str):
640
+ try:
641
+ encoded_host: bytes | None = host.encode("ascii")
642
+ except UnicodeEncodeError:
643
+ import idna
644
+
645
+ encoded_host = idna.encode(host, uts46=True)
646
+ else:
647
+ encoded_host = host
648
+
649
+ gai_res = await get_async_backend().getaddrinfo(
650
+ encoded_host, port, family=family, type=type, proto=proto, flags=flags
651
+ )
652
+ return [
653
+ (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr))
654
+ for family, type, proto, canonname, sockaddr in gai_res
655
+ # filter out IPv6 results when IPv6 is disabled
656
+ if not isinstance(sockaddr[0], int)
657
+ ]
658
+
659
+
660
+ def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[tuple[str, str]]:
661
+ """
662
+ Look up the host name of an IP address.
663
+
664
+ :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4)
665
+ :param flags: flags to pass to upstream ``getnameinfo()``
666
+ :return: a tuple of (host name, service name)
667
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
668
+ current thread
669
+
670
+ .. seealso:: :func:`socket.getnameinfo`
671
+
672
+ """
673
+ return get_async_backend().getnameinfo(sockaddr, flags)
674
+
675
+
676
+ @deprecated("This function is deprecated; use `wait_readable` instead")
677
+ def wait_socket_readable(sock: socket.socket) -> Awaitable[None]:
678
+ """
679
+ .. deprecated:: 4.7.0
680
+ Use :func:`wait_readable` instead.
681
+
682
+ Wait until the given socket has data to be read.
683
+
684
+ .. warning:: Only use this on raw sockets that have not been wrapped by any higher
685
+ level constructs like socket streams!
686
+
687
+ :param sock: a socket object
688
+ :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the
689
+ socket to become readable
690
+ :raises ~anyio.BusyResourceError: if another task is already waiting for the socket
691
+ to become readable
692
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
693
+ current thread
694
+
695
+ """
696
+ return get_async_backend().wait_readable(sock.fileno())
697
+
698
+
699
+ @deprecated("This function is deprecated; use `wait_writable` instead")
700
+ def wait_socket_writable(sock: socket.socket) -> Awaitable[None]:
701
+ """
702
+ .. deprecated:: 4.7.0
703
+ Use :func:`wait_writable` instead.
704
+
705
+ Wait until the given socket can be written to.
706
+
707
+ This does **NOT** work on Windows when using the asyncio backend with a proactor
708
+ event loop (default on py3.8+).
709
+
710
+ .. warning:: Only use this on raw sockets that have not been wrapped by any higher
711
+ level constructs like socket streams!
712
+
713
+ :param sock: a socket object
714
+ :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the
715
+ socket to become writable
716
+ :raises ~anyio.BusyResourceError: if another task is already waiting for the socket
717
+ to become writable
718
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
719
+ current thread
720
+
721
+ """
722
+ return get_async_backend().wait_writable(sock.fileno())
723
+
724
+
725
+ def wait_readable(obj: FileDescriptorLike) -> Awaitable[None]:
726
+ """
727
+ Wait until the given object has data to be read.
728
+
729
+ On Unix systems, ``obj`` must either be an integer file descriptor, or else an
730
+ object with a ``.fileno()`` method which returns an integer file descriptor. Any
731
+ kind of file descriptor can be passed, though the exact semantics will depend on
732
+ your kernel. For example, this probably won't do anything useful for on-disk files.
733
+
734
+ On Windows systems, ``obj`` must either be an integer ``SOCKET`` handle, or else an
735
+ object with a ``.fileno()`` method which returns an integer ``SOCKET`` handle. File
736
+ descriptors aren't supported, and neither are handles that refer to anything besides
737
+ a ``SOCKET``.
738
+
739
+ On backends where this functionality is not natively provided (asyncio
740
+ ``ProactorEventLoop`` on Windows), it is provided using a separate selector thread
741
+ which is set to shut down when the interpreter shuts down.
742
+
743
+ .. warning:: Don't use this on raw sockets that have been wrapped by any higher
744
+ level constructs like socket streams!
745
+
746
+ :param obj: an object with a ``.fileno()`` method or an integer handle
747
+ :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the
748
+ object to become readable
749
+ :raises ~anyio.BusyResourceError: if another task is already waiting for the object
750
+ to become readable
751
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
752
+ current thread
753
+
754
+ """
755
+ return get_async_backend().wait_readable(obj)
756
+
757
+
758
+ def wait_writable(obj: FileDescriptorLike) -> Awaitable[None]:
759
+ """
760
+ Wait until the given object can be written to.
761
+
762
+ :param obj: an object with a ``.fileno()`` method or an integer handle
763
+ :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the
764
+ object to become writable
765
+ :raises ~anyio.BusyResourceError: if another task is already waiting for the object
766
+ to become writable
767
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
768
+ current thread
769
+
770
+ .. seealso:: See the documentation of :func:`wait_readable` for the definition of
771
+ ``obj`` and notes on backend compatibility.
772
+
773
+ .. warning:: Don't use this on raw sockets that have been wrapped by any higher
774
+ level constructs like socket streams!
775
+
776
+ """
777
+ return get_async_backend().wait_writable(obj)
778
+
779
+
780
+ def notify_closing(obj: FileDescriptorLike) -> None:
781
+ """
782
+ Call this before closing a file descriptor (on Unix) or socket (on
783
+ Windows). This will cause any `wait_readable` or `wait_writable`
784
+ calls on the given object to immediately wake up and raise
785
+ `~anyio.ClosedResourceError`.
786
+
787
+ This doesn't actually close the object – you still have to do that
788
+ yourself afterwards. Also, you want to be careful to make sure no
789
+ new tasks start waiting on the object in between when you call this
790
+ and when it's actually closed. So to close something properly, you
791
+ usually want to do these steps in order:
792
+
793
+ 1. Explicitly mark the object as closed, so that any new attempts
794
+ to use it will abort before they start.
795
+ 2. Call `notify_closing` to wake up any already-existing users.
796
+ 3. Actually close the object.
797
+
798
+ It's also possible to do them in a different order if that's more
799
+ convenient, *but only if* you make sure not to have any checkpoints in
800
+ between the steps. This way they all happen in a single atomic
801
+ step, so other tasks won't be able to tell what order they happened
802
+ in anyway.
803
+
804
+ :param obj: an object with a ``.fileno()`` method or an integer handle
805
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
806
+ current thread
807
+
808
+ """
809
+ get_async_backend().notify_closing(obj)
810
+
811
+
812
+ #
813
+ # Private API
814
+ #
815
+
816
+
817
+ def convert_ipv6_sockaddr(
818
+ sockaddr: tuple[str, int, int, int] | tuple[str, int],
819
+ ) -> tuple[str, int]:
820
+ """
821
+ Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format.
822
+
823
+ If the scope ID is nonzero, it is added to the address, separated with ``%``.
824
+ Otherwise the flow id and scope id are simply cut off from the tuple.
825
+ Any other kinds of socket addresses are returned as-is.
826
+
827
+ :param sockaddr: the result of :meth:`~socket.socket.getsockname`
828
+ :return: the converted socket address
829
+
830
+ """
831
+ # This is more complicated than it should be because of MyPy
832
+ if isinstance(sockaddr, tuple) and len(sockaddr) == 4:
833
+ host, port, flowinfo, scope_id = sockaddr
834
+ if scope_id:
835
+ # PyPy (as of v7.3.11) leaves the interface name in the result, so
836
+ # we discard it and only get the scope ID from the end
837
+ # (https://foss.heptapod.net/pypy/pypy/-/issues/3938)
838
+ host = host.split("%")[0]
839
+
840
+ # Add scope_id to the address
841
+ return f"{host}%{scope_id}", port
842
+ else:
843
+ return host, port
844
+ else:
845
+ return sockaddr
846
+
847
+
848
+ async def setup_unix_local_socket(
849
+ path: None | str | bytes | PathLike[Any],
850
+ mode: int | None,
851
+ socktype: int,
852
+ ) -> socket.socket:
853
+ """
854
+ Create a UNIX local socket object, deleting the socket at the given path if it
855
+ exists.
856
+
857
+ Not available on Windows.
858
+
859
+ :param path: path of the socket
860
+ :param mode: permissions to set on the socket
861
+ :param socktype: socket.SOCK_STREAM or socket.SOCK_DGRAM
862
+
863
+ """
864
+ path_str: str | None
865
+ if path is not None:
866
+ path_str = os.fsdecode(path)
867
+
868
+ # Linux abstract namespace sockets aren't backed by a concrete file so skip stat call
869
+ if not path_str.startswith("\0"):
870
+ # Copied from pathlib...
871
+ try:
872
+ stat_result = os.stat(path)
873
+ except OSError as e:
874
+ if e.errno not in (
875
+ errno.ENOENT,
876
+ errno.ENOTDIR,
877
+ errno.EBADF,
878
+ errno.ELOOP,
879
+ ):
880
+ raise
881
+ else:
882
+ if stat.S_ISSOCK(stat_result.st_mode):
883
+ os.unlink(path)
884
+ else:
885
+ path_str = None
886
+
887
+ raw_socket = socket.socket(socket.AF_UNIX, socktype)
888
+ raw_socket.setblocking(False)
889
+
890
+ if path_str is not None:
891
+ try:
892
+ await to_thread.run_sync(raw_socket.bind, path_str, abandon_on_cancel=True)
893
+ if mode is not None:
894
+ await to_thread.run_sync(chmod, path_str, mode, abandon_on_cancel=True)
895
+ except BaseException:
896
+ raw_socket.close()
897
+ raise
898
+
899
+ return raw_socket
900
+
901
+
902
+ @dataclass
903
+ class TCPConnectable(ByteStreamConnectable):
904
+ """
905
+ Connects to a TCP server at the given host and port.
906
+
907
+ :param host: host name or IP address of the server
908
+ :param port: TCP port number of the server
909
+ """
910
+
911
+ host: str | IPv4Address | IPv6Address
912
+ port: int
913
+
914
+ def __post_init__(self) -> None:
915
+ if self.port < 1 or self.port > 65535:
916
+ raise ValueError("TCP port number out of range")
917
+
918
+ @override
919
+ async def connect(self) -> SocketStream:
920
+ try:
921
+ return await connect_tcp(self.host, self.port)
922
+ except OSError as exc:
923
+ raise ConnectionFailed(
924
+ f"error connecting to {self.host}:{self.port}: {exc}"
925
+ ) from exc
926
+
927
+
928
+ @dataclass
929
+ class UNIXConnectable(ByteStreamConnectable):
930
+ """
931
+ Connects to a UNIX domain socket at the given path.
932
+
933
+ :param path: the file system path of the socket
934
+ """
935
+
936
+ path: str | bytes | PathLike[str] | PathLike[bytes]
937
+
938
+ @override
939
+ async def connect(self) -> UNIXSocketStream:
940
+ try:
941
+ return await connect_unix(self.path)
942
+ except OSError as exc:
943
+ raise ConnectionFailed(f"error connecting to {self.path!r}: {exc}") from exc
944
+
945
+
946
+ def as_connectable(
947
+ remote: ByteStreamConnectable
948
+ | tuple[str | IPv4Address | IPv6Address, int]
949
+ | str
950
+ | bytes
951
+ | PathLike[str],
952
+ /,
953
+ *,
954
+ tls: bool = False,
955
+ ssl_context: ssl.SSLContext | None = None,
956
+ tls_hostname: str | None = None,
957
+ tls_standard_compatible: bool = True,
958
+ ) -> ByteStreamConnectable:
959
+ """
960
+ Return a byte stream connectable from the given object.
961
+
962
+ If a bytestream connectable is given, it is returned unchanged.
963
+ If a tuple of (host, port) is given, a TCP connectable is returned.
964
+ If a string or bytes path is given, a UNIX connectable is returned.
965
+
966
+ If ``tls=True``, the connectable will be wrapped in a
967
+ :class:`~.streams.tls.TLSConnectable`.
968
+
969
+ :param remote: a connectable, a tuple of (host, port) or a path to a UNIX socket
970
+ :param tls: if ``True``, wrap the plaintext connectable in a
971
+ :class:`~.streams.tls.TLSConnectable`, using the provided TLS settings)
972
+ :param ssl_context: if ``tls=True``, the SSLContext object to use (if not provided,
973
+ a secure default will be created)
974
+ :param tls_hostname: if ``tls=True``, host name of the server to use for checking
975
+ the server certificate (defaults to the host portion of the address for TCP
976
+ connectables)
977
+ :param tls_standard_compatible: if ``False`` and ``tls=True``, makes the TLS stream
978
+ skip the closing handshake when closing the connection, so it won't raise an
979
+ exception if the server does the same
980
+
981
+ """
982
+ connectable: TCPConnectable | UNIXConnectable | TLSConnectable
983
+ if isinstance(remote, ByteStreamConnectable):
984
+ return remote
985
+ elif isinstance(remote, tuple) and len(remote) == 2:
986
+ connectable = TCPConnectable(*remote)
987
+ elif isinstance(remote, (str, bytes, PathLike)):
988
+ connectable = UNIXConnectable(remote)
989
+ else:
990
+ raise TypeError(f"cannot convert {remote!r} to a connectable")
991
+
992
+ if tls:
993
+ if not tls_hostname and isinstance(connectable, TCPConnectable):
994
+ tls_hostname = str(connectable.host)
995
+
996
+ connectable = TLSConnectable(
997
+ connectable,
998
+ ssl_context=ssl_context,
999
+ hostname=tls_hostname,
1000
+ standard_compatible=tls_standard_compatible,
1001
+ )
1002
+
1003
+ return connectable
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_streams.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ from typing import TypeVar
5
+ from warnings import warn
6
+
7
+ from ..streams.memory import (
8
+ MemoryObjectReceiveStream,
9
+ MemoryObjectSendStream,
10
+ _MemoryObjectStreamState,
11
+ )
12
+
13
+ T_Item = TypeVar("T_Item")
14
+
15
+
16
+ class create_memory_object_stream(
17
+ tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]],
18
+ ):
19
+ """
20
+ Create a memory object stream.
21
+
22
+ The stream's item type can be annotated like
23
+ :func:`create_memory_object_stream[T_Item]`.
24
+
25
+ :param max_buffer_size: number of items held in the buffer until ``send()`` starts
26
+ blocking
27
+ :param item_type: old way of marking the streams with the right generic type for
28
+ static typing (does nothing on AnyIO 4)
29
+
30
+ .. deprecated:: 4.0
31
+ Use ``create_memory_object_stream[YourItemType](...)`` instead.
32
+ :return: a tuple of (send stream, receive stream)
33
+
34
+ """
35
+
36
+ def __new__( # type: ignore[misc]
37
+ cls, max_buffer_size: float = 0, item_type: object = None
38
+ ) -> tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]:
39
+ if max_buffer_size != math.inf and not isinstance(max_buffer_size, int):
40
+ raise ValueError("max_buffer_size must be either an integer or math.inf")
41
+ if max_buffer_size < 0:
42
+ raise ValueError("max_buffer_size cannot be negative")
43
+ if item_type is not None:
44
+ warn(
45
+ "The item_type argument has been deprecated in AnyIO 4.0. "
46
+ "Use create_memory_object_stream[YourItemType](...) instead.",
47
+ DeprecationWarning,
48
+ stacklevel=2,
49
+ )
50
+
51
+ state = _MemoryObjectStreamState[T_Item](max_buffer_size)
52
+ return (MemoryObjectSendStream(state), MemoryObjectReceiveStream(state))
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_subprocesses.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import AsyncIterable, Iterable, Mapping, Sequence
4
+ from io import BytesIO
5
+ from os import PathLike
6
+ from subprocess import PIPE, CalledProcessError, CompletedProcess
7
+ from typing import IO, Any, TypeAlias, cast
8
+
9
+ from ..abc import Process
10
+ from ._eventloop import get_async_backend
11
+ from ._tasks import create_task_group
12
+
13
+ StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes]
14
+
15
+
16
+ async def run_process(
17
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
18
+ *,
19
+ input: bytes | None = None,
20
+ stdin: int | IO[Any] | None = None,
21
+ stdout: int | IO[Any] | None = PIPE,
22
+ stderr: int | IO[Any] | None = PIPE,
23
+ check: bool = True,
24
+ cwd: StrOrBytesPath | None = None,
25
+ env: Mapping[str, str] | None = None,
26
+ startupinfo: Any = None,
27
+ creationflags: int = 0,
28
+ start_new_session: bool = False,
29
+ pass_fds: Sequence[int] = (),
30
+ user: str | int | None = None,
31
+ group: str | int | None = None,
32
+ extra_groups: Iterable[str | int] | None = None,
33
+ umask: int = -1,
34
+ ) -> CompletedProcess[bytes]:
35
+ """
36
+ Run an external command in a subprocess and wait until it completes.
37
+
38
+ .. seealso:: :func:`subprocess.run`
39
+
40
+ :param command: either a string to pass to the shell, or an iterable of strings
41
+ containing the executable name or path and its arguments
42
+ :param input: bytes passed to the standard input of the subprocess
43
+ :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
44
+ a file-like object, or `None`; ``input`` overrides this
45
+ :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
46
+ a file-like object, or `None`
47
+ :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
48
+ :data:`subprocess.STDOUT`, a file-like object, or `None`
49
+ :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the
50
+ process terminates with a return code other than 0
51
+ :param cwd: If not ``None``, change the working directory to this before running the
52
+ command
53
+ :param env: if not ``None``, this mapping replaces the inherited environment
54
+ variables from the parent process
55
+ :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used
56
+ to specify process startup parameters (Windows only)
57
+ :param creationflags: flags that can be used to control the creation of the
58
+ subprocess (see :class:`subprocess.Popen` for the specifics)
59
+ :param start_new_session: if ``true`` the setsid() system call will be made in the
60
+ child process prior to the execution of the subprocess. (POSIX only)
61
+ :param pass_fds: sequence of file descriptors to keep open between the parent and
62
+ child processes. (POSIX only)
63
+ :param user: effective user to run the process as (Python >= 3.9, POSIX only)
64
+ :param group: effective group to run the process as (Python >= 3.9, POSIX only)
65
+ :param extra_groups: supplementary groups to set in the subprocess (Python >= 3.9,
66
+ POSIX only)
67
+ :param umask: if not negative, this umask is applied in the child process before
68
+ running the given command (Python >= 3.9, POSIX only)
69
+ :return: an object representing the completed process
70
+ :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process
71
+ exits with a nonzero return code
72
+
73
+ """
74
+
75
+ async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None:
76
+ buffer = BytesIO()
77
+ async for chunk in stream:
78
+ buffer.write(chunk)
79
+
80
+ stream_contents[index] = buffer.getvalue()
81
+
82
+ if stdin is not None and input is not None:
83
+ raise ValueError("only one of stdin and input is allowed")
84
+
85
+ async with await open_process(
86
+ command,
87
+ stdin=PIPE if input else stdin,
88
+ stdout=stdout,
89
+ stderr=stderr,
90
+ cwd=cwd,
91
+ env=env,
92
+ startupinfo=startupinfo,
93
+ creationflags=creationflags,
94
+ start_new_session=start_new_session,
95
+ pass_fds=pass_fds,
96
+ user=user,
97
+ group=group,
98
+ extra_groups=extra_groups,
99
+ umask=umask,
100
+ ) as process:
101
+ stream_contents: list[bytes | None] = [None, None]
102
+ async with create_task_group() as tg:
103
+ if process.stdout:
104
+ tg.start_soon(drain_stream, process.stdout, 0)
105
+
106
+ if process.stderr:
107
+ tg.start_soon(drain_stream, process.stderr, 1)
108
+
109
+ if process.stdin and input:
110
+ await process.stdin.send(input)
111
+ await process.stdin.aclose()
112
+
113
+ await process.wait()
114
+
115
+ output, errors = stream_contents
116
+ if check and process.returncode != 0:
117
+ raise CalledProcessError(cast(int, process.returncode), command, output, errors)
118
+
119
+ return CompletedProcess(command, cast(int, process.returncode), output, errors)
120
+
121
+
122
+ async def open_process(
123
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
124
+ *,
125
+ stdin: int | IO[Any] | None = PIPE,
126
+ stdout: int | IO[Any] | None = PIPE,
127
+ stderr: int | IO[Any] | None = PIPE,
128
+ cwd: StrOrBytesPath | None = None,
129
+ env: Mapping[str, str] | None = None,
130
+ startupinfo: Any = None,
131
+ creationflags: int = 0,
132
+ start_new_session: bool = False,
133
+ pass_fds: Sequence[int] = (),
134
+ user: str | int | None = None,
135
+ group: str | int | None = None,
136
+ extra_groups: Iterable[str | int] | None = None,
137
+ umask: int = -1,
138
+ ) -> Process:
139
+ """
140
+ Start an external command in a subprocess.
141
+
142
+ .. seealso:: :class:`subprocess.Popen`
143
+
144
+ :param command: either a string to pass to the shell, or an iterable of strings
145
+ containing the executable name or path and its arguments
146
+ :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a
147
+ file-like object, or ``None``
148
+ :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
149
+ a file-like object, or ``None``
150
+ :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
151
+ :data:`subprocess.STDOUT`, a file-like object, or ``None``
152
+ :param cwd: If not ``None``, the working directory is changed before executing
153
+ :param env: If env is not ``None``, it must be a mapping that defines the
154
+ environment variables for the new process
155
+ :param creationflags: flags that can be used to control the creation of the
156
+ subprocess (see :class:`subprocess.Popen` for the specifics)
157
+ :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used
158
+ to specify process startup parameters (Windows only)
159
+ :param start_new_session: if ``true`` the setsid() system call will be made in the
160
+ child process prior to the execution of the subprocess. (POSIX only)
161
+ :param pass_fds: sequence of file descriptors to keep open between the parent and
162
+ child processes. (POSIX only)
163
+ :param user: effective user to run the process as (POSIX only)
164
+ :param group: effective group to run the process as (POSIX only)
165
+ :param extra_groups: supplementary groups to set in the subprocess (POSIX only)
166
+ :param umask: if not negative, this umask is applied in the child process before
167
+ running the given command (POSIX only)
168
+ :return: an asynchronous process object
169
+
170
+ """
171
+ kwargs: dict[str, Any] = {}
172
+ if user is not None:
173
+ kwargs["user"] = user
174
+
175
+ if group is not None:
176
+ kwargs["group"] = group
177
+
178
+ if extra_groups is not None:
179
+ kwargs["extra_groups"] = group
180
+
181
+ if umask >= 0:
182
+ kwargs["umask"] = umask
183
+
184
+ return await get_async_backend().open_process(
185
+ command,
186
+ stdin=stdin,
187
+ stdout=stdout,
188
+ stderr=stderr,
189
+ cwd=cwd,
190
+ env=env,
191
+ startupinfo=startupinfo,
192
+ creationflags=creationflags,
193
+ start_new_session=start_new_session,
194
+ pass_fds=pass_fds,
195
+ **kwargs,
196
+ )
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_synchronization.py ADDED
@@ -0,0 +1,757 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ from collections import deque
5
+ from collections.abc import Callable
6
+ from dataclasses import dataclass
7
+ from types import TracebackType
8
+ from typing import TypeVar
9
+
10
+ from ..lowlevel import checkpoint_if_cancelled
11
+ from ._eventloop import get_async_backend
12
+ from ._exceptions import BusyResourceError, NoEventLoopError
13
+ from ._tasks import CancelScope
14
+ from ._testing import TaskInfo, get_current_task
15
+
16
+ T = TypeVar("T")
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class EventStatistics:
21
+ """
22
+ :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait`
23
+ """
24
+
25
+ tasks_waiting: int
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class CapacityLimiterStatistics:
30
+ """
31
+ :ivar int borrowed_tokens: number of tokens currently borrowed by tasks
32
+ :ivar float total_tokens: total number of available tokens
33
+ :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from
34
+ this limiter
35
+ :ivar int tasks_waiting: number of tasks waiting on
36
+ :meth:`~.CapacityLimiter.acquire` or
37
+ :meth:`~.CapacityLimiter.acquire_on_behalf_of`
38
+ """
39
+
40
+ borrowed_tokens: int
41
+ total_tokens: float
42
+ borrowers: tuple[object, ...]
43
+ tasks_waiting: int
44
+
45
+
46
+ @dataclass(frozen=True)
47
+ class LockStatistics:
48
+ """
49
+ :ivar bool locked: flag indicating if this lock is locked or not
50
+ :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the
51
+ lock is not held by any task)
52
+ :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire`
53
+ """
54
+
55
+ locked: bool
56
+ owner: TaskInfo | None
57
+ tasks_waiting: int
58
+
59
+
60
+ @dataclass(frozen=True)
61
+ class ConditionStatistics:
62
+ """
63
+ :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait`
64
+ :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying
65
+ :class:`~.Lock`
66
+ """
67
+
68
+ tasks_waiting: int
69
+ lock_statistics: LockStatistics
70
+
71
+
72
+ @dataclass(frozen=True)
73
+ class SemaphoreStatistics:
74
+ """
75
+ :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire`
76
+
77
+ """
78
+
79
+ tasks_waiting: int
80
+
81
+
82
+ class Event:
83
+ def __new__(cls) -> Event:
84
+ try:
85
+ return get_async_backend().create_event()
86
+ except NoEventLoopError:
87
+ return EventAdapter()
88
+
89
+ def set(self) -> None:
90
+ """Set the flag, notifying all listeners."""
91
+ raise NotImplementedError
92
+
93
+ def is_set(self) -> bool:
94
+ """Return ``True`` if the flag is set, ``False`` if not."""
95
+ raise NotImplementedError
96
+
97
+ async def wait(self) -> None:
98
+ """
99
+ Wait until the flag has been set.
100
+
101
+ If the flag has already been set when this method is called, it returns
102
+ immediately.
103
+
104
+ """
105
+ raise NotImplementedError
106
+
107
+ def statistics(self) -> EventStatistics:
108
+ """Return statistics about the current state of this event."""
109
+ raise NotImplementedError
110
+
111
+
112
+ class EventAdapter(Event):
113
+ _internal_event: Event | None = None
114
+ _is_set: bool = False
115
+
116
+ def __new__(cls) -> EventAdapter:
117
+ return object.__new__(cls)
118
+
119
+ @property
120
+ def _event(self) -> Event:
121
+ if self._internal_event is None:
122
+ self._internal_event = get_async_backend().create_event()
123
+ if self._is_set:
124
+ self._internal_event.set()
125
+
126
+ return self._internal_event
127
+
128
+ def set(self) -> None:
129
+ if self._internal_event is None:
130
+ self._is_set = True
131
+ else:
132
+ self._event.set()
133
+
134
+ def is_set(self) -> bool:
135
+ if self._internal_event is None:
136
+ return self._is_set
137
+
138
+ return self._internal_event.is_set()
139
+
140
+ async def wait(self) -> None:
141
+ await self._event.wait()
142
+
143
+ def statistics(self) -> EventStatistics:
144
+ if self._internal_event is None:
145
+ return EventStatistics(tasks_waiting=0)
146
+
147
+ return self._internal_event.statistics()
148
+
149
+
150
+ class Lock:
151
+ def __new__(cls, *, fast_acquire: bool = False) -> Lock:
152
+ try:
153
+ return get_async_backend().create_lock(fast_acquire=fast_acquire)
154
+ except NoEventLoopError:
155
+ return LockAdapter(fast_acquire=fast_acquire)
156
+
157
+ async def __aenter__(self) -> None:
158
+ await self.acquire()
159
+
160
+ async def __aexit__(
161
+ self,
162
+ exc_type: type[BaseException] | None,
163
+ exc_val: BaseException | None,
164
+ exc_tb: TracebackType | None,
165
+ ) -> None:
166
+ self.release()
167
+
168
+ async def acquire(self) -> None:
169
+ """Acquire the lock."""
170
+ raise NotImplementedError
171
+
172
+ def acquire_nowait(self) -> None:
173
+ """
174
+ Acquire the lock, without blocking.
175
+
176
+ :raises ~anyio.WouldBlock: if the operation would block
177
+
178
+ """
179
+ raise NotImplementedError
180
+
181
+ def release(self) -> None:
182
+ """Release the lock."""
183
+ raise NotImplementedError
184
+
185
+ def locked(self) -> bool:
186
+ """Return True if the lock is currently held."""
187
+ raise NotImplementedError
188
+
189
+ def statistics(self) -> LockStatistics:
190
+ """
191
+ Return statistics about the current state of this lock.
192
+
193
+ .. versionadded:: 3.0
194
+ """
195
+ raise NotImplementedError
196
+
197
+
198
+ class LockAdapter(Lock):
199
+ _internal_lock: Lock | None = None
200
+
201
+ def __new__(cls, *, fast_acquire: bool = False) -> LockAdapter:
202
+ return object.__new__(cls)
203
+
204
+ def __init__(self, *, fast_acquire: bool = False):
205
+ self._fast_acquire = fast_acquire
206
+
207
+ @property
208
+ def _lock(self) -> Lock:
209
+ if self._internal_lock is None:
210
+ self._internal_lock = get_async_backend().create_lock(
211
+ fast_acquire=self._fast_acquire
212
+ )
213
+
214
+ return self._internal_lock
215
+
216
+ async def __aenter__(self) -> None:
217
+ await self._lock.acquire()
218
+
219
+ async def __aexit__(
220
+ self,
221
+ exc_type: type[BaseException] | None,
222
+ exc_val: BaseException | None,
223
+ exc_tb: TracebackType | None,
224
+ ) -> None:
225
+ if self._internal_lock is not None:
226
+ self._internal_lock.release()
227
+
228
+ async def acquire(self) -> None:
229
+ """Acquire the lock."""
230
+ await self._lock.acquire()
231
+
232
+ def acquire_nowait(self) -> None:
233
+ """
234
+ Acquire the lock, without blocking.
235
+
236
+ :raises ~anyio.WouldBlock: if the operation would block
237
+
238
+ """
239
+ self._lock.acquire_nowait()
240
+
241
+ def release(self) -> None:
242
+ """Release the lock."""
243
+ self._lock.release()
244
+
245
+ def locked(self) -> bool:
246
+ """Return True if the lock is currently held."""
247
+ return self._lock.locked()
248
+
249
+ def statistics(self) -> LockStatistics:
250
+ """
251
+ Return statistics about the current state of this lock.
252
+
253
+ .. versionadded:: 3.0
254
+
255
+ """
256
+ if self._internal_lock is None:
257
+ return LockStatistics(False, None, 0)
258
+
259
+ return self._internal_lock.statistics()
260
+
261
+
262
+ class Condition:
263
+ _owner_task: TaskInfo | None = None
264
+
265
+ def __init__(self, lock: Lock | None = None):
266
+ self._lock = lock or Lock()
267
+ self._waiters: deque[Event] = deque()
268
+
269
+ async def __aenter__(self) -> None:
270
+ await self.acquire()
271
+
272
+ async def __aexit__(
273
+ self,
274
+ exc_type: type[BaseException] | None,
275
+ exc_val: BaseException | None,
276
+ exc_tb: TracebackType | None,
277
+ ) -> None:
278
+ self.release()
279
+
280
+ def _check_acquired(self) -> None:
281
+ if self._owner_task != get_current_task():
282
+ raise RuntimeError("The current task is not holding the underlying lock")
283
+
284
+ async def acquire(self) -> None:
285
+ """Acquire the underlying lock."""
286
+ await self._lock.acquire()
287
+ self._owner_task = get_current_task()
288
+
289
+ def acquire_nowait(self) -> None:
290
+ """
291
+ Acquire the underlying lock, without blocking.
292
+
293
+ :raises ~anyio.WouldBlock: if the operation would block
294
+
295
+ """
296
+ self._lock.acquire_nowait()
297
+ self._owner_task = get_current_task()
298
+
299
+ def release(self) -> None:
300
+ """Release the underlying lock."""
301
+ self._lock.release()
302
+
303
+ def locked(self) -> bool:
304
+ """Return True if the lock is set."""
305
+ return self._lock.locked()
306
+
307
+ def notify(self, n: int = 1) -> None:
308
+ """Notify exactly n listeners."""
309
+ self._check_acquired()
310
+ for _ in range(n):
311
+ try:
312
+ event = self._waiters.popleft()
313
+ except IndexError:
314
+ break
315
+
316
+ event.set()
317
+
318
+ def notify_all(self) -> None:
319
+ """Notify all the listeners."""
320
+ self._check_acquired()
321
+ for event in self._waiters:
322
+ event.set()
323
+
324
+ self._waiters.clear()
325
+
326
+ async def wait(self) -> None:
327
+ """Wait for a notification."""
328
+ await checkpoint_if_cancelled()
329
+ self._check_acquired()
330
+ event = Event()
331
+ self._waiters.append(event)
332
+ self.release()
333
+ try:
334
+ await event.wait()
335
+ except BaseException:
336
+ if not event.is_set():
337
+ self._waiters.remove(event)
338
+ elif self._waiters:
339
+ # This task was notified by could not act on it, so pass
340
+ # it on to the next task
341
+ self._waiters.popleft().set()
342
+
343
+ raise
344
+ finally:
345
+ with CancelScope(shield=True):
346
+ await self.acquire()
347
+
348
+ async def wait_for(self, predicate: Callable[[], T]) -> T:
349
+ """
350
+ Wait until a predicate becomes true.
351
+
352
+ :param predicate: a callable that returns a truthy value when the condition is
353
+ met
354
+ :return: the result of the predicate
355
+
356
+ .. versionadded:: 4.11.0
357
+
358
+ """
359
+ while not (result := predicate()):
360
+ await self.wait()
361
+
362
+ return result
363
+
364
+ def statistics(self) -> ConditionStatistics:
365
+ """
366
+ Return statistics about the current state of this condition.
367
+
368
+ .. versionadded:: 3.0
369
+ """
370
+ return ConditionStatistics(len(self._waiters), self._lock.statistics())
371
+
372
+
373
+ class Semaphore:
374
+ def __new__(
375
+ cls,
376
+ initial_value: int,
377
+ *,
378
+ max_value: int | None = None,
379
+ fast_acquire: bool = False,
380
+ ) -> Semaphore:
381
+ try:
382
+ return get_async_backend().create_semaphore(
383
+ initial_value, max_value=max_value, fast_acquire=fast_acquire
384
+ )
385
+ except NoEventLoopError:
386
+ return SemaphoreAdapter(initial_value, max_value=max_value)
387
+
388
+ def __init__(
389
+ self,
390
+ initial_value: int,
391
+ *,
392
+ max_value: int | None = None,
393
+ fast_acquire: bool = False,
394
+ ):
395
+ if not isinstance(initial_value, int):
396
+ raise TypeError("initial_value must be an integer")
397
+ if initial_value < 0:
398
+ raise ValueError("initial_value must be >= 0")
399
+ if max_value is not None:
400
+ if not isinstance(max_value, int):
401
+ raise TypeError("max_value must be an integer or None")
402
+ if max_value < initial_value:
403
+ raise ValueError(
404
+ "max_value must be equal to or higher than initial_value"
405
+ )
406
+
407
+ self._fast_acquire = fast_acquire
408
+
409
+ async def __aenter__(self) -> Semaphore:
410
+ await self.acquire()
411
+ return self
412
+
413
+ async def __aexit__(
414
+ self,
415
+ exc_type: type[BaseException] | None,
416
+ exc_val: BaseException | None,
417
+ exc_tb: TracebackType | None,
418
+ ) -> None:
419
+ self.release()
420
+
421
+ async def acquire(self) -> None:
422
+ """Decrement the semaphore value, blocking if necessary."""
423
+ raise NotImplementedError
424
+
425
+ def acquire_nowait(self) -> None:
426
+ """
427
+ Acquire the underlying lock, without blocking.
428
+
429
+ :raises ~anyio.WouldBlock: if the operation would block
430
+
431
+ """
432
+ raise NotImplementedError
433
+
434
+ def release(self) -> None:
435
+ """Increment the semaphore value."""
436
+ raise NotImplementedError
437
+
438
+ @property
439
+ def value(self) -> int:
440
+ """The current value of the semaphore."""
441
+ raise NotImplementedError
442
+
443
+ @property
444
+ def max_value(self) -> int | None:
445
+ """The maximum value of the semaphore."""
446
+ raise NotImplementedError
447
+
448
+ def statistics(self) -> SemaphoreStatistics:
449
+ """
450
+ Return statistics about the current state of this semaphore.
451
+
452
+ .. versionadded:: 3.0
453
+ """
454
+ raise NotImplementedError
455
+
456
+
457
+ class SemaphoreAdapter(Semaphore):
458
+ _internal_semaphore: Semaphore | None = None
459
+
460
+ def __new__(
461
+ cls,
462
+ initial_value: int,
463
+ *,
464
+ max_value: int | None = None,
465
+ fast_acquire: bool = False,
466
+ ) -> SemaphoreAdapter:
467
+ return object.__new__(cls)
468
+
469
+ def __init__(
470
+ self,
471
+ initial_value: int,
472
+ *,
473
+ max_value: int | None = None,
474
+ fast_acquire: bool = False,
475
+ ) -> None:
476
+ super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
477
+ self._initial_value = initial_value
478
+ self._max_value = max_value
479
+
480
+ @property
481
+ def _semaphore(self) -> Semaphore:
482
+ if self._internal_semaphore is None:
483
+ self._internal_semaphore = get_async_backend().create_semaphore(
484
+ self._initial_value, max_value=self._max_value
485
+ )
486
+
487
+ return self._internal_semaphore
488
+
489
+ async def acquire(self) -> None:
490
+ await self._semaphore.acquire()
491
+
492
+ def acquire_nowait(self) -> None:
493
+ self._semaphore.acquire_nowait()
494
+
495
+ def release(self) -> None:
496
+ self._semaphore.release()
497
+
498
+ @property
499
+ def value(self) -> int:
500
+ if self._internal_semaphore is None:
501
+ return self._initial_value
502
+
503
+ return self._semaphore.value
504
+
505
+ @property
506
+ def max_value(self) -> int | None:
507
+ return self._max_value
508
+
509
+ def statistics(self) -> SemaphoreStatistics:
510
+ if self._internal_semaphore is None:
511
+ return SemaphoreStatistics(tasks_waiting=0)
512
+
513
+ return self._semaphore.statistics()
514
+
515
+
516
+ class CapacityLimiter:
517
+ def __new__(cls, total_tokens: float) -> CapacityLimiter:
518
+ try:
519
+ return get_async_backend().create_capacity_limiter(total_tokens)
520
+ except NoEventLoopError:
521
+ return CapacityLimiterAdapter(total_tokens)
522
+
523
+ async def __aenter__(self) -> None:
524
+ raise NotImplementedError
525
+
526
+ async def __aexit__(
527
+ self,
528
+ exc_type: type[BaseException] | None,
529
+ exc_val: BaseException | None,
530
+ exc_tb: TracebackType | None,
531
+ ) -> None:
532
+ raise NotImplementedError
533
+
534
+ @property
535
+ def total_tokens(self) -> float:
536
+ """
537
+ The total number of tokens available for borrowing.
538
+
539
+ This is a read-write property. If the total number of tokens is increased, the
540
+ proportionate number of tasks waiting on this limiter will be granted their
541
+ tokens.
542
+
543
+ .. versionchanged:: 3.0
544
+ The property is now writable.
545
+ .. versionchanged:: 4.12
546
+ The value can now be set to 0.
547
+
548
+ """
549
+ raise NotImplementedError
550
+
551
+ @total_tokens.setter
552
+ def total_tokens(self, value: float) -> None:
553
+ raise NotImplementedError
554
+
555
+ @property
556
+ def borrowed_tokens(self) -> int:
557
+ """The number of tokens that have currently been borrowed."""
558
+ raise NotImplementedError
559
+
560
+ @property
561
+ def available_tokens(self) -> float:
562
+ """The number of tokens currently available to be borrowed"""
563
+ raise NotImplementedError
564
+
565
+ def acquire_nowait(self) -> None:
566
+ """
567
+ Acquire a token for the current task without waiting for one to become
568
+ available.
569
+
570
+ :raises ~anyio.WouldBlock: if there are no tokens available for borrowing
571
+
572
+ """
573
+ raise NotImplementedError
574
+
575
+ def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
576
+ """
577
+ Acquire a token without waiting for one to become available.
578
+
579
+ :param borrower: the entity borrowing a token
580
+ :raises ~anyio.WouldBlock: if there are no tokens available for borrowing
581
+
582
+ """
583
+ raise NotImplementedError
584
+
585
+ async def acquire(self) -> None:
586
+ """
587
+ Acquire a token for the current task, waiting if necessary for one to become
588
+ available.
589
+
590
+ """
591
+ raise NotImplementedError
592
+
593
+ async def acquire_on_behalf_of(self, borrower: object) -> None:
594
+ """
595
+ Acquire a token, waiting if necessary for one to become available.
596
+
597
+ :param borrower: the entity borrowing a token
598
+
599
+ """
600
+ raise NotImplementedError
601
+
602
+ def release(self) -> None:
603
+ """
604
+ Release the token held by the current task.
605
+
606
+ :raises RuntimeError: if the current task has not borrowed a token from this
607
+ limiter.
608
+
609
+ """
610
+ raise NotImplementedError
611
+
612
+ def release_on_behalf_of(self, borrower: object) -> None:
613
+ """
614
+ Release the token held by the given borrower.
615
+
616
+ :raises RuntimeError: if the borrower has not borrowed a token from this
617
+ limiter.
618
+
619
+ """
620
+ raise NotImplementedError
621
+
622
+ def statistics(self) -> CapacityLimiterStatistics:
623
+ """
624
+ Return statistics about the current state of this limiter.
625
+
626
+ .. versionadded:: 3.0
627
+
628
+ """
629
+ raise NotImplementedError
630
+
631
+
632
+ class CapacityLimiterAdapter(CapacityLimiter):
633
+ _internal_limiter: CapacityLimiter | None = None
634
+
635
+ def __new__(cls, total_tokens: float) -> CapacityLimiterAdapter:
636
+ return object.__new__(cls)
637
+
638
+ def __init__(self, total_tokens: float) -> None:
639
+ self.total_tokens = total_tokens
640
+
641
+ @property
642
+ def _limiter(self) -> CapacityLimiter:
643
+ if self._internal_limiter is None:
644
+ self._internal_limiter = get_async_backend().create_capacity_limiter(
645
+ self._total_tokens
646
+ )
647
+
648
+ return self._internal_limiter
649
+
650
+ async def __aenter__(self) -> None:
651
+ await self._limiter.__aenter__()
652
+
653
+ async def __aexit__(
654
+ self,
655
+ exc_type: type[BaseException] | None,
656
+ exc_val: BaseException | None,
657
+ exc_tb: TracebackType | None,
658
+ ) -> None:
659
+ return await self._limiter.__aexit__(exc_type, exc_val, exc_tb)
660
+
661
+ @property
662
+ def total_tokens(self) -> float:
663
+ if self._internal_limiter is None:
664
+ return self._total_tokens
665
+
666
+ return self._internal_limiter.total_tokens
667
+
668
+ @total_tokens.setter
669
+ def total_tokens(self, value: float) -> None:
670
+ if not isinstance(value, int) and value is not math.inf:
671
+ raise TypeError("total_tokens must be an int or math.inf")
672
+ elif value < 1:
673
+ raise ValueError("total_tokens must be >= 1")
674
+
675
+ if self._internal_limiter is None:
676
+ self._total_tokens = value
677
+ return
678
+
679
+ self._limiter.total_tokens = value
680
+
681
+ @property
682
+ def borrowed_tokens(self) -> int:
683
+ if self._internal_limiter is None:
684
+ return 0
685
+
686
+ return self._internal_limiter.borrowed_tokens
687
+
688
+ @property
689
+ def available_tokens(self) -> float:
690
+ if self._internal_limiter is None:
691
+ return self._total_tokens
692
+
693
+ return self._internal_limiter.available_tokens
694
+
695
+ def acquire_nowait(self) -> None:
696
+ self._limiter.acquire_nowait()
697
+
698
+ def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
699
+ self._limiter.acquire_on_behalf_of_nowait(borrower)
700
+
701
+ async def acquire(self) -> None:
702
+ await self._limiter.acquire()
703
+
704
+ async def acquire_on_behalf_of(self, borrower: object) -> None:
705
+ await self._limiter.acquire_on_behalf_of(borrower)
706
+
707
+ def release(self) -> None:
708
+ self._limiter.release()
709
+
710
+ def release_on_behalf_of(self, borrower: object) -> None:
711
+ self._limiter.release_on_behalf_of(borrower)
712
+
713
+ def statistics(self) -> CapacityLimiterStatistics:
714
+ if self._internal_limiter is None:
715
+ return CapacityLimiterStatistics(
716
+ borrowed_tokens=0,
717
+ total_tokens=self.total_tokens,
718
+ borrowers=(),
719
+ tasks_waiting=0,
720
+ )
721
+
722
+ return self._internal_limiter.statistics()
723
+
724
+
725
+ class ResourceGuard:
726
+ """
727
+ A context manager for ensuring that a resource is only used by a single task at a
728
+ time.
729
+
730
+ Entering this context manager while the previous has not exited it yet will trigger
731
+ :exc:`BusyResourceError`.
732
+
733
+ :param action: the action to guard against (visible in the :exc:`BusyResourceError`
734
+ when triggered, e.g. "Another task is already {action} this resource")
735
+
736
+ .. versionadded:: 4.1
737
+ """
738
+
739
+ __slots__ = "action", "_guarded"
740
+
741
+ def __init__(self, action: str = "using"):
742
+ self.action: str = action
743
+ self._guarded = False
744
+
745
+ def __enter__(self) -> None:
746
+ if self._guarded:
747
+ raise BusyResourceError(self.action)
748
+
749
+ self._guarded = True
750
+
751
+ def __exit__(
752
+ self,
753
+ exc_type: type[BaseException] | None,
754
+ exc_val: BaseException | None,
755
+ exc_tb: TracebackType | None,
756
+ ) -> None:
757
+ self._guarded = False
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_tasks.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ from collections.abc import Generator
5
+ from contextlib import contextmanager
6
+ from types import TracebackType
7
+
8
+ from ..abc._tasks import TaskGroup, TaskStatus
9
+ from ._eventloop import get_async_backend
10
+
11
+
12
+ class _IgnoredTaskStatus(TaskStatus[object]):
13
+ def started(self, value: object = None) -> None:
14
+ pass
15
+
16
+
17
+ TASK_STATUS_IGNORED = _IgnoredTaskStatus()
18
+
19
+
20
+ class CancelScope:
21
+ """
22
+ Wraps a unit of work that can be made separately cancellable.
23
+
24
+ :param deadline: The time (clock value) when this scope is cancelled automatically
25
+ :param shield: ``True`` to shield the cancel scope from external cancellation
26
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
27
+ current thread
28
+ """
29
+
30
+ def __new__(
31
+ cls, *, deadline: float = math.inf, shield: bool = False
32
+ ) -> CancelScope:
33
+ return get_async_backend().create_cancel_scope(shield=shield, deadline=deadline)
34
+
35
+ def cancel(self, reason: str | None = None) -> None:
36
+ """
37
+ Cancel this scope immediately.
38
+
39
+ :param reason: a message describing the reason for the cancellation
40
+
41
+ """
42
+ raise NotImplementedError
43
+
44
+ @property
45
+ def deadline(self) -> float:
46
+ """
47
+ The time (clock value) when this scope is cancelled automatically.
48
+
49
+ Will be ``float('inf')`` if no timeout has been set.
50
+
51
+ """
52
+ raise NotImplementedError
53
+
54
+ @deadline.setter
55
+ def deadline(self, value: float) -> None:
56
+ raise NotImplementedError
57
+
58
+ @property
59
+ def cancel_called(self) -> bool:
60
+ """``True`` if :meth:`cancel` has been called."""
61
+ raise NotImplementedError
62
+
63
+ @property
64
+ def cancelled_caught(self) -> bool:
65
+ """
66
+ ``True`` if this scope suppressed a cancellation exception it itself raised.
67
+
68
+ This is typically used to check if any work was interrupted, or to see if the
69
+ scope was cancelled due to its deadline being reached. The value will, however,
70
+ only be ``True`` if the cancellation was triggered by the scope itself (and not
71
+ an outer scope).
72
+
73
+ """
74
+ raise NotImplementedError
75
+
76
+ @property
77
+ def shield(self) -> bool:
78
+ """
79
+ ``True`` if this scope is shielded from external cancellation.
80
+
81
+ While a scope is shielded, it will not receive cancellations from outside.
82
+
83
+ """
84
+ raise NotImplementedError
85
+
86
+ @shield.setter
87
+ def shield(self, value: bool) -> None:
88
+ raise NotImplementedError
89
+
90
+ def __enter__(self) -> CancelScope:
91
+ raise NotImplementedError
92
+
93
+ def __exit__(
94
+ self,
95
+ exc_type: type[BaseException] | None,
96
+ exc_val: BaseException | None,
97
+ exc_tb: TracebackType | None,
98
+ ) -> bool:
99
+ raise NotImplementedError
100
+
101
+
102
+ @contextmanager
103
+ def fail_after(
104
+ delay: float | None, shield: bool = False
105
+ ) -> Generator[CancelScope, None, None]:
106
+ """
107
+ Create a context manager which raises a :class:`TimeoutError` if does not finish in
108
+ time.
109
+
110
+ :param delay: maximum allowed time (in seconds) before raising the exception, or
111
+ ``None`` to disable the timeout
112
+ :param shield: ``True`` to shield the cancel scope from external cancellation
113
+ :return: a context manager that yields a cancel scope
114
+ :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\]
115
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
116
+ current thread
117
+
118
+ """
119
+ current_time = get_async_backend().current_time
120
+ deadline = (current_time() + delay) if delay is not None else math.inf
121
+ with get_async_backend().create_cancel_scope(
122
+ deadline=deadline, shield=shield
123
+ ) as cancel_scope:
124
+ yield cancel_scope
125
+
126
+ if cancel_scope.cancelled_caught and current_time() >= cancel_scope.deadline:
127
+ raise TimeoutError
128
+
129
+
130
+ def move_on_after(delay: float | None, shield: bool = False) -> CancelScope:
131
+ """
132
+ Create a cancel scope with a deadline that expires after the given delay.
133
+
134
+ :param delay: maximum allowed time (in seconds) before exiting the context block, or
135
+ ``None`` to disable the timeout
136
+ :param shield: ``True`` to shield the cancel scope from external cancellation
137
+ :return: a cancel scope
138
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
139
+ current thread
140
+
141
+ """
142
+ deadline = (
143
+ (get_async_backend().current_time() + delay) if delay is not None else math.inf
144
+ )
145
+ return get_async_backend().create_cancel_scope(deadline=deadline, shield=shield)
146
+
147
+
148
+ def current_effective_deadline() -> float:
149
+ """
150
+ Return the nearest deadline among all the cancel scopes effective for the current
151
+ task.
152
+
153
+ :return: a clock value from the event loop's internal clock (or ``float('inf')`` if
154
+ there is no deadline in effect, or ``float('-inf')`` if the current scope has
155
+ been cancelled)
156
+ :rtype: float
157
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
158
+ current thread
159
+
160
+ """
161
+ return get_async_backend().current_effective_deadline()
162
+
163
+
164
+ def create_task_group() -> TaskGroup:
165
+ """
166
+ Create a task group.
167
+
168
+ :return: a task group
169
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
170
+ current thread
171
+
172
+ """
173
+ return get_async_backend().create_task_group()
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_tempfile.py ADDED
@@ -0,0 +1,613 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import sys
5
+ import tempfile
6
+ from collections.abc import Iterable
7
+ from io import BytesIO, TextIOWrapper
8
+ from types import TracebackType
9
+ from typing import (
10
+ TYPE_CHECKING,
11
+ Any,
12
+ AnyStr,
13
+ Generic,
14
+ overload,
15
+ )
16
+
17
+ from .. import to_thread
18
+ from .._core._fileio import AsyncFile
19
+ from ..lowlevel import checkpoint_if_cancelled
20
+
21
+ if TYPE_CHECKING:
22
+ from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
23
+
24
+
25
+ class TemporaryFile(Generic[AnyStr]):
26
+ """
27
+ An asynchronous temporary file that is automatically created and cleaned up.
28
+
29
+ This class provides an asynchronous context manager interface to a temporary file.
30
+ The file is created using Python's standard `tempfile.TemporaryFile` function in a
31
+ background thread, and is wrapped as an asynchronous file using `AsyncFile`.
32
+
33
+ :param mode: The mode in which the file is opened. Defaults to "w+b".
34
+ :param buffering: The buffering policy (-1 means the default buffering).
35
+ :param encoding: The encoding used to decode or encode the file. Only applicable in
36
+ text mode.
37
+ :param newline: Controls how universal newlines mode works (only applicable in text
38
+ mode).
39
+ :param suffix: The suffix for the temporary file name.
40
+ :param prefix: The prefix for the temporary file name.
41
+ :param dir: The directory in which the temporary file is created.
42
+ :param errors: The error handling scheme used for encoding/decoding errors.
43
+ """
44
+
45
+ _async_file: AsyncFile[AnyStr]
46
+
47
+ @overload
48
+ def __init__(
49
+ self: TemporaryFile[bytes],
50
+ mode: OpenBinaryMode = ...,
51
+ buffering: int = ...,
52
+ encoding: str | None = ...,
53
+ newline: str | None = ...,
54
+ suffix: str | None = ...,
55
+ prefix: str | None = ...,
56
+ dir: str | None = ...,
57
+ *,
58
+ errors: str | None = ...,
59
+ ): ...
60
+ @overload
61
+ def __init__(
62
+ self: TemporaryFile[str],
63
+ mode: OpenTextMode,
64
+ buffering: int = ...,
65
+ encoding: str | None = ...,
66
+ newline: str | None = ...,
67
+ suffix: str | None = ...,
68
+ prefix: str | None = ...,
69
+ dir: str | None = ...,
70
+ *,
71
+ errors: str | None = ...,
72
+ ): ...
73
+
74
+ def __init__(
75
+ self,
76
+ mode: OpenTextMode | OpenBinaryMode = "w+b",
77
+ buffering: int = -1,
78
+ encoding: str | None = None,
79
+ newline: str | None = None,
80
+ suffix: str | None = None,
81
+ prefix: str | None = None,
82
+ dir: str | None = None,
83
+ *,
84
+ errors: str | None = None,
85
+ ) -> None:
86
+ self.mode = mode
87
+ self.buffering = buffering
88
+ self.encoding = encoding
89
+ self.newline = newline
90
+ self.suffix: str | None = suffix
91
+ self.prefix: str | None = prefix
92
+ self.dir: str | None = dir
93
+ self.errors = errors
94
+
95
+ async def __aenter__(self) -> AsyncFile[AnyStr]:
96
+ fp = await to_thread.run_sync(
97
+ lambda: tempfile.TemporaryFile(
98
+ self.mode,
99
+ self.buffering,
100
+ self.encoding,
101
+ self.newline,
102
+ self.suffix,
103
+ self.prefix,
104
+ self.dir,
105
+ errors=self.errors,
106
+ )
107
+ )
108
+ self._async_file = AsyncFile(fp)
109
+ return self._async_file
110
+
111
+ async def __aexit__(
112
+ self,
113
+ exc_type: type[BaseException] | None,
114
+ exc_value: BaseException | None,
115
+ traceback: TracebackType | None,
116
+ ) -> None:
117
+ await self._async_file.aclose()
118
+
119
+
120
+ class NamedTemporaryFile(Generic[AnyStr]):
121
+ """
122
+ An asynchronous named temporary file that is automatically created and cleaned up.
123
+
124
+ This class provides an asynchronous context manager for a temporary file with a
125
+ visible name in the file system. It uses Python's standard
126
+ :func:`~tempfile.NamedTemporaryFile` function and wraps the file object with
127
+ :class:`AsyncFile` for asynchronous operations.
128
+
129
+ :param mode: The mode in which the file is opened. Defaults to "w+b".
130
+ :param buffering: The buffering policy (-1 means the default buffering).
131
+ :param encoding: The encoding used to decode or encode the file. Only applicable in
132
+ text mode.
133
+ :param newline: Controls how universal newlines mode works (only applicable in text
134
+ mode).
135
+ :param suffix: The suffix for the temporary file name.
136
+ :param prefix: The prefix for the temporary file name.
137
+ :param dir: The directory in which the temporary file is created.
138
+ :param delete: Whether to delete the file when it is closed.
139
+ :param errors: The error handling scheme used for encoding/decoding errors.
140
+ :param delete_on_close: (Python 3.12+) Whether to delete the file on close.
141
+ """
142
+
143
+ _async_file: AsyncFile[AnyStr]
144
+
145
+ @overload
146
+ def __init__(
147
+ self: NamedTemporaryFile[bytes],
148
+ mode: OpenBinaryMode = ...,
149
+ buffering: int = ...,
150
+ encoding: str | None = ...,
151
+ newline: str | None = ...,
152
+ suffix: str | None = ...,
153
+ prefix: str | None = ...,
154
+ dir: str | None = ...,
155
+ delete: bool = ...,
156
+ *,
157
+ errors: str | None = ...,
158
+ delete_on_close: bool = ...,
159
+ ): ...
160
+ @overload
161
+ def __init__(
162
+ self: NamedTemporaryFile[str],
163
+ mode: OpenTextMode,
164
+ buffering: int = ...,
165
+ encoding: str | None = ...,
166
+ newline: str | None = ...,
167
+ suffix: str | None = ...,
168
+ prefix: str | None = ...,
169
+ dir: str | None = ...,
170
+ delete: bool = ...,
171
+ *,
172
+ errors: str | None = ...,
173
+ delete_on_close: bool = ...,
174
+ ): ...
175
+
176
+ def __init__(
177
+ self,
178
+ mode: OpenBinaryMode | OpenTextMode = "w+b",
179
+ buffering: int = -1,
180
+ encoding: str | None = None,
181
+ newline: str | None = None,
182
+ suffix: str | None = None,
183
+ prefix: str | None = None,
184
+ dir: str | None = None,
185
+ delete: bool = True,
186
+ *,
187
+ errors: str | None = None,
188
+ delete_on_close: bool = True,
189
+ ) -> None:
190
+ self._params: dict[str, Any] = {
191
+ "mode": mode,
192
+ "buffering": buffering,
193
+ "encoding": encoding,
194
+ "newline": newline,
195
+ "suffix": suffix,
196
+ "prefix": prefix,
197
+ "dir": dir,
198
+ "delete": delete,
199
+ "errors": errors,
200
+ }
201
+ if sys.version_info >= (3, 12):
202
+ self._params["delete_on_close"] = delete_on_close
203
+
204
+ async def __aenter__(self) -> AsyncFile[AnyStr]:
205
+ fp = await to_thread.run_sync(
206
+ lambda: tempfile.NamedTemporaryFile(**self._params)
207
+ )
208
+ self._async_file = AsyncFile(fp)
209
+ return self._async_file
210
+
211
+ async def __aexit__(
212
+ self,
213
+ exc_type: type[BaseException] | None,
214
+ exc_value: BaseException | None,
215
+ traceback: TracebackType | None,
216
+ ) -> None:
217
+ await self._async_file.aclose()
218
+
219
+
220
+ class SpooledTemporaryFile(AsyncFile[AnyStr]):
221
+ """
222
+ An asynchronous spooled temporary file that starts in memory and is spooled to disk.
223
+
224
+ This class provides an asynchronous interface to a spooled temporary file, much like
225
+ Python's standard :class:`~tempfile.SpooledTemporaryFile`. It supports asynchronous
226
+ write operations and provides a method to force a rollover to disk.
227
+
228
+ :param max_size: Maximum size in bytes before the file is rolled over to disk.
229
+ :param mode: The mode in which the file is opened. Defaults to "w+b".
230
+ :param buffering: The buffering policy (-1 means the default buffering).
231
+ :param encoding: The encoding used to decode or encode the file (text mode only).
232
+ :param newline: Controls how universal newlines mode works (text mode only).
233
+ :param suffix: The suffix for the temporary file name.
234
+ :param prefix: The prefix for the temporary file name.
235
+ :param dir: The directory in which the temporary file is created.
236
+ :param errors: The error handling scheme used for encoding/decoding errors.
237
+ """
238
+
239
+ _rolled: bool = False
240
+
241
+ @overload
242
+ def __init__(
243
+ self: SpooledTemporaryFile[bytes],
244
+ max_size: int = ...,
245
+ mode: OpenBinaryMode = ...,
246
+ buffering: int = ...,
247
+ encoding: str | None = ...,
248
+ newline: str | None = ...,
249
+ suffix: str | None = ...,
250
+ prefix: str | None = ...,
251
+ dir: str | None = ...,
252
+ *,
253
+ errors: str | None = ...,
254
+ ): ...
255
+ @overload
256
+ def __init__(
257
+ self: SpooledTemporaryFile[str],
258
+ max_size: int = ...,
259
+ mode: OpenTextMode = ...,
260
+ buffering: int = ...,
261
+ encoding: str | None = ...,
262
+ newline: str | None = ...,
263
+ suffix: str | None = ...,
264
+ prefix: str | None = ...,
265
+ dir: str | None = ...,
266
+ *,
267
+ errors: str | None = ...,
268
+ ): ...
269
+
270
+ def __init__(
271
+ self,
272
+ max_size: int = 0,
273
+ mode: OpenBinaryMode | OpenTextMode = "w+b",
274
+ buffering: int = -1,
275
+ encoding: str | None = None,
276
+ newline: str | None = None,
277
+ suffix: str | None = None,
278
+ prefix: str | None = None,
279
+ dir: str | None = None,
280
+ *,
281
+ errors: str | None = None,
282
+ ) -> None:
283
+ self._tempfile_params: dict[str, Any] = {
284
+ "mode": mode,
285
+ "buffering": buffering,
286
+ "encoding": encoding,
287
+ "newline": newline,
288
+ "suffix": suffix,
289
+ "prefix": prefix,
290
+ "dir": dir,
291
+ "errors": errors,
292
+ }
293
+ self._max_size = max_size
294
+ if "b" in mode:
295
+ super().__init__(BytesIO()) # type: ignore[arg-type]
296
+ else:
297
+ super().__init__(
298
+ TextIOWrapper( # type: ignore[arg-type]
299
+ BytesIO(),
300
+ encoding=encoding,
301
+ errors=errors,
302
+ newline=newline,
303
+ write_through=True,
304
+ )
305
+ )
306
+
307
+ async def aclose(self) -> None:
308
+ if not self._rolled:
309
+ self._fp.close()
310
+ return
311
+
312
+ await super().aclose()
313
+
314
+ async def _check(self) -> None:
315
+ if self._rolled or self._fp.tell() <= self._max_size:
316
+ return
317
+
318
+ await self.rollover()
319
+
320
+ async def rollover(self) -> None:
321
+ if self._rolled:
322
+ return
323
+
324
+ self._rolled = True
325
+ buffer = self._fp
326
+ buffer.seek(0)
327
+ self._fp = await to_thread.run_sync(
328
+ lambda: tempfile.TemporaryFile(**self._tempfile_params)
329
+ )
330
+ await self.write(buffer.read())
331
+ buffer.close()
332
+
333
+ @property
334
+ def closed(self) -> bool:
335
+ return self._fp.closed
336
+
337
+ async def read(self, size: int = -1) -> AnyStr:
338
+ if not self._rolled:
339
+ await checkpoint_if_cancelled()
340
+ return self._fp.read(size)
341
+
342
+ return await super().read(size) # type: ignore[return-value]
343
+
344
+ async def read1(self: SpooledTemporaryFile[bytes], size: int = -1) -> bytes:
345
+ if not self._rolled:
346
+ await checkpoint_if_cancelled()
347
+ return self._fp.read1(size)
348
+
349
+ return await super().read1(size)
350
+
351
+ async def readline(self) -> AnyStr:
352
+ if not self._rolled:
353
+ await checkpoint_if_cancelled()
354
+ return self._fp.readline()
355
+
356
+ return await super().readline() # type: ignore[return-value]
357
+
358
+ async def readlines(self) -> list[AnyStr]:
359
+ if not self._rolled:
360
+ await checkpoint_if_cancelled()
361
+ return self._fp.readlines()
362
+
363
+ return await super().readlines() # type: ignore[return-value]
364
+
365
+ async def readinto(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int:
366
+ if not self._rolled:
367
+ await checkpoint_if_cancelled()
368
+ self._fp.readinto(b)
369
+
370
+ return await super().readinto(b)
371
+
372
+ async def readinto1(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int:
373
+ if not self._rolled:
374
+ await checkpoint_if_cancelled()
375
+ self._fp.readinto(b)
376
+
377
+ return await super().readinto1(b)
378
+
379
+ async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
380
+ if not self._rolled:
381
+ await checkpoint_if_cancelled()
382
+ return self._fp.seek(offset, whence)
383
+
384
+ return await super().seek(offset, whence)
385
+
386
+ async def tell(self) -> int:
387
+ if not self._rolled:
388
+ await checkpoint_if_cancelled()
389
+ return self._fp.tell()
390
+
391
+ return await super().tell()
392
+
393
+ async def truncate(self, size: int | None = None) -> int:
394
+ if not self._rolled:
395
+ await checkpoint_if_cancelled()
396
+ return self._fp.truncate(size)
397
+
398
+ return await super().truncate(size)
399
+
400
+ @overload
401
+ async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ...
402
+ @overload
403
+ async def write(self: SpooledTemporaryFile[str], b: str) -> int: ...
404
+
405
+ async def write(self, b: ReadableBuffer | str) -> int:
406
+ """
407
+ Asynchronously write data to the spooled temporary file.
408
+
409
+ If the file has not yet been rolled over, the data is written synchronously,
410
+ and a rollover is triggered if the size exceeds the maximum size.
411
+
412
+ :param s: The data to write.
413
+ :return: The number of bytes written.
414
+ :raises RuntimeError: If the underlying file is not initialized.
415
+
416
+ """
417
+ if not self._rolled:
418
+ await checkpoint_if_cancelled()
419
+ result = self._fp.write(b)
420
+ await self._check()
421
+ return result
422
+
423
+ return await super().write(b) # type: ignore[misc]
424
+
425
+ @overload
426
+ async def writelines(
427
+ self: SpooledTemporaryFile[bytes], lines: Iterable[ReadableBuffer]
428
+ ) -> None: ...
429
+ @overload
430
+ async def writelines(
431
+ self: SpooledTemporaryFile[str], lines: Iterable[str]
432
+ ) -> None: ...
433
+
434
+ async def writelines(self, lines: Iterable[str] | Iterable[ReadableBuffer]) -> None:
435
+ """
436
+ Asynchronously write a list of lines to the spooled temporary file.
437
+
438
+ If the file has not yet been rolled over, the lines are written synchronously,
439
+ and a rollover is triggered if the size exceeds the maximum size.
440
+
441
+ :param lines: An iterable of lines to write.
442
+ :raises RuntimeError: If the underlying file is not initialized.
443
+
444
+ """
445
+ if not self._rolled:
446
+ await checkpoint_if_cancelled()
447
+ result = self._fp.writelines(lines)
448
+ await self._check()
449
+ return result
450
+
451
+ return await super().writelines(lines) # type: ignore[misc]
452
+
453
+
454
+ class TemporaryDirectory(Generic[AnyStr]):
455
+ """
456
+ An asynchronous temporary directory that is created and cleaned up automatically.
457
+
458
+ This class provides an asynchronous context manager for creating a temporary
459
+ directory. It wraps Python's standard :class:`~tempfile.TemporaryDirectory` to
460
+ perform directory creation and cleanup operations in a background thread.
461
+
462
+ :param suffix: Suffix to be added to the temporary directory name.
463
+ :param prefix: Prefix to be added to the temporary directory name.
464
+ :param dir: The parent directory where the temporary directory is created.
465
+ :param ignore_cleanup_errors: Whether to ignore errors during cleanup
466
+ :param delete: Whether to delete the directory upon closing (Python 3.12+).
467
+ """
468
+
469
+ def __init__(
470
+ self,
471
+ suffix: AnyStr | None = None,
472
+ prefix: AnyStr | None = None,
473
+ dir: AnyStr | None = None,
474
+ *,
475
+ ignore_cleanup_errors: bool = False,
476
+ delete: bool = True,
477
+ ) -> None:
478
+ self.suffix: AnyStr | None = suffix
479
+ self.prefix: AnyStr | None = prefix
480
+ self.dir: AnyStr | None = dir
481
+ self.ignore_cleanup_errors = ignore_cleanup_errors
482
+ self.delete = delete
483
+
484
+ self._tempdir: tempfile.TemporaryDirectory | None = None
485
+
486
+ async def __aenter__(self) -> str:
487
+ params: dict[str, Any] = {
488
+ "suffix": self.suffix,
489
+ "prefix": self.prefix,
490
+ "dir": self.dir,
491
+ "ignore_cleanup_errors": self.ignore_cleanup_errors,
492
+ }
493
+ if sys.version_info >= (3, 12):
494
+ params["delete"] = self.delete
495
+
496
+ self._tempdir = await to_thread.run_sync(
497
+ lambda: tempfile.TemporaryDirectory(**params)
498
+ )
499
+ return await to_thread.run_sync(self._tempdir.__enter__)
500
+
501
+ async def __aexit__(
502
+ self,
503
+ exc_type: type[BaseException] | None,
504
+ exc_value: BaseException | None,
505
+ traceback: TracebackType | None,
506
+ ) -> None:
507
+ if self._tempdir is not None:
508
+ await to_thread.run_sync(
509
+ self._tempdir.__exit__, exc_type, exc_value, traceback
510
+ )
511
+
512
+ async def cleanup(self) -> None:
513
+ if self._tempdir is not None:
514
+ await to_thread.run_sync(self._tempdir.cleanup)
515
+
516
+
517
+ @overload
518
+ async def mkstemp(
519
+ suffix: str | None = None,
520
+ prefix: str | None = None,
521
+ dir: str | None = None,
522
+ text: bool = False,
523
+ ) -> tuple[int, str]: ...
524
+
525
+
526
+ @overload
527
+ async def mkstemp(
528
+ suffix: bytes | None = None,
529
+ prefix: bytes | None = None,
530
+ dir: bytes | None = None,
531
+ text: bool = False,
532
+ ) -> tuple[int, bytes]: ...
533
+
534
+
535
+ async def mkstemp(
536
+ suffix: AnyStr | None = None,
537
+ prefix: AnyStr | None = None,
538
+ dir: AnyStr | None = None,
539
+ text: bool = False,
540
+ ) -> tuple[int, str | bytes]:
541
+ """
542
+ Asynchronously create a temporary file and return an OS-level handle and the file
543
+ name.
544
+
545
+ This function wraps `tempfile.mkstemp` and executes it in a background thread.
546
+
547
+ :param suffix: Suffix to be added to the file name.
548
+ :param prefix: Prefix to be added to the file name.
549
+ :param dir: Directory in which the temporary file is created.
550
+ :param text: Whether the file is opened in text mode.
551
+ :return: A tuple containing the file descriptor and the file name.
552
+
553
+ """
554
+ return await to_thread.run_sync(tempfile.mkstemp, suffix, prefix, dir, text)
555
+
556
+
557
+ @overload
558
+ async def mkdtemp(
559
+ suffix: str | None = None,
560
+ prefix: str | None = None,
561
+ dir: str | None = None,
562
+ ) -> str: ...
563
+
564
+
565
+ @overload
566
+ async def mkdtemp(
567
+ suffix: bytes | None = None,
568
+ prefix: bytes | None = None,
569
+ dir: bytes | None = None,
570
+ ) -> bytes: ...
571
+
572
+
573
+ async def mkdtemp(
574
+ suffix: AnyStr | None = None,
575
+ prefix: AnyStr | None = None,
576
+ dir: AnyStr | None = None,
577
+ ) -> str | bytes:
578
+ """
579
+ Asynchronously create a temporary directory and return its path.
580
+
581
+ This function wraps `tempfile.mkdtemp` and executes it in a background thread.
582
+
583
+ :param suffix: Suffix to be added to the directory name.
584
+ :param prefix: Prefix to be added to the directory name.
585
+ :param dir: Parent directory where the temporary directory is created.
586
+ :return: The path of the created temporary directory.
587
+
588
+ """
589
+ return await to_thread.run_sync(tempfile.mkdtemp, suffix, prefix, dir)
590
+
591
+
592
+ async def gettempdir() -> str:
593
+ """
594
+ Asynchronously return the name of the directory used for temporary files.
595
+
596
+ This function wraps `tempfile.gettempdir` and executes it in a background thread.
597
+
598
+ :return: The path of the temporary directory as a string.
599
+
600
+ """
601
+ return await to_thread.run_sync(tempfile.gettempdir)
602
+
603
+
604
+ async def gettempdirb() -> bytes:
605
+ """
606
+ Asynchronously return the name of the directory used for temporary files in bytes.
607
+
608
+ This function wraps `tempfile.gettempdirb` and executes it in a background thread.
609
+
610
+ :return: The path of the temporary directory as bytes.
611
+
612
+ """
613
+ return await to_thread.run_sync(tempfile.gettempdirb)
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_testing.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Awaitable, Generator
4
+ from typing import Any, cast
5
+
6
+ from ._eventloop import get_async_backend
7
+
8
+
9
+ class TaskInfo:
10
+ """
11
+ Represents an asynchronous task.
12
+
13
+ :ivar int id: the unique identifier of the task
14
+ :ivar parent_id: the identifier of the parent task, if any
15
+ :vartype parent_id: Optional[int]
16
+ :ivar str name: the description of the task (if any)
17
+ :ivar ~collections.abc.Coroutine coro: the coroutine object of the task
18
+ """
19
+
20
+ __slots__ = "_name", "id", "parent_id", "name", "coro"
21
+
22
+ def __init__(
23
+ self,
24
+ id: int,
25
+ parent_id: int | None,
26
+ name: str | None,
27
+ coro: Generator[Any, Any, Any] | Awaitable[Any],
28
+ ):
29
+ func = get_current_task
30
+ self._name = f"{func.__module__}.{func.__qualname__}"
31
+ self.id: int = id
32
+ self.parent_id: int | None = parent_id
33
+ self.name: str | None = name
34
+ self.coro: Generator[Any, Any, Any] | Awaitable[Any] = coro
35
+
36
+ def __eq__(self, other: object) -> bool:
37
+ if isinstance(other, TaskInfo):
38
+ return self.id == other.id
39
+
40
+ return NotImplemented
41
+
42
+ def __hash__(self) -> int:
43
+ return hash(self.id)
44
+
45
+ def __repr__(self) -> str:
46
+ return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})"
47
+
48
+ def has_pending_cancellation(self) -> bool:
49
+ """
50
+ Return ``True`` if the task has a cancellation pending, ``False`` otherwise.
51
+
52
+ """
53
+ return False
54
+
55
+
56
+ def get_current_task() -> TaskInfo:
57
+ """
58
+ Return the current task.
59
+
60
+ :return: a representation of the current task
61
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
62
+ current thread
63
+
64
+ """
65
+ return get_async_backend().get_current_task()
66
+
67
+
68
+ def get_running_tasks() -> list[TaskInfo]:
69
+ """
70
+ Return a list of running tasks in the current event loop.
71
+
72
+ :return: a list of task info objects
73
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
74
+ current thread
75
+
76
+ """
77
+ return cast("list[TaskInfo]", get_async_backend().get_running_tasks())
78
+
79
+
80
+ async def wait_all_tasks_blocked() -> None:
81
+ """Wait until all other tasks are waiting for something."""
82
+ await get_async_backend().wait_all_tasks_blocked()
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/_core/_typedattr.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable, Mapping
4
+ from typing import Any, TypeVar, final, overload
5
+
6
+ from ._exceptions import TypedAttributeLookupError
7
+
8
+ T_Attr = TypeVar("T_Attr")
9
+ T_Default = TypeVar("T_Default")
10
+ undefined = object()
11
+
12
+
13
+ def typed_attribute() -> Any:
14
+ """Return a unique object, used to mark typed attributes."""
15
+ return object()
16
+
17
+
18
+ class TypedAttributeSet:
19
+ """
20
+ Superclass for typed attribute collections.
21
+
22
+ Checks that every public attribute of every subclass has a type annotation.
23
+ """
24
+
25
+ def __init_subclass__(cls) -> None:
26
+ annotations: dict[str, Any] = getattr(cls, "__annotations__", {})
27
+ for attrname in dir(cls):
28
+ if not attrname.startswith("_") and attrname not in annotations:
29
+ raise TypeError(
30
+ f"Attribute {attrname!r} is missing its type annotation"
31
+ )
32
+
33
+ super().__init_subclass__()
34
+
35
+
36
+ class TypedAttributeProvider:
37
+ """Base class for classes that wish to provide typed extra attributes."""
38
+
39
+ @property
40
+ def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]:
41
+ """
42
+ A mapping of the extra attributes to callables that return the corresponding
43
+ values.
44
+
45
+ If the provider wraps another provider, the attributes from that wrapper should
46
+ also be included in the returned mapping (but the wrapper may override the
47
+ callables from the wrapped instance).
48
+
49
+ """
50
+ return {}
51
+
52
+ @overload
53
+ def extra(self, attribute: T_Attr) -> T_Attr: ...
54
+
55
+ @overload
56
+ def extra(self, attribute: T_Attr, default: T_Default) -> T_Attr | T_Default: ...
57
+
58
+ @final
59
+ def extra(self, attribute: Any, default: object = undefined) -> object:
60
+ """
61
+ extra(attribute, default=undefined)
62
+
63
+ Return the value of the given typed extra attribute.
64
+
65
+ :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to
66
+ look for
67
+ :param default: the value that should be returned if no value is found for the
68
+ attribute
69
+ :raises ~anyio.TypedAttributeLookupError: if the search failed and no default
70
+ value was given
71
+
72
+ """
73
+ try:
74
+ getter = self.extra_attributes[attribute]
75
+ except KeyError:
76
+ if default is undefined:
77
+ raise TypedAttributeLookupError("Attribute not found") from None
78
+ else:
79
+ return default
80
+
81
+ return getter()
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/__init__.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from ._eventloop import AsyncBackend as AsyncBackend
4
+ from ._resources import AsyncResource as AsyncResource
5
+ from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket
6
+ from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket
7
+ from ._sockets import IPAddressType as IPAddressType
8
+ from ._sockets import IPSockAddrType as IPSockAddrType
9
+ from ._sockets import SocketAttribute as SocketAttribute
10
+ from ._sockets import SocketListener as SocketListener
11
+ from ._sockets import SocketStream as SocketStream
12
+ from ._sockets import UDPPacketType as UDPPacketType
13
+ from ._sockets import UDPSocket as UDPSocket
14
+ from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType
15
+ from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket
16
+ from ._sockets import UNIXSocketStream as UNIXSocketStream
17
+ from ._streams import AnyByteReceiveStream as AnyByteReceiveStream
18
+ from ._streams import AnyByteSendStream as AnyByteSendStream
19
+ from ._streams import AnyByteStream as AnyByteStream
20
+ from ._streams import AnyByteStreamConnectable as AnyByteStreamConnectable
21
+ from ._streams import AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream
22
+ from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream
23
+ from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream
24
+ from ._streams import ByteReceiveStream as ByteReceiveStream
25
+ from ._streams import ByteSendStream as ByteSendStream
26
+ from ._streams import ByteStream as ByteStream
27
+ from ._streams import ByteStreamConnectable as ByteStreamConnectable
28
+ from ._streams import Listener as Listener
29
+ from ._streams import ObjectReceiveStream as ObjectReceiveStream
30
+ from ._streams import ObjectSendStream as ObjectSendStream
31
+ from ._streams import ObjectStream as ObjectStream
32
+ from ._streams import ObjectStreamConnectable as ObjectStreamConnectable
33
+ from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream
34
+ from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream
35
+ from ._streams import UnreliableObjectStream as UnreliableObjectStream
36
+ from ._subprocesses import Process as Process
37
+ from ._tasks import TaskGroup as TaskGroup
38
+ from ._tasks import TaskStatus as TaskStatus
39
+ from ._testing import TestRunner as TestRunner
40
+
41
+ # Re-exported here, for backwards compatibility
42
+ # isort: off
43
+ from .._core._synchronization import (
44
+ CapacityLimiter as CapacityLimiter,
45
+ Condition as Condition,
46
+ Event as Event,
47
+ Lock as Lock,
48
+ Semaphore as Semaphore,
49
+ )
50
+ from .._core._tasks import CancelScope as CancelScope
51
+ from ..from_thread import BlockingPortal as BlockingPortal
52
+
53
+ # Re-export imports so they look like they live directly in this package
54
+ for __value in list(locals().values()):
55
+ if getattr(__value, "__module__", "").startswith("anyio.abc."):
56
+ __value.__module__ = __name__
57
+
58
+ del __value
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_eventloop.py ADDED
@@ -0,0 +1,409 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+ import sys
5
+ from abc import ABCMeta, abstractmethod
6
+ from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
7
+ from contextlib import AbstractContextManager
8
+ from os import PathLike
9
+ from signal import Signals
10
+ from socket import AddressFamily, SocketKind, socket
11
+ from typing import (
12
+ IO,
13
+ TYPE_CHECKING,
14
+ Any,
15
+ TypeAlias,
16
+ TypeVar,
17
+ overload,
18
+ )
19
+
20
+ if sys.version_info >= (3, 11):
21
+ from typing import TypeVarTuple, Unpack
22
+ else:
23
+ from typing_extensions import TypeVarTuple, Unpack
24
+
25
+ if TYPE_CHECKING:
26
+ from _typeshed import FileDescriptorLike
27
+
28
+ from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore
29
+ from .._core._tasks import CancelScope
30
+ from .._core._testing import TaskInfo
31
+ from ._sockets import (
32
+ ConnectedUDPSocket,
33
+ ConnectedUNIXDatagramSocket,
34
+ IPSockAddrType,
35
+ SocketListener,
36
+ SocketStream,
37
+ UDPSocket,
38
+ UNIXDatagramSocket,
39
+ UNIXSocketStream,
40
+ )
41
+ from ._subprocesses import Process
42
+ from ._tasks import TaskGroup
43
+ from ._testing import TestRunner
44
+
45
+ T_Retval = TypeVar("T_Retval")
46
+ PosArgsT = TypeVarTuple("PosArgsT")
47
+ StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes]
48
+
49
+
50
+ class AsyncBackend(metaclass=ABCMeta):
51
+ @classmethod
52
+ @abstractmethod
53
+ def run(
54
+ cls,
55
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
56
+ args: tuple[Unpack[PosArgsT]],
57
+ kwargs: dict[str, Any],
58
+ options: dict[str, Any],
59
+ ) -> T_Retval:
60
+ """
61
+ Run the given coroutine function in an asynchronous event loop.
62
+
63
+ The current thread must not be already running an event loop.
64
+
65
+ :param func: a coroutine function
66
+ :param args: positional arguments to ``func``
67
+ :param kwargs: positional arguments to ``func``
68
+ :param options: keyword arguments to call the backend ``run()`` implementation
69
+ with
70
+ :return: the return value of the coroutine function
71
+ """
72
+
73
+ @classmethod
74
+ @abstractmethod
75
+ def current_token(cls) -> object:
76
+ """
77
+ Return an object that allows other threads to run code inside the event loop.
78
+
79
+ :return: a token object, specific to the event loop running in the current
80
+ thread
81
+ """
82
+
83
+ @classmethod
84
+ @abstractmethod
85
+ def current_time(cls) -> float:
86
+ """
87
+ Return the current value of the event loop's internal clock.
88
+
89
+ :return: the clock value (seconds)
90
+ """
91
+
92
+ @classmethod
93
+ @abstractmethod
94
+ def cancelled_exception_class(cls) -> type[BaseException]:
95
+ """Return the exception class that is raised in a task if it's cancelled."""
96
+
97
+ @classmethod
98
+ @abstractmethod
99
+ async def checkpoint(cls) -> None:
100
+ """
101
+ Check if the task has been cancelled, and allow rescheduling of other tasks.
102
+
103
+ This is effectively the same as running :meth:`checkpoint_if_cancelled` and then
104
+ :meth:`cancel_shielded_checkpoint`.
105
+ """
106
+
107
+ @classmethod
108
+ async def checkpoint_if_cancelled(cls) -> None:
109
+ """
110
+ Check if the current task group has been cancelled.
111
+
112
+ This will check if the task has been cancelled, but will not allow other tasks
113
+ to be scheduled if not.
114
+
115
+ """
116
+ if cls.current_effective_deadline() == -math.inf:
117
+ await cls.checkpoint()
118
+
119
+ @classmethod
120
+ async def cancel_shielded_checkpoint(cls) -> None:
121
+ """
122
+ Allow the rescheduling of other tasks.
123
+
124
+ This will give other tasks the opportunity to run, but without checking if the
125
+ current task group has been cancelled, unlike with :meth:`checkpoint`.
126
+
127
+ """
128
+ with cls.create_cancel_scope(shield=True):
129
+ await cls.sleep(0)
130
+
131
+ @classmethod
132
+ @abstractmethod
133
+ async def sleep(cls, delay: float) -> None:
134
+ """
135
+ Pause the current task for the specified duration.
136
+
137
+ :param delay: the duration, in seconds
138
+ """
139
+
140
+ @classmethod
141
+ @abstractmethod
142
+ def create_cancel_scope(
143
+ cls, *, deadline: float = math.inf, shield: bool = False
144
+ ) -> CancelScope:
145
+ pass
146
+
147
+ @classmethod
148
+ @abstractmethod
149
+ def current_effective_deadline(cls) -> float:
150
+ """
151
+ Return the nearest deadline among all the cancel scopes effective for the
152
+ current task.
153
+
154
+ :return:
155
+ - a clock value from the event loop's internal clock
156
+ - ``inf`` if there is no deadline in effect
157
+ - ``-inf`` if the current scope has been cancelled
158
+ :rtype: float
159
+ """
160
+
161
+ @classmethod
162
+ @abstractmethod
163
+ def create_task_group(cls) -> TaskGroup:
164
+ pass
165
+
166
+ @classmethod
167
+ @abstractmethod
168
+ def create_event(cls) -> Event:
169
+ pass
170
+
171
+ @classmethod
172
+ @abstractmethod
173
+ def create_lock(cls, *, fast_acquire: bool) -> Lock:
174
+ pass
175
+
176
+ @classmethod
177
+ @abstractmethod
178
+ def create_semaphore(
179
+ cls,
180
+ initial_value: int,
181
+ *,
182
+ max_value: int | None = None,
183
+ fast_acquire: bool = False,
184
+ ) -> Semaphore:
185
+ pass
186
+
187
+ @classmethod
188
+ @abstractmethod
189
+ def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
190
+ pass
191
+
192
+ @classmethod
193
+ @abstractmethod
194
+ async def run_sync_in_worker_thread(
195
+ cls,
196
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
197
+ args: tuple[Unpack[PosArgsT]],
198
+ abandon_on_cancel: bool = False,
199
+ limiter: CapacityLimiter | None = None,
200
+ ) -> T_Retval:
201
+ pass
202
+
203
+ @classmethod
204
+ @abstractmethod
205
+ def check_cancelled(cls) -> None:
206
+ pass
207
+
208
+ @classmethod
209
+ @abstractmethod
210
+ def run_async_from_thread(
211
+ cls,
212
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
213
+ args: tuple[Unpack[PosArgsT]],
214
+ token: object,
215
+ ) -> T_Retval:
216
+ pass
217
+
218
+ @classmethod
219
+ @abstractmethod
220
+ def run_sync_from_thread(
221
+ cls,
222
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
223
+ args: tuple[Unpack[PosArgsT]],
224
+ token: object,
225
+ ) -> T_Retval:
226
+ pass
227
+
228
+ @classmethod
229
+ @abstractmethod
230
+ async def open_process(
231
+ cls,
232
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
233
+ *,
234
+ stdin: int | IO[Any] | None,
235
+ stdout: int | IO[Any] | None,
236
+ stderr: int | IO[Any] | None,
237
+ **kwargs: Any,
238
+ ) -> Process:
239
+ pass
240
+
241
+ @classmethod
242
+ @abstractmethod
243
+ def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None:
244
+ pass
245
+
246
+ @classmethod
247
+ @abstractmethod
248
+ async def connect_tcp(
249
+ cls, host: str, port: int, local_address: IPSockAddrType | None = None
250
+ ) -> SocketStream:
251
+ pass
252
+
253
+ @classmethod
254
+ @abstractmethod
255
+ async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream:
256
+ pass
257
+
258
+ @classmethod
259
+ @abstractmethod
260
+ def create_tcp_listener(cls, sock: socket) -> SocketListener:
261
+ pass
262
+
263
+ @classmethod
264
+ @abstractmethod
265
+ def create_unix_listener(cls, sock: socket) -> SocketListener:
266
+ pass
267
+
268
+ @classmethod
269
+ @abstractmethod
270
+ async def create_udp_socket(
271
+ cls,
272
+ family: AddressFamily,
273
+ local_address: IPSockAddrType | None,
274
+ remote_address: IPSockAddrType | None,
275
+ reuse_port: bool,
276
+ ) -> UDPSocket | ConnectedUDPSocket:
277
+ pass
278
+
279
+ @classmethod
280
+ @overload
281
+ async def create_unix_datagram_socket(
282
+ cls, raw_socket: socket, remote_path: None
283
+ ) -> UNIXDatagramSocket: ...
284
+
285
+ @classmethod
286
+ @overload
287
+ async def create_unix_datagram_socket(
288
+ cls, raw_socket: socket, remote_path: str | bytes
289
+ ) -> ConnectedUNIXDatagramSocket: ...
290
+
291
+ @classmethod
292
+ @abstractmethod
293
+ async def create_unix_datagram_socket(
294
+ cls, raw_socket: socket, remote_path: str | bytes | None
295
+ ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket:
296
+ pass
297
+
298
+ @classmethod
299
+ @abstractmethod
300
+ async def getaddrinfo(
301
+ cls,
302
+ host: bytes | str | None,
303
+ port: str | int | None,
304
+ *,
305
+ family: int | AddressFamily = 0,
306
+ type: int | SocketKind = 0,
307
+ proto: int = 0,
308
+ flags: int = 0,
309
+ ) -> Sequence[
310
+ tuple[
311
+ AddressFamily,
312
+ SocketKind,
313
+ int,
314
+ str,
315
+ tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
316
+ ]
317
+ ]:
318
+ pass
319
+
320
+ @classmethod
321
+ @abstractmethod
322
+ async def getnameinfo(
323
+ cls, sockaddr: IPSockAddrType, flags: int = 0
324
+ ) -> tuple[str, str]:
325
+ pass
326
+
327
+ @classmethod
328
+ @abstractmethod
329
+ async def wait_readable(cls, obj: FileDescriptorLike) -> None:
330
+ pass
331
+
332
+ @classmethod
333
+ @abstractmethod
334
+ async def wait_writable(cls, obj: FileDescriptorLike) -> None:
335
+ pass
336
+
337
+ @classmethod
338
+ @abstractmethod
339
+ def notify_closing(cls, obj: FileDescriptorLike) -> None:
340
+ pass
341
+
342
+ @classmethod
343
+ @abstractmethod
344
+ async def wrap_listener_socket(cls, sock: socket) -> SocketListener:
345
+ pass
346
+
347
+ @classmethod
348
+ @abstractmethod
349
+ async def wrap_stream_socket(cls, sock: socket) -> SocketStream:
350
+ pass
351
+
352
+ @classmethod
353
+ @abstractmethod
354
+ async def wrap_unix_stream_socket(cls, sock: socket) -> UNIXSocketStream:
355
+ pass
356
+
357
+ @classmethod
358
+ @abstractmethod
359
+ async def wrap_udp_socket(cls, sock: socket) -> UDPSocket:
360
+ pass
361
+
362
+ @classmethod
363
+ @abstractmethod
364
+ async def wrap_connected_udp_socket(cls, sock: socket) -> ConnectedUDPSocket:
365
+ pass
366
+
367
+ @classmethod
368
+ @abstractmethod
369
+ async def wrap_unix_datagram_socket(cls, sock: socket) -> UNIXDatagramSocket:
370
+ pass
371
+
372
+ @classmethod
373
+ @abstractmethod
374
+ async def wrap_connected_unix_datagram_socket(
375
+ cls, sock: socket
376
+ ) -> ConnectedUNIXDatagramSocket:
377
+ pass
378
+
379
+ @classmethod
380
+ @abstractmethod
381
+ def current_default_thread_limiter(cls) -> CapacityLimiter:
382
+ pass
383
+
384
+ @classmethod
385
+ @abstractmethod
386
+ def open_signal_receiver(
387
+ cls, *signals: Signals
388
+ ) -> AbstractContextManager[AsyncIterator[Signals]]:
389
+ pass
390
+
391
+ @classmethod
392
+ @abstractmethod
393
+ def get_current_task(cls) -> TaskInfo:
394
+ pass
395
+
396
+ @classmethod
397
+ @abstractmethod
398
+ def get_running_tasks(cls) -> Sequence[TaskInfo]:
399
+ pass
400
+
401
+ @classmethod
402
+ @abstractmethod
403
+ async def wait_all_tasks_blocked(cls) -> None:
404
+ pass
405
+
406
+ @classmethod
407
+ @abstractmethod
408
+ def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
409
+ pass
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_resources.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from abc import ABCMeta, abstractmethod
4
+ from types import TracebackType
5
+ from typing import TypeVar
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ class AsyncResource(metaclass=ABCMeta):
11
+ """
12
+ Abstract base class for all closeable asynchronous resources.
13
+
14
+ Works as an asynchronous context manager which returns the instance itself on enter,
15
+ and calls :meth:`aclose` on exit.
16
+ """
17
+
18
+ __slots__ = ()
19
+
20
+ async def __aenter__(self: T) -> T:
21
+ return self
22
+
23
+ async def __aexit__(
24
+ self,
25
+ exc_type: type[BaseException] | None,
26
+ exc_val: BaseException | None,
27
+ exc_tb: TracebackType | None,
28
+ ) -> None:
29
+ await self.aclose()
30
+
31
+ @abstractmethod
32
+ async def aclose(self) -> None:
33
+ """Close the resource."""
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_sockets.py ADDED
@@ -0,0 +1,399 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import errno
4
+ import socket
5
+ from abc import abstractmethod
6
+ from collections.abc import Callable, Collection, Mapping
7
+ from contextlib import AsyncExitStack
8
+ from io import IOBase
9
+ from ipaddress import IPv4Address, IPv6Address
10
+ from socket import AddressFamily
11
+ from typing import Any, TypeAlias, TypeVar
12
+
13
+ from .._core._eventloop import get_async_backend
14
+ from .._core._typedattr import (
15
+ TypedAttributeProvider,
16
+ TypedAttributeSet,
17
+ typed_attribute,
18
+ )
19
+ from ._streams import ByteStream, Listener, UnreliableObjectStream
20
+ from ._tasks import TaskGroup
21
+
22
+ IPAddressType: TypeAlias = str | IPv4Address | IPv6Address
23
+ IPSockAddrType: TypeAlias = tuple[str, int]
24
+ SockAddrType: TypeAlias = IPSockAddrType | str
25
+ UDPPacketType: TypeAlias = tuple[bytes, IPSockAddrType]
26
+ UNIXDatagramPacketType: TypeAlias = tuple[bytes, str]
27
+ T_Retval = TypeVar("T_Retval")
28
+
29
+
30
+ def _validate_socket(
31
+ sock_or_fd: socket.socket | int,
32
+ sock_type: socket.SocketKind,
33
+ addr_family: socket.AddressFamily = socket.AF_UNSPEC,
34
+ *,
35
+ require_connected: bool = False,
36
+ require_bound: bool = False,
37
+ ) -> socket.socket:
38
+ if isinstance(sock_or_fd, int):
39
+ try:
40
+ sock = socket.socket(fileno=sock_or_fd)
41
+ except OSError as exc:
42
+ if exc.errno == errno.ENOTSOCK:
43
+ raise ValueError(
44
+ "the file descriptor does not refer to a socket"
45
+ ) from exc
46
+ elif require_connected:
47
+ raise ValueError("the socket must be connected") from exc
48
+ elif require_bound:
49
+ raise ValueError("the socket must be bound to a local address") from exc
50
+ else:
51
+ raise
52
+ elif isinstance(sock_or_fd, socket.socket):
53
+ sock = sock_or_fd
54
+ else:
55
+ raise TypeError(
56
+ f"expected an int or socket, got {type(sock_or_fd).__qualname__} instead"
57
+ )
58
+
59
+ try:
60
+ if require_connected:
61
+ try:
62
+ sock.getpeername()
63
+ except OSError as exc:
64
+ raise ValueError("the socket must be connected") from exc
65
+
66
+ if require_bound:
67
+ try:
68
+ if sock.family in (socket.AF_INET, socket.AF_INET6):
69
+ bound_addr = sock.getsockname()[1]
70
+ else:
71
+ bound_addr = sock.getsockname()
72
+ except OSError:
73
+ bound_addr = None
74
+
75
+ if not bound_addr:
76
+ raise ValueError("the socket must be bound to a local address")
77
+
78
+ if addr_family != socket.AF_UNSPEC and sock.family != addr_family:
79
+ raise ValueError(
80
+ f"address family mismatch: expected {addr_family.name}, got "
81
+ f"{sock.family.name}"
82
+ )
83
+
84
+ if sock.type != sock_type:
85
+ raise ValueError(
86
+ f"socket type mismatch: expected {sock_type.name}, got {sock.type.name}"
87
+ )
88
+ except BaseException:
89
+ # Avoid ResourceWarning from the locally constructed socket object
90
+ if isinstance(sock_or_fd, int):
91
+ sock.detach()
92
+
93
+ raise
94
+
95
+ sock.setblocking(False)
96
+ return sock
97
+
98
+
99
+ class SocketAttribute(TypedAttributeSet):
100
+ """
101
+ .. attribute:: family
102
+ :type: socket.AddressFamily
103
+
104
+ the address family of the underlying socket
105
+
106
+ .. attribute:: local_address
107
+ :type: tuple[str, int] | str
108
+
109
+ the local address the underlying socket is connected to
110
+
111
+ .. attribute:: local_port
112
+ :type: int
113
+
114
+ for IP based sockets, the local port the underlying socket is bound to
115
+
116
+ .. attribute:: raw_socket
117
+ :type: socket.socket
118
+
119
+ the underlying stdlib socket object
120
+
121
+ .. attribute:: remote_address
122
+ :type: tuple[str, int] | str
123
+
124
+ the remote address the underlying socket is connected to
125
+
126
+ .. attribute:: remote_port
127
+ :type: int
128
+
129
+ for IP based sockets, the remote port the underlying socket is connected to
130
+ """
131
+
132
+ family: AddressFamily = typed_attribute()
133
+ local_address: SockAddrType = typed_attribute()
134
+ local_port: int = typed_attribute()
135
+ raw_socket: socket.socket = typed_attribute()
136
+ remote_address: SockAddrType = typed_attribute()
137
+ remote_port: int = typed_attribute()
138
+
139
+
140
+ class _SocketProvider(TypedAttributeProvider):
141
+ @property
142
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
143
+ from .._core._sockets import convert_ipv6_sockaddr as convert
144
+
145
+ attributes: dict[Any, Callable[[], Any]] = {
146
+ SocketAttribute.family: lambda: self._raw_socket.family,
147
+ SocketAttribute.local_address: lambda: convert(
148
+ self._raw_socket.getsockname()
149
+ ),
150
+ SocketAttribute.raw_socket: lambda: self._raw_socket,
151
+ }
152
+ try:
153
+ peername: tuple[str, int] | None = convert(self._raw_socket.getpeername())
154
+ except OSError:
155
+ peername = None
156
+
157
+ # Provide the remote address for connected sockets
158
+ if peername is not None:
159
+ attributes[SocketAttribute.remote_address] = lambda: peername
160
+
161
+ # Provide local and remote ports for IP based sockets
162
+ if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6):
163
+ attributes[SocketAttribute.local_port] = lambda: (
164
+ self._raw_socket.getsockname()[1]
165
+ )
166
+ if peername is not None:
167
+ remote_port = peername[1]
168
+ attributes[SocketAttribute.remote_port] = lambda: remote_port
169
+
170
+ return attributes
171
+
172
+ @property
173
+ @abstractmethod
174
+ def _raw_socket(self) -> socket.socket:
175
+ pass
176
+
177
+
178
+ class SocketStream(ByteStream, _SocketProvider):
179
+ """
180
+ Transports bytes over a socket.
181
+
182
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
183
+ """
184
+
185
+ @classmethod
186
+ async def from_socket(cls, sock_or_fd: socket.socket | int) -> SocketStream:
187
+ """
188
+ Wrap an existing socket object or file descriptor as a socket stream.
189
+
190
+ The newly created socket wrapper takes ownership of the socket being passed in.
191
+ The existing socket must already be connected.
192
+
193
+ :param sock_or_fd: a socket object or file descriptor
194
+ :return: a socket stream
195
+
196
+ """
197
+ sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_connected=True)
198
+ return await get_async_backend().wrap_stream_socket(sock)
199
+
200
+
201
+ class UNIXSocketStream(SocketStream):
202
+ @classmethod
203
+ async def from_socket(cls, sock_or_fd: socket.socket | int) -> UNIXSocketStream:
204
+ """
205
+ Wrap an existing socket object or file descriptor as a UNIX socket stream.
206
+
207
+ The newly created socket wrapper takes ownership of the socket being passed in.
208
+ The existing socket must already be connected.
209
+
210
+ :param sock_or_fd: a socket object or file descriptor
211
+ :return: a UNIX socket stream
212
+
213
+ """
214
+ sock = _validate_socket(
215
+ sock_or_fd, socket.SOCK_STREAM, socket.AF_UNIX, require_connected=True
216
+ )
217
+ return await get_async_backend().wrap_unix_stream_socket(sock)
218
+
219
+ @abstractmethod
220
+ async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
221
+ """
222
+ Send file descriptors along with a message to the peer.
223
+
224
+ :param message: a non-empty bytestring
225
+ :param fds: a collection of files (either numeric file descriptors or open file
226
+ or socket objects)
227
+ """
228
+
229
+ @abstractmethod
230
+ async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
231
+ """
232
+ Receive file descriptors along with a message from the peer.
233
+
234
+ :param msglen: length of the message to expect from the peer
235
+ :param maxfds: maximum number of file descriptors to expect from the peer
236
+ :return: a tuple of (message, file descriptors)
237
+ """
238
+
239
+
240
+ class SocketListener(Listener[SocketStream], _SocketProvider):
241
+ """
242
+ Listens to incoming socket connections.
243
+
244
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
245
+ """
246
+
247
+ @classmethod
248
+ async def from_socket(
249
+ cls,
250
+ sock_or_fd: socket.socket | int,
251
+ ) -> SocketListener:
252
+ """
253
+ Wrap an existing socket object or file descriptor as a socket listener.
254
+
255
+ The newly created listener takes ownership of the socket being passed in.
256
+
257
+ :param sock_or_fd: a socket object or file descriptor
258
+ :return: a socket listener
259
+
260
+ """
261
+ sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_bound=True)
262
+ return await get_async_backend().wrap_listener_socket(sock)
263
+
264
+ @abstractmethod
265
+ async def accept(self) -> SocketStream:
266
+ """Accept an incoming connection."""
267
+
268
+ async def serve(
269
+ self,
270
+ handler: Callable[[SocketStream], Any],
271
+ task_group: TaskGroup | None = None,
272
+ ) -> None:
273
+ from .. import create_task_group
274
+
275
+ async with AsyncExitStack() as stack:
276
+ if task_group is None:
277
+ task_group = await stack.enter_async_context(create_task_group())
278
+
279
+ while True:
280
+ stream = await self.accept()
281
+ task_group.start_soon(handler, stream)
282
+
283
+
284
+ class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider):
285
+ """
286
+ Represents an unconnected UDP socket.
287
+
288
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
289
+ """
290
+
291
+ @classmethod
292
+ async def from_socket(cls, sock_or_fd: socket.socket | int) -> UDPSocket:
293
+ """
294
+ Wrap an existing socket object or file descriptor as a UDP socket.
295
+
296
+ The newly created socket wrapper takes ownership of the socket being passed in.
297
+ The existing socket must be bound to a local address.
298
+
299
+ :param sock_or_fd: a socket object or file descriptor
300
+ :return: a UDP socket
301
+
302
+ """
303
+ sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, require_bound=True)
304
+ return await get_async_backend().wrap_udp_socket(sock)
305
+
306
+ async def sendto(self, data: bytes, host: str, port: int) -> None:
307
+ """
308
+ Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))).
309
+
310
+ """
311
+ return await self.send((data, (host, port)))
312
+
313
+
314
+ class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider):
315
+ """
316
+ Represents an connected UDP socket.
317
+
318
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
319
+ """
320
+
321
+ @classmethod
322
+ async def from_socket(cls, sock_or_fd: socket.socket | int) -> ConnectedUDPSocket:
323
+ """
324
+ Wrap an existing socket object or file descriptor as a connected UDP socket.
325
+
326
+ The newly created socket wrapper takes ownership of the socket being passed in.
327
+ The existing socket must already be connected.
328
+
329
+ :param sock_or_fd: a socket object or file descriptor
330
+ :return: a connected UDP socket
331
+
332
+ """
333
+ sock = _validate_socket(
334
+ sock_or_fd,
335
+ socket.SOCK_DGRAM,
336
+ require_connected=True,
337
+ )
338
+ return await get_async_backend().wrap_connected_udp_socket(sock)
339
+
340
+
341
+ class UNIXDatagramSocket(
342
+ UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider
343
+ ):
344
+ """
345
+ Represents an unconnected Unix datagram socket.
346
+
347
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
348
+ """
349
+
350
+ @classmethod
351
+ async def from_socket(
352
+ cls,
353
+ sock_or_fd: socket.socket | int,
354
+ ) -> UNIXDatagramSocket:
355
+ """
356
+ Wrap an existing socket object or file descriptor as a UNIX datagram
357
+ socket.
358
+
359
+ The newly created socket wrapper takes ownership of the socket being passed in.
360
+
361
+ :param sock_or_fd: a socket object or file descriptor
362
+ :return: a UNIX datagram socket
363
+
364
+ """
365
+ sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX)
366
+ return await get_async_backend().wrap_unix_datagram_socket(sock)
367
+
368
+ async def sendto(self, data: bytes, path: str) -> None:
369
+ """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, path))."""
370
+ return await self.send((data, path))
371
+
372
+
373
+ class ConnectedUNIXDatagramSocket(UnreliableObjectStream[bytes], _SocketProvider):
374
+ """
375
+ Represents a connected Unix datagram socket.
376
+
377
+ Supports all relevant extra attributes from :class:`~SocketAttribute`.
378
+ """
379
+
380
+ @classmethod
381
+ async def from_socket(
382
+ cls,
383
+ sock_or_fd: socket.socket | int,
384
+ ) -> ConnectedUNIXDatagramSocket:
385
+ """
386
+ Wrap an existing socket object or file descriptor as a connected UNIX datagram
387
+ socket.
388
+
389
+ The newly created socket wrapper takes ownership of the socket being passed in.
390
+ The existing socket must already be connected.
391
+
392
+ :param sock_or_fd: a socket object or file descriptor
393
+ :return: a connected UNIX datagram socket
394
+
395
+ """
396
+ sock = _validate_socket(
397
+ sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX, require_connected=True
398
+ )
399
+ return await get_async_backend().wrap_connected_unix_datagram_socket(sock)
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_streams.py ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from abc import ABCMeta, abstractmethod
4
+ from collections.abc import Callable
5
+ from typing import Any, Generic, TypeAlias, TypeVar
6
+
7
+ from .._core._exceptions import EndOfStream
8
+ from .._core._typedattr import TypedAttributeProvider
9
+ from ._resources import AsyncResource
10
+ from ._tasks import TaskGroup
11
+
12
+ T_Item = TypeVar("T_Item")
13
+ T_co = TypeVar("T_co", covariant=True)
14
+ T_contra = TypeVar("T_contra", contravariant=True)
15
+
16
+
17
+ class UnreliableObjectReceiveStream(
18
+ Generic[T_co], AsyncResource, TypedAttributeProvider
19
+ ):
20
+ """
21
+ An interface for receiving objects.
22
+
23
+ This interface makes no guarantees that the received messages arrive in the order in
24
+ which they were sent, or that no messages are missed.
25
+
26
+ Asynchronously iterating over objects of this type will yield objects matching the
27
+ given type parameter.
28
+ """
29
+
30
+ def __aiter__(self) -> UnreliableObjectReceiveStream[T_co]:
31
+ return self
32
+
33
+ async def __anext__(self) -> T_co:
34
+ try:
35
+ return await self.receive()
36
+ except EndOfStream:
37
+ raise StopAsyncIteration from None
38
+
39
+ @abstractmethod
40
+ async def receive(self) -> T_co:
41
+ """
42
+ Receive the next item.
43
+
44
+ :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly
45
+ closed
46
+ :raises ~anyio.EndOfStream: if this stream has been closed from the other end
47
+ :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable
48
+ due to external causes
49
+ """
50
+
51
+
52
+ class UnreliableObjectSendStream(
53
+ Generic[T_contra], AsyncResource, TypedAttributeProvider
54
+ ):
55
+ """
56
+ An interface for sending objects.
57
+
58
+ This interface makes no guarantees that the messages sent will reach the
59
+ recipient(s) in the same order in which they were sent, or at all.
60
+ """
61
+
62
+ @abstractmethod
63
+ async def send(self, item: T_contra) -> None:
64
+ """
65
+ Send an item to the peer(s).
66
+
67
+ :param item: the item to send
68
+ :raises ~anyio.ClosedResourceError: if the send stream has been explicitly
69
+ closed
70
+ :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable
71
+ due to external causes
72
+ """
73
+
74
+
75
+ class UnreliableObjectStream(
76
+ UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item]
77
+ ):
78
+ """
79
+ A bidirectional message stream which does not guarantee the order or reliability of
80
+ message delivery.
81
+ """
82
+
83
+
84
+ class ObjectReceiveStream(UnreliableObjectReceiveStream[T_co]):
85
+ """
86
+ A receive message stream which guarantees that messages are received in the same
87
+ order in which they were sent, and that no messages are missed.
88
+ """
89
+
90
+
91
+ class ObjectSendStream(UnreliableObjectSendStream[T_contra]):
92
+ """
93
+ A send message stream which guarantees that messages are delivered in the same order
94
+ in which they were sent, without missing any messages in the middle.
95
+ """
96
+
97
+
98
+ class ObjectStream(
99
+ ObjectReceiveStream[T_Item],
100
+ ObjectSendStream[T_Item],
101
+ UnreliableObjectStream[T_Item],
102
+ ):
103
+ """
104
+ A bidirectional message stream which guarantees the order and reliability of message
105
+ delivery.
106
+ """
107
+
108
+ @abstractmethod
109
+ async def send_eof(self) -> None:
110
+ """
111
+ Send an end-of-file indication to the peer.
112
+
113
+ You should not try to send any further data to this stream after calling this
114
+ method. This method is idempotent (does nothing on successive calls).
115
+ """
116
+
117
+
118
+ class ByteReceiveStream(AsyncResource, TypedAttributeProvider):
119
+ """
120
+ An interface for receiving bytes from a single peer.
121
+
122
+ Iterating this byte stream will yield a byte string of arbitrary length, but no more
123
+ than 65536 bytes.
124
+ """
125
+
126
+ def __aiter__(self) -> ByteReceiveStream:
127
+ return self
128
+
129
+ async def __anext__(self) -> bytes:
130
+ try:
131
+ return await self.receive()
132
+ except EndOfStream:
133
+ raise StopAsyncIteration from None
134
+
135
+ @abstractmethod
136
+ async def receive(self, max_bytes: int = 65536) -> bytes:
137
+ """
138
+ Receive at most ``max_bytes`` bytes from the peer.
139
+
140
+ .. note:: Implementers of this interface should not return an empty
141
+ :class:`bytes` object, and users should ignore them.
142
+
143
+ :param max_bytes: maximum number of bytes to receive
144
+ :return: the received bytes
145
+ :raises ~anyio.EndOfStream: if this stream has been closed from the other end
146
+ """
147
+
148
+
149
+ class ByteSendStream(AsyncResource, TypedAttributeProvider):
150
+ """An interface for sending bytes to a single peer."""
151
+
152
+ @abstractmethod
153
+ async def send(self, item: bytes) -> None:
154
+ """
155
+ Send the given bytes to the peer.
156
+
157
+ :param item: the bytes to send
158
+ """
159
+
160
+
161
+ class ByteStream(ByteReceiveStream, ByteSendStream):
162
+ """A bidirectional byte stream."""
163
+
164
+ @abstractmethod
165
+ async def send_eof(self) -> None:
166
+ """
167
+ Send an end-of-file indication to the peer.
168
+
169
+ You should not try to send any further data to this stream after calling this
170
+ method. This method is idempotent (does nothing on successive calls).
171
+ """
172
+
173
+
174
+ #: Type alias for all unreliable bytes-oriented receive streams.
175
+ AnyUnreliableByteReceiveStream: TypeAlias = (
176
+ UnreliableObjectReceiveStream[bytes] | ByteReceiveStream
177
+ )
178
+ #: Type alias for all unreliable bytes-oriented send streams.
179
+ AnyUnreliableByteSendStream: TypeAlias = (
180
+ UnreliableObjectSendStream[bytes] | ByteSendStream
181
+ )
182
+ #: Type alias for all unreliable bytes-oriented streams.
183
+ AnyUnreliableByteStream: TypeAlias = UnreliableObjectStream[bytes] | ByteStream
184
+ #: Type alias for all bytes-oriented receive streams.
185
+ AnyByteReceiveStream: TypeAlias = ObjectReceiveStream[bytes] | ByteReceiveStream
186
+ #: Type alias for all bytes-oriented send streams.
187
+ AnyByteSendStream: TypeAlias = ObjectSendStream[bytes] | ByteSendStream
188
+ #: Type alias for all bytes-oriented streams.
189
+ AnyByteStream: TypeAlias = ObjectStream[bytes] | ByteStream
190
+
191
+
192
+ class Listener(Generic[T_co], AsyncResource, TypedAttributeProvider):
193
+ """An interface for objects that let you accept incoming connections."""
194
+
195
+ @abstractmethod
196
+ async def serve(
197
+ self, handler: Callable[[T_co], Any], task_group: TaskGroup | None = None
198
+ ) -> None:
199
+ """
200
+ Accept incoming connections as they come in and start tasks to handle them.
201
+
202
+ :param handler: a callable that will be used to handle each accepted connection
203
+ :param task_group: the task group that will be used to start tasks for handling
204
+ each accepted connection (if omitted, an ad-hoc task group will be created)
205
+ """
206
+
207
+
208
+ class ObjectStreamConnectable(Generic[T_co], metaclass=ABCMeta):
209
+ @abstractmethod
210
+ async def connect(self) -> ObjectStream[T_co]:
211
+ """
212
+ Connect to the remote endpoint.
213
+
214
+ :return: an object stream connected to the remote end
215
+ :raises ConnectionFailed: if the connection fails
216
+ """
217
+
218
+
219
+ class ByteStreamConnectable(metaclass=ABCMeta):
220
+ @abstractmethod
221
+ async def connect(self) -> ByteStream:
222
+ """
223
+ Connect to the remote endpoint.
224
+
225
+ :return: a bytestream connected to the remote end
226
+ :raises ConnectionFailed: if the connection fails
227
+ """
228
+
229
+
230
+ #: Type alias for all connectables returning bytestreams or bytes-oriented object streams
231
+ AnyByteStreamConnectable: TypeAlias = (
232
+ ObjectStreamConnectable[bytes] | ByteStreamConnectable
233
+ )
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_subprocesses.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from abc import abstractmethod
4
+ from signal import Signals
5
+
6
+ from ._resources import AsyncResource
7
+ from ._streams import ByteReceiveStream, ByteSendStream
8
+
9
+
10
+ class Process(AsyncResource):
11
+ """An asynchronous version of :class:`subprocess.Popen`."""
12
+
13
+ @abstractmethod
14
+ async def wait(self) -> int:
15
+ """
16
+ Wait until the process exits.
17
+
18
+ :return: the exit code of the process
19
+ """
20
+
21
+ @abstractmethod
22
+ def terminate(self) -> None:
23
+ """
24
+ Terminates the process, gracefully if possible.
25
+
26
+ On Windows, this calls ``TerminateProcess()``.
27
+ On POSIX systems, this sends ``SIGTERM`` to the process.
28
+
29
+ .. seealso:: :meth:`subprocess.Popen.terminate`
30
+ """
31
+
32
+ @abstractmethod
33
+ def kill(self) -> None:
34
+ """
35
+ Kills the process.
36
+
37
+ On Windows, this calls ``TerminateProcess()``.
38
+ On POSIX systems, this sends ``SIGKILL`` to the process.
39
+
40
+ .. seealso:: :meth:`subprocess.Popen.kill`
41
+ """
42
+
43
+ @abstractmethod
44
+ def send_signal(self, signal: Signals) -> None:
45
+ """
46
+ Send a signal to the subprocess.
47
+
48
+ .. seealso:: :meth:`subprocess.Popen.send_signal`
49
+
50
+ :param signal: the signal number (e.g. :data:`signal.SIGHUP`)
51
+ """
52
+
53
+ @property
54
+ @abstractmethod
55
+ def pid(self) -> int:
56
+ """The process ID of the process."""
57
+
58
+ @property
59
+ @abstractmethod
60
+ def returncode(self) -> int | None:
61
+ """
62
+ The return code of the process. If the process has not yet terminated, this will
63
+ be ``None``.
64
+ """
65
+
66
+ @property
67
+ @abstractmethod
68
+ def stdin(self) -> ByteSendStream | None:
69
+ """The stream for the standard input of the process."""
70
+
71
+ @property
72
+ @abstractmethod
73
+ def stdout(self) -> ByteReceiveStream | None:
74
+ """The stream for the standard output of the process."""
75
+
76
+ @property
77
+ @abstractmethod
78
+ def stderr(self) -> ByteReceiveStream | None:
79
+ """The stream for the standard error output of the process."""
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_tasks.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ from abc import ABCMeta, abstractmethod
5
+ from collections.abc import Awaitable, Callable
6
+ from types import TracebackType
7
+ from typing import TYPE_CHECKING, Any, Protocol, overload
8
+
9
+ if sys.version_info >= (3, 13):
10
+ from typing import TypeVar
11
+ else:
12
+ from typing_extensions import TypeVar
13
+
14
+ if sys.version_info >= (3, 11):
15
+ from typing import TypeVarTuple, Unpack
16
+ else:
17
+ from typing_extensions import TypeVarTuple, Unpack
18
+
19
+ if TYPE_CHECKING:
20
+ from .._core._tasks import CancelScope
21
+
22
+ T_Retval = TypeVar("T_Retval")
23
+ T_contra = TypeVar("T_contra", contravariant=True, default=None)
24
+ PosArgsT = TypeVarTuple("PosArgsT")
25
+
26
+
27
+ class TaskStatus(Protocol[T_contra]):
28
+ @overload
29
+ def started(self: TaskStatus[None]) -> None: ...
30
+
31
+ @overload
32
+ def started(self, value: T_contra) -> None: ...
33
+
34
+ def started(self, value: T_contra | None = None) -> None:
35
+ """
36
+ Signal that the task has started.
37
+
38
+ :param value: object passed back to the starter of the task
39
+ """
40
+
41
+
42
+ class TaskGroup(metaclass=ABCMeta):
43
+ """
44
+ Groups several asynchronous tasks together.
45
+
46
+ :ivar cancel_scope: the cancel scope inherited by all child tasks
47
+ :vartype cancel_scope: CancelScope
48
+
49
+ .. note:: On asyncio, support for eager task factories is considered to be
50
+ **experimental**. In particular, they don't follow the usual semantics of new
51
+ tasks being scheduled on the next iteration of the event loop, and may thus
52
+ cause unexpected behavior in code that wasn't written with such semantics in
53
+ mind.
54
+ """
55
+
56
+ cancel_scope: CancelScope
57
+
58
+ @abstractmethod
59
+ def start_soon(
60
+ self,
61
+ func: Callable[[Unpack[PosArgsT]], Awaitable[Any]],
62
+ *args: Unpack[PosArgsT],
63
+ name: object = None,
64
+ ) -> None:
65
+ """
66
+ Start a new task in this task group.
67
+
68
+ :param func: a coroutine function
69
+ :param args: positional arguments to call the function with
70
+ :param name: name of the task, for the purposes of introspection and debugging
71
+
72
+ .. versionadded:: 3.0
73
+ """
74
+
75
+ @abstractmethod
76
+ async def start(
77
+ self,
78
+ func: Callable[..., Awaitable[Any]],
79
+ *args: object,
80
+ name: object = None,
81
+ ) -> Any:
82
+ """
83
+ Start a new task and wait until it signals for readiness.
84
+
85
+ The target callable must accept a keyword argument ``task_status`` (of type
86
+ :class:`TaskStatus`). Awaiting on this method will return whatever was passed to
87
+ ``task_status.started()`` (``None`` by default).
88
+
89
+ .. note:: The :class:`TaskStatus` class is generic, and the type argument should
90
+ indicate the type of the value that will be passed to
91
+ ``task_status.started()``.
92
+
93
+ :param func: a coroutine function that accepts the ``task_status`` keyword
94
+ argument
95
+ :param args: positional arguments to call the function with
96
+ :param name: an optional name for the task, for introspection and debugging
97
+ :return: the value passed to ``task_status.started()``
98
+ :raises RuntimeError: if the task finishes without calling
99
+ ``task_status.started()``
100
+
101
+ .. seealso:: :ref:`start_initialize`
102
+
103
+ .. versionadded:: 3.0
104
+ """
105
+
106
+ @abstractmethod
107
+ async def __aenter__(self) -> TaskGroup:
108
+ """Enter the task group context and allow starting new tasks."""
109
+
110
+ @abstractmethod
111
+ async def __aexit__(
112
+ self,
113
+ exc_type: type[BaseException] | None,
114
+ exc_val: BaseException | None,
115
+ exc_tb: TracebackType | None,
116
+ ) -> bool:
117
+ """Exit the task group context waiting for all tasks to finish."""
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/abc/_testing.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import types
4
+ from abc import ABCMeta, abstractmethod
5
+ from collections.abc import AsyncGenerator, Callable, Coroutine, Iterable
6
+ from typing import Any, TypeVar
7
+
8
+ _T = TypeVar("_T")
9
+
10
+
11
+ class TestRunner(metaclass=ABCMeta):
12
+ """
13
+ Encapsulates a running event loop. Every call made through this object will use the
14
+ same event loop.
15
+ """
16
+
17
+ def __enter__(self) -> TestRunner:
18
+ return self
19
+
20
+ @abstractmethod
21
+ def __exit__(
22
+ self,
23
+ exc_type: type[BaseException] | None,
24
+ exc_val: BaseException | None,
25
+ exc_tb: types.TracebackType | None,
26
+ ) -> bool | None: ...
27
+
28
+ @abstractmethod
29
+ def run_asyncgen_fixture(
30
+ self,
31
+ fixture_func: Callable[..., AsyncGenerator[_T, Any]],
32
+ kwargs: dict[str, Any],
33
+ ) -> Iterable[_T]:
34
+ """
35
+ Run an async generator fixture.
36
+
37
+ :param fixture_func: the fixture function
38
+ :param kwargs: keyword arguments to call the fixture function with
39
+ :return: an iterator yielding the value yielded from the async generator
40
+ """
41
+
42
+ @abstractmethod
43
+ def run_fixture(
44
+ self,
45
+ fixture_func: Callable[..., Coroutine[Any, Any, _T]],
46
+ kwargs: dict[str, Any],
47
+ ) -> _T:
48
+ """
49
+ Run an async fixture.
50
+
51
+ :param fixture_func: the fixture function
52
+ :param kwargs: keyword arguments to call the fixture function with
53
+ :return: the return value of the fixture function
54
+ """
55
+
56
+ @abstractmethod
57
+ def run_test(
58
+ self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
59
+ ) -> None:
60
+ """
61
+ Run an async test function.
62
+
63
+ :param test_func: the test function
64
+ :param kwargs: keyword arguments to call the test function with
65
+ """
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/from_thread.py ADDED
@@ -0,0 +1,578 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "BlockingPortal",
5
+ "BlockingPortalProvider",
6
+ "check_cancelled",
7
+ "run",
8
+ "run_sync",
9
+ "start_blocking_portal",
10
+ )
11
+
12
+ import sys
13
+ from collections.abc import Awaitable, Callable, Generator
14
+ from concurrent.futures import Future
15
+ from contextlib import (
16
+ AbstractAsyncContextManager,
17
+ AbstractContextManager,
18
+ contextmanager,
19
+ )
20
+ from dataclasses import dataclass, field
21
+ from functools import partial
22
+ from inspect import isawaitable
23
+ from threading import Lock, Thread, current_thread, get_ident
24
+ from types import TracebackType
25
+ from typing import (
26
+ Any,
27
+ Generic,
28
+ TypeVar,
29
+ cast,
30
+ overload,
31
+ )
32
+
33
+ from ._core._eventloop import (
34
+ get_cancelled_exc_class,
35
+ threadlocals,
36
+ )
37
+ from ._core._eventloop import run as run_eventloop
38
+ from ._core._exceptions import NoEventLoopError
39
+ from ._core._synchronization import Event
40
+ from ._core._tasks import CancelScope, create_task_group
41
+ from .abc._tasks import TaskStatus
42
+ from .lowlevel import EventLoopToken, current_token
43
+
44
+ if sys.version_info >= (3, 11):
45
+ from typing import TypeVarTuple, Unpack
46
+ else:
47
+ from typing_extensions import TypeVarTuple, Unpack
48
+
49
+ T_Retval = TypeVar("T_Retval")
50
+ T_co = TypeVar("T_co", covariant=True)
51
+ PosArgsT = TypeVarTuple("PosArgsT")
52
+
53
+
54
+ def _token_or_error(token: EventLoopToken | None) -> EventLoopToken:
55
+ if token is not None:
56
+ return token
57
+
58
+ try:
59
+ return threadlocals.current_token
60
+ except AttributeError:
61
+ raise NoEventLoopError(
62
+ "Not running inside an AnyIO worker thread, and no event loop token was "
63
+ "provided"
64
+ ) from None
65
+
66
+
67
+ def run(
68
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
69
+ *args: Unpack[PosArgsT],
70
+ token: EventLoopToken | None = None,
71
+ ) -> T_Retval:
72
+ """
73
+ Call a coroutine function from a worker thread.
74
+
75
+ :param func: a coroutine function
76
+ :param args: positional arguments for the callable
77
+ :param token: an event loop token to use to get back to the event loop thread
78
+ (required if calling this function from outside an AnyIO worker thread)
79
+ :return: the return value of the coroutine function
80
+ :raises MissingTokenError: if no token was provided and called from outside an
81
+ AnyIO worker thread
82
+ :raises RunFinishedError: if the event loop tied to ``token`` is no longer running
83
+
84
+ .. versionchanged:: 4.11.0
85
+ Added the ``token`` parameter.
86
+
87
+ """
88
+ explicit_token = token is not None
89
+ token = _token_or_error(token)
90
+ return token.backend_class.run_async_from_thread(
91
+ func, args, token=token.native_token if explicit_token else None
92
+ )
93
+
94
+
95
+ def run_sync(
96
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
97
+ *args: Unpack[PosArgsT],
98
+ token: EventLoopToken | None = None,
99
+ ) -> T_Retval:
100
+ """
101
+ Call a function in the event loop thread from a worker thread.
102
+
103
+ :param func: a callable
104
+ :param args: positional arguments for the callable
105
+ :param token: an event loop token to use to get back to the event loop thread
106
+ (required if calling this function from outside an AnyIO worker thread)
107
+ :return: the return value of the callable
108
+ :raises MissingTokenError: if no token was provided and called from outside an
109
+ AnyIO worker thread
110
+ :raises RunFinishedError: if the event loop tied to ``token`` is no longer running
111
+
112
+ .. versionchanged:: 4.11.0
113
+ Added the ``token`` parameter.
114
+
115
+ """
116
+ explicit_token = token is not None
117
+ token = _token_or_error(token)
118
+ return token.backend_class.run_sync_from_thread(
119
+ func, args, token=token.native_token if explicit_token else None
120
+ )
121
+
122
+
123
+ class _BlockingAsyncContextManager(Generic[T_co], AbstractContextManager):
124
+ _enter_future: Future[T_co]
125
+ _exit_future: Future[bool | None]
126
+ _exit_event: Event
127
+ _exit_exc_info: tuple[
128
+ type[BaseException] | None, BaseException | None, TracebackType | None
129
+ ] = (None, None, None)
130
+
131
+ def __init__(
132
+ self, async_cm: AbstractAsyncContextManager[T_co], portal: BlockingPortal
133
+ ):
134
+ self._async_cm = async_cm
135
+ self._portal = portal
136
+
137
+ async def run_async_cm(self) -> bool | None:
138
+ try:
139
+ self._exit_event = Event()
140
+ value = await self._async_cm.__aenter__()
141
+ except BaseException as exc:
142
+ self._enter_future.set_exception(exc)
143
+ raise
144
+ else:
145
+ self._enter_future.set_result(value)
146
+
147
+ try:
148
+ # Wait for the sync context manager to exit.
149
+ # This next statement can raise `get_cancelled_exc_class()` if
150
+ # something went wrong in a task group in this async context
151
+ # manager.
152
+ await self._exit_event.wait()
153
+ finally:
154
+ # In case of cancellation, it could be that we end up here before
155
+ # `_BlockingAsyncContextManager.__exit__` is called, and an
156
+ # `_exit_exc_info` has been set.
157
+ result = await self._async_cm.__aexit__(*self._exit_exc_info)
158
+
159
+ return result
160
+
161
+ def __enter__(self) -> T_co:
162
+ self._enter_future = Future()
163
+ self._exit_future = self._portal.start_task_soon(self.run_async_cm)
164
+ return self._enter_future.result()
165
+
166
+ def __exit__(
167
+ self,
168
+ __exc_type: type[BaseException] | None,
169
+ __exc_value: BaseException | None,
170
+ __traceback: TracebackType | None,
171
+ ) -> bool | None:
172
+ self._exit_exc_info = __exc_type, __exc_value, __traceback
173
+ self._portal.call(self._exit_event.set)
174
+ return self._exit_future.result()
175
+
176
+
177
+ class _BlockingPortalTaskStatus(TaskStatus):
178
+ def __init__(self, future: Future):
179
+ self._future = future
180
+
181
+ def started(self, value: object = None) -> None:
182
+ self._future.set_result(value)
183
+
184
+
185
+ class BlockingPortal:
186
+ """
187
+ An object that lets external threads run code in an asynchronous event loop.
188
+
189
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
190
+ current thread
191
+ """
192
+
193
+ def __init__(self) -> None:
194
+ self._token = current_token()
195
+ self._event_loop_thread_id: int | None = get_ident()
196
+ self._stop_event = Event()
197
+ self._task_group = create_task_group()
198
+
199
+ async def __aenter__(self) -> BlockingPortal:
200
+ await self._task_group.__aenter__()
201
+ return self
202
+
203
+ async def __aexit__(
204
+ self,
205
+ exc_type: type[BaseException] | None,
206
+ exc_val: BaseException | None,
207
+ exc_tb: TracebackType | None,
208
+ ) -> bool:
209
+ await self.stop()
210
+ return await self._task_group.__aexit__(exc_type, exc_val, exc_tb)
211
+
212
+ def _check_running(self) -> None:
213
+ if self._event_loop_thread_id is None:
214
+ raise RuntimeError("This portal is not running")
215
+ if self._event_loop_thread_id == get_ident():
216
+ raise RuntimeError(
217
+ "This method cannot be called from the event loop thread"
218
+ )
219
+
220
+ async def sleep_until_stopped(self) -> None:
221
+ """Sleep until :meth:`stop` is called."""
222
+ await self._stop_event.wait()
223
+
224
+ async def stop(self, cancel_remaining: bool = False) -> None:
225
+ """
226
+ Signal the portal to shut down.
227
+
228
+ This marks the portal as no longer accepting new calls and exits from
229
+ :meth:`sleep_until_stopped`.
230
+
231
+ :param cancel_remaining: ``True`` to cancel all the remaining tasks, ``False``
232
+ to let them finish before returning
233
+
234
+ """
235
+ self._event_loop_thread_id = None
236
+ self._stop_event.set()
237
+ if cancel_remaining:
238
+ self._task_group.cancel_scope.cancel("the blocking portal is shutting down")
239
+
240
+ async def _call_func(
241
+ self,
242
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval],
243
+ args: tuple[Unpack[PosArgsT]],
244
+ kwargs: dict[str, Any],
245
+ future: Future[T_Retval],
246
+ ) -> None:
247
+ def callback(f: Future[T_Retval]) -> None:
248
+ if f.cancelled():
249
+ if self._event_loop_thread_id == get_ident():
250
+ scope.cancel("the future was cancelled")
251
+ elif self._event_loop_thread_id is not None:
252
+ self.call(scope.cancel, "the future was cancelled")
253
+
254
+ try:
255
+ retval_or_awaitable = func(*args, **kwargs)
256
+ if isawaitable(retval_or_awaitable):
257
+ with CancelScope() as scope:
258
+ future.add_done_callback(callback)
259
+ retval = await retval_or_awaitable
260
+ else:
261
+ retval = retval_or_awaitable
262
+ except get_cancelled_exc_class():
263
+ future.cancel()
264
+ future.set_running_or_notify_cancel()
265
+ except BaseException as exc:
266
+ if not future.cancelled():
267
+ future.set_exception(exc)
268
+
269
+ # Let base exceptions fall through
270
+ if not isinstance(exc, Exception):
271
+ raise
272
+ else:
273
+ if not future.cancelled():
274
+ future.set_result(retval)
275
+ finally:
276
+ scope = None # type: ignore[assignment]
277
+
278
+ def _spawn_task_from_thread(
279
+ self,
280
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval],
281
+ args: tuple[Unpack[PosArgsT]],
282
+ kwargs: dict[str, Any],
283
+ name: object,
284
+ future: Future[T_Retval],
285
+ ) -> None:
286
+ """
287
+ Spawn a new task using the given callable.
288
+
289
+ :param func: a callable
290
+ :param args: positional arguments to be passed to the callable
291
+ :param kwargs: keyword arguments to be passed to the callable
292
+ :param name: name of the task (will be coerced to a string if not ``None``)
293
+ :param future: a future that will resolve to the return value of the callable,
294
+ or the exception raised during its execution
295
+
296
+ """
297
+ run_sync(
298
+ partial(self._task_group.start_soon, name=name),
299
+ self._call_func,
300
+ func,
301
+ args,
302
+ kwargs,
303
+ future,
304
+ token=self._token,
305
+ )
306
+
307
+ @overload
308
+ def call(
309
+ self,
310
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
311
+ *args: Unpack[PosArgsT],
312
+ ) -> T_Retval: ...
313
+
314
+ @overload
315
+ def call(
316
+ self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT]
317
+ ) -> T_Retval: ...
318
+
319
+ def call(
320
+ self,
321
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval],
322
+ *args: Unpack[PosArgsT],
323
+ ) -> T_Retval:
324
+ """
325
+ Call the given function in the event loop thread.
326
+
327
+ If the callable returns a coroutine object, it is awaited on.
328
+
329
+ :param func: any callable
330
+ :raises RuntimeError: if the portal is not running or if this method is called
331
+ from within the event loop thread
332
+
333
+ """
334
+ return cast(T_Retval, self.start_task_soon(func, *args).result())
335
+
336
+ @overload
337
+ def start_task_soon(
338
+ self,
339
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
340
+ *args: Unpack[PosArgsT],
341
+ name: object = None,
342
+ ) -> Future[T_Retval]: ...
343
+
344
+ @overload
345
+ def start_task_soon(
346
+ self,
347
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
348
+ *args: Unpack[PosArgsT],
349
+ name: object = None,
350
+ ) -> Future[T_Retval]: ...
351
+
352
+ def start_task_soon(
353
+ self,
354
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval],
355
+ *args: Unpack[PosArgsT],
356
+ name: object = None,
357
+ ) -> Future[T_Retval]:
358
+ """
359
+ Start a task in the portal's task group.
360
+
361
+ The task will be run inside a cancel scope which can be cancelled by cancelling
362
+ the returned future.
363
+
364
+ :param func: the target function
365
+ :param args: positional arguments passed to ``func``
366
+ :param name: name of the task (will be coerced to a string if not ``None``)
367
+ :return: a future that resolves with the return value of the callable if the
368
+ task completes successfully, or with the exception raised in the task
369
+ :raises RuntimeError: if the portal is not running or if this method is called
370
+ from within the event loop thread
371
+ :rtype: concurrent.futures.Future[T_Retval]
372
+
373
+ .. versionadded:: 3.0
374
+
375
+ """
376
+ self._check_running()
377
+ f: Future[T_Retval] = Future()
378
+ self._spawn_task_from_thread(func, args, {}, name, f)
379
+ return f
380
+
381
+ def start_task(
382
+ self,
383
+ func: Callable[..., Awaitable[T_Retval]],
384
+ *args: object,
385
+ name: object = None,
386
+ ) -> tuple[Future[T_Retval], Any]:
387
+ """
388
+ Start a task in the portal's task group and wait until it signals for readiness.
389
+
390
+ This method works the same way as :meth:`.abc.TaskGroup.start`.
391
+
392
+ :param func: the target function
393
+ :param args: positional arguments passed to ``func``
394
+ :param name: name of the task (will be coerced to a string if not ``None``)
395
+ :return: a tuple of (future, task_status_value) where the ``task_status_value``
396
+ is the value passed to ``task_status.started()`` from within the target
397
+ function
398
+ :rtype: tuple[concurrent.futures.Future[T_Retval], Any]
399
+
400
+ .. versionadded:: 3.0
401
+
402
+ """
403
+
404
+ def task_done(future: Future[T_Retval]) -> None:
405
+ if not task_status_future.done():
406
+ if future.cancelled():
407
+ task_status_future.cancel()
408
+ elif future.exception():
409
+ task_status_future.set_exception(future.exception())
410
+ else:
411
+ exc = RuntimeError(
412
+ "Task exited without calling task_status.started()"
413
+ )
414
+ task_status_future.set_exception(exc)
415
+
416
+ self._check_running()
417
+ task_status_future: Future = Future()
418
+ task_status = _BlockingPortalTaskStatus(task_status_future)
419
+ f: Future = Future()
420
+ f.add_done_callback(task_done)
421
+ self._spawn_task_from_thread(func, args, {"task_status": task_status}, name, f)
422
+ return f, task_status_future.result()
423
+
424
+ def wrap_async_context_manager(
425
+ self, cm: AbstractAsyncContextManager[T_co]
426
+ ) -> AbstractContextManager[T_co]:
427
+ """
428
+ Wrap an async context manager as a synchronous context manager via this portal.
429
+
430
+ Spawns a task that will call both ``__aenter__()`` and ``__aexit__()``, stopping
431
+ in the middle until the synchronous context manager exits.
432
+
433
+ :param cm: an asynchronous context manager
434
+ :return: a synchronous context manager
435
+
436
+ .. versionadded:: 2.1
437
+
438
+ """
439
+ return _BlockingAsyncContextManager(cm, self)
440
+
441
+
442
+ @dataclass
443
+ class BlockingPortalProvider:
444
+ """
445
+ A manager for a blocking portal. Used as a context manager. The first thread to
446
+ enter this context manager causes a blocking portal to be started with the specific
447
+ parameters, and the last thread to exit causes the portal to be shut down. Thus,
448
+ there will be exactly one blocking portal running in this context as long as at
449
+ least one thread has entered this context manager.
450
+
451
+ The parameters are the same as for :func:`~anyio.run`.
452
+
453
+ :param backend: name of the backend
454
+ :param backend_options: backend options
455
+
456
+ .. versionadded:: 4.4
457
+ """
458
+
459
+ backend: str = "asyncio"
460
+ backend_options: dict[str, Any] | None = None
461
+ _lock: Lock = field(init=False, default_factory=Lock)
462
+ _leases: int = field(init=False, default=0)
463
+ _portal: BlockingPortal = field(init=False)
464
+ _portal_cm: AbstractContextManager[BlockingPortal] | None = field(
465
+ init=False, default=None
466
+ )
467
+
468
+ def __enter__(self) -> BlockingPortal:
469
+ with self._lock:
470
+ if self._portal_cm is None:
471
+ self._portal_cm = start_blocking_portal(
472
+ self.backend, self.backend_options
473
+ )
474
+ self._portal = self._portal_cm.__enter__()
475
+
476
+ self._leases += 1
477
+ return self._portal
478
+
479
+ def __exit__(
480
+ self,
481
+ exc_type: type[BaseException] | None,
482
+ exc_val: BaseException | None,
483
+ exc_tb: TracebackType | None,
484
+ ) -> None:
485
+ portal_cm: AbstractContextManager[BlockingPortal] | None = None
486
+ with self._lock:
487
+ assert self._portal_cm
488
+ assert self._leases > 0
489
+ self._leases -= 1
490
+ if not self._leases:
491
+ portal_cm = self._portal_cm
492
+ self._portal_cm = None
493
+ del self._portal
494
+
495
+ if portal_cm:
496
+ portal_cm.__exit__(None, None, None)
497
+
498
+
499
+ @contextmanager
500
+ def start_blocking_portal(
501
+ backend: str = "asyncio",
502
+ backend_options: dict[str, Any] | None = None,
503
+ *,
504
+ name: str | None = None,
505
+ ) -> Generator[BlockingPortal, Any, None]:
506
+ """
507
+ Start a new event loop in a new thread and run a blocking portal in its main task.
508
+
509
+ The parameters are the same as for :func:`~anyio.run`.
510
+
511
+ :param backend: name of the backend
512
+ :param backend_options: backend options
513
+ :param name: name of the thread
514
+ :return: a context manager that yields a blocking portal
515
+
516
+ .. versionchanged:: 3.0
517
+ Usage as a context manager is now required.
518
+
519
+ """
520
+
521
+ async def run_portal() -> None:
522
+ async with BlockingPortal() as portal_:
523
+ if name is None:
524
+ current_thread().name = f"{backend}-portal-{id(portal_):x}"
525
+
526
+ future.set_result(portal_)
527
+ await portal_.sleep_until_stopped()
528
+
529
+ def run_blocking_portal() -> None:
530
+ if future.set_running_or_notify_cancel():
531
+ try:
532
+ run_eventloop(
533
+ run_portal, backend=backend, backend_options=backend_options
534
+ )
535
+ except BaseException as exc:
536
+ if not future.done():
537
+ future.set_exception(exc)
538
+
539
+ future: Future[BlockingPortal] = Future()
540
+ thread = Thread(target=run_blocking_portal, daemon=True, name=name)
541
+ thread.start()
542
+ try:
543
+ cancel_remaining_tasks = False
544
+ portal = future.result()
545
+ try:
546
+ yield portal
547
+ except BaseException:
548
+ cancel_remaining_tasks = True
549
+ raise
550
+ finally:
551
+ try:
552
+ portal.call(portal.stop, cancel_remaining_tasks)
553
+ except RuntimeError:
554
+ pass
555
+ finally:
556
+ thread.join()
557
+
558
+
559
+ def check_cancelled() -> None:
560
+ """
561
+ Check if the cancel scope of the host task's running the current worker thread has
562
+ been cancelled.
563
+
564
+ If the host task's current cancel scope has indeed been cancelled, the
565
+ backend-specific cancellation exception will be raised.
566
+
567
+ :raises RuntimeError: if the current thread was not spawned by
568
+ :func:`.to_thread.run_sync`
569
+
570
+ """
571
+ try:
572
+ token: EventLoopToken = threadlocals.current_token
573
+ except AttributeError:
574
+ raise NoEventLoopError(
575
+ "This function can only be called inside an AnyIO worker thread"
576
+ ) from None
577
+
578
+ token.backend_class.check_cancelled()
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/functools.py ADDED
@@ -0,0 +1,409 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "AsyncCacheInfo",
5
+ "AsyncCacheParameters",
6
+ "AsyncLRUCacheWrapper",
7
+ "cache",
8
+ "lru_cache",
9
+ "reduce",
10
+ )
11
+
12
+ import functools
13
+ import sys
14
+ from collections import OrderedDict
15
+ from collections.abc import (
16
+ AsyncIterable,
17
+ Awaitable,
18
+ Callable,
19
+ Coroutine,
20
+ Hashable,
21
+ Iterable,
22
+ )
23
+ from functools import update_wrapper
24
+ from inspect import iscoroutinefunction
25
+ from typing import (
26
+ Any,
27
+ Generic,
28
+ NamedTuple,
29
+ TypedDict,
30
+ TypeVar,
31
+ cast,
32
+ final,
33
+ overload,
34
+ )
35
+ from weakref import WeakKeyDictionary
36
+
37
+ from ._core._eventloop import current_time
38
+ from ._core._synchronization import Lock
39
+ from .lowlevel import RunVar, checkpoint
40
+
41
+ if sys.version_info >= (3, 11):
42
+ from typing import ParamSpec
43
+ else:
44
+ from typing_extensions import ParamSpec
45
+
46
+ T = TypeVar("T")
47
+ S = TypeVar("S")
48
+ P = ParamSpec("P")
49
+ lru_cache_items: RunVar[
50
+ WeakKeyDictionary[
51
+ AsyncLRUCacheWrapper[Any, Any],
52
+ OrderedDict[
53
+ Hashable,
54
+ tuple[_InitialMissingType, Lock, float | None]
55
+ | tuple[Any, None, float | None],
56
+ ],
57
+ ]
58
+ ] = RunVar("lru_cache_items")
59
+
60
+
61
+ class _InitialMissingType:
62
+ pass
63
+
64
+
65
+ initial_missing: _InitialMissingType = _InitialMissingType()
66
+
67
+
68
+ class AsyncCacheInfo(NamedTuple):
69
+ hits: int
70
+ misses: int
71
+ maxsize: int | None
72
+ currsize: int
73
+ ttl: int | None
74
+
75
+
76
+ class AsyncCacheParameters(TypedDict):
77
+ maxsize: int | None
78
+ typed: bool
79
+ always_checkpoint: bool
80
+ ttl: int | None
81
+
82
+
83
+ class _LRUMethodWrapper(Generic[T]):
84
+ def __init__(self, wrapper: AsyncLRUCacheWrapper[..., T], instance: object):
85
+ self.__wrapper = wrapper
86
+ self.__instance = instance
87
+
88
+ def cache_info(self) -> AsyncCacheInfo:
89
+ return self.__wrapper.cache_info()
90
+
91
+ def cache_parameters(self) -> AsyncCacheParameters:
92
+ return self.__wrapper.cache_parameters()
93
+
94
+ def cache_clear(self) -> None:
95
+ self.__wrapper.cache_clear()
96
+
97
+ async def __call__(self, *args: Any, **kwargs: Any) -> T:
98
+ if self.__instance is None:
99
+ return await self.__wrapper(*args, **kwargs)
100
+
101
+ return await self.__wrapper(self.__instance, *args, **kwargs)
102
+
103
+
104
+ @final
105
+ class AsyncLRUCacheWrapper(Generic[P, T]):
106
+ def __init__(
107
+ self,
108
+ func: Callable[P, Awaitable[T]],
109
+ maxsize: int | None,
110
+ typed: bool,
111
+ always_checkpoint: bool,
112
+ ttl: int | None,
113
+ ):
114
+ self.__wrapped__ = func
115
+ self._hits: int = 0
116
+ self._misses: int = 0
117
+ self._maxsize = max(maxsize, 0) if maxsize is not None else None
118
+ self._currsize: int = 0
119
+ self._typed = typed
120
+ self._always_checkpoint = always_checkpoint
121
+ self._ttl = ttl
122
+ update_wrapper(self, func)
123
+
124
+ def cache_info(self) -> AsyncCacheInfo:
125
+ return AsyncCacheInfo(
126
+ self._hits, self._misses, self._maxsize, self._currsize, self._ttl
127
+ )
128
+
129
+ def cache_parameters(self) -> AsyncCacheParameters:
130
+ return {
131
+ "maxsize": self._maxsize,
132
+ "typed": self._typed,
133
+ "always_checkpoint": self._always_checkpoint,
134
+ "ttl": self._ttl,
135
+ }
136
+
137
+ def cache_clear(self) -> None:
138
+ if cache := lru_cache_items.get(None):
139
+ cache.pop(self, None)
140
+ self._hits = self._misses = self._currsize = 0
141
+
142
+ async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:
143
+ # Easy case first: if maxsize == 0, no caching is done
144
+ if self._maxsize == 0:
145
+ value = await self.__wrapped__(*args, **kwargs)
146
+ self._misses += 1
147
+ return value
148
+
149
+ # The key is constructed as a flat tuple to avoid memory overhead
150
+ key: tuple[Any, ...] = args
151
+ if kwargs:
152
+ # initial_missing is used as a separator
153
+ key += (initial_missing,) + sum(kwargs.items(), ())
154
+
155
+ if self._typed:
156
+ key += tuple(type(arg) for arg in args)
157
+ if kwargs:
158
+ key += (initial_missing,) + tuple(type(val) for val in kwargs.values())
159
+
160
+ try:
161
+ cache = lru_cache_items.get()
162
+ except LookupError:
163
+ cache = WeakKeyDictionary()
164
+ lru_cache_items.set(cache)
165
+
166
+ try:
167
+ cache_entry = cache[self]
168
+ except KeyError:
169
+ cache_entry = cache[self] = OrderedDict()
170
+
171
+ cached_value: T | _InitialMissingType
172
+ try:
173
+ cached_value, lock, expires_at = cache_entry[key]
174
+ except KeyError:
175
+ # We're the first task to call this function
176
+ cached_value, lock, expires_at = (
177
+ initial_missing,
178
+ Lock(fast_acquire=not self._always_checkpoint),
179
+ None,
180
+ )
181
+ cache_entry[key] = cached_value, lock, expires_at
182
+
183
+ if lock is None:
184
+ if expires_at is not None and current_time() >= expires_at:
185
+ self._currsize -= 1
186
+ cached_value, lock, expires_at = (
187
+ initial_missing,
188
+ Lock(fast_acquire=not self._always_checkpoint),
189
+ None,
190
+ )
191
+ cache_entry[key] = cached_value, lock, expires_at
192
+ else:
193
+ # The value was already cached
194
+ self._hits += 1
195
+ cache_entry.move_to_end(key)
196
+ if self._always_checkpoint:
197
+ await checkpoint()
198
+
199
+ return cast(T, cached_value)
200
+
201
+ async with lock:
202
+ # Check if another task filled the cache while we acquired the lock
203
+ if (cached_value := cache_entry[key][0]) is initial_missing:
204
+ self._misses += 1
205
+ if self._maxsize is not None and self._currsize >= self._maxsize:
206
+ cache_entry.popitem(last=False)
207
+ else:
208
+ self._currsize += 1
209
+
210
+ value = await self.__wrapped__(*args, **kwargs)
211
+ expires_at = (
212
+ current_time() + self._ttl if self._ttl is not None else None
213
+ )
214
+ cache_entry[key] = value, None, expires_at
215
+ else:
216
+ # Another task filled the cache while we were waiting for the lock
217
+ self._hits += 1
218
+ cache_entry.move_to_end(key)
219
+ value = cast(T, cached_value)
220
+
221
+ return value
222
+
223
+ def __get__(
224
+ self, instance: object, owner: type | None = None
225
+ ) -> _LRUMethodWrapper[T]:
226
+ wrapper = _LRUMethodWrapper(self, instance)
227
+ update_wrapper(wrapper, self.__wrapped__)
228
+ return wrapper
229
+
230
+
231
+ class _LRUCacheWrapper(Generic[T]):
232
+ def __init__(
233
+ self, maxsize: int | None, typed: bool, always_checkpoint: bool, ttl: int | None
234
+ ):
235
+ self._maxsize = maxsize
236
+ self._typed = typed
237
+ self._always_checkpoint = always_checkpoint
238
+ self._ttl = ttl
239
+
240
+ @overload
241
+ def __call__( # type: ignore[overload-overlap]
242
+ self, func: Callable[P, Coroutine[Any, Any, T]], /
243
+ ) -> AsyncLRUCacheWrapper[P, T]: ...
244
+
245
+ @overload
246
+ def __call__(
247
+ self, func: Callable[..., T], /
248
+ ) -> functools._lru_cache_wrapper[T]: ...
249
+
250
+ def __call__(
251
+ self, f: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T], /
252
+ ) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]:
253
+ if iscoroutinefunction(f):
254
+ return AsyncLRUCacheWrapper(
255
+ f, self._maxsize, self._typed, self._always_checkpoint, self._ttl
256
+ )
257
+
258
+ return functools.lru_cache(maxsize=self._maxsize, typed=self._typed)(f) # type: ignore[arg-type]
259
+
260
+
261
+ @overload
262
+ def cache( # type: ignore[overload-overlap]
263
+ func: Callable[P, Coroutine[Any, Any, T]], /
264
+ ) -> AsyncLRUCacheWrapper[P, T]: ...
265
+
266
+
267
+ @overload
268
+ def cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ...
269
+
270
+
271
+ def cache(
272
+ func: Callable[..., T] | Callable[P, Coroutine[Any, Any, T]], /
273
+ ) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]:
274
+ """
275
+ A convenient shortcut for :func:`lru_cache` with ``maxsize=None``.
276
+
277
+ This is the asynchronous equivalent to :func:`functools.cache`.
278
+
279
+ """
280
+ return lru_cache(maxsize=None)(func)
281
+
282
+
283
+ @overload
284
+ def lru_cache(
285
+ *,
286
+ maxsize: int | None = ...,
287
+ typed: bool = ...,
288
+ always_checkpoint: bool = ...,
289
+ ttl: int | None = ...,
290
+ ) -> _LRUCacheWrapper[Any]: ...
291
+
292
+
293
+ @overload
294
+ def lru_cache( # type: ignore[overload-overlap]
295
+ func: Callable[P, Coroutine[Any, Any, T]], /
296
+ ) -> AsyncLRUCacheWrapper[P, T]: ...
297
+
298
+
299
+ @overload
300
+ def lru_cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ...
301
+
302
+
303
+ def lru_cache(
304
+ func: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T] | None = None,
305
+ /,
306
+ *,
307
+ maxsize: int | None = 128,
308
+ typed: bool = False,
309
+ always_checkpoint: bool = False,
310
+ ttl: int | None = None,
311
+ ) -> (
312
+ AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T] | _LRUCacheWrapper[Any]
313
+ ):
314
+ """
315
+ An asynchronous version of :func:`functools.lru_cache`.
316
+
317
+ If a synchronous function is passed, the standard library
318
+ :func:`functools.lru_cache` is applied instead.
319
+
320
+ :param always_checkpoint: if ``True``, every call to the cached function will be
321
+ guaranteed to yield control to the event loop at least once
322
+ :param ttl: time in seconds after which to invalidate cache entries
323
+
324
+ .. note:: Caches and locks are managed on a per-event loop basis.
325
+
326
+ """
327
+ if func is None:
328
+ return _LRUCacheWrapper[Any](maxsize, typed, always_checkpoint, ttl)
329
+
330
+ if not callable(func):
331
+ raise TypeError("the first argument must be callable")
332
+
333
+ return _LRUCacheWrapper[T](maxsize, typed, always_checkpoint, ttl)(func)
334
+
335
+
336
+ @overload
337
+ async def reduce(
338
+ function: Callable[[T, S], Awaitable[T]],
339
+ iterable: Iterable[S] | AsyncIterable[S],
340
+ /,
341
+ initial: T,
342
+ ) -> T: ...
343
+
344
+
345
+ @overload
346
+ async def reduce(
347
+ function: Callable[[T, T], Awaitable[T]],
348
+ iterable: Iterable[T] | AsyncIterable[T],
349
+ /,
350
+ ) -> T: ...
351
+
352
+
353
+ async def reduce( # type: ignore[misc]
354
+ function: Callable[[T, T], Awaitable[T]] | Callable[[T, S], Awaitable[T]],
355
+ iterable: Iterable[T] | Iterable[S] | AsyncIterable[T] | AsyncIterable[S],
356
+ /,
357
+ initial: T | _InitialMissingType = initial_missing,
358
+ ) -> T:
359
+ """
360
+ Asynchronous version of :func:`functools.reduce`.
361
+
362
+ :param function: a coroutine function that takes two arguments: the accumulated
363
+ value and the next element from the iterable
364
+ :param iterable: an iterable or async iterable
365
+ :param initial: the initial value (if missing, the first element of the iterable is
366
+ used as the initial value)
367
+
368
+ """
369
+ element: Any
370
+ function_called = False
371
+ if isinstance(iterable, AsyncIterable):
372
+ async_it = iterable.__aiter__()
373
+ if initial is initial_missing:
374
+ try:
375
+ value = cast(T, await async_it.__anext__())
376
+ except StopAsyncIteration:
377
+ raise TypeError(
378
+ "reduce() of empty sequence with no initial value"
379
+ ) from None
380
+ else:
381
+ value = cast(T, initial)
382
+
383
+ async for element in async_it:
384
+ value = await function(value, element)
385
+ function_called = True
386
+ elif isinstance(iterable, Iterable):
387
+ it = iter(iterable)
388
+ if initial is initial_missing:
389
+ try:
390
+ value = cast(T, next(it))
391
+ except StopIteration:
392
+ raise TypeError(
393
+ "reduce() of empty sequence with no initial value"
394
+ ) from None
395
+ else:
396
+ value = cast(T, initial)
397
+
398
+ for element in it:
399
+ value = await function(value, element)
400
+ function_called = True
401
+ else:
402
+ raise TypeError("reduce() argument 2 must be an iterable or async iterable")
403
+
404
+ # Make sure there is at least one checkpoint, even if an empty iterable and an
405
+ # initial value were given
406
+ if not function_called:
407
+ await checkpoint()
408
+
409
+ return value
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/lowlevel.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "EventLoopToken",
5
+ "RunvarToken",
6
+ "RunVar",
7
+ "checkpoint",
8
+ "checkpoint_if_cancelled",
9
+ "cancel_shielded_checkpoint",
10
+ "current_token",
11
+ )
12
+
13
+ import enum
14
+ from dataclasses import dataclass
15
+ from types import TracebackType
16
+ from typing import Any, Generic, Literal, TypeVar, final, overload
17
+ from weakref import WeakKeyDictionary
18
+
19
+ from ._core._eventloop import get_async_backend
20
+ from .abc import AsyncBackend
21
+
22
+ T = TypeVar("T")
23
+ D = TypeVar("D")
24
+
25
+
26
+ async def checkpoint() -> None:
27
+ """
28
+ Check for cancellation and allow the scheduler to switch to another task.
29
+
30
+ Equivalent to (but more efficient than)::
31
+
32
+ await checkpoint_if_cancelled()
33
+ await cancel_shielded_checkpoint()
34
+
35
+ .. versionadded:: 3.0
36
+
37
+ """
38
+ await get_async_backend().checkpoint()
39
+
40
+
41
+ async def checkpoint_if_cancelled() -> None:
42
+ """
43
+ Enter a checkpoint if the enclosing cancel scope has been cancelled.
44
+
45
+ This does not allow the scheduler to switch to a different task.
46
+
47
+ .. versionadded:: 3.0
48
+
49
+ """
50
+ await get_async_backend().checkpoint_if_cancelled()
51
+
52
+
53
+ async def cancel_shielded_checkpoint() -> None:
54
+ """
55
+ Allow the scheduler to switch to another task but without checking for cancellation.
56
+
57
+ Equivalent to (but potentially more efficient than)::
58
+
59
+ with CancelScope(shield=True):
60
+ await checkpoint()
61
+
62
+ .. versionadded:: 3.0
63
+
64
+ """
65
+ await get_async_backend().cancel_shielded_checkpoint()
66
+
67
+
68
+ @final
69
+ @dataclass(frozen=True, repr=False)
70
+ class EventLoopToken:
71
+ """
72
+ An opaque object that holds a reference to an event loop.
73
+
74
+ .. versionadded:: 4.11.0
75
+ """
76
+
77
+ backend_class: type[AsyncBackend]
78
+ native_token: object
79
+
80
+
81
+ def current_token() -> EventLoopToken:
82
+ """
83
+ Return a token object that can be used to call code in the current event loop from
84
+ another thread.
85
+
86
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
87
+ current thread
88
+
89
+ .. versionadded:: 4.11.0
90
+
91
+ """
92
+ backend_class = get_async_backend()
93
+ raw_token = backend_class.current_token()
94
+ return EventLoopToken(backend_class, raw_token)
95
+
96
+
97
+ _run_vars: WeakKeyDictionary[object, dict[RunVar[Any], Any]] = WeakKeyDictionary()
98
+
99
+
100
+ class _NoValueSet(enum.Enum):
101
+ NO_VALUE_SET = enum.auto()
102
+
103
+
104
+ class RunvarToken(Generic[T]):
105
+ __slots__ = "_var", "_value", "_redeemed"
106
+
107
+ def __init__(self, var: RunVar[T], value: T | Literal[_NoValueSet.NO_VALUE_SET]):
108
+ self._var = var
109
+ self._value: T | Literal[_NoValueSet.NO_VALUE_SET] = value
110
+ self._redeemed = False
111
+
112
+ def __enter__(self) -> RunvarToken[T]:
113
+ return self
114
+
115
+ def __exit__(
116
+ self,
117
+ exc_type: type[BaseException] | None,
118
+ exc_val: BaseException | None,
119
+ exc_tb: TracebackType | None,
120
+ ) -> None:
121
+ self._var.reset(self)
122
+
123
+
124
+ class RunVar(Generic[T]):
125
+ """
126
+ Like a :class:`~contextvars.ContextVar`, except scoped to the running event loop.
127
+
128
+ Can be used as a context manager, Just like :class:`~contextvars.ContextVar`, that
129
+ will reset the variable to its previous value when the context block is exited.
130
+ """
131
+
132
+ __slots__ = "_name", "_default"
133
+
134
+ NO_VALUE_SET: Literal[_NoValueSet.NO_VALUE_SET] = _NoValueSet.NO_VALUE_SET
135
+
136
+ def __init__(
137
+ self, name: str, default: T | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET
138
+ ):
139
+ self._name = name
140
+ self._default = default
141
+
142
+ @property
143
+ def _current_vars(self) -> dict[RunVar[T], T]:
144
+ native_token = current_token().native_token
145
+ try:
146
+ return _run_vars[native_token]
147
+ except KeyError:
148
+ run_vars = _run_vars[native_token] = {}
149
+ return run_vars
150
+
151
+ @overload
152
+ def get(self, default: D) -> T | D: ...
153
+
154
+ @overload
155
+ def get(self) -> T: ...
156
+
157
+ def get(
158
+ self, default: D | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET
159
+ ) -> T | D:
160
+ try:
161
+ return self._current_vars[self]
162
+ except KeyError:
163
+ if default is not RunVar.NO_VALUE_SET:
164
+ return default
165
+ elif self._default is not RunVar.NO_VALUE_SET:
166
+ return self._default
167
+
168
+ raise LookupError(
169
+ f'Run variable "{self._name}" has no value and no default set'
170
+ )
171
+
172
+ def set(self, value: T) -> RunvarToken[T]:
173
+ current_vars = self._current_vars
174
+ token = RunvarToken(self, current_vars.get(self, RunVar.NO_VALUE_SET))
175
+ current_vars[self] = value
176
+ return token
177
+
178
+ def reset(self, token: RunvarToken[T]) -> None:
179
+ if token._var is not self:
180
+ raise ValueError("This token does not belong to this RunVar")
181
+
182
+ if token._redeemed:
183
+ raise ValueError("This token has already been used")
184
+
185
+ if token._value is _NoValueSet.NO_VALUE_SET:
186
+ try:
187
+ del self._current_vars[self]
188
+ except KeyError:
189
+ pass
190
+ else:
191
+ self._current_vars[self] = token._value
192
+
193
+ token._redeemed = True
194
+
195
+ def __repr__(self) -> str:
196
+ return f"<RunVar name={self._name!r}>"
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/py.typed ADDED
File without changes
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/pytest_plugin.py ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ import socket
5
+ import sys
6
+ from collections.abc import Callable, Generator, Iterator
7
+ from contextlib import ExitStack, contextmanager
8
+ from inspect import isasyncgenfunction, iscoroutinefunction, ismethod
9
+ from typing import Any, cast
10
+
11
+ import pytest
12
+ from _pytest.fixtures import FuncFixtureInfo, SubRequest
13
+ from _pytest.outcomes import Exit
14
+ from _pytest.python import CallSpec2
15
+ from _pytest.scope import Scope
16
+
17
+ from . import get_available_backends
18
+ from ._core._eventloop import (
19
+ current_async_library,
20
+ get_async_backend,
21
+ reset_current_async_library,
22
+ set_current_async_library,
23
+ )
24
+ from ._core._exceptions import iterate_exceptions
25
+ from .abc import TestRunner
26
+
27
+ if sys.version_info < (3, 11):
28
+ from exceptiongroup import ExceptionGroup
29
+
30
+ _current_runner: TestRunner | None = None
31
+ _runner_stack: ExitStack | None = None
32
+ _runner_leases = 0
33
+
34
+
35
+ def extract_backend_and_options(backend: object) -> tuple[str, dict[str, Any]]:
36
+ if isinstance(backend, str):
37
+ return backend, {}
38
+ elif isinstance(backend, tuple) and len(backend) == 2:
39
+ if isinstance(backend[0], str) and isinstance(backend[1], dict):
40
+ return cast(tuple[str, dict[str, Any]], backend)
41
+
42
+ raise TypeError("anyio_backend must be either a string or tuple of (string, dict)")
43
+
44
+
45
+ @contextmanager
46
+ def get_runner(
47
+ backend_name: str, backend_options: dict[str, Any]
48
+ ) -> Iterator[TestRunner]:
49
+ global _current_runner, _runner_leases, _runner_stack
50
+ if _current_runner is None:
51
+ asynclib = get_async_backend(backend_name)
52
+ _runner_stack = ExitStack()
53
+ if current_async_library() is None:
54
+ # Since we're in control of the event loop, we can cache the name of the
55
+ # async library
56
+ token = set_current_async_library(backend_name)
57
+ _runner_stack.callback(reset_current_async_library, token)
58
+
59
+ backend_options = backend_options or {}
60
+ _current_runner = _runner_stack.enter_context(
61
+ asynclib.create_test_runner(backend_options)
62
+ )
63
+
64
+ _runner_leases += 1
65
+ try:
66
+ yield _current_runner
67
+ finally:
68
+ _runner_leases -= 1
69
+ if not _runner_leases:
70
+ assert _runner_stack is not None
71
+ _runner_stack.close()
72
+ _runner_stack = _current_runner = None
73
+
74
+
75
+ def pytest_addoption(parser: pytest.Parser) -> None:
76
+ parser.addini(
77
+ "anyio_mode",
78
+ default="strict",
79
+ help='AnyIO plugin mode (either "strict" or "auto")',
80
+ )
81
+
82
+
83
+ def pytest_configure(config: pytest.Config) -> None:
84
+ config.addinivalue_line(
85
+ "markers",
86
+ "anyio: mark the (coroutine function) test to be run asynchronously via anyio.",
87
+ )
88
+ if (
89
+ config.getini("anyio_mode") == "auto"
90
+ and config.pluginmanager.has_plugin("asyncio")
91
+ and config.getini("asyncio_mode") == "auto"
92
+ ):
93
+ config.issue_config_time_warning(
94
+ pytest.PytestConfigWarning(
95
+ "AnyIO auto mode has been enabled together with pytest-asyncio auto "
96
+ "mode. This may cause unexpected behavior."
97
+ ),
98
+ 1,
99
+ )
100
+
101
+
102
+ @pytest.hookimpl(hookwrapper=True)
103
+ def pytest_fixture_setup(fixturedef: Any, request: Any) -> Generator[Any]:
104
+ def wrapper(anyio_backend: Any, request: SubRequest, **kwargs: Any) -> Any:
105
+ # Rebind any fixture methods to the request instance
106
+ if (
107
+ request.instance
108
+ and ismethod(func)
109
+ and type(func.__self__) is type(request.instance)
110
+ ):
111
+ local_func = func.__func__.__get__(request.instance)
112
+ else:
113
+ local_func = func
114
+
115
+ backend_name, backend_options = extract_backend_and_options(anyio_backend)
116
+ if has_backend_arg:
117
+ kwargs["anyio_backend"] = anyio_backend
118
+
119
+ if has_request_arg:
120
+ kwargs["request"] = request
121
+
122
+ with get_runner(backend_name, backend_options) as runner:
123
+ if isasyncgenfunction(local_func):
124
+ yield from runner.run_asyncgen_fixture(local_func, kwargs)
125
+ else:
126
+ yield runner.run_fixture(local_func, kwargs)
127
+
128
+ # Only apply this to coroutine functions and async generator functions in requests
129
+ # that involve the anyio_backend fixture
130
+ func = fixturedef.func
131
+ if isasyncgenfunction(func) or iscoroutinefunction(func):
132
+ if "anyio_backend" in request.fixturenames:
133
+ fixturedef.func = wrapper
134
+ original_argname = fixturedef.argnames
135
+
136
+ if not (has_backend_arg := "anyio_backend" in fixturedef.argnames):
137
+ fixturedef.argnames += ("anyio_backend",)
138
+
139
+ if not (has_request_arg := "request" in fixturedef.argnames):
140
+ fixturedef.argnames += ("request",)
141
+
142
+ try:
143
+ return (yield)
144
+ finally:
145
+ fixturedef.func = func
146
+ fixturedef.argnames = original_argname
147
+
148
+ return (yield)
149
+
150
+
151
+ @pytest.hookimpl(tryfirst=True)
152
+ def pytest_pycollect_makeitem(
153
+ collector: pytest.Module | pytest.Class, name: str, obj: object
154
+ ) -> None:
155
+ if collector.istestfunction(obj, name):
156
+ inner_func = obj.hypothesis.inner_test if hasattr(obj, "hypothesis") else obj
157
+ if iscoroutinefunction(inner_func):
158
+ anyio_auto_mode = collector.config.getini("anyio_mode") == "auto"
159
+ marker = collector.get_closest_marker("anyio")
160
+ own_markers = getattr(obj, "pytestmark", ())
161
+ if (
162
+ anyio_auto_mode
163
+ or marker
164
+ or any(marker.name == "anyio" for marker in own_markers)
165
+ ):
166
+ pytest.mark.usefixtures("anyio_backend")(obj)
167
+
168
+
169
+ def pytest_collection_finish(session: pytest.Session) -> None:
170
+ for i, item in reversed(list(enumerate(session.items))):
171
+ if (
172
+ isinstance(item, pytest.Function)
173
+ and iscoroutinefunction(item.function)
174
+ and item.get_closest_marker("anyio") is not None
175
+ and "anyio_backend" not in item.fixturenames
176
+ ):
177
+ new_items = []
178
+ try:
179
+ cs_fields = {f.name for f in dataclasses.fields(CallSpec2)}
180
+ except TypeError:
181
+ cs_fields = set()
182
+
183
+ for param_index, backend in enumerate(get_available_backends()):
184
+ if "_arg2scope" in cs_fields: # pytest >= 8
185
+ callspec = CallSpec2(
186
+ params={"anyio_backend": backend},
187
+ indices={"anyio_backend": param_index},
188
+ _arg2scope={"anyio_backend": Scope.Module},
189
+ _idlist=[backend],
190
+ marks=[],
191
+ )
192
+ else: # pytest 7.x
193
+ callspec = CallSpec2( # type: ignore[call-arg]
194
+ funcargs={},
195
+ params={"anyio_backend": backend},
196
+ indices={"anyio_backend": param_index},
197
+ arg2scope={"anyio_backend": Scope.Module},
198
+ idlist=[backend],
199
+ marks=[],
200
+ )
201
+
202
+ fi = item._fixtureinfo
203
+ new_names_closure = list(fi.names_closure)
204
+ if "anyio_backend" not in new_names_closure:
205
+ new_names_closure.append("anyio_backend")
206
+
207
+ new_fixtureinfo = FuncFixtureInfo(
208
+ argnames=fi.argnames,
209
+ initialnames=fi.initialnames,
210
+ names_closure=new_names_closure,
211
+ name2fixturedefs=fi.name2fixturedefs,
212
+ )
213
+ new_item = pytest.Function.from_parent(
214
+ item.parent,
215
+ name=f"{item.originalname}[{backend}]",
216
+ callspec=callspec,
217
+ callobj=item.obj,
218
+ fixtureinfo=new_fixtureinfo,
219
+ keywords=item.keywords,
220
+ originalname=item.originalname,
221
+ )
222
+ new_items.append(new_item)
223
+
224
+ session.items[i : i + 1] = new_items
225
+
226
+
227
+ @pytest.hookimpl(tryfirst=True)
228
+ def pytest_pyfunc_call(pyfuncitem: Any) -> bool | None:
229
+ def run_with_hypothesis(**kwargs: Any) -> None:
230
+ with get_runner(backend_name, backend_options) as runner:
231
+ runner.run_test(original_func, kwargs)
232
+
233
+ backend = pyfuncitem.funcargs.get("anyio_backend")
234
+ if backend:
235
+ backend_name, backend_options = extract_backend_and_options(backend)
236
+
237
+ if hasattr(pyfuncitem.obj, "hypothesis"):
238
+ # Wrap the inner test function unless it's already wrapped
239
+ original_func = pyfuncitem.obj.hypothesis.inner_test
240
+ if original_func.__qualname__ != run_with_hypothesis.__qualname__:
241
+ if iscoroutinefunction(original_func):
242
+ pyfuncitem.obj.hypothesis.inner_test = run_with_hypothesis
243
+
244
+ return None
245
+
246
+ if iscoroutinefunction(pyfuncitem.obj):
247
+ funcargs = pyfuncitem.funcargs
248
+ testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames}
249
+ with get_runner(backend_name, backend_options) as runner:
250
+ try:
251
+ runner.run_test(pyfuncitem.obj, testargs)
252
+ except ExceptionGroup as excgrp:
253
+ for exc in iterate_exceptions(excgrp):
254
+ if isinstance(exc, (Exit, KeyboardInterrupt, SystemExit)):
255
+ raise exc from excgrp
256
+
257
+ raise
258
+
259
+ return True
260
+
261
+ return None
262
+
263
+
264
+ @pytest.fixture(scope="module", params=get_available_backends())
265
+ def anyio_backend(request: Any) -> Any:
266
+ return request.param
267
+
268
+
269
+ @pytest.fixture
270
+ def anyio_backend_name(anyio_backend: Any) -> str:
271
+ if isinstance(anyio_backend, str):
272
+ return anyio_backend
273
+ else:
274
+ return anyio_backend[0]
275
+
276
+
277
+ @pytest.fixture
278
+ def anyio_backend_options(anyio_backend: Any) -> dict[str, Any]:
279
+ if isinstance(anyio_backend, str):
280
+ return {}
281
+ else:
282
+ return anyio_backend[1]
283
+
284
+
285
+ class FreePortFactory:
286
+ """
287
+ Manages port generation based on specified socket kind, ensuring no duplicate
288
+ ports are generated.
289
+
290
+ This class provides functionality for generating available free ports on the
291
+ system. It is initialized with a specific socket kind and can generate ports
292
+ for given address families while avoiding reuse of previously generated ports.
293
+
294
+ Users should not instantiate this class directly, but use the
295
+ ``free_tcp_port_factory`` and ``free_udp_port_factory`` fixtures instead. For simple
296
+ uses cases, ``free_tcp_port`` and ``free_udp_port`` can be used instead.
297
+ """
298
+
299
+ def __init__(self, kind: socket.SocketKind) -> None:
300
+ self._kind = kind
301
+ self._generated = set[int]()
302
+
303
+ @property
304
+ def kind(self) -> socket.SocketKind:
305
+ """
306
+ The type of socket connection (e.g., :data:`~socket.SOCK_STREAM` or
307
+ :data:`~socket.SOCK_DGRAM`) used to bind for checking port availability
308
+
309
+ """
310
+ return self._kind
311
+
312
+ def __call__(self, family: socket.AddressFamily | None = None) -> int:
313
+ """
314
+ Return an unbound port for the given address family.
315
+
316
+ :param family: if omitted, both IPv4 and IPv6 addresses will be tried
317
+ :return: a port number
318
+
319
+ """
320
+ if family is not None:
321
+ families = [family]
322
+ else:
323
+ families = [socket.AF_INET]
324
+ if socket.has_ipv6:
325
+ families.append(socket.AF_INET6)
326
+
327
+ while True:
328
+ port = 0
329
+ with ExitStack() as stack:
330
+ for family in families:
331
+ sock = stack.enter_context(socket.socket(family, self._kind))
332
+ addr = "::1" if family == socket.AF_INET6 else "127.0.0.1"
333
+ try:
334
+ sock.bind((addr, port))
335
+ except OSError:
336
+ break
337
+
338
+ if not port:
339
+ port = sock.getsockname()[1]
340
+ else:
341
+ if port not in self._generated:
342
+ self._generated.add(port)
343
+ return port
344
+
345
+
346
+ @pytest.fixture(scope="session")
347
+ def free_tcp_port_factory() -> FreePortFactory:
348
+ return FreePortFactory(socket.SOCK_STREAM)
349
+
350
+
351
+ @pytest.fixture(scope="session")
352
+ def free_udp_port_factory() -> FreePortFactory:
353
+ return FreePortFactory(socket.SOCK_DGRAM)
354
+
355
+
356
+ @pytest.fixture
357
+ def free_tcp_port(free_tcp_port_factory: Callable[[], int]) -> int:
358
+ return free_tcp_port_factory()
359
+
360
+
361
+ @pytest.fixture
362
+ def free_udp_port(free_udp_port_factory: Callable[[], int]) -> int:
363
+ return free_udp_port_factory()
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/__init__.py ADDED
File without changes
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/buffered.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "BufferedByteReceiveStream",
5
+ "BufferedByteStream",
6
+ "BufferedConnectable",
7
+ )
8
+
9
+ import sys
10
+ from collections.abc import Callable, Iterable, Mapping
11
+ from dataclasses import dataclass, field
12
+ from typing import Any, SupportsIndex
13
+
14
+ from .. import ClosedResourceError, DelimiterNotFound, EndOfStream, IncompleteRead
15
+ from ..abc import (
16
+ AnyByteReceiveStream,
17
+ AnyByteStream,
18
+ AnyByteStreamConnectable,
19
+ ByteReceiveStream,
20
+ ByteStream,
21
+ ByteStreamConnectable,
22
+ )
23
+
24
+ if sys.version_info >= (3, 12):
25
+ from typing import override
26
+ else:
27
+ from typing_extensions import override
28
+
29
+
30
+ @dataclass(eq=False)
31
+ class BufferedByteReceiveStream(ByteReceiveStream):
32
+ """
33
+ Wraps any bytes-based receive stream and uses a buffer to provide sophisticated
34
+ receiving capabilities in the form of a byte stream.
35
+ """
36
+
37
+ receive_stream: AnyByteReceiveStream
38
+ _buffer: bytearray = field(init=False, default_factory=bytearray)
39
+ _closed: bool = field(init=False, default=False)
40
+
41
+ async def aclose(self) -> None:
42
+ await self.receive_stream.aclose()
43
+ self._closed = True
44
+
45
+ @property
46
+ def buffer(self) -> bytes:
47
+ """The bytes currently in the buffer."""
48
+ return bytes(self._buffer)
49
+
50
+ @property
51
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
52
+ return self.receive_stream.extra_attributes
53
+
54
+ def feed_data(self, data: Iterable[SupportsIndex], /) -> None:
55
+ """
56
+ Append data directly into the buffer.
57
+
58
+ Any data in the buffer will be consumed by receive operations before receiving
59
+ anything from the wrapped stream.
60
+
61
+ :param data: the data to append to the buffer (can be bytes or anything else
62
+ that supports ``__index__()``)
63
+
64
+ """
65
+ self._buffer.extend(data)
66
+
67
+ async def receive(self, max_bytes: int = 65536) -> bytes:
68
+ if self._closed:
69
+ raise ClosedResourceError
70
+
71
+ if self._buffer:
72
+ chunk = bytes(self._buffer[:max_bytes])
73
+ del self._buffer[:max_bytes]
74
+ return chunk
75
+ elif isinstance(self.receive_stream, ByteReceiveStream):
76
+ return await self.receive_stream.receive(max_bytes)
77
+ else:
78
+ # With a bytes-oriented object stream, we need to handle any surplus bytes
79
+ # we get from the receive() call
80
+ chunk = await self.receive_stream.receive()
81
+ if len(chunk) > max_bytes:
82
+ # Save the surplus bytes in the buffer
83
+ self._buffer.extend(chunk[max_bytes:])
84
+ return chunk[:max_bytes]
85
+ else:
86
+ return chunk
87
+
88
+ async def receive_exactly(self, nbytes: int) -> bytes:
89
+ """
90
+ Read exactly the given amount of bytes from the stream.
91
+
92
+ :param nbytes: the number of bytes to read
93
+ :return: the bytes read
94
+ :raises ~anyio.IncompleteRead: if the stream was closed before the requested
95
+ amount of bytes could be read from the stream
96
+
97
+ """
98
+ while True:
99
+ remaining = nbytes - len(self._buffer)
100
+ if remaining <= 0:
101
+ retval = self._buffer[:nbytes]
102
+ del self._buffer[:nbytes]
103
+ return bytes(retval)
104
+
105
+ try:
106
+ if isinstance(self.receive_stream, ByteReceiveStream):
107
+ chunk = await self.receive_stream.receive(remaining)
108
+ else:
109
+ chunk = await self.receive_stream.receive()
110
+ except EndOfStream as exc:
111
+ raise IncompleteRead from exc
112
+
113
+ self._buffer.extend(chunk)
114
+
115
+ async def receive_until(self, delimiter: bytes, max_bytes: int) -> bytes:
116
+ """
117
+ Read from the stream until the delimiter is found or max_bytes have been read.
118
+
119
+ :param delimiter: the marker to look for in the stream
120
+ :param max_bytes: maximum number of bytes that will be read before raising
121
+ :exc:`~anyio.DelimiterNotFound`
122
+ :return: the bytes read (not including the delimiter)
123
+ :raises ~anyio.IncompleteRead: if the stream was closed before the delimiter
124
+ was found
125
+ :raises ~anyio.DelimiterNotFound: if the delimiter is not found within the
126
+ bytes read up to the maximum allowed
127
+
128
+ """
129
+ delimiter_size = len(delimiter)
130
+ offset = 0
131
+ while True:
132
+ # Check if the delimiter can be found in the current buffer
133
+ index = self._buffer.find(delimiter, offset)
134
+ if index >= 0:
135
+ found = self._buffer[:index]
136
+ del self._buffer[: index + len(delimiter) :]
137
+ return bytes(found)
138
+
139
+ # Check if the buffer is already at or over the limit
140
+ if len(self._buffer) >= max_bytes:
141
+ raise DelimiterNotFound(max_bytes)
142
+
143
+ # Read more data into the buffer from the socket
144
+ try:
145
+ data = await self.receive_stream.receive()
146
+ except EndOfStream as exc:
147
+ raise IncompleteRead from exc
148
+
149
+ # Move the offset forward and add the new data to the buffer
150
+ offset = max(len(self._buffer) - delimiter_size + 1, 0)
151
+ self._buffer.extend(data)
152
+
153
+
154
+ class BufferedByteStream(BufferedByteReceiveStream, ByteStream):
155
+ """
156
+ A full-duplex variant of :class:`BufferedByteReceiveStream`. All writes are passed
157
+ through to the wrapped stream as-is.
158
+ """
159
+
160
+ def __init__(self, stream: AnyByteStream):
161
+ """
162
+ :param stream: the stream to be wrapped
163
+
164
+ """
165
+ super().__init__(stream)
166
+ self._stream = stream
167
+
168
+ @override
169
+ async def send_eof(self) -> None:
170
+ await self._stream.send_eof()
171
+
172
+ @override
173
+ async def send(self, item: bytes) -> None:
174
+ await self._stream.send(item)
175
+
176
+
177
+ class BufferedConnectable(ByteStreamConnectable):
178
+ def __init__(self, connectable: AnyByteStreamConnectable):
179
+ """
180
+ :param connectable: the connectable to wrap
181
+
182
+ """
183
+ self.connectable = connectable
184
+
185
+ @override
186
+ async def connect(self) -> BufferedByteStream:
187
+ stream = await self.connectable.connect()
188
+ return BufferedByteStream(stream)
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/file.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "FileReadStream",
5
+ "FileStreamAttribute",
6
+ "FileWriteStream",
7
+ )
8
+
9
+ from collections.abc import Callable, Mapping
10
+ from io import SEEK_SET, UnsupportedOperation
11
+ from os import PathLike
12
+ from pathlib import Path
13
+ from typing import IO, Any
14
+
15
+ from .. import (
16
+ BrokenResourceError,
17
+ ClosedResourceError,
18
+ EndOfStream,
19
+ TypedAttributeSet,
20
+ to_thread,
21
+ typed_attribute,
22
+ )
23
+ from ..abc import ByteReceiveStream, ByteSendStream
24
+
25
+
26
+ class FileStreamAttribute(TypedAttributeSet):
27
+ #: the open file descriptor
28
+ file: IO[bytes] = typed_attribute()
29
+ #: the path of the file on the file system, if available (file must be a real file)
30
+ path: Path = typed_attribute()
31
+ #: the file number, if available (file must be a real file or a TTY)
32
+ fileno: int = typed_attribute()
33
+
34
+
35
+ class _BaseFileStream:
36
+ def __init__(self, file: IO[bytes]):
37
+ self._file = file
38
+
39
+ async def aclose(self) -> None:
40
+ await to_thread.run_sync(self._file.close)
41
+
42
+ @property
43
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
44
+ attributes: dict[Any, Callable[[], Any]] = {
45
+ FileStreamAttribute.file: lambda: self._file,
46
+ }
47
+
48
+ if hasattr(self._file, "name"):
49
+ attributes[FileStreamAttribute.path] = lambda: Path(self._file.name)
50
+
51
+ try:
52
+ self._file.fileno()
53
+ except UnsupportedOperation:
54
+ pass
55
+ else:
56
+ attributes[FileStreamAttribute.fileno] = lambda: self._file.fileno()
57
+
58
+ return attributes
59
+
60
+
61
+ class FileReadStream(_BaseFileStream, ByteReceiveStream):
62
+ """
63
+ A byte stream that reads from a file in the file system.
64
+
65
+ :param file: a file that has been opened for reading in binary mode
66
+
67
+ .. versionadded:: 3.0
68
+ """
69
+
70
+ @classmethod
71
+ async def from_path(cls, path: str | PathLike[str]) -> FileReadStream:
72
+ """
73
+ Create a file read stream by opening the given file.
74
+
75
+ :param path: path of the file to read from
76
+
77
+ """
78
+ file = await to_thread.run_sync(Path(path).open, "rb")
79
+ return cls(file)
80
+
81
+ async def receive(self, max_bytes: int = 65536) -> bytes:
82
+ try:
83
+ data = await to_thread.run_sync(self._file.read, max_bytes)
84
+ except ValueError:
85
+ raise ClosedResourceError from None
86
+ except OSError as exc:
87
+ raise BrokenResourceError from exc
88
+
89
+ if data:
90
+ return data
91
+ else:
92
+ raise EndOfStream
93
+
94
+ async def seek(self, position: int, whence: int = SEEK_SET) -> int:
95
+ """
96
+ Seek the file to the given position.
97
+
98
+ .. seealso:: :meth:`io.IOBase.seek`
99
+
100
+ .. note:: Not all file descriptors are seekable.
101
+
102
+ :param position: position to seek the file to
103
+ :param whence: controls how ``position`` is interpreted
104
+ :return: the new absolute position
105
+ :raises OSError: if the file is not seekable
106
+
107
+ """
108
+ return await to_thread.run_sync(self._file.seek, position, whence)
109
+
110
+ async def tell(self) -> int:
111
+ """
112
+ Return the current stream position.
113
+
114
+ .. note:: Not all file descriptors are seekable.
115
+
116
+ :return: the current absolute position
117
+ :raises OSError: if the file is not seekable
118
+
119
+ """
120
+ return await to_thread.run_sync(self._file.tell)
121
+
122
+
123
+ class FileWriteStream(_BaseFileStream, ByteSendStream):
124
+ """
125
+ A byte stream that writes to a file in the file system.
126
+
127
+ :param file: a file that has been opened for writing in binary mode
128
+
129
+ .. versionadded:: 3.0
130
+ """
131
+
132
+ @classmethod
133
+ async def from_path(
134
+ cls, path: str | PathLike[str], append: bool = False
135
+ ) -> FileWriteStream:
136
+ """
137
+ Create a file write stream by opening the given file for writing.
138
+
139
+ :param path: path of the file to write to
140
+ :param append: if ``True``, open the file for appending; if ``False``, any
141
+ existing file at the given path will be truncated
142
+
143
+ """
144
+ mode = "ab" if append else "wb"
145
+ file = await to_thread.run_sync(Path(path).open, mode)
146
+ return cls(file)
147
+
148
+ async def send(self, item: bytes) -> None:
149
+ try:
150
+ await to_thread.run_sync(self._file.write, item)
151
+ except ValueError:
152
+ raise ClosedResourceError from None
153
+ except OSError as exc:
154
+ raise BrokenResourceError from exc
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/memory.py ADDED
@@ -0,0 +1,325 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "MemoryObjectReceiveStream",
5
+ "MemoryObjectSendStream",
6
+ "MemoryObjectStreamStatistics",
7
+ )
8
+
9
+ import warnings
10
+ from collections import OrderedDict, deque
11
+ from dataclasses import dataclass, field
12
+ from types import TracebackType
13
+ from typing import Generic, NamedTuple, TypeVar
14
+
15
+ from .. import (
16
+ BrokenResourceError,
17
+ ClosedResourceError,
18
+ EndOfStream,
19
+ WouldBlock,
20
+ )
21
+ from .._core._testing import TaskInfo, get_current_task
22
+ from ..abc import Event, ObjectReceiveStream, ObjectSendStream
23
+ from ..lowlevel import checkpoint
24
+
25
+ T_Item = TypeVar("T_Item")
26
+ T_co = TypeVar("T_co", covariant=True)
27
+ T_contra = TypeVar("T_contra", contravariant=True)
28
+
29
+
30
+ class MemoryObjectStreamStatistics(NamedTuple):
31
+ current_buffer_used: int #: number of items stored in the buffer
32
+ #: maximum number of items that can be stored on this stream (or :data:`math.inf`)
33
+ max_buffer_size: float
34
+ open_send_streams: int #: number of unclosed clones of the send stream
35
+ open_receive_streams: int #: number of unclosed clones of the receive stream
36
+ #: number of tasks blocked on :meth:`MemoryObjectSendStream.send`
37
+ tasks_waiting_send: int
38
+ #: number of tasks blocked on :meth:`MemoryObjectReceiveStream.receive`
39
+ tasks_waiting_receive: int
40
+
41
+
42
+ @dataclass(eq=False)
43
+ class _MemoryObjectItemReceiver(Generic[T_Item]):
44
+ task_info: TaskInfo = field(init=False, default_factory=get_current_task)
45
+ item: T_Item = field(init=False)
46
+
47
+ def __repr__(self) -> str:
48
+ # When item is not defined, we get following error with default __repr__:
49
+ # AttributeError: 'MemoryObjectItemReceiver' object has no attribute 'item'
50
+ item = getattr(self, "item", None)
51
+ return f"{self.__class__.__name__}(task_info={self.task_info}, item={item!r})"
52
+
53
+
54
+ @dataclass(eq=False)
55
+ class _MemoryObjectStreamState(Generic[T_Item]):
56
+ max_buffer_size: float = field()
57
+ buffer: deque[T_Item] = field(init=False, default_factory=deque)
58
+ open_send_channels: int = field(init=False, default=0)
59
+ open_receive_channels: int = field(init=False, default=0)
60
+ waiting_receivers: OrderedDict[Event, _MemoryObjectItemReceiver[T_Item]] = field(
61
+ init=False, default_factory=OrderedDict
62
+ )
63
+ waiting_senders: OrderedDict[Event, T_Item] = field(
64
+ init=False, default_factory=OrderedDict
65
+ )
66
+
67
+ def statistics(self) -> MemoryObjectStreamStatistics:
68
+ return MemoryObjectStreamStatistics(
69
+ len(self.buffer),
70
+ self.max_buffer_size,
71
+ self.open_send_channels,
72
+ self.open_receive_channels,
73
+ len(self.waiting_senders),
74
+ len(self.waiting_receivers),
75
+ )
76
+
77
+
78
+ @dataclass(eq=False)
79
+ class MemoryObjectReceiveStream(Generic[T_co], ObjectReceiveStream[T_co]):
80
+ _state: _MemoryObjectStreamState[T_co]
81
+ _closed: bool = field(init=False, default=False)
82
+
83
+ def __post_init__(self) -> None:
84
+ self._state.open_receive_channels += 1
85
+
86
+ def receive_nowait(self) -> T_co:
87
+ """
88
+ Receive the next item if it can be done without waiting.
89
+
90
+ :return: the received item
91
+ :raises ~anyio.ClosedResourceError: if this send stream has been closed
92
+ :raises ~anyio.EndOfStream: if the buffer is empty and this stream has been
93
+ closed from the sending end
94
+ :raises ~anyio.WouldBlock: if there are no items in the buffer and no tasks
95
+ waiting to send
96
+
97
+ """
98
+ if self._closed:
99
+ raise ClosedResourceError
100
+
101
+ if self._state.waiting_senders:
102
+ # Get the item from the next sender
103
+ send_event, item = self._state.waiting_senders.popitem(last=False)
104
+ self._state.buffer.append(item)
105
+ send_event.set()
106
+
107
+ if self._state.buffer:
108
+ return self._state.buffer.popleft()
109
+ elif not self._state.open_send_channels:
110
+ raise EndOfStream
111
+
112
+ raise WouldBlock
113
+
114
+ async def receive(self) -> T_co:
115
+ await checkpoint()
116
+ try:
117
+ return self.receive_nowait()
118
+ except WouldBlock:
119
+ # Add ourselves in the queue
120
+ receive_event = Event()
121
+ receiver = _MemoryObjectItemReceiver[T_co]()
122
+ self._state.waiting_receivers[receive_event] = receiver
123
+
124
+ try:
125
+ await receive_event.wait()
126
+ finally:
127
+ self._state.waiting_receivers.pop(receive_event, None)
128
+
129
+ try:
130
+ return receiver.item
131
+ except AttributeError:
132
+ raise EndOfStream from None
133
+
134
+ def clone(self) -> MemoryObjectReceiveStream[T_co]:
135
+ """
136
+ Create a clone of this receive stream.
137
+
138
+ Each clone can be closed separately. Only when all clones have been closed will
139
+ the receiving end of the memory stream be considered closed by the sending ends.
140
+
141
+ :return: the cloned stream
142
+
143
+ """
144
+ if self._closed:
145
+ raise ClosedResourceError
146
+
147
+ return MemoryObjectReceiveStream(_state=self._state)
148
+
149
+ def close(self) -> None:
150
+ """
151
+ Close the stream.
152
+
153
+ This works the exact same way as :meth:`aclose`, but is provided as a special
154
+ case for the benefit of synchronous callbacks.
155
+
156
+ """
157
+ if not self._closed:
158
+ self._closed = True
159
+ self._state.open_receive_channels -= 1
160
+ if self._state.open_receive_channels == 0:
161
+ send_events = list(self._state.waiting_senders.keys())
162
+ for event in send_events:
163
+ event.set()
164
+
165
+ async def aclose(self) -> None:
166
+ self.close()
167
+
168
+ def statistics(self) -> MemoryObjectStreamStatistics:
169
+ """
170
+ Return statistics about the current state of this stream.
171
+
172
+ .. versionadded:: 3.0
173
+ """
174
+ return self._state.statistics()
175
+
176
+ def __enter__(self) -> MemoryObjectReceiveStream[T_co]:
177
+ return self
178
+
179
+ def __exit__(
180
+ self,
181
+ exc_type: type[BaseException] | None,
182
+ exc_val: BaseException | None,
183
+ exc_tb: TracebackType | None,
184
+ ) -> None:
185
+ self.close()
186
+
187
+ def __del__(self) -> None:
188
+ if not self._closed:
189
+ warnings.warn(
190
+ f"Unclosed <{self.__class__.__name__} at {id(self):x}>",
191
+ ResourceWarning,
192
+ stacklevel=1,
193
+ source=self,
194
+ )
195
+
196
+
197
+ @dataclass(eq=False)
198
+ class MemoryObjectSendStream(Generic[T_contra], ObjectSendStream[T_contra]):
199
+ _state: _MemoryObjectStreamState[T_contra]
200
+ _closed: bool = field(init=False, default=False)
201
+
202
+ def __post_init__(self) -> None:
203
+ self._state.open_send_channels += 1
204
+
205
+ def send_nowait(self, item: T_contra) -> None:
206
+ """
207
+ Send an item immediately if it can be done without waiting.
208
+
209
+ :param item: the item to send
210
+ :raises ~anyio.ClosedResourceError: if this send stream has been closed
211
+ :raises ~anyio.BrokenResourceError: if the stream has been closed from the
212
+ receiving end
213
+ :raises ~anyio.WouldBlock: if the buffer is full and there are no tasks waiting
214
+ to receive
215
+
216
+ """
217
+ if self._closed:
218
+ raise ClosedResourceError
219
+ if not self._state.open_receive_channels:
220
+ raise BrokenResourceError
221
+
222
+ while self._state.waiting_receivers:
223
+ receive_event, receiver = self._state.waiting_receivers.popitem(last=False)
224
+ if not receiver.task_info.has_pending_cancellation():
225
+ receiver.item = item
226
+ receive_event.set()
227
+ return
228
+
229
+ if len(self._state.buffer) < self._state.max_buffer_size:
230
+ self._state.buffer.append(item)
231
+ else:
232
+ raise WouldBlock
233
+
234
+ async def send(self, item: T_contra) -> None:
235
+ """
236
+ Send an item to the stream.
237
+
238
+ If the buffer is full, this method blocks until there is again room in the
239
+ buffer or the item can be sent directly to a receiver.
240
+
241
+ :param item: the item to send
242
+ :raises ~anyio.ClosedResourceError: if this send stream has been closed
243
+ :raises ~anyio.BrokenResourceError: if the stream has been closed from the
244
+ receiving end
245
+
246
+ """
247
+ await checkpoint()
248
+ try:
249
+ self.send_nowait(item)
250
+ except WouldBlock:
251
+ # Wait until there's someone on the receiving end
252
+ send_event = Event()
253
+ self._state.waiting_senders[send_event] = item
254
+ try:
255
+ await send_event.wait()
256
+ except BaseException:
257
+ self._state.waiting_senders.pop(send_event, None)
258
+ raise
259
+
260
+ if send_event in self._state.waiting_senders:
261
+ del self._state.waiting_senders[send_event]
262
+ raise BrokenResourceError from None
263
+
264
+ def clone(self) -> MemoryObjectSendStream[T_contra]:
265
+ """
266
+ Create a clone of this send stream.
267
+
268
+ Each clone can be closed separately. Only when all clones have been closed will
269
+ the sending end of the memory stream be considered closed by the receiving ends.
270
+
271
+ :return: the cloned stream
272
+
273
+ """
274
+ if self._closed:
275
+ raise ClosedResourceError
276
+
277
+ return MemoryObjectSendStream(_state=self._state)
278
+
279
+ def close(self) -> None:
280
+ """
281
+ Close the stream.
282
+
283
+ This works the exact same way as :meth:`aclose`, but is provided as a special
284
+ case for the benefit of synchronous callbacks.
285
+
286
+ """
287
+ if not self._closed:
288
+ self._closed = True
289
+ self._state.open_send_channels -= 1
290
+ if self._state.open_send_channels == 0:
291
+ receive_events = list(self._state.waiting_receivers.keys())
292
+ self._state.waiting_receivers.clear()
293
+ for event in receive_events:
294
+ event.set()
295
+
296
+ async def aclose(self) -> None:
297
+ self.close()
298
+
299
+ def statistics(self) -> MemoryObjectStreamStatistics:
300
+ """
301
+ Return statistics about the current state of this stream.
302
+
303
+ .. versionadded:: 3.0
304
+ """
305
+ return self._state.statistics()
306
+
307
+ def __enter__(self) -> MemoryObjectSendStream[T_contra]:
308
+ return self
309
+
310
+ def __exit__(
311
+ self,
312
+ exc_type: type[BaseException] | None,
313
+ exc_val: BaseException | None,
314
+ exc_tb: TracebackType | None,
315
+ ) -> None:
316
+ self.close()
317
+
318
+ def __del__(self) -> None:
319
+ if not self._closed:
320
+ warnings.warn(
321
+ f"Unclosed <{self.__class__.__name__} at {id(self):x}>",
322
+ ResourceWarning,
323
+ stacklevel=1,
324
+ source=self,
325
+ )
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/stapled.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "MultiListener",
5
+ "StapledByteStream",
6
+ "StapledObjectStream",
7
+ )
8
+
9
+ from collections.abc import Callable, Mapping, Sequence
10
+ from dataclasses import dataclass
11
+ from typing import Any, Generic, TypeVar
12
+
13
+ from ..abc import (
14
+ ByteReceiveStream,
15
+ ByteSendStream,
16
+ ByteStream,
17
+ Listener,
18
+ ObjectReceiveStream,
19
+ ObjectSendStream,
20
+ ObjectStream,
21
+ TaskGroup,
22
+ )
23
+
24
+ T_Item = TypeVar("T_Item")
25
+ T_Stream = TypeVar("T_Stream")
26
+
27
+
28
+ @dataclass(eq=False)
29
+ class StapledByteStream(ByteStream):
30
+ """
31
+ Combines two byte streams into a single, bidirectional byte stream.
32
+
33
+ Extra attributes will be provided from both streams, with the receive stream
34
+ providing the values in case of a conflict.
35
+
36
+ :param ByteSendStream send_stream: the sending byte stream
37
+ :param ByteReceiveStream receive_stream: the receiving byte stream
38
+ """
39
+
40
+ send_stream: ByteSendStream
41
+ receive_stream: ByteReceiveStream
42
+
43
+ async def receive(self, max_bytes: int = 65536) -> bytes:
44
+ return await self.receive_stream.receive(max_bytes)
45
+
46
+ async def send(self, item: bytes) -> None:
47
+ await self.send_stream.send(item)
48
+
49
+ async def send_eof(self) -> None:
50
+ await self.send_stream.aclose()
51
+
52
+ async def aclose(self) -> None:
53
+ await self.send_stream.aclose()
54
+ await self.receive_stream.aclose()
55
+
56
+ @property
57
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
58
+ return {
59
+ **self.send_stream.extra_attributes,
60
+ **self.receive_stream.extra_attributes,
61
+ }
62
+
63
+
64
+ @dataclass(eq=False)
65
+ class StapledObjectStream(Generic[T_Item], ObjectStream[T_Item]):
66
+ """
67
+ Combines two object streams into a single, bidirectional object stream.
68
+
69
+ Extra attributes will be provided from both streams, with the receive stream
70
+ providing the values in case of a conflict.
71
+
72
+ :param ObjectSendStream send_stream: the sending object stream
73
+ :param ObjectReceiveStream receive_stream: the receiving object stream
74
+ """
75
+
76
+ send_stream: ObjectSendStream[T_Item]
77
+ receive_stream: ObjectReceiveStream[T_Item]
78
+
79
+ async def receive(self) -> T_Item:
80
+ return await self.receive_stream.receive()
81
+
82
+ async def send(self, item: T_Item) -> None:
83
+ await self.send_stream.send(item)
84
+
85
+ async def send_eof(self) -> None:
86
+ await self.send_stream.aclose()
87
+
88
+ async def aclose(self) -> None:
89
+ await self.send_stream.aclose()
90
+ await self.receive_stream.aclose()
91
+
92
+ @property
93
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
94
+ return {
95
+ **self.send_stream.extra_attributes,
96
+ **self.receive_stream.extra_attributes,
97
+ }
98
+
99
+
100
+ @dataclass(eq=False)
101
+ class MultiListener(Generic[T_Stream], Listener[T_Stream]):
102
+ """
103
+ Combines multiple listeners into one, serving connections from all of them at once.
104
+
105
+ Any MultiListeners in the given collection of listeners will have their listeners
106
+ moved into this one.
107
+
108
+ Extra attributes are provided from each listener, with each successive listener
109
+ overriding any conflicting attributes from the previous one.
110
+
111
+ :param listeners: listeners to serve
112
+ :type listeners: Sequence[Listener[T_Stream]]
113
+ """
114
+
115
+ listeners: Sequence[Listener[T_Stream]]
116
+
117
+ def __post_init__(self) -> None:
118
+ listeners: list[Listener[T_Stream]] = []
119
+ for listener in self.listeners:
120
+ if isinstance(listener, MultiListener):
121
+ listeners.extend(listener.listeners)
122
+ del listener.listeners[:] # type: ignore[attr-defined]
123
+ else:
124
+ listeners.append(listener)
125
+
126
+ self.listeners = listeners
127
+
128
+ async def serve(
129
+ self, handler: Callable[[T_Stream], Any], task_group: TaskGroup | None = None
130
+ ) -> None:
131
+ from .. import create_task_group
132
+
133
+ async with create_task_group() as tg:
134
+ for listener in self.listeners:
135
+ tg.start_soon(listener.serve, handler, task_group)
136
+
137
+ async def aclose(self) -> None:
138
+ for listener in self.listeners:
139
+ await listener.aclose()
140
+
141
+ @property
142
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
143
+ attributes: dict = {}
144
+ for listener in self.listeners:
145
+ attributes.update(listener.extra_attributes)
146
+
147
+ return attributes
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/text.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "TextConnectable",
5
+ "TextReceiveStream",
6
+ "TextSendStream",
7
+ "TextStream",
8
+ )
9
+
10
+ import codecs
11
+ import sys
12
+ from collections.abc import Callable, Mapping
13
+ from dataclasses import InitVar, dataclass, field
14
+ from typing import Any
15
+
16
+ from ..abc import (
17
+ AnyByteReceiveStream,
18
+ AnyByteSendStream,
19
+ AnyByteStream,
20
+ AnyByteStreamConnectable,
21
+ ObjectReceiveStream,
22
+ ObjectSendStream,
23
+ ObjectStream,
24
+ ObjectStreamConnectable,
25
+ )
26
+
27
+ if sys.version_info >= (3, 12):
28
+ from typing import override
29
+ else:
30
+ from typing_extensions import override
31
+
32
+
33
+ @dataclass(eq=False)
34
+ class TextReceiveStream(ObjectReceiveStream[str]):
35
+ """
36
+ Stream wrapper that decodes bytes to strings using the given encoding.
37
+
38
+ Decoding is done using :class:`~codecs.IncrementalDecoder` which returns any
39
+ completely received unicode characters as soon as they come in.
40
+
41
+ :param transport_stream: any bytes-based receive stream
42
+ :param encoding: character encoding to use for decoding bytes to strings (defaults
43
+ to ``utf-8``)
44
+ :param errors: handling scheme for decoding errors (defaults to ``strict``; see the
45
+ `codecs module documentation`_ for a comprehensive list of options)
46
+
47
+ .. _codecs module documentation:
48
+ https://docs.python.org/3/library/codecs.html#codec-objects
49
+ """
50
+
51
+ transport_stream: AnyByteReceiveStream
52
+ encoding: InitVar[str] = "utf-8"
53
+ errors: InitVar[str] = "strict"
54
+ _decoder: codecs.IncrementalDecoder = field(init=False)
55
+
56
+ def __post_init__(self, encoding: str, errors: str) -> None:
57
+ decoder_class = codecs.getincrementaldecoder(encoding)
58
+ self._decoder = decoder_class(errors=errors)
59
+
60
+ async def receive(self) -> str:
61
+ while True:
62
+ chunk = await self.transport_stream.receive()
63
+ decoded = self._decoder.decode(chunk)
64
+ if decoded:
65
+ return decoded
66
+
67
+ async def aclose(self) -> None:
68
+ await self.transport_stream.aclose()
69
+ self._decoder.reset()
70
+
71
+ @property
72
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
73
+ return self.transport_stream.extra_attributes
74
+
75
+
76
+ @dataclass(eq=False)
77
+ class TextSendStream(ObjectSendStream[str]):
78
+ """
79
+ Sends strings to the wrapped stream as bytes using the given encoding.
80
+
81
+ :param AnyByteSendStream transport_stream: any bytes-based send stream
82
+ :param str encoding: character encoding to use for encoding strings to bytes
83
+ (defaults to ``utf-8``)
84
+ :param str errors: handling scheme for encoding errors (defaults to ``strict``; see
85
+ the `codecs module documentation`_ for a comprehensive list of options)
86
+
87
+ .. _codecs module documentation:
88
+ https://docs.python.org/3/library/codecs.html#codec-objects
89
+ """
90
+
91
+ transport_stream: AnyByteSendStream
92
+ encoding: InitVar[str] = "utf-8"
93
+ errors: str = "strict"
94
+ _encoder: Callable[..., tuple[bytes, int]] = field(init=False)
95
+
96
+ def __post_init__(self, encoding: str) -> None:
97
+ self._encoder = codecs.getencoder(encoding)
98
+
99
+ async def send(self, item: str) -> None:
100
+ encoded = self._encoder(item, self.errors)[0]
101
+ await self.transport_stream.send(encoded)
102
+
103
+ async def aclose(self) -> None:
104
+ await self.transport_stream.aclose()
105
+
106
+ @property
107
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
108
+ return self.transport_stream.extra_attributes
109
+
110
+
111
+ @dataclass(eq=False)
112
+ class TextStream(ObjectStream[str]):
113
+ """
114
+ A bidirectional stream that decodes bytes to strings on receive and encodes strings
115
+ to bytes on send.
116
+
117
+ Extra attributes will be provided from both streams, with the receive stream
118
+ providing the values in case of a conflict.
119
+
120
+ :param AnyByteStream transport_stream: any bytes-based stream
121
+ :param str encoding: character encoding to use for encoding/decoding strings to/from
122
+ bytes (defaults to ``utf-8``)
123
+ :param str errors: handling scheme for encoding errors (defaults to ``strict``; see
124
+ the `codecs module documentation`_ for a comprehensive list of options)
125
+
126
+ .. _codecs module documentation:
127
+ https://docs.python.org/3/library/codecs.html#codec-objects
128
+ """
129
+
130
+ transport_stream: AnyByteStream
131
+ encoding: InitVar[str] = "utf-8"
132
+ errors: InitVar[str] = "strict"
133
+ _receive_stream: TextReceiveStream = field(init=False)
134
+ _send_stream: TextSendStream = field(init=False)
135
+
136
+ def __post_init__(self, encoding: str, errors: str) -> None:
137
+ self._receive_stream = TextReceiveStream(
138
+ self.transport_stream, encoding=encoding, errors=errors
139
+ )
140
+ self._send_stream = TextSendStream(
141
+ self.transport_stream, encoding=encoding, errors=errors
142
+ )
143
+
144
+ async def receive(self) -> str:
145
+ return await self._receive_stream.receive()
146
+
147
+ async def send(self, item: str) -> None:
148
+ await self._send_stream.send(item)
149
+
150
+ async def send_eof(self) -> None:
151
+ await self.transport_stream.send_eof()
152
+
153
+ async def aclose(self) -> None:
154
+ await self._send_stream.aclose()
155
+ await self._receive_stream.aclose()
156
+
157
+ @property
158
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
159
+ return {
160
+ **self._send_stream.extra_attributes,
161
+ **self._receive_stream.extra_attributes,
162
+ }
163
+
164
+
165
+ class TextConnectable(ObjectStreamConnectable[str]):
166
+ def __init__(self, connectable: AnyByteStreamConnectable):
167
+ """
168
+ :param connectable: the bytestream endpoint to wrap
169
+
170
+ """
171
+ self.connectable = connectable
172
+
173
+ @override
174
+ async def connect(self) -> TextStream:
175
+ stream = await self.connectable.connect()
176
+ return TextStream(stream)
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/streams/tls.py ADDED
@@ -0,0 +1,421 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "TLSAttribute",
5
+ "TLSConnectable",
6
+ "TLSListener",
7
+ "TLSStream",
8
+ )
9
+
10
+ import logging
11
+ import re
12
+ import ssl
13
+ import sys
14
+ from collections.abc import Callable, Mapping
15
+ from dataclasses import dataclass
16
+ from functools import wraps
17
+ from ssl import SSLContext
18
+ from typing import Any, TypeAlias, TypeVar
19
+
20
+ from .. import (
21
+ BrokenResourceError,
22
+ EndOfStream,
23
+ aclose_forcefully,
24
+ get_cancelled_exc_class,
25
+ to_thread,
26
+ )
27
+ from .._core._typedattr import TypedAttributeSet, typed_attribute
28
+ from ..abc import (
29
+ AnyByteStream,
30
+ AnyByteStreamConnectable,
31
+ ByteStream,
32
+ ByteStreamConnectable,
33
+ Listener,
34
+ TaskGroup,
35
+ )
36
+
37
+ if sys.version_info >= (3, 11):
38
+ from typing import TypeVarTuple, Unpack
39
+ else:
40
+ from typing_extensions import TypeVarTuple, Unpack
41
+
42
+ if sys.version_info >= (3, 12):
43
+ from typing import override
44
+ else:
45
+ from typing_extensions import override
46
+
47
+ T_Retval = TypeVar("T_Retval")
48
+ PosArgsT = TypeVarTuple("PosArgsT")
49
+ _PCTRTT: TypeAlias = tuple[tuple[str, str], ...]
50
+ _PCTRTTT: TypeAlias = tuple[_PCTRTT, ...]
51
+
52
+
53
+ class TLSAttribute(TypedAttributeSet):
54
+ """Contains Transport Layer Security related attributes."""
55
+
56
+ #: the selected ALPN protocol
57
+ alpn_protocol: str | None = typed_attribute()
58
+ #: the channel binding for type ``tls-unique``
59
+ channel_binding_tls_unique: bytes = typed_attribute()
60
+ #: the selected cipher
61
+ cipher: tuple[str, str, int] = typed_attribute()
62
+ #: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert`
63
+ # for more information)
64
+ peer_certificate: None | (dict[str, str | _PCTRTTT | _PCTRTT]) = typed_attribute()
65
+ #: the peer certificate in binary form
66
+ peer_certificate_binary: bytes | None = typed_attribute()
67
+ #: ``True`` if this is the server side of the connection
68
+ server_side: bool = typed_attribute()
69
+ #: ciphers shared by the client during the TLS handshake (``None`` if this is the
70
+ #: client side)
71
+ shared_ciphers: list[tuple[str, str, int]] | None = typed_attribute()
72
+ #: the :class:`~ssl.SSLObject` used for encryption
73
+ ssl_object: ssl.SSLObject = typed_attribute()
74
+ #: ``True`` if this stream does (and expects) a closing TLS handshake when the
75
+ #: stream is being closed
76
+ standard_compatible: bool = typed_attribute()
77
+ #: the TLS protocol version (e.g. ``TLSv1.2``)
78
+ tls_version: str = typed_attribute()
79
+
80
+
81
+ @dataclass(eq=False)
82
+ class TLSStream(ByteStream):
83
+ """
84
+ A stream wrapper that encrypts all sent data and decrypts received data.
85
+
86
+ This class has no public initializer; use :meth:`wrap` instead.
87
+ All extra attributes from :class:`~TLSAttribute` are supported.
88
+
89
+ :var AnyByteStream transport_stream: the wrapped stream
90
+
91
+ """
92
+
93
+ transport_stream: AnyByteStream
94
+ standard_compatible: bool
95
+ _ssl_object: ssl.SSLObject
96
+ _read_bio: ssl.MemoryBIO
97
+ _write_bio: ssl.MemoryBIO
98
+
99
+ @classmethod
100
+ async def wrap(
101
+ cls,
102
+ transport_stream: AnyByteStream,
103
+ *,
104
+ server_side: bool | None = None,
105
+ hostname: str | None = None,
106
+ ssl_context: ssl.SSLContext | None = None,
107
+ standard_compatible: bool = True,
108
+ ) -> TLSStream:
109
+ """
110
+ Wrap an existing stream with Transport Layer Security.
111
+
112
+ This performs a TLS handshake with the peer.
113
+
114
+ :param transport_stream: a bytes-transporting stream to wrap
115
+ :param server_side: ``True`` if this is the server side of the connection,
116
+ ``False`` if this is the client side (if omitted, will be set to ``False``
117
+ if ``hostname`` has been provided, ``False`` otherwise). Used only to create
118
+ a default context when an explicit context has not been provided.
119
+ :param hostname: host name of the peer (if host name checking is desired)
120
+ :param ssl_context: the SSLContext object to use (if not provided, a secure
121
+ default will be created)
122
+ :param standard_compatible: if ``False``, skip the closing handshake when
123
+ closing the connection, and don't raise an exception if the peer does the
124
+ same
125
+ :raises ~ssl.SSLError: if the TLS handshake fails
126
+
127
+ """
128
+ if server_side is None:
129
+ server_side = not hostname
130
+
131
+ if not ssl_context:
132
+ purpose = (
133
+ ssl.Purpose.CLIENT_AUTH if server_side else ssl.Purpose.SERVER_AUTH
134
+ )
135
+ ssl_context = ssl.create_default_context(purpose)
136
+
137
+ # Re-enable detection of unexpected EOFs if it was disabled by Python
138
+ if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"):
139
+ ssl_context.options &= ~ssl.OP_IGNORE_UNEXPECTED_EOF
140
+
141
+ bio_in = ssl.MemoryBIO()
142
+ bio_out = ssl.MemoryBIO()
143
+
144
+ # External SSLContext implementations may do blocking I/O in wrap_bio(),
145
+ # but the standard library implementation won't
146
+ if type(ssl_context) is ssl.SSLContext:
147
+ ssl_object = ssl_context.wrap_bio(
148
+ bio_in, bio_out, server_side=server_side, server_hostname=hostname
149
+ )
150
+ else:
151
+ ssl_object = await to_thread.run_sync(
152
+ ssl_context.wrap_bio,
153
+ bio_in,
154
+ bio_out,
155
+ server_side,
156
+ hostname,
157
+ None,
158
+ )
159
+
160
+ wrapper = cls(
161
+ transport_stream=transport_stream,
162
+ standard_compatible=standard_compatible,
163
+ _ssl_object=ssl_object,
164
+ _read_bio=bio_in,
165
+ _write_bio=bio_out,
166
+ )
167
+ await wrapper._call_sslobject_method(ssl_object.do_handshake)
168
+ return wrapper
169
+
170
+ async def _call_sslobject_method(
171
+ self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT]
172
+ ) -> T_Retval:
173
+ while True:
174
+ try:
175
+ result = func(*args)
176
+ except ssl.SSLWantReadError:
177
+ try:
178
+ # Flush any pending writes first
179
+ if self._write_bio.pending:
180
+ await self.transport_stream.send(self._write_bio.read())
181
+
182
+ data = await self.transport_stream.receive()
183
+ except EndOfStream:
184
+ self._read_bio.write_eof()
185
+ except OSError as exc:
186
+ self._read_bio.write_eof()
187
+ self._write_bio.write_eof()
188
+ raise BrokenResourceError from exc
189
+ else:
190
+ self._read_bio.write(data)
191
+ except ssl.SSLWantWriteError:
192
+ await self.transport_stream.send(self._write_bio.read())
193
+ except ssl.SSLSyscallError as exc:
194
+ self._read_bio.write_eof()
195
+ self._write_bio.write_eof()
196
+ raise BrokenResourceError from exc
197
+ except ssl.SSLError as exc:
198
+ self._read_bio.write_eof()
199
+ self._write_bio.write_eof()
200
+ if isinstance(exc, ssl.SSLEOFError) or (
201
+ exc.strerror and "UNEXPECTED_EOF_WHILE_READING" in exc.strerror
202
+ ):
203
+ if self.standard_compatible:
204
+ raise BrokenResourceError from exc
205
+ else:
206
+ raise EndOfStream from None
207
+
208
+ raise
209
+ else:
210
+ # Flush any pending writes first
211
+ if self._write_bio.pending:
212
+ await self.transport_stream.send(self._write_bio.read())
213
+
214
+ return result
215
+
216
+ async def unwrap(self) -> tuple[AnyByteStream, bytes]:
217
+ """
218
+ Does the TLS closing handshake.
219
+
220
+ :return: a tuple of (wrapped byte stream, bytes left in the read buffer)
221
+
222
+ """
223
+ await self._call_sslobject_method(self._ssl_object.unwrap)
224
+ self._read_bio.write_eof()
225
+ self._write_bio.write_eof()
226
+ return self.transport_stream, self._read_bio.read()
227
+
228
+ async def aclose(self) -> None:
229
+ if self.standard_compatible:
230
+ try:
231
+ await self.unwrap()
232
+ except BaseException:
233
+ await aclose_forcefully(self.transport_stream)
234
+ raise
235
+
236
+ await self.transport_stream.aclose()
237
+
238
+ async def receive(self, max_bytes: int = 65536) -> bytes:
239
+ data = await self._call_sslobject_method(self._ssl_object.read, max_bytes)
240
+ if not data:
241
+ raise EndOfStream
242
+
243
+ return data
244
+
245
+ async def send(self, item: bytes) -> None:
246
+ await self._call_sslobject_method(self._ssl_object.write, item)
247
+
248
+ async def send_eof(self) -> None:
249
+ tls_version = self.extra(TLSAttribute.tls_version)
250
+ match = re.match(r"TLSv(\d+)(?:\.(\d+))?", tls_version)
251
+ if match:
252
+ major, minor = int(match.group(1)), int(match.group(2) or 0)
253
+ if (major, minor) < (1, 3):
254
+ raise NotImplementedError(
255
+ f"send_eof() requires at least TLSv1.3; current "
256
+ f"session uses {tls_version}"
257
+ )
258
+
259
+ raise NotImplementedError(
260
+ "send_eof() has not yet been implemented for TLS streams"
261
+ )
262
+
263
+ @property
264
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
265
+ return {
266
+ **self.transport_stream.extra_attributes,
267
+ TLSAttribute.alpn_protocol: self._ssl_object.selected_alpn_protocol,
268
+ TLSAttribute.channel_binding_tls_unique: (
269
+ self._ssl_object.get_channel_binding
270
+ ),
271
+ TLSAttribute.cipher: self._ssl_object.cipher,
272
+ TLSAttribute.peer_certificate: lambda: self._ssl_object.getpeercert(False),
273
+ TLSAttribute.peer_certificate_binary: lambda: self._ssl_object.getpeercert(
274
+ True
275
+ ),
276
+ TLSAttribute.server_side: lambda: self._ssl_object.server_side,
277
+ TLSAttribute.shared_ciphers: lambda: (
278
+ self._ssl_object.shared_ciphers()
279
+ if self._ssl_object.server_side
280
+ else None
281
+ ),
282
+ TLSAttribute.standard_compatible: lambda: self.standard_compatible,
283
+ TLSAttribute.ssl_object: lambda: self._ssl_object,
284
+ TLSAttribute.tls_version: self._ssl_object.version,
285
+ }
286
+
287
+
288
+ @dataclass(eq=False)
289
+ class TLSListener(Listener[TLSStream]):
290
+ """
291
+ A convenience listener that wraps another listener and auto-negotiates a TLS session
292
+ on every accepted connection.
293
+
294
+ If the TLS handshake times out or raises an exception,
295
+ :meth:`handle_handshake_error` is called to do whatever post-mortem processing is
296
+ deemed necessary.
297
+
298
+ Supports only the :attr:`~TLSAttribute.standard_compatible` extra attribute.
299
+
300
+ :param Listener listener: the listener to wrap
301
+ :param ssl_context: the SSL context object
302
+ :param standard_compatible: a flag passed through to :meth:`TLSStream.wrap`
303
+ :param handshake_timeout: time limit for the TLS handshake
304
+ (passed to :func:`~anyio.fail_after`)
305
+ """
306
+
307
+ listener: Listener[Any]
308
+ ssl_context: ssl.SSLContext
309
+ standard_compatible: bool = True
310
+ handshake_timeout: float = 30
311
+
312
+ @staticmethod
313
+ async def handle_handshake_error(exc: BaseException, stream: AnyByteStream) -> None:
314
+ """
315
+ Handle an exception raised during the TLS handshake.
316
+
317
+ This method does 3 things:
318
+
319
+ #. Forcefully closes the original stream
320
+ #. Logs the exception (unless it was a cancellation exception) using the
321
+ ``anyio.streams.tls`` logger
322
+ #. Reraises the exception if it was a base exception or a cancellation exception
323
+
324
+ :param exc: the exception
325
+ :param stream: the original stream
326
+
327
+ """
328
+ await aclose_forcefully(stream)
329
+
330
+ # Log all except cancellation exceptions
331
+ if not isinstance(exc, get_cancelled_exc_class()):
332
+ # CPython (as of 3.11.5) returns incorrect `sys.exc_info()` here when using
333
+ # any asyncio implementation, so we explicitly pass the exception to log
334
+ # (https://github.com/python/cpython/issues/108668). Trio does not have this
335
+ # issue because it works around the CPython bug.
336
+ logging.getLogger(__name__).exception(
337
+ "Error during TLS handshake", exc_info=exc
338
+ )
339
+
340
+ # Only reraise base exceptions and cancellation exceptions
341
+ if not isinstance(exc, Exception) or isinstance(exc, get_cancelled_exc_class()):
342
+ raise
343
+
344
+ async def serve(
345
+ self,
346
+ handler: Callable[[TLSStream], Any],
347
+ task_group: TaskGroup | None = None,
348
+ ) -> None:
349
+ @wraps(handler)
350
+ async def handler_wrapper(stream: AnyByteStream) -> None:
351
+ from .. import fail_after
352
+
353
+ try:
354
+ with fail_after(self.handshake_timeout):
355
+ wrapped_stream = await TLSStream.wrap(
356
+ stream,
357
+ ssl_context=self.ssl_context,
358
+ standard_compatible=self.standard_compatible,
359
+ )
360
+ except BaseException as exc:
361
+ await self.handle_handshake_error(exc, stream)
362
+ else:
363
+ await handler(wrapped_stream)
364
+
365
+ await self.listener.serve(handler_wrapper, task_group)
366
+
367
+ async def aclose(self) -> None:
368
+ await self.listener.aclose()
369
+
370
+ @property
371
+ def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
372
+ return {
373
+ TLSAttribute.standard_compatible: lambda: self.standard_compatible,
374
+ }
375
+
376
+
377
+ class TLSConnectable(ByteStreamConnectable):
378
+ """
379
+ Wraps another connectable and does TLS negotiation after a successful connection.
380
+
381
+ :param connectable: the connectable to wrap
382
+ :param hostname: host name of the server (if host name checking is desired)
383
+ :param ssl_context: the SSLContext object to use (if not provided, a secure default
384
+ will be created)
385
+ :param standard_compatible: if ``False``, skip the closing handshake when closing
386
+ the connection, and don't raise an exception if the server does the same
387
+ """
388
+
389
+ def __init__(
390
+ self,
391
+ connectable: AnyByteStreamConnectable,
392
+ *,
393
+ hostname: str | None = None,
394
+ ssl_context: ssl.SSLContext | None = None,
395
+ standard_compatible: bool = True,
396
+ ) -> None:
397
+ self.connectable = connectable
398
+ self.ssl_context: SSLContext = ssl_context or ssl.create_default_context(
399
+ ssl.Purpose.SERVER_AUTH
400
+ )
401
+ if not isinstance(self.ssl_context, ssl.SSLContext):
402
+ raise TypeError(
403
+ "ssl_context must be an instance of ssl.SSLContext, not "
404
+ f"{type(self.ssl_context).__name__}"
405
+ )
406
+ self.hostname = hostname
407
+ self.standard_compatible = standard_compatible
408
+
409
+ @override
410
+ async def connect(self) -> TLSStream:
411
+ stream = await self.connectable.connect()
412
+ try:
413
+ return await TLSStream.wrap(
414
+ stream,
415
+ hostname=self.hostname,
416
+ ssl_context=self.ssl_context,
417
+ standard_compatible=self.standard_compatible,
418
+ )
419
+ except BaseException:
420
+ await aclose_forcefully(stream)
421
+ raise
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/to_interpreter.py ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "run_sync",
5
+ "current_default_interpreter_limiter",
6
+ )
7
+
8
+ import atexit
9
+ import os
10
+ import sys
11
+ from collections import deque
12
+ from collections.abc import Callable
13
+ from typing import Any, Final, TypeVar
14
+
15
+ from . import current_time, to_thread
16
+ from ._core._exceptions import BrokenWorkerInterpreter
17
+ from ._core._synchronization import CapacityLimiter
18
+ from .lowlevel import RunVar
19
+
20
+ if sys.version_info >= (3, 11):
21
+ from typing import TypeVarTuple, Unpack
22
+ else:
23
+ from typing_extensions import TypeVarTuple, Unpack
24
+
25
+ if sys.version_info >= (3, 14):
26
+ from concurrent.interpreters import ExecutionFailed, create
27
+
28
+ def _interp_call(
29
+ func: Callable[..., Any], args: tuple[Any, ...]
30
+ ) -> tuple[Any, bool]:
31
+ try:
32
+ retval = func(*args)
33
+ except BaseException as exc:
34
+ return exc, True
35
+ else:
36
+ return retval, False
37
+
38
+ class _Worker:
39
+ last_used: float = 0
40
+
41
+ def __init__(self) -> None:
42
+ self._interpreter = create()
43
+
44
+ def destroy(self) -> None:
45
+ self._interpreter.close()
46
+
47
+ def call(
48
+ self,
49
+ func: Callable[..., T_Retval],
50
+ args: tuple[Any, ...],
51
+ ) -> T_Retval:
52
+ try:
53
+ res, is_exception = self._interpreter.call(_interp_call, func, args)
54
+ except ExecutionFailed as exc:
55
+ raise BrokenWorkerInterpreter(exc.excinfo) from exc
56
+
57
+ if is_exception:
58
+ raise res
59
+
60
+ return res
61
+ elif sys.version_info >= (3, 13):
62
+ import _interpqueues
63
+ import _interpreters
64
+
65
+ UNBOUND: Final = 2 # I have no clue how this works, but it was used in the stdlib
66
+ FMT_UNPICKLED: Final = 0
67
+ FMT_PICKLED: Final = 1
68
+ QUEUE_PICKLE_ARGS: Final = (FMT_PICKLED, UNBOUND)
69
+ QUEUE_UNPICKLE_ARGS: Final = (FMT_UNPICKLED, UNBOUND)
70
+
71
+ _run_func = compile(
72
+ """
73
+ import _interpqueues
74
+ from _interpreters import NotShareableError
75
+ from pickle import loads, dumps, HIGHEST_PROTOCOL
76
+
77
+ QUEUE_PICKLE_ARGS = (1, 2)
78
+ QUEUE_UNPICKLE_ARGS = (0, 2)
79
+
80
+ item = _interpqueues.get(queue_id)[0]
81
+ try:
82
+ func, args = loads(item)
83
+ retval = func(*args)
84
+ except BaseException as exc:
85
+ is_exception = True
86
+ retval = exc
87
+ else:
88
+ is_exception = False
89
+
90
+ try:
91
+ _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_UNPICKLE_ARGS)
92
+ except NotShareableError:
93
+ retval = dumps(retval, HIGHEST_PROTOCOL)
94
+ _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_PICKLE_ARGS)
95
+ """,
96
+ "<string>",
97
+ "exec",
98
+ )
99
+
100
+ class _Worker:
101
+ last_used: float = 0
102
+
103
+ def __init__(self) -> None:
104
+ self._interpreter_id = _interpreters.create()
105
+ self._queue_id = _interpqueues.create(1, *QUEUE_UNPICKLE_ARGS)
106
+ _interpreters.set___main___attrs(
107
+ self._interpreter_id, {"queue_id": self._queue_id}
108
+ )
109
+
110
+ def destroy(self) -> None:
111
+ _interpqueues.destroy(self._queue_id)
112
+ _interpreters.destroy(self._interpreter_id)
113
+
114
+ def call(
115
+ self,
116
+ func: Callable[..., T_Retval],
117
+ args: tuple[Any, ...],
118
+ ) -> T_Retval:
119
+ import pickle
120
+
121
+ item = pickle.dumps((func, args), pickle.HIGHEST_PROTOCOL)
122
+ _interpqueues.put(self._queue_id, item, *QUEUE_PICKLE_ARGS)
123
+ exc_info = _interpreters.exec(self._interpreter_id, _run_func)
124
+ if exc_info:
125
+ raise BrokenWorkerInterpreter(exc_info)
126
+
127
+ res = _interpqueues.get(self._queue_id)
128
+ (res, is_exception), fmt = res[:2]
129
+ if fmt == FMT_PICKLED:
130
+ res = pickle.loads(res)
131
+
132
+ if is_exception:
133
+ raise res
134
+
135
+ return res
136
+ else:
137
+
138
+ class _Worker:
139
+ last_used: float = 0
140
+
141
+ def __init__(self) -> None:
142
+ raise RuntimeError("subinterpreters require at least Python 3.13")
143
+
144
+ def call(
145
+ self,
146
+ func: Callable[..., T_Retval],
147
+ args: tuple[Any, ...],
148
+ ) -> T_Retval:
149
+ raise NotImplementedError
150
+
151
+ def destroy(self) -> None:
152
+ pass
153
+
154
+
155
+ DEFAULT_CPU_COUNT: Final = 8 # this is just an arbitrarily selected value
156
+ MAX_WORKER_IDLE_TIME = (
157
+ 30 # seconds a subinterpreter can be idle before becoming eligible for pruning
158
+ )
159
+
160
+ T_Retval = TypeVar("T_Retval")
161
+ PosArgsT = TypeVarTuple("PosArgsT")
162
+
163
+ _idle_workers = RunVar[deque[_Worker]]("_available_workers")
164
+ _default_interpreter_limiter = RunVar[CapacityLimiter]("_default_interpreter_limiter")
165
+
166
+
167
+ def _stop_workers(workers: deque[_Worker]) -> None:
168
+ for worker in workers:
169
+ worker.destroy()
170
+
171
+ workers.clear()
172
+
173
+
174
+ async def run_sync(
175
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
176
+ *args: Unpack[PosArgsT],
177
+ limiter: CapacityLimiter | None = None,
178
+ ) -> T_Retval:
179
+ """
180
+ Call the given function with the given arguments in a subinterpreter.
181
+
182
+ .. warning:: On Python 3.13, the :mod:`concurrent.interpreters` module was not yet
183
+ available, so the code path for that Python version relies on an undocumented,
184
+ private API. As such, it is recommended to not rely on this function for anything
185
+ mission-critical on Python 3.13.
186
+
187
+ :param func: a callable
188
+ :param args: the positional arguments for the callable
189
+ :param limiter: capacity limiter to use to limit the total number of subinterpreters
190
+ running (if omitted, the default limiter is used)
191
+ :return: the result of the call
192
+ :raises BrokenWorkerInterpreter: if there's an internal error in a subinterpreter
193
+
194
+ """
195
+ if limiter is None:
196
+ limiter = current_default_interpreter_limiter()
197
+
198
+ try:
199
+ idle_workers = _idle_workers.get()
200
+ except LookupError:
201
+ idle_workers = deque()
202
+ _idle_workers.set(idle_workers)
203
+ atexit.register(_stop_workers, idle_workers)
204
+
205
+ async with limiter:
206
+ try:
207
+ worker = idle_workers.pop()
208
+ except IndexError:
209
+ worker = _Worker()
210
+
211
+ try:
212
+ return await to_thread.run_sync(
213
+ worker.call,
214
+ func,
215
+ args,
216
+ limiter=limiter,
217
+ )
218
+ finally:
219
+ # Prune workers that have been idle for too long
220
+ now = current_time()
221
+ while idle_workers:
222
+ if now - idle_workers[0].last_used <= MAX_WORKER_IDLE_TIME:
223
+ break
224
+
225
+ await to_thread.run_sync(idle_workers.popleft().destroy, limiter=limiter)
226
+
227
+ worker.last_used = current_time()
228
+ idle_workers.append(worker)
229
+
230
+
231
+ def current_default_interpreter_limiter() -> CapacityLimiter:
232
+ """
233
+ Return the capacity limiter used by default to limit the number of concurrently
234
+ running subinterpreters.
235
+
236
+ Defaults to the number of CPU cores.
237
+
238
+ :return: a capacity limiter object
239
+
240
+ """
241
+ try:
242
+ return _default_interpreter_limiter.get()
243
+ except LookupError:
244
+ limiter = CapacityLimiter(os.cpu_count() or DEFAULT_CPU_COUNT)
245
+ _default_interpreter_limiter.set(limiter)
246
+ return limiter
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/to_process.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "current_default_process_limiter",
5
+ "process_worker",
6
+ "run_sync",
7
+ )
8
+
9
+ import os
10
+ import pickle
11
+ import subprocess
12
+ import sys
13
+ from collections import deque
14
+ from collections.abc import Callable
15
+ from importlib.util import module_from_spec, spec_from_file_location
16
+ from typing import TypeVar, cast
17
+
18
+ from ._core._eventloop import current_time, get_async_backend, get_cancelled_exc_class
19
+ from ._core._exceptions import BrokenWorkerProcess
20
+ from ._core._subprocesses import open_process
21
+ from ._core._synchronization import CapacityLimiter
22
+ from ._core._tasks import CancelScope, fail_after
23
+ from .abc import ByteReceiveStream, ByteSendStream, Process
24
+ from .lowlevel import RunVar, checkpoint_if_cancelled
25
+ from .streams.buffered import BufferedByteReceiveStream
26
+
27
+ if sys.version_info >= (3, 11):
28
+ from typing import TypeVarTuple, Unpack
29
+ else:
30
+ from typing_extensions import TypeVarTuple, Unpack
31
+
32
+ WORKER_MAX_IDLE_TIME = 300 # 5 minutes
33
+
34
+ T_Retval = TypeVar("T_Retval")
35
+ PosArgsT = TypeVarTuple("PosArgsT")
36
+
37
+ _process_pool_workers: RunVar[set[Process]] = RunVar("_process_pool_workers")
38
+ _process_pool_idle_workers: RunVar[deque[tuple[Process, float]]] = RunVar(
39
+ "_process_pool_idle_workers"
40
+ )
41
+ _default_process_limiter: RunVar[CapacityLimiter] = RunVar("_default_process_limiter")
42
+
43
+
44
+ async def run_sync( # type: ignore[return]
45
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
46
+ *args: Unpack[PosArgsT],
47
+ cancellable: bool = False,
48
+ limiter: CapacityLimiter | None = None,
49
+ ) -> T_Retval:
50
+ """
51
+ Call the given function with the given arguments in a worker process.
52
+
53
+ If the ``cancellable`` option is enabled and the task waiting for its completion is
54
+ cancelled, the worker process running it will be abruptly terminated using SIGKILL
55
+ (or ``terminateProcess()`` on Windows).
56
+
57
+ :param func: a callable
58
+ :param args: positional arguments for the callable
59
+ :param cancellable: ``True`` to allow cancellation of the operation while it's
60
+ running
61
+ :param limiter: capacity limiter to use to limit the total amount of processes
62
+ running (if omitted, the default limiter is used)
63
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
64
+ current thread
65
+ :return: an awaitable that yields the return value of the function.
66
+
67
+ """
68
+
69
+ async def send_raw_command(pickled_cmd: bytes) -> object:
70
+ try:
71
+ await stdin.send(pickled_cmd)
72
+ response = await buffered.receive_until(b"\n", 50)
73
+ status, length = response.split(b" ")
74
+ if status not in (b"RETURN", b"EXCEPTION"):
75
+ raise RuntimeError(
76
+ f"Worker process returned unexpected response: {response!r}"
77
+ )
78
+
79
+ pickled_response = await buffered.receive_exactly(int(length))
80
+ except BaseException as exc:
81
+ workers.discard(process)
82
+ try:
83
+ process.kill()
84
+ with CancelScope(shield=True):
85
+ await process.aclose()
86
+ except ProcessLookupError:
87
+ pass
88
+
89
+ if isinstance(exc, get_cancelled_exc_class()):
90
+ raise
91
+ else:
92
+ raise BrokenWorkerProcess from exc
93
+
94
+ retval = pickle.loads(pickled_response)
95
+ if status == b"EXCEPTION":
96
+ assert isinstance(retval, BaseException)
97
+ raise retval
98
+ else:
99
+ return retval
100
+
101
+ # First pickle the request before trying to reserve a worker process
102
+ await checkpoint_if_cancelled()
103
+ request = pickle.dumps(("run", func, args), protocol=pickle.HIGHEST_PROTOCOL)
104
+
105
+ # If this is the first run in this event loop thread, set up the necessary variables
106
+ try:
107
+ workers = _process_pool_workers.get()
108
+ idle_workers = _process_pool_idle_workers.get()
109
+ except LookupError:
110
+ workers = set()
111
+ idle_workers = deque()
112
+ _process_pool_workers.set(workers)
113
+ _process_pool_idle_workers.set(idle_workers)
114
+ get_async_backend().setup_process_pool_exit_at_shutdown(workers)
115
+
116
+ async with limiter or current_default_process_limiter():
117
+ # Pop processes from the pool (starting from the most recently used) until we
118
+ # find one that hasn't exited yet
119
+ process: Process
120
+ while idle_workers:
121
+ process, idle_since = idle_workers.pop()
122
+ if process.returncode is None:
123
+ stdin = cast(ByteSendStream, process.stdin)
124
+ buffered = BufferedByteReceiveStream(
125
+ cast(ByteReceiveStream, process.stdout)
126
+ )
127
+
128
+ # Prune any other workers that have been idle for WORKER_MAX_IDLE_TIME
129
+ # seconds or longer
130
+ now = current_time()
131
+ killed_processes: list[Process] = []
132
+ while idle_workers:
133
+ if now - idle_workers[0][1] < WORKER_MAX_IDLE_TIME:
134
+ break
135
+
136
+ process_to_kill, idle_since = idle_workers.popleft()
137
+ process_to_kill.kill()
138
+ workers.remove(process_to_kill)
139
+ killed_processes.append(process_to_kill)
140
+
141
+ with CancelScope(shield=True):
142
+ for killed_process in killed_processes:
143
+ await killed_process.aclose()
144
+
145
+ break
146
+
147
+ workers.remove(process)
148
+ else:
149
+ command = [sys.executable, "-u", "-m", __name__]
150
+ process = await open_process(
151
+ command, stdin=subprocess.PIPE, stdout=subprocess.PIPE
152
+ )
153
+ try:
154
+ stdin = cast(ByteSendStream, process.stdin)
155
+ buffered = BufferedByteReceiveStream(
156
+ cast(ByteReceiveStream, process.stdout)
157
+ )
158
+ with fail_after(20):
159
+ message = await buffered.receive(6)
160
+
161
+ if message != b"READY\n":
162
+ raise BrokenWorkerProcess(
163
+ f"Worker process returned unexpected response: {message!r}"
164
+ )
165
+
166
+ main_module_path = getattr(sys.modules["__main__"], "__file__", None)
167
+ pickled = pickle.dumps(
168
+ ("init", sys.path, main_module_path),
169
+ protocol=pickle.HIGHEST_PROTOCOL,
170
+ )
171
+ await send_raw_command(pickled)
172
+ except (BrokenWorkerProcess, get_cancelled_exc_class()):
173
+ raise
174
+ except BaseException as exc:
175
+ process.kill()
176
+ raise BrokenWorkerProcess(
177
+ "Error during worker process initialization"
178
+ ) from exc
179
+
180
+ workers.add(process)
181
+
182
+ with CancelScope(shield=not cancellable):
183
+ try:
184
+ return cast(T_Retval, await send_raw_command(request))
185
+ finally:
186
+ if process in workers:
187
+ idle_workers.append((process, current_time()))
188
+
189
+
190
+ def current_default_process_limiter() -> CapacityLimiter:
191
+ """
192
+ Return the capacity limiter that is used by default to limit the number of worker
193
+ processes.
194
+
195
+ :return: a capacity limiter object
196
+
197
+ """
198
+ try:
199
+ return _default_process_limiter.get()
200
+ except LookupError:
201
+ limiter = CapacityLimiter(os.cpu_count() or 2)
202
+ _default_process_limiter.set(limiter)
203
+ return limiter
204
+
205
+
206
+ def process_worker() -> None:
207
+ # Redirect standard streams to os.devnull so that user code won't interfere with the
208
+ # parent-worker communication
209
+ stdin = sys.stdin
210
+ stdout = sys.stdout
211
+ sys.stdin = open(os.devnull)
212
+ sys.stdout = open(os.devnull, "w")
213
+
214
+ stdout.buffer.write(b"READY\n")
215
+ while True:
216
+ retval = exception = None
217
+ try:
218
+ command, *args = pickle.load(stdin.buffer)
219
+ except EOFError:
220
+ return
221
+ except BaseException as exc:
222
+ exception = exc
223
+ else:
224
+ if command == "run":
225
+ func, args = args
226
+ try:
227
+ retval = func(*args)
228
+ except BaseException as exc:
229
+ exception = exc
230
+ elif command == "init":
231
+ main_module_path: str | None
232
+ sys.path, main_module_path = args
233
+ del sys.modules["__main__"]
234
+ if main_module_path and os.path.isfile(main_module_path):
235
+ # Load the parent's main module but as __mp_main__ instead of
236
+ # __main__ (like multiprocessing does) to avoid infinite recursion
237
+ try:
238
+ spec = spec_from_file_location("__mp_main__", main_module_path)
239
+ if spec and spec.loader:
240
+ main = module_from_spec(spec)
241
+ spec.loader.exec_module(main)
242
+ sys.modules["__main__"] = main
243
+ except BaseException as exc:
244
+ exception = exc
245
+ try:
246
+ if exception is not None:
247
+ status = b"EXCEPTION"
248
+ pickled = pickle.dumps(exception, pickle.HIGHEST_PROTOCOL)
249
+ else:
250
+ status = b"RETURN"
251
+ pickled = pickle.dumps(retval, pickle.HIGHEST_PROTOCOL)
252
+ except BaseException as exc:
253
+ exception = exc
254
+ status = b"EXCEPTION"
255
+ pickled = pickle.dumps(exc, pickle.HIGHEST_PROTOCOL)
256
+
257
+ stdout.buffer.write(b"%s %d\n" % (status, len(pickled)))
258
+ stdout.buffer.write(pickled)
259
+
260
+ # Respect SIGTERM
261
+ if isinstance(exception, SystemExit):
262
+ raise exception
263
+
264
+
265
+ if __name__ == "__main__":
266
+ process_worker()
bioagent-bench/.venv/lib/python3.14/site-packages/anyio/to_thread.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ __all__ = (
4
+ "run_sync",
5
+ "current_default_thread_limiter",
6
+ )
7
+
8
+ import sys
9
+ from collections.abc import Callable
10
+ from typing import TypeVar
11
+ from warnings import warn
12
+
13
+ from ._core._eventloop import get_async_backend
14
+ from .abc import CapacityLimiter
15
+
16
+ if sys.version_info >= (3, 11):
17
+ from typing import TypeVarTuple, Unpack
18
+ else:
19
+ from typing_extensions import TypeVarTuple, Unpack
20
+
21
+ T_Retval = TypeVar("T_Retval")
22
+ PosArgsT = TypeVarTuple("PosArgsT")
23
+
24
+
25
+ async def run_sync(
26
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
27
+ *args: Unpack[PosArgsT],
28
+ abandon_on_cancel: bool = False,
29
+ cancellable: bool | None = None,
30
+ limiter: CapacityLimiter | None = None,
31
+ ) -> T_Retval:
32
+ """
33
+ Call the given function with the given arguments in a worker thread.
34
+
35
+ If the ``abandon_on_cancel`` option is enabled and the task waiting for its
36
+ completion is cancelled, the thread will still run its course but its
37
+ return value (or any raised exception) will be ignored.
38
+
39
+ :param func: a callable
40
+ :param args: positional arguments for the callable
41
+ :param abandon_on_cancel: ``True`` to abandon the thread (leaving it to run
42
+ unchecked on own) if the host task is cancelled, ``False`` to ignore
43
+ cancellations in the host task until the operation has completed in the worker
44
+ thread
45
+ :param cancellable: deprecated alias of ``abandon_on_cancel``; will override
46
+ ``abandon_on_cancel`` if both parameters are passed
47
+ :param limiter: capacity limiter to use to limit the total amount of threads running
48
+ (if omitted, the default limiter is used)
49
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
50
+ current thread
51
+ :return: an awaitable that yields the return value of the function.
52
+
53
+ """
54
+ if cancellable is not None:
55
+ abandon_on_cancel = cancellable
56
+ warn(
57
+ "The `cancellable=` keyword argument to `anyio.to_thread.run_sync` is "
58
+ "deprecated since AnyIO 4.1.0; use `abandon_on_cancel=` instead",
59
+ DeprecationWarning,
60
+ stacklevel=2,
61
+ )
62
+
63
+ return await get_async_backend().run_sync_in_worker_thread(
64
+ func, args, abandon_on_cancel=abandon_on_cancel, limiter=limiter
65
+ )
66
+
67
+
68
+ def current_default_thread_limiter() -> CapacityLimiter:
69
+ """
70
+ Return the capacity limiter that is used by default to limit the number of
71
+ concurrent threads.
72
+
73
+ :return: a capacity limiter object
74
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
75
+ current thread
76
+
77
+ """
78
+ return get_async_backend().current_default_thread_limiter()
bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ uv
bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/METADATA ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: certifi
3
+ Version: 2026.4.22
4
+ Summary: Python package for providing Mozilla's CA Bundle.
5
+ Home-page: https://github.com/certifi/python-certifi
6
+ Author: Kenneth Reitz
7
+ Author-email: me@kennethreitz.com
8
+ License: MPL-2.0
9
+ Project-URL: Source, https://github.com/certifi/python-certifi
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
13
+ Classifier: Natural Language :: English
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.7
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Requires-Python: >=3.7
26
+ License-File: LICENSE
27
+ Dynamic: author
28
+ Dynamic: author-email
29
+ Dynamic: classifier
30
+ Dynamic: description
31
+ Dynamic: home-page
32
+ Dynamic: license
33
+ Dynamic: license-file
34
+ Dynamic: project-url
35
+ Dynamic: requires-python
36
+ Dynamic: summary
37
+
38
+ Certifi: Python SSL Certificates
39
+ ================================
40
+
41
+ Certifi provides Mozilla's carefully curated collection of Root Certificates for
42
+ validating the trustworthiness of SSL certificates while verifying the identity
43
+ of TLS hosts. It has been extracted from the `Requests`_ project.
44
+
45
+ Installation
46
+ ------------
47
+
48
+ ``certifi`` is available on PyPI. Simply install it with ``pip``::
49
+
50
+ $ pip install certifi
51
+
52
+ Usage
53
+ -----
54
+
55
+ To reference the installed certificate authority (CA) bundle, you can use the
56
+ built-in function::
57
+
58
+ >>> import certifi
59
+
60
+ >>> certifi.where()
61
+ '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem'
62
+
63
+ Or from the command line::
64
+
65
+ $ python -m certifi
66
+ /usr/local/lib/python3.7/site-packages/certifi/cacert.pem
67
+
68
+ Enjoy!
69
+
70
+ .. _`Requests`: https://requests.readthedocs.io/en/master/
71
+
72
+ Addition/Removal of Certificates
73
+ --------------------------------
74
+
75
+ Certifi does not support any addition/removal or other modification of the
76
+ CA trust store content. This project is intended to provide a reliable and
77
+ highly portable root of trust to python deployments. Look to upstream projects
78
+ for methods to use alternate trust.
bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/RECORD ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ certifi-2026.4.22.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
2
+ certifi-2026.4.22.dist-info/METADATA,sha256=Ttb_6cy-0FBGq3v_ICTNPKcXKVs2i-0f4gpz42W8QVo,2474
3
+ certifi-2026.4.22.dist-info/RECORD,,
4
+ certifi-2026.4.22.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ certifi-2026.4.22.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
6
+ certifi-2026.4.22.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989
7
+ certifi-2026.4.22.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8
8
+ certifi/__init__.py,sha256=iBJYWtxRGHMaO1S73pWYpFn962WQ4ldof2GkfMSREJM,94
9
+ certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243
10
+ certifi/cacert.pem,sha256=Fr4_b-sVQIGV3P46oade-dty9ka5brvv3Gj1YlX3mfg,238641
11
+ certifi/core.py,sha256=XFXycndG5pf37ayeF8N32HUuDafsyhkVMbO4BAPWHa0,3394
12
+ certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/REQUESTED ADDED
File without changes
bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ This package contains a modified version of ca-bundle.crt:
2
+
3
+ ca-bundle.crt -- Bundle of CA Root Certificates
4
+
5
+ This is a bundle of X.509 certificates of public Certificate Authorities
6
+ (CA). These were automatically extracted from Mozilla's root certificates
7
+ file (certdata.txt). This file can be found in the mozilla source tree:
8
+ https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt
9
+ It contains the certificates in PEM format and therefore
10
+ can be directly used with curl / libcurl / php_curl, or with
11
+ an Apache+mod_ssl webserver for SSL client authentication.
12
+ Just configure this file as the SSLCACertificateFile.#
13
+
14
+ ***** BEGIN LICENSE BLOCK *****
15
+ This Source Code Form is subject to the terms of the Mozilla Public License,
16
+ v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
17
+ one at http://mozilla.org/MPL/2.0/.
18
+
19
+ ***** END LICENSE BLOCK *****
20
+ @(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $
bioagent-bench/.venv/lib/python3.14/site-packages/certifi-2026.4.22.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ certifi