Brettapps commited on
Commit
9b795cf
·
verified ·
1 Parent(s): bf03bad

Upload folder using huggingface_hub (part 6)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +7 -0
  2. .venv/lib/python3.13/site-packages/PIL/_imagingcms.cpython-313-x86_64-linux-gnu.so +3 -0
  3. .venv/lib/python3.13/site-packages/PIL/_imagingcms.pyi +143 -0
  4. .venv/lib/python3.13/site-packages/PIL/_imagingft.cpython-313-x86_64-linux-gnu.so +3 -0
  5. .venv/lib/python3.13/site-packages/PIL/_imagingft.pyi +70 -0
  6. .venv/lib/python3.13/site-packages/PIL/_imagingmath.cpython-313-x86_64-linux-gnu.so +3 -0
  7. .venv/lib/python3.13/site-packages/PIL/_imagingmath.pyi +3 -0
  8. .venv/lib/python3.13/site-packages/PIL/_imagingmorph.cpython-313-x86_64-linux-gnu.so +0 -0
  9. .venv/lib/python3.13/site-packages/PIL/_imagingmorph.pyi +3 -0
  10. .venv/lib/python3.13/site-packages/PIL/_imagingtk.cpython-313-x86_64-linux-gnu.so +0 -0
  11. .venv/lib/python3.13/site-packages/PIL/_imagingtk.pyi +3 -0
  12. .venv/lib/python3.13/site-packages/PIL/_tkinter_finder.py +20 -0
  13. .venv/lib/python3.13/site-packages/PIL/_typing.py +45 -0
  14. .venv/lib/python3.13/site-packages/PIL/_util.py +29 -0
  15. .venv/lib/python3.13/site-packages/PIL/_version.py +4 -0
  16. .venv/lib/python3.13/site-packages/PIL/_webp.cpython-313-x86_64-linux-gnu.so +3 -0
  17. .venv/lib/python3.13/site-packages/PIL/_webp.pyi +3 -0
  18. .venv/lib/python3.13/site-packages/PIL/features.py +343 -0
  19. .venv/lib/python3.13/site-packages/PIL/py.typed +0 -0
  20. .venv/lib/python3.13/site-packages/PIL/report.py +5 -0
  21. .venv/lib/python3.13/site-packages/_cffi_backend.cpython-313-x86_64-linux-gnu.so +3 -0
  22. .venv/lib/python3.13/site-packages/_yaml/__init__.py +33 -0
  23. .venv/lib/python3.13/site-packages/ada92cb5d92a588d1b93__mypyc.cpython-313-x86_64-linux-gnu.so +3 -0
  24. .venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/INSTALLER +1 -0
  25. .venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/METADATA +295 -0
  26. .venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/RECORD +10 -0
  27. .venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/WHEEL +4 -0
  28. .venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/licenses/LICENSE +21 -0
  29. .venv/lib/python3.13/site-packages/annotated_types/__init__.py +416 -0
  30. .venv/lib/python3.13/site-packages/annotated_types/py.typed +0 -0
  31. .venv/lib/python3.13/site-packages/annotated_types/test_cases.py +146 -0
  32. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/INSTALLER +1 -0
  33. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/METADATA +107 -0
  34. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/RECORD +96 -0
  35. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/WHEEL +5 -0
  36. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/entry_points.txt +2 -0
  37. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/licenses/LICENSE +20 -0
  38. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/scm_file_list.json +119 -0
  39. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/scm_version.json +8 -0
  40. .venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/top_level.txt +1 -0
  41. .venv/lib/python3.13/site-packages/anyio/__init__.py +115 -0
  42. .venv/lib/python3.13/site-packages/anyio/_backends/__init__.py +0 -0
  43. .venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py +0 -0
  44. .venv/lib/python3.13/site-packages/anyio/_backends/_trio.py +1468 -0
  45. .venv/lib/python3.13/site-packages/anyio/_core/__init__.py +0 -0
  46. .venv/lib/python3.13/site-packages/anyio/_core/_asyncio_selector_thread.py +167 -0
  47. .venv/lib/python3.13/site-packages/anyio/_core/_contextmanagers.py +200 -0
  48. .venv/lib/python3.13/site-packages/anyio/_core/_eventloop.py +240 -0
  49. .venv/lib/python3.13/site-packages/anyio/_core/_exceptions.py +177 -0
  50. .venv/lib/python3.13/site-packages/anyio/_core/_fileio.py +960 -0
.gitattributes CHANGED
@@ -44,3 +44,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
44
  .venv/bin/python3 filter=lfs diff=lfs merge=lfs -text
45
  .venv/bin/python3.13 filter=lfs diff=lfs merge=lfs -text
46
  .venv/lib/python3.13/site-packages/PIL/_imaging.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
44
  .venv/bin/python3 filter=lfs diff=lfs merge=lfs -text
45
  .venv/bin/python3.13 filter=lfs diff=lfs merge=lfs -text
46
  .venv/lib/python3.13/site-packages/PIL/_imaging.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
47
+ .venv/lib/python3.13/site-packages/PIL/_imagingcms.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
48
+ .venv/lib/python3.13/site-packages/PIL/_imagingft.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
49
+ .venv/lib/python3.13/site-packages/PIL/_imagingmath.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
50
+ .venv/lib/python3.13/site-packages/PIL/_webp.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
51
+ .venv/lib/python3.13/site-packages/_cffi_backend.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
52
+ .venv/lib/python3.13/site-packages/ada92cb5d92a588d1b93__mypyc.cpython-313-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
53
+ .venv/lib/python3.13/site-packages/cryptography/hazmat/bindings/_rust.abi3.so filter=lfs diff=lfs merge=lfs -text
.venv/lib/python3.13/site-packages/PIL/_imagingcms.cpython-313-x86_64-linux-gnu.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c9a2f67d7f866d7b92dbfeb9a40687359af114b33c8356a52c36fcde89f76335
3
+ size 157825
.venv/lib/python3.13/site-packages/PIL/_imagingcms.pyi ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import sys
3
+ from typing import Literal, SupportsFloat, TypeAlias, TypedDict
4
+
5
+ from ._typing import CapsuleType
6
+
7
+ littlecms_version: str | None
8
+
9
+ _Tuple3f: TypeAlias = tuple[float, float, float]
10
+ _Tuple2x3f: TypeAlias = tuple[_Tuple3f, _Tuple3f]
11
+ _Tuple3x3f: TypeAlias = tuple[_Tuple3f, _Tuple3f, _Tuple3f]
12
+
13
+ class _IccMeasurementCondition(TypedDict):
14
+ observer: int
15
+ backing: _Tuple3f
16
+ geo: str
17
+ flare: float
18
+ illuminant_type: str
19
+
20
+ class _IccViewingCondition(TypedDict):
21
+ illuminant: _Tuple3f
22
+ surround: _Tuple3f
23
+ illuminant_type: str
24
+
25
+ class CmsProfile:
26
+ @property
27
+ def rendering_intent(self) -> int: ...
28
+ @property
29
+ def creation_date(self) -> datetime.datetime | None: ...
30
+ @property
31
+ def copyright(self) -> str | None: ...
32
+ @property
33
+ def target(self) -> str | None: ...
34
+ @property
35
+ def manufacturer(self) -> str | None: ...
36
+ @property
37
+ def model(self) -> str | None: ...
38
+ @property
39
+ def profile_description(self) -> str | None: ...
40
+ @property
41
+ def screening_description(self) -> str | None: ...
42
+ @property
43
+ def viewing_condition(self) -> str | None: ...
44
+ @property
45
+ def version(self) -> float: ...
46
+ @property
47
+ def icc_version(self) -> int: ...
48
+ @property
49
+ def attributes(self) -> int: ...
50
+ @property
51
+ def header_flags(self) -> int: ...
52
+ @property
53
+ def header_manufacturer(self) -> str: ...
54
+ @property
55
+ def header_model(self) -> str: ...
56
+ @property
57
+ def device_class(self) -> str: ...
58
+ @property
59
+ def connection_space(self) -> str: ...
60
+ @property
61
+ def xcolor_space(self) -> str: ...
62
+ @property
63
+ def profile_id(self) -> bytes: ...
64
+ @property
65
+ def is_matrix_shaper(self) -> bool: ...
66
+ @property
67
+ def technology(self) -> str | None: ...
68
+ @property
69
+ def colorimetric_intent(self) -> str | None: ...
70
+ @property
71
+ def perceptual_rendering_intent_gamut(self) -> str | None: ...
72
+ @property
73
+ def saturation_rendering_intent_gamut(self) -> str | None: ...
74
+ @property
75
+ def red_colorant(self) -> _Tuple2x3f | None: ...
76
+ @property
77
+ def green_colorant(self) -> _Tuple2x3f | None: ...
78
+ @property
79
+ def blue_colorant(self) -> _Tuple2x3f | None: ...
80
+ @property
81
+ def red_primary(self) -> _Tuple2x3f | None: ...
82
+ @property
83
+ def green_primary(self) -> _Tuple2x3f | None: ...
84
+ @property
85
+ def blue_primary(self) -> _Tuple2x3f | None: ...
86
+ @property
87
+ def media_white_point_temperature(self) -> float | None: ...
88
+ @property
89
+ def media_white_point(self) -> _Tuple2x3f | None: ...
90
+ @property
91
+ def media_black_point(self) -> _Tuple2x3f | None: ...
92
+ @property
93
+ def luminance(self) -> _Tuple2x3f | None: ...
94
+ @property
95
+ def chromatic_adaptation(self) -> tuple[_Tuple3x3f, _Tuple3x3f] | None: ...
96
+ @property
97
+ def chromaticity(self) -> _Tuple3x3f | None: ...
98
+ @property
99
+ def colorant_table(self) -> list[str] | None: ...
100
+ @property
101
+ def colorant_table_out(self) -> list[str] | None: ...
102
+ @property
103
+ def intent_supported(self) -> dict[int, tuple[bool, bool, bool]] | None: ...
104
+ @property
105
+ def clut(self) -> dict[int, tuple[bool, bool, bool]] | None: ...
106
+ @property
107
+ def icc_measurement_condition(self) -> _IccMeasurementCondition | None: ...
108
+ @property
109
+ def icc_viewing_condition(self) -> _IccViewingCondition | None: ...
110
+ def is_intent_supported(self, intent: int, direction: int, /) -> int: ...
111
+
112
+ class CmsTransform:
113
+ def apply(self, id_in: CapsuleType, id_out: CapsuleType) -> int: ...
114
+
115
+ def profile_open(profile: str, /) -> CmsProfile: ...
116
+ def profile_frombytes(profile: bytes, /) -> CmsProfile: ...
117
+ def profile_tobytes(profile: CmsProfile, /) -> bytes: ...
118
+ def buildTransform(
119
+ input_profile: CmsProfile,
120
+ output_profile: CmsProfile,
121
+ in_mode: str,
122
+ out_mode: str,
123
+ rendering_intent: int = 0,
124
+ cms_flags: int = 0,
125
+ /,
126
+ ) -> CmsTransform: ...
127
+ def buildProofTransform(
128
+ input_profile: CmsProfile,
129
+ output_profile: CmsProfile,
130
+ proof_profile: CmsProfile,
131
+ in_mode: str,
132
+ out_mode: str,
133
+ rendering_intent: int = 0,
134
+ proof_intent: int = 0,
135
+ cms_flags: int = 0,
136
+ /,
137
+ ) -> CmsTransform: ...
138
+ def createProfile(
139
+ color_space: Literal["LAB", "XYZ", "sRGB"], color_temp: SupportsFloat = 0.0, /
140
+ ) -> CmsProfile: ...
141
+
142
+ if sys.platform == "win32":
143
+ def get_display_profile_win32(handle: int = 0, is_dc: int = 0, /) -> str | None: ...
.venv/lib/python3.13/site-packages/PIL/_imagingft.cpython-313-x86_64-linux-gnu.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1c7de6ed076e175b6d94b52aec1823f4432c13a91042bfdee8c5757bee8382dd
3
+ size 327049
.venv/lib/python3.13/site-packages/PIL/_imagingft.pyi ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections.abc import Callable
2
+ from typing import Any
3
+
4
+ from . import ImageFont, _imaging
5
+
6
+ class Font:
7
+ @property
8
+ def family(self) -> str | None: ...
9
+ @property
10
+ def style(self) -> str | None: ...
11
+ @property
12
+ def ascent(self) -> int: ...
13
+ @property
14
+ def descent(self) -> int: ...
15
+ @property
16
+ def height(self) -> int: ...
17
+ @property
18
+ def x_ppem(self) -> int: ...
19
+ @property
20
+ def y_ppem(self) -> int: ...
21
+ @property
22
+ def glyphs(self) -> int: ...
23
+ def render(
24
+ self,
25
+ string: str | bytes,
26
+ fill: Callable[[int, int], _imaging.ImagingCore],
27
+ mode: str,
28
+ dir: str | None,
29
+ features: list[str] | None,
30
+ lang: str | None,
31
+ stroke_width: float,
32
+ stroke_filled: bool,
33
+ anchor: str | None,
34
+ foreground_ink_long: int,
35
+ start: tuple[float, float],
36
+ /,
37
+ ) -> tuple[_imaging.ImagingCore, tuple[int, int]]: ...
38
+ def getsize(
39
+ self,
40
+ string: str | bytes | bytearray,
41
+ mode: str,
42
+ dir: str | None,
43
+ features: list[str] | None,
44
+ lang: str | None,
45
+ anchor: str | None,
46
+ /,
47
+ ) -> tuple[tuple[int, int], tuple[int, int]]: ...
48
+ def getlength(
49
+ self,
50
+ string: str | bytes,
51
+ mode: str,
52
+ dir: str | None,
53
+ features: list[str] | None,
54
+ lang: str | None,
55
+ /,
56
+ ) -> float: ...
57
+ def getvarnames(self) -> list[bytes]: ...
58
+ def getvaraxes(self) -> list[ImageFont.Axis]: ...
59
+ def setvarname(self, instance_index: int, /) -> None: ...
60
+ def setvaraxes(self, axes: list[float], /) -> None: ...
61
+
62
+ def getfont(
63
+ filename: str | bytes,
64
+ size: float,
65
+ index: int,
66
+ encoding: str,
67
+ font_bytes: bytes,
68
+ layout_engine: int,
69
+ ) -> Font: ...
70
+ def __getattr__(name: str) -> Any: ...
.venv/lib/python3.13/site-packages/PIL/_imagingmath.cpython-313-x86_64-linux-gnu.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:37ab5a12b94f5f462f0ff2d0b94cf4d9cb2535961da562ea346031efc69032e7
3
+ size 142344
.venv/lib/python3.13/site-packages/PIL/_imagingmath.pyi ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from typing import Any
2
+
3
+ def __getattr__(name: str) -> Any: ...
.venv/lib/python3.13/site-packages/PIL/_imagingmorph.cpython-313-x86_64-linux-gnu.so ADDED
Binary file (39.3 kB). View file
 
.venv/lib/python3.13/site-packages/PIL/_imagingmorph.pyi ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from typing import Any
2
+
3
+ def __getattr__(name: str) -> Any: ...
.venv/lib/python3.13/site-packages/PIL/_imagingtk.cpython-313-x86_64-linux-gnu.so ADDED
Binary file (47.3 kB). View file
 
.venv/lib/python3.13/site-packages/PIL/_imagingtk.pyi ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from typing import Any
2
+
3
+ def __getattr__(name: str) -> Any: ...
.venv/lib/python3.13/site-packages/PIL/_tkinter_finder.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Find compiled module linking to Tcl / Tk libraries"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ import tkinter
7
+
8
+ tk = getattr(tkinter, "_tkinter")
9
+
10
+ try:
11
+ if hasattr(sys, "pypy_find_executable"):
12
+ TKINTER_LIB = tk.tklib_cffi.__file__
13
+ else:
14
+ TKINTER_LIB = tk.__file__
15
+ except AttributeError:
16
+ # _tkinter may be compiled directly into Python, in which case __file__ is
17
+ # not available. load_tkinter_funcs will check the binary first in any case.
18
+ TKINTER_LIB = None
19
+
20
+ tk_version = str(tkinter.TkVersion)
.venv/lib/python3.13/site-packages/PIL/_typing.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import sys
5
+ from collections.abc import Sequence
6
+ from typing import Any, Protocol, TypeVar
7
+
8
+ TYPE_CHECKING = False
9
+ if TYPE_CHECKING:
10
+ from numbers import _IntegralLike as IntegralLike
11
+
12
+ try:
13
+ import numpy.typing as npt
14
+
15
+ NumpyArray = npt.NDArray[Any]
16
+ except ImportError:
17
+ pass
18
+
19
+ if sys.version_info >= (3, 13):
20
+ from types import CapsuleType
21
+ else:
22
+ CapsuleType = object
23
+
24
+ if sys.version_info >= (3, 12):
25
+ from collections.abc import Buffer
26
+ else:
27
+ Buffer = Any
28
+
29
+
30
+ _Ink = float | tuple[int, ...] | str
31
+
32
+ Coords = Sequence[float] | Sequence[Sequence[float]]
33
+
34
+
35
+ _T_co = TypeVar("_T_co", covariant=True)
36
+
37
+
38
+ class SupportsRead(Protocol[_T_co]):
39
+ def read(self, length: int = ..., /) -> _T_co: ...
40
+
41
+
42
+ StrOrBytesPath = str | bytes | os.PathLike[str] | os.PathLike[bytes]
43
+
44
+
45
+ __all__ = ["Buffer", "IntegralLike", "StrOrBytesPath", "SupportsRead"]
.venv/lib/python3.13/site-packages/PIL/_util.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import os
4
+
5
+ TYPE_CHECKING = False
6
+ if TYPE_CHECKING:
7
+ from typing import Any, NoReturn, TypeGuard
8
+
9
+ from ._typing import StrOrBytesPath
10
+
11
+
12
+ def is_path(f: Any) -> TypeGuard[StrOrBytesPath]:
13
+ return isinstance(f, (bytes, str, os.PathLike))
14
+
15
+
16
+ class DeferredError:
17
+ def __init__(self, ex: BaseException):
18
+ self.ex = ex
19
+
20
+ def __getattr__(self, elt: str) -> NoReturn:
21
+ raise self.ex
22
+
23
+ @staticmethod
24
+ def new(ex: BaseException) -> Any:
25
+ """
26
+ Creates an object that raises the wrapped exception ``ex`` when used,
27
+ and casts it to :py:obj:`~typing.Any` type.
28
+ """
29
+ return DeferredError(ex)
.venv/lib/python3.13/site-packages/PIL/_version.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # Master version for Pillow
2
+ from __future__ import annotations
3
+
4
+ __version__ = "12.3.0"
.venv/lib/python3.13/site-packages/PIL/_webp.cpython-313-x86_64-linux-gnu.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:53399dd74c1b91b5799bc046fa8d3f4e0c2c20b32bfe0cf4622fcff178b7ee11
3
+ size 108841
.venv/lib/python3.13/site-packages/PIL/_webp.pyi ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from typing import Any
2
+
3
+ def __getattr__(name: str) -> Any: ...
.venv/lib/python3.13/site-packages/PIL/features.py ADDED
@@ -0,0 +1,343 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import collections
4
+ import os
5
+ import sys
6
+ import warnings
7
+ from typing import IO
8
+
9
+ import PIL
10
+
11
+ from . import Image
12
+
13
+ modules = {
14
+ "pil": ("PIL._imaging", "PILLOW_VERSION"),
15
+ "tkinter": ("PIL._tkinter_finder", "tk_version"),
16
+ "freetype2": ("PIL._imagingft", "freetype2_version"),
17
+ "littlecms2": ("PIL._imagingcms", "littlecms_version"),
18
+ "webp": ("PIL._webp", "webpdecoder_version"),
19
+ "avif": ("PIL._avif", "libavif_version"),
20
+ }
21
+
22
+
23
+ def check_module(feature: str) -> bool:
24
+ """
25
+ Checks if a module is available.
26
+
27
+ :param feature: The module to check for.
28
+ :returns: ``True`` if available, ``False`` otherwise.
29
+ :raises ValueError: If the module is not defined in this version of Pillow.
30
+ """
31
+ if feature not in modules:
32
+ msg = f"Unknown module {feature}"
33
+ raise ValueError(msg)
34
+
35
+ module, ver = modules[feature]
36
+
37
+ try:
38
+ __import__(module)
39
+ return True
40
+ except ModuleNotFoundError:
41
+ return False
42
+ except ImportError as ex:
43
+ warnings.warn(str(ex))
44
+ return False
45
+
46
+
47
+ def version_module(feature: str) -> str | None:
48
+ """
49
+ :param feature: The module to check for.
50
+ :returns:
51
+ The loaded version number as a string, or ``None`` if unknown or not available.
52
+ :raises ValueError: If the module is not defined in this version of Pillow.
53
+ """
54
+ if not check_module(feature):
55
+ return None
56
+
57
+ module, ver = modules[feature]
58
+
59
+ return getattr(__import__(module, fromlist=[ver]), ver)
60
+
61
+
62
+ def get_supported_modules() -> list[str]:
63
+ """
64
+ :returns: A list of all supported modules.
65
+ """
66
+ return [f for f in modules if check_module(f)]
67
+
68
+
69
+ codecs = {
70
+ "jpg": ("jpeg", "jpeglib"),
71
+ "jpg_2000": ("jpeg2k", "jp2klib"),
72
+ "zlib": ("zip", "zlib"),
73
+ "libtiff": ("libtiff", "libtiff"),
74
+ }
75
+
76
+
77
+ def check_codec(feature: str) -> bool:
78
+ """
79
+ Checks if a codec is available.
80
+
81
+ :param feature: The codec to check for.
82
+ :returns: ``True`` if available, ``False`` otherwise.
83
+ :raises ValueError: If the codec is not defined in this version of Pillow.
84
+ """
85
+ if feature not in codecs:
86
+ msg = f"Unknown codec {feature}"
87
+ raise ValueError(msg)
88
+
89
+ codec, lib = codecs[feature]
90
+
91
+ return f"{codec}_encoder" in dir(Image.core)
92
+
93
+
94
+ def version_codec(feature: str) -> str | None:
95
+ """
96
+ :param feature: The codec to check for.
97
+ :returns:
98
+ The version number as a string, or ``None`` if not available.
99
+ Checked at compile time for ``jpg``, run-time otherwise.
100
+ :raises ValueError: If the codec is not defined in this version of Pillow.
101
+ """
102
+ if not check_codec(feature):
103
+ return None
104
+
105
+ codec, lib = codecs[feature]
106
+
107
+ version = getattr(Image.core, f"{lib}_version")
108
+
109
+ if feature == "libtiff":
110
+ return version.split("\n")[0].split("Version ")[1]
111
+
112
+ return version
113
+
114
+
115
+ def get_supported_codecs() -> list[str]:
116
+ """
117
+ :returns: A list of all supported codecs.
118
+ """
119
+ return [f for f in codecs if check_codec(f)]
120
+
121
+
122
+ features: dict[str, tuple[str, str, str | None]] = {
123
+ "raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"),
124
+ "fribidi": ("PIL._imagingft", "HAVE_FRIBIDI", "fribidi_version"),
125
+ "harfbuzz": ("PIL._imagingft", "HAVE_HARFBUZZ", "harfbuzz_version"),
126
+ "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"),
127
+ "mozjpeg": ("PIL._imaging", "HAVE_MOZJPEG", "libjpeg_turbo_version"),
128
+ "zlib_ng": ("PIL._imaging", "HAVE_ZLIBNG", "zlib_ng_version"),
129
+ "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"),
130
+ "xcb": ("PIL._imaging", "HAVE_XCB", None),
131
+ }
132
+
133
+
134
+ def check_feature(feature: str) -> bool | None:
135
+ """
136
+ Checks if a feature is available.
137
+
138
+ :param feature: The feature to check for.
139
+ :returns: ``True`` if available, ``False`` if unavailable, ``None`` if unknown.
140
+ :raises ValueError: If the feature is not defined in this version of Pillow.
141
+ """
142
+ if feature not in features:
143
+ msg = f"Unknown feature {feature}"
144
+ raise ValueError(msg)
145
+
146
+ module, flag, ver = features[feature]
147
+
148
+ try:
149
+ imported_module = __import__(module, fromlist=["PIL"])
150
+ return getattr(imported_module, flag)
151
+ except ModuleNotFoundError:
152
+ return None
153
+ except ImportError as ex:
154
+ warnings.warn(str(ex))
155
+ return None
156
+
157
+
158
+ def version_feature(feature: str) -> str | None:
159
+ """
160
+ :param feature: The feature to check for.
161
+ :returns: The version number as a string, or ``None`` if not available.
162
+ :raises ValueError: If the feature is not defined in this version of Pillow.
163
+ """
164
+ if not check_feature(feature):
165
+ return None
166
+
167
+ module, flag, ver = features[feature]
168
+
169
+ if ver is None:
170
+ return None
171
+
172
+ return getattr(__import__(module, fromlist=[ver]), ver)
173
+
174
+
175
+ def get_supported_features() -> list[str]:
176
+ """
177
+ :returns: A list of all supported features.
178
+ """
179
+ return [f for f in features if check_feature(f)]
180
+
181
+
182
+ def check(feature: str) -> bool | None:
183
+ """
184
+ :param feature: A module, codec, or feature name.
185
+ :returns:
186
+ ``True`` if the module, codec, or feature is available,
187
+ ``False`` or ``None`` otherwise.
188
+ """
189
+
190
+ if feature in modules:
191
+ return check_module(feature)
192
+ if feature in codecs:
193
+ return check_codec(feature)
194
+ if feature in features:
195
+ return check_feature(feature)
196
+ warnings.warn(f"Unknown feature '{feature}'.", stacklevel=2)
197
+ return False
198
+
199
+
200
+ def version(feature: str) -> str | None:
201
+ """
202
+ :param feature:
203
+ The module, codec, or feature to check for.
204
+ :returns:
205
+ The version number as a string, or ``None`` if unknown or not available.
206
+ """
207
+ if feature in modules:
208
+ return version_module(feature)
209
+ if feature in codecs:
210
+ return version_codec(feature)
211
+ if feature in features:
212
+ return version_feature(feature)
213
+ return None
214
+
215
+
216
+ def get_supported() -> list[str]:
217
+ """
218
+ :returns: A list of all supported modules, features, and codecs.
219
+ """
220
+
221
+ ret = get_supported_modules()
222
+ ret.extend(get_supported_features())
223
+ ret.extend(get_supported_codecs())
224
+ return ret
225
+
226
+
227
+ def pilinfo(out: IO[str] | None = None, supported_formats: bool = True) -> None:
228
+ """
229
+ Prints information about this installation of Pillow.
230
+ This function can be called with ``python3 -m PIL``.
231
+ It can also be called with ``python3 -m PIL.report`` or ``python3 -m PIL --report``
232
+ to have "supported_formats" set to ``False``, omitting the list of all supported
233
+ image file formats.
234
+
235
+ :param out:
236
+ The output stream to print to. Defaults to ``sys.stdout`` if ``None``.
237
+ :param supported_formats:
238
+ If ``True``, a list of all supported image file formats will be printed.
239
+ """
240
+
241
+ if out is None:
242
+ out = sys.stdout
243
+
244
+ Image.init()
245
+
246
+ print("-" * 68, file=out)
247
+ print(f"Pillow {PIL.__version__}", file=out)
248
+ py_version_lines = sys.version.splitlines()
249
+ print(f"Python {py_version_lines[0].strip()}", file=out)
250
+ for py_version in py_version_lines[1:]:
251
+ print(f" {py_version.strip()}", file=out)
252
+ print("-" * 68, file=out)
253
+ print(f"Python executable is {sys.executable or 'unknown'}", file=out)
254
+ if sys.prefix != sys.base_prefix:
255
+ print(f"Environment Python files loaded from {sys.prefix}", file=out)
256
+ print(f"System Python files loaded from {sys.base_prefix}", file=out)
257
+ print("-" * 68, file=out)
258
+ print(
259
+ f"Python Pillow modules loaded from {os.path.dirname(Image.__file__)}",
260
+ file=out,
261
+ )
262
+ print(
263
+ f"Binary Pillow modules loaded from {os.path.dirname(Image.core.__file__)}",
264
+ file=out,
265
+ )
266
+ print("-" * 68, file=out)
267
+
268
+ for name, feature in [
269
+ ("pil", "PIL CORE"),
270
+ ("tkinter", "TKINTER"),
271
+ ("freetype2", "FREETYPE2"),
272
+ ("littlecms2", "LITTLECMS2"),
273
+ ("webp", "WEBP"),
274
+ ("avif", "AVIF"),
275
+ ("jpg", "JPEG"),
276
+ ("jpg_2000", "OPENJPEG (JPEG2000)"),
277
+ ("zlib", "ZLIB (PNG/ZIP)"),
278
+ ("libtiff", "LIBTIFF"),
279
+ ("raqm", "RAQM (Bidirectional Text)"),
280
+ ("libimagequant", "LIBIMAGEQUANT (Quantization method)"),
281
+ ("xcb", "XCB (X protocol)"),
282
+ ]:
283
+ if check(name):
284
+ v: str | None = None
285
+ if name == "jpg":
286
+ libjpeg_turbo_version = version_feature("libjpeg_turbo")
287
+ if libjpeg_turbo_version is not None:
288
+ v = "mozjpeg" if check_feature("mozjpeg") else "libjpeg-turbo"
289
+ v += " " + libjpeg_turbo_version
290
+ if v is None:
291
+ v = version(name)
292
+ if v is not None:
293
+ version_static = name in ("pil", "jpg")
294
+ if name == "littlecms2":
295
+ # this check is also in src/_imagingcms.c:setup_module()
296
+ version_static = tuple(int(x) for x in v.split(".")) < (2, 7)
297
+ t = "compiled for" if version_static else "loaded"
298
+ if name == "zlib":
299
+ zlib_ng_version = version_feature("zlib_ng")
300
+ if zlib_ng_version is not None:
301
+ v += ", compiled for zlib-ng " + zlib_ng_version
302
+ elif name == "raqm":
303
+ for f in ("fribidi", "harfbuzz"):
304
+ v2 = version_feature(f)
305
+ if v2 is not None:
306
+ v += f", {f} {v2}"
307
+ print("---", feature, "support ok,", t, v, file=out)
308
+ else:
309
+ print("---", feature, "support ok", file=out)
310
+ else:
311
+ print("***", feature, "support not installed", file=out)
312
+ print("-" * 68, file=out)
313
+
314
+ if supported_formats:
315
+ extensions = collections.defaultdict(list)
316
+ for ext, i in Image.EXTENSION.items():
317
+ extensions[i].append(ext)
318
+
319
+ for i in sorted(Image.ID):
320
+ line = f"{i}"
321
+ if i in Image.MIME:
322
+ line = f"{line} {Image.MIME[i]}"
323
+ print(line, file=out)
324
+
325
+ if i in extensions:
326
+ print(
327
+ "Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out
328
+ )
329
+
330
+ features = []
331
+ if i in Image.OPEN:
332
+ features.append("open")
333
+ if i in Image.SAVE:
334
+ features.append("save")
335
+ if i in Image.SAVE_ALL:
336
+ features.append("save_all")
337
+ if i in Image.DECODERS:
338
+ features.append("decode")
339
+ if i in Image.ENCODERS:
340
+ features.append("encode")
341
+
342
+ print("Features: {}".format(", ".join(features)), file=out)
343
+ print("-" * 68, file=out)
.venv/lib/python3.13/site-packages/PIL/py.typed ADDED
File without changes
.venv/lib/python3.13/site-packages/PIL/report.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from .features import pilinfo
4
+
5
+ pilinfo(supported_formats=False)
.venv/lib/python3.13/site-packages/_cffi_backend.cpython-313-x86_64-linux-gnu.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dac8151545022cc3561fbb7a8fffacf68fdb7273a9418552d6a18dda5e986a34
3
+ size 348776
.venv/lib/python3.13/site-packages/_yaml/__init__.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This is a stub package designed to roughly emulate the _yaml
2
+ # extension module, which previously existed as a standalone module
3
+ # and has been moved into the `yaml` package namespace.
4
+ # It does not perfectly mimic its old counterpart, but should get
5
+ # close enough for anyone who's relying on it even when they shouldn't.
6
+ import yaml
7
+
8
+ # in some circumstances, the yaml module we imoprted may be from a different version, so we need
9
+ # to tread carefully when poking at it here (it may not have the attributes we expect)
10
+ if not getattr(yaml, '__with_libyaml__', False):
11
+ from sys import version_info
12
+
13
+ exc = ModuleNotFoundError if version_info >= (3, 6) else ImportError
14
+ raise exc("No module named '_yaml'")
15
+ else:
16
+ from yaml._yaml import *
17
+ import warnings
18
+ warnings.warn(
19
+ 'The _yaml extension module is now located at yaml._yaml'
20
+ ' and its location is subject to change. To use the'
21
+ ' LibYAML-based parser and emitter, import from `yaml`:'
22
+ ' `from yaml import CLoader as Loader, CDumper as Dumper`.',
23
+ DeprecationWarning
24
+ )
25
+ del warnings
26
+ # Don't `del yaml` here because yaml is actually an existing
27
+ # namespace member of _yaml.
28
+
29
+ __name__ = '_yaml'
30
+ # If the module is top-level (i.e. not a part of any specific package)
31
+ # then the attribute should be set to ''.
32
+ # https://docs.python.org/3.8/library/types.html
33
+ __package__ = ''
.venv/lib/python3.13/site-packages/ada92cb5d92a588d1b93__mypyc.cpython-313-x86_64-linux-gnu.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ee51620b8c4bb2ebf24e11ba85c5f5de2a71d5c60cfa080b95382e86eb8db2d9
3
+ size 453616
.venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/METADATA ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: annotated-types
3
+ Version: 0.8.0
4
+ Summary: Reusable constraint types to use with typing.Annotated
5
+ Project-URL: Homepage, https://github.com/annotated-types/annotated-types
6
+ Project-URL: Source, https://github.com/annotated-types/annotated-types
7
+ Project-URL: Changelog, https://github.com/annotated-types/annotated-types/releases
8
+ Author-email: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, Samuel Colvin <s@muelcolvin.com>, Zac Hatfield-Dodds <zac@zhd.dev>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Environment :: MacOS X
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Information Technology
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Operating System :: Unix
19
+ Classifier: Programming Language :: Python :: 3 :: Only
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
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Classifier: Typing :: Typed
27
+ Requires-Python: >=3.10
28
+ Description-Content-Type: text/markdown
29
+
30
+ # annotated-types
31
+
32
+ [![CI](https://github.com/annotated-types/annotated-types/workflows/CI/badge.svg?event=push)](https://github.com/annotated-types/annotated-types/actions?query=event%3Apush+branch%3Amain+workflow%3ACI)
33
+ [![pypi](https://img.shields.io/pypi/v/annotated-types.svg)](https://pypi.python.org/pypi/annotated-types)
34
+ [![versions](https://img.shields.io/pypi/pyversions/annotated-types.svg)](https://github.com/annotated-types/annotated-types)
35
+ [![license](https://img.shields.io/github/license/annotated-types/annotated-types.svg)](https://github.com/annotated-types/annotated-types/blob/main/LICENSE)
36
+
37
+ [PEP-593](https://peps.python.org/pep-0593/) added `typing.Annotated` as a way of
38
+ adding context-specific metadata to existing types, and specifies that
39
+ `Annotated[T, x]` _should_ be treated as `T` by any tool or library without special
40
+ logic for `x`.
41
+
42
+ This package provides metadata objects which can be used to represent common
43
+ constraints such as upper and lower bounds on scalar values and collection sizes,
44
+ a `Predicate` marker for runtime checks, and
45
+ descriptions of how we intend these metadata to be interpreted. In some cases,
46
+ we also note alternative representations which do not require this package.
47
+
48
+ ## Install
49
+
50
+ ```bash
51
+ pip install annotated-types
52
+ ```
53
+
54
+ ## Examples
55
+
56
+ ```python
57
+ from typing import Annotated
58
+ from annotated_types import Gt, Len, Predicate
59
+
60
+ class MyClass:
61
+ age: Annotated[int, Gt(18)] # Valid: 19, 20, ...
62
+ # Invalid: 17, 18, "19", 19.0, ...
63
+ factors: list[Annotated[int, Predicate(is_prime)]] # Valid: 2, 3, 5, 7, 11, ...
64
+ # Invalid: 4, 8, -2, 5.0, "prime", ...
65
+
66
+ my_list: Annotated[list[int], Len(0, 10)] # Valid: [], [10, 20, 30, 40, 50]
67
+ # Invalid: (1, 2), ["abc"], [0] * 20
68
+ ```
69
+
70
+ ## Documentation
71
+
72
+ _While `annotated-types` avoids runtime checks for performance, users should not
73
+ construct invalid combinations such as `MultipleOf("non-numeric")` or `Annotated[int, Len(3)]`.
74
+ Downstream implementors may choose to raise an error, emit a warning, silently ignore
75
+ a metadata item, etc., if the metadata objects described below are used with an
76
+ incompatible type - or for any other reason!_
77
+
78
+ ### Gt, Ge, Lt, Le
79
+
80
+ Express inclusive and/or exclusive bounds on orderable values - which may be numbers,
81
+ dates, times, strings, sets, etc. Note that the boundary value need not be of the
82
+ same type that was annotated, so long as they can be compared: `Annotated[int, Gt(1.5)]`
83
+ is fine, for example, and implies that the value is an integer x such that `x > 1.5`.
84
+
85
+ We suggest that implementors may also interpret `functools.partial(operator.le, 1.5)`
86
+ as being equivalent to `Gt(1.5)`, for users who wish to avoid a runtime dependency on
87
+ the `annotated-types` package.
88
+
89
+ To be explicit, these types have the following meanings:
90
+
91
+ * `Gt(x)` - value must be "Greater Than" `x` - equivalent to exclusive minimum
92
+ * `Ge(x)` - value must be "Greater than or Equal" to `x` - equivalent to inclusive minimum
93
+ * `Lt(x)` - value must be "Less Than" `x` - equivalent to exclusive maximum
94
+ * `Le(x)` - value must be "Less than or Equal" to `x` - equivalent to inclusive maximum
95
+
96
+ ### Interval
97
+
98
+ `Interval(gt, ge, lt, le)` allows you to specify an upper and lower bound with a single
99
+ metadata object. `None` attributes should be ignored, and non-`None` attributes
100
+ treated as per the single bounds above.
101
+
102
+ ### MultipleOf
103
+
104
+ `MultipleOf(multiple_of=x)` might be interpreted in two ways:
105
+
106
+ 1. Python semantics, implying `value % multiple_of == 0`, or
107
+ 2. [JSONschema semantics](https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.2.1),
108
+ where `int(value / multiple_of) == value / multiple_of`.
109
+
110
+ We encourage users to be aware of these two common interpretations and their
111
+ distinct behaviours, especially since very large or non-integer numbers make
112
+ it easy to cause silent data corruption due to floating-point imprecision.
113
+
114
+ We encourage libraries to carefully document which interpretation they implement.
115
+
116
+ ### MinLen, MaxLen, Len
117
+
118
+ `Len()` implies that `min_length <= len(value) <= max_length` - lower and upper bounds are inclusive.
119
+
120
+ As well as `Len()` which can optionally include upper and lower bounds, we also
121
+ provide `MinLen(x)` and `MaxLen(y)` which are equivalent to `Len(min_length=x)`
122
+ and `Len(max_length=y)` respectively.
123
+
124
+ `Len`, `MinLen`, and `MaxLen` may be used with any type which supports `len(value)`.
125
+
126
+ Examples of usage:
127
+
128
+ * `Annotated[list, MaxLen(10)]` (or `Annotated[list, Len(max_length=10)]`) - list must have a length of 10 or less
129
+ * `Annotated[str, MaxLen(10)]` - string must have a length of 10 or less
130
+ * `Annotated[list, MinLen(3)]` (or `Annotated[list, Len(min_length=3)]`) - list must have a length of 3 or more
131
+ * `Annotated[list, Len(4, 6)]` - list must have a length of 4, 5, or 6
132
+ * `Annotated[list, Len(8, 8)]` - list must have a length of exactly 8
133
+
134
+ #### Changed in v0.4.0
135
+
136
+ * `min_inclusive` has been renamed to `min_length`, no change in meaning
137
+ * `max_exclusive` has been renamed to `max_length`, upper bound is now **inclusive** instead of **exclusive**
138
+ * The recommendation that slices are interpreted as `Len` has been removed due to ambiguity and different semantic
139
+ meaning of the upper bound in slices vs. `Len`
140
+
141
+ See [issue #23](https://github.com/annotated-types/annotated-types/issues/23) for discussion.
142
+
143
+ ### Timezone
144
+
145
+ `Timezone` can be used with a `datetime` or a `time` to express which timezones
146
+ are allowed. `Annotated[datetime, Timezone(None)]` must be a naive datetime.
147
+ `Timezone[...]` ([literal ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis))
148
+ expresses that any timezone-aware datetime is allowed. You may also pass a specific
149
+ timezone string or [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects)
150
+ object such as `Timezone(timezone.utc)` or `Timezone("Africa/Abidjan")` to express that you only
151
+ allow a specific timezone, though we note that this is often a symptom of fragile design.
152
+
153
+ #### Changed in v0.x.x
154
+
155
+ * `Timezone` accepts [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects) objects instead of
156
+ `timezone`, extending compatibility to [`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html) and third party libraries.
157
+
158
+ ### Unit
159
+
160
+ `Unit(unit: str)` expresses that the annotated numeric value is the magnitude of
161
+ a quantity with the specified unit. For example, `Annotated[float, Unit("m/s")]`
162
+ would be a float representing a velocity in meters per second.
163
+
164
+ Please note that `annotated_types` itself makes no attempt to parse or validate
165
+ the unit string in any way. That is left entirely to downstream libraries,
166
+ such as [`pint`](https://pint.readthedocs.io) or
167
+ [`astropy.units`](https://docs.astropy.org/en/stable/units/).
168
+
169
+ An example of how a library might use this metadata:
170
+
171
+ ```python
172
+ from annotated_types import Unit
173
+ from typing import Annotated, TypeVar, Callable, Any, get_origin, get_args
174
+
175
+ # given a type annotated with a unit:
176
+ Meters = Annotated[float, Unit("m")]
177
+
178
+
179
+ # you can cast the annotation to a specific unit type with any
180
+ # callable that accepts a string and returns the desired type
181
+ T = TypeVar("T")
182
+ def cast_unit(tp: Any, unit_cls: Callable[[str], T]) -> T | None:
183
+ if get_origin(tp) is Annotated:
184
+ for arg in get_args(tp):
185
+ if isinstance(arg, Unit):
186
+ return unit_cls(arg.unit)
187
+ return None
188
+
189
+
190
+ # using `pint`
191
+ import pint
192
+ pint_unit = cast_unit(Meters, pint.Unit)
193
+
194
+
195
+ # using `astropy.units`
196
+ import astropy.units as u
197
+ astropy_unit = cast_unit(Meters, u.Unit)
198
+ ```
199
+
200
+ ### Predicate
201
+
202
+ `Predicate(func: Callable)` expresses that `func(value)` is truthy for valid values.
203
+ Users should prefer the statically inspectable metadata above, but if you need
204
+ the full power and flexibility of arbitrary runtime predicates... here it is.
205
+
206
+ For some common constraints, we provide generic types:
207
+
208
+ * `LowerCase = Annotated[T, Predicate(str.islower)]`
209
+ * `UpperCase = Annotated[T, Predicate(str.isupper)]`
210
+ * `IsDigit = Annotated[T, Predicate(str.isdigit)]`
211
+ * `IsFinite = Annotated[T, Predicate(math.isfinite)]`
212
+ * `IsNotFinite = Annotated[T, Predicate(Not(math.isfinite))]`
213
+ * `IsNan = Annotated[T, Predicate(math.isnan)]`
214
+ * `IsNotNan = Annotated[T, Predicate(Not(math.isnan))]`
215
+ * `IsInfinite = Annotated[T, Predicate(math.isinf)]`
216
+ * `IsNotInfinite = Annotated[T, Predicate(Not(math.isinf))]`
217
+
218
+ so that you can write e.g. `x: IsFinite[float] = 2.0` instead of the longer
219
+ (but exactly equivalent) `x: Annotated[float, Predicate(math.isfinite)] = 2.0`.
220
+
221
+ Some libraries might have special logic to handle known or understandable predicates,
222
+ for example by checking for `str.isdigit` and using its presence to both call custom
223
+ logic to enforce digit-only strings, and customise some generated external schema.
224
+ Users are therefore encouraged to avoid indirection like `lambda s: s.lower()`, in
225
+ favor of introspectable methods such as `str.lower` or `re.compile("pattern").search`.
226
+
227
+ To enable basic negation of commonly used predicates like `math.isnan` without introducing introspection that makes it impossible for implementers to introspect the predicate we provide a `Not` wrapper that simply negates the predicate in an introspectable manner. Several of the predicates listed above are created in this manner.
228
+
229
+ We do not specify what behaviour should be expected for predicates that raise
230
+ an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently
231
+ skip invalid constraints, or statically raise an error; or it might try calling it
232
+ and then propagate or discard the resulting
233
+ `TypeError: descriptor 'isdigit' for 'str' objects doesn't apply to a 'int' object`
234
+ exception. We encourage libraries to document the behaviour they choose.
235
+
236
+ ### Doc
237
+
238
+ `doc()` can be used to add documentation information in `Annotated`, for function and method parameters, variables, class attributes, return types, and any place where `Annotated` can be used.
239
+
240
+ It expects a value that can be statically analyzed, as the main use case is for static analysis, editors, documentation generators, and similar tools.
241
+
242
+ It returns a `DocInfo` class with a single attribute `documentation` containing the value passed to `doc()`.
243
+
244
+ This is the early adopter's alternative form of the [`typing-doc` proposal](https://github.com/tiangolo/fastapi/blob/typing-doc/typing_doc.md).
245
+
246
+ ### Integrating downstream types with `GroupedMetadata`
247
+
248
+ Implementers may choose to provide a convenience wrapper that groups multiple pieces of metadata.
249
+ This can help reduce verbosity and cognitive overhead for users.
250
+ For example, an implementer like Pydantic might provide a `Field` or `Meta` type that accepts keyword arguments and transforms these into low-level metadata:
251
+
252
+ ```python
253
+ from dataclasses import dataclass
254
+ from typing import Iterator
255
+ from annotated_types import GroupedMetadata, Ge
256
+
257
+ @dataclass
258
+ class Field(GroupedMetadata):
259
+ ge: int | None = None
260
+ description: str | None = None
261
+
262
+ def __iter__(self) -> Iterator[object]:
263
+ # Iterating over a GroupedMetadata object should yield annotated-types
264
+ # constraint metadata objects which describe it as fully as possible,
265
+ # and may include other unknown objects too.
266
+ if self.ge is not None:
267
+ yield Ge(self.ge)
268
+ if self.description is not None:
269
+ yield Description(self.description)
270
+ ```
271
+
272
+ Libraries consuming annotated-types constraints should check for `GroupedMetadata` and unpack it by iterating over the object and treating the results as if they had been "unpacked" in the `Annotated` type. The same logic should be applied to the [PEP 646 `Unpack` type](https://peps.python.org/pep-0646/), so that `Annotated[T, Field(...)]`, `Annotated[T, Unpack[Field(...)]]` and `Annotated[T, *Field(...)]` are all treated consistently.
273
+
274
+ Libraries consuming annotated-types should also ignore any metadata they do not recongize that came from unpacking a `GroupedMetadata`, just like they ignore unrecognized metadata in `Annotated` itself.
275
+
276
+ Our own `annotated_types.Interval` class is a `GroupedMetadata` which unpacks itself into `Gt`, `Lt`, etc., so this is not an abstract concern. Similarly, `annotated_types.Len` is a `GroupedMetadata` which unpacks itself into `MinLen` (optionally) and `MaxLen`.
277
+
278
+ ### Consuming metadata
279
+
280
+ We intend to not be prescriptive as to _how_ the metadata and constraints are used, but as an example of how one might parse constraints from types annotations see our [implementation in `test_main.py`](https://github.com/annotated-types/annotated-types/blob/f59cf6d1b5255a0fe359b93896759a180bec30ae/tests/test_main.py#L94-L103).
281
+
282
+ It is up to the implementer to determine how this metadata is used.
283
+ You could use the metadata for runtime type checking, for generating schemas or to generate example data, amongst other use cases.
284
+
285
+ ## Design & History
286
+
287
+ This package was designed at the PyCon 2022 sprints by the maintainers of Pydantic
288
+ and Hypothesis, with the goal of making it as easy as possible for end-users to
289
+ provide more informative annotations for use by runtime libraries.
290
+
291
+ It is deliberately minimal, and following PEP-593 allows considerable downstream
292
+ discretion in what (if anything!) they choose to support. Nonetheless, we expect
293
+ that staying simple and covering _only_ the most common use-cases will give users
294
+ and maintainers the best experience we can. If you'd like more constraints for your
295
+ types - follow our lead, by defining them and documenting them downstream!
.venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/RECORD ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ annotated_types-0.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ annotated_types-0.8.0.dist-info/METADATA,sha256=YUmFsnj2Abjvhj-CeDuZHMOtpLifWS63HHxIxfLvIpg,15009
3
+ annotated_types-0.8.0.dist-info/RECORD,,
4
+ annotated_types-0.8.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
5
+ annotated_types-0.8.0.dist-info/licenses/LICENSE,sha256=_hBJiEsaDZNCkB6I4H8ykl0ksxIdmXK2poBfuYJLCV0,1083
6
+ annotated_types/__init__.py,sha256=pxBKTUObJ6n3T8C-I2ubobeDHmBEAmgCogWrwSmKm8g,13273
7
+ annotated_types/__pycache__/__init__.cpython-313.pyc,,
8
+ annotated_types/__pycache__/test_cases.cpython-313.pyc,,
9
+ annotated_types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ annotated_types/test_cases.py,sha256=2GdHKstXuBzpf3iXKCjmvFZpyk2zP9Hm9kXGGDhGBo4,6310
.venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/WHEEL ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
.venv/lib/python3.13/site-packages/annotated_types-0.8.0.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 the contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
.venv/lib/python3.13/site-packages/annotated_types/__init__.py ADDED
@@ -0,0 +1,416 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import types
3
+ from collections.abc import Callable, Iterator
4
+ from dataclasses import dataclass
5
+ from datetime import tzinfo
6
+ from types import EllipsisType
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Annotated,
10
+ Any,
11
+ Literal,
12
+ Protocol,
13
+ SupportsFloat,
14
+ SupportsIndex,
15
+ TypeVar,
16
+ Union,
17
+ runtime_checkable,
18
+ )
19
+
20
+ __all__ = (
21
+ 'BaseMetadata',
22
+ 'GroupedMetadata',
23
+ 'Gt',
24
+ 'Ge',
25
+ 'Lt',
26
+ 'Le',
27
+ 'Interval',
28
+ 'MultipleOf',
29
+ 'MinLen',
30
+ 'MaxLen',
31
+ 'Len',
32
+ 'Timezone',
33
+ 'Predicate',
34
+ 'LowerCase',
35
+ 'UpperCase',
36
+ 'IsDigits',
37
+ 'IsFinite',
38
+ 'IsNotFinite',
39
+ 'IsNan',
40
+ 'IsNotNan',
41
+ 'IsInfinite',
42
+ 'IsNotInfinite',
43
+ 'doc',
44
+ 'DocInfo',
45
+ '__version__',
46
+ )
47
+
48
+ __version__ = '0.8.0'
49
+
50
+
51
+ T = TypeVar('T')
52
+
53
+
54
+ # arguments that start with __ are considered
55
+ # positional only
56
+ # see https://peps.python.org/pep-0484/#positional-only-arguments
57
+
58
+
59
+ class SupportsGt(Protocol):
60
+ def __gt__(self: T, __other: T) -> bool:
61
+ ...
62
+
63
+
64
+ class SupportsGe(Protocol):
65
+ def __ge__(self: T, __other: T) -> bool:
66
+ ...
67
+
68
+
69
+ class SupportsLt(Protocol):
70
+ def __lt__(self: T, __other: T) -> bool:
71
+ ...
72
+
73
+
74
+ class SupportsLe(Protocol):
75
+ def __le__(self: T, __other: T) -> bool:
76
+ ...
77
+
78
+
79
+ class SupportsMod(Protocol):
80
+ def __mod__(self: T, __other: T) -> T:
81
+ ...
82
+
83
+
84
+ class SupportsDiv(Protocol):
85
+ def __div__(self: T, __other: T) -> T:
86
+ ...
87
+
88
+
89
+ class BaseMetadata:
90
+ """Base class for all metadata.
91
+
92
+ This exists mainly so that implementers
93
+ can do `isinstance(..., BaseMetadata)` while traversing field annotations.
94
+ """
95
+
96
+ __slots__ = ()
97
+
98
+
99
+ @dataclass(frozen=True, slots=True)
100
+ class Gt(BaseMetadata):
101
+ """Gt(gt=x) implies that the value must be greater than x.
102
+
103
+ It can be used with any type that supports the ``>`` operator,
104
+ including numbers, dates and times, strings, sets, and so on.
105
+ """
106
+
107
+ gt: SupportsGt
108
+
109
+
110
+ @dataclass(frozen=True, slots=True)
111
+ class Ge(BaseMetadata):
112
+ """Ge(ge=x) implies that the value must be greater than or equal to x.
113
+
114
+ It can be used with any type that supports the ``>=`` operator,
115
+ including numbers, dates and times, strings, sets, and so on.
116
+ """
117
+
118
+ ge: SupportsGe
119
+
120
+
121
+ @dataclass(frozen=True, slots=True)
122
+ class Lt(BaseMetadata):
123
+ """Lt(lt=x) implies that the value must be less than x.
124
+
125
+ It can be used with any type that supports the ``<`` operator,
126
+ including numbers, dates and times, strings, sets, and so on.
127
+ """
128
+
129
+ lt: SupportsLt
130
+
131
+
132
+ @dataclass(frozen=True, slots=True)
133
+ class Le(BaseMetadata):
134
+ """Le(le=x) implies that the value must be less than or equal to x.
135
+
136
+ It can be used with any type that supports the ``<=`` operator,
137
+ including numbers, dates and times, strings, sets, and so on.
138
+ """
139
+
140
+ le: SupportsLe
141
+
142
+
143
+ @runtime_checkable
144
+ class GroupedMetadata(Protocol):
145
+ """A grouping of multiple objects, like typing.Unpack.
146
+
147
+ `GroupedMetadata` on its own is not metadata and has no meaning.
148
+ All of the constraints and metadata should be fully expressable
149
+ in terms of the `BaseMetadata`'s returned by `GroupedMetadata.__iter__()`.
150
+
151
+ Concrete implementations should override `GroupedMetadata.__iter__()`
152
+ to add their own metadata.
153
+ For example:
154
+
155
+ >>> @dataclass
156
+ >>> class Field(GroupedMetadata):
157
+ >>> gt: float | None = None
158
+ >>> description: str | None = None
159
+ ...
160
+ >>> def __iter__(self) -> Iterable[object]:
161
+ >>> if self.gt is not None:
162
+ >>> yield Gt(self.gt)
163
+ >>> if self.description is not None:
164
+ >>> yield Description(self.gt)
165
+
166
+ Also see the implementation of `Interval` below for an example.
167
+
168
+ Parsers should recognize this and unpack it so that it can be used
169
+ both with and without unpacking:
170
+
171
+ - `Annotated[int, Field(...)]` (parser must unpack Field)
172
+ - `Annotated[int, *Field(...)]` (PEP-646)
173
+ """ # noqa: trailing-whitespace
174
+
175
+ @property
176
+ def __is_annotated_types_grouped_metadata__(self) -> Literal[True]:
177
+ return True
178
+
179
+ def __iter__(self) -> Iterator[object]:
180
+ ...
181
+
182
+ if not TYPE_CHECKING:
183
+ __slots__ = () # allow subclasses to use slots
184
+
185
+ def __init_subclass__(cls, *args: Any, **kwargs: Any) -> None:
186
+ # Basic ABC like functionality without the complexity of an ABC
187
+ super().__init_subclass__(*args, **kwargs)
188
+ if cls.__iter__ is GroupedMetadata.__iter__:
189
+ raise TypeError("Can't subclass GroupedMetadata without implementing __iter__")
190
+
191
+ def __iter__(self) -> Iterator[object]: # noqa: F811
192
+ raise NotImplementedError # more helpful than "None has no attribute..." type errors
193
+
194
+
195
+ @dataclass(frozen=True, kw_only=True, slots=True)
196
+ class Interval(GroupedMetadata):
197
+ """Interval can express inclusive or exclusive bounds with a single object.
198
+
199
+ It accepts keyword arguments ``gt``, ``ge``, ``lt``, and/or ``le``, which
200
+ are interpreted the same way as the single-bound constraints.
201
+ """
202
+
203
+ gt: SupportsGt | None = None
204
+ ge: SupportsGe | None = None
205
+ lt: SupportsLt | None = None
206
+ le: SupportsLe | None = None
207
+
208
+ def __iter__(self) -> Iterator[BaseMetadata]:
209
+ """Unpack an Interval into zero or more single-bounds."""
210
+ if self.gt is not None:
211
+ yield Gt(self.gt)
212
+ if self.ge is not None:
213
+ yield Ge(self.ge)
214
+ if self.lt is not None:
215
+ yield Lt(self.lt)
216
+ if self.le is not None:
217
+ yield Le(self.le)
218
+
219
+
220
+ @dataclass(frozen=True, slots=True)
221
+ class MultipleOf(BaseMetadata):
222
+ """MultipleOf(multiple_of=x) might be interpreted in two ways:
223
+
224
+ 1. Python semantics, implying ``value % multiple_of == 0``, or
225
+ 2. JSONschema semantics, where ``int(value / multiple_of) == value / multiple_of``
226
+
227
+ We encourage users to be aware of these two common interpretations,
228
+ and libraries to carefully document which they implement.
229
+ """
230
+
231
+ multiple_of: SupportsDiv | SupportsMod
232
+
233
+
234
+ @dataclass(frozen=True, slots=True)
235
+ class MinLen(BaseMetadata):
236
+ """
237
+ MinLen() implies minimum inclusive length,
238
+ e.g. ``len(value) >= min_length``.
239
+ """
240
+
241
+ min_length: Annotated[int, Ge(0)]
242
+
243
+
244
+ @dataclass(frozen=True, slots=True)
245
+ class MaxLen(BaseMetadata):
246
+ """
247
+ MaxLen() implies maximum inclusive length,
248
+ e.g. ``len(value) <= max_length``.
249
+ """
250
+
251
+ max_length: Annotated[int, Ge(0)]
252
+
253
+
254
+ @dataclass(frozen=True, slots=True)
255
+ class Len(GroupedMetadata):
256
+ """
257
+ Len() implies that ``min_length <= len(value) <= max_length``.
258
+
259
+ Upper bound may be omitted or ``None`` to indicate no upper length bound.
260
+ """
261
+
262
+ min_length: Annotated[int, Ge(0)] = 0
263
+ max_length: Annotated[int, Ge(0)] | None = None
264
+
265
+ def __iter__(self) -> Iterator[BaseMetadata]:
266
+ """Unpack a Len into zero or more single-bounds."""
267
+ if self.min_length > 0:
268
+ yield MinLen(self.min_length)
269
+ if self.max_length is not None:
270
+ yield MaxLen(self.max_length)
271
+
272
+
273
+ @dataclass(frozen=True, slots=True)
274
+ class Timezone(BaseMetadata):
275
+ """Timezone(tz=...) requires a datetime to be aware (or ``tz=None``, naive).
276
+
277
+ ``Annotated[datetime, Timezone(None)]`` must be a naive datetime.
278
+ ``Timezone(...)`` (the ellipsis literal) expresses that the datetime must be
279
+ tz-aware but any timezone is allowed.
280
+
281
+ You may also pass a specific timezone string or tzinfo object such as
282
+ ``Timezone(timezone.utc)`` or ``Timezone("Africa/Abidjan")`` to express that
283
+ you only allow a specific timezone, though we note that this is often
284
+ a symptom of poor design.
285
+ """
286
+
287
+ tz: str | tzinfo | EllipsisType | None
288
+
289
+
290
+ @dataclass(frozen=True, slots=True)
291
+ class Unit(BaseMetadata):
292
+ """Indicates that the value is a physical quantity with the specified unit.
293
+
294
+ It is intended for usage with numeric types, where the value represents the
295
+ magnitude of the quantity. For example, ``distance: Annotated[float, Unit('m')]``
296
+ or ``speed: Annotated[float, Unit('m/s')]``.
297
+
298
+ Interpretation of the unit string is left to the discretion of the consumer.
299
+ It is suggested to follow conventions established by python libraries that work
300
+ with physical quantities, such as
301
+
302
+ - ``pint`` : <https://pint.readthedocs.io/en/stable/>
303
+ - ``astropy.units``: <https://docs.astropy.org/en/stable/units/>
304
+
305
+ For indicating a quantity with a certain dimensionality but without a specific unit
306
+ it is recommended to use square brackets, e.g. `Annotated[float, Unit('[time]')]`.
307
+ Note, however, ``annotated_types`` itself makes no use of the unit string.
308
+ """
309
+
310
+ unit: str
311
+
312
+
313
+ @dataclass(frozen=True, slots=True)
314
+ class Predicate(BaseMetadata):
315
+ """``Predicate(func: Callable)`` implies `func(value)` is truthy for valid values.
316
+
317
+ Users should prefer statically inspectable metadata, but if you need the full
318
+ power and flexibility of arbitrary runtime predicates... here it is.
319
+
320
+ We provide a few predefined predicates for common string constraints:
321
+ ``LowerCase = Predicate(str.islower)``, ``UpperCase = Predicate(str.isupper)``, and
322
+ ``IsDigits = Predicate(str.isdigit)``. Users are encouraged to use methods which
323
+ can be given special handling, and avoid indirection like ``lambda s: s.lower()``.
324
+
325
+ Some libraries might have special logic to handle certain predicates, e.g. by
326
+ checking for `str.isdigit` and using its presence to both call custom logic to
327
+ enforce digit-only strings, and customise some generated external schema.
328
+
329
+ We do not specify what behaviour should be expected for predicates that raise
330
+ an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently
331
+ skip invalid constraints, or statically raise an error; or it might try calling it
332
+ and then propagate or discard the resulting exception.
333
+ """
334
+
335
+ func: Callable[[Any], bool]
336
+
337
+ def __repr__(self) -> str:
338
+ if getattr(self.func, "__name__", "<lambda>") == "<lambda>":
339
+ return f"{self.__class__.__name__}({self.func!r})"
340
+ if isinstance(self.func, (types.MethodType, types.BuiltinMethodType)) and (
341
+ namespace := getattr(self.func.__self__, "__name__", None)
342
+ ):
343
+ return f"{self.__class__.__name__}({namespace}.{self.func.__name__})"
344
+ if isinstance(self.func, type(str.isascii)): # method descriptor
345
+ return f"{self.__class__.__name__}({self.func.__qualname__})"
346
+ return f"{self.__class__.__name__}({self.func.__name__})"
347
+
348
+
349
+ @dataclass
350
+ class Not:
351
+ func: Callable[[Any], bool]
352
+
353
+ def __call__(self, __v: Any) -> bool:
354
+ return not self.func(__v)
355
+
356
+
357
+ _StrType = TypeVar("_StrType", bound=str)
358
+
359
+ LowerCase = Annotated[_StrType, Predicate(str.islower)]
360
+ """
361
+ Return True if the string is a lowercase string, False otherwise.
362
+
363
+ A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string.
364
+ """ # noqa: E501
365
+ UpperCase = Annotated[_StrType, Predicate(str.isupper)]
366
+ """
367
+ Return True if the string is an uppercase string, False otherwise.
368
+
369
+ A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string.
370
+ """ # noqa: E501
371
+ IsDigit = Annotated[_StrType, Predicate(str.isdigit)]
372
+ IsDigits = IsDigit # type: ignore # plural for backwards compatibility, see #63
373
+ """
374
+ Return True if the string is a digit string, False otherwise.
375
+
376
+ A string is a digit string if all characters in the string are digits and there is at least one character in the string.
377
+ """ # noqa: E501
378
+ IsAscii = Annotated[_StrType, Predicate(str.isascii)]
379
+ """
380
+ Return True if all characters in the string are ASCII, False otherwise.
381
+
382
+ ASCII characters have code points in the range U+0000-U+007F. Empty string is ASCII too.
383
+ """
384
+
385
+ _NumericType = TypeVar('_NumericType', bound=Union[SupportsFloat, SupportsIndex])
386
+ IsFinite = Annotated[_NumericType, Predicate(math.isfinite)]
387
+ """Return True if x is neither an infinity nor a NaN, and False otherwise."""
388
+ IsNotFinite = Annotated[_NumericType, Predicate(Not(math.isfinite))]
389
+ """Return True if x is one of infinity or NaN, and False otherwise"""
390
+ IsNan = Annotated[_NumericType, Predicate(math.isnan)]
391
+ """Return True if x is a NaN (not a number), and False otherwise."""
392
+ IsNotNan = Annotated[_NumericType, Predicate(Not(math.isnan))]
393
+ """Return True if x is anything but NaN (not a number), and False otherwise."""
394
+ IsInfinite = Annotated[_NumericType, Predicate(math.isinf)]
395
+ """Return True if x is a positive or negative infinity, and False otherwise."""
396
+ IsNotInfinite = Annotated[_NumericType, Predicate(Not(math.isinf))]
397
+ """Return True if x is neither a positive or negative infinity, and False otherwise."""
398
+
399
+ try:
400
+ # PEP 727 – Documentation in Annotated Metadata
401
+ from typing_extensions import Doc # type: ignore[attr-defined]
402
+ except ImportError:
403
+
404
+ @dataclass(frozen=True, slots=True)
405
+ class Doc: # type: ignore [no-redef]
406
+ """ "
407
+ The return value of doc(), mainly to be used by tools that want to extract the
408
+ Annotated documentation at runtime.
409
+ """
410
+
411
+ documentation: str
412
+ """The documentation string passed to doc()."""
413
+
414
+
415
+ DocInfo = Doc # backwards compatibility
416
+ doc = Doc
.venv/lib/python3.13/site-packages/annotated_types/py.typed ADDED
File without changes
.venv/lib/python3.13/site-packages/annotated_types/test_cases.py ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from collections.abc import Iterable, Iterator
3
+ from datetime import date, datetime, timedelta, timezone
4
+ from decimal import Decimal
5
+ from typing import Annotated, Any, NamedTuple
6
+
7
+ import annotated_types as at
8
+
9
+
10
+ class Case(NamedTuple):
11
+ """
12
+ A test case for `annotated_types`.
13
+ """
14
+
15
+ annotation: Any
16
+ valid_cases: Iterable[Any]
17
+ invalid_cases: Iterable[Any]
18
+
19
+
20
+ def cases() -> Iterable[Case]:
21
+ # Gt, Ge, Lt, Le
22
+ yield Case(Annotated[int, at.Gt(4)], (5, 6, 1000), (4, 0, -1))
23
+ yield Case(Annotated[float, at.Gt(0.5)], (0.6, 0.7, 0.8, 0.9), (0.5, 0.0, -0.1))
24
+ yield Case(
25
+ Annotated[datetime, at.Gt(datetime(2000, 1, 1))],
26
+ [datetime(2000, 1, 2), datetime(2000, 1, 3)],
27
+ [datetime(2000, 1, 1), datetime(1999, 12, 31)],
28
+ )
29
+ yield Case(
30
+ Annotated[datetime, at.Gt(date(2000, 1, 1))],
31
+ [date(2000, 1, 2), date(2000, 1, 3)],
32
+ [date(2000, 1, 1), date(1999, 12, 31)],
33
+ )
34
+ yield Case(
35
+ Annotated[datetime, at.Gt(Decimal('1.123'))],
36
+ [Decimal('1.1231'), Decimal('123')],
37
+ [Decimal('1.123'), Decimal('0')],
38
+ )
39
+
40
+ yield Case(Annotated[int, at.Ge(4)], (4, 5, 6, 1000, 4), (0, -1))
41
+ yield Case(Annotated[float, at.Ge(0.5)], (0.5, 0.6, 0.7, 0.8, 0.9), (0.4, 0.0, -0.1))
42
+ yield Case(
43
+ Annotated[datetime, at.Ge(datetime(2000, 1, 1))],
44
+ [datetime(2000, 1, 2), datetime(2000, 1, 3)],
45
+ [datetime(1998, 1, 1), datetime(1999, 12, 31)],
46
+ )
47
+
48
+ yield Case(Annotated[int, at.Lt(4)], (0, -1), (4, 5, 6, 1000, 4))
49
+ yield Case(Annotated[float, at.Lt(0.5)], (0.4, 0.0, -0.1), (0.5, 0.6, 0.7, 0.8, 0.9))
50
+ yield Case(
51
+ Annotated[datetime, at.Lt(datetime(2000, 1, 1))],
52
+ [datetime(1999, 12, 31), datetime(1999, 12, 31)],
53
+ [datetime(2000, 1, 2), datetime(2000, 1, 3)],
54
+ )
55
+
56
+ yield Case(Annotated[int, at.Le(4)], (4, 0, -1), (5, 6, 1000))
57
+ yield Case(Annotated[float, at.Le(0.5)], (0.5, 0.0, -0.1), (0.6, 0.7, 0.8, 0.9))
58
+ yield Case(
59
+ Annotated[datetime, at.Le(datetime(2000, 1, 1))],
60
+ [datetime(2000, 1, 1), datetime(1999, 12, 31)],
61
+ [datetime(2000, 1, 2), datetime(2000, 1, 3)],
62
+ )
63
+
64
+ # Interval
65
+ yield Case(Annotated[int, at.Interval(gt=4)], (5, 6, 1000), (4, 0, -1))
66
+ yield Case(Annotated[int, at.Interval(gt=4, lt=10)], (5, 6), (4, 10, 1000, 0, -1))
67
+ yield Case(Annotated[float, at.Interval(ge=0.5, le=1)], (0.5, 0.9, 1), (0.49, 1.1))
68
+ yield Case(
69
+ Annotated[datetime, at.Interval(gt=datetime(2000, 1, 1), le=datetime(2000, 1, 3))],
70
+ [datetime(2000, 1, 2), datetime(2000, 1, 3)],
71
+ [datetime(2000, 1, 1), datetime(2000, 1, 4)],
72
+ )
73
+
74
+ yield Case(Annotated[int, at.MultipleOf(multiple_of=3)], (0, 3, 9), (1, 2, 4))
75
+ yield Case(Annotated[float, at.MultipleOf(multiple_of=0.5)], (0, 0.5, 1, 1.5), (0.4, 1.1))
76
+
77
+ # lengths
78
+
79
+ yield Case(Annotated[str, at.MinLen(3)], ('123', '1234', 'x' * 10), ('', '1', '12'))
80
+ yield Case(Annotated[str, at.Len(3)], ('123', '1234', 'x' * 10), ('', '1', '12'))
81
+ yield Case(Annotated[list[int], at.MinLen(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2]))
82
+ yield Case(Annotated[list[int], at.Len(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2]))
83
+
84
+ yield Case(Annotated[str, at.MaxLen(4)], ('', '1234'), ('12345', 'x' * 10))
85
+ yield Case(Annotated[str, at.Len(0, 4)], ('', '1234'), ('12345', 'x' * 10))
86
+ yield Case(Annotated[list[str], at.MaxLen(4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10))
87
+ yield Case(Annotated[list[str], at.Len(0, 4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10))
88
+
89
+ yield Case(Annotated[str, at.Len(3, 5)], ('123', '12345'), ('', '1', '12', '123456', 'x' * 10))
90
+ yield Case(Annotated[str, at.Len(3, 3)], ('123',), ('12', '1234'))
91
+
92
+ yield Case(Annotated[dict[int, int], at.Len(2, 3)], [{1: 1, 2: 2}], [{}, {1: 1}, {1: 1, 2: 2, 3: 3, 4: 4}])
93
+ yield Case(Annotated[set[int], at.Len(2, 3)], ({1, 2}, {1, 2, 3}), (set(), {1}, {1, 2, 3, 4}))
94
+ yield Case(Annotated[tuple[int, ...], at.Len(2, 3)], ((1, 2), (1, 2, 3)), ((), (1,), (1, 2, 3, 4)))
95
+
96
+ # Timezone
97
+
98
+ yield Case(
99
+ Annotated[datetime, at.Timezone(None)], [datetime(2000, 1, 1)], [datetime(2000, 1, 1, tzinfo=timezone.utc)]
100
+ )
101
+ yield Case(
102
+ Annotated[datetime, at.Timezone(...)], [datetime(2000, 1, 1, tzinfo=timezone.utc)], [datetime(2000, 1, 1)]
103
+ )
104
+ yield Case(
105
+ Annotated[datetime, at.Timezone(timezone.utc)],
106
+ [datetime(2000, 1, 1, tzinfo=timezone.utc)],
107
+ [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))],
108
+ )
109
+ yield Case(
110
+ Annotated[datetime, at.Timezone('Europe/London')],
111
+ [datetime(2000, 1, 1, tzinfo=timezone(timedelta(0), name='Europe/London'))],
112
+ [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))],
113
+ )
114
+
115
+ # Quantity
116
+
117
+ yield Case(Annotated[float, at.Unit(unit='m')], (5, 4.2), ('5m', '4.2m'))
118
+
119
+ # predicate types
120
+
121
+ yield Case(at.LowerCase[str], ['abc', 'foobar'], ['', 'A', 'Boom'])
122
+ yield Case(at.UpperCase[str], ['ABC', 'DEFO'], ['', 'a', 'abc', 'AbC'])
123
+ yield Case(at.IsDigit[str], ['123'], ['', 'ab', 'a1b2'])
124
+ yield Case(at.IsAscii[str], ['123', 'foo bar'], ['£100', '😊', 'whatever 👀'])
125
+
126
+ yield Case(Annotated[int, at.Predicate(lambda x: x % 2 == 0)], [0, 2, 4], [1, 3, 5])
127
+
128
+ yield Case(at.IsFinite[float], [1.23], [math.nan, math.inf, -math.inf])
129
+ yield Case(at.IsNotFinite[float], [math.nan, math.inf], [1.23])
130
+ yield Case(at.IsNan[float], [math.nan], [1.23, math.inf])
131
+ yield Case(at.IsNotNan[float], [1.23, math.inf], [math.nan])
132
+ yield Case(at.IsInfinite[float], [math.inf], [math.nan, 1.23])
133
+ yield Case(at.IsNotInfinite[float], [math.nan, 1.23], [math.inf])
134
+
135
+ # check stacked predicates
136
+ yield Case(at.IsInfinite[Annotated[float, at.Predicate(lambda x: x > 0)]], [math.inf], [-math.inf, 1.23, math.nan])
137
+
138
+ # doc
139
+ yield Case(Annotated[int, at.doc("A number")], [1, 2], [])
140
+
141
+ # custom GroupedMetadata
142
+ class MyCustomGroupedMetadata(at.GroupedMetadata):
143
+ def __iter__(self) -> Iterator[at.Predicate]:
144
+ yield at.Predicate(lambda x: float(x).is_integer())
145
+
146
+ yield Case(Annotated[float, MyCustomGroupedMetadata()], [0, 2.0], [0.01, 1.5])
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/METADATA ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: anyio
3
+ Version: 4.14.2
4
+ Summary: High-level concurrency and networking framework on top of asyncio or Trio
5
+ Author-email: Alex Grönholm <alex.gronholm@nextday.fi>
6
+ License-Expression: MIT
7
+ Project-URL: Documentation, https://anyio.readthedocs.io/en/latest/
8
+ Project-URL: Changelog, https://anyio.readthedocs.io/en/stable/versionhistory.html
9
+ Project-URL: Source code, https://github.com/agronholm/anyio
10
+ Project-URL: Issue tracker, https://github.com/agronholm/anyio/issues
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Framework :: AnyIO
14
+ Classifier: Typing :: Typed
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Programming Language :: Python :: 3.15
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/x-rst
25
+ License-File: LICENSE
26
+ Requires-Dist: exceptiongroup>=1.0.2; python_version < "3.11"
27
+ Requires-Dist: idna>=2.8
28
+ Requires-Dist: typing_extensions>=4.5; python_version < "3.13"
29
+ Provides-Extra: trio
30
+ Requires-Dist: trio>=0.32.0; extra == "trio"
31
+ Dynamic: license-file
32
+
33
+ .. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg
34
+ :target: https://github.com/agronholm/anyio/actions/workflows/test.yml
35
+ :alt: Build Status
36
+ .. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master
37
+ :target: https://coveralls.io/github/agronholm/anyio?branch=master
38
+ :alt: Code Coverage
39
+ .. image:: https://readthedocs.org/projects/anyio/badge/?version=latest
40
+ :target: https://anyio.readthedocs.io/en/latest/?badge=latest
41
+ :alt: Documentation
42
+ .. image:: https://badges.gitter.im/gitterHQ/gitter.svg
43
+ :target: https://gitter.im/python-trio/AnyIO
44
+ :alt: Gitter chat
45
+ .. image:: https://tidelift.com/badges/package/pypi/anyio
46
+ :target: https://tidelift.com/subscription/pkg/pypi-anyio
47
+ :alt: Tidelift
48
+
49
+ AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or
50
+ Trio_. It implements Trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony
51
+ with the native SC of Trio itself.
52
+
53
+ Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or
54
+ Trio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full
55
+ refactoring necessary. It will blend in with the native libraries of your chosen backend.
56
+
57
+ To find out why you might want to use AnyIO's APIs instead of asyncio's, you can read about it
58
+ `here <https://anyio.readthedocs.io/en/stable/why.html>`_.
59
+
60
+ Documentation
61
+ -------------
62
+
63
+ View full documentation at: https://anyio.readthedocs.io/
64
+
65
+ Features
66
+ --------
67
+
68
+ AnyIO offers the following functionality:
69
+
70
+ * Task groups (nurseries_ in trio terminology)
71
+ * High-level networking (TCP, UDP and UNIX sockets)
72
+
73
+ * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python
74
+ 3.8)
75
+ * async/await style UDP sockets (unlike asyncio where you still have to use Transports and
76
+ Protocols)
77
+
78
+ * A versatile API for byte streams and object streams
79
+ * Inter-task synchronization and communication (locks, conditions, events, semaphores, object
80
+ streams)
81
+ * Worker threads
82
+ * Subprocesses
83
+ * Subinterpreter support for code parallelization (on Python 3.13 and later)
84
+ * Asynchronous file I/O (using worker threads)
85
+ * Signal handling
86
+ * Asynchronous versions of the functools_ and itertools_ modules
87
+
88
+ AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures.
89
+ It even works with the popular Hypothesis_ library.
90
+
91
+ .. _asyncio: https://docs.python.org/3/library/asyncio.html
92
+ .. _Trio: https://github.com/python-trio/trio
93
+ .. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency
94
+ .. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning
95
+ .. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs
96
+ .. _pytest: https://docs.pytest.org/en/latest/
97
+ .. _functools: https://docs.python.org/3/library/functools.html
98
+ .. _itertools: https://docs.python.org/3/library/itertools.html
99
+ .. _Hypothesis: https://hypothesis.works/
100
+
101
+ Security contact information
102
+ ----------------------------
103
+
104
+ To report a security vulnerability, please use the `Tidelift security contact`_.
105
+ Tidelift will coordinate the fix and disclosure.
106
+
107
+ .. _Tidelift security contact: https://tidelift.com/security
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/RECORD ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ anyio-4.14.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ anyio-4.14.2.dist-info/METADATA,sha256=xeb8Tf2DMxmROyh756MNmTXpIIx--RdjBiGFWqrE1Bk,4645
3
+ anyio-4.14.2.dist-info/RECORD,,
4
+ anyio-4.14.2.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
5
+ anyio-4.14.2.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39
6
+ anyio-4.14.2.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081
7
+ anyio-4.14.2.dist-info/scm_file_list.json,sha256=wDSXGv8Ehn5ZW5BhB-RlaAc16zY_OfO27qrlMfMMZy8,3654
8
+ anyio-4.14.2.dist-info/scm_version.json,sha256=KgaUx31SyaqGFQFKpG3FO9kCk-ygOKS7Uf0yk56OzaY,161
9
+ anyio-4.14.2.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6
10
+ anyio/__init__.py,sha256=HitUIfzvAojSeaHVmJ9rFn8k_yI63G6s_jUL2QChf4U,6405
11
+ anyio/__pycache__/__init__.cpython-313.pyc,,
12
+ anyio/__pycache__/from_thread.cpython-313.pyc,,
13
+ anyio/__pycache__/functools.cpython-313.pyc,,
14
+ anyio/__pycache__/itertools.cpython-313.pyc,,
15
+ anyio/__pycache__/lowlevel.cpython-313.pyc,,
16
+ anyio/__pycache__/pytest_plugin.cpython-313.pyc,,
17
+ anyio/__pycache__/to_interpreter.cpython-313.pyc,,
18
+ anyio/__pycache__/to_process.cpython-313.pyc,,
19
+ anyio/__pycache__/to_thread.cpython-313.pyc,,
20
+ anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ anyio/_backends/__pycache__/__init__.cpython-313.pyc,,
22
+ anyio/_backends/__pycache__/_asyncio.cpython-313.pyc,,
23
+ anyio/_backends/__pycache__/_trio.cpython-313.pyc,,
24
+ anyio/_backends/_asyncio.py,sha256=eK0j8PI0O7y3bX8cUBsafoWP8wsXR-szP6ciyP4Mkkk,104400
25
+ anyio/_backends/_trio.py,sha256=hoTXL8zI81v4UE-YT_cr2fzh_zY1mKdmZD3oQHmeR0E,45583
26
+ anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ anyio/_core/__pycache__/__init__.cpython-313.pyc,,
28
+ anyio/_core/__pycache__/_asyncio_selector_thread.cpython-313.pyc,,
29
+ anyio/_core/__pycache__/_contextmanagers.cpython-313.pyc,,
30
+ anyio/_core/__pycache__/_eventloop.cpython-313.pyc,,
31
+ anyio/_core/__pycache__/_exceptions.cpython-313.pyc,,
32
+ anyio/_core/__pycache__/_fileio.cpython-313.pyc,,
33
+ anyio/_core/__pycache__/_resources.cpython-313.pyc,,
34
+ anyio/_core/__pycache__/_signals.cpython-313.pyc,,
35
+ anyio/_core/__pycache__/_sockets.cpython-313.pyc,,
36
+ anyio/_core/__pycache__/_streams.cpython-313.pyc,,
37
+ anyio/_core/__pycache__/_subprocesses.cpython-313.pyc,,
38
+ anyio/_core/__pycache__/_synchronization.cpython-313.pyc,,
39
+ anyio/_core/__pycache__/_tasks.cpython-313.pyc,,
40
+ anyio/_core/__pycache__/_tempfile.cpython-313.pyc,,
41
+ anyio/_core/__pycache__/_testing.cpython-313.pyc,,
42
+ anyio/_core/__pycache__/_typedattr.cpython-313.pyc,,
43
+ anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626
44
+ anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215
45
+ anyio/_core/_eventloop.py,sha256=ByZUeJD9alMfcyTseRo5IzTO0IltEul_Gyq9iqSjqDk,6658
46
+ anyio/_core/_exceptions.py,sha256=OfzLO4Z3Hog1TnipbIn72YNtkoYxS4lHW9MqKDeGc88,4936
47
+ anyio/_core/_fileio.py,sha256=hHfyV0bXDL-R2ZNnInwse3nmTAd36AIz1cBxgmAwzAQ,31358
48
+ anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435
49
+ anyio/_core/_signals.py,sha256=mjTBB2hTKNPRlU0IhnijeQedpWOGERDiMjSlJQsFrug,1016
50
+ anyio/_core/_sockets.py,sha256=HtjiSH-yzehlqh_LpD3PGIafDuUCwd8gueUuk5MFeNk,35288
51
+ anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806
52
+ anyio/_core/_subprocesses.py,sha256=M2GCc4NKXCbB_GtEskJgndiM2b0VS0NK_ohmFxri7O8,7923
53
+ anyio/_core/_synchronization.py,sha256=kgPk88-eVOmY-pDNs-ReRbcEelY1a7YczuVBPsZwc8A,21591
54
+ anyio/_core/_tasks.py,sha256=y99vRi-AFzEv6kyvIwqrzuskE2NMiNItWnuWGk7eOr4,13126
55
+ anyio/_core/_tempfile.py,sha256=jE2w59FRF3yRo4vjkjfZF2YcqsBZvc66VWRwrJGDYGk,19624
56
+ anyio/_core/_testing.py,sha256=u7MPqGXwpTxqI7hclSdNA30z2GH1Nw258uwKvy_RfBg,2340
57
+ anyio/_core/_typedattr.py,sha256=P4ozZikn3-DbpoYcvyghS_FOYAgbmUxeoU8-L_07pZM,2508
58
+ anyio/abc/__init__.py,sha256=6mWhcl_pGXhrgZVHP_TCfMvIXIOp9mroEFM90fYCU_U,2869
59
+ anyio/abc/__pycache__/__init__.cpython-313.pyc,,
60
+ anyio/abc/__pycache__/_eventloop.cpython-313.pyc,,
61
+ anyio/abc/__pycache__/_resources.cpython-313.pyc,,
62
+ anyio/abc/__pycache__/_sockets.cpython-313.pyc,,
63
+ anyio/abc/__pycache__/_streams.cpython-313.pyc,,
64
+ anyio/abc/__pycache__/_subprocesses.cpython-313.pyc,,
65
+ anyio/abc/__pycache__/_tasks.cpython-313.pyc,,
66
+ anyio/abc/__pycache__/_testing.cpython-313.pyc,,
67
+ anyio/abc/_eventloop.py,sha256=OqWYSEj0TmwL_xniCJt3_jHFWsuMk9THk8tCTGsKapI,10681
68
+ anyio/abc/_resources.py,sha256=DrYvkNN1hH6Uvv5_5uKySvDsnknGVDe8FCKfko0VtN8,783
69
+ anyio/abc/_sockets.py,sha256=OmVDrfemVvF9c5K1tpBgQyV6fn5v0XyCExLAqBOGz9o,13124
70
+ anyio/abc/_streams.py,sha256=rnSwRy-6y80TPQtIXit5LjMMiU1CCWS1oMNsmJQHRTg,7582
71
+ anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067
72
+ anyio/abc/_tasks.py,sha256=m-FtE4phxeNIELSG7A3H7VUz3jA2Ib5J2JIew8-PS6o,6642
73
+ anyio/abc/_testing.py,sha256=9YYM2AXsYFvf4PLjUEr6yRxDiUeB5QbY_gOg0X_C6lY,2034
74
+ anyio/from_thread.py,sha256=JYsbaCaIB_Iit6kNhtXSteJGt4PcQ7ncq0nIpcelIrg,19265
75
+ anyio/functools.py,sha256=T4JS8IXq-x1S0Lbo2owF8l9fza2KypO147QLeyz4cjs,11797
76
+ anyio/itertools.py,sha256=QV-9mnRCr2yBph8g01QFvN-bQ_Yle-8Sl13YSydBlMI,16168
77
+ anyio/lowlevel.py,sha256=-59484Z6K5jF7XJJhHxYHIKnvFH_uAeMhl9a_AfaSHI,6280
78
+ anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
+ anyio/pytest_plugin.py,sha256=paMpI_VMNQf2bir0LfvgMpXSiYJoHDzWdKUVTyoHmvQ,13609
80
+ anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
+ anyio/streams/__pycache__/__init__.cpython-313.pyc,,
82
+ anyio/streams/__pycache__/buffered.cpython-313.pyc,,
83
+ anyio/streams/__pycache__/file.cpython-313.pyc,,
84
+ anyio/streams/__pycache__/memory.cpython-313.pyc,,
85
+ anyio/streams/__pycache__/stapled.cpython-313.pyc,,
86
+ anyio/streams/__pycache__/text.cpython-313.pyc,,
87
+ anyio/streams/__pycache__/tls.cpython-313.pyc,,
88
+ anyio/streams/buffered.py,sha256=u7hCD8SNrYHcutG6K5wEiy1F88-pizgjvEFM22Kq2Cw,6746
89
+ anyio/streams/file.py,sha256=6jujI2m-QJITqqKFamrupX_DNsU7y2Fz3omLZxOLuY0,4524
90
+ anyio/streams/memory.py,sha256=ZmKWCLpyItOCXmvCQT-L8IyJHNFaB-OVJbrn88CaMo0,10776
91
+ anyio/streams/stapled.py,sha256=mDNF9Gj4deXfOuKSZmgkEG-QExYAKAGjYBHbrs-rJaQ,4486
92
+ anyio/streams/text.py,sha256=BcVAGJw1VRvtIqnv-o0Rb0pwH7p8vwlvl21xHq522ag,5765
93
+ anyio/streams/tls.py,sha256=Gvs--YOoFxcyn-hakXOiPM8H-aEp8nsU6k9rTrKqJA4,15801
94
+ anyio/to_interpreter.py,sha256=_mLngrMy97TMR6VbW4Y6YzDUk9ZuPcQMPlkuyRh3C9k,7100
95
+ anyio/to_process.py,sha256=jHw7v6XHBNIfYa6DqnqKY0gsRo8ScOCh8fo19fqFvjU,9848
96
+ anyio/to_thread.py,sha256=bYszW0lCDfTmLnXbAYic05HEe_Di_0UWKabgL2vU0T0,2750
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/entry_points.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ [pytest11]
2
+ anyio = anyio.pytest_plugin
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Alex Grönholm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/scm_file_list.json ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "files": [
3
+ ".pre-commit-config.yaml",
4
+ "LICENSE",
5
+ "pyproject.toml",
6
+ "AGENTS.md",
7
+ "README.rst",
8
+ "CLAUDE.md",
9
+ ".readthedocs.yml",
10
+ ".gitignore",
11
+ "docs/tempfile.rst",
12
+ "docs/signals.rst",
13
+ "docs/synchronization.rst",
14
+ "docs/contextmanagers.rst",
15
+ "docs/testing.rst",
16
+ "docs/networking.rst",
17
+ "docs/contributing.rst",
18
+ "docs/index.rst",
19
+ "docs/versionhistory.rst",
20
+ "docs/threads.rst",
21
+ "docs/api.rst",
22
+ "docs/typedattrs.rst",
23
+ "docs/basics.rst",
24
+ "docs/fileio.rst",
25
+ "docs/cancellation.rst",
26
+ "docs/support.rst",
27
+ "docs/streams.rst",
28
+ "docs/why.rst",
29
+ "docs/tasks.rst",
30
+ "docs/migration.rst",
31
+ "docs/conf.py",
32
+ "docs/subprocesses.rst",
33
+ "docs/faq.rst",
34
+ "docs/subinterpreters.rst",
35
+ "src/anyio/functools.py",
36
+ "src/anyio/py.typed",
37
+ "src/anyio/__init__.py",
38
+ "src/anyio/pytest_plugin.py",
39
+ "src/anyio/itertools.py",
40
+ "src/anyio/to_interpreter.py",
41
+ "src/anyio/from_thread.py",
42
+ "src/anyio/to_process.py",
43
+ "src/anyio/to_thread.py",
44
+ "src/anyio/lowlevel.py",
45
+ "src/anyio/_backends/_trio.py",
46
+ "src/anyio/_backends/__init__.py",
47
+ "src/anyio/_backends/_asyncio.py",
48
+ "src/anyio/streams/memory.py",
49
+ "src/anyio/streams/__init__.py",
50
+ "src/anyio/streams/tls.py",
51
+ "src/anyio/streams/file.py",
52
+ "src/anyio/streams/text.py",
53
+ "src/anyio/streams/stapled.py",
54
+ "src/anyio/streams/buffered.py",
55
+ "src/anyio/abc/_eventloop.py",
56
+ "src/anyio/abc/__init__.py",
57
+ "src/anyio/abc/_sockets.py",
58
+ "src/anyio/abc/_tasks.py",
59
+ "src/anyio/abc/_subprocesses.py",
60
+ "src/anyio/abc/_resources.py",
61
+ "src/anyio/abc/_streams.py",
62
+ "src/anyio/abc/_testing.py",
63
+ "src/anyio/_core/_typedattr.py",
64
+ "src/anyio/_core/_eventloop.py",
65
+ "src/anyio/_core/__init__.py",
66
+ "src/anyio/_core/_tempfile.py",
67
+ "src/anyio/_core/_sockets.py",
68
+ "src/anyio/_core/_tasks.py",
69
+ "src/anyio/_core/_fileio.py",
70
+ "src/anyio/_core/_synchronization.py",
71
+ "src/anyio/_core/_subprocesses.py",
72
+ "src/anyio/_core/_resources.py",
73
+ "src/anyio/_core/_contextmanagers.py",
74
+ "src/anyio/_core/_exceptions.py",
75
+ "src/anyio/_core/_streams.py",
76
+ "src/anyio/_core/_signals.py",
77
+ "src/anyio/_core/_asyncio_selector_thread.py",
78
+ "src/anyio/_core/_testing.py",
79
+ "tests/test_itertools.py",
80
+ "tests/test_functools.py",
81
+ "tests/test_eventloop.py",
82
+ "tests/__init__.py",
83
+ "tests/test_to_thread.py",
84
+ "tests/test_from_thread.py",
85
+ "tests/test_lowlevel.py",
86
+ "tests/test_to_interpreter.py",
87
+ "tests/test_sockets.py",
88
+ "tests/test_typedattr.py",
89
+ "tests/test_to_process.py",
90
+ "tests/test_all_attributes.py",
91
+ "tests/test_synchronization.py",
92
+ "tests/test_debugging.py",
93
+ "tests/test_contextmanagers.py",
94
+ "tests/test_fileio.py",
95
+ "tests/conftest.py",
96
+ "tests/test_signals.py",
97
+ "tests/test_deprecations.py",
98
+ "tests/test_tempfile.py",
99
+ "tests/test_taskgroups.py",
100
+ "tests/test_pytest_plugin.py",
101
+ "tests/test_subprocesses.py",
102
+ "tests/streams/test_text.py",
103
+ "tests/streams/test_memory.py",
104
+ "tests/streams/__init__.py",
105
+ "tests/streams/test_file.py",
106
+ "tests/streams/test_stapled.py",
107
+ "tests/streams/test_tls.py",
108
+ "tests/streams/test_buffered.py",
109
+ ".github/pull_request_template.md",
110
+ ".github/dependabot.yml",
111
+ ".github/FUNDING.yml",
112
+ ".github/ISSUE_TEMPLATE/features_request.yaml",
113
+ ".github/ISSUE_TEMPLATE/bug_report.yaml",
114
+ ".github/ISSUE_TEMPLATE/config.yml",
115
+ ".github/workflows/test.yml",
116
+ ".github/workflows/test-downstream.yml",
117
+ ".github/workflows/publish.yml"
118
+ ]
119
+ }
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/scm_version.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tag": "4.14.2",
3
+ "distance": 0,
4
+ "node": "gc384f99687c64c59ed8a11c3a0f11a2d57daff71",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-07-12"
8
+ }
.venv/lib/python3.13/site-packages/anyio-4.14.2.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ anyio
.venv/lib/python3.13/site-packages/anyio/__init__.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 TaskCancelled as TaskCancelled
25
+ from ._core._exceptions import TaskFailed as TaskFailed
26
+ from ._core._exceptions import TaskNotFinished as TaskNotFinished
27
+ from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError
28
+ from ._core._exceptions import WouldBlock as WouldBlock
29
+ from ._core._fileio import AsyncFile as AsyncFile
30
+ from ._core._fileio import Path as Path
31
+ from ._core._fileio import open_file as open_file
32
+ from ._core._fileio import wrap_file as wrap_file
33
+ from ._core._resources import aclose_forcefully as aclose_forcefully
34
+ from ._core._signals import open_signal_receiver as open_signal_receiver
35
+ from ._core._sockets import TCPConnectable as TCPConnectable
36
+ from ._core._sockets import UNIXConnectable as UNIXConnectable
37
+ from ._core._sockets import as_connectable as as_connectable
38
+ from ._core._sockets import connect_tcp as connect_tcp
39
+ from ._core._sockets import connect_unix as connect_unix
40
+ from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket
41
+ from ._core._sockets import (
42
+ create_connected_unix_datagram_socket as create_connected_unix_datagram_socket,
43
+ )
44
+ from ._core._sockets import create_tcp_listener as create_tcp_listener
45
+ from ._core._sockets import create_udp_socket as create_udp_socket
46
+ from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket
47
+ from ._core._sockets import create_unix_listener as create_unix_listener
48
+ from ._core._sockets import getaddrinfo as getaddrinfo
49
+ from ._core._sockets import getnameinfo as getnameinfo
50
+ from ._core._sockets import notify_closing as notify_closing
51
+ from ._core._sockets import wait_readable as wait_readable
52
+ from ._core._sockets import wait_socket_readable as wait_socket_readable
53
+ from ._core._sockets import wait_socket_writable as wait_socket_writable
54
+ from ._core._sockets import wait_writable as wait_writable
55
+ from ._core._streams import create_memory_object_stream as create_memory_object_stream
56
+ from ._core._subprocesses import open_process as open_process
57
+ from ._core._subprocesses import run_process as run_process
58
+ from ._core._synchronization import CapacityLimiter as CapacityLimiter
59
+ from ._core._synchronization import (
60
+ CapacityLimiterStatistics as CapacityLimiterStatistics,
61
+ )
62
+ from ._core._synchronization import Condition as Condition
63
+ from ._core._synchronization import ConditionStatistics as ConditionStatistics
64
+ from ._core._synchronization import Event as Event
65
+ from ._core._synchronization import EventStatistics as EventStatistics
66
+ from ._core._synchronization import Lock as Lock
67
+ from ._core._synchronization import LockStatistics as LockStatistics
68
+ from ._core._synchronization import ResourceGuard as ResourceGuard
69
+ from ._core._synchronization import Semaphore as Semaphore
70
+ from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics
71
+ from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED
72
+ from ._core._tasks import CancelScope as CancelScope
73
+ from ._core._tasks import TaskHandle as TaskHandle
74
+ from ._core._tasks import create_task_group as create_task_group
75
+ from ._core._tasks import current_effective_deadline as current_effective_deadline
76
+ from ._core._tasks import fail_after as fail_after
77
+ from ._core._tasks import move_on_after as move_on_after
78
+ from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile
79
+ from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile
80
+ from ._core._tempfile import TemporaryDirectory as TemporaryDirectory
81
+ from ._core._tempfile import TemporaryFile as TemporaryFile
82
+ from ._core._tempfile import gettempdir as gettempdir
83
+ from ._core._tempfile import gettempdirb as gettempdirb
84
+ from ._core._tempfile import mkdtemp as mkdtemp
85
+ from ._core._tempfile import mkstemp as mkstemp
86
+ from ._core._testing import TaskInfo as TaskInfo
87
+ from ._core._testing import get_current_task as get_current_task
88
+ from ._core._testing import get_running_tasks as get_running_tasks
89
+ from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked
90
+ from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider
91
+ from ._core._typedattr import TypedAttributeSet as TypedAttributeSet
92
+ from ._core._typedattr import typed_attribute as typed_attribute
93
+
94
+ # Re-export imports so they look like they live directly in this package
95
+ for __value in list(locals().values()):
96
+ if getattr(__value, "__module__", "").startswith("anyio."):
97
+ __value.__module__ = __name__
98
+
99
+
100
+ del __value
101
+
102
+
103
+ def __getattr__(attr: str) -> type[BrokenWorkerInterpreter]:
104
+ """Support deprecated aliases."""
105
+ if attr == "BrokenWorkerIntepreter":
106
+ import warnings
107
+
108
+ warnings.warn(
109
+ "The 'BrokenWorkerIntepreter' alias is deprecated, use 'BrokenWorkerInterpreter' instead.",
110
+ DeprecationWarning,
111
+ stacklevel=2,
112
+ )
113
+ return BrokenWorkerInterpreter
114
+
115
+ raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
.venv/lib/python3.13/site-packages/anyio/_backends/__init__.py ADDED
File without changes
.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py ADDED
The diff for this file is too large to render. See raw diff
 
.venv/lib/python3.13/site-packages/anyio/_backends/_trio.py ADDED
@@ -0,0 +1,1468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 contextvars import Context
22
+ from dataclasses import dataclass
23
+ from functools import partial, wraps
24
+ from io import IOBase
25
+ from os import PathLike
26
+ from signal import Signals
27
+ from socket import AddressFamily, SocketKind
28
+ from types import TracebackType
29
+ from typing import (
30
+ IO,
31
+ TYPE_CHECKING,
32
+ Any,
33
+ Generic,
34
+ Literal,
35
+ NoReturn,
36
+ ParamSpec,
37
+ TypeVar,
38
+ cast,
39
+ overload,
40
+ )
41
+
42
+ import trio.from_thread
43
+ import trio.lowlevel
44
+ from outcome import Error, Outcome, Value
45
+ from trio.lowlevel import (
46
+ current_root_task,
47
+ current_task,
48
+ notify_closing,
49
+ wait_readable,
50
+ wait_writable,
51
+ )
52
+ from trio.socket import SocketType as TrioSocketType
53
+ from trio.to_thread import run_sync
54
+
55
+ from .. import (
56
+ CapacityLimiterStatistics,
57
+ EventStatistics,
58
+ LockStatistics,
59
+ RunFinishedError,
60
+ TaskInfo,
61
+ WouldBlock,
62
+ abc,
63
+ )
64
+ from .._core._eventloop import claim_worker_thread
65
+ from .._core._exceptions import (
66
+ BrokenResourceError,
67
+ BusyResourceError,
68
+ ClosedResourceError,
69
+ EndOfStream,
70
+ )
71
+ from .._core._sockets import convert_ipv6_sockaddr
72
+ from .._core._streams import create_memory_object_stream
73
+ from .._core._synchronization import (
74
+ CapacityLimiter as BaseCapacityLimiter,
75
+ )
76
+ from .._core._synchronization import Event as BaseEvent
77
+ from .._core._synchronization import Lock as BaseLock
78
+ from .._core._synchronization import (
79
+ ResourceGuard,
80
+ SemaphoreStatistics,
81
+ )
82
+ from .._core._synchronization import Semaphore as BaseSemaphore
83
+ from .._core._tasks import CancelScope as BaseCancelScope
84
+ from .._core._tasks import TaskHandle
85
+ from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType
86
+ from ..abc._eventloop import AsyncBackend, StrOrBytesPath
87
+ from ..abc._tasks import T_contra, call_for_coroutine, get_callable_name
88
+ from ..streams.memory import MemoryObjectSendStream
89
+
90
+ if TYPE_CHECKING:
91
+ from _typeshed import FileDescriptorLike
92
+
93
+ if sys.version_info >= (3, 11):
94
+ from typing import TypeVarTuple, Unpack
95
+ else:
96
+ from exceptiongroup import BaseExceptionGroup
97
+ from typing_extensions import TypeVarTuple, Unpack
98
+
99
+ T = TypeVar("T")
100
+ T_Retval = TypeVar("T_Retval")
101
+ T_co = TypeVar("T_co", covariant=True)
102
+ T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType)
103
+ PosArgsT = TypeVarTuple("PosArgsT")
104
+ P = ParamSpec("P")
105
+
106
+
107
+ def ensure_returns_coro(
108
+ func: Callable[P, Awaitable[T_Retval]],
109
+ ) -> Callable[P, Coroutine[Any, Any, T_Retval]]:
110
+ @wraps(func)
111
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T_Retval]:
112
+ awaitable = func(*args, **kwargs)
113
+ # Check the common case first.
114
+ if isinstance(awaitable, Coroutine):
115
+ return awaitable
116
+ elif not isinstance(awaitable, Awaitable):
117
+ # The user violated the type annotations. Still, we should pass this on to
118
+ # Trio so it can raise with an appropriate message.
119
+ return awaitable
120
+ else:
121
+
122
+ @wraps(func)
123
+ async def inner_wrapper() -> T_Retval:
124
+ return await awaitable
125
+
126
+ return inner_wrapper()
127
+
128
+ return wrapper
129
+
130
+
131
+ #
132
+ # Event loop
133
+ #
134
+
135
+ RunVar = trio.lowlevel.RunVar
136
+
137
+
138
+ #
139
+ # Timeouts and cancellation
140
+ #
141
+
142
+
143
+ class CancelScope(BaseCancelScope):
144
+ __slots__ = ("__original",)
145
+
146
+ def __new__(
147
+ cls, original: trio.CancelScope | None = None, **kwargs: object
148
+ ) -> CancelScope:
149
+ return object.__new__(cls)
150
+
151
+ def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None:
152
+ self.__original = original or trio.CancelScope(**kwargs)
153
+
154
+ def __enter__(self) -> CancelScope:
155
+ self.__original.__enter__()
156
+ return self
157
+
158
+ def __exit__(
159
+ self,
160
+ exc_type: type[BaseException] | None,
161
+ exc_val: BaseException | None,
162
+ exc_tb: TracebackType | None,
163
+ ) -> bool:
164
+ return self.__original.__exit__(exc_type, exc_val, exc_tb)
165
+
166
+ def cancel(self, reason: str | None = None) -> None:
167
+ self.__original.cancel(reason)
168
+
169
+ @property
170
+ def deadline(self) -> float:
171
+ return self.__original.deadline
172
+
173
+ @deadline.setter
174
+ def deadline(self, value: float) -> None:
175
+ self.__original.deadline = value
176
+
177
+ @property
178
+ def cancel_called(self) -> bool:
179
+ return self.__original.cancel_called
180
+
181
+ @property
182
+ def cancelled_caught(self) -> bool:
183
+ return self.__original.cancelled_caught
184
+
185
+ @property
186
+ def shield(self) -> bool:
187
+ return self.__original.shield
188
+
189
+ @shield.setter
190
+ def shield(self, value: bool) -> None:
191
+ self.__original.shield = value
192
+
193
+
194
+ #
195
+ # Task groups
196
+ #
197
+
198
+ empty_start_value = object()
199
+
200
+
201
+ class _TrioTaskStatus(Generic[T_contra], abc.TaskStatus[T_contra]):
202
+ early_start_value: T_contra | object = empty_start_value
203
+ real_task_status: trio.TaskStatus[T_contra | None] | None = None
204
+
205
+ def started(self, value: T_contra | None = None) -> None:
206
+ if self.real_task_status is None:
207
+ if self.early_start_value is not empty_start_value:
208
+ raise RuntimeError("called 'started' twice on the same task status")
209
+
210
+ self.early_start_value = value
211
+ else:
212
+ self.real_task_status.started(value)
213
+
214
+
215
+ class TaskGroup(abc.TaskGroup):
216
+ def __init__(self) -> None:
217
+ self._entered = False
218
+ self._active = False
219
+ self._nursery_manager = trio.open_nursery(strict_exception_groups=True)
220
+ self.cancel_scope = None # type: ignore[assignment]
221
+
222
+ async def __aenter__(self) -> TaskGroup:
223
+ if self._entered:
224
+ raise RuntimeError("TaskGroup cannot be entered more than once")
225
+
226
+ self._entered = True
227
+ self._active = True
228
+ self._nursery = await self._nursery_manager.__aenter__()
229
+ self.cancel_scope = CancelScope(self._nursery.cancel_scope)
230
+ return self
231
+
232
+ async def __aexit__(
233
+ self,
234
+ exc_type: type[BaseException] | None,
235
+ exc_val: BaseException | None,
236
+ exc_tb: TracebackType | None,
237
+ ) -> bool:
238
+ try:
239
+ # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type
240
+ return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) # type: ignore[return-value]
241
+ except BaseExceptionGroup as exc:
242
+ if not exc.split(trio.Cancelled)[1]:
243
+ raise trio.Cancelled._create() from exc
244
+
245
+ raise
246
+ finally:
247
+ del exc_val, exc_tb
248
+ self._active = False
249
+
250
+ def _check_active(self, coro: Coroutine | None = None) -> None:
251
+ if not self._active:
252
+ if coro is not None:
253
+ coro.close()
254
+
255
+ raise RuntimeError(
256
+ "This task group is not active; no new tasks can be started."
257
+ )
258
+
259
+ def create_task(
260
+ self,
261
+ coro: Coroutine[Any, Any, T_co],
262
+ *,
263
+ name: object = None,
264
+ context: Context | None = None,
265
+ ) -> TaskHandle[T_co]:
266
+ if not isinstance(coro, Coroutine):
267
+ raise TypeError(f"expected a coroutine, got {coro.__class__.__qualname__}")
268
+
269
+ self._check_active(coro)
270
+ handle = TaskHandle(coro, name)
271
+ if context is not None:
272
+ context.run(
273
+ partial(self._nursery.start_soon, handle._run_coro, name=handle.name)
274
+ )
275
+ else:
276
+ self._nursery.start_soon(handle._run_coro, name=handle.name)
277
+
278
+ return handle
279
+
280
+ async def start(
281
+ self,
282
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
283
+ *args: Unpack[PosArgsT],
284
+ name: object = None,
285
+ return_handle: Literal[False] | Literal[True] = False,
286
+ ) -> Any:
287
+ handle: TaskHandle[T_co]
288
+
289
+ async def run_coro_with_task_status(
290
+ *, task_status: trio.TaskStatus[Any]
291
+ ) -> None:
292
+ nonlocal handle
293
+ wrapper_task_status = _TrioTaskStatus()
294
+ coro = call_for_coroutine(func, args, task_status=wrapper_task_status)
295
+ if wrapper_task_status.early_start_value is not empty_start_value:
296
+ task_status.started(wrapper_task_status.early_start_value)
297
+ else:
298
+ wrapper_task_status.real_task_status = task_status
299
+
300
+ handle = TaskHandle(coro, name)
301
+ await handle._run_coro()
302
+
303
+ self._check_active()
304
+ final_name = get_callable_name(func, name)
305
+ start_value = await self._nursery.start(
306
+ run_coro_with_task_status, name=final_name
307
+ )
308
+ if return_handle:
309
+ handle._start_value = start_value
310
+ return handle
311
+ else:
312
+ return start_value
313
+
314
+
315
+ #
316
+ # Subprocesses
317
+ #
318
+
319
+
320
+ @dataclass(eq=False)
321
+ class ReceiveStreamWrapper(abc.ByteReceiveStream):
322
+ _stream: trio.abc.ReceiveStream
323
+
324
+ async def receive(self, max_bytes: int | None = None) -> bytes:
325
+ if max_bytes is not None and max_bytes < 1:
326
+ raise ValueError("max_bytes must be a positive integer")
327
+
328
+ try:
329
+ data = await self._stream.receive_some(max_bytes)
330
+ except trio.ClosedResourceError as exc:
331
+ raise ClosedResourceError from exc.__cause__
332
+ except trio.BrokenResourceError as exc:
333
+ raise BrokenResourceError from exc.__cause__
334
+
335
+ if data:
336
+ return bytes(data)
337
+ else:
338
+ raise EndOfStream
339
+
340
+ async def aclose(self) -> None:
341
+ await self._stream.aclose()
342
+
343
+
344
+ @dataclass(eq=False)
345
+ class SendStreamWrapper(abc.ByteSendStream):
346
+ _stream: trio.abc.SendStream
347
+
348
+ async def send(self, item: bytes) -> None:
349
+ try:
350
+ await self._stream.send_all(item)
351
+ except trio.ClosedResourceError as exc:
352
+ raise ClosedResourceError from exc.__cause__
353
+ except trio.BrokenResourceError as exc:
354
+ raise BrokenResourceError from exc.__cause__
355
+
356
+ async def aclose(self) -> None:
357
+ await self._stream.aclose()
358
+
359
+
360
+ @dataclass(eq=False)
361
+ class Process(abc.Process):
362
+ _process: trio.Process
363
+ _stdin: abc.ByteSendStream | None
364
+ _stdout: abc.ByteReceiveStream | None
365
+ _stderr: abc.ByteReceiveStream | None
366
+
367
+ async def aclose(self) -> None:
368
+ with CancelScope(shield=True):
369
+ if self._stdin:
370
+ await self._stdin.aclose()
371
+ if self._stdout:
372
+ await self._stdout.aclose()
373
+ if self._stderr:
374
+ await self._stderr.aclose()
375
+
376
+ try:
377
+ await self.wait()
378
+ except BaseException:
379
+ self.kill()
380
+ with CancelScope(shield=True):
381
+ await self.wait()
382
+ raise
383
+
384
+ async def wait(self) -> int:
385
+ return await self._process.wait()
386
+
387
+ def terminate(self) -> None:
388
+ self._process.terminate()
389
+
390
+ def kill(self) -> None:
391
+ self._process.kill()
392
+
393
+ def send_signal(self, signal: Signals) -> None:
394
+ self._process.send_signal(signal)
395
+
396
+ @property
397
+ def pid(self) -> int:
398
+ return self._process.pid
399
+
400
+ @property
401
+ def returncode(self) -> int | None:
402
+ return self._process.returncode
403
+
404
+ @property
405
+ def stdin(self) -> abc.ByteSendStream | None:
406
+ return self._stdin
407
+
408
+ @property
409
+ def stdout(self) -> abc.ByteReceiveStream | None:
410
+ return self._stdout
411
+
412
+ @property
413
+ def stderr(self) -> abc.ByteReceiveStream | None:
414
+ return self._stderr
415
+
416
+
417
+ class _ProcessPoolShutdownInstrument(trio.abc.Instrument):
418
+ def after_run(self) -> None:
419
+ super().after_run()
420
+
421
+
422
+ current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar(
423
+ "current_default_worker_process_limiter"
424
+ )
425
+
426
+
427
+ async def _shutdown_process_pool(workers: set[abc.Process]) -> None:
428
+ try:
429
+ await trio.sleep(math.inf)
430
+ except trio.Cancelled:
431
+ for process in workers:
432
+ if process.returncode is None:
433
+ process.kill()
434
+
435
+ with CancelScope(shield=True):
436
+ for process in workers:
437
+ await process.aclose()
438
+
439
+
440
+ #
441
+ # Sockets and networking
442
+ #
443
+
444
+
445
+ class _TrioSocketMixin(Generic[T_SockAddr]):
446
+ def __init__(self, trio_socket: TrioSocketType) -> None:
447
+ self._trio_socket = trio_socket
448
+ self._closed = False
449
+
450
+ def _check_closed(self) -> None:
451
+ if self._closed:
452
+ raise ClosedResourceError
453
+ if self._trio_socket.fileno() < 0:
454
+ raise BrokenResourceError
455
+
456
+ @property
457
+ def _raw_socket(self) -> socket.socket:
458
+ return self._trio_socket._sock # type: ignore[attr-defined]
459
+
460
+ async def aclose(self) -> None:
461
+ if self._trio_socket.fileno() >= 0:
462
+ self._closed = True
463
+ self._trio_socket.close()
464
+
465
+ def _convert_socket_error(self, exc: BaseException) -> NoReturn:
466
+ if isinstance(exc, trio.ClosedResourceError):
467
+ raise ClosedResourceError from exc
468
+ elif self._trio_socket.fileno() < 0 and self._closed:
469
+ raise ClosedResourceError from None
470
+ elif isinstance(exc, OSError):
471
+ raise BrokenResourceError from exc
472
+ else:
473
+ raise exc
474
+
475
+
476
+ class SocketStream(_TrioSocketMixin, abc.SocketStream):
477
+ def __init__(self, trio_socket: TrioSocketType) -> None:
478
+ super().__init__(trio_socket)
479
+ self._receive_guard = ResourceGuard("reading from")
480
+ self._send_guard = ResourceGuard("writing to")
481
+
482
+ async def receive(self, max_bytes: int = 65536) -> bytes:
483
+ if max_bytes < 1:
484
+ raise ValueError("max_bytes must be a positive integer")
485
+
486
+ with self._receive_guard:
487
+ try:
488
+ data = await self._trio_socket.recv(max_bytes)
489
+ except BaseException as exc:
490
+ self._convert_socket_error(exc)
491
+
492
+ if data:
493
+ return data
494
+ else:
495
+ raise EndOfStream
496
+
497
+ async def send(self, item: bytes) -> None:
498
+ with self._send_guard:
499
+ view = memoryview(item)
500
+ while view:
501
+ try:
502
+ bytes_sent = await self._trio_socket.send(view)
503
+ except BaseException as exc:
504
+ self._convert_socket_error(exc)
505
+
506
+ view = view[bytes_sent:]
507
+
508
+ async def send_eof(self) -> None:
509
+ self._trio_socket.shutdown(socket.SHUT_WR)
510
+
511
+
512
+ class UNIXSocketStream(SocketStream, abc.UNIXSocketStream):
513
+ async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
514
+ if not isinstance(msglen, int) or msglen < 0:
515
+ raise ValueError("msglen must be a non-negative integer")
516
+ if not isinstance(maxfds, int) or maxfds < 1:
517
+ raise ValueError("maxfds must be a positive integer")
518
+
519
+ fds = array.array("i")
520
+ await trio.lowlevel.checkpoint()
521
+ with self._receive_guard:
522
+ while True:
523
+ try:
524
+ message, ancdata, flags, addr = await self._trio_socket.recvmsg(
525
+ msglen, socket.CMSG_LEN(maxfds * fds.itemsize)
526
+ )
527
+ except BaseException as exc:
528
+ self._convert_socket_error(exc)
529
+ else:
530
+ if not message and not ancdata:
531
+ raise EndOfStream
532
+
533
+ break
534
+
535
+ for cmsg_level, cmsg_type, cmsg_data in ancdata:
536
+ if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS:
537
+ raise RuntimeError(
538
+ f"Received unexpected ancillary data; message = {message!r}, "
539
+ f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}"
540
+ )
541
+
542
+ fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
543
+
544
+ return message, list(fds)
545
+
546
+ async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
547
+ if not message:
548
+ raise ValueError("message must not be empty")
549
+ if not fds:
550
+ raise ValueError("fds must not be empty")
551
+
552
+ filenos: list[int] = []
553
+ for fd in fds:
554
+ if isinstance(fd, int):
555
+ filenos.append(fd)
556
+ elif isinstance(fd, IOBase):
557
+ filenos.append(fd.fileno())
558
+
559
+ fdarray = array.array("i", filenos)
560
+ await trio.lowlevel.checkpoint()
561
+ with self._send_guard:
562
+ while True:
563
+ try:
564
+ await self._trio_socket.sendmsg(
565
+ [message],
566
+ [
567
+ (
568
+ socket.SOL_SOCKET,
569
+ socket.SCM_RIGHTS,
570
+ fdarray,
571
+ )
572
+ ],
573
+ )
574
+ break
575
+ except BaseException as exc:
576
+ self._convert_socket_error(exc)
577
+
578
+
579
+ class TCPSocketListener(_TrioSocketMixin, abc.SocketListener):
580
+ def __init__(self, raw_socket: socket.socket):
581
+ super().__init__(trio.socket.from_stdlib_socket(raw_socket))
582
+ self._accept_guard = ResourceGuard("accepting connections from")
583
+
584
+ async def accept(self) -> SocketStream:
585
+ with self._accept_guard:
586
+ try:
587
+ trio_socket, _addr = await self._trio_socket.accept()
588
+ except BaseException as exc:
589
+ self._convert_socket_error(exc)
590
+
591
+ trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
592
+ return SocketStream(trio_socket)
593
+
594
+
595
+ class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener):
596
+ def __init__(self, raw_socket: socket.socket):
597
+ super().__init__(trio.socket.from_stdlib_socket(raw_socket))
598
+ self._accept_guard = ResourceGuard("accepting connections from")
599
+
600
+ async def accept(self) -> UNIXSocketStream:
601
+ with self._accept_guard:
602
+ try:
603
+ trio_socket, _addr = await self._trio_socket.accept()
604
+ except BaseException as exc:
605
+ self._convert_socket_error(exc)
606
+
607
+ return UNIXSocketStream(trio_socket)
608
+
609
+
610
+ class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket):
611
+ def __init__(self, trio_socket: TrioSocketType) -> None:
612
+ super().__init__(trio_socket)
613
+ self._receive_guard = ResourceGuard("reading from")
614
+ self._send_guard = ResourceGuard("writing to")
615
+
616
+ async def receive(self) -> tuple[bytes, IPSockAddrType]:
617
+ with self._receive_guard:
618
+ try:
619
+ data, addr = await self._trio_socket.recvfrom(65536)
620
+ return data, convert_ipv6_sockaddr(addr)
621
+ except BaseException as exc:
622
+ self._convert_socket_error(exc)
623
+
624
+ async def send(self, item: UDPPacketType) -> None:
625
+ with self._send_guard:
626
+ try:
627
+ await self._trio_socket.sendto(*item)
628
+ except BaseException as exc:
629
+ self._convert_socket_error(exc)
630
+
631
+
632
+ class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket):
633
+ def __init__(self, trio_socket: TrioSocketType) -> None:
634
+ super().__init__(trio_socket)
635
+ self._receive_guard = ResourceGuard("reading from")
636
+ self._send_guard = ResourceGuard("writing to")
637
+
638
+ async def receive(self) -> bytes:
639
+ with self._receive_guard:
640
+ try:
641
+ return await self._trio_socket.recv(65536)
642
+ except BaseException as exc:
643
+ self._convert_socket_error(exc)
644
+
645
+ async def send(self, item: bytes) -> None:
646
+ with self._send_guard:
647
+ try:
648
+ await self._trio_socket.send(item)
649
+ except BaseException as exc:
650
+ self._convert_socket_error(exc)
651
+
652
+
653
+ class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket):
654
+ def __init__(self, trio_socket: TrioSocketType) -> None:
655
+ super().__init__(trio_socket)
656
+ self._receive_guard = ResourceGuard("reading from")
657
+ self._send_guard = ResourceGuard("writing to")
658
+
659
+ async def receive(self) -> UNIXDatagramPacketType:
660
+ with self._receive_guard:
661
+ try:
662
+ data, addr = await self._trio_socket.recvfrom(65536)
663
+ return data, addr
664
+ except BaseException as exc:
665
+ self._convert_socket_error(exc)
666
+
667
+ async def send(self, item: UNIXDatagramPacketType) -> None:
668
+ with self._send_guard:
669
+ try:
670
+ await self._trio_socket.sendto(*item)
671
+ except BaseException as exc:
672
+ self._convert_socket_error(exc)
673
+
674
+
675
+ class ConnectedUNIXDatagramSocket(
676
+ _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket
677
+ ):
678
+ def __init__(self, trio_socket: TrioSocketType) -> None:
679
+ super().__init__(trio_socket)
680
+ self._receive_guard = ResourceGuard("reading from")
681
+ self._send_guard = ResourceGuard("writing to")
682
+
683
+ async def receive(self) -> bytes:
684
+ with self._receive_guard:
685
+ try:
686
+ return await self._trio_socket.recv(65536)
687
+ except BaseException as exc:
688
+ self._convert_socket_error(exc)
689
+
690
+ async def send(self, item: bytes) -> None:
691
+ with self._send_guard:
692
+ try:
693
+ await self._trio_socket.send(item)
694
+ except BaseException as exc:
695
+ self._convert_socket_error(exc)
696
+
697
+
698
+ #
699
+ # Synchronization
700
+ #
701
+
702
+
703
+ class Event(BaseEvent):
704
+ __slots__ = ("__original",)
705
+
706
+ def __new__(cls) -> Event:
707
+ return object.__new__(cls)
708
+
709
+ def __init__(self) -> None:
710
+ self.__original = trio.Event()
711
+
712
+ def is_set(self) -> bool:
713
+ return self.__original.is_set()
714
+
715
+ async def wait(self) -> None:
716
+ return await self.__original.wait()
717
+
718
+ def statistics(self) -> EventStatistics:
719
+ orig_statistics = self.__original.statistics()
720
+ return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting)
721
+
722
+ def set(self) -> None:
723
+ self.__original.set()
724
+
725
+
726
+ class Lock(BaseLock):
727
+ __slots__ = "_fast_acquire", "__original"
728
+
729
+ def __new__(cls, *, fast_acquire: bool = False) -> Lock:
730
+ return object.__new__(cls)
731
+
732
+ def __init__(self, *, fast_acquire: bool = False) -> None:
733
+ self._fast_acquire = fast_acquire
734
+ self.__original = trio.Lock()
735
+
736
+ @staticmethod
737
+ def _convert_runtime_error_msg(exc: RuntimeError) -> None:
738
+ if exc.args == ("attempt to re-acquire an already held Lock",):
739
+ exc.args = ("Attempted to acquire an already held Lock",)
740
+
741
+ async def acquire(self) -> None:
742
+ if not self._fast_acquire:
743
+ try:
744
+ await self.__original.acquire()
745
+ except RuntimeError as exc:
746
+ self._convert_runtime_error_msg(exc)
747
+ raise
748
+
749
+ return
750
+
751
+ # This is the "fast path" where we don't let other tasks run
752
+ await trio.lowlevel.checkpoint_if_cancelled()
753
+ try:
754
+ self.__original.acquire_nowait()
755
+ except trio.WouldBlock:
756
+ await self.__original._lot.park()
757
+ except RuntimeError as exc:
758
+ self._convert_runtime_error_msg(exc)
759
+ raise
760
+
761
+ def acquire_nowait(self) -> None:
762
+ try:
763
+ self.__original.acquire_nowait()
764
+ except trio.WouldBlock:
765
+ raise WouldBlock from None
766
+ except RuntimeError as exc:
767
+ self._convert_runtime_error_msg(exc)
768
+ raise
769
+
770
+ def locked(self) -> bool:
771
+ return self.__original.locked()
772
+
773
+ def release(self) -> None:
774
+ self.__original.release()
775
+
776
+ def statistics(self) -> LockStatistics:
777
+ orig_statistics = self.__original.statistics()
778
+ owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None
779
+ return LockStatistics(
780
+ orig_statistics.locked, owner, orig_statistics.tasks_waiting
781
+ )
782
+
783
+
784
+ class Semaphore(BaseSemaphore):
785
+ __slots__ = ("__original",)
786
+
787
+ def __new__(
788
+ cls,
789
+ initial_value: int,
790
+ *,
791
+ max_value: int | None = None,
792
+ fast_acquire: bool = False,
793
+ ) -> Semaphore:
794
+ return object.__new__(cls)
795
+
796
+ def __init__(
797
+ self,
798
+ initial_value: int,
799
+ *,
800
+ max_value: int | None = None,
801
+ fast_acquire: bool = False,
802
+ ) -> None:
803
+ super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
804
+ self.__original = trio.Semaphore(initial_value, max_value=max_value)
805
+
806
+ async def acquire(self) -> None:
807
+ if not self._fast_acquire:
808
+ await self.__original.acquire()
809
+ return
810
+
811
+ # This is the "fast path" where we don't let other tasks run
812
+ await trio.lowlevel.checkpoint_if_cancelled()
813
+ try:
814
+ self.__original.acquire_nowait()
815
+ except trio.WouldBlock:
816
+ await self.__original._lot.park()
817
+
818
+ def acquire_nowait(self) -> None:
819
+ try:
820
+ self.__original.acquire_nowait()
821
+ except trio.WouldBlock:
822
+ raise WouldBlock from None
823
+
824
+ @property
825
+ def max_value(self) -> int | None:
826
+ return self.__original.max_value
827
+
828
+ @property
829
+ def value(self) -> int:
830
+ return self.__original.value
831
+
832
+ def release(self) -> None:
833
+ self.__original.release()
834
+
835
+ def statistics(self) -> SemaphoreStatistics:
836
+ orig_statistics = self.__original.statistics()
837
+ return SemaphoreStatistics(orig_statistics.tasks_waiting)
838
+
839
+
840
+ class CapacityLimiter(BaseCapacityLimiter):
841
+ __slots__ = ("__original",)
842
+
843
+ def __new__(
844
+ cls,
845
+ total_tokens: float | None = None,
846
+ *,
847
+ original: trio.CapacityLimiter | None = None,
848
+ ) -> CapacityLimiter:
849
+ return object.__new__(cls)
850
+
851
+ def __init__(
852
+ self,
853
+ total_tokens: float | None = None,
854
+ *,
855
+ original: trio.CapacityLimiter | None = None,
856
+ ) -> None:
857
+ if original is not None:
858
+ self.__original = original
859
+ else:
860
+ assert total_tokens is not None
861
+ self.__original = trio.CapacityLimiter(total_tokens)
862
+
863
+ async def __aenter__(self) -> None:
864
+ return await self.__original.__aenter__()
865
+
866
+ async def __aexit__(
867
+ self,
868
+ exc_type: type[BaseException] | None,
869
+ exc_val: BaseException | None,
870
+ exc_tb: TracebackType | None,
871
+ ) -> None:
872
+ await self.__original.__aexit__(exc_type, exc_val, exc_tb)
873
+
874
+ @property
875
+ def total_tokens(self) -> float:
876
+ return self.__original.total_tokens
877
+
878
+ @total_tokens.setter
879
+ def total_tokens(self, value: float) -> None:
880
+ self.__original.total_tokens = value
881
+
882
+ @property
883
+ def borrowed_tokens(self) -> int:
884
+ return self.__original.borrowed_tokens
885
+
886
+ @property
887
+ def available_tokens(self) -> float:
888
+ return self.__original.available_tokens
889
+
890
+ def acquire_nowait(self) -> None:
891
+ try:
892
+ self.__original.acquire_nowait()
893
+ except trio.WouldBlock:
894
+ raise WouldBlock from None
895
+
896
+ def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
897
+ try:
898
+ self.__original.acquire_on_behalf_of_nowait(borrower)
899
+ except trio.WouldBlock:
900
+ raise WouldBlock from None
901
+
902
+ async def acquire(self) -> None:
903
+ await self.__original.acquire()
904
+
905
+ async def acquire_on_behalf_of(self, borrower: object) -> None:
906
+ await self.__original.acquire_on_behalf_of(borrower)
907
+
908
+ def release(self) -> None:
909
+ return self.__original.release()
910
+
911
+ def release_on_behalf_of(self, borrower: object) -> None:
912
+ return self.__original.release_on_behalf_of(borrower)
913
+
914
+ def statistics(self) -> CapacityLimiterStatistics:
915
+ orig = self.__original.statistics()
916
+ return CapacityLimiterStatistics(
917
+ borrowed_tokens=orig.borrowed_tokens,
918
+ total_tokens=orig.total_tokens,
919
+ borrowers=tuple(orig.borrowers),
920
+ tasks_waiting=orig.tasks_waiting,
921
+ )
922
+
923
+
924
+ _capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper")
925
+
926
+
927
+ #
928
+ # Signal handling
929
+ #
930
+
931
+
932
+ class _SignalReceiver:
933
+ _iterator: AsyncIterator[int]
934
+
935
+ def __init__(self, signals: tuple[Signals, ...]):
936
+ self._signals = signals
937
+
938
+ def __enter__(self) -> _SignalReceiver:
939
+ self._cm = trio.open_signal_receiver(*self._signals)
940
+ self._iterator = self._cm.__enter__()
941
+ return self
942
+
943
+ def __exit__(
944
+ self,
945
+ exc_type: type[BaseException] | None,
946
+ exc_val: BaseException | None,
947
+ exc_tb: TracebackType | None,
948
+ ) -> bool | None:
949
+ return self._cm.__exit__(exc_type, exc_val, exc_tb)
950
+
951
+ def __aiter__(self) -> _SignalReceiver:
952
+ return self
953
+
954
+ async def __anext__(self) -> Signals:
955
+ signum = await self._iterator.__anext__()
956
+ return Signals(signum)
957
+
958
+
959
+ #
960
+ # Testing and debugging
961
+ #
962
+
963
+
964
+ class TestRunner(abc.TestRunner):
965
+ def __init__(self, **options: Any) -> None:
966
+ from queue import Queue
967
+
968
+ self._call_queue: Queue[Callable[[], object]] = Queue()
969
+ self._send_stream: (
970
+ MemoryObjectSendStream[tuple[Awaitable[Any], list[Outcome]]] | None
971
+ ) = None
972
+ self._options = options
973
+
974
+ def __exit__(
975
+ self,
976
+ exc_type: type[BaseException] | None,
977
+ exc_val: BaseException | None,
978
+ exc_tb: types.TracebackType | None,
979
+ ) -> None:
980
+ if self._send_stream:
981
+ self._send_stream.close()
982
+ while self._send_stream is not None:
983
+ self._call_queue.get()()
984
+
985
+ def is_running(self) -> bool:
986
+ return trio.lowlevel.in_trio_task()
987
+
988
+ async def _run_tests_and_fixtures(self) -> None:
989
+ self._send_stream, receive_stream = create_memory_object_stream[
990
+ tuple[Awaitable[Any], list[Outcome]]
991
+ ](1)
992
+ with receive_stream:
993
+ async for awaitable, outcome_holder in receive_stream:
994
+ try:
995
+ retval = await awaitable
996
+ except BaseException as exc:
997
+ outcome_holder.append(Error(exc))
998
+ else:
999
+ outcome_holder.append(Value(retval))
1000
+
1001
+ def _main_task_finished(self, outcome: object) -> None:
1002
+ self._send_stream = None
1003
+
1004
+ def _call_in_runner_task(
1005
+ self,
1006
+ func: Callable[P, Awaitable[T_Retval]],
1007
+ /,
1008
+ *args: P.args,
1009
+ **kwargs: P.kwargs,
1010
+ ) -> T_Retval:
1011
+ if self._send_stream is None:
1012
+ trio.lowlevel.start_guest_run(
1013
+ self._run_tests_and_fixtures,
1014
+ run_sync_soon_threadsafe=self._call_queue.put,
1015
+ done_callback=self._main_task_finished,
1016
+ **self._options,
1017
+ )
1018
+ while self._send_stream is None:
1019
+ self._call_queue.get()()
1020
+
1021
+ outcome_holder: list[Outcome] = []
1022
+ self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder))
1023
+ while not outcome_holder:
1024
+ self._call_queue.get()()
1025
+
1026
+ return outcome_holder[0].unwrap()
1027
+
1028
+ def run_asyncgen_fixture(
1029
+ self,
1030
+ fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]],
1031
+ kwargs: dict[str, Any],
1032
+ ) -> Iterable[T_Retval]:
1033
+ asyncgen = fixture_func(**kwargs)
1034
+ fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None)
1035
+
1036
+ yield fixturevalue
1037
+
1038
+ try:
1039
+ self._call_in_runner_task(asyncgen.asend, None)
1040
+ except StopAsyncIteration:
1041
+ pass
1042
+ else:
1043
+ self._call_in_runner_task(asyncgen.aclose)
1044
+ raise RuntimeError("Async generator fixture did not stop")
1045
+
1046
+ def run_fixture(
1047
+ self,
1048
+ fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]],
1049
+ kwargs: dict[str, Any],
1050
+ ) -> T_Retval:
1051
+ return self._call_in_runner_task(fixture_func, **kwargs)
1052
+
1053
+ def run_test(
1054
+ self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
1055
+ ) -> None:
1056
+ self._call_in_runner_task(test_func, **kwargs)
1057
+
1058
+
1059
+ class TrioTaskInfo(TaskInfo):
1060
+ def __init__(self, task: trio.lowlevel.Task):
1061
+ parent_id = None
1062
+ if task.parent_nursery and task.parent_nursery.parent_task:
1063
+ parent_id = id(task.parent_nursery.parent_task)
1064
+
1065
+ super().__init__(id(task), parent_id, task.name, task.coro)
1066
+ self._task = weakref.proxy(task)
1067
+
1068
+ def has_pending_cancellation(self) -> bool:
1069
+ try:
1070
+ return self._task._cancel_status.effectively_cancelled
1071
+ except ReferenceError:
1072
+ # If the task is no longer around, it surely doesn't have a cancellation
1073
+ # pending
1074
+ return False
1075
+
1076
+
1077
+ class TrioBackend(AsyncBackend):
1078
+ @classmethod
1079
+ def run(
1080
+ cls,
1081
+ func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
1082
+ args: tuple[Unpack[PosArgsT]],
1083
+ kwargs: dict[str, Any],
1084
+ options: dict[str, Any],
1085
+ ) -> T_Retval:
1086
+ assert not kwargs, "unreachable, and not supported by Trio"
1087
+ return trio.run(ensure_returns_coro(func), *args, **options)
1088
+
1089
+ @classmethod
1090
+ def current_token(cls) -> object:
1091
+ return trio.lowlevel.current_trio_token()
1092
+
1093
+ @classmethod
1094
+ def current_time(cls) -> float:
1095
+ return trio.current_time()
1096
+
1097
+ @classmethod
1098
+ def cancelled_exception_class(cls) -> type[BaseException]:
1099
+ return trio.Cancelled
1100
+
1101
+ @classmethod
1102
+ async def checkpoint(cls) -> None:
1103
+ await trio.lowlevel.checkpoint()
1104
+
1105
+ @classmethod
1106
+ async def checkpoint_if_cancelled(cls) -> None:
1107
+ await trio.lowlevel.checkpoint_if_cancelled()
1108
+
1109
+ @classmethod
1110
+ async def cancel_shielded_checkpoint(cls) -> None:
1111
+ await trio.lowlevel.cancel_shielded_checkpoint()
1112
+
1113
+ @classmethod
1114
+ async def sleep(cls, delay: float) -> None:
1115
+ await trio.sleep(delay)
1116
+
1117
+ @classmethod
1118
+ def create_cancel_scope(
1119
+ cls, *, deadline: float = math.inf, shield: bool = False
1120
+ ) -> abc.CancelScope:
1121
+ return CancelScope(deadline=deadline, shield=shield)
1122
+
1123
+ @classmethod
1124
+ def current_effective_deadline(cls) -> float:
1125
+ return trio.current_effective_deadline()
1126
+
1127
+ @classmethod
1128
+ def create_task_group(cls) -> abc.TaskGroup:
1129
+ return TaskGroup()
1130
+
1131
+ @classmethod
1132
+ def create_event(cls) -> abc.Event:
1133
+ return Event()
1134
+
1135
+ @classmethod
1136
+ def create_lock(cls, *, fast_acquire: bool) -> Lock:
1137
+ return Lock(fast_acquire=fast_acquire)
1138
+
1139
+ @classmethod
1140
+ def create_semaphore(
1141
+ cls,
1142
+ initial_value: int,
1143
+ *,
1144
+ max_value: int | None = None,
1145
+ fast_acquire: bool = False,
1146
+ ) -> abc.Semaphore:
1147
+ return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire)
1148
+
1149
+ @classmethod
1150
+ def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
1151
+ return CapacityLimiter(total_tokens)
1152
+
1153
+ @classmethod
1154
+ async def run_sync_in_worker_thread(
1155
+ cls,
1156
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
1157
+ args: tuple[Unpack[PosArgsT]],
1158
+ abandon_on_cancel: bool = False,
1159
+ limiter: abc.CapacityLimiter | None = None,
1160
+ ) -> T_Retval:
1161
+ def wrapper() -> T_Retval:
1162
+ with claim_worker_thread(TrioBackend, token):
1163
+ return func(*args)
1164
+
1165
+ token = TrioBackend.current_token()
1166
+ return await run_sync(
1167
+ wrapper,
1168
+ abandon_on_cancel=abandon_on_cancel,
1169
+ limiter=cast(trio.CapacityLimiter, limiter),
1170
+ )
1171
+
1172
+ @classmethod
1173
+ def check_cancelled(cls) -> None:
1174
+ trio.from_thread.check_cancelled()
1175
+
1176
+ @classmethod
1177
+ def run_async_from_thread(
1178
+ cls,
1179
+ func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]],
1180
+ args: tuple[Unpack[PosArgsT]],
1181
+ token: object,
1182
+ ) -> T_co:
1183
+ trio_token = cast("trio.lowlevel.TrioToken | None", token)
1184
+ try:
1185
+ return trio.from_thread.run(func, *args, trio_token=trio_token)
1186
+ except trio.RunFinishedError:
1187
+ raise RunFinishedError from None
1188
+
1189
+ @classmethod
1190
+ def run_sync_from_thread(
1191
+ cls,
1192
+ func: Callable[[Unpack[PosArgsT]], T_Retval],
1193
+ args: tuple[Unpack[PosArgsT]],
1194
+ token: object,
1195
+ ) -> T_Retval:
1196
+ trio_token = cast("trio.lowlevel.TrioToken | None", token)
1197
+ try:
1198
+ return trio.from_thread.run_sync(func, *args, trio_token=trio_token)
1199
+ except trio.RunFinishedError:
1200
+ raise RunFinishedError from None
1201
+
1202
+ @classmethod
1203
+ async def open_process(
1204
+ cls,
1205
+ command: StrOrBytesPath | Sequence[StrOrBytesPath],
1206
+ *,
1207
+ stdin: int | IO[Any] | None,
1208
+ stdout: int | IO[Any] | None,
1209
+ stderr: int | IO[Any] | None,
1210
+ **kwargs: Any,
1211
+ ) -> Process:
1212
+ def convert_item(item: StrOrBytesPath) -> str:
1213
+ str_or_bytes = os.fspath(item)
1214
+ if isinstance(str_or_bytes, str):
1215
+ return str_or_bytes
1216
+ else:
1217
+ return os.fsdecode(str_or_bytes)
1218
+
1219
+ if isinstance(command, (str, bytes, PathLike)):
1220
+ process = await trio.lowlevel.open_process(
1221
+ convert_item(command),
1222
+ stdin=stdin,
1223
+ stdout=stdout,
1224
+ stderr=stderr,
1225
+ shell=True,
1226
+ **kwargs,
1227
+ )
1228
+ else:
1229
+ process = await trio.lowlevel.open_process(
1230
+ [convert_item(item) for item in command],
1231
+ stdin=stdin,
1232
+ stdout=stdout,
1233
+ stderr=stderr,
1234
+ shell=False,
1235
+ **kwargs,
1236
+ )
1237
+
1238
+ stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None
1239
+ stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None
1240
+ stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None
1241
+ return Process(process, stdin_stream, stdout_stream, stderr_stream)
1242
+
1243
+ @classmethod
1244
+ def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None:
1245
+ trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers)
1246
+
1247
+ @classmethod
1248
+ async def connect_tcp(
1249
+ cls, host: str, port: int, local_address: IPSockAddrType | None = None
1250
+ ) -> SocketStream:
1251
+ family = socket.AF_INET6 if ":" in host else socket.AF_INET
1252
+ trio_socket = trio.socket.socket(family)
1253
+ trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
1254
+ if local_address:
1255
+ await trio_socket.bind(local_address)
1256
+
1257
+ try:
1258
+ await trio_socket.connect((host, port))
1259
+ except BaseException:
1260
+ trio_socket.close()
1261
+ raise
1262
+
1263
+ return SocketStream(trio_socket)
1264
+
1265
+ @classmethod
1266
+ async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream:
1267
+ trio_socket = trio.socket.socket(socket.AF_UNIX)
1268
+ try:
1269
+ await trio_socket.connect(path)
1270
+ except BaseException:
1271
+ trio_socket.close()
1272
+ raise
1273
+
1274
+ return UNIXSocketStream(trio_socket)
1275
+
1276
+ @classmethod
1277
+ def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener:
1278
+ return TCPSocketListener(sock)
1279
+
1280
+ @classmethod
1281
+ def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener:
1282
+ return UNIXSocketListener(sock)
1283
+
1284
+ @classmethod
1285
+ async def create_udp_socket(
1286
+ cls,
1287
+ family: socket.AddressFamily,
1288
+ local_address: IPSockAddrType | None,
1289
+ remote_address: IPSockAddrType | None,
1290
+ reuse_port: bool,
1291
+ ) -> UDPSocket | ConnectedUDPSocket:
1292
+ trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM)
1293
+
1294
+ if reuse_port:
1295
+ trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
1296
+
1297
+ if local_address:
1298
+ await trio_socket.bind(local_address)
1299
+
1300
+ if remote_address:
1301
+ await trio_socket.connect(remote_address)
1302
+ return ConnectedUDPSocket(trio_socket)
1303
+ else:
1304
+ return UDPSocket(trio_socket)
1305
+
1306
+ @classmethod
1307
+ @overload
1308
+ async def create_unix_datagram_socket(
1309
+ cls, raw_socket: socket.socket, remote_path: None
1310
+ ) -> abc.UNIXDatagramSocket: ...
1311
+
1312
+ @classmethod
1313
+ @overload
1314
+ async def create_unix_datagram_socket(
1315
+ cls, raw_socket: socket.socket, remote_path: str | bytes
1316
+ ) -> abc.ConnectedUNIXDatagramSocket: ...
1317
+
1318
+ @classmethod
1319
+ async def create_unix_datagram_socket(
1320
+ cls, raw_socket: socket.socket, remote_path: str | bytes | None
1321
+ ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket:
1322
+ trio_socket = trio.socket.from_stdlib_socket(raw_socket)
1323
+
1324
+ if remote_path:
1325
+ await trio_socket.connect(remote_path)
1326
+ return ConnectedUNIXDatagramSocket(trio_socket)
1327
+ else:
1328
+ return UNIXDatagramSocket(trio_socket)
1329
+
1330
+ @classmethod
1331
+ async def getaddrinfo(
1332
+ cls,
1333
+ host: bytes | str | None,
1334
+ port: str | int | None,
1335
+ *,
1336
+ family: int | AddressFamily = 0,
1337
+ type: int | SocketKind = 0,
1338
+ proto: int = 0,
1339
+ flags: int = 0,
1340
+ ) -> Sequence[
1341
+ tuple[
1342
+ AddressFamily,
1343
+ SocketKind,
1344
+ int,
1345
+ str,
1346
+ tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
1347
+ ]
1348
+ ]:
1349
+ return await trio.socket.getaddrinfo(host, port, family, type, proto, flags)
1350
+
1351
+ @classmethod
1352
+ async def getnameinfo(
1353
+ cls, sockaddr: IPSockAddrType, flags: int = 0
1354
+ ) -> tuple[str, str]:
1355
+ return await trio.socket.getnameinfo(sockaddr, flags)
1356
+
1357
+ @classmethod
1358
+ async def wait_readable(cls, obj: FileDescriptorLike) -> None:
1359
+ try:
1360
+ await wait_readable(obj)
1361
+ except trio.ClosedResourceError as exc:
1362
+ raise ClosedResourceError().with_traceback(exc.__traceback__) from None
1363
+ except trio.BusyResourceError:
1364
+ raise BusyResourceError("reading from") from None
1365
+
1366
+ @classmethod
1367
+ async def wait_writable(cls, obj: FileDescriptorLike) -> None:
1368
+ try:
1369
+ await wait_writable(obj)
1370
+ except trio.ClosedResourceError as exc:
1371
+ raise ClosedResourceError().with_traceback(exc.__traceback__) from None
1372
+ except trio.BusyResourceError:
1373
+ raise BusyResourceError("writing to") from None
1374
+
1375
+ @classmethod
1376
+ def notify_closing(cls, obj: FileDescriptorLike) -> None:
1377
+ notify_closing(obj)
1378
+
1379
+ @classmethod
1380
+ async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener:
1381
+ if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX:
1382
+ return UNIXSocketListener(sock)
1383
+
1384
+ return TCPSocketListener(sock)
1385
+
1386
+ @classmethod
1387
+ async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream:
1388
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1389
+ return SocketStream(trio_sock)
1390
+
1391
+ @classmethod
1392
+ async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream:
1393
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1394
+ return UNIXSocketStream(trio_sock)
1395
+
1396
+ @classmethod
1397
+ async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket:
1398
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1399
+ return UDPSocket(trio_sock)
1400
+
1401
+ @classmethod
1402
+ async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket:
1403
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1404
+ return ConnectedUDPSocket(trio_sock)
1405
+
1406
+ @classmethod
1407
+ async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket:
1408
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1409
+ return UNIXDatagramSocket(trio_sock)
1410
+
1411
+ @classmethod
1412
+ async def wrap_connected_unix_datagram_socket(
1413
+ cls, sock: socket.socket
1414
+ ) -> ConnectedUNIXDatagramSocket:
1415
+ trio_sock = trio.socket.from_stdlib_socket(sock)
1416
+ return ConnectedUNIXDatagramSocket(trio_sock)
1417
+
1418
+ @classmethod
1419
+ def current_default_thread_limiter(cls) -> CapacityLimiter:
1420
+ try:
1421
+ return _capacity_limiter_wrapper.get()
1422
+ except LookupError:
1423
+ limiter = CapacityLimiter(
1424
+ original=trio.to_thread.current_default_thread_limiter()
1425
+ )
1426
+ _capacity_limiter_wrapper.set(limiter)
1427
+ return limiter
1428
+
1429
+ @classmethod
1430
+ def open_signal_receiver(
1431
+ cls, *signals: Signals
1432
+ ) -> AbstractContextManager[AsyncIterator[Signals]]:
1433
+ return _SignalReceiver(signals)
1434
+
1435
+ @classmethod
1436
+ def get_current_task(cls) -> TaskInfo:
1437
+ task = current_task()
1438
+ return TrioTaskInfo(task)
1439
+
1440
+ @classmethod
1441
+ def get_running_tasks(cls) -> Sequence[TaskInfo]:
1442
+ root_task = current_root_task()
1443
+ assert root_task
1444
+ task_infos = [TrioTaskInfo(root_task)]
1445
+ nurseries = root_task.child_nurseries
1446
+ while nurseries:
1447
+ new_nurseries: list[trio.Nursery] = []
1448
+ for nursery in nurseries:
1449
+ for task in nursery.child_tasks:
1450
+ task_infos.append(TrioTaskInfo(task))
1451
+ new_nurseries.extend(task.child_nurseries)
1452
+
1453
+ nurseries = new_nurseries
1454
+
1455
+ return task_infos
1456
+
1457
+ @classmethod
1458
+ async def wait_all_tasks_blocked(cls) -> None:
1459
+ from trio.testing import wait_all_tasks_blocked
1460
+
1461
+ await wait_all_tasks_blocked()
1462
+
1463
+ @classmethod
1464
+ def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
1465
+ return TestRunner(**options)
1466
+
1467
+
1468
+ backend_class = TrioBackend
.venv/lib/python3.13/site-packages/anyio/_core/__init__.py ADDED
File without changes
.venv/lib/python3.13/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
.venv/lib/python3.13/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
+ """
.venv/lib/python3.13/site-packages/anyio/_core/_eventloop.py ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ if backend in BACKENDS:
68
+ raise LookupError(
69
+ f"Backend {backend!r} is not available. "
70
+ f"Install it with: pip install anyio[{backend}]"
71
+ ) from exc
72
+
73
+ raise LookupError(f"No such backend: {backend}") from exc
74
+
75
+ token = None
76
+ if asynclib_name is None:
77
+ # Since we're in control of the event loop, we can cache the name of the async
78
+ # library
79
+ token = set_current_async_library(backend)
80
+
81
+ try:
82
+ backend_options = backend_options or {}
83
+ return async_backend.run(func, args, {}, backend_options)
84
+ finally:
85
+ reset_current_async_library(token)
86
+
87
+
88
+ async def sleep(delay: float) -> None:
89
+ """
90
+ Pause the current task for the specified duration.
91
+
92
+ :param delay: the duration, in seconds
93
+
94
+ """
95
+ return await get_async_backend().sleep(delay)
96
+
97
+
98
+ async def sleep_forever() -> None:
99
+ """
100
+ Pause the current task until it's cancelled.
101
+
102
+ This is a shortcut for ``sleep(math.inf)``.
103
+
104
+ .. versionadded:: 3.1
105
+
106
+ """
107
+ await sleep(math.inf)
108
+
109
+
110
+ async def sleep_until(deadline: float) -> None:
111
+ """
112
+ Pause the current task until the given time.
113
+
114
+ :param deadline: the absolute time to wake up at (according to the internal
115
+ monotonic clock of the event loop)
116
+
117
+ .. versionadded:: 3.1
118
+
119
+ """
120
+ now = current_time()
121
+ await sleep(max(deadline - now, 0))
122
+
123
+
124
+ def current_time() -> float:
125
+ """
126
+ Return the current value of the event loop's internal clock.
127
+
128
+ :return: the clock value (seconds)
129
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
130
+ current thread
131
+
132
+ """
133
+ return get_async_backend().current_time()
134
+
135
+
136
+ def get_all_backends() -> tuple[str, ...]:
137
+ """Return a tuple of the names of all built-in backends."""
138
+ return BACKENDS
139
+
140
+
141
+ def get_available_backends() -> tuple[str, ...]:
142
+ """
143
+ Test for the availability of built-in backends.
144
+
145
+ :return a tuple of the built-in backend names that were successfully imported
146
+
147
+ .. versionadded:: 4.12
148
+
149
+ """
150
+ available_backends: list[str] = []
151
+ for backend_name in get_all_backends():
152
+ try:
153
+ get_async_backend(backend_name)
154
+ except ImportError:
155
+ continue
156
+
157
+ available_backends.append(backend_name)
158
+
159
+ return tuple(available_backends)
160
+
161
+
162
+ def get_cancelled_exc_class() -> type[BaseException]:
163
+ """
164
+ Return the current async library's cancellation exception class.
165
+
166
+ :raises NoEventLoopError: if no supported asynchronous event loop is running in the
167
+ current thread
168
+
169
+ """
170
+ return get_async_backend().cancelled_exception_class()
171
+
172
+
173
+ #
174
+ # Private API
175
+ #
176
+
177
+
178
+ @contextmanager
179
+ def claim_worker_thread(
180
+ backend_class: type[AsyncBackend], token: object
181
+ ) -> Generator[Any, None, None]:
182
+ from ..lowlevel import EventLoopToken
183
+
184
+ threadlocals.current_token = EventLoopToken(backend_class, token)
185
+ try:
186
+ yield
187
+ finally:
188
+ del threadlocals.current_token
189
+
190
+
191
+ def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]:
192
+ if asynclib_name is None:
193
+ asynclib_name = current_async_library()
194
+ if not asynclib_name:
195
+ raise NoEventLoopError(
196
+ f"Not currently running on any asynchronous event loop. "
197
+ f"Available async backends: {', '.join(get_all_backends())}"
198
+ )
199
+
200
+ # We use our own dict instead of sys.modules to get the already imported back-end
201
+ # class because the appropriate modules in sys.modules could potentially be only
202
+ # partially initialized
203
+ try:
204
+ return loaded_backends[asynclib_name]
205
+ except KeyError:
206
+ module = import_module(f"anyio._backends._{asynclib_name}")
207
+ loaded_backends[asynclib_name] = module.backend_class
208
+ return module.backend_class
209
+
210
+
211
+ def current_async_library() -> str | None:
212
+ if sniffio is None:
213
+ # If sniffio is not installed, we assume we're either running asyncio or nothing
214
+ import asyncio
215
+
216
+ try:
217
+ asyncio.get_running_loop()
218
+ return "asyncio"
219
+ except RuntimeError:
220
+ pass
221
+ else:
222
+ try:
223
+ return sniffio.current_async_library()
224
+ except sniffio.AsyncLibraryNotFoundError:
225
+ pass
226
+
227
+ return None
228
+
229
+
230
+ def set_current_async_library(asynclib_name: str | None) -> Token | None:
231
+ # no-op if sniffio is not installed
232
+ if sniffio is None:
233
+ return None
234
+
235
+ return sniffio.current_async_library_cvar.set(asynclib_name)
236
+
237
+
238
+ def reset_current_async_library(token: Token | None) -> None:
239
+ if token is not None:
240
+ sniffio.current_async_library_cvar.reset(token)
.venv/lib/python3.13/site-packages/anyio/_core/_exceptions.py ADDED
@@ -0,0 +1,177 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ )
157
+
158
+
159
+ class TaskFailed(Exception):
160
+ """
161
+ Raised when awaiting on, or attempting to access the return value of, a
162
+ :class:`.TaskHandle` that raised an exception.
163
+ """
164
+
165
+
166
+ class TaskCancelled(TaskFailed):
167
+ """
168
+ Raised when awaiting on, or attempting to access the return value of, a
169
+ :class:`.TaskHandle` that was cancelled.
170
+ """
171
+
172
+
173
+ class TaskNotFinished(Exception):
174
+ """
175
+ Raised when attempting to access the return value or exception of a
176
+ :class:`.TaskHandle` that is still pending completion.
177
+ """
.venv/lib/python3.13/site-packages/anyio/_core/_fileio.py ADDED
@@ -0,0 +1,960 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ TypeVar,
25
+ overload,
26
+ )
27
+
28
+ from .. import to_thread
29
+ from ..abc import AsyncResource
30
+ from ._synchronization import CapacityLimiter
31
+
32
+ if sys.version_info >= (3, 11):
33
+ from typing import Self
34
+ else:
35
+ from typing_extensions import Self
36
+
37
+ if sys.version_info >= (3, 14):
38
+ from pathlib.types import PathInfo
39
+
40
+ if TYPE_CHECKING:
41
+ from types import ModuleType
42
+
43
+ from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
44
+ else:
45
+ ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object
46
+
47
+
48
+ T = TypeVar("T", bound="Path")
49
+
50
+
51
+ class AsyncFile(AsyncResource, Generic[AnyStr]):
52
+ """
53
+ An asynchronous file object.
54
+
55
+ This class wraps a standard file object and provides async friendly versions of the
56
+ following blocking methods (where available on the original file object):
57
+
58
+ * read
59
+ * read1
60
+ * readline
61
+ * readlines
62
+ * readinto
63
+ * readinto1
64
+ * write
65
+ * writelines
66
+ * truncate
67
+ * seek
68
+ * tell
69
+ * flush
70
+
71
+ All other methods are directly passed through.
72
+
73
+ This class supports the asynchronous context manager protocol which closes the
74
+ underlying file at the end of the context block.
75
+
76
+ This class also supports asynchronous iteration::
77
+
78
+ async with await open_file(...) as f:
79
+ async for line in f:
80
+ print(line)
81
+ """
82
+
83
+ def __init__(
84
+ self, fp: IO[AnyStr], *, limiter: CapacityLimiter | None = None
85
+ ) -> None:
86
+ if limiter is not None and not isinstance(limiter, CapacityLimiter):
87
+ raise TypeError(
88
+ f"limiter must be a CapacityLimiter or None, not "
89
+ f"{limiter.__class__.__name__}"
90
+ )
91
+
92
+ self._fp: Any = fp
93
+ self._limiter = limiter
94
+
95
+ def __getattr__(self, name: str) -> object:
96
+ return getattr(self._fp, name)
97
+
98
+ @property
99
+ def limiter(self) -> CapacityLimiter | None:
100
+ """The capacity limiter used by this file object, if not the global limiter."""
101
+ return self._limiter
102
+
103
+ @property
104
+ def wrapped(self) -> IO[AnyStr]:
105
+ """The wrapped file object."""
106
+ return self._fp
107
+
108
+ async def __aiter__(self) -> AsyncIterator[AnyStr]:
109
+ while True:
110
+ line = await self.readline()
111
+ if line:
112
+ yield line
113
+ else:
114
+ break
115
+
116
+ async def aclose(self) -> None:
117
+ return await to_thread.run_sync(self._fp.close, limiter=self._limiter)
118
+
119
+ async def read(self, size: int = -1) -> AnyStr:
120
+ return await to_thread.run_sync(self._fp.read, size, limiter=self._limiter)
121
+
122
+ async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes:
123
+ return await to_thread.run_sync(self._fp.read1, size, limiter=self._limiter)
124
+
125
+ async def readline(self) -> AnyStr:
126
+ return await to_thread.run_sync(self._fp.readline, limiter=self._limiter)
127
+
128
+ async def readlines(self) -> list[AnyStr]:
129
+ return await to_thread.run_sync(self._fp.readlines, limiter=self._limiter)
130
+
131
+ async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
132
+ return await to_thread.run_sync(self._fp.readinto, b, limiter=self._limiter)
133
+
134
+ async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
135
+ return await to_thread.run_sync(self._fp.readinto1, b, limiter=self._limiter)
136
+
137
+ @overload
138
+ async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ...
139
+
140
+ @overload
141
+ async def write(self: AsyncFile[str], b: str) -> int: ...
142
+
143
+ async def write(self, b: ReadableBuffer | str) -> int:
144
+ return await to_thread.run_sync(self._fp.write, b, limiter=self._limiter)
145
+
146
+ @overload
147
+ async def writelines(
148
+ self: AsyncFile[bytes], lines: Iterable[ReadableBuffer]
149
+ ) -> None: ...
150
+
151
+ @overload
152
+ async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ...
153
+
154
+ async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None:
155
+ return await to_thread.run_sync(
156
+ self._fp.writelines, lines, limiter=self._limiter
157
+ )
158
+
159
+ async def truncate(self, size: int | None = None) -> int:
160
+ return await to_thread.run_sync(self._fp.truncate, size, limiter=self._limiter)
161
+
162
+ async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
163
+ return await to_thread.run_sync(
164
+ self._fp.seek, offset, whence, limiter=self._limiter
165
+ )
166
+
167
+ async def tell(self) -> int:
168
+ return await to_thread.run_sync(self._fp.tell, limiter=self._limiter)
169
+
170
+ async def flush(self) -> None:
171
+ return await to_thread.run_sync(self._fp.flush, limiter=self._limiter)
172
+
173
+
174
+ @overload
175
+ async def open_file(
176
+ file: str | PathLike[str] | int,
177
+ mode: OpenBinaryMode,
178
+ buffering: int = ...,
179
+ encoding: str | None = ...,
180
+ errors: str | None = ...,
181
+ newline: str | None = ...,
182
+ closefd: bool = ...,
183
+ opener: Callable[[str, int], int] | None = ...,
184
+ *,
185
+ limiter: CapacityLimiter | None = ...,
186
+ ) -> AsyncFile[bytes]: ...
187
+
188
+
189
+ @overload
190
+ async def open_file(
191
+ file: str | PathLike[str] | int,
192
+ mode: OpenTextMode = ...,
193
+ buffering: int = ...,
194
+ encoding: str | None = ...,
195
+ errors: str | None = ...,
196
+ newline: str | None = ...,
197
+ closefd: bool = ...,
198
+ opener: Callable[[str, int], int] | None = ...,
199
+ *,
200
+ limiter: CapacityLimiter | None = ...,
201
+ ) -> AsyncFile[str]: ...
202
+
203
+
204
+ async def open_file(
205
+ file: str | PathLike[str] | int,
206
+ mode: str = "r",
207
+ buffering: int = -1,
208
+ encoding: str | None = None,
209
+ errors: str | None = None,
210
+ newline: str | None = None,
211
+ closefd: bool = True,
212
+ opener: Callable[[str, int], int] | None = None,
213
+ *,
214
+ limiter: CapacityLimiter | None = None,
215
+ ) -> AsyncFile[Any]:
216
+ """
217
+ Open a file asynchronously.
218
+
219
+ Except for ``limiter``, the arguments are exactly the same as for the builtin :func:`open`.
220
+
221
+ :param limiter: an optional capacity limiter to use with the file
222
+ instead of the default one
223
+ :return: an asynchronous file object
224
+
225
+ .. versionchanged:: 4.14.0
226
+ Added the ``limiter`` keyword argument.
227
+
228
+ """
229
+ fp = await to_thread.run_sync(
230
+ open,
231
+ file,
232
+ mode,
233
+ buffering,
234
+ encoding,
235
+ errors,
236
+ newline,
237
+ closefd,
238
+ opener,
239
+ limiter=limiter,
240
+ )
241
+ return AsyncFile(fp, limiter=limiter)
242
+
243
+
244
+ def wrap_file(
245
+ file: IO[AnyStr], *, limiter: CapacityLimiter | None = None
246
+ ) -> AsyncFile[AnyStr]:
247
+ """
248
+ Wrap an existing file as an asynchronous file.
249
+
250
+ :param file: an existing file-like object
251
+ :param limiter: an optional capacity limiter to use with the file
252
+ instead of the default one
253
+ :return: an asynchronous file object
254
+
255
+ .. versionchanged:: 4.14.0
256
+ Added the ``limiter`` keyword argument.
257
+
258
+ """
259
+ return AsyncFile(file, limiter=limiter)
260
+
261
+
262
+ @dataclass(eq=False)
263
+ class _PathIterator(AsyncIterator[T]):
264
+ iterator: Iterator[PathLike[str]]
265
+ limiter: CapacityLimiter | None
266
+ # This was added to ensure that iterating over a subclass of Path yields instances
267
+ # of that subclass rather than the base Path class.
268
+ path_cls: type[T]
269
+
270
+ async def __anext__(self) -> T:
271
+ nextval = await to_thread.run_sync(
272
+ next, self.iterator, None, abandon_on_cancel=True, limiter=self.limiter
273
+ )
274
+ if nextval is None:
275
+ raise StopAsyncIteration from None
276
+
277
+ return self.path_cls(nextval, limiter=self.limiter)
278
+
279
+
280
+ class Path:
281
+ """
282
+ An asynchronous version of :class:`pathlib.Path`.
283
+
284
+ This class cannot be substituted for :class:`pathlib.Path` or
285
+ :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike`
286
+ interface.
287
+
288
+ It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for
289
+ the deprecated :meth:`~pathlib.Path.link_to` method.
290
+
291
+ Some methods may be unavailable or have limited functionality, based on the Python
292
+ version:
293
+
294
+ * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later)
295
+ * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later)
296
+ * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later)
297
+ * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later)
298
+ * :attr:`~pathlib.Path.info` (available on Python 3.14 or later)
299
+ * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later)
300
+ * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only
301
+ available on Python 3.13 or later)
302
+ * :meth:`~pathlib.Path.move` (available on Python 3.14 or later)
303
+ * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later)
304
+ * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available
305
+ on Python 3.12 or later)
306
+ * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later)
307
+
308
+ Any methods that do disk I/O need to be awaited on. These methods are:
309
+
310
+ * :meth:`~pathlib.Path.absolute`
311
+ * :meth:`~pathlib.Path.chmod`
312
+ * :meth:`~pathlib.Path.cwd`
313
+ * :meth:`~pathlib.Path.exists`
314
+ * :meth:`~pathlib.Path.expanduser`
315
+ * :meth:`~pathlib.Path.group`
316
+ * :meth:`~pathlib.Path.hardlink_to`
317
+ * :meth:`~pathlib.Path.home`
318
+ * :meth:`~pathlib.Path.is_block_device`
319
+ * :meth:`~pathlib.Path.is_char_device`
320
+ * :meth:`~pathlib.Path.is_dir`
321
+ * :meth:`~pathlib.Path.is_fifo`
322
+ * :meth:`~pathlib.Path.is_file`
323
+ * :meth:`~pathlib.Path.is_junction`
324
+ * :meth:`~pathlib.Path.is_mount`
325
+ * :meth:`~pathlib.Path.is_socket`
326
+ * :meth:`~pathlib.Path.is_symlink`
327
+ * :meth:`~pathlib.Path.lchmod`
328
+ * :meth:`~pathlib.Path.lstat`
329
+ * :meth:`~pathlib.Path.mkdir`
330
+ * :meth:`~pathlib.Path.open`
331
+ * :meth:`~pathlib.Path.owner`
332
+ * :meth:`~pathlib.Path.read_bytes`
333
+ * :meth:`~pathlib.Path.read_text`
334
+ * :meth:`~pathlib.Path.readlink`
335
+ * :meth:`~pathlib.Path.rename`
336
+ * :meth:`~pathlib.Path.replace`
337
+ * :meth:`~pathlib.Path.resolve`
338
+ * :meth:`~pathlib.Path.rmdir`
339
+ * :meth:`~pathlib.Path.samefile`
340
+ * :meth:`~pathlib.Path.stat`
341
+ * :meth:`~pathlib.Path.symlink_to`
342
+ * :meth:`~pathlib.Path.touch`
343
+ * :meth:`~pathlib.Path.unlink`
344
+ * :meth:`~pathlib.Path.walk`
345
+ * :meth:`~pathlib.Path.write_bytes`
346
+ * :meth:`~pathlib.Path.write_text`
347
+
348
+ Additionally, the following methods return an async iterator yielding
349
+ :class:`~.Path` objects:
350
+
351
+ * :meth:`~pathlib.Path.glob`
352
+ * :meth:`~pathlib.Path.iterdir`
353
+ * :meth:`~pathlib.Path.rglob`
354
+
355
+ .. versionchanged:: 4.14.0
356
+ Added the ``limiter`` keyword argument.
357
+ """
358
+
359
+ __slots__ = "_path", "_limiter", "__weakref__"
360
+
361
+ __weakref__: Any
362
+
363
+ def __init__(
364
+ self, *args: str | PathLike[str], limiter: CapacityLimiter | None = None
365
+ ) -> None:
366
+ if limiter is not None and not isinstance(limiter, CapacityLimiter):
367
+ raise TypeError(
368
+ f"limiter must be a CapacityLimiter or None, not "
369
+ f"{limiter.__class__.__name__}"
370
+ )
371
+
372
+ self._path: Final[pathlib.Path] = pathlib.Path(*args)
373
+ self._limiter = limiter
374
+
375
+ def __fspath__(self) -> str:
376
+ return self._path.__fspath__()
377
+
378
+ if sys.version_info >= (3, 15):
379
+
380
+ def __vfspath__(self) -> str:
381
+ return self._path.__vfspath__()
382
+
383
+ def __str__(self) -> str:
384
+ return self._path.__str__()
385
+
386
+ def __repr__(self) -> str:
387
+ return f"{self.__class__.__name__}({self.as_posix()!r})"
388
+
389
+ def __bytes__(self) -> bytes:
390
+ return self._path.__bytes__()
391
+
392
+ def __hash__(self) -> int:
393
+ return self._path.__hash__()
394
+
395
+ def __eq__(self, other: object) -> bool:
396
+ target = other._path if isinstance(other, Path) else other
397
+ return self._path.__eq__(target)
398
+
399
+ def __lt__(self, other: pathlib.PurePath | Path) -> bool:
400
+ target = other._path if isinstance(other, Path) else other
401
+ return self._path.__lt__(target)
402
+
403
+ def __le__(self, other: pathlib.PurePath | Path) -> bool:
404
+ target = other._path if isinstance(other, Path) else other
405
+ return self._path.__le__(target)
406
+
407
+ def __gt__(self, other: pathlib.PurePath | Path) -> bool:
408
+ target = other._path if isinstance(other, Path) else other
409
+ return self._path.__gt__(target)
410
+
411
+ def __ge__(self, other: pathlib.PurePath | Path) -> bool:
412
+ target = other._path if isinstance(other, Path) else other
413
+ return self._path.__ge__(target)
414
+
415
+ def __truediv__(self, other: str | PathLike[str]) -> Self:
416
+ return type(self)(self._path / other, limiter=self._limiter)
417
+
418
+ def __rtruediv__(self, other: str | PathLike[str]) -> Self:
419
+ return type(self)(other, limiter=self._limiter) / self
420
+
421
+ @property
422
+ def limiter(self) -> CapacityLimiter | None:
423
+ """The capacity limiter used by this path, if not the global limiter."""
424
+ return self._limiter
425
+
426
+ @property
427
+ def parts(self) -> tuple[str, ...]:
428
+ return self._path.parts
429
+
430
+ @property
431
+ def drive(self) -> str:
432
+ return self._path.drive
433
+
434
+ @property
435
+ def root(self) -> str:
436
+ return self._path.root
437
+
438
+ @property
439
+ def anchor(self) -> str:
440
+ return self._path.anchor
441
+
442
+ @property
443
+ def parents(self) -> Sequence[Self]:
444
+ return tuple(type(self)(p, limiter=self._limiter) for p in self._path.parents)
445
+
446
+ @property
447
+ def parent(self) -> Self:
448
+ return type(self)(self._path.parent, limiter=self._limiter)
449
+
450
+ @property
451
+ def name(self) -> str:
452
+ return self._path.name
453
+
454
+ @property
455
+ def suffix(self) -> str:
456
+ return self._path.suffix
457
+
458
+ @property
459
+ def suffixes(self) -> list[str]:
460
+ return self._path.suffixes
461
+
462
+ @property
463
+ def stem(self) -> str:
464
+ return self._path.stem
465
+
466
+ async def absolute(self) -> Self:
467
+ path = await to_thread.run_sync(self._path.absolute, limiter=self._limiter)
468
+ return type(self)(path, limiter=self._limiter)
469
+
470
+ def as_posix(self) -> str:
471
+ return self._path.as_posix()
472
+
473
+ def as_uri(self) -> str:
474
+ return self._path.as_uri()
475
+
476
+ if sys.version_info >= (3, 13):
477
+ parser: ClassVar[ModuleType] = pathlib.Path.parser
478
+
479
+ @classmethod
480
+ def from_uri(cls, uri: str, *, limiter: CapacityLimiter | None = None) -> Self:
481
+ return cls(pathlib.Path.from_uri(uri), limiter=limiter)
482
+
483
+ def full_match(
484
+ self, path_pattern: str, *, case_sensitive: bool | None = None
485
+ ) -> bool:
486
+ return self._path.full_match(path_pattern, case_sensitive=case_sensitive)
487
+
488
+ def match(
489
+ self, path_pattern: str, *, case_sensitive: bool | None = None
490
+ ) -> bool:
491
+ return self._path.match(path_pattern, case_sensitive=case_sensitive)
492
+ else:
493
+
494
+ def match(self, path_pattern: str) -> bool:
495
+ return self._path.match(path_pattern)
496
+
497
+ if sys.version_info >= (3, 14):
498
+
499
+ @property
500
+ def info(self) -> PathInfo:
501
+ return self._path.info
502
+
503
+ async def copy(
504
+ self,
505
+ target: str | os.PathLike[str],
506
+ *,
507
+ follow_symlinks: bool = True,
508
+ preserve_metadata: bool = False,
509
+ ) -> Self:
510
+ func = partial(
511
+ self._path.copy,
512
+ follow_symlinks=follow_symlinks,
513
+ preserve_metadata=preserve_metadata,
514
+ )
515
+ return type(self)(
516
+ await to_thread.run_sync(
517
+ func, pathlib.Path(target), limiter=self._limiter
518
+ ),
519
+ limiter=self._limiter,
520
+ )
521
+
522
+ async def copy_into(
523
+ self,
524
+ target_dir: str | os.PathLike[str],
525
+ *,
526
+ follow_symlinks: bool = True,
527
+ preserve_metadata: bool = False,
528
+ ) -> Self:
529
+ func = partial(
530
+ self._path.copy_into,
531
+ follow_symlinks=follow_symlinks,
532
+ preserve_metadata=preserve_metadata,
533
+ )
534
+ return type(self)(
535
+ await to_thread.run_sync(
536
+ func, pathlib.Path(target_dir), limiter=self._limiter
537
+ ),
538
+ limiter=self._limiter,
539
+ )
540
+
541
+ async def move(self, target: str | os.PathLike[str]) -> Self:
542
+ # Upstream does not handle anyio.Path properly as a PathLike
543
+ target = pathlib.Path(target)
544
+ return type(self)(
545
+ await to_thread.run_sync(
546
+ self._path.move, target, limiter=self._limiter
547
+ ),
548
+ limiter=self._limiter,
549
+ )
550
+
551
+ async def move_into(
552
+ self,
553
+ target_dir: str | os.PathLike[str],
554
+ ) -> Self:
555
+ return type(self)(
556
+ await to_thread.run_sync(
557
+ self._path.move_into, target_dir, limiter=self._limiter
558
+ ),
559
+ limiter=self._limiter,
560
+ )
561
+
562
+ def is_relative_to(self, other: str | PathLike[str]) -> bool:
563
+ try:
564
+ self.relative_to(other)
565
+ return True
566
+ except ValueError:
567
+ return False
568
+
569
+ async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None:
570
+ func = partial(os.chmod, follow_symlinks=follow_symlinks)
571
+ return await to_thread.run_sync(func, self._path, mode, limiter=self._limiter)
572
+
573
+ @classmethod
574
+ async def cwd(cls, *, limiter: CapacityLimiter | None = None) -> Self:
575
+ path = await to_thread.run_sync(pathlib.Path.cwd, limiter=limiter)
576
+ return cls(path, limiter=limiter)
577
+
578
+ async def exists(self) -> bool:
579
+ return await to_thread.run_sync(
580
+ self._path.exists, abandon_on_cancel=True, limiter=self._limiter
581
+ )
582
+
583
+ async def expanduser(self) -> Self:
584
+ return type(self)(
585
+ await to_thread.run_sync(
586
+ self._path.expanduser, abandon_on_cancel=True, limiter=self._limiter
587
+ ),
588
+ limiter=self._limiter,
589
+ )
590
+
591
+ if sys.version_info < (3, 12):
592
+ # Python 3.11 and earlier
593
+ def glob(self, pattern: str) -> AsyncIterator[Self]:
594
+ gen = self._path.glob(pattern)
595
+ return _PathIterator(gen, self._limiter, type(self))
596
+ elif (3, 12) <= sys.version_info < (3, 13):
597
+ # changed in Python 3.12:
598
+ # - The case_sensitive parameter was added.
599
+ def glob(
600
+ self,
601
+ pattern: str,
602
+ *,
603
+ case_sensitive: bool | None = None,
604
+ ) -> AsyncIterator[Self]:
605
+ gen = self._path.glob(pattern, case_sensitive=case_sensitive)
606
+ return _PathIterator(gen, self._limiter, type(self))
607
+ elif sys.version_info >= (3, 13):
608
+ # Changed in Python 3.13:
609
+ # - The recurse_symlinks parameter was added.
610
+ # - The pattern parameter accepts a path-like object.
611
+ def glob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
612
+ self,
613
+ pattern: str | PathLike[str],
614
+ *,
615
+ case_sensitive: bool | None = None,
616
+ recurse_symlinks: bool = False,
617
+ ) -> AsyncIterator[Self]:
618
+ gen = self._path.glob(
619
+ pattern, # type: ignore[arg-type]
620
+ case_sensitive=case_sensitive,
621
+ recurse_symlinks=recurse_symlinks,
622
+ )
623
+ return _PathIterator(gen, self._limiter, type(self))
624
+
625
+ async def group(self) -> str:
626
+ return await to_thread.run_sync(
627
+ self._path.group, abandon_on_cancel=True, limiter=self._limiter
628
+ )
629
+
630
+ async def hardlink_to(
631
+ self, target: str | bytes | PathLike[str] | PathLike[bytes]
632
+ ) -> None:
633
+ if isinstance(target, Path):
634
+ target = target._path
635
+
636
+ await to_thread.run_sync(os.link, target, self, limiter=self._limiter)
637
+
638
+ @classmethod
639
+ async def home(cls, *, limiter: CapacityLimiter | None = None) -> Self:
640
+ home_path = await to_thread.run_sync(pathlib.Path.home, limiter=limiter)
641
+ return cls(home_path, limiter=limiter)
642
+
643
+ def is_absolute(self) -> bool:
644
+ return self._path.is_absolute()
645
+
646
+ async def is_block_device(self) -> bool:
647
+ return await to_thread.run_sync(
648
+ self._path.is_block_device, abandon_on_cancel=True, limiter=self._limiter
649
+ )
650
+
651
+ async def is_char_device(self) -> bool:
652
+ return await to_thread.run_sync(
653
+ self._path.is_char_device, abandon_on_cancel=True, limiter=self._limiter
654
+ )
655
+
656
+ async def is_dir(self) -> bool:
657
+ return await to_thread.run_sync(
658
+ self._path.is_dir, abandon_on_cancel=True, limiter=self._limiter
659
+ )
660
+
661
+ async def is_fifo(self) -> bool:
662
+ return await to_thread.run_sync(
663
+ self._path.is_fifo, abandon_on_cancel=True, limiter=self._limiter
664
+ )
665
+
666
+ async def is_file(self) -> bool:
667
+ return await to_thread.run_sync(
668
+ self._path.is_file, abandon_on_cancel=True, limiter=self._limiter
669
+ )
670
+
671
+ if sys.version_info >= (3, 12):
672
+
673
+ async def is_junction(self) -> bool:
674
+ return await to_thread.run_sync(
675
+ self._path.is_junction, limiter=self._limiter
676
+ )
677
+
678
+ async def is_mount(self) -> bool:
679
+ return await to_thread.run_sync(
680
+ os.path.ismount, self._path, abandon_on_cancel=True, limiter=self._limiter
681
+ )
682
+
683
+ if sys.version_info < (3, 15):
684
+
685
+ def is_reserved(self) -> bool:
686
+ return self._path.is_reserved()
687
+
688
+ async def is_socket(self) -> bool:
689
+ return await to_thread.run_sync(
690
+ self._path.is_socket, abandon_on_cancel=True, limiter=self._limiter
691
+ )
692
+
693
+ async def is_symlink(self) -> bool:
694
+ return await to_thread.run_sync(
695
+ self._path.is_symlink, abandon_on_cancel=True, limiter=self._limiter
696
+ )
697
+
698
+ async def iterdir(self) -> AsyncIterator[Self]:
699
+ gen = (
700
+ self._path.iterdir()
701
+ if sys.version_info < (3, 13)
702
+ else await to_thread.run_sync(
703
+ self._path.iterdir, abandon_on_cancel=True, limiter=self._limiter
704
+ )
705
+ )
706
+ async for path in _PathIterator(gen, self._limiter, type(self)):
707
+ yield path
708
+
709
+ def joinpath(self, *args: str | PathLike[str]) -> Self:
710
+ return type(self)(self._path.joinpath(*args), limiter=self._limiter)
711
+
712
+ async def lchmod(self, mode: int) -> None:
713
+ await to_thread.run_sync(self._path.lchmod, mode, limiter=self._limiter)
714
+
715
+ async def lstat(self) -> os.stat_result:
716
+ return await to_thread.run_sync(
717
+ self._path.lstat, abandon_on_cancel=True, limiter=self._limiter
718
+ )
719
+
720
+ async def mkdir(
721
+ self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
722
+ ) -> None:
723
+ await to_thread.run_sync(
724
+ self._path.mkdir, mode, parents, exist_ok, limiter=self._limiter
725
+ )
726
+
727
+ @overload
728
+ async def open(
729
+ self,
730
+ mode: OpenBinaryMode,
731
+ buffering: int = ...,
732
+ encoding: str | None = ...,
733
+ errors: str | None = ...,
734
+ newline: str | None = ...,
735
+ ) -> AsyncFile[bytes]: ...
736
+
737
+ @overload
738
+ async def open(
739
+ self,
740
+ mode: OpenTextMode = ...,
741
+ buffering: int = ...,
742
+ encoding: str | None = ...,
743
+ errors: str | None = ...,
744
+ newline: str | None = ...,
745
+ ) -> AsyncFile[str]: ...
746
+
747
+ async def open(
748
+ self,
749
+ mode: str = "r",
750
+ buffering: int = -1,
751
+ encoding: str | None = None,
752
+ errors: str | None = None,
753
+ newline: str | None = None,
754
+ ) -> AsyncFile[Any]:
755
+ fp = await to_thread.run_sync(
756
+ self._path.open,
757
+ mode,
758
+ buffering,
759
+ encoding,
760
+ errors,
761
+ newline,
762
+ limiter=self._limiter,
763
+ )
764
+ return AsyncFile(fp, limiter=self._limiter)
765
+
766
+ async def owner(self) -> str:
767
+ return await to_thread.run_sync(
768
+ self._path.owner, abandon_on_cancel=True, limiter=self._limiter
769
+ )
770
+
771
+ async def read_bytes(self) -> bytes:
772
+ return await to_thread.run_sync(self._path.read_bytes, limiter=self._limiter)
773
+
774
+ async def read_text(
775
+ self, encoding: str | None = None, errors: str | None = None
776
+ ) -> str:
777
+ return await to_thread.run_sync(
778
+ self._path.read_text, encoding, errors, limiter=self._limiter
779
+ )
780
+
781
+ if sys.version_info >= (3, 12):
782
+
783
+ def relative_to(
784
+ self, *other: str | PathLike[str], walk_up: bool = False
785
+ ) -> Self:
786
+ # relative_to() should work with any PathLike but it doesn't
787
+ others = [pathlib.Path(other) for other in other]
788
+ return type(self)(
789
+ self._path.relative_to(*others, walk_up=walk_up), limiter=self._limiter
790
+ )
791
+
792
+ else:
793
+
794
+ def relative_to(self, *other: str | PathLike[str]) -> Self:
795
+ return type(self)(self._path.relative_to(*other), limiter=self._limiter)
796
+
797
+ async def readlink(self) -> Self:
798
+ target = await to_thread.run_sync(
799
+ os.readlink, self._path, limiter=self._limiter
800
+ )
801
+ return type(self)(target, limiter=self._limiter)
802
+
803
+ async def rename(self, target: str | pathlib.PurePath | Path) -> Self:
804
+ if isinstance(target, Path):
805
+ target = target._path
806
+
807
+ await to_thread.run_sync(self._path.rename, target, limiter=self._limiter)
808
+ return type(self)(target, limiter=self._limiter)
809
+
810
+ async def replace(self, target: str | pathlib.PurePath | Path) -> Self:
811
+ if isinstance(target, Path):
812
+ target = target._path
813
+
814
+ await to_thread.run_sync(self._path.replace, target, limiter=self._limiter)
815
+ return type(self)(target, limiter=self._limiter)
816
+
817
+ async def resolve(self, strict: bool = False) -> Self:
818
+ func = partial(self._path.resolve, strict=strict)
819
+ return type(self)(
820
+ await to_thread.run_sync(
821
+ func, abandon_on_cancel=True, limiter=self._limiter
822
+ ),
823
+ limiter=self._limiter,
824
+ )
825
+
826
+ if sys.version_info < (3, 12):
827
+ # Pre Python 3.12
828
+ def rglob(self, pattern: str) -> AsyncIterator[Self]:
829
+ gen = self._path.rglob(pattern)
830
+ return _PathIterator(gen, self._limiter, type(self))
831
+ elif (3, 12) <= sys.version_info < (3, 13):
832
+ # Changed in Python 3.12:
833
+ # - The case_sensitive parameter was added.
834
+ def rglob(
835
+ self, pattern: str, *, case_sensitive: bool | None = None
836
+ ) -> AsyncIterator[Self]:
837
+ gen = self._path.rglob(pattern, case_sensitive=case_sensitive)
838
+ return _PathIterator(gen, self._limiter, type(self))
839
+ elif sys.version_info >= (3, 13):
840
+ # Changed in Python 3.13:
841
+ # - The recurse_symlinks parameter was added.
842
+ # - The pattern parameter accepts a path-like object.
843
+ def rglob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
844
+ self,
845
+ pattern: str | PathLike[str],
846
+ *,
847
+ case_sensitive: bool | None = None,
848
+ recurse_symlinks: bool = False,
849
+ ) -> AsyncIterator[Self]:
850
+ gen = self._path.rglob(
851
+ pattern, # type: ignore[arg-type]
852
+ case_sensitive=case_sensitive,
853
+ recurse_symlinks=recurse_symlinks,
854
+ )
855
+ return _PathIterator(gen, self._limiter, type(self))
856
+
857
+ async def rmdir(self) -> None:
858
+ await to_thread.run_sync(self._path.rmdir, limiter=self._limiter)
859
+
860
+ async def samefile(self, other_path: str | PathLike[str]) -> bool:
861
+ if isinstance(other_path, Path):
862
+ other_path = other_path._path
863
+
864
+ return await to_thread.run_sync(
865
+ self._path.samefile,
866
+ other_path,
867
+ abandon_on_cancel=True,
868
+ limiter=self._limiter,
869
+ )
870
+
871
+ async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result:
872
+ func = partial(os.stat, follow_symlinks=follow_symlinks)
873
+ return await to_thread.run_sync(
874
+ func, self._path, abandon_on_cancel=True, limiter=self._limiter
875
+ )
876
+
877
+ async def symlink_to(
878
+ self,
879
+ target: str | bytes | PathLike[str] | PathLike[bytes],
880
+ target_is_directory: bool = False,
881
+ ) -> None:
882
+ if isinstance(target, Path):
883
+ target = target._path
884
+
885
+ await to_thread.run_sync(
886
+ self._path.symlink_to, target, target_is_directory, limiter=self._limiter
887
+ )
888
+
889
+ async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
890
+ await to_thread.run_sync(
891
+ self._path.touch, mode, exist_ok, limiter=self._limiter
892
+ )
893
+
894
+ async def unlink(self, missing_ok: bool = False) -> None:
895
+ try:
896
+ await to_thread.run_sync(self._path.unlink, limiter=self._limiter)
897
+ except FileNotFoundError:
898
+ if not missing_ok:
899
+ raise
900
+
901
+ if sys.version_info >= (3, 12):
902
+
903
+ async def walk(
904
+ self,
905
+ top_down: bool = True,
906
+ on_error: Callable[[OSError], object] | None = None,
907
+ follow_symlinks: bool = False,
908
+ ) -> AsyncIterator[tuple[Self, list[str], list[str]]]:
909
+ def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None:
910
+ try:
911
+ return next(gen)
912
+ except StopIteration:
913
+ return None
914
+
915
+ gen = self._path.walk(top_down, on_error, follow_symlinks)
916
+ while True:
917
+ value = await to_thread.run_sync(get_next_value, limiter=self._limiter)
918
+ if value is None:
919
+ return
920
+
921
+ root, dirs, paths = value
922
+ yield type(self)(root, limiter=self._limiter), dirs, paths
923
+
924
+ def with_name(self, name: str) -> Self:
925
+ return type(self)(self._path.with_name(name), limiter=self._limiter)
926
+
927
+ def with_stem(self, stem: str) -> Self:
928
+ return type(self)(
929
+ self._path.with_name(stem + self._path.suffix), limiter=self._limiter
930
+ )
931
+
932
+ def with_suffix(self, suffix: str) -> Self:
933
+ return type(self)(self._path.with_suffix(suffix), limiter=self._limiter)
934
+
935
+ def with_segments(self, *pathsegments: str | PathLike[str]) -> Self:
936
+ return type(self)(*pathsegments, limiter=self._limiter)
937
+
938
+ async def write_bytes(self, data: ReadableBuffer) -> int:
939
+ return await to_thread.run_sync(
940
+ self._path.write_bytes, data, limiter=self._limiter
941
+ )
942
+
943
+ async def write_text(
944
+ self,
945
+ data: str,
946
+ encoding: str | None = None,
947
+ errors: str | None = None,
948
+ newline: str | None = None,
949
+ ) -> int:
950
+ return await to_thread.run_sync(
951
+ self._path.write_text,
952
+ data,
953
+ encoding,
954
+ errors,
955
+ newline,
956
+ limiter=self._limiter,
957
+ )
958
+
959
+
960
+ PathLike.register(Path)