CrashOverrideX commited on
Commit
86c423e
·
verified ·
1 Parent(s): 175d37c

Delete venv

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. venv/.gitignore +0 -2
  2. venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER +0 -1
  3. venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/METADATA +0 -145
  4. venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD +0 -11
  5. venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL +0 -4
  6. venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt +0 -4
  7. venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE +0 -21
  8. venv/Lib/site-packages/annotated_doc/__init__.py +0 -3
  9. venv/Lib/site-packages/annotated_doc/main.py +0 -36
  10. venv/Lib/site-packages/annotated_doc/py.typed +0 -0
  11. venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER +0 -1
  12. venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA +0 -295
  13. venv/Lib/site-packages/annotated_types-0.7.0.dist-info/RECORD +0 -10
  14. venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL +0 -4
  15. venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE +0 -21
  16. venv/Lib/site-packages/annotated_types/__init__.py +0 -432
  17. venv/Lib/site-packages/annotated_types/py.typed +0 -0
  18. venv/Lib/site-packages/annotated_types/test_cases.py +0 -151
  19. venv/Lib/site-packages/anyio-4.12.1.dist-info/INSTALLER +0 -1
  20. venv/Lib/site-packages/anyio-4.12.1.dist-info/METADATA +0 -96
  21. venv/Lib/site-packages/anyio-4.12.1.dist-info/RECORD +0 -92
  22. venv/Lib/site-packages/anyio-4.12.1.dist-info/WHEEL +0 -5
  23. venv/Lib/site-packages/anyio-4.12.1.dist-info/entry_points.txt +0 -2
  24. venv/Lib/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE +0 -20
  25. venv/Lib/site-packages/anyio-4.12.1.dist-info/top_level.txt +0 -1
  26. venv/Lib/site-packages/anyio/__init__.py +0 -111
  27. venv/Lib/site-packages/anyio/_backends/__init__.py +0 -0
  28. venv/Lib/site-packages/anyio/_backends/_asyncio.py +0 -0
  29. venv/Lib/site-packages/anyio/_backends/_trio.py +0 -1346
  30. venv/Lib/site-packages/anyio/_core/__init__.py +0 -0
  31. venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py +0 -167
  32. venv/Lib/site-packages/anyio/_core/_contextmanagers.py +0 -200
  33. venv/Lib/site-packages/anyio/_core/_eventloop.py +0 -234
  34. venv/Lib/site-packages/anyio/_core/_exceptions.py +0 -156
  35. venv/Lib/site-packages/anyio/_core/_fileio.py +0 -797
  36. venv/Lib/site-packages/anyio/_core/_resources.py +0 -18
  37. venv/Lib/site-packages/anyio/_core/_signals.py +0 -29
  38. venv/Lib/site-packages/anyio/_core/_sockets.py +0 -1003
  39. venv/Lib/site-packages/anyio/_core/_streams.py +0 -52
  40. venv/Lib/site-packages/anyio/_core/_subprocesses.py +0 -202
  41. venv/Lib/site-packages/anyio/_core/_synchronization.py +0 -753
  42. venv/Lib/site-packages/anyio/_core/_tasks.py +0 -173
  43. venv/Lib/site-packages/anyio/_core/_tempfile.py +0 -616
  44. venv/Lib/site-packages/anyio/_core/_testing.py +0 -82
  45. venv/Lib/site-packages/anyio/_core/_typedattr.py +0 -81
  46. venv/Lib/site-packages/anyio/abc/__init__.py +0 -58
  47. venv/Lib/site-packages/anyio/abc/_eventloop.py +0 -414
  48. venv/Lib/site-packages/anyio/abc/_resources.py +0 -33
  49. venv/Lib/site-packages/anyio/abc/_sockets.py +0 -405
  50. venv/Lib/site-packages/anyio/abc/_streams.py +0 -239
venv/.gitignore DELETED
@@ -1,2 +0,0 @@
1
- # Created by venv; see https://docs.python.org/3/library/venv.html
2
- *
 
 
 
venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/INSTALLER DELETED
@@ -1 +0,0 @@
1
- pip
 
 
venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/METADATA DELETED
@@ -1,145 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: annotated-doc
3
- Version: 0.0.4
4
- Summary: Document parameters, class attributes, return types, and variables inline, with Annotated.
5
- Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com>
6
- License-Expression: MIT
7
- License-File: LICENSE
8
- Classifier: Intended Audience :: Information Technology
9
- Classifier: Intended Audience :: System Administrators
10
- Classifier: Operating System :: OS Independent
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python
13
- Classifier: Topic :: Internet
14
- Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
15
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
16
- Classifier: Topic :: Software Development :: Libraries
17
- Classifier: Topic :: Software Development
18
- Classifier: Typing :: Typed
19
- Classifier: Development Status :: 4 - Beta
20
- Classifier: Intended Audience :: Developers
21
- Classifier: Programming Language :: Python :: 3 :: Only
22
- Classifier: Programming Language :: Python :: 3.8
23
- Classifier: Programming Language :: Python :: 3.9
24
- Classifier: Programming Language :: Python :: 3.10
25
- Classifier: Programming Language :: Python :: 3.11
26
- Classifier: Programming Language :: Python :: 3.12
27
- Classifier: Programming Language :: Python :: 3.13
28
- Classifier: Programming Language :: Python :: 3.14
29
- Project-URL: Homepage, https://github.com/fastapi/annotated-doc
30
- Project-URL: Documentation, https://github.com/fastapi/annotated-doc
31
- Project-URL: Repository, https://github.com/fastapi/annotated-doc
32
- Project-URL: Issues, https://github.com/fastapi/annotated-doc/issues
33
- Project-URL: Changelog, https://github.com/fastapi/annotated-doc/release-notes.md
34
- Requires-Python: >=3.8
35
- Description-Content-Type: text/markdown
36
-
37
- # Annotated Doc
38
-
39
- Document parameters, class attributes, return types, and variables inline, with `Annotated`.
40
-
41
- <a href="https://github.com/fastapi/annotated-doc/actions?query=workflow%3ATest+event%3Apush+branch%3Amain" target="_blank">
42
- <img src="https://github.com/fastapi/annotated-doc/actions/workflows/test.yml/badge.svg?event=push&branch=main" alt="Test">
43
- </a>
44
- <a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/annotated-doc" target="_blank">
45
- <img src="https://coverage-badge.samuelcolvin.workers.dev/fastapi/annotated-doc.svg" alt="Coverage">
46
- </a>
47
- <a href="https://pypi.org/project/annotated-doc" target="_blank">
48
- <img src="https://img.shields.io/pypi/v/annotated-doc?color=%2334D058&label=pypi%20package" alt="Package version">
49
- </a>
50
- <a href="https://pypi.org/project/annotated-doc" target="_blank">
51
- <img src="https://img.shields.io/pypi/pyversions/annotated-doc.svg?color=%2334D058" alt="Supported Python versions">
52
- </a>
53
-
54
- ## Installation
55
-
56
- ```bash
57
- pip install annotated-doc
58
- ```
59
-
60
- Or with `uv`:
61
-
62
- ```Python
63
- uv add annotated-doc
64
- ```
65
-
66
- ## Usage
67
-
68
- Import `Doc` and pass a single literal string with the documentation for the specific parameter, class attribute, return type, or variable.
69
-
70
- For example, to document a parameter `name` in a function `hi` you could do:
71
-
72
- ```Python
73
- from typing import Annotated
74
-
75
- from annotated_doc import Doc
76
-
77
- def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None:
78
- print(f"Hi, {name}!")
79
- ```
80
-
81
- You can also use it to document class attributes:
82
-
83
- ```Python
84
- from typing import Annotated
85
-
86
- from annotated_doc import Doc
87
-
88
- class User:
89
- name: Annotated[str, Doc("The user's name")]
90
- age: Annotated[int, Doc("The user's age")]
91
- ```
92
-
93
- The same way, you could document return types and variables, or anything that could have a type annotation with `Annotated`.
94
-
95
- ## Who Uses This
96
-
97
- `annotated-doc` was made for:
98
-
99
- * [FastAPI](https://fastapi.tiangolo.com/)
100
- * [Typer](https://typer.tiangolo.com/)
101
- * [SQLModel](https://sqlmodel.tiangolo.com/)
102
- * [Asyncer](https://asyncer.tiangolo.com/)
103
-
104
- `annotated-doc` is supported by [griffe-typingdoc](https://github.com/mkdocstrings/griffe-typingdoc), which powers reference documentation like the one in the [FastAPI Reference](https://fastapi.tiangolo.com/reference/).
105
-
106
- ## Reasons not to use `annotated-doc`
107
-
108
- You are already comfortable with one of the existing docstring formats, like:
109
-
110
- * Sphinx
111
- * numpydoc
112
- * Google
113
- * Keras
114
-
115
- Your team is already comfortable using them.
116
-
117
- You prefer having the documentation about parameters all together in a docstring, separated from the code defining them.
118
-
119
- You care about a specific set of users, using one specific editor, and that editor already has support for the specific docstring format you use.
120
-
121
- ## Reasons to use `annotated-doc`
122
-
123
- * No micro-syntax to learn for newcomers, it’s **just Python** syntax.
124
- * **Editing** would be already fully supported by default by any editor (current or future) supporting Python syntax, including syntax errors, syntax highlighting, etc.
125
- * **Rendering** would be relatively straightforward to implement by static tools (tools that don't need runtime execution), as the information can be extracted from the AST they normally already create.
126
- * **Deduplication of information**: the name of a parameter would be defined in a single place, not duplicated inside of a docstring.
127
- * **Elimination** of the possibility of having **inconsistencies** when removing a parameter or class variable and **forgetting to remove** its documentation.
128
- * **Minimization** of the probability of adding a new parameter or class variable and **forgetting to add its documentation**.
129
- * **Elimination** of the possibility of having **inconsistencies** between the **name** of a parameter in the **signature** and the name in the docstring when it is renamed.
130
- * **Access** to the documentation string for each symbol at **runtime**, including existing (older) Python versions.
131
- * A more formalized way to document other symbols, like type aliases, that could use Annotated.
132
- * **Support** for apps using FastAPI, Typer and others.
133
- * **AI Accessibility**: AI tools will have an easier way understanding each parameter as the distance from documentation to parameter is much closer.
134
-
135
- ## History
136
-
137
- I ([@tiangolo](https://github.com/tiangolo)) originally wanted for this to be part of the Python standard library (in [PEP 727](https://peps.python.org/pep-0727/)), but the proposal was withdrawn as there was a fair amount of negative feedback and opposition.
138
-
139
- The conclusion was that this was better done as an external effort, in a third-party library.
140
-
141
- So, here it is, with a simpler approach, as a third-party library, in a way that can be used by others, starting with FastAPI and friends.
142
-
143
- ## License
144
-
145
- This project is licensed under the terms of the MIT license.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/RECORD DELETED
@@ -1,11 +0,0 @@
1
- annotated_doc-0.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
- annotated_doc-0.0.4.dist-info/METADATA,sha256=Irm5KJua33dY2qKKAjJ-OhKaVBVIfwFGej_dSe3Z1TU,6566
3
- annotated_doc-0.0.4.dist-info/RECORD,,
4
- annotated_doc-0.0.4.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
5
- annotated_doc-0.0.4.dist-info/entry_points.txt,sha256=6OYgBcLyFCUgeqLgnvMyOJxPCWzgy7se4rLPKtNonMs,34
6
- annotated_doc-0.0.4.dist-info/licenses/LICENSE,sha256=__Fwd5pqy_ZavbQFwIfxzuF4ZpHkqWpANFF-SlBKDN8,1086
7
- annotated_doc/__init__.py,sha256=VuyxxUe80kfEyWnOrCx_Bk8hybo3aKo6RYBlkBBYW8k,52
8
- annotated_doc/__pycache__/__init__.cpython-313.pyc,,
9
- annotated_doc/__pycache__/main.cpython-313.pyc,,
10
- annotated_doc/main.py,sha256=5Zfvxv80SwwLqpRW73AZyZyiM4bWma9QWRbp_cgD20s,1075
11
- annotated_doc/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/WHEEL DELETED
@@ -1,4 +0,0 @@
1
- Wheel-Version: 1.0
2
- Generator: pdm-backend (2.4.5)
3
- Root-Is-Purelib: true
4
- Tag: py3-none-any
 
 
 
 
 
venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/entry_points.txt DELETED
@@ -1,4 +0,0 @@
1
- [console_scripts]
2
-
3
- [gui_scripts]
4
-
 
 
 
 
 
venv/Lib/site-packages/annotated_doc-0.0.4.dist-info/licenses/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2025 Sebastián Ramírez
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
13
- all 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
21
- THE SOFTWARE.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/annotated_doc/__init__.py DELETED
@@ -1,3 +0,0 @@
1
- from .main import Doc as Doc
2
-
3
- __version__ = "0.0.4"
 
 
 
 
venv/Lib/site-packages/annotated_doc/main.py DELETED
@@ -1,36 +0,0 @@
1
- class Doc:
2
- """Define the documentation of a type annotation using `Annotated`, to be
3
- used in class attributes, function and method parameters, return values,
4
- and variables.
5
-
6
- The value should be a positional-only string literal to allow static tools
7
- like editors and documentation generators to use it.
8
-
9
- This complements docstrings.
10
-
11
- The string value passed is available in the attribute `documentation`.
12
-
13
- Example:
14
-
15
- ```Python
16
- from typing import Annotated
17
- from annotated_doc import Doc
18
-
19
- def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None:
20
- print(f"Hi, {name}!")
21
- ```
22
- """
23
-
24
- def __init__(self, documentation: str, /) -> None:
25
- self.documentation = documentation
26
-
27
- def __repr__(self) -> str:
28
- return f"Doc({self.documentation!r})"
29
-
30
- def __hash__(self) -> int:
31
- return hash(self.documentation)
32
-
33
- def __eq__(self, other: object) -> bool:
34
- if not isinstance(other, Doc):
35
- return NotImplemented
36
- return self.documentation == other.documentation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/annotated_doc/py.typed DELETED
File without changes
venv/Lib/site-packages/annotated_types-0.7.0.dist-info/INSTALLER DELETED
@@ -1 +0,0 @@
1
- pip
 
 
venv/Lib/site-packages/annotated_types-0.7.0.dist-info/METADATA DELETED
@@ -1,295 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: annotated-types
3
- Version: 0.7.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-File: LICENSE
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Environment :: Console
12
- Classifier: Environment :: MacOS X
13
- Classifier: Intended Audience :: Developers
14
- Classifier: Intended Audience :: Information Technology
15
- Classifier: License :: OSI Approved :: MIT License
16
- Classifier: Operating System :: POSIX :: Linux
17
- Classifier: Operating System :: Unix
18
- Classifier: Programming Language :: Python :: 3 :: Only
19
- Classifier: Programming Language :: Python :: 3.8
20
- Classifier: Programming Language :: Python :: 3.9
21
- Classifier: Programming Language :: Python :: 3.10
22
- Classifier: Programming Language :: Python :: 3.11
23
- Classifier: Programming Language :: Python :: 3.12
24
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
- Classifier: Typing :: Typed
26
- Requires-Python: >=3.8
27
- Requires-Dist: typing-extensions>=4.0.0; python_version < '3.9'
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
- * `IsLower = Annotated[T, Predicate(str.islower)]`
209
- * `IsUpper = 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/site-packages/annotated_types-0.7.0.dist-info/RECORD DELETED
@@ -1,10 +0,0 @@
1
- annotated_types-0.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
- annotated_types-0.7.0.dist-info/METADATA,sha256=7ltqxksJJ0wCYFGBNIQCWTlWQGeAH0hRFdnK3CB895E,15046
3
- annotated_types-0.7.0.dist-info/RECORD,,
4
- annotated_types-0.7.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
5
- annotated_types-0.7.0.dist-info/licenses/LICENSE,sha256=_hBJiEsaDZNCkB6I4H8ykl0ksxIdmXK2poBfuYJLCV0,1083
6
- annotated_types/__init__.py,sha256=RynLsRKUEGI0KimXydlD1fZEfEzWwDo0Uon3zOKhG1Q,13819
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=zHFX6EpcMbGJ8FzBYDbO56bPwx_DYIVSKbZM-4B3_lg,6421
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/annotated_types-0.7.0.dist-info/WHEEL DELETED
@@ -1,4 +0,0 @@
1
- Wheel-Version: 1.0
2
- Generator: hatchling 1.24.2
3
- Root-Is-Purelib: true
4
- Tag: py3-none-any
 
 
 
 
 
venv/Lib/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE DELETED
@@ -1,21 +0,0 @@
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/site-packages/annotated_types/__init__.py DELETED
@@ -1,432 +0,0 @@
1
- import math
2
- import sys
3
- import types
4
- from dataclasses import dataclass
5
- from datetime import tzinfo
6
- from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, SupportsFloat, SupportsIndex, TypeVar, Union
7
-
8
- if sys.version_info < (3, 8):
9
- from typing_extensions import Protocol, runtime_checkable
10
- else:
11
- from typing import Protocol, runtime_checkable
12
-
13
- if sys.version_info < (3, 9):
14
- from typing_extensions import Annotated, Literal
15
- else:
16
- from typing import Annotated, Literal
17
-
18
- if sys.version_info < (3, 10):
19
- EllipsisType = type(Ellipsis)
20
- KW_ONLY = {}
21
- SLOTS = {}
22
- else:
23
- from types import EllipsisType
24
-
25
- KW_ONLY = {"kw_only": True}
26
- SLOTS = {"slots": True}
27
-
28
-
29
- __all__ = (
30
- 'BaseMetadata',
31
- 'GroupedMetadata',
32
- 'Gt',
33
- 'Ge',
34
- 'Lt',
35
- 'Le',
36
- 'Interval',
37
- 'MultipleOf',
38
- 'MinLen',
39
- 'MaxLen',
40
- 'Len',
41
- 'Timezone',
42
- 'Predicate',
43
- 'LowerCase',
44
- 'UpperCase',
45
- 'IsDigits',
46
- 'IsFinite',
47
- 'IsNotFinite',
48
- 'IsNan',
49
- 'IsNotNan',
50
- 'IsInfinite',
51
- 'IsNotInfinite',
52
- 'doc',
53
- 'DocInfo',
54
- '__version__',
55
- )
56
-
57
- __version__ = '0.7.0'
58
-
59
-
60
- T = TypeVar('T')
61
-
62
-
63
- # arguments that start with __ are considered
64
- # positional only
65
- # see https://peps.python.org/pep-0484/#positional-only-arguments
66
-
67
-
68
- class SupportsGt(Protocol):
69
- def __gt__(self: T, __other: T) -> bool:
70
- ...
71
-
72
-
73
- class SupportsGe(Protocol):
74
- def __ge__(self: T, __other: T) -> bool:
75
- ...
76
-
77
-
78
- class SupportsLt(Protocol):
79
- def __lt__(self: T, __other: T) -> bool:
80
- ...
81
-
82
-
83
- class SupportsLe(Protocol):
84
- def __le__(self: T, __other: T) -> bool:
85
- ...
86
-
87
-
88
- class SupportsMod(Protocol):
89
- def __mod__(self: T, __other: T) -> T:
90
- ...
91
-
92
-
93
- class SupportsDiv(Protocol):
94
- def __div__(self: T, __other: T) -> T:
95
- ...
96
-
97
-
98
- class BaseMetadata:
99
- """Base class for all metadata.
100
-
101
- This exists mainly so that implementers
102
- can do `isinstance(..., BaseMetadata)` while traversing field annotations.
103
- """
104
-
105
- __slots__ = ()
106
-
107
-
108
- @dataclass(frozen=True, **SLOTS)
109
- class Gt(BaseMetadata):
110
- """Gt(gt=x) implies that the value must be greater than x.
111
-
112
- It can be used with any type that supports the ``>`` operator,
113
- including numbers, dates and times, strings, sets, and so on.
114
- """
115
-
116
- gt: SupportsGt
117
-
118
-
119
- @dataclass(frozen=True, **SLOTS)
120
- class Ge(BaseMetadata):
121
- """Ge(ge=x) implies that the value must be greater than or equal to x.
122
-
123
- It can be used with any type that supports the ``>=`` operator,
124
- including numbers, dates and times, strings, sets, and so on.
125
- """
126
-
127
- ge: SupportsGe
128
-
129
-
130
- @dataclass(frozen=True, **SLOTS)
131
- class Lt(BaseMetadata):
132
- """Lt(lt=x) implies that the value must be less than x.
133
-
134
- It can be used with any type that supports the ``<`` operator,
135
- including numbers, dates and times, strings, sets, and so on.
136
- """
137
-
138
- lt: SupportsLt
139
-
140
-
141
- @dataclass(frozen=True, **SLOTS)
142
- class Le(BaseMetadata):
143
- """Le(le=x) implies that the value must be less than or equal to x.
144
-
145
- It can be used with any type that supports the ``<=`` operator,
146
- including numbers, dates and times, strings, sets, and so on.
147
- """
148
-
149
- le: SupportsLe
150
-
151
-
152
- @runtime_checkable
153
- class GroupedMetadata(Protocol):
154
- """A grouping of multiple objects, like typing.Unpack.
155
-
156
- `GroupedMetadata` on its own is not metadata and has no meaning.
157
- All of the constraints and metadata should be fully expressable
158
- in terms of the `BaseMetadata`'s returned by `GroupedMetadata.__iter__()`.
159
-
160
- Concrete implementations should override `GroupedMetadata.__iter__()`
161
- to add their own metadata.
162
- For example:
163
-
164
- >>> @dataclass
165
- >>> class Field(GroupedMetadata):
166
- >>> gt: float | None = None
167
- >>> description: str | None = None
168
- ...
169
- >>> def __iter__(self) -> Iterable[object]:
170
- >>> if self.gt is not None:
171
- >>> yield Gt(self.gt)
172
- >>> if self.description is not None:
173
- >>> yield Description(self.gt)
174
-
175
- Also see the implementation of `Interval` below for an example.
176
-
177
- Parsers should recognize this and unpack it so that it can be used
178
- both with and without unpacking:
179
-
180
- - `Annotated[int, Field(...)]` (parser must unpack Field)
181
- - `Annotated[int, *Field(...)]` (PEP-646)
182
- """ # noqa: trailing-whitespace
183
-
184
- @property
185
- def __is_annotated_types_grouped_metadata__(self) -> Literal[True]:
186
- return True
187
-
188
- def __iter__(self) -> Iterator[object]:
189
- ...
190
-
191
- if not TYPE_CHECKING:
192
- __slots__ = () # allow subclasses to use slots
193
-
194
- def __init_subclass__(cls, *args: Any, **kwargs: Any) -> None:
195
- # Basic ABC like functionality without the complexity of an ABC
196
- super().__init_subclass__(*args, **kwargs)
197
- if cls.__iter__ is GroupedMetadata.__iter__:
198
- raise TypeError("Can't subclass GroupedMetadata without implementing __iter__")
199
-
200
- def __iter__(self) -> Iterator[object]: # noqa: F811
201
- raise NotImplementedError # more helpful than "None has no attribute..." type errors
202
-
203
-
204
- @dataclass(frozen=True, **KW_ONLY, **SLOTS)
205
- class Interval(GroupedMetadata):
206
- """Interval can express inclusive or exclusive bounds with a single object.
207
-
208
- It accepts keyword arguments ``gt``, ``ge``, ``lt``, and/or ``le``, which
209
- are interpreted the same way as the single-bound constraints.
210
- """
211
-
212
- gt: Union[SupportsGt, None] = None
213
- ge: Union[SupportsGe, None] = None
214
- lt: Union[SupportsLt, None] = None
215
- le: Union[SupportsLe, None] = None
216
-
217
- def __iter__(self) -> Iterator[BaseMetadata]:
218
- """Unpack an Interval into zero or more single-bounds."""
219
- if self.gt is not None:
220
- yield Gt(self.gt)
221
- if self.ge is not None:
222
- yield Ge(self.ge)
223
- if self.lt is not None:
224
- yield Lt(self.lt)
225
- if self.le is not None:
226
- yield Le(self.le)
227
-
228
-
229
- @dataclass(frozen=True, **SLOTS)
230
- class MultipleOf(BaseMetadata):
231
- """MultipleOf(multiple_of=x) might be interpreted in two ways:
232
-
233
- 1. Python semantics, implying ``value % multiple_of == 0``, or
234
- 2. JSONschema semantics, where ``int(value / multiple_of) == value / multiple_of``
235
-
236
- We encourage users to be aware of these two common interpretations,
237
- and libraries to carefully document which they implement.
238
- """
239
-
240
- multiple_of: Union[SupportsDiv, SupportsMod]
241
-
242
-
243
- @dataclass(frozen=True, **SLOTS)
244
- class MinLen(BaseMetadata):
245
- """
246
- MinLen() implies minimum inclusive length,
247
- e.g. ``len(value) >= min_length``.
248
- """
249
-
250
- min_length: Annotated[int, Ge(0)]
251
-
252
-
253
- @dataclass(frozen=True, **SLOTS)
254
- class MaxLen(BaseMetadata):
255
- """
256
- MaxLen() implies maximum inclusive length,
257
- e.g. ``len(value) <= max_length``.
258
- """
259
-
260
- max_length: Annotated[int, Ge(0)]
261
-
262
-
263
- @dataclass(frozen=True, **SLOTS)
264
- class Len(GroupedMetadata):
265
- """
266
- Len() implies that ``min_length <= len(value) <= max_length``.
267
-
268
- Upper bound may be omitted or ``None`` to indicate no upper length bound.
269
- """
270
-
271
- min_length: Annotated[int, Ge(0)] = 0
272
- max_length: Optional[Annotated[int, Ge(0)]] = None
273
-
274
- def __iter__(self) -> Iterator[BaseMetadata]:
275
- """Unpack a Len into zone or more single-bounds."""
276
- if self.min_length > 0:
277
- yield MinLen(self.min_length)
278
- if self.max_length is not None:
279
- yield MaxLen(self.max_length)
280
-
281
-
282
- @dataclass(frozen=True, **SLOTS)
283
- class Timezone(BaseMetadata):
284
- """Timezone(tz=...) requires a datetime to be aware (or ``tz=None``, naive).
285
-
286
- ``Annotated[datetime, Timezone(None)]`` must be a naive datetime.
287
- ``Timezone[...]`` (the ellipsis literal) expresses that the datetime must be
288
- tz-aware but any timezone is allowed.
289
-
290
- You may also pass a specific timezone string or tzinfo object such as
291
- ``Timezone(timezone.utc)`` or ``Timezone("Africa/Abidjan")`` to express that
292
- you only allow a specific timezone, though we note that this is often
293
- a symptom of poor design.
294
- """
295
-
296
- tz: Union[str, tzinfo, EllipsisType, None]
297
-
298
-
299
- @dataclass(frozen=True, **SLOTS)
300
- class Unit(BaseMetadata):
301
- """Indicates that the value is a physical quantity with the specified unit.
302
-
303
- It is intended for usage with numeric types, where the value represents the
304
- magnitude of the quantity. For example, ``distance: Annotated[float, Unit('m')]``
305
- or ``speed: Annotated[float, Unit('m/s')]``.
306
-
307
- Interpretation of the unit string is left to the discretion of the consumer.
308
- It is suggested to follow conventions established by python libraries that work
309
- with physical quantities, such as
310
-
311
- - ``pint`` : <https://pint.readthedocs.io/en/stable/>
312
- - ``astropy.units``: <https://docs.astropy.org/en/stable/units/>
313
-
314
- For indicating a quantity with a certain dimensionality but without a specific unit
315
- it is recommended to use square brackets, e.g. `Annotated[float, Unit('[time]')]`.
316
- Note, however, ``annotated_types`` itself makes no use of the unit string.
317
- """
318
-
319
- unit: str
320
-
321
-
322
- @dataclass(frozen=True, **SLOTS)
323
- class Predicate(BaseMetadata):
324
- """``Predicate(func: Callable)`` implies `func(value)` is truthy for valid values.
325
-
326
- Users should prefer statically inspectable metadata, but if you need the full
327
- power and flexibility of arbitrary runtime predicates... here it is.
328
-
329
- We provide a few predefined predicates for common string constraints:
330
- ``IsLower = Predicate(str.islower)``, ``IsUpper = Predicate(str.isupper)``, and
331
- ``IsDigits = Predicate(str.isdigit)``. Users are encouraged to use methods which
332
- can be given special handling, and avoid indirection like ``lambda s: s.lower()``.
333
-
334
- Some libraries might have special logic to handle certain predicates, e.g. by
335
- checking for `str.isdigit` and using its presence to both call custom logic to
336
- enforce digit-only strings, and customise some generated external schema.
337
-
338
- We do not specify what behaviour should be expected for predicates that raise
339
- an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently
340
- skip invalid constraints, or statically raise an error; or it might try calling it
341
- and then propagate or discard the resulting exception.
342
- """
343
-
344
- func: Callable[[Any], bool]
345
-
346
- def __repr__(self) -> str:
347
- if getattr(self.func, "__name__", "<lambda>") == "<lambda>":
348
- return f"{self.__class__.__name__}({self.func!r})"
349
- if isinstance(self.func, (types.MethodType, types.BuiltinMethodType)) and (
350
- namespace := getattr(self.func.__self__, "__name__", None)
351
- ):
352
- return f"{self.__class__.__name__}({namespace}.{self.func.__name__})"
353
- if isinstance(self.func, type(str.isascii)): # method descriptor
354
- return f"{self.__class__.__name__}({self.func.__qualname__})"
355
- return f"{self.__class__.__name__}({self.func.__name__})"
356
-
357
-
358
- @dataclass
359
- class Not:
360
- func: Callable[[Any], bool]
361
-
362
- def __call__(self, __v: Any) -> bool:
363
- return not self.func(__v)
364
-
365
-
366
- _StrType = TypeVar("_StrType", bound=str)
367
-
368
- LowerCase = Annotated[_StrType, Predicate(str.islower)]
369
- """
370
- Return True if the string is a lowercase string, False otherwise.
371
-
372
- A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string.
373
- """ # noqa: E501
374
- UpperCase = Annotated[_StrType, Predicate(str.isupper)]
375
- """
376
- Return True if the string is an uppercase string, False otherwise.
377
-
378
- A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string.
379
- """ # noqa: E501
380
- IsDigit = Annotated[_StrType, Predicate(str.isdigit)]
381
- IsDigits = IsDigit # type: ignore # plural for backwards compatibility, see #63
382
- """
383
- Return True if the string is a digit string, False otherwise.
384
-
385
- A string is a digit string if all characters in the string are digits and there is at least one character in the string.
386
- """ # noqa: E501
387
- IsAscii = Annotated[_StrType, Predicate(str.isascii)]
388
- """
389
- Return True if all characters in the string are ASCII, False otherwise.
390
-
391
- ASCII characters have code points in the range U+0000-U+007F. Empty string is ASCII too.
392
- """
393
-
394
- _NumericType = TypeVar('_NumericType', bound=Union[SupportsFloat, SupportsIndex])
395
- IsFinite = Annotated[_NumericType, Predicate(math.isfinite)]
396
- """Return True if x is neither an infinity nor a NaN, and False otherwise."""
397
- IsNotFinite = Annotated[_NumericType, Predicate(Not(math.isfinite))]
398
- """Return True if x is one of infinity or NaN, and False otherwise"""
399
- IsNan = Annotated[_NumericType, Predicate(math.isnan)]
400
- """Return True if x is a NaN (not a number), and False otherwise."""
401
- IsNotNan = Annotated[_NumericType, Predicate(Not(math.isnan))]
402
- """Return True if x is anything but NaN (not a number), and False otherwise."""
403
- IsInfinite = Annotated[_NumericType, Predicate(math.isinf)]
404
- """Return True if x is a positive or negative infinity, and False otherwise."""
405
- IsNotInfinite = Annotated[_NumericType, Predicate(Not(math.isinf))]
406
- """Return True if x is neither a positive or negative infinity, and False otherwise."""
407
-
408
- try:
409
- from typing_extensions import DocInfo, doc # type: ignore [attr-defined]
410
- except ImportError:
411
-
412
- @dataclass(frozen=True, **SLOTS)
413
- class DocInfo: # type: ignore [no-redef]
414
- """ "
415
- The return value of doc(), mainly to be used by tools that want to extract the
416
- Annotated documentation at runtime.
417
- """
418
-
419
- documentation: str
420
- """The documentation string passed to doc()."""
421
-
422
- def doc(
423
- documentation: str,
424
- ) -> DocInfo:
425
- """
426
- Add documentation to a type annotation inside of Annotated.
427
-
428
- For example:
429
-
430
- >>> def hi(name: Annotated[int, doc("The name of the user")]) -> None: ...
431
- """
432
- return DocInfo(documentation)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/annotated_types/py.typed DELETED
File without changes
venv/Lib/site-packages/annotated_types/test_cases.py DELETED
@@ -1,151 +0,0 @@
1
- import math
2
- import sys
3
- from datetime import date, datetime, timedelta, timezone
4
- from decimal import Decimal
5
- from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Set, Tuple
6
-
7
- if sys.version_info < (3, 9):
8
- from typing_extensions import Annotated
9
- else:
10
- from typing import Annotated
11
-
12
- import annotated_types as at
13
-
14
-
15
- class Case(NamedTuple):
16
- """
17
- A test case for `annotated_types`.
18
- """
19
-
20
- annotation: Any
21
- valid_cases: Iterable[Any]
22
- invalid_cases: Iterable[Any]
23
-
24
-
25
- def cases() -> Iterable[Case]:
26
- # Gt, Ge, Lt, Le
27
- yield Case(Annotated[int, at.Gt(4)], (5, 6, 1000), (4, 0, -1))
28
- yield Case(Annotated[float, at.Gt(0.5)], (0.6, 0.7, 0.8, 0.9), (0.5, 0.0, -0.1))
29
- yield Case(
30
- Annotated[datetime, at.Gt(datetime(2000, 1, 1))],
31
- [datetime(2000, 1, 2), datetime(2000, 1, 3)],
32
- [datetime(2000, 1, 1), datetime(1999, 12, 31)],
33
- )
34
- yield Case(
35
- Annotated[datetime, at.Gt(date(2000, 1, 1))],
36
- [date(2000, 1, 2), date(2000, 1, 3)],
37
- [date(2000, 1, 1), date(1999, 12, 31)],
38
- )
39
- yield Case(
40
- Annotated[datetime, at.Gt(Decimal('1.123'))],
41
- [Decimal('1.1231'), Decimal('123')],
42
- [Decimal('1.123'), Decimal('0')],
43
- )
44
-
45
- yield Case(Annotated[int, at.Ge(4)], (4, 5, 6, 1000, 4), (0, -1))
46
- yield Case(Annotated[float, at.Ge(0.5)], (0.5, 0.6, 0.7, 0.8, 0.9), (0.4, 0.0, -0.1))
47
- yield Case(
48
- Annotated[datetime, at.Ge(datetime(2000, 1, 1))],
49
- [datetime(2000, 1, 2), datetime(2000, 1, 3)],
50
- [datetime(1998, 1, 1), datetime(1999, 12, 31)],
51
- )
52
-
53
- yield Case(Annotated[int, at.Lt(4)], (0, -1), (4, 5, 6, 1000, 4))
54
- yield Case(Annotated[float, at.Lt(0.5)], (0.4, 0.0, -0.1), (0.5, 0.6, 0.7, 0.8, 0.9))
55
- yield Case(
56
- Annotated[datetime, at.Lt(datetime(2000, 1, 1))],
57
- [datetime(1999, 12, 31), datetime(1999, 12, 31)],
58
- [datetime(2000, 1, 2), datetime(2000, 1, 3)],
59
- )
60
-
61
- yield Case(Annotated[int, at.Le(4)], (4, 0, -1), (5, 6, 1000))
62
- yield Case(Annotated[float, at.Le(0.5)], (0.5, 0.0, -0.1), (0.6, 0.7, 0.8, 0.9))
63
- yield Case(
64
- Annotated[datetime, at.Le(datetime(2000, 1, 1))],
65
- [datetime(2000, 1, 1), datetime(1999, 12, 31)],
66
- [datetime(2000, 1, 2), datetime(2000, 1, 3)],
67
- )
68
-
69
- # Interval
70
- yield Case(Annotated[int, at.Interval(gt=4)], (5, 6, 1000), (4, 0, -1))
71
- yield Case(Annotated[int, at.Interval(gt=4, lt=10)], (5, 6), (4, 10, 1000, 0, -1))
72
- yield Case(Annotated[float, at.Interval(ge=0.5, le=1)], (0.5, 0.9, 1), (0.49, 1.1))
73
- yield Case(
74
- Annotated[datetime, at.Interval(gt=datetime(2000, 1, 1), le=datetime(2000, 1, 3))],
75
- [datetime(2000, 1, 2), datetime(2000, 1, 3)],
76
- [datetime(2000, 1, 1), datetime(2000, 1, 4)],
77
- )
78
-
79
- yield Case(Annotated[int, at.MultipleOf(multiple_of=3)], (0, 3, 9), (1, 2, 4))
80
- yield Case(Annotated[float, at.MultipleOf(multiple_of=0.5)], (0, 0.5, 1, 1.5), (0.4, 1.1))
81
-
82
- # lengths
83
-
84
- yield Case(Annotated[str, at.MinLen(3)], ('123', '1234', 'x' * 10), ('', '1', '12'))
85
- yield Case(Annotated[str, at.Len(3)], ('123', '1234', 'x' * 10), ('', '1', '12'))
86
- yield Case(Annotated[List[int], at.MinLen(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2]))
87
- yield Case(Annotated[List[int], at.Len(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2]))
88
-
89
- yield Case(Annotated[str, at.MaxLen(4)], ('', '1234'), ('12345', 'x' * 10))
90
- yield Case(Annotated[str, at.Len(0, 4)], ('', '1234'), ('12345', 'x' * 10))
91
- yield Case(Annotated[List[str], at.MaxLen(4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10))
92
- yield Case(Annotated[List[str], at.Len(0, 4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10))
93
-
94
- yield Case(Annotated[str, at.Len(3, 5)], ('123', '12345'), ('', '1', '12', '123456', 'x' * 10))
95
- yield Case(Annotated[str, at.Len(3, 3)], ('123',), ('12', '1234'))
96
-
97
- yield Case(Annotated[Dict[int, int], at.Len(2, 3)], [{1: 1, 2: 2}], [{}, {1: 1}, {1: 1, 2: 2, 3: 3, 4: 4}])
98
- yield Case(Annotated[Set[int], at.Len(2, 3)], ({1, 2}, {1, 2, 3}), (set(), {1}, {1, 2, 3, 4}))
99
- yield Case(Annotated[Tuple[int, ...], at.Len(2, 3)], ((1, 2), (1, 2, 3)), ((), (1,), (1, 2, 3, 4)))
100
-
101
- # Timezone
102
-
103
- yield Case(
104
- Annotated[datetime, at.Timezone(None)], [datetime(2000, 1, 1)], [datetime(2000, 1, 1, tzinfo=timezone.utc)]
105
- )
106
- yield Case(
107
- Annotated[datetime, at.Timezone(...)], [datetime(2000, 1, 1, tzinfo=timezone.utc)], [datetime(2000, 1, 1)]
108
- )
109
- yield Case(
110
- Annotated[datetime, at.Timezone(timezone.utc)],
111
- [datetime(2000, 1, 1, tzinfo=timezone.utc)],
112
- [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))],
113
- )
114
- yield Case(
115
- Annotated[datetime, at.Timezone('Europe/London')],
116
- [datetime(2000, 1, 1, tzinfo=timezone(timedelta(0), name='Europe/London'))],
117
- [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))],
118
- )
119
-
120
- # Quantity
121
-
122
- yield Case(Annotated[float, at.Unit(unit='m')], (5, 4.2), ('5m', '4.2m'))
123
-
124
- # predicate types
125
-
126
- yield Case(at.LowerCase[str], ['abc', 'foobar'], ['', 'A', 'Boom'])
127
- yield Case(at.UpperCase[str], ['ABC', 'DEFO'], ['', 'a', 'abc', 'AbC'])
128
- yield Case(at.IsDigit[str], ['123'], ['', 'ab', 'a1b2'])
129
- yield Case(at.IsAscii[str], ['123', 'foo bar'], ['£100', '😊', 'whatever 👀'])
130
-
131
- yield Case(Annotated[int, at.Predicate(lambda x: x % 2 == 0)], [0, 2, 4], [1, 3, 5])
132
-
133
- yield Case(at.IsFinite[float], [1.23], [math.nan, math.inf, -math.inf])
134
- yield Case(at.IsNotFinite[float], [math.nan, math.inf], [1.23])
135
- yield Case(at.IsNan[float], [math.nan], [1.23, math.inf])
136
- yield Case(at.IsNotNan[float], [1.23, math.inf], [math.nan])
137
- yield Case(at.IsInfinite[float], [math.inf], [math.nan, 1.23])
138
- yield Case(at.IsNotInfinite[float], [math.nan, 1.23], [math.inf])
139
-
140
- # check stacked predicates
141
- yield Case(at.IsInfinite[Annotated[float, at.Predicate(lambda x: x > 0)]], [math.inf], [-math.inf, 1.23, math.nan])
142
-
143
- # doc
144
- yield Case(Annotated[int, at.doc("A number")], [1, 2], [])
145
-
146
- # custom GroupedMetadata
147
- class MyCustomGroupedMetadata(at.GroupedMetadata):
148
- def __iter__(self) -> Iterator[at.Predicate]:
149
- yield at.Predicate(lambda x: float(x).is_integer())
150
-
151
- yield Case(Annotated[float, MyCustomGroupedMetadata()], [0, 2.0], [0.01, 1.5])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio-4.12.1.dist-info/INSTALLER DELETED
@@ -1 +0,0 @@
1
- pip
 
 
venv/Lib/site-packages/anyio-4.12.1.dist-info/METADATA DELETED
@@ -1,96 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: anyio
3
- Version: 4.12.1
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.9
18
- Classifier: Programming Language :: Python :: 3.10
19
- Classifier: Programming Language :: Python :: 3.11
20
- Classifier: Programming Language :: Python :: 3.12
21
- Classifier: Programming Language :: Python :: 3.13
22
- Classifier: Programming Language :: Python :: 3.14
23
- Requires-Python: >=3.9
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; python_version >= "3.10" and extra == "trio"
31
- Requires-Dist: trio>=0.31.0; python_version < "3.10" and extra == "trio"
32
- Dynamic: license-file
33
-
34
- .. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg
35
- :target: https://github.com/agronholm/anyio/actions/workflows/test.yml
36
- :alt: Build Status
37
- .. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master
38
- :target: https://coveralls.io/github/agronholm/anyio?branch=master
39
- :alt: Code Coverage
40
- .. image:: https://readthedocs.org/projects/anyio/badge/?version=latest
41
- :target: https://anyio.readthedocs.io/en/latest/?badge=latest
42
- :alt: Documentation
43
- .. image:: https://badges.gitter.im/gitterHQ/gitter.svg
44
- :target: https://gitter.im/python-trio/AnyIO
45
- :alt: Gitter chat
46
-
47
- AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or
48
- Trio_. It implements Trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony
49
- with the native SC of Trio itself.
50
-
51
- Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or
52
- Trio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full
53
- refactoring necessary. It will blend in with the native libraries of your chosen backend.
54
-
55
- To find out why you might want to use AnyIO's APIs instead of asyncio's, you can read about it
56
- `here <https://anyio.readthedocs.io/en/stable/why.html>`_.
57
-
58
- Documentation
59
- -------------
60
-
61
- View full documentation at: https://anyio.readthedocs.io/
62
-
63
- Features
64
- --------
65
-
66
- AnyIO offers the following functionality:
67
-
68
- * Task groups (nurseries_ in trio terminology)
69
- * High-level networking (TCP, UDP and UNIX sockets)
70
-
71
- * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python
72
- 3.8)
73
- * async/await style UDP sockets (unlike asyncio where you still have to use Transports and
74
- Protocols)
75
-
76
- * A versatile API for byte streams and object streams
77
- * Inter-task synchronization and communication (locks, conditions, events, semaphores, object
78
- streams)
79
- * Worker threads
80
- * Subprocesses
81
- * Subinterpreter support for code parallelization (on Python 3.13 and later)
82
- * Asynchronous file I/O (using worker threads)
83
- * Signal handling
84
- * Asynchronous version of the functools_ module
85
-
86
- AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures.
87
- It even works with the popular Hypothesis_ library.
88
-
89
- .. _asyncio: https://docs.python.org/3/library/asyncio.html
90
- .. _Trio: https://github.com/python-trio/trio
91
- .. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency
92
- .. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning
93
- .. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs
94
- .. _pytest: https://docs.pytest.org/en/latest/
95
- .. _functools: https://docs.python.org/3/library/functools.html
96
- .. _Hypothesis: https://hypothesis.works/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio-4.12.1.dist-info/RECORD DELETED
@@ -1,92 +0,0 @@
1
- anyio-4.12.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
- anyio-4.12.1.dist-info/METADATA,sha256=DfiDab9Tmmcfy802lOLTMEHJQShkOSbopCwqCYbLuJk,4277
3
- anyio-4.12.1.dist-info/RECORD,,
4
- anyio-4.12.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
5
- anyio-4.12.1.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39
6
- anyio-4.12.1.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081
7
- anyio-4.12.1.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6
8
- anyio/__init__.py,sha256=7iDVqMUprUuKNY91FuoKqayAhR-OY136YDPI6P78HHk,6170
9
- anyio/__pycache__/__init__.cpython-313.pyc,,
10
- anyio/__pycache__/from_thread.cpython-313.pyc,,
11
- anyio/__pycache__/functools.cpython-313.pyc,,
12
- anyio/__pycache__/lowlevel.cpython-313.pyc,,
13
- anyio/__pycache__/pytest_plugin.cpython-313.pyc,,
14
- anyio/__pycache__/to_interpreter.cpython-313.pyc,,
15
- anyio/__pycache__/to_process.cpython-313.pyc,,
16
- anyio/__pycache__/to_thread.cpython-313.pyc,,
17
- anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- anyio/_backends/__pycache__/__init__.cpython-313.pyc,,
19
- anyio/_backends/__pycache__/_asyncio.cpython-313.pyc,,
20
- anyio/_backends/__pycache__/_trio.cpython-313.pyc,,
21
- anyio/_backends/_asyncio.py,sha256=xG6qv60mgGnL0mK82dxjH2b8hlkMlJ-x2BqIq3qv70Y,98863
22
- anyio/_backends/_trio.py,sha256=30Rctb7lm8g63ZHljVPVnj5aH-uK6oQvphjwUBoAzuI,41456
23
- anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- anyio/_core/__pycache__/__init__.cpython-313.pyc,,
25
- anyio/_core/__pycache__/_asyncio_selector_thread.cpython-313.pyc,,
26
- anyio/_core/__pycache__/_contextmanagers.cpython-313.pyc,,
27
- anyio/_core/__pycache__/_eventloop.cpython-313.pyc,,
28
- anyio/_core/__pycache__/_exceptions.cpython-313.pyc,,
29
- anyio/_core/__pycache__/_fileio.cpython-313.pyc,,
30
- anyio/_core/__pycache__/_resources.cpython-313.pyc,,
31
- anyio/_core/__pycache__/_signals.cpython-313.pyc,,
32
- anyio/_core/__pycache__/_sockets.cpython-313.pyc,,
33
- anyio/_core/__pycache__/_streams.cpython-313.pyc,,
34
- anyio/_core/__pycache__/_subprocesses.cpython-313.pyc,,
35
- anyio/_core/__pycache__/_synchronization.cpython-313.pyc,,
36
- anyio/_core/__pycache__/_tasks.cpython-313.pyc,,
37
- anyio/_core/__pycache__/_tempfile.cpython-313.pyc,,
38
- anyio/_core/__pycache__/_testing.cpython-313.pyc,,
39
- anyio/_core/__pycache__/_typedattr.cpython-313.pyc,,
40
- anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626
41
- anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215
42
- anyio/_core/_eventloop.py,sha256=c2EdcBX-xnKwxPcC4Pjn3_qG9I-x4IWFO2R9RqCGjM4,6448
43
- anyio/_core/_exceptions.py,sha256=Y3aq-Wxd7Q2HqwSg7nZPvRsHEuGazv_qeet6gqEBdPk,4407
44
- anyio/_core/_fileio.py,sha256=uc7t10Vb-If7GbdWM_zFf-ajUe6uek63fSt7IBLlZW0,25731
45
- anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435
46
- anyio/_core/_signals.py,sha256=mjTBB2hTKNPRlU0IhnijeQedpWOGERDiMjSlJQsFrug,1016
47
- anyio/_core/_sockets.py,sha256=RBXHcUqZt5gg_-OOfgHVv8uq2FSKk1uVUzTdpjBoI1o,34977
48
- anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806
49
- anyio/_core/_subprocesses.py,sha256=EXm5igL7dj55iYkPlbYVAqtbqxJxjU-6OndSTIx9SRg,8047
50
- anyio/_core/_synchronization.py,sha256=MgVVqFzvt580tHC31LiOcq1G6aryut--xRG4Ff8KwxQ,20869
51
- anyio/_core/_tasks.py,sha256=pVB7K6AAulzUM8YgXAeqNZG44nSyZ1bYJjH8GznC00I,5435
52
- anyio/_core/_tempfile.py,sha256=lHb7CW4FyIlpkf5ADAf4VmLHCKwEHF9nxqNyBCFFUiA,19697
53
- anyio/_core/_testing.py,sha256=u7MPqGXwpTxqI7hclSdNA30z2GH1Nw258uwKvy_RfBg,2340
54
- anyio/_core/_typedattr.py,sha256=P4ozZikn3-DbpoYcvyghS_FOYAgbmUxeoU8-L_07pZM,2508
55
- anyio/abc/__init__.py,sha256=6mWhcl_pGXhrgZVHP_TCfMvIXIOp9mroEFM90fYCU_U,2869
56
- anyio/abc/__pycache__/__init__.cpython-313.pyc,,
57
- anyio/abc/__pycache__/_eventloop.cpython-313.pyc,,
58
- anyio/abc/__pycache__/_resources.cpython-313.pyc,,
59
- anyio/abc/__pycache__/_sockets.cpython-313.pyc,,
60
- anyio/abc/__pycache__/_streams.cpython-313.pyc,,
61
- anyio/abc/__pycache__/_subprocesses.cpython-313.pyc,,
62
- anyio/abc/__pycache__/_tasks.cpython-313.pyc,,
63
- anyio/abc/__pycache__/_testing.cpython-313.pyc,,
64
- anyio/abc/_eventloop.py,sha256=GlzgB3UJGgG6Kr7olpjOZ-o00PghecXuofVDQ_5611Q,10749
65
- anyio/abc/_resources.py,sha256=DrYvkNN1hH6Uvv5_5uKySvDsnknGVDe8FCKfko0VtN8,783
66
- anyio/abc/_sockets.py,sha256=ECTY0jLEF18gryANHR3vFzXzGdZ-xPwELq1QdgOb0Jo,13258
67
- anyio/abc/_streams.py,sha256=005GKSCXGprxnhucILboSqc2JFovECZk9m3p-qqxXVc,7640
68
- anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067
69
- anyio/abc/_tasks.py,sha256=KC7wrciE48AINOI-AhPutnFhe1ewfP7QnamFlDzqesQ,3721
70
- anyio/abc/_testing.py,sha256=tBJUzkSfOXJw23fe8qSJ03kJlShOYjjaEyFB6k6MYT8,1821
71
- anyio/from_thread.py,sha256=L-0w1HxJ6BSb-KuVi57k5Tkc3yzQrx3QK5tAxMPcY-0,19141
72
- anyio/functools.py,sha256=HWj7GBEmc0Z-mZg3uok7Z7ZJn0rEC_0Pzbt0nYUDaTQ,10973
73
- anyio/lowlevel.py,sha256=AyKLVK3LaWSoK39LkCKxE4_GDMLKZBNqTrLUgk63y80,5158
74
- anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- anyio/pytest_plugin.py,sha256=3jAFQn0jv_pyoWE2GBBlHaj9sqXj4e8vob0_hgrsXE8,10244
76
- anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
- anyio/streams/__pycache__/__init__.cpython-313.pyc,,
78
- anyio/streams/__pycache__/buffered.cpython-313.pyc,,
79
- anyio/streams/__pycache__/file.cpython-313.pyc,,
80
- anyio/streams/__pycache__/memory.cpython-313.pyc,,
81
- anyio/streams/__pycache__/stapled.cpython-313.pyc,,
82
- anyio/streams/__pycache__/text.cpython-313.pyc,,
83
- anyio/streams/__pycache__/tls.cpython-313.pyc,,
84
- anyio/streams/buffered.py,sha256=2R3PeJhe4EXrdYqz44Y6-Eg9R6DrmlsYrP36Ir43-po,6263
85
- anyio/streams/file.py,sha256=4WZ7XGz5WNu39FQHvqbe__TQ0HDP9OOhgO1mk9iVpVU,4470
86
- anyio/streams/memory.py,sha256=F0zwzvFJKAhX_LRZGoKzzqDC2oMM-f-yyTBrEYEGOaU,10740
87
- anyio/streams/stapled.py,sha256=T8Xqwf8K6EgURPxbt1N4i7A8BAk-gScv-GRhjLXIf_o,4390
88
- anyio/streams/text.py,sha256=BcVAGJw1VRvtIqnv-o0Rb0pwH7p8vwlvl21xHq522ag,5765
89
- anyio/streams/tls.py,sha256=Jpxy0Mfbcp1BxHCwE-YjSSFaLnIBbnnwur-excYThs4,15368
90
- anyio/to_interpreter.py,sha256=_mLngrMy97TMR6VbW4Y6YzDUk9ZuPcQMPlkuyRh3C9k,7100
91
- anyio/to_process.py,sha256=J7gAA_YOuoHqnpDAf5fm1Qu6kOmTzdFbiDNvnV755vk,9798
92
- anyio/to_thread.py,sha256=menEgXYmUV7Fjg_9WqCV95P9MAtQS8BzPGGcWB_QnfQ,2687
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio-4.12.1.dist-info/WHEEL DELETED
@@ -1,5 +0,0 @@
1
- Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
3
- Root-Is-Purelib: true
4
- Tag: py3-none-any
5
-
 
 
 
 
 
 
venv/Lib/site-packages/anyio-4.12.1.dist-info/entry_points.txt DELETED
@@ -1,2 +0,0 @@
1
- [pytest11]
2
- anyio = anyio.pytest_plugin
 
 
 
venv/Lib/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE DELETED
@@ -1,20 +0,0 @@
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/site-packages/anyio-4.12.1.dist-info/top_level.txt DELETED
@@ -1 +0,0 @@
1
- anyio
 
 
venv/Lib/site-packages/anyio/__init__.py DELETED
@@ -1,111 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from ._core._contextmanagers import AsyncContextManagerMixin as AsyncContextManagerMixin
4
- from ._core._contextmanagers import ContextManagerMixin as ContextManagerMixin
5
- from ._core._eventloop import current_time as current_time
6
- from ._core._eventloop import get_all_backends as get_all_backends
7
- from ._core._eventloop import get_available_backends as get_available_backends
8
- from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class
9
- from ._core._eventloop import run as run
10
- from ._core._eventloop import sleep as sleep
11
- from ._core._eventloop import sleep_forever as sleep_forever
12
- from ._core._eventloop import sleep_until as sleep_until
13
- from ._core._exceptions import BrokenResourceError as BrokenResourceError
14
- from ._core._exceptions import BrokenWorkerInterpreter as BrokenWorkerInterpreter
15
- from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess
16
- from ._core._exceptions import BusyResourceError as BusyResourceError
17
- from ._core._exceptions import ClosedResourceError as ClosedResourceError
18
- from ._core._exceptions import ConnectionFailed as ConnectionFailed
19
- from ._core._exceptions import DelimiterNotFound as DelimiterNotFound
20
- from ._core._exceptions import EndOfStream as EndOfStream
21
- from ._core._exceptions import IncompleteRead as IncompleteRead
22
- from ._core._exceptions import NoEventLoopError as NoEventLoopError
23
- from ._core._exceptions import RunFinishedError as RunFinishedError
24
- from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError
25
- from ._core._exceptions import WouldBlock as WouldBlock
26
- from ._core._fileio import AsyncFile as AsyncFile
27
- from ._core._fileio import Path as Path
28
- from ._core._fileio import open_file as open_file
29
- from ._core._fileio import wrap_file as wrap_file
30
- from ._core._resources import aclose_forcefully as aclose_forcefully
31
- from ._core._signals import open_signal_receiver as open_signal_receiver
32
- from ._core._sockets import TCPConnectable as TCPConnectable
33
- from ._core._sockets import UNIXConnectable as UNIXConnectable
34
- from ._core._sockets import as_connectable as as_connectable
35
- from ._core._sockets import connect_tcp as connect_tcp
36
- from ._core._sockets import connect_unix as connect_unix
37
- from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket
38
- from ._core._sockets import (
39
- create_connected_unix_datagram_socket as create_connected_unix_datagram_socket,
40
- )
41
- from ._core._sockets import create_tcp_listener as create_tcp_listener
42
- from ._core._sockets import create_udp_socket as create_udp_socket
43
- from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket
44
- from ._core._sockets import create_unix_listener as create_unix_listener
45
- from ._core._sockets import getaddrinfo as getaddrinfo
46
- from ._core._sockets import getnameinfo as getnameinfo
47
- from ._core._sockets import notify_closing as notify_closing
48
- from ._core._sockets import wait_readable as wait_readable
49
- from ._core._sockets import wait_socket_readable as wait_socket_readable
50
- from ._core._sockets import wait_socket_writable as wait_socket_writable
51
- from ._core._sockets import wait_writable as wait_writable
52
- from ._core._streams import create_memory_object_stream as create_memory_object_stream
53
- from ._core._subprocesses import open_process as open_process
54
- from ._core._subprocesses import run_process as run_process
55
- from ._core._synchronization import CapacityLimiter as CapacityLimiter
56
- from ._core._synchronization import (
57
- CapacityLimiterStatistics as CapacityLimiterStatistics,
58
- )
59
- from ._core._synchronization import Condition as Condition
60
- from ._core._synchronization import ConditionStatistics as ConditionStatistics
61
- from ._core._synchronization import Event as Event
62
- from ._core._synchronization import EventStatistics as EventStatistics
63
- from ._core._synchronization import Lock as Lock
64
- from ._core._synchronization import LockStatistics as LockStatistics
65
- from ._core._synchronization import ResourceGuard as ResourceGuard
66
- from ._core._synchronization import Semaphore as Semaphore
67
- from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics
68
- from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED
69
- from ._core._tasks import CancelScope as CancelScope
70
- from ._core._tasks import create_task_group as create_task_group
71
- from ._core._tasks import current_effective_deadline as current_effective_deadline
72
- from ._core._tasks import fail_after as fail_after
73
- from ._core._tasks import move_on_after as move_on_after
74
- from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile
75
- from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile
76
- from ._core._tempfile import TemporaryDirectory as TemporaryDirectory
77
- from ._core._tempfile import TemporaryFile as TemporaryFile
78
- from ._core._tempfile import gettempdir as gettempdir
79
- from ._core._tempfile import gettempdirb as gettempdirb
80
- from ._core._tempfile import mkdtemp as mkdtemp
81
- from ._core._tempfile import mkstemp as mkstemp
82
- from ._core._testing import TaskInfo as TaskInfo
83
- from ._core._testing import get_current_task as get_current_task
84
- from ._core._testing import get_running_tasks as get_running_tasks
85
- from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked
86
- from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider
87
- from ._core._typedattr import TypedAttributeSet as TypedAttributeSet
88
- from ._core._typedattr import typed_attribute as typed_attribute
89
-
90
- # Re-export imports so they look like they live directly in this package
91
- for __value in list(locals().values()):
92
- if getattr(__value, "__module__", "").startswith("anyio."):
93
- __value.__module__ = __name__
94
-
95
-
96
- del __value
97
-
98
-
99
- def __getattr__(attr: str) -> type[BrokenWorkerInterpreter]:
100
- """Support deprecated aliases."""
101
- if attr == "BrokenWorkerIntepreter":
102
- import warnings
103
-
104
- warnings.warn(
105
- "The 'BrokenWorkerIntepreter' alias is deprecated, use 'BrokenWorkerInterpreter' instead.",
106
- DeprecationWarning,
107
- stacklevel=2,
108
- )
109
- return BrokenWorkerInterpreter
110
-
111
- raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_backends/__init__.py DELETED
File without changes
venv/Lib/site-packages/anyio/_backends/_asyncio.py DELETED
The diff for this file is too large to render. See raw diff
 
venv/Lib/site-packages/anyio/_backends/_trio.py DELETED
@@ -1,1346 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import array
4
- import math
5
- import os
6
- import socket
7
- import sys
8
- import types
9
- import weakref
10
- from collections.abc import (
11
- AsyncGenerator,
12
- AsyncIterator,
13
- Awaitable,
14
- Callable,
15
- Collection,
16
- Coroutine,
17
- Iterable,
18
- Sequence,
19
- )
20
- from contextlib import AbstractContextManager
21
- from dataclasses import dataclass
22
- from io import IOBase
23
- from os import PathLike
24
- from signal import Signals
25
- from socket import AddressFamily, SocketKind
26
- from types import TracebackType
27
- from typing import (
28
- IO,
29
- TYPE_CHECKING,
30
- Any,
31
- Generic,
32
- NoReturn,
33
- TypeVar,
34
- cast,
35
- overload,
36
- )
37
-
38
- import trio.from_thread
39
- import trio.lowlevel
40
- from outcome import Error, Outcome, Value
41
- from trio.lowlevel import (
42
- current_root_task,
43
- current_task,
44
- notify_closing,
45
- wait_readable,
46
- wait_writable,
47
- )
48
- from trio.socket import SocketType as TrioSocketType
49
- from trio.to_thread import run_sync
50
-
51
- from .. import (
52
- CapacityLimiterStatistics,
53
- EventStatistics,
54
- LockStatistics,
55
- RunFinishedError,
56
- TaskInfo,
57
- WouldBlock,
58
- abc,
59
- )
60
- from .._core._eventloop import claim_worker_thread
61
- from .._core._exceptions import (
62
- BrokenResourceError,
63
- BusyResourceError,
64
- ClosedResourceError,
65
- EndOfStream,
66
- )
67
- from .._core._sockets import convert_ipv6_sockaddr
68
- from .._core._streams import create_memory_object_stream
69
- from .._core._synchronization import (
70
- CapacityLimiter as BaseCapacityLimiter,
71
- )
72
- from .._core._synchronization import Event as BaseEvent
73
- from .._core._synchronization import Lock as BaseLock
74
- from .._core._synchronization import (
75
- ResourceGuard,
76
- SemaphoreStatistics,
77
- )
78
- from .._core._synchronization import Semaphore as BaseSemaphore
79
- from .._core._tasks import CancelScope as BaseCancelScope
80
- from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType
81
- from ..abc._eventloop import AsyncBackend, StrOrBytesPath
82
- from ..streams.memory import MemoryObjectSendStream
83
-
84
- if TYPE_CHECKING:
85
- from _typeshed import FileDescriptorLike
86
-
87
- if sys.version_info >= (3, 10):
88
- from typing import ParamSpec
89
- else:
90
- from typing_extensions import ParamSpec
91
-
92
- if sys.version_info >= (3, 11):
93
- from typing import TypeVarTuple, Unpack
94
- else:
95
- from exceptiongroup import BaseExceptionGroup
96
- from typing_extensions import TypeVarTuple, Unpack
97
-
98
- T = TypeVar("T")
99
- T_Retval = TypeVar("T_Retval")
100
- T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType)
101
- PosArgsT = TypeVarTuple("PosArgsT")
102
- P = ParamSpec("P")
103
-
104
-
105
- #
106
- # Event loop
107
- #
108
-
109
- RunVar = trio.lowlevel.RunVar
110
-
111
-
112
- #
113
- # Timeouts and cancellation
114
- #
115
-
116
-
117
- class CancelScope(BaseCancelScope):
118
- def __new__(
119
- cls, original: trio.CancelScope | None = None, **kwargs: object
120
- ) -> CancelScope:
121
- return object.__new__(cls)
122
-
123
- def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None:
124
- self.__original = original or trio.CancelScope(**kwargs)
125
-
126
- def __enter__(self) -> CancelScope:
127
- self.__original.__enter__()
128
- return self
129
-
130
- def __exit__(
131
- self,
132
- exc_type: type[BaseException] | None,
133
- exc_val: BaseException | None,
134
- exc_tb: TracebackType | None,
135
- ) -> bool:
136
- return self.__original.__exit__(exc_type, exc_val, exc_tb)
137
-
138
- def cancel(self, reason: str | None = None) -> None:
139
- self.__original.cancel(reason)
140
-
141
- @property
142
- def deadline(self) -> float:
143
- return self.__original.deadline
144
-
145
- @deadline.setter
146
- def deadline(self, value: float) -> None:
147
- self.__original.deadline = value
148
-
149
- @property
150
- def cancel_called(self) -> bool:
151
- return self.__original.cancel_called
152
-
153
- @property
154
- def cancelled_caught(self) -> bool:
155
- return self.__original.cancelled_caught
156
-
157
- @property
158
- def shield(self) -> bool:
159
- return self.__original.shield
160
-
161
- @shield.setter
162
- def shield(self, value: bool) -> None:
163
- self.__original.shield = value
164
-
165
-
166
- #
167
- # Task groups
168
- #
169
-
170
-
171
- class TaskGroup(abc.TaskGroup):
172
- def __init__(self) -> None:
173
- self._active = False
174
- self._nursery_manager = trio.open_nursery(strict_exception_groups=True)
175
- self.cancel_scope = None # type: ignore[assignment]
176
-
177
- async def __aenter__(self) -> TaskGroup:
178
- self._active = True
179
- self._nursery = await self._nursery_manager.__aenter__()
180
- self.cancel_scope = CancelScope(self._nursery.cancel_scope)
181
- return self
182
-
183
- async def __aexit__(
184
- self,
185
- exc_type: type[BaseException] | None,
186
- exc_val: BaseException | None,
187
- exc_tb: TracebackType | None,
188
- ) -> bool:
189
- try:
190
- # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type
191
- return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) # type: ignore[return-value]
192
- except BaseExceptionGroup as exc:
193
- if not exc.split(trio.Cancelled)[1]:
194
- raise trio.Cancelled._create() from exc
195
-
196
- raise
197
- finally:
198
- del exc_val, exc_tb
199
- self._active = False
200
-
201
- def start_soon(
202
- self,
203
- func: Callable[[Unpack[PosArgsT]], Awaitable[Any]],
204
- *args: Unpack[PosArgsT],
205
- name: object = None,
206
- ) -> None:
207
- if not self._active:
208
- raise RuntimeError(
209
- "This task group is not active; no new tasks can be started."
210
- )
211
-
212
- self._nursery.start_soon(func, *args, name=name)
213
-
214
- async def start(
215
- self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None
216
- ) -> Any:
217
- if not self._active:
218
- raise RuntimeError(
219
- "This task group is not active; no new tasks can be started."
220
- )
221
-
222
- return await self._nursery.start(func, *args, name=name)
223
-
224
-
225
- #
226
- # Subprocesses
227
- #
228
-
229
-
230
- @dataclass(eq=False)
231
- class ReceiveStreamWrapper(abc.ByteReceiveStream):
232
- _stream: trio.abc.ReceiveStream
233
-
234
- async def receive(self, max_bytes: int | None = None) -> bytes:
235
- try:
236
- data = await self._stream.receive_some(max_bytes)
237
- except trio.ClosedResourceError as exc:
238
- raise ClosedResourceError from exc.__cause__
239
- except trio.BrokenResourceError as exc:
240
- raise BrokenResourceError from exc.__cause__
241
-
242
- if data:
243
- return bytes(data)
244
- else:
245
- raise EndOfStream
246
-
247
- async def aclose(self) -> None:
248
- await self._stream.aclose()
249
-
250
-
251
- @dataclass(eq=False)
252
- class SendStreamWrapper(abc.ByteSendStream):
253
- _stream: trio.abc.SendStream
254
-
255
- async def send(self, item: bytes) -> None:
256
- try:
257
- await self._stream.send_all(item)
258
- except trio.ClosedResourceError as exc:
259
- raise ClosedResourceError from exc.__cause__
260
- except trio.BrokenResourceError as exc:
261
- raise BrokenResourceError from exc.__cause__
262
-
263
- async def aclose(self) -> None:
264
- await self._stream.aclose()
265
-
266
-
267
- @dataclass(eq=False)
268
- class Process(abc.Process):
269
- _process: trio.Process
270
- _stdin: abc.ByteSendStream | None
271
- _stdout: abc.ByteReceiveStream | None
272
- _stderr: abc.ByteReceiveStream | None
273
-
274
- async def aclose(self) -> None:
275
- with CancelScope(shield=True):
276
- if self._stdin:
277
- await self._stdin.aclose()
278
- if self._stdout:
279
- await self._stdout.aclose()
280
- if self._stderr:
281
- await self._stderr.aclose()
282
-
283
- try:
284
- await self.wait()
285
- except BaseException:
286
- self.kill()
287
- with CancelScope(shield=True):
288
- await self.wait()
289
- raise
290
-
291
- async def wait(self) -> int:
292
- return await self._process.wait()
293
-
294
- def terminate(self) -> None:
295
- self._process.terminate()
296
-
297
- def kill(self) -> None:
298
- self._process.kill()
299
-
300
- def send_signal(self, signal: Signals) -> None:
301
- self._process.send_signal(signal)
302
-
303
- @property
304
- def pid(self) -> int:
305
- return self._process.pid
306
-
307
- @property
308
- def returncode(self) -> int | None:
309
- return self._process.returncode
310
-
311
- @property
312
- def stdin(self) -> abc.ByteSendStream | None:
313
- return self._stdin
314
-
315
- @property
316
- def stdout(self) -> abc.ByteReceiveStream | None:
317
- return self._stdout
318
-
319
- @property
320
- def stderr(self) -> abc.ByteReceiveStream | None:
321
- return self._stderr
322
-
323
-
324
- class _ProcessPoolShutdownInstrument(trio.abc.Instrument):
325
- def after_run(self) -> None:
326
- super().after_run()
327
-
328
-
329
- current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar(
330
- "current_default_worker_process_limiter"
331
- )
332
-
333
-
334
- async def _shutdown_process_pool(workers: set[abc.Process]) -> None:
335
- try:
336
- await trio.sleep(math.inf)
337
- except trio.Cancelled:
338
- for process in workers:
339
- if process.returncode is None:
340
- process.kill()
341
-
342
- with CancelScope(shield=True):
343
- for process in workers:
344
- await process.aclose()
345
-
346
-
347
- #
348
- # Sockets and networking
349
- #
350
-
351
-
352
- class _TrioSocketMixin(Generic[T_SockAddr]):
353
- def __init__(self, trio_socket: TrioSocketType) -> None:
354
- self._trio_socket = trio_socket
355
- self._closed = False
356
-
357
- def _check_closed(self) -> None:
358
- if self._closed:
359
- raise ClosedResourceError
360
- if self._trio_socket.fileno() < 0:
361
- raise BrokenResourceError
362
-
363
- @property
364
- def _raw_socket(self) -> socket.socket:
365
- return self._trio_socket._sock # type: ignore[attr-defined]
366
-
367
- async def aclose(self) -> None:
368
- if self._trio_socket.fileno() >= 0:
369
- self._closed = True
370
- self._trio_socket.close()
371
-
372
- def _convert_socket_error(self, exc: BaseException) -> NoReturn:
373
- if isinstance(exc, trio.ClosedResourceError):
374
- raise ClosedResourceError from exc
375
- elif self._trio_socket.fileno() < 0 and self._closed:
376
- raise ClosedResourceError from None
377
- elif isinstance(exc, OSError):
378
- raise BrokenResourceError from exc
379
- else:
380
- raise exc
381
-
382
-
383
- class SocketStream(_TrioSocketMixin, abc.SocketStream):
384
- def __init__(self, trio_socket: TrioSocketType) -> None:
385
- super().__init__(trio_socket)
386
- self._receive_guard = ResourceGuard("reading from")
387
- self._send_guard = ResourceGuard("writing to")
388
-
389
- async def receive(self, max_bytes: int = 65536) -> bytes:
390
- with self._receive_guard:
391
- try:
392
- data = await self._trio_socket.recv(max_bytes)
393
- except BaseException as exc:
394
- self._convert_socket_error(exc)
395
-
396
- if data:
397
- return data
398
- else:
399
- raise EndOfStream
400
-
401
- async def send(self, item: bytes) -> None:
402
- with self._send_guard:
403
- view = memoryview(item)
404
- while view:
405
- try:
406
- bytes_sent = await self._trio_socket.send(view)
407
- except BaseException as exc:
408
- self._convert_socket_error(exc)
409
-
410
- view = view[bytes_sent:]
411
-
412
- async def send_eof(self) -> None:
413
- self._trio_socket.shutdown(socket.SHUT_WR)
414
-
415
-
416
- class UNIXSocketStream(SocketStream, abc.UNIXSocketStream):
417
- async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
418
- if not isinstance(msglen, int) or msglen < 0:
419
- raise ValueError("msglen must be a non-negative integer")
420
- if not isinstance(maxfds, int) or maxfds < 1:
421
- raise ValueError("maxfds must be a positive integer")
422
-
423
- fds = array.array("i")
424
- await trio.lowlevel.checkpoint()
425
- with self._receive_guard:
426
- while True:
427
- try:
428
- message, ancdata, flags, addr = await self._trio_socket.recvmsg(
429
- msglen, socket.CMSG_LEN(maxfds * fds.itemsize)
430
- )
431
- except BaseException as exc:
432
- self._convert_socket_error(exc)
433
- else:
434
- if not message and not ancdata:
435
- raise EndOfStream
436
-
437
- break
438
-
439
- for cmsg_level, cmsg_type, cmsg_data in ancdata:
440
- if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS:
441
- raise RuntimeError(
442
- f"Received unexpected ancillary data; message = {message!r}, "
443
- f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}"
444
- )
445
-
446
- fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
447
-
448
- return message, list(fds)
449
-
450
- async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
451
- if not message:
452
- raise ValueError("message must not be empty")
453
- if not fds:
454
- raise ValueError("fds must not be empty")
455
-
456
- filenos: list[int] = []
457
- for fd in fds:
458
- if isinstance(fd, int):
459
- filenos.append(fd)
460
- elif isinstance(fd, IOBase):
461
- filenos.append(fd.fileno())
462
-
463
- fdarray = array.array("i", filenos)
464
- await trio.lowlevel.checkpoint()
465
- with self._send_guard:
466
- while True:
467
- try:
468
- await self._trio_socket.sendmsg(
469
- [message],
470
- [
471
- (
472
- socket.SOL_SOCKET,
473
- socket.SCM_RIGHTS,
474
- fdarray,
475
- )
476
- ],
477
- )
478
- break
479
- except BaseException as exc:
480
- self._convert_socket_error(exc)
481
-
482
-
483
- class TCPSocketListener(_TrioSocketMixin, abc.SocketListener):
484
- def __init__(self, raw_socket: socket.socket):
485
- super().__init__(trio.socket.from_stdlib_socket(raw_socket))
486
- self._accept_guard = ResourceGuard("accepting connections from")
487
-
488
- async def accept(self) -> SocketStream:
489
- with self._accept_guard:
490
- try:
491
- trio_socket, _addr = await self._trio_socket.accept()
492
- except BaseException as exc:
493
- self._convert_socket_error(exc)
494
-
495
- trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
496
- return SocketStream(trio_socket)
497
-
498
-
499
- class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener):
500
- def __init__(self, raw_socket: socket.socket):
501
- super().__init__(trio.socket.from_stdlib_socket(raw_socket))
502
- self._accept_guard = ResourceGuard("accepting connections from")
503
-
504
- async def accept(self) -> UNIXSocketStream:
505
- with self._accept_guard:
506
- try:
507
- trio_socket, _addr = await self._trio_socket.accept()
508
- except BaseException as exc:
509
- self._convert_socket_error(exc)
510
-
511
- return UNIXSocketStream(trio_socket)
512
-
513
-
514
- class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket):
515
- def __init__(self, trio_socket: TrioSocketType) -> None:
516
- super().__init__(trio_socket)
517
- self._receive_guard = ResourceGuard("reading from")
518
- self._send_guard = ResourceGuard("writing to")
519
-
520
- async def receive(self) -> tuple[bytes, IPSockAddrType]:
521
- with self._receive_guard:
522
- try:
523
- data, addr = await self._trio_socket.recvfrom(65536)
524
- return data, convert_ipv6_sockaddr(addr)
525
- except BaseException as exc:
526
- self._convert_socket_error(exc)
527
-
528
- async def send(self, item: UDPPacketType) -> None:
529
- with self._send_guard:
530
- try:
531
- await self._trio_socket.sendto(*item)
532
- except BaseException as exc:
533
- self._convert_socket_error(exc)
534
-
535
-
536
- class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket):
537
- def __init__(self, trio_socket: TrioSocketType) -> None:
538
- super().__init__(trio_socket)
539
- self._receive_guard = ResourceGuard("reading from")
540
- self._send_guard = ResourceGuard("writing to")
541
-
542
- async def receive(self) -> bytes:
543
- with self._receive_guard:
544
- try:
545
- return await self._trio_socket.recv(65536)
546
- except BaseException as exc:
547
- self._convert_socket_error(exc)
548
-
549
- async def send(self, item: bytes) -> None:
550
- with self._send_guard:
551
- try:
552
- await self._trio_socket.send(item)
553
- except BaseException as exc:
554
- self._convert_socket_error(exc)
555
-
556
-
557
- class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket):
558
- def __init__(self, trio_socket: TrioSocketType) -> None:
559
- super().__init__(trio_socket)
560
- self._receive_guard = ResourceGuard("reading from")
561
- self._send_guard = ResourceGuard("writing to")
562
-
563
- async def receive(self) -> UNIXDatagramPacketType:
564
- with self._receive_guard:
565
- try:
566
- data, addr = await self._trio_socket.recvfrom(65536)
567
- return data, addr
568
- except BaseException as exc:
569
- self._convert_socket_error(exc)
570
-
571
- async def send(self, item: UNIXDatagramPacketType) -> None:
572
- with self._send_guard:
573
- try:
574
- await self._trio_socket.sendto(*item)
575
- except BaseException as exc:
576
- self._convert_socket_error(exc)
577
-
578
-
579
- class ConnectedUNIXDatagramSocket(
580
- _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket
581
- ):
582
- def __init__(self, trio_socket: TrioSocketType) -> None:
583
- super().__init__(trio_socket)
584
- self._receive_guard = ResourceGuard("reading from")
585
- self._send_guard = ResourceGuard("writing to")
586
-
587
- async def receive(self) -> bytes:
588
- with self._receive_guard:
589
- try:
590
- return await self._trio_socket.recv(65536)
591
- except BaseException as exc:
592
- self._convert_socket_error(exc)
593
-
594
- async def send(self, item: bytes) -> None:
595
- with self._send_guard:
596
- try:
597
- await self._trio_socket.send(item)
598
- except BaseException as exc:
599
- self._convert_socket_error(exc)
600
-
601
-
602
- #
603
- # Synchronization
604
- #
605
-
606
-
607
- class Event(BaseEvent):
608
- def __new__(cls) -> Event:
609
- return object.__new__(cls)
610
-
611
- def __init__(self) -> None:
612
- self.__original = trio.Event()
613
-
614
- def is_set(self) -> bool:
615
- return self.__original.is_set()
616
-
617
- async def wait(self) -> None:
618
- return await self.__original.wait()
619
-
620
- def statistics(self) -> EventStatistics:
621
- orig_statistics = self.__original.statistics()
622
- return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting)
623
-
624
- def set(self) -> None:
625
- self.__original.set()
626
-
627
-
628
- class Lock(BaseLock):
629
- def __new__(cls, *, fast_acquire: bool = False) -> Lock:
630
- return object.__new__(cls)
631
-
632
- def __init__(self, *, fast_acquire: bool = False) -> None:
633
- self._fast_acquire = fast_acquire
634
- self.__original = trio.Lock()
635
-
636
- @staticmethod
637
- def _convert_runtime_error_msg(exc: RuntimeError) -> None:
638
- if exc.args == ("attempt to re-acquire an already held Lock",):
639
- exc.args = ("Attempted to acquire an already held Lock",)
640
-
641
- async def acquire(self) -> None:
642
- if not self._fast_acquire:
643
- try:
644
- await self.__original.acquire()
645
- except RuntimeError as exc:
646
- self._convert_runtime_error_msg(exc)
647
- raise
648
-
649
- return
650
-
651
- # This is the "fast path" where we don't let other tasks run
652
- await trio.lowlevel.checkpoint_if_cancelled()
653
- try:
654
- self.__original.acquire_nowait()
655
- except trio.WouldBlock:
656
- await self.__original._lot.park()
657
- except RuntimeError as exc:
658
- self._convert_runtime_error_msg(exc)
659
- raise
660
-
661
- def acquire_nowait(self) -> None:
662
- try:
663
- self.__original.acquire_nowait()
664
- except trio.WouldBlock:
665
- raise WouldBlock from None
666
- except RuntimeError as exc:
667
- self._convert_runtime_error_msg(exc)
668
- raise
669
-
670
- def locked(self) -> bool:
671
- return self.__original.locked()
672
-
673
- def release(self) -> None:
674
- self.__original.release()
675
-
676
- def statistics(self) -> LockStatistics:
677
- orig_statistics = self.__original.statistics()
678
- owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None
679
- return LockStatistics(
680
- orig_statistics.locked, owner, orig_statistics.tasks_waiting
681
- )
682
-
683
-
684
- class Semaphore(BaseSemaphore):
685
- def __new__(
686
- cls,
687
- initial_value: int,
688
- *,
689
- max_value: int | None = None,
690
- fast_acquire: bool = False,
691
- ) -> Semaphore:
692
- return object.__new__(cls)
693
-
694
- def __init__(
695
- self,
696
- initial_value: int,
697
- *,
698
- max_value: int | None = None,
699
- fast_acquire: bool = False,
700
- ) -> None:
701
- super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
702
- self.__original = trio.Semaphore(initial_value, max_value=max_value)
703
-
704
- async def acquire(self) -> None:
705
- if not self._fast_acquire:
706
- await self.__original.acquire()
707
- return
708
-
709
- # This is the "fast path" where we don't let other tasks run
710
- await trio.lowlevel.checkpoint_if_cancelled()
711
- try:
712
- self.__original.acquire_nowait()
713
- except trio.WouldBlock:
714
- await self.__original._lot.park()
715
-
716
- def acquire_nowait(self) -> None:
717
- try:
718
- self.__original.acquire_nowait()
719
- except trio.WouldBlock:
720
- raise WouldBlock from None
721
-
722
- @property
723
- def max_value(self) -> int | None:
724
- return self.__original.max_value
725
-
726
- @property
727
- def value(self) -> int:
728
- return self.__original.value
729
-
730
- def release(self) -> None:
731
- self.__original.release()
732
-
733
- def statistics(self) -> SemaphoreStatistics:
734
- orig_statistics = self.__original.statistics()
735
- return SemaphoreStatistics(orig_statistics.tasks_waiting)
736
-
737
-
738
- class CapacityLimiter(BaseCapacityLimiter):
739
- def __new__(
740
- cls,
741
- total_tokens: float | None = None,
742
- *,
743
- original: trio.CapacityLimiter | None = None,
744
- ) -> CapacityLimiter:
745
- return object.__new__(cls)
746
-
747
- def __init__(
748
- self,
749
- total_tokens: float | None = None,
750
- *,
751
- original: trio.CapacityLimiter | None = None,
752
- ) -> None:
753
- if original is not None:
754
- self.__original = original
755
- else:
756
- assert total_tokens is not None
757
- self.__original = trio.CapacityLimiter(total_tokens)
758
-
759
- async def __aenter__(self) -> None:
760
- return await self.__original.__aenter__()
761
-
762
- async def __aexit__(
763
- self,
764
- exc_type: type[BaseException] | None,
765
- exc_val: BaseException | None,
766
- exc_tb: TracebackType | None,
767
- ) -> None:
768
- await self.__original.__aexit__(exc_type, exc_val, exc_tb)
769
-
770
- @property
771
- def total_tokens(self) -> float:
772
- return self.__original.total_tokens
773
-
774
- @total_tokens.setter
775
- def total_tokens(self, value: float) -> None:
776
- self.__original.total_tokens = value
777
-
778
- @property
779
- def borrowed_tokens(self) -> int:
780
- return self.__original.borrowed_tokens
781
-
782
- @property
783
- def available_tokens(self) -> float:
784
- return self.__original.available_tokens
785
-
786
- def acquire_nowait(self) -> None:
787
- self.__original.acquire_nowait()
788
-
789
- def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
790
- self.__original.acquire_on_behalf_of_nowait(borrower)
791
-
792
- async def acquire(self) -> None:
793
- await self.__original.acquire()
794
-
795
- async def acquire_on_behalf_of(self, borrower: object) -> None:
796
- await self.__original.acquire_on_behalf_of(borrower)
797
-
798
- def release(self) -> None:
799
- return self.__original.release()
800
-
801
- def release_on_behalf_of(self, borrower: object) -> None:
802
- return self.__original.release_on_behalf_of(borrower)
803
-
804
- def statistics(self) -> CapacityLimiterStatistics:
805
- orig = self.__original.statistics()
806
- return CapacityLimiterStatistics(
807
- borrowed_tokens=orig.borrowed_tokens,
808
- total_tokens=orig.total_tokens,
809
- borrowers=tuple(orig.borrowers),
810
- tasks_waiting=orig.tasks_waiting,
811
- )
812
-
813
-
814
- _capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper")
815
-
816
-
817
- #
818
- # Signal handling
819
- #
820
-
821
-
822
- class _SignalReceiver:
823
- _iterator: AsyncIterator[int]
824
-
825
- def __init__(self, signals: tuple[Signals, ...]):
826
- self._signals = signals
827
-
828
- def __enter__(self) -> _SignalReceiver:
829
- self._cm = trio.open_signal_receiver(*self._signals)
830
- self._iterator = self._cm.__enter__()
831
- return self
832
-
833
- def __exit__(
834
- self,
835
- exc_type: type[BaseException] | None,
836
- exc_val: BaseException | None,
837
- exc_tb: TracebackType | None,
838
- ) -> bool | None:
839
- return self._cm.__exit__(exc_type, exc_val, exc_tb)
840
-
841
- def __aiter__(self) -> _SignalReceiver:
842
- return self
843
-
844
- async def __anext__(self) -> Signals:
845
- signum = await self._iterator.__anext__()
846
- return Signals(signum)
847
-
848
-
849
- #
850
- # Testing and debugging
851
- #
852
-
853
-
854
- class TestRunner(abc.TestRunner):
855
- def __init__(self, **options: Any) -> None:
856
- from queue import Queue
857
-
858
- self._call_queue: Queue[Callable[[], object]] = Queue()
859
- self._send_stream: MemoryObjectSendStream | None = None
860
- self._options = options
861
-
862
- def __exit__(
863
- self,
864
- exc_type: type[BaseException] | None,
865
- exc_val: BaseException | None,
866
- exc_tb: types.TracebackType | None,
867
- ) -> None:
868
- if self._send_stream:
869
- self._send_stream.close()
870
- while self._send_stream is not None:
871
- self._call_queue.get()()
872
-
873
- async def _run_tests_and_fixtures(self) -> None:
874
- self._send_stream, receive_stream = create_memory_object_stream(1)
875
- with receive_stream:
876
- async for coro, outcome_holder in receive_stream:
877
- try:
878
- retval = await coro
879
- except BaseException as exc:
880
- outcome_holder.append(Error(exc))
881
- else:
882
- outcome_holder.append(Value(retval))
883
-
884
- def _main_task_finished(self, outcome: object) -> None:
885
- self._send_stream = None
886
-
887
- def _call_in_runner_task(
888
- self,
889
- func: Callable[P, Awaitable[T_Retval]],
890
- *args: P.args,
891
- **kwargs: P.kwargs,
892
- ) -> T_Retval:
893
- if self._send_stream is None:
894
- trio.lowlevel.start_guest_run(
895
- self._run_tests_and_fixtures,
896
- run_sync_soon_threadsafe=self._call_queue.put,
897
- done_callback=self._main_task_finished,
898
- **self._options,
899
- )
900
- while self._send_stream is None:
901
- self._call_queue.get()()
902
-
903
- outcome_holder: list[Outcome] = []
904
- self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder))
905
- while not outcome_holder:
906
- self._call_queue.get()()
907
-
908
- return outcome_holder[0].unwrap()
909
-
910
- def run_asyncgen_fixture(
911
- self,
912
- fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]],
913
- kwargs: dict[str, Any],
914
- ) -> Iterable[T_Retval]:
915
- asyncgen = fixture_func(**kwargs)
916
- fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None)
917
-
918
- yield fixturevalue
919
-
920
- try:
921
- self._call_in_runner_task(asyncgen.asend, None)
922
- except StopAsyncIteration:
923
- pass
924
- else:
925
- self._call_in_runner_task(asyncgen.aclose)
926
- raise RuntimeError("Async generator fixture did not stop")
927
-
928
- def run_fixture(
929
- self,
930
- fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]],
931
- kwargs: dict[str, Any],
932
- ) -> T_Retval:
933
- return self._call_in_runner_task(fixture_func, **kwargs)
934
-
935
- def run_test(
936
- self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
937
- ) -> None:
938
- self._call_in_runner_task(test_func, **kwargs)
939
-
940
-
941
- class TrioTaskInfo(TaskInfo):
942
- def __init__(self, task: trio.lowlevel.Task):
943
- parent_id = None
944
- if task.parent_nursery and task.parent_nursery.parent_task:
945
- parent_id = id(task.parent_nursery.parent_task)
946
-
947
- super().__init__(id(task), parent_id, task.name, task.coro)
948
- self._task = weakref.proxy(task)
949
-
950
- def has_pending_cancellation(self) -> bool:
951
- try:
952
- return self._task._cancel_status.effectively_cancelled
953
- except ReferenceError:
954
- # If the task is no longer around, it surely doesn't have a cancellation
955
- # pending
956
- return False
957
-
958
-
959
- class TrioBackend(AsyncBackend):
960
- @classmethod
961
- def run(
962
- cls,
963
- func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
964
- args: tuple[Unpack[PosArgsT]],
965
- kwargs: dict[str, Any],
966
- options: dict[str, Any],
967
- ) -> T_Retval:
968
- return trio.run(func, *args)
969
-
970
- @classmethod
971
- def current_token(cls) -> object:
972
- return trio.lowlevel.current_trio_token()
973
-
974
- @classmethod
975
- def current_time(cls) -> float:
976
- return trio.current_time()
977
-
978
- @classmethod
979
- def cancelled_exception_class(cls) -> type[BaseException]:
980
- return trio.Cancelled
981
-
982
- @classmethod
983
- async def checkpoint(cls) -> None:
984
- await trio.lowlevel.checkpoint()
985
-
986
- @classmethod
987
- async def checkpoint_if_cancelled(cls) -> None:
988
- await trio.lowlevel.checkpoint_if_cancelled()
989
-
990
- @classmethod
991
- async def cancel_shielded_checkpoint(cls) -> None:
992
- await trio.lowlevel.cancel_shielded_checkpoint()
993
-
994
- @classmethod
995
- async def sleep(cls, delay: float) -> None:
996
- await trio.sleep(delay)
997
-
998
- @classmethod
999
- def create_cancel_scope(
1000
- cls, *, deadline: float = math.inf, shield: bool = False
1001
- ) -> abc.CancelScope:
1002
- return CancelScope(deadline=deadline, shield=shield)
1003
-
1004
- @classmethod
1005
- def current_effective_deadline(cls) -> float:
1006
- return trio.current_effective_deadline()
1007
-
1008
- @classmethod
1009
- def create_task_group(cls) -> abc.TaskGroup:
1010
- return TaskGroup()
1011
-
1012
- @classmethod
1013
- def create_event(cls) -> abc.Event:
1014
- return Event()
1015
-
1016
- @classmethod
1017
- def create_lock(cls, *, fast_acquire: bool) -> Lock:
1018
- return Lock(fast_acquire=fast_acquire)
1019
-
1020
- @classmethod
1021
- def create_semaphore(
1022
- cls,
1023
- initial_value: int,
1024
- *,
1025
- max_value: int | None = None,
1026
- fast_acquire: bool = False,
1027
- ) -> abc.Semaphore:
1028
- return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire)
1029
-
1030
- @classmethod
1031
- def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
1032
- return CapacityLimiter(total_tokens)
1033
-
1034
- @classmethod
1035
- async def run_sync_in_worker_thread(
1036
- cls,
1037
- func: Callable[[Unpack[PosArgsT]], T_Retval],
1038
- args: tuple[Unpack[PosArgsT]],
1039
- abandon_on_cancel: bool = False,
1040
- limiter: abc.CapacityLimiter | None = None,
1041
- ) -> T_Retval:
1042
- def wrapper() -> T_Retval:
1043
- with claim_worker_thread(TrioBackend, token):
1044
- return func(*args)
1045
-
1046
- token = TrioBackend.current_token()
1047
- return await run_sync(
1048
- wrapper,
1049
- abandon_on_cancel=abandon_on_cancel,
1050
- limiter=cast(trio.CapacityLimiter, limiter),
1051
- )
1052
-
1053
- @classmethod
1054
- def check_cancelled(cls) -> None:
1055
- trio.from_thread.check_cancelled()
1056
-
1057
- @classmethod
1058
- def run_async_from_thread(
1059
- cls,
1060
- func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
1061
- args: tuple[Unpack[PosArgsT]],
1062
- token: object,
1063
- ) -> T_Retval:
1064
- trio_token = cast("trio.lowlevel.TrioToken | None", token)
1065
- try:
1066
- return trio.from_thread.run(func, *args, trio_token=trio_token)
1067
- except trio.RunFinishedError:
1068
- raise RunFinishedError from None
1069
-
1070
- @classmethod
1071
- def run_sync_from_thread(
1072
- cls,
1073
- func: Callable[[Unpack[PosArgsT]], T_Retval],
1074
- args: tuple[Unpack[PosArgsT]],
1075
- token: object,
1076
- ) -> T_Retval:
1077
- trio_token = cast("trio.lowlevel.TrioToken | None", token)
1078
- try:
1079
- return trio.from_thread.run_sync(func, *args, trio_token=trio_token)
1080
- except trio.RunFinishedError:
1081
- raise RunFinishedError from None
1082
-
1083
- @classmethod
1084
- async def open_process(
1085
- cls,
1086
- command: StrOrBytesPath | Sequence[StrOrBytesPath],
1087
- *,
1088
- stdin: int | IO[Any] | None,
1089
- stdout: int | IO[Any] | None,
1090
- stderr: int | IO[Any] | None,
1091
- **kwargs: Any,
1092
- ) -> Process:
1093
- def convert_item(item: StrOrBytesPath) -> str:
1094
- str_or_bytes = os.fspath(item)
1095
- if isinstance(str_or_bytes, str):
1096
- return str_or_bytes
1097
- else:
1098
- return os.fsdecode(str_or_bytes)
1099
-
1100
- if isinstance(command, (str, bytes, PathLike)):
1101
- process = await trio.lowlevel.open_process(
1102
- convert_item(command),
1103
- stdin=stdin,
1104
- stdout=stdout,
1105
- stderr=stderr,
1106
- shell=True,
1107
- **kwargs,
1108
- )
1109
- else:
1110
- process = await trio.lowlevel.open_process(
1111
- [convert_item(item) for item in command],
1112
- stdin=stdin,
1113
- stdout=stdout,
1114
- stderr=stderr,
1115
- shell=False,
1116
- **kwargs,
1117
- )
1118
-
1119
- stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None
1120
- stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None
1121
- stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None
1122
- return Process(process, stdin_stream, stdout_stream, stderr_stream)
1123
-
1124
- @classmethod
1125
- def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None:
1126
- trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers)
1127
-
1128
- @classmethod
1129
- async def connect_tcp(
1130
- cls, host: str, port: int, local_address: IPSockAddrType | None = None
1131
- ) -> SocketStream:
1132
- family = socket.AF_INET6 if ":" in host else socket.AF_INET
1133
- trio_socket = trio.socket.socket(family)
1134
- trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
1135
- if local_address:
1136
- await trio_socket.bind(local_address)
1137
-
1138
- try:
1139
- await trio_socket.connect((host, port))
1140
- except BaseException:
1141
- trio_socket.close()
1142
- raise
1143
-
1144
- return SocketStream(trio_socket)
1145
-
1146
- @classmethod
1147
- async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream:
1148
- trio_socket = trio.socket.socket(socket.AF_UNIX)
1149
- try:
1150
- await trio_socket.connect(path)
1151
- except BaseException:
1152
- trio_socket.close()
1153
- raise
1154
-
1155
- return UNIXSocketStream(trio_socket)
1156
-
1157
- @classmethod
1158
- def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener:
1159
- return TCPSocketListener(sock)
1160
-
1161
- @classmethod
1162
- def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener:
1163
- return UNIXSocketListener(sock)
1164
-
1165
- @classmethod
1166
- async def create_udp_socket(
1167
- cls,
1168
- family: socket.AddressFamily,
1169
- local_address: IPSockAddrType | None,
1170
- remote_address: IPSockAddrType | None,
1171
- reuse_port: bool,
1172
- ) -> UDPSocket | ConnectedUDPSocket:
1173
- trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM)
1174
-
1175
- if reuse_port:
1176
- trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
1177
-
1178
- if local_address:
1179
- await trio_socket.bind(local_address)
1180
-
1181
- if remote_address:
1182
- await trio_socket.connect(remote_address)
1183
- return ConnectedUDPSocket(trio_socket)
1184
- else:
1185
- return UDPSocket(trio_socket)
1186
-
1187
- @classmethod
1188
- @overload
1189
- async def create_unix_datagram_socket(
1190
- cls, raw_socket: socket.socket, remote_path: None
1191
- ) -> abc.UNIXDatagramSocket: ...
1192
-
1193
- @classmethod
1194
- @overload
1195
- async def create_unix_datagram_socket(
1196
- cls, raw_socket: socket.socket, remote_path: str | bytes
1197
- ) -> abc.ConnectedUNIXDatagramSocket: ...
1198
-
1199
- @classmethod
1200
- async def create_unix_datagram_socket(
1201
- cls, raw_socket: socket.socket, remote_path: str | bytes | None
1202
- ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket:
1203
- trio_socket = trio.socket.from_stdlib_socket(raw_socket)
1204
-
1205
- if remote_path:
1206
- await trio_socket.connect(remote_path)
1207
- return ConnectedUNIXDatagramSocket(trio_socket)
1208
- else:
1209
- return UNIXDatagramSocket(trio_socket)
1210
-
1211
- @classmethod
1212
- async def getaddrinfo(
1213
- cls,
1214
- host: bytes | str | None,
1215
- port: str | int | None,
1216
- *,
1217
- family: int | AddressFamily = 0,
1218
- type: int | SocketKind = 0,
1219
- proto: int = 0,
1220
- flags: int = 0,
1221
- ) -> Sequence[
1222
- tuple[
1223
- AddressFamily,
1224
- SocketKind,
1225
- int,
1226
- str,
1227
- tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
1228
- ]
1229
- ]:
1230
- return await trio.socket.getaddrinfo(host, port, family, type, proto, flags)
1231
-
1232
- @classmethod
1233
- async def getnameinfo(
1234
- cls, sockaddr: IPSockAddrType, flags: int = 0
1235
- ) -> tuple[str, str]:
1236
- return await trio.socket.getnameinfo(sockaddr, flags)
1237
-
1238
- @classmethod
1239
- async def wait_readable(cls, obj: FileDescriptorLike) -> None:
1240
- try:
1241
- await wait_readable(obj)
1242
- except trio.ClosedResourceError as exc:
1243
- raise ClosedResourceError().with_traceback(exc.__traceback__) from None
1244
- except trio.BusyResourceError:
1245
- raise BusyResourceError("reading from") from None
1246
-
1247
- @classmethod
1248
- async def wait_writable(cls, obj: FileDescriptorLike) -> None:
1249
- try:
1250
- await wait_writable(obj)
1251
- except trio.ClosedResourceError as exc:
1252
- raise ClosedResourceError().with_traceback(exc.__traceback__) from None
1253
- except trio.BusyResourceError:
1254
- raise BusyResourceError("writing to") from None
1255
-
1256
- @classmethod
1257
- def notify_closing(cls, obj: FileDescriptorLike) -> None:
1258
- notify_closing(obj)
1259
-
1260
- @classmethod
1261
- async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener:
1262
- return TCPSocketListener(sock)
1263
-
1264
- @classmethod
1265
- async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream:
1266
- trio_sock = trio.socket.from_stdlib_socket(sock)
1267
- return SocketStream(trio_sock)
1268
-
1269
- @classmethod
1270
- async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream:
1271
- trio_sock = trio.socket.from_stdlib_socket(sock)
1272
- return UNIXSocketStream(trio_sock)
1273
-
1274
- @classmethod
1275
- async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket:
1276
- trio_sock = trio.socket.from_stdlib_socket(sock)
1277
- return UDPSocket(trio_sock)
1278
-
1279
- @classmethod
1280
- async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket:
1281
- trio_sock = trio.socket.from_stdlib_socket(sock)
1282
- return ConnectedUDPSocket(trio_sock)
1283
-
1284
- @classmethod
1285
- async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket:
1286
- trio_sock = trio.socket.from_stdlib_socket(sock)
1287
- return UNIXDatagramSocket(trio_sock)
1288
-
1289
- @classmethod
1290
- async def wrap_connected_unix_datagram_socket(
1291
- cls, sock: socket.socket
1292
- ) -> ConnectedUNIXDatagramSocket:
1293
- trio_sock = trio.socket.from_stdlib_socket(sock)
1294
- return ConnectedUNIXDatagramSocket(trio_sock)
1295
-
1296
- @classmethod
1297
- def current_default_thread_limiter(cls) -> CapacityLimiter:
1298
- try:
1299
- return _capacity_limiter_wrapper.get()
1300
- except LookupError:
1301
- limiter = CapacityLimiter(
1302
- original=trio.to_thread.current_default_thread_limiter()
1303
- )
1304
- _capacity_limiter_wrapper.set(limiter)
1305
- return limiter
1306
-
1307
- @classmethod
1308
- def open_signal_receiver(
1309
- cls, *signals: Signals
1310
- ) -> AbstractContextManager[AsyncIterator[Signals]]:
1311
- return _SignalReceiver(signals)
1312
-
1313
- @classmethod
1314
- def get_current_task(cls) -> TaskInfo:
1315
- task = current_task()
1316
- return TrioTaskInfo(task)
1317
-
1318
- @classmethod
1319
- def get_running_tasks(cls) -> Sequence[TaskInfo]:
1320
- root_task = current_root_task()
1321
- assert root_task
1322
- task_infos = [TrioTaskInfo(root_task)]
1323
- nurseries = root_task.child_nurseries
1324
- while nurseries:
1325
- new_nurseries: list[trio.Nursery] = []
1326
- for nursery in nurseries:
1327
- for task in nursery.child_tasks:
1328
- task_infos.append(TrioTaskInfo(task))
1329
- new_nurseries.extend(task.child_nurseries)
1330
-
1331
- nurseries = new_nurseries
1332
-
1333
- return task_infos
1334
-
1335
- @classmethod
1336
- async def wait_all_tasks_blocked(cls) -> None:
1337
- from trio.testing import wait_all_tasks_blocked
1338
-
1339
- await wait_all_tasks_blocked()
1340
-
1341
- @classmethod
1342
- def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
1343
- return TestRunner(**options)
1344
-
1345
-
1346
- backend_class = TrioBackend
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/__init__.py DELETED
File without changes
venv/Lib/site-packages/anyio/_core/_asyncio_selector_thread.py DELETED
@@ -1,167 +0,0 @@
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/site-packages/anyio/_core/_contextmanagers.py DELETED
@@ -1,200 +0,0 @@
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/site-packages/anyio/_core/_eventloop.py DELETED
@@ -1,234 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import math
4
- import sys
5
- import threading
6
- from collections.abc import Awaitable, Callable, Generator
7
- from contextlib import contextmanager
8
- from contextvars import Token
9
- from importlib import import_module
10
- from typing import TYPE_CHECKING, Any, TypeVar
11
-
12
- from ._exceptions import NoEventLoopError
13
-
14
- if sys.version_info >= (3, 11):
15
- from typing import TypeVarTuple, Unpack
16
- else:
17
- from typing_extensions import TypeVarTuple, Unpack
18
-
19
- sniffio: Any
20
- try:
21
- import sniffio
22
- except ModuleNotFoundError:
23
- sniffio = None
24
-
25
- if TYPE_CHECKING:
26
- from ..abc import AsyncBackend
27
-
28
- # This must be updated when new backends are introduced
29
- BACKENDS = "asyncio", "trio"
30
-
31
- T_Retval = TypeVar("T_Retval")
32
- PosArgsT = TypeVarTuple("PosArgsT")
33
-
34
- threadlocals = threading.local()
35
- loaded_backends: dict[str, type[AsyncBackend]] = {}
36
-
37
-
38
- def run(
39
- func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
40
- *args: Unpack[PosArgsT],
41
- backend: str = "asyncio",
42
- backend_options: dict[str, Any] | None = None,
43
- ) -> T_Retval:
44
- """
45
- Run the given coroutine function in an asynchronous event loop.
46
-
47
- The current thread must not be already running an event loop.
48
-
49
- :param func: a coroutine function
50
- :param args: positional arguments to ``func``
51
- :param backend: name of the asynchronous event loop implementation – currently
52
- either ``asyncio`` or ``trio``
53
- :param backend_options: keyword arguments to call the backend ``run()``
54
- implementation with (documented :ref:`here <backend options>`)
55
- :return: the return value of the coroutine function
56
- :raises RuntimeError: if an asynchronous event loop is already running in this
57
- thread
58
- :raises LookupError: if the named backend is not found
59
-
60
- """
61
- if asynclib_name := current_async_library():
62
- raise RuntimeError(f"Already running {asynclib_name} in this thread")
63
-
64
- try:
65
- async_backend = get_async_backend(backend)
66
- except ImportError as exc:
67
- raise LookupError(f"No such backend: {backend}") from exc
68
-
69
- token = None
70
- if asynclib_name is None:
71
- # Since we're in control of the event loop, we can cache the name of the async
72
- # library
73
- token = set_current_async_library(backend)
74
-
75
- try:
76
- backend_options = backend_options or {}
77
- return async_backend.run(func, args, {}, backend_options)
78
- finally:
79
- reset_current_async_library(token)
80
-
81
-
82
- async def sleep(delay: float) -> None:
83
- """
84
- Pause the current task for the specified duration.
85
-
86
- :param delay: the duration, in seconds
87
-
88
- """
89
- return await get_async_backend().sleep(delay)
90
-
91
-
92
- async def sleep_forever() -> None:
93
- """
94
- Pause the current task until it's cancelled.
95
-
96
- This is a shortcut for ``sleep(math.inf)``.
97
-
98
- .. versionadded:: 3.1
99
-
100
- """
101
- await sleep(math.inf)
102
-
103
-
104
- async def sleep_until(deadline: float) -> None:
105
- """
106
- Pause the current task until the given time.
107
-
108
- :param deadline: the absolute time to wake up at (according to the internal
109
- monotonic clock of the event loop)
110
-
111
- .. versionadded:: 3.1
112
-
113
- """
114
- now = current_time()
115
- await sleep(max(deadline - now, 0))
116
-
117
-
118
- def current_time() -> float:
119
- """
120
- Return the current value of the event loop's internal clock.
121
-
122
- :return: the clock value (seconds)
123
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
124
- current thread
125
-
126
- """
127
- return get_async_backend().current_time()
128
-
129
-
130
- def get_all_backends() -> tuple[str, ...]:
131
- """Return a tuple of the names of all built-in backends."""
132
- return BACKENDS
133
-
134
-
135
- def get_available_backends() -> tuple[str, ...]:
136
- """
137
- Test for the availability of built-in backends.
138
-
139
- :return a tuple of the built-in backend names that were successfully imported
140
-
141
- .. versionadded:: 4.12
142
-
143
- """
144
- available_backends: list[str] = []
145
- for backend_name in get_all_backends():
146
- try:
147
- get_async_backend(backend_name)
148
- except ImportError:
149
- continue
150
-
151
- available_backends.append(backend_name)
152
-
153
- return tuple(available_backends)
154
-
155
-
156
- def get_cancelled_exc_class() -> type[BaseException]:
157
- """
158
- Return the current async library's cancellation exception class.
159
-
160
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
161
- current thread
162
-
163
- """
164
- return get_async_backend().cancelled_exception_class()
165
-
166
-
167
- #
168
- # Private API
169
- #
170
-
171
-
172
- @contextmanager
173
- def claim_worker_thread(
174
- backend_class: type[AsyncBackend], token: object
175
- ) -> Generator[Any, None, None]:
176
- from ..lowlevel import EventLoopToken
177
-
178
- threadlocals.current_token = EventLoopToken(backend_class, token)
179
- try:
180
- yield
181
- finally:
182
- del threadlocals.current_token
183
-
184
-
185
- def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]:
186
- if asynclib_name is None:
187
- asynclib_name = current_async_library()
188
- if not asynclib_name:
189
- raise NoEventLoopError(
190
- f"Not currently running on any asynchronous event loop. "
191
- f"Available async backends: {', '.join(get_all_backends())}"
192
- )
193
-
194
- # We use our own dict instead of sys.modules to get the already imported back-end
195
- # class because the appropriate modules in sys.modules could potentially be only
196
- # partially initialized
197
- try:
198
- return loaded_backends[asynclib_name]
199
- except KeyError:
200
- module = import_module(f"anyio._backends._{asynclib_name}")
201
- loaded_backends[asynclib_name] = module.backend_class
202
- return module.backend_class
203
-
204
-
205
- def current_async_library() -> str | None:
206
- if sniffio is None:
207
- # If sniffio is not installed, we assume we're either running asyncio or nothing
208
- import asyncio
209
-
210
- try:
211
- asyncio.get_running_loop()
212
- return "asyncio"
213
- except RuntimeError:
214
- pass
215
- else:
216
- try:
217
- return sniffio.current_async_library()
218
- except sniffio.AsyncLibraryNotFoundError:
219
- pass
220
-
221
- return None
222
-
223
-
224
- def set_current_async_library(asynclib_name: str | None) -> Token | None:
225
- # no-op if sniffio is not installed
226
- if sniffio is None:
227
- return None
228
-
229
- return sniffio.current_async_library_cvar.set(asynclib_name)
230
-
231
-
232
- def reset_current_async_library(token: Token | None) -> None:
233
- if token is not None:
234
- sniffio.current_async_library_cvar.reset(token)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_exceptions.py DELETED
@@ -1,156 +0,0 @@
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
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_fileio.py DELETED
@@ -1,797 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import os
4
- import pathlib
5
- import sys
6
- from collections.abc import (
7
- AsyncIterator,
8
- Callable,
9
- Iterable,
10
- Iterator,
11
- Sequence,
12
- )
13
- from dataclasses import dataclass
14
- from functools import partial
15
- from os import PathLike
16
- from typing import (
17
- IO,
18
- TYPE_CHECKING,
19
- Any,
20
- AnyStr,
21
- ClassVar,
22
- Final,
23
- Generic,
24
- overload,
25
- )
26
-
27
- from .. import to_thread
28
- from ..abc import AsyncResource
29
-
30
- if TYPE_CHECKING:
31
- from types import ModuleType
32
-
33
- from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
34
- else:
35
- ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object
36
-
37
-
38
- class AsyncFile(AsyncResource, Generic[AnyStr]):
39
- """
40
- An asynchronous file object.
41
-
42
- This class wraps a standard file object and provides async friendly versions of the
43
- following blocking methods (where available on the original file object):
44
-
45
- * read
46
- * read1
47
- * readline
48
- * readlines
49
- * readinto
50
- * readinto1
51
- * write
52
- * writelines
53
- * truncate
54
- * seek
55
- * tell
56
- * flush
57
-
58
- All other methods are directly passed through.
59
-
60
- This class supports the asynchronous context manager protocol which closes the
61
- underlying file at the end of the context block.
62
-
63
- This class also supports asynchronous iteration::
64
-
65
- async with await open_file(...) as f:
66
- async for line in f:
67
- print(line)
68
- """
69
-
70
- def __init__(self, fp: IO[AnyStr]) -> None:
71
- self._fp: Any = fp
72
-
73
- def __getattr__(self, name: str) -> object:
74
- return getattr(self._fp, name)
75
-
76
- @property
77
- def wrapped(self) -> IO[AnyStr]:
78
- """The wrapped file object."""
79
- return self._fp
80
-
81
- async def __aiter__(self) -> AsyncIterator[AnyStr]:
82
- while True:
83
- line = await self.readline()
84
- if line:
85
- yield line
86
- else:
87
- break
88
-
89
- async def aclose(self) -> None:
90
- return await to_thread.run_sync(self._fp.close)
91
-
92
- async def read(self, size: int = -1) -> AnyStr:
93
- return await to_thread.run_sync(self._fp.read, size)
94
-
95
- async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes:
96
- return await to_thread.run_sync(self._fp.read1, size)
97
-
98
- async def readline(self) -> AnyStr:
99
- return await to_thread.run_sync(self._fp.readline)
100
-
101
- async def readlines(self) -> list[AnyStr]:
102
- return await to_thread.run_sync(self._fp.readlines)
103
-
104
- async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
105
- return await to_thread.run_sync(self._fp.readinto, b)
106
-
107
- async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
108
- return await to_thread.run_sync(self._fp.readinto1, b)
109
-
110
- @overload
111
- async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ...
112
-
113
- @overload
114
- async def write(self: AsyncFile[str], b: str) -> int: ...
115
-
116
- async def write(self, b: ReadableBuffer | str) -> int:
117
- return await to_thread.run_sync(self._fp.write, b)
118
-
119
- @overload
120
- async def writelines(
121
- self: AsyncFile[bytes], lines: Iterable[ReadableBuffer]
122
- ) -> None: ...
123
-
124
- @overload
125
- async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ...
126
-
127
- async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None:
128
- return await to_thread.run_sync(self._fp.writelines, lines)
129
-
130
- async def truncate(self, size: int | None = None) -> int:
131
- return await to_thread.run_sync(self._fp.truncate, size)
132
-
133
- async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
134
- return await to_thread.run_sync(self._fp.seek, offset, whence)
135
-
136
- async def tell(self) -> int:
137
- return await to_thread.run_sync(self._fp.tell)
138
-
139
- async def flush(self) -> None:
140
- return await to_thread.run_sync(self._fp.flush)
141
-
142
-
143
- @overload
144
- async def open_file(
145
- file: str | PathLike[str] | int,
146
- mode: OpenBinaryMode,
147
- buffering: int = ...,
148
- encoding: str | None = ...,
149
- errors: str | None = ...,
150
- newline: str | None = ...,
151
- closefd: bool = ...,
152
- opener: Callable[[str, int], int] | None = ...,
153
- ) -> AsyncFile[bytes]: ...
154
-
155
-
156
- @overload
157
- async def open_file(
158
- file: str | PathLike[str] | int,
159
- mode: OpenTextMode = ...,
160
- buffering: int = ...,
161
- encoding: str | None = ...,
162
- errors: str | None = ...,
163
- newline: str | None = ...,
164
- closefd: bool = ...,
165
- opener: Callable[[str, int], int] | None = ...,
166
- ) -> AsyncFile[str]: ...
167
-
168
-
169
- async def open_file(
170
- file: str | PathLike[str] | int,
171
- mode: str = "r",
172
- buffering: int = -1,
173
- encoding: str | None = None,
174
- errors: str | None = None,
175
- newline: str | None = None,
176
- closefd: bool = True,
177
- opener: Callable[[str, int], int] | None = None,
178
- ) -> AsyncFile[Any]:
179
- """
180
- Open a file asynchronously.
181
-
182
- The arguments are exactly the same as for the builtin :func:`open`.
183
-
184
- :return: an asynchronous file object
185
-
186
- """
187
- fp = await to_thread.run_sync(
188
- open, file, mode, buffering, encoding, errors, newline, closefd, opener
189
- )
190
- return AsyncFile(fp)
191
-
192
-
193
- def wrap_file(file: IO[AnyStr]) -> AsyncFile[AnyStr]:
194
- """
195
- Wrap an existing file as an asynchronous file.
196
-
197
- :param file: an existing file-like object
198
- :return: an asynchronous file object
199
-
200
- """
201
- return AsyncFile(file)
202
-
203
-
204
- @dataclass(eq=False)
205
- class _PathIterator(AsyncIterator["Path"]):
206
- iterator: Iterator[PathLike[str]]
207
-
208
- async def __anext__(self) -> Path:
209
- nextval = await to_thread.run_sync(
210
- next, self.iterator, None, abandon_on_cancel=True
211
- )
212
- if nextval is None:
213
- raise StopAsyncIteration from None
214
-
215
- return Path(nextval)
216
-
217
-
218
- class Path:
219
- """
220
- An asynchronous version of :class:`pathlib.Path`.
221
-
222
- This class cannot be substituted for :class:`pathlib.Path` or
223
- :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike`
224
- interface.
225
-
226
- It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for
227
- the deprecated :meth:`~pathlib.Path.link_to` method.
228
-
229
- Some methods may be unavailable or have limited functionality, based on the Python
230
- version:
231
-
232
- * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later)
233
- * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later)
234
- * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later)
235
- * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later)
236
- * :attr:`~pathlib.Path.info` (available on Python 3.14 or later)
237
- * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later)
238
- * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only
239
- available on Python 3.13 or later)
240
- * :meth:`~pathlib.Path.move` (available on Python 3.14 or later)
241
- * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later)
242
- * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available
243
- on Python 3.12 or later)
244
- * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later)
245
-
246
- Any methods that do disk I/O need to be awaited on. These methods are:
247
-
248
- * :meth:`~pathlib.Path.absolute`
249
- * :meth:`~pathlib.Path.chmod`
250
- * :meth:`~pathlib.Path.cwd`
251
- * :meth:`~pathlib.Path.exists`
252
- * :meth:`~pathlib.Path.expanduser`
253
- * :meth:`~pathlib.Path.group`
254
- * :meth:`~pathlib.Path.hardlink_to`
255
- * :meth:`~pathlib.Path.home`
256
- * :meth:`~pathlib.Path.is_block_device`
257
- * :meth:`~pathlib.Path.is_char_device`
258
- * :meth:`~pathlib.Path.is_dir`
259
- * :meth:`~pathlib.Path.is_fifo`
260
- * :meth:`~pathlib.Path.is_file`
261
- * :meth:`~pathlib.Path.is_junction`
262
- * :meth:`~pathlib.Path.is_mount`
263
- * :meth:`~pathlib.Path.is_socket`
264
- * :meth:`~pathlib.Path.is_symlink`
265
- * :meth:`~pathlib.Path.lchmod`
266
- * :meth:`~pathlib.Path.lstat`
267
- * :meth:`~pathlib.Path.mkdir`
268
- * :meth:`~pathlib.Path.open`
269
- * :meth:`~pathlib.Path.owner`
270
- * :meth:`~pathlib.Path.read_bytes`
271
- * :meth:`~pathlib.Path.read_text`
272
- * :meth:`~pathlib.Path.readlink`
273
- * :meth:`~pathlib.Path.rename`
274
- * :meth:`~pathlib.Path.replace`
275
- * :meth:`~pathlib.Path.resolve`
276
- * :meth:`~pathlib.Path.rmdir`
277
- * :meth:`~pathlib.Path.samefile`
278
- * :meth:`~pathlib.Path.stat`
279
- * :meth:`~pathlib.Path.symlink_to`
280
- * :meth:`~pathlib.Path.touch`
281
- * :meth:`~pathlib.Path.unlink`
282
- * :meth:`~pathlib.Path.walk`
283
- * :meth:`~pathlib.Path.write_bytes`
284
- * :meth:`~pathlib.Path.write_text`
285
-
286
- Additionally, the following methods return an async iterator yielding
287
- :class:`~.Path` objects:
288
-
289
- * :meth:`~pathlib.Path.glob`
290
- * :meth:`~pathlib.Path.iterdir`
291
- * :meth:`~pathlib.Path.rglob`
292
- """
293
-
294
- __slots__ = "_path", "__weakref__"
295
-
296
- __weakref__: Any
297
-
298
- def __init__(self, *args: str | PathLike[str]) -> None:
299
- self._path: Final[pathlib.Path] = pathlib.Path(*args)
300
-
301
- def __fspath__(self) -> str:
302
- return self._path.__fspath__()
303
-
304
- def __str__(self) -> str:
305
- return self._path.__str__()
306
-
307
- def __repr__(self) -> str:
308
- return f"{self.__class__.__name__}({self.as_posix()!r})"
309
-
310
- def __bytes__(self) -> bytes:
311
- return self._path.__bytes__()
312
-
313
- def __hash__(self) -> int:
314
- return self._path.__hash__()
315
-
316
- def __eq__(self, other: object) -> bool:
317
- target = other._path if isinstance(other, Path) else other
318
- return self._path.__eq__(target)
319
-
320
- def __lt__(self, other: pathlib.PurePath | Path) -> bool:
321
- target = other._path if isinstance(other, Path) else other
322
- return self._path.__lt__(target)
323
-
324
- def __le__(self, other: pathlib.PurePath | Path) -> bool:
325
- target = other._path if isinstance(other, Path) else other
326
- return self._path.__le__(target)
327
-
328
- def __gt__(self, other: pathlib.PurePath | Path) -> bool:
329
- target = other._path if isinstance(other, Path) else other
330
- return self._path.__gt__(target)
331
-
332
- def __ge__(self, other: pathlib.PurePath | Path) -> bool:
333
- target = other._path if isinstance(other, Path) else other
334
- return self._path.__ge__(target)
335
-
336
- def __truediv__(self, other: str | PathLike[str]) -> Path:
337
- return Path(self._path / other)
338
-
339
- def __rtruediv__(self, other: str | PathLike[str]) -> Path:
340
- return Path(other) / self
341
-
342
- @property
343
- def parts(self) -> tuple[str, ...]:
344
- return self._path.parts
345
-
346
- @property
347
- def drive(self) -> str:
348
- return self._path.drive
349
-
350
- @property
351
- def root(self) -> str:
352
- return self._path.root
353
-
354
- @property
355
- def anchor(self) -> str:
356
- return self._path.anchor
357
-
358
- @property
359
- def parents(self) -> Sequence[Path]:
360
- return tuple(Path(p) for p in self._path.parents)
361
-
362
- @property
363
- def parent(self) -> Path:
364
- return Path(self._path.parent)
365
-
366
- @property
367
- def name(self) -> str:
368
- return self._path.name
369
-
370
- @property
371
- def suffix(self) -> str:
372
- return self._path.suffix
373
-
374
- @property
375
- def suffixes(self) -> list[str]:
376
- return self._path.suffixes
377
-
378
- @property
379
- def stem(self) -> str:
380
- return self._path.stem
381
-
382
- async def absolute(self) -> Path:
383
- path = await to_thread.run_sync(self._path.absolute)
384
- return Path(path)
385
-
386
- def as_posix(self) -> str:
387
- return self._path.as_posix()
388
-
389
- def as_uri(self) -> str:
390
- return self._path.as_uri()
391
-
392
- if sys.version_info >= (3, 13):
393
- parser: ClassVar[ModuleType] = pathlib.Path.parser
394
-
395
- @classmethod
396
- def from_uri(cls, uri: str) -> Path:
397
- return Path(pathlib.Path.from_uri(uri))
398
-
399
- def full_match(
400
- self, path_pattern: str, *, case_sensitive: bool | None = None
401
- ) -> bool:
402
- return self._path.full_match(path_pattern, case_sensitive=case_sensitive)
403
-
404
- def match(
405
- self, path_pattern: str, *, case_sensitive: bool | None = None
406
- ) -> bool:
407
- return self._path.match(path_pattern, case_sensitive=case_sensitive)
408
- else:
409
-
410
- def match(self, path_pattern: str) -> bool:
411
- return self._path.match(path_pattern)
412
-
413
- if sys.version_info >= (3, 14):
414
-
415
- @property
416
- def info(self) -> Any: # TODO: add return type annotation when Typeshed gets it
417
- return self._path.info
418
-
419
- async def copy(
420
- self,
421
- target: str | os.PathLike[str],
422
- *,
423
- follow_symlinks: bool = True,
424
- preserve_metadata: bool = False,
425
- ) -> Path:
426
- func = partial(
427
- self._path.copy,
428
- follow_symlinks=follow_symlinks,
429
- preserve_metadata=preserve_metadata,
430
- )
431
- return Path(await to_thread.run_sync(func, pathlib.Path(target)))
432
-
433
- async def copy_into(
434
- self,
435
- target_dir: str | os.PathLike[str],
436
- *,
437
- follow_symlinks: bool = True,
438
- preserve_metadata: bool = False,
439
- ) -> Path:
440
- func = partial(
441
- self._path.copy_into,
442
- follow_symlinks=follow_symlinks,
443
- preserve_metadata=preserve_metadata,
444
- )
445
- return Path(await to_thread.run_sync(func, pathlib.Path(target_dir)))
446
-
447
- async def move(self, target: str | os.PathLike[str]) -> Path:
448
- # Upstream does not handle anyio.Path properly as a PathLike
449
- target = pathlib.Path(target)
450
- return Path(await to_thread.run_sync(self._path.move, target))
451
-
452
- async def move_into(
453
- self,
454
- target_dir: str | os.PathLike[str],
455
- ) -> Path:
456
- return Path(await to_thread.run_sync(self._path.move_into, target_dir))
457
-
458
- def is_relative_to(self, other: str | PathLike[str]) -> bool:
459
- try:
460
- self.relative_to(other)
461
- return True
462
- except ValueError:
463
- return False
464
-
465
- async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None:
466
- func = partial(os.chmod, follow_symlinks=follow_symlinks)
467
- return await to_thread.run_sync(func, self._path, mode)
468
-
469
- @classmethod
470
- async def cwd(cls) -> Path:
471
- path = await to_thread.run_sync(pathlib.Path.cwd)
472
- return cls(path)
473
-
474
- async def exists(self) -> bool:
475
- return await to_thread.run_sync(self._path.exists, abandon_on_cancel=True)
476
-
477
- async def expanduser(self) -> Path:
478
- return Path(
479
- await to_thread.run_sync(self._path.expanduser, abandon_on_cancel=True)
480
- )
481
-
482
- if sys.version_info < (3, 12):
483
- # Python 3.11 and earlier
484
- def glob(self, pattern: str) -> AsyncIterator[Path]:
485
- gen = self._path.glob(pattern)
486
- return _PathIterator(gen)
487
- elif (3, 12) <= sys.version_info < (3, 13):
488
- # changed in Python 3.12:
489
- # - The case_sensitive parameter was added.
490
- def glob(
491
- self,
492
- pattern: str,
493
- *,
494
- case_sensitive: bool | None = None,
495
- ) -> AsyncIterator[Path]:
496
- gen = self._path.glob(pattern, case_sensitive=case_sensitive)
497
- return _PathIterator(gen)
498
- elif sys.version_info >= (3, 13):
499
- # Changed in Python 3.13:
500
- # - The recurse_symlinks parameter was added.
501
- # - The pattern parameter accepts a path-like object.
502
- def glob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
503
- self,
504
- pattern: str | PathLike[str],
505
- *,
506
- case_sensitive: bool | None = None,
507
- recurse_symlinks: bool = False,
508
- ) -> AsyncIterator[Path]:
509
- gen = self._path.glob(
510
- pattern, # type: ignore[arg-type]
511
- case_sensitive=case_sensitive,
512
- recurse_symlinks=recurse_symlinks,
513
- )
514
- return _PathIterator(gen)
515
-
516
- async def group(self) -> str:
517
- return await to_thread.run_sync(self._path.group, abandon_on_cancel=True)
518
-
519
- async def hardlink_to(
520
- self, target: str | bytes | PathLike[str] | PathLike[bytes]
521
- ) -> None:
522
- if isinstance(target, Path):
523
- target = target._path
524
-
525
- await to_thread.run_sync(os.link, target, self)
526
-
527
- @classmethod
528
- async def home(cls) -> Path:
529
- home_path = await to_thread.run_sync(pathlib.Path.home)
530
- return cls(home_path)
531
-
532
- def is_absolute(self) -> bool:
533
- return self._path.is_absolute()
534
-
535
- async def is_block_device(self) -> bool:
536
- return await to_thread.run_sync(
537
- self._path.is_block_device, abandon_on_cancel=True
538
- )
539
-
540
- async def is_char_device(self) -> bool:
541
- return await to_thread.run_sync(
542
- self._path.is_char_device, abandon_on_cancel=True
543
- )
544
-
545
- async def is_dir(self) -> bool:
546
- return await to_thread.run_sync(self._path.is_dir, abandon_on_cancel=True)
547
-
548
- async def is_fifo(self) -> bool:
549
- return await to_thread.run_sync(self._path.is_fifo, abandon_on_cancel=True)
550
-
551
- async def is_file(self) -> bool:
552
- return await to_thread.run_sync(self._path.is_file, abandon_on_cancel=True)
553
-
554
- if sys.version_info >= (3, 12):
555
-
556
- async def is_junction(self) -> bool:
557
- return await to_thread.run_sync(self._path.is_junction)
558
-
559
- async def is_mount(self) -> bool:
560
- return await to_thread.run_sync(
561
- os.path.ismount, self._path, abandon_on_cancel=True
562
- )
563
-
564
- def is_reserved(self) -> bool:
565
- return self._path.is_reserved()
566
-
567
- async def is_socket(self) -> bool:
568
- return await to_thread.run_sync(self._path.is_socket, abandon_on_cancel=True)
569
-
570
- async def is_symlink(self) -> bool:
571
- return await to_thread.run_sync(self._path.is_symlink, abandon_on_cancel=True)
572
-
573
- async def iterdir(self) -> AsyncIterator[Path]:
574
- gen = (
575
- self._path.iterdir()
576
- if sys.version_info < (3, 13)
577
- else await to_thread.run_sync(self._path.iterdir, abandon_on_cancel=True)
578
- )
579
- async for path in _PathIterator(gen):
580
- yield path
581
-
582
- def joinpath(self, *args: str | PathLike[str]) -> Path:
583
- return Path(self._path.joinpath(*args))
584
-
585
- async def lchmod(self, mode: int) -> None:
586
- await to_thread.run_sync(self._path.lchmod, mode)
587
-
588
- async def lstat(self) -> os.stat_result:
589
- return await to_thread.run_sync(self._path.lstat, abandon_on_cancel=True)
590
-
591
- async def mkdir(
592
- self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
593
- ) -> None:
594
- await to_thread.run_sync(self._path.mkdir, mode, parents, exist_ok)
595
-
596
- @overload
597
- async def open(
598
- self,
599
- mode: OpenBinaryMode,
600
- buffering: int = ...,
601
- encoding: str | None = ...,
602
- errors: str | None = ...,
603
- newline: str | None = ...,
604
- ) -> AsyncFile[bytes]: ...
605
-
606
- @overload
607
- async def open(
608
- self,
609
- mode: OpenTextMode = ...,
610
- buffering: int = ...,
611
- encoding: str | None = ...,
612
- errors: str | None = ...,
613
- newline: str | None = ...,
614
- ) -> AsyncFile[str]: ...
615
-
616
- async def open(
617
- self,
618
- mode: str = "r",
619
- buffering: int = -1,
620
- encoding: str | None = None,
621
- errors: str | None = None,
622
- newline: str | None = None,
623
- ) -> AsyncFile[Any]:
624
- fp = await to_thread.run_sync(
625
- self._path.open, mode, buffering, encoding, errors, newline
626
- )
627
- return AsyncFile(fp)
628
-
629
- async def owner(self) -> str:
630
- return await to_thread.run_sync(self._path.owner, abandon_on_cancel=True)
631
-
632
- async def read_bytes(self) -> bytes:
633
- return await to_thread.run_sync(self._path.read_bytes)
634
-
635
- async def read_text(
636
- self, encoding: str | None = None, errors: str | None = None
637
- ) -> str:
638
- return await to_thread.run_sync(self._path.read_text, encoding, errors)
639
-
640
- if sys.version_info >= (3, 12):
641
-
642
- def relative_to(
643
- self, *other: str | PathLike[str], walk_up: bool = False
644
- ) -> Path:
645
- # relative_to() should work with any PathLike but it doesn't
646
- others = [pathlib.Path(other) for other in other]
647
- return Path(self._path.relative_to(*others, walk_up=walk_up))
648
-
649
- else:
650
-
651
- def relative_to(self, *other: str | PathLike[str]) -> Path:
652
- return Path(self._path.relative_to(*other))
653
-
654
- async def readlink(self) -> Path:
655
- target = await to_thread.run_sync(os.readlink, self._path)
656
- return Path(target)
657
-
658
- async def rename(self, target: str | pathlib.PurePath | Path) -> Path:
659
- if isinstance(target, Path):
660
- target = target._path
661
-
662
- await to_thread.run_sync(self._path.rename, target)
663
- return Path(target)
664
-
665
- async def replace(self, target: str | pathlib.PurePath | Path) -> Path:
666
- if isinstance(target, Path):
667
- target = target._path
668
-
669
- await to_thread.run_sync(self._path.replace, target)
670
- return Path(target)
671
-
672
- async def resolve(self, strict: bool = False) -> Path:
673
- func = partial(self._path.resolve, strict=strict)
674
- return Path(await to_thread.run_sync(func, abandon_on_cancel=True))
675
-
676
- if sys.version_info < (3, 12):
677
- # Pre Python 3.12
678
- def rglob(self, pattern: str) -> AsyncIterator[Path]:
679
- gen = self._path.rglob(pattern)
680
- return _PathIterator(gen)
681
- elif (3, 12) <= sys.version_info < (3, 13):
682
- # Changed in Python 3.12:
683
- # - The case_sensitive parameter was added.
684
- def rglob(
685
- self, pattern: str, *, case_sensitive: bool | None = None
686
- ) -> AsyncIterator[Path]:
687
- gen = self._path.rglob(pattern, case_sensitive=case_sensitive)
688
- return _PathIterator(gen)
689
- elif sys.version_info >= (3, 13):
690
- # Changed in Python 3.13:
691
- # - The recurse_symlinks parameter was added.
692
- # - The pattern parameter accepts a path-like object.
693
- def rglob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
694
- self,
695
- pattern: str | PathLike[str],
696
- *,
697
- case_sensitive: bool | None = None,
698
- recurse_symlinks: bool = False,
699
- ) -> AsyncIterator[Path]:
700
- gen = self._path.rglob(
701
- pattern, # type: ignore[arg-type]
702
- case_sensitive=case_sensitive,
703
- recurse_symlinks=recurse_symlinks,
704
- )
705
- return _PathIterator(gen)
706
-
707
- async def rmdir(self) -> None:
708
- await to_thread.run_sync(self._path.rmdir)
709
-
710
- async def samefile(self, other_path: str | PathLike[str]) -> bool:
711
- if isinstance(other_path, Path):
712
- other_path = other_path._path
713
-
714
- return await to_thread.run_sync(
715
- self._path.samefile, other_path, abandon_on_cancel=True
716
- )
717
-
718
- async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result:
719
- func = partial(os.stat, follow_symlinks=follow_symlinks)
720
- return await to_thread.run_sync(func, self._path, abandon_on_cancel=True)
721
-
722
- async def symlink_to(
723
- self,
724
- target: str | bytes | PathLike[str] | PathLike[bytes],
725
- target_is_directory: bool = False,
726
- ) -> None:
727
- if isinstance(target, Path):
728
- target = target._path
729
-
730
- await to_thread.run_sync(self._path.symlink_to, target, target_is_directory)
731
-
732
- async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
733
- await to_thread.run_sync(self._path.touch, mode, exist_ok)
734
-
735
- async def unlink(self, missing_ok: bool = False) -> None:
736
- try:
737
- await to_thread.run_sync(self._path.unlink)
738
- except FileNotFoundError:
739
- if not missing_ok:
740
- raise
741
-
742
- if sys.version_info >= (3, 12):
743
-
744
- async def walk(
745
- self,
746
- top_down: bool = True,
747
- on_error: Callable[[OSError], object] | None = None,
748
- follow_symlinks: bool = False,
749
- ) -> AsyncIterator[tuple[Path, list[str], list[str]]]:
750
- def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None:
751
- try:
752
- return next(gen)
753
- except StopIteration:
754
- return None
755
-
756
- gen = self._path.walk(top_down, on_error, follow_symlinks)
757
- while True:
758
- value = await to_thread.run_sync(get_next_value)
759
- if value is None:
760
- return
761
-
762
- root, dirs, paths = value
763
- yield Path(root), dirs, paths
764
-
765
- def with_name(self, name: str) -> Path:
766
- return Path(self._path.with_name(name))
767
-
768
- def with_stem(self, stem: str) -> Path:
769
- return Path(self._path.with_name(stem + self._path.suffix))
770
-
771
- def with_suffix(self, suffix: str) -> Path:
772
- return Path(self._path.with_suffix(suffix))
773
-
774
- def with_segments(self, *pathsegments: str | PathLike[str]) -> Path:
775
- return Path(*pathsegments)
776
-
777
- async def write_bytes(self, data: bytes) -> int:
778
- return await to_thread.run_sync(self._path.write_bytes, data)
779
-
780
- async def write_text(
781
- self,
782
- data: str,
783
- encoding: str | None = None,
784
- errors: str | None = None,
785
- newline: str | None = None,
786
- ) -> int:
787
- # Path.write_text() does not support the "newline" parameter before Python 3.10
788
- def sync_write_text() -> int:
789
- with self._path.open(
790
- "w", encoding=encoding, errors=errors, newline=newline
791
- ) as fp:
792
- return fp.write(data)
793
-
794
- return await to_thread.run_sync(sync_write_text)
795
-
796
-
797
- PathLike.register(Path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_resources.py DELETED
@@ -1,18 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from ..abc import AsyncResource
4
- from ._tasks import CancelScope
5
-
6
-
7
- async def aclose_forcefully(resource: AsyncResource) -> None:
8
- """
9
- Close an asynchronous resource in a cancelled scope.
10
-
11
- Doing this closes the resource without waiting on anything.
12
-
13
- :param resource: the resource to close
14
-
15
- """
16
- with CancelScope() as scope:
17
- scope.cancel()
18
- await resource.aclose()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_signals.py DELETED
@@ -1,29 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import AsyncIterator
4
- from contextlib import AbstractContextManager
5
- from signal import Signals
6
-
7
- from ._eventloop import get_async_backend
8
-
9
-
10
- def open_signal_receiver(
11
- *signals: Signals,
12
- ) -> AbstractContextManager[AsyncIterator[Signals]]:
13
- """
14
- Start receiving operating system signals.
15
-
16
- :param signals: signals to receive (e.g. ``signal.SIGINT``)
17
- :return: an asynchronous context manager for an asynchronous iterator which yields
18
- signal numbers
19
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
20
- current thread
21
-
22
- .. warning:: Windows does not support signals natively so it is best to avoid
23
- relying on this in cross-platform applications.
24
-
25
- .. warning:: On asyncio, this permanently replaces any previous signal handler for
26
- the given signals, as set via :meth:`~asyncio.loop.add_signal_handler`.
27
-
28
- """
29
- return get_async_backend().open_signal_receiver(*signals)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_sockets.py DELETED
@@ -1,1003 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import errno
4
- import os
5
- import socket
6
- import ssl
7
- import stat
8
- import sys
9
- from collections.abc import Awaitable
10
- from dataclasses import dataclass
11
- from ipaddress import IPv4Address, IPv6Address, ip_address
12
- from os import PathLike, chmod
13
- from socket import AddressFamily, SocketKind
14
- from typing import TYPE_CHECKING, Any, Literal, cast, overload
15
-
16
- from .. import ConnectionFailed, to_thread
17
- from ..abc import (
18
- ByteStreamConnectable,
19
- ConnectedUDPSocket,
20
- ConnectedUNIXDatagramSocket,
21
- IPAddressType,
22
- IPSockAddrType,
23
- SocketListener,
24
- SocketStream,
25
- UDPSocket,
26
- UNIXDatagramSocket,
27
- UNIXSocketStream,
28
- )
29
- from ..streams.stapled import MultiListener
30
- from ..streams.tls import TLSConnectable, TLSStream
31
- from ._eventloop import get_async_backend
32
- from ._resources import aclose_forcefully
33
- from ._synchronization import Event
34
- from ._tasks import create_task_group, move_on_after
35
-
36
- if TYPE_CHECKING:
37
- from _typeshed import FileDescriptorLike
38
- else:
39
- FileDescriptorLike = object
40
-
41
- if sys.version_info < (3, 11):
42
- from exceptiongroup import ExceptionGroup
43
-
44
- if sys.version_info >= (3, 12):
45
- from typing import override
46
- else:
47
- from typing_extensions import override
48
-
49
- if sys.version_info < (3, 13):
50
- from typing_extensions import deprecated
51
- else:
52
- from warnings import deprecated
53
-
54
- IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41) # https://bugs.python.org/issue29515
55
-
56
- AnyIPAddressFamily = Literal[
57
- AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6
58
- ]
59
- IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6]
60
-
61
-
62
- # tls_hostname given
63
- @overload
64
- async def connect_tcp(
65
- remote_host: IPAddressType,
66
- remote_port: int,
67
- *,
68
- local_host: IPAddressType | None = ...,
69
- ssl_context: ssl.SSLContext | None = ...,
70
- tls_standard_compatible: bool = ...,
71
- tls_hostname: str,
72
- happy_eyeballs_delay: float = ...,
73
- ) -> TLSStream: ...
74
-
75
-
76
- # ssl_context given
77
- @overload
78
- async def connect_tcp(
79
- remote_host: IPAddressType,
80
- remote_port: int,
81
- *,
82
- local_host: IPAddressType | None = ...,
83
- ssl_context: ssl.SSLContext,
84
- tls_standard_compatible: bool = ...,
85
- tls_hostname: str | None = ...,
86
- happy_eyeballs_delay: float = ...,
87
- ) -> TLSStream: ...
88
-
89
-
90
- # tls=True
91
- @overload
92
- async def connect_tcp(
93
- remote_host: IPAddressType,
94
- remote_port: int,
95
- *,
96
- local_host: IPAddressType | None = ...,
97
- tls: Literal[True],
98
- ssl_context: ssl.SSLContext | None = ...,
99
- tls_standard_compatible: bool = ...,
100
- tls_hostname: str | None = ...,
101
- happy_eyeballs_delay: float = ...,
102
- ) -> TLSStream: ...
103
-
104
-
105
- # tls=False
106
- @overload
107
- async def connect_tcp(
108
- remote_host: IPAddressType,
109
- remote_port: int,
110
- *,
111
- local_host: IPAddressType | None = ...,
112
- tls: Literal[False],
113
- ssl_context: ssl.SSLContext | None = ...,
114
- tls_standard_compatible: bool = ...,
115
- tls_hostname: str | None = ...,
116
- happy_eyeballs_delay: float = ...,
117
- ) -> SocketStream: ...
118
-
119
-
120
- # No TLS arguments
121
- @overload
122
- async def connect_tcp(
123
- remote_host: IPAddressType,
124
- remote_port: int,
125
- *,
126
- local_host: IPAddressType | None = ...,
127
- happy_eyeballs_delay: float = ...,
128
- ) -> SocketStream: ...
129
-
130
-
131
- async def connect_tcp(
132
- remote_host: IPAddressType,
133
- remote_port: int,
134
- *,
135
- local_host: IPAddressType | None = None,
136
- tls: bool = False,
137
- ssl_context: ssl.SSLContext | None = None,
138
- tls_standard_compatible: bool = True,
139
- tls_hostname: str | None = None,
140
- happy_eyeballs_delay: float = 0.25,
141
- ) -> SocketStream | TLSStream:
142
- """
143
- Connect to a host using the TCP protocol.
144
-
145
- This function implements the stateless version of the Happy Eyeballs algorithm (RFC
146
- 6555). If ``remote_host`` is a host name that resolves to multiple IP addresses,
147
- each one is tried until one connection attempt succeeds. If the first attempt does
148
- not connected within 250 milliseconds, a second attempt is started using the next
149
- address in the list, and so on. On IPv6 enabled systems, an IPv6 address (if
150
- available) is tried first.
151
-
152
- When the connection has been established, a TLS handshake will be done if either
153
- ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``.
154
-
155
- :param remote_host: the IP address or host name to connect to
156
- :param remote_port: port on the target host to connect to
157
- :param local_host: the interface address or name to bind the socket to before
158
- connecting
159
- :param tls: ``True`` to do a TLS handshake with the connected stream and return a
160
- :class:`~anyio.streams.tls.TLSStream` instead
161
- :param ssl_context: the SSL context object to use (if omitted, a default context is
162
- created)
163
- :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake
164
- before closing the stream and requires that the server does this as well.
165
- Otherwise, :exc:`~ssl.SSLEOFError` may be raised during reads from the stream.
166
- Some protocols, such as HTTP, require this option to be ``False``.
167
- See :meth:`~ssl.SSLContext.wrap_socket` for details.
168
- :param tls_hostname: host name to check the server certificate against (defaults to
169
- the value of ``remote_host``)
170
- :param happy_eyeballs_delay: delay (in seconds) before starting the next connection
171
- attempt
172
- :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream
173
- :raises ConnectionFailed: if the connection fails
174
-
175
- """
176
- # Placed here due to https://github.com/python/mypy/issues/7057
177
- connected_stream: SocketStream | None = None
178
-
179
- async def try_connect(remote_host: str, event: Event) -> None:
180
- nonlocal connected_stream
181
- try:
182
- stream = await asynclib.connect_tcp(remote_host, remote_port, local_address)
183
- except OSError as exc:
184
- oserrors.append(exc)
185
- return
186
- else:
187
- if connected_stream is None:
188
- connected_stream = stream
189
- tg.cancel_scope.cancel()
190
- else:
191
- await stream.aclose()
192
- finally:
193
- event.set()
194
-
195
- asynclib = get_async_backend()
196
- local_address: IPSockAddrType | None = None
197
- family = socket.AF_UNSPEC
198
- if local_host:
199
- gai_res = await getaddrinfo(str(local_host), None)
200
- family, *_, local_address = gai_res[0]
201
-
202
- target_host = str(remote_host)
203
- try:
204
- addr_obj = ip_address(remote_host)
205
- except ValueError:
206
- addr_obj = None
207
-
208
- if addr_obj is not None:
209
- if isinstance(addr_obj, IPv6Address):
210
- target_addrs = [(socket.AF_INET6, addr_obj.compressed)]
211
- else:
212
- target_addrs = [(socket.AF_INET, addr_obj.compressed)]
213
- else:
214
- # getaddrinfo() will raise an exception if name resolution fails
215
- gai_res = await getaddrinfo(
216
- target_host, remote_port, family=family, type=socket.SOCK_STREAM
217
- )
218
-
219
- # Organize the list so that the first address is an IPv6 address (if available)
220
- # and the second one is an IPv4 addresses. The rest can be in whatever order.
221
- v6_found = v4_found = False
222
- target_addrs = []
223
- for af, *_, sa in gai_res:
224
- if af == socket.AF_INET6 and not v6_found:
225
- v6_found = True
226
- target_addrs.insert(0, (af, sa[0]))
227
- elif af == socket.AF_INET and not v4_found and v6_found:
228
- v4_found = True
229
- target_addrs.insert(1, (af, sa[0]))
230
- else:
231
- target_addrs.append((af, sa[0]))
232
-
233
- oserrors: list[OSError] = []
234
- try:
235
- async with create_task_group() as tg:
236
- for _af, addr in target_addrs:
237
- event = Event()
238
- tg.start_soon(try_connect, addr, event)
239
- with move_on_after(happy_eyeballs_delay):
240
- await event.wait()
241
-
242
- if connected_stream is None:
243
- cause = (
244
- oserrors[0]
245
- if len(oserrors) == 1
246
- else ExceptionGroup("multiple connection attempts failed", oserrors)
247
- )
248
- raise OSError("All connection attempts failed") from cause
249
- finally:
250
- oserrors.clear()
251
-
252
- if tls or tls_hostname or ssl_context:
253
- try:
254
- return await TLSStream.wrap(
255
- connected_stream,
256
- server_side=False,
257
- hostname=tls_hostname or str(remote_host),
258
- ssl_context=ssl_context,
259
- standard_compatible=tls_standard_compatible,
260
- )
261
- except BaseException:
262
- await aclose_forcefully(connected_stream)
263
- raise
264
-
265
- return connected_stream
266
-
267
-
268
- async def connect_unix(path: str | bytes | PathLike[Any]) -> UNIXSocketStream:
269
- """
270
- Connect to the given UNIX socket.
271
-
272
- Not available on Windows.
273
-
274
- :param path: path to the socket
275
- :return: a socket stream object
276
- :raises ConnectionFailed: if the connection fails
277
-
278
- """
279
- path = os.fspath(path)
280
- return await get_async_backend().connect_unix(path)
281
-
282
-
283
- async def create_tcp_listener(
284
- *,
285
- local_host: IPAddressType | None = None,
286
- local_port: int = 0,
287
- family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC,
288
- backlog: int = 65536,
289
- reuse_port: bool = False,
290
- ) -> MultiListener[SocketStream]:
291
- """
292
- Create a TCP socket listener.
293
-
294
- :param local_port: port number to listen on
295
- :param local_host: IP address of the interface to listen on. If omitted, listen on
296
- all IPv4 and IPv6 interfaces. To listen on all interfaces on a specific address
297
- family, use ``0.0.0.0`` for IPv4 or ``::`` for IPv6.
298
- :param family: address family (used if ``local_host`` was omitted)
299
- :param backlog: maximum number of queued incoming connections (up to a maximum of
300
- 2**16, or 65536)
301
- :param reuse_port: ``True`` to allow multiple sockets to bind to the same
302
- address/port (not supported on Windows)
303
- :return: a multi-listener object containing one or more socket listeners
304
- :raises OSError: if there's an error creating a socket, or binding to one or more
305
- interfaces failed
306
-
307
- """
308
- asynclib = get_async_backend()
309
- backlog = min(backlog, 65536)
310
- local_host = str(local_host) if local_host is not None else None
311
-
312
- def setup_raw_socket(
313
- fam: AddressFamily,
314
- bind_addr: tuple[str, int] | tuple[str, int, int, int],
315
- *,
316
- v6only: bool = True,
317
- ) -> socket.socket:
318
- sock = socket.socket(fam)
319
- try:
320
- sock.setblocking(False)
321
-
322
- if fam == AddressFamily.AF_INET6:
323
- sock.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, v6only)
324
-
325
- # For Windows, enable exclusive address use. For others, enable address
326
- # reuse.
327
- if sys.platform == "win32":
328
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
329
- else:
330
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
331
-
332
- if reuse_port:
333
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
334
-
335
- # Workaround for #554
336
- if fam == socket.AF_INET6 and "%" in bind_addr[0]:
337
- addr, scope_id = bind_addr[0].split("%", 1)
338
- bind_addr = (addr, bind_addr[1], 0, int(scope_id))
339
-
340
- sock.bind(bind_addr)
341
- sock.listen(backlog)
342
- except BaseException:
343
- sock.close()
344
- raise
345
-
346
- return sock
347
-
348
- # We passing type=0 on non-Windows platforms as a workaround for a uvloop bug
349
- # where we don't get the correct scope ID for IPv6 link-local addresses when passing
350
- # type=socket.SOCK_STREAM to getaddrinfo():
351
- # https://github.com/MagicStack/uvloop/issues/539
352
- gai_res = await getaddrinfo(
353
- local_host,
354
- local_port,
355
- family=family,
356
- type=socket.SOCK_STREAM if sys.platform == "win32" else 0,
357
- flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
358
- )
359
-
360
- # The set comprehension is here to work around a glibc bug:
361
- # https://sourceware.org/bugzilla/show_bug.cgi?id=14969
362
- sockaddrs = sorted({res for res in gai_res if res[1] == SocketKind.SOCK_STREAM})
363
-
364
- # Special case for dual-stack binding on the "any" interface
365
- if (
366
- local_host is None
367
- and family == AddressFamily.AF_UNSPEC
368
- and socket.has_dualstack_ipv6()
369
- and any(fam == AddressFamily.AF_INET6 for fam, *_ in gai_res)
370
- ):
371
- raw_socket = setup_raw_socket(
372
- AddressFamily.AF_INET6, ("::", local_port), v6only=False
373
- )
374
- listener = asynclib.create_tcp_listener(raw_socket)
375
- return MultiListener([listener])
376
-
377
- errors: list[OSError] = []
378
- try:
379
- for _ in range(len(sockaddrs)):
380
- listeners: list[SocketListener] = []
381
- bound_ephemeral_port = local_port
382
- try:
383
- for fam, *_, sockaddr in sockaddrs:
384
- sockaddr = sockaddr[0], bound_ephemeral_port, *sockaddr[2:]
385
- raw_socket = setup_raw_socket(fam, sockaddr)
386
-
387
- # Store the assigned port if an ephemeral port was requested, so
388
- # we'll bind to the same port on all interfaces
389
- if local_port == 0 and len(gai_res) > 1:
390
- bound_ephemeral_port = raw_socket.getsockname()[1]
391
-
392
- listeners.append(asynclib.create_tcp_listener(raw_socket))
393
- except BaseException as exc:
394
- for listener in listeners:
395
- await listener.aclose()
396
-
397
- # If an ephemeral port was requested but binding the assigned port
398
- # failed for another interface, rotate the address list and try again
399
- if (
400
- isinstance(exc, OSError)
401
- and exc.errno == errno.EADDRINUSE
402
- and local_port == 0
403
- and bound_ephemeral_port
404
- ):
405
- errors.append(exc)
406
- sockaddrs.append(sockaddrs.pop(0))
407
- continue
408
-
409
- raise
410
-
411
- return MultiListener(listeners)
412
-
413
- raise OSError(
414
- f"Could not create {len(sockaddrs)} listeners with a consistent port"
415
- ) from ExceptionGroup("Several bind attempts failed", errors)
416
- finally:
417
- del errors # Prevent reference cycles
418
-
419
-
420
- async def create_unix_listener(
421
- path: str | bytes | PathLike[Any],
422
- *,
423
- mode: int | None = None,
424
- backlog: int = 65536,
425
- ) -> SocketListener:
426
- """
427
- Create a UNIX socket listener.
428
-
429
- Not available on Windows.
430
-
431
- :param path: path of the socket
432
- :param mode: permissions to set on the socket
433
- :param backlog: maximum number of queued incoming connections (up to a maximum of
434
- 2**16, or 65536)
435
- :return: a listener object
436
-
437
- .. versionchanged:: 3.0
438
- If a socket already exists on the file system in the given path, it will be
439
- removed first.
440
-
441
- """
442
- backlog = min(backlog, 65536)
443
- raw_socket = await setup_unix_local_socket(path, mode, socket.SOCK_STREAM)
444
- try:
445
- raw_socket.listen(backlog)
446
- return get_async_backend().create_unix_listener(raw_socket)
447
- except BaseException:
448
- raw_socket.close()
449
- raise
450
-
451
-
452
- async def create_udp_socket(
453
- family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC,
454
- *,
455
- local_host: IPAddressType | None = None,
456
- local_port: int = 0,
457
- reuse_port: bool = False,
458
- ) -> UDPSocket:
459
- """
460
- Create a UDP socket.
461
-
462
- If ``port`` has been given, the socket will be bound to this port on the local
463
- machine, making this socket suitable for providing UDP based services.
464
-
465
- :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically
466
- determined from ``local_host`` if omitted
467
- :param local_host: IP address or host name of the local interface to bind to
468
- :param local_port: local port to bind to
469
- :param reuse_port: ``True`` to allow multiple sockets to bind to the same
470
- address/port (not supported on Windows)
471
- :return: a UDP socket
472
-
473
- """
474
- if family is AddressFamily.AF_UNSPEC and not local_host:
475
- raise ValueError('Either "family" or "local_host" must be given')
476
-
477
- if local_host:
478
- gai_res = await getaddrinfo(
479
- str(local_host),
480
- local_port,
481
- family=family,
482
- type=socket.SOCK_DGRAM,
483
- flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
484
- )
485
- family = cast(AnyIPAddressFamily, gai_res[0][0])
486
- local_address = gai_res[0][-1]
487
- elif family is AddressFamily.AF_INET6:
488
- local_address = ("::", 0)
489
- else:
490
- local_address = ("0.0.0.0", 0)
491
-
492
- sock = await get_async_backend().create_udp_socket(
493
- family, local_address, None, reuse_port
494
- )
495
- return cast(UDPSocket, sock)
496
-
497
-
498
- async def create_connected_udp_socket(
499
- remote_host: IPAddressType,
500
- remote_port: int,
501
- *,
502
- family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC,
503
- local_host: IPAddressType | None = None,
504
- local_port: int = 0,
505
- reuse_port: bool = False,
506
- ) -> ConnectedUDPSocket:
507
- """
508
- Create a connected UDP socket.
509
-
510
- Connected UDP sockets can only communicate with the specified remote host/port, an
511
- any packets sent from other sources are dropped.
512
-
513
- :param remote_host: remote host to set as the default target
514
- :param remote_port: port on the remote host to set as the default target
515
- :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically
516
- determined from ``local_host`` or ``remote_host`` if omitted
517
- :param local_host: IP address or host name of the local interface to bind to
518
- :param local_port: local port to bind to
519
- :param reuse_port: ``True`` to allow multiple sockets to bind to the same
520
- address/port (not supported on Windows)
521
- :return: a connected UDP socket
522
-
523
- """
524
- local_address = None
525
- if local_host:
526
- gai_res = await getaddrinfo(
527
- str(local_host),
528
- local_port,
529
- family=family,
530
- type=socket.SOCK_DGRAM,
531
- flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
532
- )
533
- family = cast(AnyIPAddressFamily, gai_res[0][0])
534
- local_address = gai_res[0][-1]
535
-
536
- gai_res = await getaddrinfo(
537
- str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM
538
- )
539
- family = cast(AnyIPAddressFamily, gai_res[0][0])
540
- remote_address = gai_res[0][-1]
541
-
542
- sock = await get_async_backend().create_udp_socket(
543
- family, local_address, remote_address, reuse_port
544
- )
545
- return cast(ConnectedUDPSocket, sock)
546
-
547
-
548
- async def create_unix_datagram_socket(
549
- *,
550
- local_path: None | str | bytes | PathLike[Any] = None,
551
- local_mode: int | None = None,
552
- ) -> UNIXDatagramSocket:
553
- """
554
- Create a UNIX datagram socket.
555
-
556
- Not available on Windows.
557
-
558
- If ``local_path`` has been given, the socket will be bound to this path, making this
559
- socket suitable for receiving datagrams from other processes. Other processes can
560
- send datagrams to this socket only if ``local_path`` is set.
561
-
562
- If a socket already exists on the file system in the ``local_path``, it will be
563
- removed first.
564
-
565
- :param local_path: the path on which to bind to
566
- :param local_mode: permissions to set on the local socket
567
- :return: a UNIX datagram socket
568
-
569
- """
570
- raw_socket = await setup_unix_local_socket(
571
- local_path, local_mode, socket.SOCK_DGRAM
572
- )
573
- return await get_async_backend().create_unix_datagram_socket(raw_socket, None)
574
-
575
-
576
- async def create_connected_unix_datagram_socket(
577
- remote_path: str | bytes | PathLike[Any],
578
- *,
579
- local_path: None | str | bytes | PathLike[Any] = None,
580
- local_mode: int | None = None,
581
- ) -> ConnectedUNIXDatagramSocket:
582
- """
583
- Create a connected UNIX datagram socket.
584
-
585
- Connected datagram sockets can only communicate with the specified remote path.
586
-
587
- If ``local_path`` has been given, the socket will be bound to this path, making
588
- this socket suitable for receiving datagrams from other processes. Other processes
589
- can send datagrams to this socket only if ``local_path`` is set.
590
-
591
- If a socket already exists on the file system in the ``local_path``, it will be
592
- removed first.
593
-
594
- :param remote_path: the path to set as the default target
595
- :param local_path: the path on which to bind to
596
- :param local_mode: permissions to set on the local socket
597
- :return: a connected UNIX datagram socket
598
-
599
- """
600
- remote_path = os.fspath(remote_path)
601
- raw_socket = await setup_unix_local_socket(
602
- local_path, local_mode, socket.SOCK_DGRAM
603
- )
604
- return await get_async_backend().create_unix_datagram_socket(
605
- raw_socket, remote_path
606
- )
607
-
608
-
609
- async def getaddrinfo(
610
- host: bytes | str | None,
611
- port: str | int | None,
612
- *,
613
- family: int | AddressFamily = 0,
614
- type: int | SocketKind = 0,
615
- proto: int = 0,
616
- flags: int = 0,
617
- ) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int]]]:
618
- """
619
- Look up a numeric IP address given a host name.
620
-
621
- Internationalized domain names are translated according to the (non-transitional)
622
- IDNA 2008 standard.
623
-
624
- .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of
625
- (host, port), unlike what :func:`socket.getaddrinfo` does.
626
-
627
- :param host: host name
628
- :param port: port number
629
- :param family: socket family (`'AF_INET``, ...)
630
- :param type: socket type (``SOCK_STREAM``, ...)
631
- :param proto: protocol number
632
- :param flags: flags to pass to upstream ``getaddrinfo()``
633
- :return: list of tuples containing (family, type, proto, canonname, sockaddr)
634
-
635
- .. seealso:: :func:`socket.getaddrinfo`
636
-
637
- """
638
- # Handle unicode hostnames
639
- if isinstance(host, str):
640
- try:
641
- encoded_host: bytes | None = host.encode("ascii")
642
- except UnicodeEncodeError:
643
- import idna
644
-
645
- encoded_host = idna.encode(host, uts46=True)
646
- else:
647
- encoded_host = host
648
-
649
- gai_res = await get_async_backend().getaddrinfo(
650
- encoded_host, port, family=family, type=type, proto=proto, flags=flags
651
- )
652
- return [
653
- (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr))
654
- for family, type, proto, canonname, sockaddr in gai_res
655
- # filter out IPv6 results when IPv6 is disabled
656
- if not isinstance(sockaddr[0], int)
657
- ]
658
-
659
-
660
- def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[tuple[str, str]]:
661
- """
662
- Look up the host name of an IP address.
663
-
664
- :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4)
665
- :param flags: flags to pass to upstream ``getnameinfo()``
666
- :return: a tuple of (host name, service name)
667
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
668
- current thread
669
-
670
- .. seealso:: :func:`socket.getnameinfo`
671
-
672
- """
673
- return get_async_backend().getnameinfo(sockaddr, flags)
674
-
675
-
676
- @deprecated("This function is deprecated; use `wait_readable` instead")
677
- def wait_socket_readable(sock: socket.socket) -> Awaitable[None]:
678
- """
679
- .. deprecated:: 4.7.0
680
- Use :func:`wait_readable` instead.
681
-
682
- Wait until the given socket has data to be read.
683
-
684
- .. warning:: Only use this on raw sockets that have not been wrapped by any higher
685
- level constructs like socket streams!
686
-
687
- :param sock: a socket object
688
- :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the
689
- socket to become readable
690
- :raises ~anyio.BusyResourceError: if another task is already waiting for the socket
691
- to become readable
692
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
693
- current thread
694
-
695
- """
696
- return get_async_backend().wait_readable(sock.fileno())
697
-
698
-
699
- @deprecated("This function is deprecated; use `wait_writable` instead")
700
- def wait_socket_writable(sock: socket.socket) -> Awaitable[None]:
701
- """
702
- .. deprecated:: 4.7.0
703
- Use :func:`wait_writable` instead.
704
-
705
- Wait until the given socket can be written to.
706
-
707
- This does **NOT** work on Windows when using the asyncio backend with a proactor
708
- event loop (default on py3.8+).
709
-
710
- .. warning:: Only use this on raw sockets that have not been wrapped by any higher
711
- level constructs like socket streams!
712
-
713
- :param sock: a socket object
714
- :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the
715
- socket to become writable
716
- :raises ~anyio.BusyResourceError: if another task is already waiting for the socket
717
- to become writable
718
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
719
- current thread
720
-
721
- """
722
- return get_async_backend().wait_writable(sock.fileno())
723
-
724
-
725
- def wait_readable(obj: FileDescriptorLike) -> Awaitable[None]:
726
- """
727
- Wait until the given object has data to be read.
728
-
729
- On Unix systems, ``obj`` must either be an integer file descriptor, or else an
730
- object with a ``.fileno()`` method which returns an integer file descriptor. Any
731
- kind of file descriptor can be passed, though the exact semantics will depend on
732
- your kernel. For example, this probably won't do anything useful for on-disk files.
733
-
734
- On Windows systems, ``obj`` must either be an integer ``SOCKET`` handle, or else an
735
- object with a ``.fileno()`` method which returns an integer ``SOCKET`` handle. File
736
- descriptors aren't supported, and neither are handles that refer to anything besides
737
- a ``SOCKET``.
738
-
739
- On backends where this functionality is not natively provided (asyncio
740
- ``ProactorEventLoop`` on Windows), it is provided using a separate selector thread
741
- which is set to shut down when the interpreter shuts down.
742
-
743
- .. warning:: Don't use this on raw sockets that have been wrapped by any higher
744
- level constructs like socket streams!
745
-
746
- :param obj: an object with a ``.fileno()`` method or an integer handle
747
- :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the
748
- object to become readable
749
- :raises ~anyio.BusyResourceError: if another task is already waiting for the object
750
- to become readable
751
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
752
- current thread
753
-
754
- """
755
- return get_async_backend().wait_readable(obj)
756
-
757
-
758
- def wait_writable(obj: FileDescriptorLike) -> Awaitable[None]:
759
- """
760
- Wait until the given object can be written to.
761
-
762
- :param obj: an object with a ``.fileno()`` method or an integer handle
763
- :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the
764
- object to become writable
765
- :raises ~anyio.BusyResourceError: if another task is already waiting for the object
766
- to become writable
767
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
768
- current thread
769
-
770
- .. seealso:: See the documentation of :func:`wait_readable` for the definition of
771
- ``obj`` and notes on backend compatibility.
772
-
773
- .. warning:: Don't use this on raw sockets that have been wrapped by any higher
774
- level constructs like socket streams!
775
-
776
- """
777
- return get_async_backend().wait_writable(obj)
778
-
779
-
780
- def notify_closing(obj: FileDescriptorLike) -> None:
781
- """
782
- Call this before closing a file descriptor (on Unix) or socket (on
783
- Windows). This will cause any `wait_readable` or `wait_writable`
784
- calls on the given object to immediately wake up and raise
785
- `~anyio.ClosedResourceError`.
786
-
787
- This doesn't actually close the object – you still have to do that
788
- yourself afterwards. Also, you want to be careful to make sure no
789
- new tasks start waiting on the object in between when you call this
790
- and when it's actually closed. So to close something properly, you
791
- usually want to do these steps in order:
792
-
793
- 1. Explicitly mark the object as closed, so that any new attempts
794
- to use it will abort before they start.
795
- 2. Call `notify_closing` to wake up any already-existing users.
796
- 3. Actually close the object.
797
-
798
- It's also possible to do them in a different order if that's more
799
- convenient, *but only if* you make sure not to have any checkpoints in
800
- between the steps. This way they all happen in a single atomic
801
- step, so other tasks won't be able to tell what order they happened
802
- in anyway.
803
-
804
- :param obj: an object with a ``.fileno()`` method or an integer handle
805
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
806
- current thread
807
-
808
- """
809
- get_async_backend().notify_closing(obj)
810
-
811
-
812
- #
813
- # Private API
814
- #
815
-
816
-
817
- def convert_ipv6_sockaddr(
818
- sockaddr: tuple[str, int, int, int] | tuple[str, int],
819
- ) -> tuple[str, int]:
820
- """
821
- Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format.
822
-
823
- If the scope ID is nonzero, it is added to the address, separated with ``%``.
824
- Otherwise the flow id and scope id are simply cut off from the tuple.
825
- Any other kinds of socket addresses are returned as-is.
826
-
827
- :param sockaddr: the result of :meth:`~socket.socket.getsockname`
828
- :return: the converted socket address
829
-
830
- """
831
- # This is more complicated than it should be because of MyPy
832
- if isinstance(sockaddr, tuple) and len(sockaddr) == 4:
833
- host, port, flowinfo, scope_id = sockaddr
834
- if scope_id:
835
- # PyPy (as of v7.3.11) leaves the interface name in the result, so
836
- # we discard it and only get the scope ID from the end
837
- # (https://foss.heptapod.net/pypy/pypy/-/issues/3938)
838
- host = host.split("%")[0]
839
-
840
- # Add scope_id to the address
841
- return f"{host}%{scope_id}", port
842
- else:
843
- return host, port
844
- else:
845
- return sockaddr
846
-
847
-
848
- async def setup_unix_local_socket(
849
- path: None | str | bytes | PathLike[Any],
850
- mode: int | None,
851
- socktype: int,
852
- ) -> socket.socket:
853
- """
854
- Create a UNIX local socket object, deleting the socket at the given path if it
855
- exists.
856
-
857
- Not available on Windows.
858
-
859
- :param path: path of the socket
860
- :param mode: permissions to set on the socket
861
- :param socktype: socket.SOCK_STREAM or socket.SOCK_DGRAM
862
-
863
- """
864
- path_str: str | None
865
- if path is not None:
866
- path_str = os.fsdecode(path)
867
-
868
- # Linux abstract namespace sockets aren't backed by a concrete file so skip stat call
869
- if not path_str.startswith("\0"):
870
- # Copied from pathlib...
871
- try:
872
- stat_result = os.stat(path)
873
- except OSError as e:
874
- if e.errno not in (
875
- errno.ENOENT,
876
- errno.ENOTDIR,
877
- errno.EBADF,
878
- errno.ELOOP,
879
- ):
880
- raise
881
- else:
882
- if stat.S_ISSOCK(stat_result.st_mode):
883
- os.unlink(path)
884
- else:
885
- path_str = None
886
-
887
- raw_socket = socket.socket(socket.AF_UNIX, socktype)
888
- raw_socket.setblocking(False)
889
-
890
- if path_str is not None:
891
- try:
892
- await to_thread.run_sync(raw_socket.bind, path_str, abandon_on_cancel=True)
893
- if mode is not None:
894
- await to_thread.run_sync(chmod, path_str, mode, abandon_on_cancel=True)
895
- except BaseException:
896
- raw_socket.close()
897
- raise
898
-
899
- return raw_socket
900
-
901
-
902
- @dataclass
903
- class TCPConnectable(ByteStreamConnectable):
904
- """
905
- Connects to a TCP server at the given host and port.
906
-
907
- :param host: host name or IP address of the server
908
- :param port: TCP port number of the server
909
- """
910
-
911
- host: str | IPv4Address | IPv6Address
912
- port: int
913
-
914
- def __post_init__(self) -> None:
915
- if self.port < 1 or self.port > 65535:
916
- raise ValueError("TCP port number out of range")
917
-
918
- @override
919
- async def connect(self) -> SocketStream:
920
- try:
921
- return await connect_tcp(self.host, self.port)
922
- except OSError as exc:
923
- raise ConnectionFailed(
924
- f"error connecting to {self.host}:{self.port}: {exc}"
925
- ) from exc
926
-
927
-
928
- @dataclass
929
- class UNIXConnectable(ByteStreamConnectable):
930
- """
931
- Connects to a UNIX domain socket at the given path.
932
-
933
- :param path: the file system path of the socket
934
- """
935
-
936
- path: str | bytes | PathLike[str] | PathLike[bytes]
937
-
938
- @override
939
- async def connect(self) -> UNIXSocketStream:
940
- try:
941
- return await connect_unix(self.path)
942
- except OSError as exc:
943
- raise ConnectionFailed(f"error connecting to {self.path!r}: {exc}") from exc
944
-
945
-
946
- def as_connectable(
947
- remote: ByteStreamConnectable
948
- | tuple[str | IPv4Address | IPv6Address, int]
949
- | str
950
- | bytes
951
- | PathLike[str],
952
- /,
953
- *,
954
- tls: bool = False,
955
- ssl_context: ssl.SSLContext | None = None,
956
- tls_hostname: str | None = None,
957
- tls_standard_compatible: bool = True,
958
- ) -> ByteStreamConnectable:
959
- """
960
- Return a byte stream connectable from the given object.
961
-
962
- If a bytestream connectable is given, it is returned unchanged.
963
- If a tuple of (host, port) is given, a TCP connectable is returned.
964
- If a string or bytes path is given, a UNIX connectable is returned.
965
-
966
- If ``tls=True``, the connectable will be wrapped in a
967
- :class:`~.streams.tls.TLSConnectable`.
968
-
969
- :param remote: a connectable, a tuple of (host, port) or a path to a UNIX socket
970
- :param tls: if ``True``, wrap the plaintext connectable in a
971
- :class:`~.streams.tls.TLSConnectable`, using the provided TLS settings)
972
- :param ssl_context: if ``tls=True``, the SSLContext object to use (if not provided,
973
- a secure default will be created)
974
- :param tls_hostname: if ``tls=True``, host name of the server to use for checking
975
- the server certificate (defaults to the host portion of the address for TCP
976
- connectables)
977
- :param tls_standard_compatible: if ``False`` and ``tls=True``, makes the TLS stream
978
- skip the closing handshake when closing the connection, so it won't raise an
979
- exception if the server does the same
980
-
981
- """
982
- connectable: TCPConnectable | UNIXConnectable | TLSConnectable
983
- if isinstance(remote, ByteStreamConnectable):
984
- return remote
985
- elif isinstance(remote, tuple) and len(remote) == 2:
986
- connectable = TCPConnectable(*remote)
987
- elif isinstance(remote, (str, bytes, PathLike)):
988
- connectable = UNIXConnectable(remote)
989
- else:
990
- raise TypeError(f"cannot convert {remote!r} to a connectable")
991
-
992
- if tls:
993
- if not tls_hostname and isinstance(connectable, TCPConnectable):
994
- tls_hostname = str(connectable.host)
995
-
996
- connectable = TLSConnectable(
997
- connectable,
998
- ssl_context=ssl_context,
999
- hostname=tls_hostname,
1000
- standard_compatible=tls_standard_compatible,
1001
- )
1002
-
1003
- return connectable
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_streams.py DELETED
@@ -1,52 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import math
4
- from typing import TypeVar
5
- from warnings import warn
6
-
7
- from ..streams.memory import (
8
- MemoryObjectReceiveStream,
9
- MemoryObjectSendStream,
10
- _MemoryObjectStreamState,
11
- )
12
-
13
- T_Item = TypeVar("T_Item")
14
-
15
-
16
- class create_memory_object_stream(
17
- tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]],
18
- ):
19
- """
20
- Create a memory object stream.
21
-
22
- The stream's item type can be annotated like
23
- :func:`create_memory_object_stream[T_Item]`.
24
-
25
- :param max_buffer_size: number of items held in the buffer until ``send()`` starts
26
- blocking
27
- :param item_type: old way of marking the streams with the right generic type for
28
- static typing (does nothing on AnyIO 4)
29
-
30
- .. deprecated:: 4.0
31
- Use ``create_memory_object_stream[YourItemType](...)`` instead.
32
- :return: a tuple of (send stream, receive stream)
33
-
34
- """
35
-
36
- def __new__( # type: ignore[misc]
37
- cls, max_buffer_size: float = 0, item_type: object = None
38
- ) -> tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]:
39
- if max_buffer_size != math.inf and not isinstance(max_buffer_size, int):
40
- raise ValueError("max_buffer_size must be either an integer or math.inf")
41
- if max_buffer_size < 0:
42
- raise ValueError("max_buffer_size cannot be negative")
43
- if item_type is not None:
44
- warn(
45
- "The item_type argument has been deprecated in AnyIO 4.0. "
46
- "Use create_memory_object_stream[YourItemType](...) instead.",
47
- DeprecationWarning,
48
- stacklevel=2,
49
- )
50
-
51
- state = _MemoryObjectStreamState[T_Item](max_buffer_size)
52
- return (MemoryObjectSendStream(state), MemoryObjectReceiveStream(state))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_subprocesses.py DELETED
@@ -1,202 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import sys
4
- from collections.abc import AsyncIterable, Iterable, Mapping, Sequence
5
- from io import BytesIO
6
- from os import PathLike
7
- from subprocess import PIPE, CalledProcessError, CompletedProcess
8
- from typing import IO, Any, Union, cast
9
-
10
- from ..abc import Process
11
- from ._eventloop import get_async_backend
12
- from ._tasks import create_task_group
13
-
14
- if sys.version_info >= (3, 10):
15
- from typing import TypeAlias
16
- else:
17
- from typing_extensions import TypeAlias
18
-
19
- StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"]
20
-
21
-
22
- async def run_process(
23
- command: StrOrBytesPath | Sequence[StrOrBytesPath],
24
- *,
25
- input: bytes | None = None,
26
- stdin: int | IO[Any] | None = None,
27
- stdout: int | IO[Any] | None = PIPE,
28
- stderr: int | IO[Any] | None = PIPE,
29
- check: bool = True,
30
- cwd: StrOrBytesPath | None = None,
31
- env: Mapping[str, str] | None = None,
32
- startupinfo: Any = None,
33
- creationflags: int = 0,
34
- start_new_session: bool = False,
35
- pass_fds: Sequence[int] = (),
36
- user: str | int | None = None,
37
- group: str | int | None = None,
38
- extra_groups: Iterable[str | int] | None = None,
39
- umask: int = -1,
40
- ) -> CompletedProcess[bytes]:
41
- """
42
- Run an external command in a subprocess and wait until it completes.
43
-
44
- .. seealso:: :func:`subprocess.run`
45
-
46
- :param command: either a string to pass to the shell, or an iterable of strings
47
- containing the executable name or path and its arguments
48
- :param input: bytes passed to the standard input of the subprocess
49
- :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
50
- a file-like object, or `None`; ``input`` overrides this
51
- :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
52
- a file-like object, or `None`
53
- :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
54
- :data:`subprocess.STDOUT`, a file-like object, or `None`
55
- :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the
56
- process terminates with a return code other than 0
57
- :param cwd: If not ``None``, change the working directory to this before running the
58
- command
59
- :param env: if not ``None``, this mapping replaces the inherited environment
60
- variables from the parent process
61
- :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used
62
- to specify process startup parameters (Windows only)
63
- :param creationflags: flags that can be used to control the creation of the
64
- subprocess (see :class:`subprocess.Popen` for the specifics)
65
- :param start_new_session: if ``true`` the setsid() system call will be made in the
66
- child process prior to the execution of the subprocess. (POSIX only)
67
- :param pass_fds: sequence of file descriptors to keep open between the parent and
68
- child processes. (POSIX only)
69
- :param user: effective user to run the process as (Python >= 3.9, POSIX only)
70
- :param group: effective group to run the process as (Python >= 3.9, POSIX only)
71
- :param extra_groups: supplementary groups to set in the subprocess (Python >= 3.9,
72
- POSIX only)
73
- :param umask: if not negative, this umask is applied in the child process before
74
- running the given command (Python >= 3.9, POSIX only)
75
- :return: an object representing the completed process
76
- :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process
77
- exits with a nonzero return code
78
-
79
- """
80
-
81
- async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None:
82
- buffer = BytesIO()
83
- async for chunk in stream:
84
- buffer.write(chunk)
85
-
86
- stream_contents[index] = buffer.getvalue()
87
-
88
- if stdin is not None and input is not None:
89
- raise ValueError("only one of stdin and input is allowed")
90
-
91
- async with await open_process(
92
- command,
93
- stdin=PIPE if input else stdin,
94
- stdout=stdout,
95
- stderr=stderr,
96
- cwd=cwd,
97
- env=env,
98
- startupinfo=startupinfo,
99
- creationflags=creationflags,
100
- start_new_session=start_new_session,
101
- pass_fds=pass_fds,
102
- user=user,
103
- group=group,
104
- extra_groups=extra_groups,
105
- umask=umask,
106
- ) as process:
107
- stream_contents: list[bytes | None] = [None, None]
108
- async with create_task_group() as tg:
109
- if process.stdout:
110
- tg.start_soon(drain_stream, process.stdout, 0)
111
-
112
- if process.stderr:
113
- tg.start_soon(drain_stream, process.stderr, 1)
114
-
115
- if process.stdin and input:
116
- await process.stdin.send(input)
117
- await process.stdin.aclose()
118
-
119
- await process.wait()
120
-
121
- output, errors = stream_contents
122
- if check and process.returncode != 0:
123
- raise CalledProcessError(cast(int, process.returncode), command, output, errors)
124
-
125
- return CompletedProcess(command, cast(int, process.returncode), output, errors)
126
-
127
-
128
- async def open_process(
129
- command: StrOrBytesPath | Sequence[StrOrBytesPath],
130
- *,
131
- stdin: int | IO[Any] | None = PIPE,
132
- stdout: int | IO[Any] | None = PIPE,
133
- stderr: int | IO[Any] | None = PIPE,
134
- cwd: StrOrBytesPath | None = None,
135
- env: Mapping[str, str] | None = None,
136
- startupinfo: Any = None,
137
- creationflags: int = 0,
138
- start_new_session: bool = False,
139
- pass_fds: Sequence[int] = (),
140
- user: str | int | None = None,
141
- group: str | int | None = None,
142
- extra_groups: Iterable[str | int] | None = None,
143
- umask: int = -1,
144
- ) -> Process:
145
- """
146
- Start an external command in a subprocess.
147
-
148
- .. seealso:: :class:`subprocess.Popen`
149
-
150
- :param command: either a string to pass to the shell, or an iterable of strings
151
- containing the executable name or path and its arguments
152
- :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a
153
- file-like object, or ``None``
154
- :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
155
- a file-like object, or ``None``
156
- :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
157
- :data:`subprocess.STDOUT`, a file-like object, or ``None``
158
- :param cwd: If not ``None``, the working directory is changed before executing
159
- :param env: If env is not ``None``, it must be a mapping that defines the
160
- environment variables for the new process
161
- :param creationflags: flags that can be used to control the creation of the
162
- subprocess (see :class:`subprocess.Popen` for the specifics)
163
- :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used
164
- to specify process startup parameters (Windows only)
165
- :param start_new_session: if ``true`` the setsid() system call will be made in the
166
- child process prior to the execution of the subprocess. (POSIX only)
167
- :param pass_fds: sequence of file descriptors to keep open between the parent and
168
- child processes. (POSIX only)
169
- :param user: effective user to run the process as (POSIX only)
170
- :param group: effective group to run the process as (POSIX only)
171
- :param extra_groups: supplementary groups to set in the subprocess (POSIX only)
172
- :param umask: if not negative, this umask is applied in the child process before
173
- running the given command (POSIX only)
174
- :return: an asynchronous process object
175
-
176
- """
177
- kwargs: dict[str, Any] = {}
178
- if user is not None:
179
- kwargs["user"] = user
180
-
181
- if group is not None:
182
- kwargs["group"] = group
183
-
184
- if extra_groups is not None:
185
- kwargs["extra_groups"] = group
186
-
187
- if umask >= 0:
188
- kwargs["umask"] = umask
189
-
190
- return await get_async_backend().open_process(
191
- command,
192
- stdin=stdin,
193
- stdout=stdout,
194
- stderr=stderr,
195
- cwd=cwd,
196
- env=env,
197
- startupinfo=startupinfo,
198
- creationflags=creationflags,
199
- start_new_session=start_new_session,
200
- pass_fds=pass_fds,
201
- **kwargs,
202
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_synchronization.py DELETED
@@ -1,753 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import math
4
- from collections import deque
5
- from collections.abc import Callable
6
- from dataclasses import dataclass
7
- from types import TracebackType
8
- from typing import TypeVar
9
-
10
- from ..lowlevel import checkpoint_if_cancelled
11
- from ._eventloop import get_async_backend
12
- from ._exceptions import BusyResourceError, NoEventLoopError
13
- from ._tasks import CancelScope
14
- from ._testing import TaskInfo, get_current_task
15
-
16
- T = TypeVar("T")
17
-
18
-
19
- @dataclass(frozen=True)
20
- class EventStatistics:
21
- """
22
- :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait`
23
- """
24
-
25
- tasks_waiting: int
26
-
27
-
28
- @dataclass(frozen=True)
29
- class CapacityLimiterStatistics:
30
- """
31
- :ivar int borrowed_tokens: number of tokens currently borrowed by tasks
32
- :ivar float total_tokens: total number of available tokens
33
- :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from
34
- this limiter
35
- :ivar int tasks_waiting: number of tasks waiting on
36
- :meth:`~.CapacityLimiter.acquire` or
37
- :meth:`~.CapacityLimiter.acquire_on_behalf_of`
38
- """
39
-
40
- borrowed_tokens: int
41
- total_tokens: float
42
- borrowers: tuple[object, ...]
43
- tasks_waiting: int
44
-
45
-
46
- @dataclass(frozen=True)
47
- class LockStatistics:
48
- """
49
- :ivar bool locked: flag indicating if this lock is locked or not
50
- :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the
51
- lock is not held by any task)
52
- :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire`
53
- """
54
-
55
- locked: bool
56
- owner: TaskInfo | None
57
- tasks_waiting: int
58
-
59
-
60
- @dataclass(frozen=True)
61
- class ConditionStatistics:
62
- """
63
- :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait`
64
- :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying
65
- :class:`~.Lock`
66
- """
67
-
68
- tasks_waiting: int
69
- lock_statistics: LockStatistics
70
-
71
-
72
- @dataclass(frozen=True)
73
- class SemaphoreStatistics:
74
- """
75
- :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire`
76
-
77
- """
78
-
79
- tasks_waiting: int
80
-
81
-
82
- class Event:
83
- def __new__(cls) -> Event:
84
- try:
85
- return get_async_backend().create_event()
86
- except NoEventLoopError:
87
- return EventAdapter()
88
-
89
- def set(self) -> None:
90
- """Set the flag, notifying all listeners."""
91
- raise NotImplementedError
92
-
93
- def is_set(self) -> bool:
94
- """Return ``True`` if the flag is set, ``False`` if not."""
95
- raise NotImplementedError
96
-
97
- async def wait(self) -> None:
98
- """
99
- Wait until the flag has been set.
100
-
101
- If the flag has already been set when this method is called, it returns
102
- immediately.
103
-
104
- """
105
- raise NotImplementedError
106
-
107
- def statistics(self) -> EventStatistics:
108
- """Return statistics about the current state of this event."""
109
- raise NotImplementedError
110
-
111
-
112
- class EventAdapter(Event):
113
- _internal_event: Event | None = None
114
- _is_set: bool = False
115
-
116
- def __new__(cls) -> EventAdapter:
117
- return object.__new__(cls)
118
-
119
- @property
120
- def _event(self) -> Event:
121
- if self._internal_event is None:
122
- self._internal_event = get_async_backend().create_event()
123
- if self._is_set:
124
- self._internal_event.set()
125
-
126
- return self._internal_event
127
-
128
- def set(self) -> None:
129
- if self._internal_event is None:
130
- self._is_set = True
131
- else:
132
- self._event.set()
133
-
134
- def is_set(self) -> bool:
135
- if self._internal_event is None:
136
- return self._is_set
137
-
138
- return self._internal_event.is_set()
139
-
140
- async def wait(self) -> None:
141
- await self._event.wait()
142
-
143
- def statistics(self) -> EventStatistics:
144
- if self._internal_event is None:
145
- return EventStatistics(tasks_waiting=0)
146
-
147
- return self._internal_event.statistics()
148
-
149
-
150
- class Lock:
151
- def __new__(cls, *, fast_acquire: bool = False) -> Lock:
152
- try:
153
- return get_async_backend().create_lock(fast_acquire=fast_acquire)
154
- except NoEventLoopError:
155
- return LockAdapter(fast_acquire=fast_acquire)
156
-
157
- async def __aenter__(self) -> None:
158
- await self.acquire()
159
-
160
- async def __aexit__(
161
- self,
162
- exc_type: type[BaseException] | None,
163
- exc_val: BaseException | None,
164
- exc_tb: TracebackType | None,
165
- ) -> None:
166
- self.release()
167
-
168
- async def acquire(self) -> None:
169
- """Acquire the lock."""
170
- raise NotImplementedError
171
-
172
- def acquire_nowait(self) -> None:
173
- """
174
- Acquire the lock, without blocking.
175
-
176
- :raises ~anyio.WouldBlock: if the operation would block
177
-
178
- """
179
- raise NotImplementedError
180
-
181
- def release(self) -> None:
182
- """Release the lock."""
183
- raise NotImplementedError
184
-
185
- def locked(self) -> bool:
186
- """Return True if the lock is currently held."""
187
- raise NotImplementedError
188
-
189
- def statistics(self) -> LockStatistics:
190
- """
191
- Return statistics about the current state of this lock.
192
-
193
- .. versionadded:: 3.0
194
- """
195
- raise NotImplementedError
196
-
197
-
198
- class LockAdapter(Lock):
199
- _internal_lock: Lock | None = None
200
-
201
- def __new__(cls, *, fast_acquire: bool = False) -> LockAdapter:
202
- return object.__new__(cls)
203
-
204
- def __init__(self, *, fast_acquire: bool = False):
205
- self._fast_acquire = fast_acquire
206
-
207
- @property
208
- def _lock(self) -> Lock:
209
- if self._internal_lock is None:
210
- self._internal_lock = get_async_backend().create_lock(
211
- fast_acquire=self._fast_acquire
212
- )
213
-
214
- return self._internal_lock
215
-
216
- async def __aenter__(self) -> None:
217
- await self._lock.acquire()
218
-
219
- async def __aexit__(
220
- self,
221
- exc_type: type[BaseException] | None,
222
- exc_val: BaseException | None,
223
- exc_tb: TracebackType | None,
224
- ) -> None:
225
- if self._internal_lock is not None:
226
- self._internal_lock.release()
227
-
228
- async def acquire(self) -> None:
229
- """Acquire the lock."""
230
- await self._lock.acquire()
231
-
232
- def acquire_nowait(self) -> None:
233
- """
234
- Acquire the lock, without blocking.
235
-
236
- :raises ~anyio.WouldBlock: if the operation would block
237
-
238
- """
239
- self._lock.acquire_nowait()
240
-
241
- def release(self) -> None:
242
- """Release the lock."""
243
- self._lock.release()
244
-
245
- def locked(self) -> bool:
246
- """Return True if the lock is currently held."""
247
- return self._lock.locked()
248
-
249
- def statistics(self) -> LockStatistics:
250
- """
251
- Return statistics about the current state of this lock.
252
-
253
- .. versionadded:: 3.0
254
-
255
- """
256
- if self._internal_lock is None:
257
- return LockStatistics(False, None, 0)
258
-
259
- return self._internal_lock.statistics()
260
-
261
-
262
- class Condition:
263
- _owner_task: TaskInfo | None = None
264
-
265
- def __init__(self, lock: Lock | None = None):
266
- self._lock = lock or Lock()
267
- self._waiters: deque[Event] = deque()
268
-
269
- async def __aenter__(self) -> None:
270
- await self.acquire()
271
-
272
- async def __aexit__(
273
- self,
274
- exc_type: type[BaseException] | None,
275
- exc_val: BaseException | None,
276
- exc_tb: TracebackType | None,
277
- ) -> None:
278
- self.release()
279
-
280
- def _check_acquired(self) -> None:
281
- if self._owner_task != get_current_task():
282
- raise RuntimeError("The current task is not holding the underlying lock")
283
-
284
- async def acquire(self) -> None:
285
- """Acquire the underlying lock."""
286
- await self._lock.acquire()
287
- self._owner_task = get_current_task()
288
-
289
- def acquire_nowait(self) -> None:
290
- """
291
- Acquire the underlying lock, without blocking.
292
-
293
- :raises ~anyio.WouldBlock: if the operation would block
294
-
295
- """
296
- self._lock.acquire_nowait()
297
- self._owner_task = get_current_task()
298
-
299
- def release(self) -> None:
300
- """Release the underlying lock."""
301
- self._lock.release()
302
-
303
- def locked(self) -> bool:
304
- """Return True if the lock is set."""
305
- return self._lock.locked()
306
-
307
- def notify(self, n: int = 1) -> None:
308
- """Notify exactly n listeners."""
309
- self._check_acquired()
310
- for _ in range(n):
311
- try:
312
- event = self._waiters.popleft()
313
- except IndexError:
314
- break
315
-
316
- event.set()
317
-
318
- def notify_all(self) -> None:
319
- """Notify all the listeners."""
320
- self._check_acquired()
321
- for event in self._waiters:
322
- event.set()
323
-
324
- self._waiters.clear()
325
-
326
- async def wait(self) -> None:
327
- """Wait for a notification."""
328
- await checkpoint_if_cancelled()
329
- self._check_acquired()
330
- event = Event()
331
- self._waiters.append(event)
332
- self.release()
333
- try:
334
- await event.wait()
335
- except BaseException:
336
- if not event.is_set():
337
- self._waiters.remove(event)
338
-
339
- raise
340
- finally:
341
- with CancelScope(shield=True):
342
- await self.acquire()
343
-
344
- async def wait_for(self, predicate: Callable[[], T]) -> T:
345
- """
346
- Wait until a predicate becomes true.
347
-
348
- :param predicate: a callable that returns a truthy value when the condition is
349
- met
350
- :return: the result of the predicate
351
-
352
- .. versionadded:: 4.11.0
353
-
354
- """
355
- while not (result := predicate()):
356
- await self.wait()
357
-
358
- return result
359
-
360
- def statistics(self) -> ConditionStatistics:
361
- """
362
- Return statistics about the current state of this condition.
363
-
364
- .. versionadded:: 3.0
365
- """
366
- return ConditionStatistics(len(self._waiters), self._lock.statistics())
367
-
368
-
369
- class Semaphore:
370
- def __new__(
371
- cls,
372
- initial_value: int,
373
- *,
374
- max_value: int | None = None,
375
- fast_acquire: bool = False,
376
- ) -> Semaphore:
377
- try:
378
- return get_async_backend().create_semaphore(
379
- initial_value, max_value=max_value, fast_acquire=fast_acquire
380
- )
381
- except NoEventLoopError:
382
- return SemaphoreAdapter(initial_value, max_value=max_value)
383
-
384
- def __init__(
385
- self,
386
- initial_value: int,
387
- *,
388
- max_value: int | None = None,
389
- fast_acquire: bool = False,
390
- ):
391
- if not isinstance(initial_value, int):
392
- raise TypeError("initial_value must be an integer")
393
- if initial_value < 0:
394
- raise ValueError("initial_value must be >= 0")
395
- if max_value is not None:
396
- if not isinstance(max_value, int):
397
- raise TypeError("max_value must be an integer or None")
398
- if max_value < initial_value:
399
- raise ValueError(
400
- "max_value must be equal to or higher than initial_value"
401
- )
402
-
403
- self._fast_acquire = fast_acquire
404
-
405
- async def __aenter__(self) -> Semaphore:
406
- await self.acquire()
407
- return self
408
-
409
- async def __aexit__(
410
- self,
411
- exc_type: type[BaseException] | None,
412
- exc_val: BaseException | None,
413
- exc_tb: TracebackType | None,
414
- ) -> None:
415
- self.release()
416
-
417
- async def acquire(self) -> None:
418
- """Decrement the semaphore value, blocking if necessary."""
419
- raise NotImplementedError
420
-
421
- def acquire_nowait(self) -> None:
422
- """
423
- Acquire the underlying lock, without blocking.
424
-
425
- :raises ~anyio.WouldBlock: if the operation would block
426
-
427
- """
428
- raise NotImplementedError
429
-
430
- def release(self) -> None:
431
- """Increment the semaphore value."""
432
- raise NotImplementedError
433
-
434
- @property
435
- def value(self) -> int:
436
- """The current value of the semaphore."""
437
- raise NotImplementedError
438
-
439
- @property
440
- def max_value(self) -> int | None:
441
- """The maximum value of the semaphore."""
442
- raise NotImplementedError
443
-
444
- def statistics(self) -> SemaphoreStatistics:
445
- """
446
- Return statistics about the current state of this semaphore.
447
-
448
- .. versionadded:: 3.0
449
- """
450
- raise NotImplementedError
451
-
452
-
453
- class SemaphoreAdapter(Semaphore):
454
- _internal_semaphore: Semaphore | None = None
455
-
456
- def __new__(
457
- cls,
458
- initial_value: int,
459
- *,
460
- max_value: int | None = None,
461
- fast_acquire: bool = False,
462
- ) -> SemaphoreAdapter:
463
- return object.__new__(cls)
464
-
465
- def __init__(
466
- self,
467
- initial_value: int,
468
- *,
469
- max_value: int | None = None,
470
- fast_acquire: bool = False,
471
- ) -> None:
472
- super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
473
- self._initial_value = initial_value
474
- self._max_value = max_value
475
-
476
- @property
477
- def _semaphore(self) -> Semaphore:
478
- if self._internal_semaphore is None:
479
- self._internal_semaphore = get_async_backend().create_semaphore(
480
- self._initial_value, max_value=self._max_value
481
- )
482
-
483
- return self._internal_semaphore
484
-
485
- async def acquire(self) -> None:
486
- await self._semaphore.acquire()
487
-
488
- def acquire_nowait(self) -> None:
489
- self._semaphore.acquire_nowait()
490
-
491
- def release(self) -> None:
492
- self._semaphore.release()
493
-
494
- @property
495
- def value(self) -> int:
496
- if self._internal_semaphore is None:
497
- return self._initial_value
498
-
499
- return self._semaphore.value
500
-
501
- @property
502
- def max_value(self) -> int | None:
503
- return self._max_value
504
-
505
- def statistics(self) -> SemaphoreStatistics:
506
- if self._internal_semaphore is None:
507
- return SemaphoreStatistics(tasks_waiting=0)
508
-
509
- return self._semaphore.statistics()
510
-
511
-
512
- class CapacityLimiter:
513
- def __new__(cls, total_tokens: float) -> CapacityLimiter:
514
- try:
515
- return get_async_backend().create_capacity_limiter(total_tokens)
516
- except NoEventLoopError:
517
- return CapacityLimiterAdapter(total_tokens)
518
-
519
- async def __aenter__(self) -> None:
520
- raise NotImplementedError
521
-
522
- async def __aexit__(
523
- self,
524
- exc_type: type[BaseException] | None,
525
- exc_val: BaseException | None,
526
- exc_tb: TracebackType | None,
527
- ) -> None:
528
- raise NotImplementedError
529
-
530
- @property
531
- def total_tokens(self) -> float:
532
- """
533
- The total number of tokens available for borrowing.
534
-
535
- This is a read-write property. If the total number of tokens is increased, the
536
- proportionate number of tasks waiting on this limiter will be granted their
537
- tokens.
538
-
539
- .. versionchanged:: 3.0
540
- The property is now writable.
541
- .. versionchanged:: 4.12
542
- The value can now be set to 0.
543
-
544
- """
545
- raise NotImplementedError
546
-
547
- @total_tokens.setter
548
- def total_tokens(self, value: float) -> None:
549
- raise NotImplementedError
550
-
551
- @property
552
- def borrowed_tokens(self) -> int:
553
- """The number of tokens that have currently been borrowed."""
554
- raise NotImplementedError
555
-
556
- @property
557
- def available_tokens(self) -> float:
558
- """The number of tokens currently available to be borrowed"""
559
- raise NotImplementedError
560
-
561
- def acquire_nowait(self) -> None:
562
- """
563
- Acquire a token for the current task without waiting for one to become
564
- available.
565
-
566
- :raises ~anyio.WouldBlock: if there are no tokens available for borrowing
567
-
568
- """
569
- raise NotImplementedError
570
-
571
- def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
572
- """
573
- Acquire a token without waiting for one to become available.
574
-
575
- :param borrower: the entity borrowing a token
576
- :raises ~anyio.WouldBlock: if there are no tokens available for borrowing
577
-
578
- """
579
- raise NotImplementedError
580
-
581
- async def acquire(self) -> None:
582
- """
583
- Acquire a token for the current task, waiting if necessary for one to become
584
- available.
585
-
586
- """
587
- raise NotImplementedError
588
-
589
- async def acquire_on_behalf_of(self, borrower: object) -> None:
590
- """
591
- Acquire a token, waiting if necessary for one to become available.
592
-
593
- :param borrower: the entity borrowing a token
594
-
595
- """
596
- raise NotImplementedError
597
-
598
- def release(self) -> None:
599
- """
600
- Release the token held by the current task.
601
-
602
- :raises RuntimeError: if the current task has not borrowed a token from this
603
- limiter.
604
-
605
- """
606
- raise NotImplementedError
607
-
608
- def release_on_behalf_of(self, borrower: object) -> None:
609
- """
610
- Release the token held by the given borrower.
611
-
612
- :raises RuntimeError: if the borrower has not borrowed a token from this
613
- limiter.
614
-
615
- """
616
- raise NotImplementedError
617
-
618
- def statistics(self) -> CapacityLimiterStatistics:
619
- """
620
- Return statistics about the current state of this limiter.
621
-
622
- .. versionadded:: 3.0
623
-
624
- """
625
- raise NotImplementedError
626
-
627
-
628
- class CapacityLimiterAdapter(CapacityLimiter):
629
- _internal_limiter: CapacityLimiter | None = None
630
-
631
- def __new__(cls, total_tokens: float) -> CapacityLimiterAdapter:
632
- return object.__new__(cls)
633
-
634
- def __init__(self, total_tokens: float) -> None:
635
- self.total_tokens = total_tokens
636
-
637
- @property
638
- def _limiter(self) -> CapacityLimiter:
639
- if self._internal_limiter is None:
640
- self._internal_limiter = get_async_backend().create_capacity_limiter(
641
- self._total_tokens
642
- )
643
-
644
- return self._internal_limiter
645
-
646
- async def __aenter__(self) -> None:
647
- await self._limiter.__aenter__()
648
-
649
- async def __aexit__(
650
- self,
651
- exc_type: type[BaseException] | None,
652
- exc_val: BaseException | None,
653
- exc_tb: TracebackType | None,
654
- ) -> None:
655
- return await self._limiter.__aexit__(exc_type, exc_val, exc_tb)
656
-
657
- @property
658
- def total_tokens(self) -> float:
659
- if self._internal_limiter is None:
660
- return self._total_tokens
661
-
662
- return self._internal_limiter.total_tokens
663
-
664
- @total_tokens.setter
665
- def total_tokens(self, value: float) -> None:
666
- if not isinstance(value, int) and value is not math.inf:
667
- raise TypeError("total_tokens must be an int or math.inf")
668
- elif value < 1:
669
- raise ValueError("total_tokens must be >= 1")
670
-
671
- if self._internal_limiter is None:
672
- self._total_tokens = value
673
- return
674
-
675
- self._limiter.total_tokens = value
676
-
677
- @property
678
- def borrowed_tokens(self) -> int:
679
- if self._internal_limiter is None:
680
- return 0
681
-
682
- return self._internal_limiter.borrowed_tokens
683
-
684
- @property
685
- def available_tokens(self) -> float:
686
- if self._internal_limiter is None:
687
- return self._total_tokens
688
-
689
- return self._internal_limiter.available_tokens
690
-
691
- def acquire_nowait(self) -> None:
692
- self._limiter.acquire_nowait()
693
-
694
- def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
695
- self._limiter.acquire_on_behalf_of_nowait(borrower)
696
-
697
- async def acquire(self) -> None:
698
- await self._limiter.acquire()
699
-
700
- async def acquire_on_behalf_of(self, borrower: object) -> None:
701
- await self._limiter.acquire_on_behalf_of(borrower)
702
-
703
- def release(self) -> None:
704
- self._limiter.release()
705
-
706
- def release_on_behalf_of(self, borrower: object) -> None:
707
- self._limiter.release_on_behalf_of(borrower)
708
-
709
- def statistics(self) -> CapacityLimiterStatistics:
710
- if self._internal_limiter is None:
711
- return CapacityLimiterStatistics(
712
- borrowed_tokens=0,
713
- total_tokens=self.total_tokens,
714
- borrowers=(),
715
- tasks_waiting=0,
716
- )
717
-
718
- return self._internal_limiter.statistics()
719
-
720
-
721
- class ResourceGuard:
722
- """
723
- A context manager for ensuring that a resource is only used by a single task at a
724
- time.
725
-
726
- Entering this context manager while the previous has not exited it yet will trigger
727
- :exc:`BusyResourceError`.
728
-
729
- :param action: the action to guard against (visible in the :exc:`BusyResourceError`
730
- when triggered, e.g. "Another task is already {action} this resource")
731
-
732
- .. versionadded:: 4.1
733
- """
734
-
735
- __slots__ = "action", "_guarded"
736
-
737
- def __init__(self, action: str = "using"):
738
- self.action: str = action
739
- self._guarded = False
740
-
741
- def __enter__(self) -> None:
742
- if self._guarded:
743
- raise BusyResourceError(self.action)
744
-
745
- self._guarded = True
746
-
747
- def __exit__(
748
- self,
749
- exc_type: type[BaseException] | None,
750
- exc_val: BaseException | None,
751
- exc_tb: TracebackType | None,
752
- ) -> None:
753
- self._guarded = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_tasks.py DELETED
@@ -1,173 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import math
4
- from collections.abc import Generator
5
- from contextlib import contextmanager
6
- from types import TracebackType
7
-
8
- from ..abc._tasks import TaskGroup, TaskStatus
9
- from ._eventloop import get_async_backend
10
-
11
-
12
- class _IgnoredTaskStatus(TaskStatus[object]):
13
- def started(self, value: object = None) -> None:
14
- pass
15
-
16
-
17
- TASK_STATUS_IGNORED = _IgnoredTaskStatus()
18
-
19
-
20
- class CancelScope:
21
- """
22
- Wraps a unit of work that can be made separately cancellable.
23
-
24
- :param deadline: The time (clock value) when this scope is cancelled automatically
25
- :param shield: ``True`` to shield the cancel scope from external cancellation
26
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
27
- current thread
28
- """
29
-
30
- def __new__(
31
- cls, *, deadline: float = math.inf, shield: bool = False
32
- ) -> CancelScope:
33
- return get_async_backend().create_cancel_scope(shield=shield, deadline=deadline)
34
-
35
- def cancel(self, reason: str | None = None) -> None:
36
- """
37
- Cancel this scope immediately.
38
-
39
- :param reason: a message describing the reason for the cancellation
40
-
41
- """
42
- raise NotImplementedError
43
-
44
- @property
45
- def deadline(self) -> float:
46
- """
47
- The time (clock value) when this scope is cancelled automatically.
48
-
49
- Will be ``float('inf')`` if no timeout has been set.
50
-
51
- """
52
- raise NotImplementedError
53
-
54
- @deadline.setter
55
- def deadline(self, value: float) -> None:
56
- raise NotImplementedError
57
-
58
- @property
59
- def cancel_called(self) -> bool:
60
- """``True`` if :meth:`cancel` has been called."""
61
- raise NotImplementedError
62
-
63
- @property
64
- def cancelled_caught(self) -> bool:
65
- """
66
- ``True`` if this scope suppressed a cancellation exception it itself raised.
67
-
68
- This is typically used to check if any work was interrupted, or to see if the
69
- scope was cancelled due to its deadline being reached. The value will, however,
70
- only be ``True`` if the cancellation was triggered by the scope itself (and not
71
- an outer scope).
72
-
73
- """
74
- raise NotImplementedError
75
-
76
- @property
77
- def shield(self) -> bool:
78
- """
79
- ``True`` if this scope is shielded from external cancellation.
80
-
81
- While a scope is shielded, it will not receive cancellations from outside.
82
-
83
- """
84
- raise NotImplementedError
85
-
86
- @shield.setter
87
- def shield(self, value: bool) -> None:
88
- raise NotImplementedError
89
-
90
- def __enter__(self) -> CancelScope:
91
- raise NotImplementedError
92
-
93
- def __exit__(
94
- self,
95
- exc_type: type[BaseException] | None,
96
- exc_val: BaseException | None,
97
- exc_tb: TracebackType | None,
98
- ) -> bool:
99
- raise NotImplementedError
100
-
101
-
102
- @contextmanager
103
- def fail_after(
104
- delay: float | None, shield: bool = False
105
- ) -> Generator[CancelScope, None, None]:
106
- """
107
- Create a context manager which raises a :class:`TimeoutError` if does not finish in
108
- time.
109
-
110
- :param delay: maximum allowed time (in seconds) before raising the exception, or
111
- ``None`` to disable the timeout
112
- :param shield: ``True`` to shield the cancel scope from external cancellation
113
- :return: a context manager that yields a cancel scope
114
- :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\]
115
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
116
- current thread
117
-
118
- """
119
- current_time = get_async_backend().current_time
120
- deadline = (current_time() + delay) if delay is not None else math.inf
121
- with get_async_backend().create_cancel_scope(
122
- deadline=deadline, shield=shield
123
- ) as cancel_scope:
124
- yield cancel_scope
125
-
126
- if cancel_scope.cancelled_caught and current_time() >= cancel_scope.deadline:
127
- raise TimeoutError
128
-
129
-
130
- def move_on_after(delay: float | None, shield: bool = False) -> CancelScope:
131
- """
132
- Create a cancel scope with a deadline that expires after the given delay.
133
-
134
- :param delay: maximum allowed time (in seconds) before exiting the context block, or
135
- ``None`` to disable the timeout
136
- :param shield: ``True`` to shield the cancel scope from external cancellation
137
- :return: a cancel scope
138
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
139
- current thread
140
-
141
- """
142
- deadline = (
143
- (get_async_backend().current_time() + delay) if delay is not None else math.inf
144
- )
145
- return get_async_backend().create_cancel_scope(deadline=deadline, shield=shield)
146
-
147
-
148
- def current_effective_deadline() -> float:
149
- """
150
- Return the nearest deadline among all the cancel scopes effective for the current
151
- task.
152
-
153
- :return: a clock value from the event loop's internal clock (or ``float('inf')`` if
154
- there is no deadline in effect, or ``float('-inf')`` if the current scope has
155
- been cancelled)
156
- :rtype: float
157
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
158
- current thread
159
-
160
- """
161
- return get_async_backend().current_effective_deadline()
162
-
163
-
164
- def create_task_group() -> TaskGroup:
165
- """
166
- Create a task group.
167
-
168
- :return: a task group
169
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
170
- current thread
171
-
172
- """
173
- return get_async_backend().create_task_group()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_tempfile.py DELETED
@@ -1,616 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import os
4
- import sys
5
- import tempfile
6
- from collections.abc import Iterable
7
- from io import BytesIO, TextIOWrapper
8
- from types import TracebackType
9
- from typing import (
10
- TYPE_CHECKING,
11
- Any,
12
- AnyStr,
13
- Generic,
14
- overload,
15
- )
16
-
17
- from .. import to_thread
18
- from .._core._fileio import AsyncFile
19
- from ..lowlevel import checkpoint_if_cancelled
20
-
21
- if TYPE_CHECKING:
22
- from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
23
-
24
-
25
- class TemporaryFile(Generic[AnyStr]):
26
- """
27
- An asynchronous temporary file that is automatically created and cleaned up.
28
-
29
- This class provides an asynchronous context manager interface to a temporary file.
30
- The file is created using Python's standard `tempfile.TemporaryFile` function in a
31
- background thread, and is wrapped as an asynchronous file using `AsyncFile`.
32
-
33
- :param mode: The mode in which the file is opened. Defaults to "w+b".
34
- :param buffering: The buffering policy (-1 means the default buffering).
35
- :param encoding: The encoding used to decode or encode the file. Only applicable in
36
- text mode.
37
- :param newline: Controls how universal newlines mode works (only applicable in text
38
- mode).
39
- :param suffix: The suffix for the temporary file name.
40
- :param prefix: The prefix for the temporary file name.
41
- :param dir: The directory in which the temporary file is created.
42
- :param errors: The error handling scheme used for encoding/decoding errors.
43
- """
44
-
45
- _async_file: AsyncFile[AnyStr]
46
-
47
- @overload
48
- def __init__(
49
- self: TemporaryFile[bytes],
50
- mode: OpenBinaryMode = ...,
51
- buffering: int = ...,
52
- encoding: str | None = ...,
53
- newline: str | None = ...,
54
- suffix: str | None = ...,
55
- prefix: str | None = ...,
56
- dir: str | None = ...,
57
- *,
58
- errors: str | None = ...,
59
- ): ...
60
- @overload
61
- def __init__(
62
- self: TemporaryFile[str],
63
- mode: OpenTextMode,
64
- buffering: int = ...,
65
- encoding: str | None = ...,
66
- newline: str | None = ...,
67
- suffix: str | None = ...,
68
- prefix: str | None = ...,
69
- dir: str | None = ...,
70
- *,
71
- errors: str | None = ...,
72
- ): ...
73
-
74
- def __init__(
75
- self,
76
- mode: OpenTextMode | OpenBinaryMode = "w+b",
77
- buffering: int = -1,
78
- encoding: str | None = None,
79
- newline: str | None = None,
80
- suffix: str | None = None,
81
- prefix: str | None = None,
82
- dir: str | None = None,
83
- *,
84
- errors: str | None = None,
85
- ) -> None:
86
- self.mode = mode
87
- self.buffering = buffering
88
- self.encoding = encoding
89
- self.newline = newline
90
- self.suffix: str | None = suffix
91
- self.prefix: str | None = prefix
92
- self.dir: str | None = dir
93
- self.errors = errors
94
-
95
- async def __aenter__(self) -> AsyncFile[AnyStr]:
96
- fp = await to_thread.run_sync(
97
- lambda: tempfile.TemporaryFile(
98
- self.mode,
99
- self.buffering,
100
- self.encoding,
101
- self.newline,
102
- self.suffix,
103
- self.prefix,
104
- self.dir,
105
- errors=self.errors,
106
- )
107
- )
108
- self._async_file = AsyncFile(fp)
109
- return self._async_file
110
-
111
- async def __aexit__(
112
- self,
113
- exc_type: type[BaseException] | None,
114
- exc_value: BaseException | None,
115
- traceback: TracebackType | None,
116
- ) -> None:
117
- await self._async_file.aclose()
118
-
119
-
120
- class NamedTemporaryFile(Generic[AnyStr]):
121
- """
122
- An asynchronous named temporary file that is automatically created and cleaned up.
123
-
124
- This class provides an asynchronous context manager for a temporary file with a
125
- visible name in the file system. It uses Python's standard
126
- :func:`~tempfile.NamedTemporaryFile` function and wraps the file object with
127
- :class:`AsyncFile` for asynchronous operations.
128
-
129
- :param mode: The mode in which the file is opened. Defaults to "w+b".
130
- :param buffering: The buffering policy (-1 means the default buffering).
131
- :param encoding: The encoding used to decode or encode the file. Only applicable in
132
- text mode.
133
- :param newline: Controls how universal newlines mode works (only applicable in text
134
- mode).
135
- :param suffix: The suffix for the temporary file name.
136
- :param prefix: The prefix for the temporary file name.
137
- :param dir: The directory in which the temporary file is created.
138
- :param delete: Whether to delete the file when it is closed.
139
- :param errors: The error handling scheme used for encoding/decoding errors.
140
- :param delete_on_close: (Python 3.12+) Whether to delete the file on close.
141
- """
142
-
143
- _async_file: AsyncFile[AnyStr]
144
-
145
- @overload
146
- def __init__(
147
- self: NamedTemporaryFile[bytes],
148
- mode: OpenBinaryMode = ...,
149
- buffering: int = ...,
150
- encoding: str | None = ...,
151
- newline: str | None = ...,
152
- suffix: str | None = ...,
153
- prefix: str | None = ...,
154
- dir: str | None = ...,
155
- delete: bool = ...,
156
- *,
157
- errors: str | None = ...,
158
- delete_on_close: bool = ...,
159
- ): ...
160
- @overload
161
- def __init__(
162
- self: NamedTemporaryFile[str],
163
- mode: OpenTextMode,
164
- buffering: int = ...,
165
- encoding: str | None = ...,
166
- newline: str | None = ...,
167
- suffix: str | None = ...,
168
- prefix: str | None = ...,
169
- dir: str | None = ...,
170
- delete: bool = ...,
171
- *,
172
- errors: str | None = ...,
173
- delete_on_close: bool = ...,
174
- ): ...
175
-
176
- def __init__(
177
- self,
178
- mode: OpenBinaryMode | OpenTextMode = "w+b",
179
- buffering: int = -1,
180
- encoding: str | None = None,
181
- newline: str | None = None,
182
- suffix: str | None = None,
183
- prefix: str | None = None,
184
- dir: str | None = None,
185
- delete: bool = True,
186
- *,
187
- errors: str | None = None,
188
- delete_on_close: bool = True,
189
- ) -> None:
190
- self._params: dict[str, Any] = {
191
- "mode": mode,
192
- "buffering": buffering,
193
- "encoding": encoding,
194
- "newline": newline,
195
- "suffix": suffix,
196
- "prefix": prefix,
197
- "dir": dir,
198
- "delete": delete,
199
- "errors": errors,
200
- }
201
- if sys.version_info >= (3, 12):
202
- self._params["delete_on_close"] = delete_on_close
203
-
204
- async def __aenter__(self) -> AsyncFile[AnyStr]:
205
- fp = await to_thread.run_sync(
206
- lambda: tempfile.NamedTemporaryFile(**self._params)
207
- )
208
- self._async_file = AsyncFile(fp)
209
- return self._async_file
210
-
211
- async def __aexit__(
212
- self,
213
- exc_type: type[BaseException] | None,
214
- exc_value: BaseException | None,
215
- traceback: TracebackType | None,
216
- ) -> None:
217
- await self._async_file.aclose()
218
-
219
-
220
- class SpooledTemporaryFile(AsyncFile[AnyStr]):
221
- """
222
- An asynchronous spooled temporary file that starts in memory and is spooled to disk.
223
-
224
- This class provides an asynchronous interface to a spooled temporary file, much like
225
- Python's standard :class:`~tempfile.SpooledTemporaryFile`. It supports asynchronous
226
- write operations and provides a method to force a rollover to disk.
227
-
228
- :param max_size: Maximum size in bytes before the file is rolled over to disk.
229
- :param mode: The mode in which the file is opened. Defaults to "w+b".
230
- :param buffering: The buffering policy (-1 means the default buffering).
231
- :param encoding: The encoding used to decode or encode the file (text mode only).
232
- :param newline: Controls how universal newlines mode works (text mode only).
233
- :param suffix: The suffix for the temporary file name.
234
- :param prefix: The prefix for the temporary file name.
235
- :param dir: The directory in which the temporary file is created.
236
- :param errors: The error handling scheme used for encoding/decoding errors.
237
- """
238
-
239
- _rolled: bool = False
240
-
241
- @overload
242
- def __init__(
243
- self: SpooledTemporaryFile[bytes],
244
- max_size: int = ...,
245
- mode: OpenBinaryMode = ...,
246
- buffering: int = ...,
247
- encoding: str | None = ...,
248
- newline: str | None = ...,
249
- suffix: str | None = ...,
250
- prefix: str | None = ...,
251
- dir: str | None = ...,
252
- *,
253
- errors: str | None = ...,
254
- ): ...
255
- @overload
256
- def __init__(
257
- self: SpooledTemporaryFile[str],
258
- max_size: int = ...,
259
- mode: OpenTextMode = ...,
260
- buffering: int = ...,
261
- encoding: str | None = ...,
262
- newline: str | None = ...,
263
- suffix: str | None = ...,
264
- prefix: str | None = ...,
265
- dir: str | None = ...,
266
- *,
267
- errors: str | None = ...,
268
- ): ...
269
-
270
- def __init__(
271
- self,
272
- max_size: int = 0,
273
- mode: OpenBinaryMode | OpenTextMode = "w+b",
274
- buffering: int = -1,
275
- encoding: str | None = None,
276
- newline: str | None = None,
277
- suffix: str | None = None,
278
- prefix: str | None = None,
279
- dir: str | None = None,
280
- *,
281
- errors: str | None = None,
282
- ) -> None:
283
- self._tempfile_params: dict[str, Any] = {
284
- "mode": mode,
285
- "buffering": buffering,
286
- "encoding": encoding,
287
- "newline": newline,
288
- "suffix": suffix,
289
- "prefix": prefix,
290
- "dir": dir,
291
- "errors": errors,
292
- }
293
- self._max_size = max_size
294
- if "b" in mode:
295
- super().__init__(BytesIO()) # type: ignore[arg-type]
296
- else:
297
- super().__init__(
298
- TextIOWrapper( # type: ignore[arg-type]
299
- BytesIO(),
300
- encoding=encoding,
301
- errors=errors,
302
- newline=newline,
303
- write_through=True,
304
- )
305
- )
306
-
307
- async def aclose(self) -> None:
308
- if not self._rolled:
309
- self._fp.close()
310
- return
311
-
312
- await super().aclose()
313
-
314
- async def _check(self) -> None:
315
- if self._rolled or self._fp.tell() <= self._max_size:
316
- return
317
-
318
- await self.rollover()
319
-
320
- async def rollover(self) -> None:
321
- if self._rolled:
322
- return
323
-
324
- self._rolled = True
325
- buffer = self._fp
326
- buffer.seek(0)
327
- self._fp = await to_thread.run_sync(
328
- lambda: tempfile.TemporaryFile(**self._tempfile_params)
329
- )
330
- await self.write(buffer.read())
331
- buffer.close()
332
-
333
- @property
334
- def closed(self) -> bool:
335
- return self._fp.closed
336
-
337
- async def read(self, size: int = -1) -> AnyStr:
338
- if not self._rolled:
339
- await checkpoint_if_cancelled()
340
- return self._fp.read(size)
341
-
342
- return await super().read(size) # type: ignore[return-value]
343
-
344
- async def read1(self: SpooledTemporaryFile[bytes], size: int = -1) -> bytes:
345
- if not self._rolled:
346
- await checkpoint_if_cancelled()
347
- return self._fp.read1(size)
348
-
349
- return await super().read1(size)
350
-
351
- async def readline(self) -> AnyStr:
352
- if not self._rolled:
353
- await checkpoint_if_cancelled()
354
- return self._fp.readline()
355
-
356
- return await super().readline() # type: ignore[return-value]
357
-
358
- async def readlines(self) -> list[AnyStr]:
359
- if not self._rolled:
360
- await checkpoint_if_cancelled()
361
- return self._fp.readlines()
362
-
363
- return await super().readlines() # type: ignore[return-value]
364
-
365
- async def readinto(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int:
366
- if not self._rolled:
367
- await checkpoint_if_cancelled()
368
- self._fp.readinto(b)
369
-
370
- return await super().readinto(b)
371
-
372
- async def readinto1(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int:
373
- if not self._rolled:
374
- await checkpoint_if_cancelled()
375
- self._fp.readinto(b)
376
-
377
- return await super().readinto1(b)
378
-
379
- async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
380
- if not self._rolled:
381
- await checkpoint_if_cancelled()
382
- return self._fp.seek(offset, whence)
383
-
384
- return await super().seek(offset, whence)
385
-
386
- async def tell(self) -> int:
387
- if not self._rolled:
388
- await checkpoint_if_cancelled()
389
- return self._fp.tell()
390
-
391
- return await super().tell()
392
-
393
- async def truncate(self, size: int | None = None) -> int:
394
- if not self._rolled:
395
- await checkpoint_if_cancelled()
396
- return self._fp.truncate(size)
397
-
398
- return await super().truncate(size)
399
-
400
- @overload
401
- async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ...
402
- @overload
403
- async def write(self: SpooledTemporaryFile[str], b: str) -> int: ...
404
-
405
- async def write(self, b: ReadableBuffer | str) -> int:
406
- """
407
- Asynchronously write data to the spooled temporary file.
408
-
409
- If the file has not yet been rolled over, the data is written synchronously,
410
- and a rollover is triggered if the size exceeds the maximum size.
411
-
412
- :param s: The data to write.
413
- :return: The number of bytes written.
414
- :raises RuntimeError: If the underlying file is not initialized.
415
-
416
- """
417
- if not self._rolled:
418
- await checkpoint_if_cancelled()
419
- result = self._fp.write(b)
420
- await self._check()
421
- return result
422
-
423
- return await super().write(b) # type: ignore[misc]
424
-
425
- @overload
426
- async def writelines(
427
- self: SpooledTemporaryFile[bytes], lines: Iterable[ReadableBuffer]
428
- ) -> None: ...
429
- @overload
430
- async def writelines(
431
- self: SpooledTemporaryFile[str], lines: Iterable[str]
432
- ) -> None: ...
433
-
434
- async def writelines(self, lines: Iterable[str] | Iterable[ReadableBuffer]) -> None:
435
- """
436
- Asynchronously write a list of lines to the spooled temporary file.
437
-
438
- If the file has not yet been rolled over, the lines are written synchronously,
439
- and a rollover is triggered if the size exceeds the maximum size.
440
-
441
- :param lines: An iterable of lines to write.
442
- :raises RuntimeError: If the underlying file is not initialized.
443
-
444
- """
445
- if not self._rolled:
446
- await checkpoint_if_cancelled()
447
- result = self._fp.writelines(lines)
448
- await self._check()
449
- return result
450
-
451
- return await super().writelines(lines) # type: ignore[misc]
452
-
453
-
454
- class TemporaryDirectory(Generic[AnyStr]):
455
- """
456
- An asynchronous temporary directory that is created and cleaned up automatically.
457
-
458
- This class provides an asynchronous context manager for creating a temporary
459
- directory. It wraps Python's standard :class:`~tempfile.TemporaryDirectory` to
460
- perform directory creation and cleanup operations in a background thread.
461
-
462
- :param suffix: Suffix to be added to the temporary directory name.
463
- :param prefix: Prefix to be added to the temporary directory name.
464
- :param dir: The parent directory where the temporary directory is created.
465
- :param ignore_cleanup_errors: Whether to ignore errors during cleanup
466
- (Python 3.10+).
467
- :param delete: Whether to delete the directory upon closing (Python 3.12+).
468
- """
469
-
470
- def __init__(
471
- self,
472
- suffix: AnyStr | None = None,
473
- prefix: AnyStr | None = None,
474
- dir: AnyStr | None = None,
475
- *,
476
- ignore_cleanup_errors: bool = False,
477
- delete: bool = True,
478
- ) -> None:
479
- self.suffix: AnyStr | None = suffix
480
- self.prefix: AnyStr | None = prefix
481
- self.dir: AnyStr | None = dir
482
- self.ignore_cleanup_errors = ignore_cleanup_errors
483
- self.delete = delete
484
-
485
- self._tempdir: tempfile.TemporaryDirectory | None = None
486
-
487
- async def __aenter__(self) -> str:
488
- params: dict[str, Any] = {
489
- "suffix": self.suffix,
490
- "prefix": self.prefix,
491
- "dir": self.dir,
492
- }
493
- if sys.version_info >= (3, 10):
494
- params["ignore_cleanup_errors"] = self.ignore_cleanup_errors
495
-
496
- if sys.version_info >= (3, 12):
497
- params["delete"] = self.delete
498
-
499
- self._tempdir = await to_thread.run_sync(
500
- lambda: tempfile.TemporaryDirectory(**params)
501
- )
502
- return await to_thread.run_sync(self._tempdir.__enter__)
503
-
504
- async def __aexit__(
505
- self,
506
- exc_type: type[BaseException] | None,
507
- exc_value: BaseException | None,
508
- traceback: TracebackType | None,
509
- ) -> None:
510
- if self._tempdir is not None:
511
- await to_thread.run_sync(
512
- self._tempdir.__exit__, exc_type, exc_value, traceback
513
- )
514
-
515
- async def cleanup(self) -> None:
516
- if self._tempdir is not None:
517
- await to_thread.run_sync(self._tempdir.cleanup)
518
-
519
-
520
- @overload
521
- async def mkstemp(
522
- suffix: str | None = None,
523
- prefix: str | None = None,
524
- dir: str | None = None,
525
- text: bool = False,
526
- ) -> tuple[int, str]: ...
527
-
528
-
529
- @overload
530
- async def mkstemp(
531
- suffix: bytes | None = None,
532
- prefix: bytes | None = None,
533
- dir: bytes | None = None,
534
- text: bool = False,
535
- ) -> tuple[int, bytes]: ...
536
-
537
-
538
- async def mkstemp(
539
- suffix: AnyStr | None = None,
540
- prefix: AnyStr | None = None,
541
- dir: AnyStr | None = None,
542
- text: bool = False,
543
- ) -> tuple[int, str | bytes]:
544
- """
545
- Asynchronously create a temporary file and return an OS-level handle and the file
546
- name.
547
-
548
- This function wraps `tempfile.mkstemp` and executes it in a background thread.
549
-
550
- :param suffix: Suffix to be added to the file name.
551
- :param prefix: Prefix to be added to the file name.
552
- :param dir: Directory in which the temporary file is created.
553
- :param text: Whether the file is opened in text mode.
554
- :return: A tuple containing the file descriptor and the file name.
555
-
556
- """
557
- return await to_thread.run_sync(tempfile.mkstemp, suffix, prefix, dir, text)
558
-
559
-
560
- @overload
561
- async def mkdtemp(
562
- suffix: str | None = None,
563
- prefix: str | None = None,
564
- dir: str | None = None,
565
- ) -> str: ...
566
-
567
-
568
- @overload
569
- async def mkdtemp(
570
- suffix: bytes | None = None,
571
- prefix: bytes | None = None,
572
- dir: bytes | None = None,
573
- ) -> bytes: ...
574
-
575
-
576
- async def mkdtemp(
577
- suffix: AnyStr | None = None,
578
- prefix: AnyStr | None = None,
579
- dir: AnyStr | None = None,
580
- ) -> str | bytes:
581
- """
582
- Asynchronously create a temporary directory and return its path.
583
-
584
- This function wraps `tempfile.mkdtemp` and executes it in a background thread.
585
-
586
- :param suffix: Suffix to be added to the directory name.
587
- :param prefix: Prefix to be added to the directory name.
588
- :param dir: Parent directory where the temporary directory is created.
589
- :return: The path of the created temporary directory.
590
-
591
- """
592
- return await to_thread.run_sync(tempfile.mkdtemp, suffix, prefix, dir)
593
-
594
-
595
- async def gettempdir() -> str:
596
- """
597
- Asynchronously return the name of the directory used for temporary files.
598
-
599
- This function wraps `tempfile.gettempdir` and executes it in a background thread.
600
-
601
- :return: The path of the temporary directory as a string.
602
-
603
- """
604
- return await to_thread.run_sync(tempfile.gettempdir)
605
-
606
-
607
- async def gettempdirb() -> bytes:
608
- """
609
- Asynchronously return the name of the directory used for temporary files in bytes.
610
-
611
- This function wraps `tempfile.gettempdirb` and executes it in a background thread.
612
-
613
- :return: The path of the temporary directory as bytes.
614
-
615
- """
616
- return await to_thread.run_sync(tempfile.gettempdirb)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_testing.py DELETED
@@ -1,82 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import Awaitable, Generator
4
- from typing import Any, cast
5
-
6
- from ._eventloop import get_async_backend
7
-
8
-
9
- class TaskInfo:
10
- """
11
- Represents an asynchronous task.
12
-
13
- :ivar int id: the unique identifier of the task
14
- :ivar parent_id: the identifier of the parent task, if any
15
- :vartype parent_id: Optional[int]
16
- :ivar str name: the description of the task (if any)
17
- :ivar ~collections.abc.Coroutine coro: the coroutine object of the task
18
- """
19
-
20
- __slots__ = "_name", "id", "parent_id", "name", "coro"
21
-
22
- def __init__(
23
- self,
24
- id: int,
25
- parent_id: int | None,
26
- name: str | None,
27
- coro: Generator[Any, Any, Any] | Awaitable[Any],
28
- ):
29
- func = get_current_task
30
- self._name = f"{func.__module__}.{func.__qualname__}"
31
- self.id: int = id
32
- self.parent_id: int | None = parent_id
33
- self.name: str | None = name
34
- self.coro: Generator[Any, Any, Any] | Awaitable[Any] = coro
35
-
36
- def __eq__(self, other: object) -> bool:
37
- if isinstance(other, TaskInfo):
38
- return self.id == other.id
39
-
40
- return NotImplemented
41
-
42
- def __hash__(self) -> int:
43
- return hash(self.id)
44
-
45
- def __repr__(self) -> str:
46
- return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})"
47
-
48
- def has_pending_cancellation(self) -> bool:
49
- """
50
- Return ``True`` if the task has a cancellation pending, ``False`` otherwise.
51
-
52
- """
53
- return False
54
-
55
-
56
- def get_current_task() -> TaskInfo:
57
- """
58
- Return the current task.
59
-
60
- :return: a representation of the current task
61
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
62
- current thread
63
-
64
- """
65
- return get_async_backend().get_current_task()
66
-
67
-
68
- def get_running_tasks() -> list[TaskInfo]:
69
- """
70
- Return a list of running tasks in the current event loop.
71
-
72
- :return: a list of task info objects
73
- :raises NoEventLoopError: if no supported asynchronous event loop is running in the
74
- current thread
75
-
76
- """
77
- return cast("list[TaskInfo]", get_async_backend().get_running_tasks())
78
-
79
-
80
- async def wait_all_tasks_blocked() -> None:
81
- """Wait until all other tasks are waiting for something."""
82
- await get_async_backend().wait_all_tasks_blocked()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/_core/_typedattr.py DELETED
@@ -1,81 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from collections.abc import Callable, Mapping
4
- from typing import Any, TypeVar, final, overload
5
-
6
- from ._exceptions import TypedAttributeLookupError
7
-
8
- T_Attr = TypeVar("T_Attr")
9
- T_Default = TypeVar("T_Default")
10
- undefined = object()
11
-
12
-
13
- def typed_attribute() -> Any:
14
- """Return a unique object, used to mark typed attributes."""
15
- return object()
16
-
17
-
18
- class TypedAttributeSet:
19
- """
20
- Superclass for typed attribute collections.
21
-
22
- Checks that every public attribute of every subclass has a type annotation.
23
- """
24
-
25
- def __init_subclass__(cls) -> None:
26
- annotations: dict[str, Any] = getattr(cls, "__annotations__", {})
27
- for attrname in dir(cls):
28
- if not attrname.startswith("_") and attrname not in annotations:
29
- raise TypeError(
30
- f"Attribute {attrname!r} is missing its type annotation"
31
- )
32
-
33
- super().__init_subclass__()
34
-
35
-
36
- class TypedAttributeProvider:
37
- """Base class for classes that wish to provide typed extra attributes."""
38
-
39
- @property
40
- def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]:
41
- """
42
- A mapping of the extra attributes to callables that return the corresponding
43
- values.
44
-
45
- If the provider wraps another provider, the attributes from that wrapper should
46
- also be included in the returned mapping (but the wrapper may override the
47
- callables from the wrapped instance).
48
-
49
- """
50
- return {}
51
-
52
- @overload
53
- def extra(self, attribute: T_Attr) -> T_Attr: ...
54
-
55
- @overload
56
- def extra(self, attribute: T_Attr, default: T_Default) -> T_Attr | T_Default: ...
57
-
58
- @final
59
- def extra(self, attribute: Any, default: object = undefined) -> object:
60
- """
61
- extra(attribute, default=undefined)
62
-
63
- Return the value of the given typed extra attribute.
64
-
65
- :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to
66
- look for
67
- :param default: the value that should be returned if no value is found for the
68
- attribute
69
- :raises ~anyio.TypedAttributeLookupError: if the search failed and no default
70
- value was given
71
-
72
- """
73
- try:
74
- getter = self.extra_attributes[attribute]
75
- except KeyError:
76
- if default is undefined:
77
- raise TypedAttributeLookupError("Attribute not found") from None
78
- else:
79
- return default
80
-
81
- return getter()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/abc/__init__.py DELETED
@@ -1,58 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from ._eventloop import AsyncBackend as AsyncBackend
4
- from ._resources import AsyncResource as AsyncResource
5
- from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket
6
- from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket
7
- from ._sockets import IPAddressType as IPAddressType
8
- from ._sockets import IPSockAddrType as IPSockAddrType
9
- from ._sockets import SocketAttribute as SocketAttribute
10
- from ._sockets import SocketListener as SocketListener
11
- from ._sockets import SocketStream as SocketStream
12
- from ._sockets import UDPPacketType as UDPPacketType
13
- from ._sockets import UDPSocket as UDPSocket
14
- from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType
15
- from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket
16
- from ._sockets import UNIXSocketStream as UNIXSocketStream
17
- from ._streams import AnyByteReceiveStream as AnyByteReceiveStream
18
- from ._streams import AnyByteSendStream as AnyByteSendStream
19
- from ._streams import AnyByteStream as AnyByteStream
20
- from ._streams import AnyByteStreamConnectable as AnyByteStreamConnectable
21
- from ._streams import AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream
22
- from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream
23
- from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream
24
- from ._streams import ByteReceiveStream as ByteReceiveStream
25
- from ._streams import ByteSendStream as ByteSendStream
26
- from ._streams import ByteStream as ByteStream
27
- from ._streams import ByteStreamConnectable as ByteStreamConnectable
28
- from ._streams import Listener as Listener
29
- from ._streams import ObjectReceiveStream as ObjectReceiveStream
30
- from ._streams import ObjectSendStream as ObjectSendStream
31
- from ._streams import ObjectStream as ObjectStream
32
- from ._streams import ObjectStreamConnectable as ObjectStreamConnectable
33
- from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream
34
- from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream
35
- from ._streams import UnreliableObjectStream as UnreliableObjectStream
36
- from ._subprocesses import Process as Process
37
- from ._tasks import TaskGroup as TaskGroup
38
- from ._tasks import TaskStatus as TaskStatus
39
- from ._testing import TestRunner as TestRunner
40
-
41
- # Re-exported here, for backwards compatibility
42
- # isort: off
43
- from .._core._synchronization import (
44
- CapacityLimiter as CapacityLimiter,
45
- Condition as Condition,
46
- Event as Event,
47
- Lock as Lock,
48
- Semaphore as Semaphore,
49
- )
50
- from .._core._tasks import CancelScope as CancelScope
51
- from ..from_thread import BlockingPortal as BlockingPortal
52
-
53
- # Re-export imports so they look like they live directly in this package
54
- for __value in list(locals().values()):
55
- if getattr(__value, "__module__", "").startswith("anyio.abc."):
56
- __value.__module__ = __name__
57
-
58
- del __value
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/abc/_eventloop.py DELETED
@@ -1,414 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import math
4
- import sys
5
- from abc import ABCMeta, abstractmethod
6
- from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
7
- from contextlib import AbstractContextManager
8
- from os import PathLike
9
- from signal import Signals
10
- from socket import AddressFamily, SocketKind, socket
11
- from typing import (
12
- IO,
13
- TYPE_CHECKING,
14
- Any,
15
- TypeVar,
16
- Union,
17
- overload,
18
- )
19
-
20
- if sys.version_info >= (3, 11):
21
- from typing import TypeVarTuple, Unpack
22
- else:
23
- from typing_extensions import TypeVarTuple, Unpack
24
-
25
- if sys.version_info >= (3, 10):
26
- from typing import TypeAlias
27
- else:
28
- from typing_extensions import TypeAlias
29
-
30
- if TYPE_CHECKING:
31
- from _typeshed import FileDescriptorLike
32
-
33
- from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore
34
- from .._core._tasks import CancelScope
35
- from .._core._testing import TaskInfo
36
- from ._sockets import (
37
- ConnectedUDPSocket,
38
- ConnectedUNIXDatagramSocket,
39
- IPSockAddrType,
40
- SocketListener,
41
- SocketStream,
42
- UDPSocket,
43
- UNIXDatagramSocket,
44
- UNIXSocketStream,
45
- )
46
- from ._subprocesses import Process
47
- from ._tasks import TaskGroup
48
- from ._testing import TestRunner
49
-
50
- T_Retval = TypeVar("T_Retval")
51
- PosArgsT = TypeVarTuple("PosArgsT")
52
- StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"]
53
-
54
-
55
- class AsyncBackend(metaclass=ABCMeta):
56
- @classmethod
57
- @abstractmethod
58
- def run(
59
- cls,
60
- func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
61
- args: tuple[Unpack[PosArgsT]],
62
- kwargs: dict[str, Any],
63
- options: dict[str, Any],
64
- ) -> T_Retval:
65
- """
66
- Run the given coroutine function in an asynchronous event loop.
67
-
68
- The current thread must not be already running an event loop.
69
-
70
- :param func: a coroutine function
71
- :param args: positional arguments to ``func``
72
- :param kwargs: positional arguments to ``func``
73
- :param options: keyword arguments to call the backend ``run()`` implementation
74
- with
75
- :return: the return value of the coroutine function
76
- """
77
-
78
- @classmethod
79
- @abstractmethod
80
- def current_token(cls) -> object:
81
- """
82
- Return an object that allows other threads to run code inside the event loop.
83
-
84
- :return: a token object, specific to the event loop running in the current
85
- thread
86
- """
87
-
88
- @classmethod
89
- @abstractmethod
90
- def current_time(cls) -> float:
91
- """
92
- Return the current value of the event loop's internal clock.
93
-
94
- :return: the clock value (seconds)
95
- """
96
-
97
- @classmethod
98
- @abstractmethod
99
- def cancelled_exception_class(cls) -> type[BaseException]:
100
- """Return the exception class that is raised in a task if it's cancelled."""
101
-
102
- @classmethod
103
- @abstractmethod
104
- async def checkpoint(cls) -> None:
105
- """
106
- Check if the task has been cancelled, and allow rescheduling of other tasks.
107
-
108
- This is effectively the same as running :meth:`checkpoint_if_cancelled` and then
109
- :meth:`cancel_shielded_checkpoint`.
110
- """
111
-
112
- @classmethod
113
- async def checkpoint_if_cancelled(cls) -> None:
114
- """
115
- Check if the current task group has been cancelled.
116
-
117
- This will check if the task has been cancelled, but will not allow other tasks
118
- to be scheduled if not.
119
-
120
- """
121
- if cls.current_effective_deadline() == -math.inf:
122
- await cls.checkpoint()
123
-
124
- @classmethod
125
- async def cancel_shielded_checkpoint(cls) -> None:
126
- """
127
- Allow the rescheduling of other tasks.
128
-
129
- This will give other tasks the opportunity to run, but without checking if the
130
- current task group has been cancelled, unlike with :meth:`checkpoint`.
131
-
132
- """
133
- with cls.create_cancel_scope(shield=True):
134
- await cls.sleep(0)
135
-
136
- @classmethod
137
- @abstractmethod
138
- async def sleep(cls, delay: float) -> None:
139
- """
140
- Pause the current task for the specified duration.
141
-
142
- :param delay: the duration, in seconds
143
- """
144
-
145
- @classmethod
146
- @abstractmethod
147
- def create_cancel_scope(
148
- cls, *, deadline: float = math.inf, shield: bool = False
149
- ) -> CancelScope:
150
- pass
151
-
152
- @classmethod
153
- @abstractmethod
154
- def current_effective_deadline(cls) -> float:
155
- """
156
- Return the nearest deadline among all the cancel scopes effective for the
157
- current task.
158
-
159
- :return:
160
- - a clock value from the event loop's internal clock
161
- - ``inf`` if there is no deadline in effect
162
- - ``-inf`` if the current scope has been cancelled
163
- :rtype: float
164
- """
165
-
166
- @classmethod
167
- @abstractmethod
168
- def create_task_group(cls) -> TaskGroup:
169
- pass
170
-
171
- @classmethod
172
- @abstractmethod
173
- def create_event(cls) -> Event:
174
- pass
175
-
176
- @classmethod
177
- @abstractmethod
178
- def create_lock(cls, *, fast_acquire: bool) -> Lock:
179
- pass
180
-
181
- @classmethod
182
- @abstractmethod
183
- def create_semaphore(
184
- cls,
185
- initial_value: int,
186
- *,
187
- max_value: int | None = None,
188
- fast_acquire: bool = False,
189
- ) -> Semaphore:
190
- pass
191
-
192
- @classmethod
193
- @abstractmethod
194
- def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
195
- pass
196
-
197
- @classmethod
198
- @abstractmethod
199
- async def run_sync_in_worker_thread(
200
- cls,
201
- func: Callable[[Unpack[PosArgsT]], T_Retval],
202
- args: tuple[Unpack[PosArgsT]],
203
- abandon_on_cancel: bool = False,
204
- limiter: CapacityLimiter | None = None,
205
- ) -> T_Retval:
206
- pass
207
-
208
- @classmethod
209
- @abstractmethod
210
- def check_cancelled(cls) -> None:
211
- pass
212
-
213
- @classmethod
214
- @abstractmethod
215
- def run_async_from_thread(
216
- cls,
217
- func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
218
- args: tuple[Unpack[PosArgsT]],
219
- token: object,
220
- ) -> T_Retval:
221
- pass
222
-
223
- @classmethod
224
- @abstractmethod
225
- def run_sync_from_thread(
226
- cls,
227
- func: Callable[[Unpack[PosArgsT]], T_Retval],
228
- args: tuple[Unpack[PosArgsT]],
229
- token: object,
230
- ) -> T_Retval:
231
- pass
232
-
233
- @classmethod
234
- @abstractmethod
235
- async def open_process(
236
- cls,
237
- command: StrOrBytesPath | Sequence[StrOrBytesPath],
238
- *,
239
- stdin: int | IO[Any] | None,
240
- stdout: int | IO[Any] | None,
241
- stderr: int | IO[Any] | None,
242
- **kwargs: Any,
243
- ) -> Process:
244
- pass
245
-
246
- @classmethod
247
- @abstractmethod
248
- def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None:
249
- pass
250
-
251
- @classmethod
252
- @abstractmethod
253
- async def connect_tcp(
254
- cls, host: str, port: int, local_address: IPSockAddrType | None = None
255
- ) -> SocketStream:
256
- pass
257
-
258
- @classmethod
259
- @abstractmethod
260
- async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream:
261
- pass
262
-
263
- @classmethod
264
- @abstractmethod
265
- def create_tcp_listener(cls, sock: socket) -> SocketListener:
266
- pass
267
-
268
- @classmethod
269
- @abstractmethod
270
- def create_unix_listener(cls, sock: socket) -> SocketListener:
271
- pass
272
-
273
- @classmethod
274
- @abstractmethod
275
- async def create_udp_socket(
276
- cls,
277
- family: AddressFamily,
278
- local_address: IPSockAddrType | None,
279
- remote_address: IPSockAddrType | None,
280
- reuse_port: bool,
281
- ) -> UDPSocket | ConnectedUDPSocket:
282
- pass
283
-
284
- @classmethod
285
- @overload
286
- async def create_unix_datagram_socket(
287
- cls, raw_socket: socket, remote_path: None
288
- ) -> UNIXDatagramSocket: ...
289
-
290
- @classmethod
291
- @overload
292
- async def create_unix_datagram_socket(
293
- cls, raw_socket: socket, remote_path: str | bytes
294
- ) -> ConnectedUNIXDatagramSocket: ...
295
-
296
- @classmethod
297
- @abstractmethod
298
- async def create_unix_datagram_socket(
299
- cls, raw_socket: socket, remote_path: str | bytes | None
300
- ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket:
301
- pass
302
-
303
- @classmethod
304
- @abstractmethod
305
- async def getaddrinfo(
306
- cls,
307
- host: bytes | str | None,
308
- port: str | int | None,
309
- *,
310
- family: int | AddressFamily = 0,
311
- type: int | SocketKind = 0,
312
- proto: int = 0,
313
- flags: int = 0,
314
- ) -> Sequence[
315
- tuple[
316
- AddressFamily,
317
- SocketKind,
318
- int,
319
- str,
320
- tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
321
- ]
322
- ]:
323
- pass
324
-
325
- @classmethod
326
- @abstractmethod
327
- async def getnameinfo(
328
- cls, sockaddr: IPSockAddrType, flags: int = 0
329
- ) -> tuple[str, str]:
330
- pass
331
-
332
- @classmethod
333
- @abstractmethod
334
- async def wait_readable(cls, obj: FileDescriptorLike) -> None:
335
- pass
336
-
337
- @classmethod
338
- @abstractmethod
339
- async def wait_writable(cls, obj: FileDescriptorLike) -> None:
340
- pass
341
-
342
- @classmethod
343
- @abstractmethod
344
- def notify_closing(cls, obj: FileDescriptorLike) -> None:
345
- pass
346
-
347
- @classmethod
348
- @abstractmethod
349
- async def wrap_listener_socket(cls, sock: socket) -> SocketListener:
350
- pass
351
-
352
- @classmethod
353
- @abstractmethod
354
- async def wrap_stream_socket(cls, sock: socket) -> SocketStream:
355
- pass
356
-
357
- @classmethod
358
- @abstractmethod
359
- async def wrap_unix_stream_socket(cls, sock: socket) -> UNIXSocketStream:
360
- pass
361
-
362
- @classmethod
363
- @abstractmethod
364
- async def wrap_udp_socket(cls, sock: socket) -> UDPSocket:
365
- pass
366
-
367
- @classmethod
368
- @abstractmethod
369
- async def wrap_connected_udp_socket(cls, sock: socket) -> ConnectedUDPSocket:
370
- pass
371
-
372
- @classmethod
373
- @abstractmethod
374
- async def wrap_unix_datagram_socket(cls, sock: socket) -> UNIXDatagramSocket:
375
- pass
376
-
377
- @classmethod
378
- @abstractmethod
379
- async def wrap_connected_unix_datagram_socket(
380
- cls, sock: socket
381
- ) -> ConnectedUNIXDatagramSocket:
382
- pass
383
-
384
- @classmethod
385
- @abstractmethod
386
- def current_default_thread_limiter(cls) -> CapacityLimiter:
387
- pass
388
-
389
- @classmethod
390
- @abstractmethod
391
- def open_signal_receiver(
392
- cls, *signals: Signals
393
- ) -> AbstractContextManager[AsyncIterator[Signals]]:
394
- pass
395
-
396
- @classmethod
397
- @abstractmethod
398
- def get_current_task(cls) -> TaskInfo:
399
- pass
400
-
401
- @classmethod
402
- @abstractmethod
403
- def get_running_tasks(cls) -> Sequence[TaskInfo]:
404
- pass
405
-
406
- @classmethod
407
- @abstractmethod
408
- async def wait_all_tasks_blocked(cls) -> None:
409
- pass
410
-
411
- @classmethod
412
- @abstractmethod
413
- def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
414
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/abc/_resources.py DELETED
@@ -1,33 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from abc import ABCMeta, abstractmethod
4
- from types import TracebackType
5
- from typing import TypeVar
6
-
7
- T = TypeVar("T")
8
-
9
-
10
- class AsyncResource(metaclass=ABCMeta):
11
- """
12
- Abstract base class for all closeable asynchronous resources.
13
-
14
- Works as an asynchronous context manager which returns the instance itself on enter,
15
- and calls :meth:`aclose` on exit.
16
- """
17
-
18
- __slots__ = ()
19
-
20
- async def __aenter__(self: T) -> T:
21
- return self
22
-
23
- async def __aexit__(
24
- self,
25
- exc_type: type[BaseException] | None,
26
- exc_val: BaseException | None,
27
- exc_tb: TracebackType | None,
28
- ) -> None:
29
- await self.aclose()
30
-
31
- @abstractmethod
32
- async def aclose(self) -> None:
33
- """Close the resource."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/abc/_sockets.py DELETED
@@ -1,405 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import errno
4
- import socket
5
- import sys
6
- from abc import abstractmethod
7
- from collections.abc import Callable, Collection, Mapping
8
- from contextlib import AsyncExitStack
9
- from io import IOBase
10
- from ipaddress import IPv4Address, IPv6Address
11
- from socket import AddressFamily
12
- from typing import Any, TypeVar, Union
13
-
14
- from .._core._eventloop import get_async_backend
15
- from .._core._typedattr import (
16
- TypedAttributeProvider,
17
- TypedAttributeSet,
18
- typed_attribute,
19
- )
20
- from ._streams import ByteStream, Listener, UnreliableObjectStream
21
- from ._tasks import TaskGroup
22
-
23
- if sys.version_info >= (3, 10):
24
- from typing import TypeAlias
25
- else:
26
- from typing_extensions import TypeAlias
27
-
28
- IPAddressType: TypeAlias = Union[str, IPv4Address, IPv6Address]
29
- IPSockAddrType: TypeAlias = tuple[str, int]
30
- SockAddrType: TypeAlias = Union[IPSockAddrType, str]
31
- UDPPacketType: TypeAlias = tuple[bytes, IPSockAddrType]
32
- UNIXDatagramPacketType: TypeAlias = tuple[bytes, str]
33
- T_Retval = TypeVar("T_Retval")
34
-
35
-
36
- def _validate_socket(
37
- sock_or_fd: socket.socket | int,
38
- sock_type: socket.SocketKind,
39
- addr_family: socket.AddressFamily = socket.AF_UNSPEC,
40
- *,
41
- require_connected: bool = False,
42
- require_bound: bool = False,
43
- ) -> socket.socket:
44
- if isinstance(sock_or_fd, int):
45
- try:
46
- sock = socket.socket(fileno=sock_or_fd)
47
- except OSError as exc:
48
- if exc.errno == errno.ENOTSOCK:
49
- raise ValueError(
50
- "the file descriptor does not refer to a socket"
51
- ) from exc
52
- elif require_connected:
53
- raise ValueError("the socket must be connected") from exc
54
- elif require_bound:
55
- raise ValueError("the socket must be bound to a local address") from exc
56
- else:
57
- raise
58
- elif isinstance(sock_or_fd, socket.socket):
59
- sock = sock_or_fd
60
- else:
61
- raise TypeError(
62
- f"expected an int or socket, got {type(sock_or_fd).__qualname__} instead"
63
- )
64
-
65
- try:
66
- if require_connected:
67
- try:
68
- sock.getpeername()
69
- except OSError as exc:
70
- raise ValueError("the socket must be connected") from exc
71
-
72
- if require_bound:
73
- try:
74
- if sock.family in (socket.AF_INET, socket.AF_INET6):
75
- bound_addr = sock.getsockname()[1]
76
- else:
77
- bound_addr = sock.getsockname()
78
- except OSError:
79
- bound_addr = None
80
-
81
- if not bound_addr:
82
- raise ValueError("the socket must be bound to a local address")
83
-
84
- if addr_family != socket.AF_UNSPEC and sock.family != addr_family:
85
- raise ValueError(
86
- f"address family mismatch: expected {addr_family.name}, got "
87
- f"{sock.family.name}"
88
- )
89
-
90
- if sock.type != sock_type:
91
- raise ValueError(
92
- f"socket type mismatch: expected {sock_type.name}, got {sock.type.name}"
93
- )
94
- except BaseException:
95
- # Avoid ResourceWarning from the locally constructed socket object
96
- if isinstance(sock_or_fd, int):
97
- sock.detach()
98
-
99
- raise
100
-
101
- sock.setblocking(False)
102
- return sock
103
-
104
-
105
- class SocketAttribute(TypedAttributeSet):
106
- """
107
- .. attribute:: family
108
- :type: socket.AddressFamily
109
-
110
- the address family of the underlying socket
111
-
112
- .. attribute:: local_address
113
- :type: tuple[str, int] | str
114
-
115
- the local address the underlying socket is connected to
116
-
117
- .. attribute:: local_port
118
- :type: int
119
-
120
- for IP based sockets, the local port the underlying socket is bound to
121
-
122
- .. attribute:: raw_socket
123
- :type: socket.socket
124
-
125
- the underlying stdlib socket object
126
-
127
- .. attribute:: remote_address
128
- :type: tuple[str, int] | str
129
-
130
- the remote address the underlying socket is connected to
131
-
132
- .. attribute:: remote_port
133
- :type: int
134
-
135
- for IP based sockets, the remote port the underlying socket is connected to
136
- """
137
-
138
- family: AddressFamily = typed_attribute()
139
- local_address: SockAddrType = typed_attribute()
140
- local_port: int = typed_attribute()
141
- raw_socket: socket.socket = typed_attribute()
142
- remote_address: SockAddrType = typed_attribute()
143
- remote_port: int = typed_attribute()
144
-
145
-
146
- class _SocketProvider(TypedAttributeProvider):
147
- @property
148
- def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]:
149
- from .._core._sockets import convert_ipv6_sockaddr as convert
150
-
151
- attributes: dict[Any, Callable[[], Any]] = {
152
- SocketAttribute.family: lambda: self._raw_socket.family,
153
- SocketAttribute.local_address: lambda: convert(
154
- self._raw_socket.getsockname()
155
- ),
156
- SocketAttribute.raw_socket: lambda: self._raw_socket,
157
- }
158
- try:
159
- peername: tuple[str, int] | None = convert(self._raw_socket.getpeername())
160
- except OSError:
161
- peername = None
162
-
163
- # Provide the remote address for connected sockets
164
- if peername is not None:
165
- attributes[SocketAttribute.remote_address] = lambda: peername
166
-
167
- # Provide local and remote ports for IP based sockets
168
- if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6):
169
- attributes[SocketAttribute.local_port] = (
170
- lambda: self._raw_socket.getsockname()[1]
171
- )
172
- if peername is not None:
173
- remote_port = peername[1]
174
- attributes[SocketAttribute.remote_port] = lambda: remote_port
175
-
176
- return attributes
177
-
178
- @property
179
- @abstractmethod
180
- def _raw_socket(self) -> socket.socket:
181
- pass
182
-
183
-
184
- class SocketStream(ByteStream, _SocketProvider):
185
- """
186
- Transports bytes over a socket.
187
-
188
- Supports all relevant extra attributes from :class:`~SocketAttribute`.
189
- """
190
-
191
- @classmethod
192
- async def from_socket(cls, sock_or_fd: socket.socket | int) -> SocketStream:
193
- """
194
- Wrap an existing socket object or file descriptor as a socket stream.
195
-
196
- The newly created socket wrapper takes ownership of the socket being passed in.
197
- The existing socket must already be connected.
198
-
199
- :param sock_or_fd: a socket object or file descriptor
200
- :return: a socket stream
201
-
202
- """
203
- sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_connected=True)
204
- return await get_async_backend().wrap_stream_socket(sock)
205
-
206
-
207
- class UNIXSocketStream(SocketStream):
208
- @classmethod
209
- async def from_socket(cls, sock_or_fd: socket.socket | int) -> UNIXSocketStream:
210
- """
211
- Wrap an existing socket object or file descriptor as a UNIX socket stream.
212
-
213
- The newly created socket wrapper takes ownership of the socket being passed in.
214
- The existing socket must already be connected.
215
-
216
- :param sock_or_fd: a socket object or file descriptor
217
- :return: a UNIX socket stream
218
-
219
- """
220
- sock = _validate_socket(
221
- sock_or_fd, socket.SOCK_STREAM, socket.AF_UNIX, require_connected=True
222
- )
223
- return await get_async_backend().wrap_unix_stream_socket(sock)
224
-
225
- @abstractmethod
226
- async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
227
- """
228
- Send file descriptors along with a message to the peer.
229
-
230
- :param message: a non-empty bytestring
231
- :param fds: a collection of files (either numeric file descriptors or open file
232
- or socket objects)
233
- """
234
-
235
- @abstractmethod
236
- async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
237
- """
238
- Receive file descriptors along with a message from the peer.
239
-
240
- :param msglen: length of the message to expect from the peer
241
- :param maxfds: maximum number of file descriptors to expect from the peer
242
- :return: a tuple of (message, file descriptors)
243
- """
244
-
245
-
246
- class SocketListener(Listener[SocketStream], _SocketProvider):
247
- """
248
- Listens to incoming socket connections.
249
-
250
- Supports all relevant extra attributes from :class:`~SocketAttribute`.
251
- """
252
-
253
- @classmethod
254
- async def from_socket(
255
- cls,
256
- sock_or_fd: socket.socket | int,
257
- ) -> SocketListener:
258
- """
259
- Wrap an existing socket object or file descriptor as a socket listener.
260
-
261
- The newly created listener takes ownership of the socket being passed in.
262
-
263
- :param sock_or_fd: a socket object or file descriptor
264
- :return: a socket listener
265
-
266
- """
267
- sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_bound=True)
268
- return await get_async_backend().wrap_listener_socket(sock)
269
-
270
- @abstractmethod
271
- async def accept(self) -> SocketStream:
272
- """Accept an incoming connection."""
273
-
274
- async def serve(
275
- self,
276
- handler: Callable[[SocketStream], Any],
277
- task_group: TaskGroup | None = None,
278
- ) -> None:
279
- from .. import create_task_group
280
-
281
- async with AsyncExitStack() as stack:
282
- if task_group is None:
283
- task_group = await stack.enter_async_context(create_task_group())
284
-
285
- while True:
286
- stream = await self.accept()
287
- task_group.start_soon(handler, stream)
288
-
289
-
290
- class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider):
291
- """
292
- Represents an unconnected UDP socket.
293
-
294
- Supports all relevant extra attributes from :class:`~SocketAttribute`.
295
- """
296
-
297
- @classmethod
298
- async def from_socket(cls, sock_or_fd: socket.socket | int) -> UDPSocket:
299
- """
300
- Wrap an existing socket object or file descriptor as a UDP socket.
301
-
302
- The newly created socket wrapper takes ownership of the socket being passed in.
303
- The existing socket must be bound to a local address.
304
-
305
- :param sock_or_fd: a socket object or file descriptor
306
- :return: a UDP socket
307
-
308
- """
309
- sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, require_bound=True)
310
- return await get_async_backend().wrap_udp_socket(sock)
311
-
312
- async def sendto(self, data: bytes, host: str, port: int) -> None:
313
- """
314
- Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))).
315
-
316
- """
317
- return await self.send((data, (host, port)))
318
-
319
-
320
- class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider):
321
- """
322
- Represents an connected UDP socket.
323
-
324
- Supports all relevant extra attributes from :class:`~SocketAttribute`.
325
- """
326
-
327
- @classmethod
328
- async def from_socket(cls, sock_or_fd: socket.socket | int) -> ConnectedUDPSocket:
329
- """
330
- Wrap an existing socket object or file descriptor as a connected UDP socket.
331
-
332
- The newly created socket wrapper takes ownership of the socket being passed in.
333
- The existing socket must already be connected.
334
-
335
- :param sock_or_fd: a socket object or file descriptor
336
- :return: a connected UDP socket
337
-
338
- """
339
- sock = _validate_socket(
340
- sock_or_fd,
341
- socket.SOCK_DGRAM,
342
- require_connected=True,
343
- )
344
- return await get_async_backend().wrap_connected_udp_socket(sock)
345
-
346
-
347
- class UNIXDatagramSocket(
348
- UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider
349
- ):
350
- """
351
- Represents an unconnected Unix datagram socket.
352
-
353
- Supports all relevant extra attributes from :class:`~SocketAttribute`.
354
- """
355
-
356
- @classmethod
357
- async def from_socket(
358
- cls,
359
- sock_or_fd: socket.socket | int,
360
- ) -> UNIXDatagramSocket:
361
- """
362
- Wrap an existing socket object or file descriptor as a UNIX datagram
363
- socket.
364
-
365
- The newly created socket wrapper takes ownership of the socket being passed in.
366
-
367
- :param sock_or_fd: a socket object or file descriptor
368
- :return: a UNIX datagram socket
369
-
370
- """
371
- sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX)
372
- return await get_async_backend().wrap_unix_datagram_socket(sock)
373
-
374
- async def sendto(self, data: bytes, path: str) -> None:
375
- """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, path))."""
376
- return await self.send((data, path))
377
-
378
-
379
- class ConnectedUNIXDatagramSocket(UnreliableObjectStream[bytes], _SocketProvider):
380
- """
381
- Represents a connected Unix datagram socket.
382
-
383
- Supports all relevant extra attributes from :class:`~SocketAttribute`.
384
- """
385
-
386
- @classmethod
387
- async def from_socket(
388
- cls,
389
- sock_or_fd: socket.socket | int,
390
- ) -> ConnectedUNIXDatagramSocket:
391
- """
392
- Wrap an existing socket object or file descriptor as a connected UNIX datagram
393
- socket.
394
-
395
- The newly created socket wrapper takes ownership of the socket being passed in.
396
- The existing socket must already be connected.
397
-
398
- :param sock_or_fd: a socket object or file descriptor
399
- :return: a connected UNIX datagram socket
400
-
401
- """
402
- sock = _validate_socket(
403
- sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX, require_connected=True
404
- )
405
- return await get_async_backend().wrap_connected_unix_datagram_socket(sock)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
venv/Lib/site-packages/anyio/abc/_streams.py DELETED
@@ -1,239 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import sys
4
- from abc import ABCMeta, abstractmethod
5
- from collections.abc import Callable
6
- from typing import Any, Generic, TypeVar, Union
7
-
8
- from .._core._exceptions import EndOfStream
9
- from .._core._typedattr import TypedAttributeProvider
10
- from ._resources import AsyncResource
11
- from ._tasks import TaskGroup
12
-
13
- if sys.version_info >= (3, 10):
14
- from typing import TypeAlias
15
- else:
16
- from typing_extensions import TypeAlias
17
-
18
- T_Item = TypeVar("T_Item")
19
- T_co = TypeVar("T_co", covariant=True)
20
- T_contra = TypeVar("T_contra", contravariant=True)
21
-
22
-
23
- class UnreliableObjectReceiveStream(
24
- Generic[T_co], AsyncResource, TypedAttributeProvider
25
- ):
26
- """
27
- An interface for receiving objects.
28
-
29
- This interface makes no guarantees that the received messages arrive in the order in
30
- which they were sent, or that no messages are missed.
31
-
32
- Asynchronously iterating over objects of this type will yield objects matching the
33
- given type parameter.
34
- """
35
-
36
- def __aiter__(self) -> UnreliableObjectReceiveStream[T_co]:
37
- return self
38
-
39
- async def __anext__(self) -> T_co:
40
- try:
41
- return await self.receive()
42
- except EndOfStream:
43
- raise StopAsyncIteration from None
44
-
45
- @abstractmethod
46
- async def receive(self) -> T_co:
47
- """
48
- Receive the next item.
49
-
50
- :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly
51
- closed
52
- :raises ~anyio.EndOfStream: if this stream has been closed from the other end
53
- :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable
54
- due to external causes
55
- """
56
-
57
-
58
- class UnreliableObjectSendStream(
59
- Generic[T_contra], AsyncResource, TypedAttributeProvider
60
- ):
61
- """
62
- An interface for sending objects.
63
-
64
- This interface makes no guarantees that the messages sent will reach the
65
- recipient(s) in the same order in which they were sent, or at all.
66
- """
67
-
68
- @abstractmethod
69
- async def send(self, item: T_contra) -> None:
70
- """
71
- Send an item to the peer(s).
72
-
73
- :param item: the item to send
74
- :raises ~anyio.ClosedResourceError: if the send stream has been explicitly
75
- closed
76
- :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable
77
- due to external causes
78
- """
79
-
80
-
81
- class UnreliableObjectStream(
82
- UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item]
83
- ):
84
- """
85
- A bidirectional message stream which does not guarantee the order or reliability of
86
- message delivery.
87
- """
88
-
89
-
90
- class ObjectReceiveStream(UnreliableObjectReceiveStream[T_co]):
91
- """
92
- A receive message stream which guarantees that messages are received in the same
93
- order in which they were sent, and that no messages are missed.
94
- """
95
-
96
-
97
- class ObjectSendStream(UnreliableObjectSendStream[T_contra]):
98
- """
99
- A send message stream which guarantees that messages are delivered in the same order
100
- in which they were sent, without missing any messages in the middle.
101
- """
102
-
103
-
104
- class ObjectStream(
105
- ObjectReceiveStream[T_Item],
106
- ObjectSendStream[T_Item],
107
- UnreliableObjectStream[T_Item],
108
- ):
109
- """
110
- A bidirectional message stream which guarantees the order and reliability of message
111
- delivery.
112
- """
113
-
114
- @abstractmethod
115
- async def send_eof(self) -> None:
116
- """
117
- Send an end-of-file indication to the peer.
118
-
119
- You should not try to send any further data to this stream after calling this
120
- method. This method is idempotent (does nothing on successive calls).
121
- """
122
-
123
-
124
- class ByteReceiveStream(AsyncResource, TypedAttributeProvider):
125
- """
126
- An interface for receiving bytes from a single peer.
127
-
128
- Iterating this byte stream will yield a byte string of arbitrary length, but no more
129
- than 65536 bytes.
130
- """
131
-
132
- def __aiter__(self) -> ByteReceiveStream:
133
- return self
134
-
135
- async def __anext__(self) -> bytes:
136
- try:
137
- return await self.receive()
138
- except EndOfStream:
139
- raise StopAsyncIteration from None
140
-
141
- @abstractmethod
142
- async def receive(self, max_bytes: int = 65536) -> bytes:
143
- """
144
- Receive at most ``max_bytes`` bytes from the peer.
145
-
146
- .. note:: Implementers of this interface should not return an empty
147
- :class:`bytes` object, and users should ignore them.
148
-
149
- :param max_bytes: maximum number of bytes to receive
150
- :return: the received bytes
151
- :raises ~anyio.EndOfStream: if this stream has been closed from the other end
152
- """
153
-
154
-
155
- class ByteSendStream(AsyncResource, TypedAttributeProvider):
156
- """An interface for sending bytes to a single peer."""
157
-
158
- @abstractmethod
159
- async def send(self, item: bytes) -> None:
160
- """
161
- Send the given bytes to the peer.
162
-
163
- :param item: the bytes to send
164
- """
165
-
166
-
167
- class ByteStream(ByteReceiveStream, ByteSendStream):
168
- """A bidirectional byte stream."""
169
-
170
- @abstractmethod
171
- async def send_eof(self) -> None:
172
- """
173
- Send an end-of-file indication to the peer.
174
-
175
- You should not try to send any further data to this stream after calling this
176
- method. This method is idempotent (does nothing on successive calls).
177
- """
178
-
179
-
180
- #: Type alias for all unreliable bytes-oriented receive streams.
181
- AnyUnreliableByteReceiveStream: TypeAlias = Union[
182
- UnreliableObjectReceiveStream[bytes], ByteReceiveStream
183
- ]
184
- #: Type alias for all unreliable bytes-oriented send streams.
185
- AnyUnreliableByteSendStream: TypeAlias = Union[
186
- UnreliableObjectSendStream[bytes], ByteSendStream
187
- ]
188
- #: Type alias for all unreliable bytes-oriented streams.
189
- AnyUnreliableByteStream: TypeAlias = Union[UnreliableObjectStream[bytes], ByteStream]
190
- #: Type alias for all bytes-oriented receive streams.
191
- AnyByteReceiveStream: TypeAlias = Union[ObjectReceiveStream[bytes], ByteReceiveStream]
192
- #: Type alias for all bytes-oriented send streams.
193
- AnyByteSendStream: TypeAlias = Union[ObjectSendStream[bytes], ByteSendStream]
194
- #: Type alias for all bytes-oriented streams.
195
- AnyByteStream: TypeAlias = Union[ObjectStream[bytes], ByteStream]
196
-
197
-
198
- class Listener(Generic[T_co], AsyncResource, TypedAttributeProvider):
199
- """An interface for objects that let you accept incoming connections."""
200
-
201
- @abstractmethod
202
- async def serve(
203
- self, handler: Callable[[T_co], Any], task_group: TaskGroup | None = None
204
- ) -> None:
205
- """
206
- Accept incoming connections as they come in and start tasks to handle them.
207
-
208
- :param handler: a callable that will be used to handle each accepted connection
209
- :param task_group: the task group that will be used to start tasks for handling
210
- each accepted connection (if omitted, an ad-hoc task group will be created)
211
- """
212
-
213
-
214
- class ObjectStreamConnectable(Generic[T_co], metaclass=ABCMeta):
215
- @abstractmethod
216
- async def connect(self) -> ObjectStream[T_co]:
217
- """
218
- Connect to the remote endpoint.
219
-
220
- :return: an object stream connected to the remote end
221
- :raises ConnectionFailed: if the connection fails
222
- """
223
-
224
-
225
- class ByteStreamConnectable(metaclass=ABCMeta):
226
- @abstractmethod
227
- async def connect(self) -> ByteStream:
228
- """
229
- Connect to the remote endpoint.
230
-
231
- :return: a bytestream connected to the remote end
232
- :raises ConnectionFailed: if the connection fails
233
- """
234
-
235
-
236
- #: Type alias for all connectables returning bytestreams or bytes-oriented object streams
237
- AnyByteStreamConnectable: TypeAlias = Union[
238
- ObjectStreamConnectable[bytes], ByteStreamConnectable
239
- ]