koichi12 commited on
Commit
b17ecb6
·
verified ·
1 Parent(s): 36cbb94

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/INSTALLER +1 -0
  2. .venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/METADATA +261 -0
  3. .venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/RECORD +9 -0
  4. .venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/WHEEL +5 -0
  5. .venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/top_level.txt +2 -0
  6. .venv/lib/python3.11/site-packages/platformdirs-4.3.6.dist-info/METADATA +327 -0
  7. .venv/lib/python3.11/site-packages/platformdirs-4.3.6.dist-info/RECORD +22 -0
  8. .venv/lib/python3.11/site-packages/platformdirs-4.3.6.dist-info/licenses/LICENSE +21 -0
  9. .venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/INSTALLER +1 -0
  10. .venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/METADATA +212 -0
  11. .venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/RECORD +154 -0
  12. .venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/WHEEL +5 -0
  13. .venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/entry_points.txt +3 -0
  14. .venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/top_level.txt +3 -0
  15. .venv/lib/python3.11/site-packages/uvloop/__init__.py +168 -0
  16. .venv/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pyc +0 -0
  17. .venv/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pyc +0 -0
  18. .venv/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pyc +0 -0
  19. .venv/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pyc +0 -0
  20. .venv/lib/python3.11/site-packages/uvloop/_noop.py +3 -0
  21. .venv/lib/python3.11/site-packages/uvloop/_testbase.py +552 -0
  22. .venv/lib/python3.11/site-packages/uvloop/_version.py +13 -0
  23. .venv/lib/python3.11/site-packages/uvloop/cbhandles.pxd +39 -0
  24. .venv/lib/python3.11/site-packages/uvloop/cbhandles.pyx +434 -0
  25. .venv/lib/python3.11/site-packages/uvloop/dns.pyx +479 -0
  26. .venv/lib/python3.11/site-packages/uvloop/errors.pyx +113 -0
  27. .venv/lib/python3.11/site-packages/uvloop/handles/async_.pxd +11 -0
  28. .venv/lib/python3.11/site-packages/uvloop/handles/async_.pyx +56 -0
  29. .venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pxd +54 -0
  30. .venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pyx +293 -0
  31. .venv/lib/python3.11/site-packages/uvloop/handles/check.pxd +14 -0
  32. .venv/lib/python3.11/site-packages/uvloop/handles/check.pyx +72 -0
  33. .venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pxd +12 -0
  34. .venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pyx +116 -0
  35. .venv/lib/python3.11/site-packages/uvloop/handles/handle.pxd +48 -0
  36. .venv/lib/python3.11/site-packages/uvloop/handles/handle.pyx +395 -0
  37. .venv/lib/python3.11/site-packages/uvloop/handles/idle.pxd +14 -0
  38. .venv/lib/python3.11/site-packages/uvloop/handles/idle.pyx +72 -0
  39. .venv/lib/python3.11/site-packages/uvloop/handles/pipe.pxd +33 -0
  40. .venv/lib/python3.11/site-packages/uvloop/handles/pipe.pyx +247 -0
  41. .venv/lib/python3.11/site-packages/uvloop/handles/poll.pxd +25 -0
  42. .venv/lib/python3.11/site-packages/uvloop/handles/poll.pyx +233 -0
  43. .venv/lib/python3.11/site-packages/uvloop/handles/process.pxd +80 -0
  44. .venv/lib/python3.11/site-packages/uvloop/handles/process.pyx +792 -0
  45. .venv/lib/python3.11/site-packages/uvloop/handles/stream.pxd +50 -0
  46. .venv/lib/python3.11/site-packages/uvloop/handles/stream.pyx +1019 -0
  47. .venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pxd +26 -0
  48. .venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pyx +150 -0
  49. .venv/lib/python3.11/site-packages/uvloop/handles/tcp.pxd +26 -0
  50. .venv/lib/python3.11/site-packages/uvloop/handles/tcp.pyx +228 -0
.venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/METADATA ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.2
2
+ Name: nvidia-ml-py
3
+ Version: 12.570.86
4
+ Summary: Python Bindings for the NVIDIA Management Library
5
+ Home-page: https://forums.developer.nvidia.com
6
+ Author: NVIDIA Corporation
7
+ Author-email: nvml-bindings@nvidia.com
8
+ License: BSD
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: System Administrators
12
+ Classifier: License :: OSI Approved :: BSD License
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Classifier: Topic :: System :: Hardware
18
+ Classifier: Topic :: System :: Systems Administration
19
+ Description-Content-Type: text/markdown
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: description-content-type
25
+ Dynamic: home-page
26
+ Dynamic: license
27
+ Dynamic: summary
28
+
29
+ pyNVML
30
+ ======
31
+
32
+ Python bindings to the NVIDIA Management Library
33
+ ------------------------------------------------
34
+
35
+ Provides a Python interface to GPU management and monitoring functions.
36
+
37
+ This is a wrapper around the NVML library.
38
+ For information about the NVML library, see the NVML developer page
39
+ http://developer.nvidia.com/nvidia-management-library-nvml
40
+
41
+ Download the latest package from:
42
+ http://pypi.python.org/pypi/nvidia-ml-py/
43
+
44
+ Note this file can be run with 'python -m doctest -v README.txt'
45
+ although the results are system dependent
46
+
47
+ The nvml header file contains function documentation that is relevant
48
+ to this wrapper. The header file is distributed with.
49
+ https://developer.nvidia.com/gpu-deployment-kit
50
+
51
+ The main difference is this library handles allocating structs and
52
+ passing pointers to the functions, before returning the desired value.
53
+ Non-success return codes are raised as exceptions as described in the
54
+ section below.
55
+
56
+ REQUIRES
57
+ --------
58
+ Python 2.5, or an earlier version with the ctypes module.
59
+
60
+ INSTALLATION
61
+ ------------
62
+
63
+ Pip Installation with python3:
64
+ - `python3 -m pip install nvidia-ml-py`
65
+
66
+ Manual Installation:
67
+ ```
68
+ $ tar -xzf nvidia-ml-py-$major-$minor-$patch.tar.gz`
69
+ $ cd nvidia-ml-py-$major-$minor-$patch
70
+ $ sudo python setup.py install
71
+ ```
72
+
73
+ USAGE
74
+ -----
75
+ ```
76
+ >>> from pynvml import *
77
+ >>> nvmlInit()
78
+ >>> print(f"Driver Version: {nvmlSystemGetDriverVersion()}")
79
+ Driver Version: 11.515.48
80
+ >>> deviceCount = nvmlDeviceGetCount()
81
+ >>> for i in range(deviceCount):
82
+ ... handle = nvmlDeviceGetHandleByIndex(i)
83
+ ... print(f"Device {i} : {nvmlDeviceGetName(handle)}")
84
+ ...
85
+ Device 0 : Tesla K40c
86
+
87
+ >>> nvmlShutdown()
88
+ ```
89
+
90
+ FUNCTIONS
91
+ ---------
92
+ Python methods wrap NVML functions, implemented in a C shared library.
93
+ Each function's use is the same with the following exceptions:
94
+
95
+ - Instead of returning error codes, failing error codes are raised as Python exceptions.
96
+
97
+ ```
98
+ >>> try:
99
+ ... nvmlDeviceGetCount()
100
+ ... except NVMLError as error:
101
+ ... print(error)
102
+ ...
103
+ Uninitialized
104
+ ```
105
+
106
+ - C function output parameters are returned from the corresponding Python function left to right.
107
+ ```
108
+ nvmlReturn_t nvmlDeviceGetEccMode(nvmlDevice_t device,
109
+ nvmlEnableState_t *current,
110
+ nvmlEnableState_t *pending);
111
+
112
+ >>> nvmlInit()
113
+ >>> handle = nvmlDeviceGetHandleByIndex(0)
114
+ >>> (current, pending) = nvmlDeviceGetEccMode(handle)
115
+ ```
116
+ - C structs are converted into Python classes.
117
+
118
+ ```
119
+ // C Function and typedef struct
120
+ nvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo(nvmlDevice_t device,
121
+ nvmlMemory_t *memory);
122
+ typedef struct nvmlMemory_st {
123
+ unsigned long long total;
124
+ unsigned long long free;
125
+ unsigned long long used;
126
+ } nvmlMemory_t;
127
+
128
+
129
+ # Python call to function and accessing members of ctype struct
130
+ >>> info = nvmlDeviceGetMemoryInfo(handle)
131
+ >>> print(f"Total memory: {info.total}")
132
+ Total memory: 5636292608
133
+ >>> print(f"Free memory:, {info.free}")
134
+ Free memory: 5578420224
135
+ >>> print(f"Used memory: {info.used}")
136
+ Used memory: 57872384
137
+ ```
138
+
139
+ - Python handles string buffer creation.
140
+
141
+ ```
142
+ // C Function that needs character array and length
143
+ nvmlReturn_t nvmlSystemGetDriverVersion(char* version,
144
+ unsigned int length);
145
+
146
+ # Python function handles memory
147
+ >>> version = nvmlSystemGetDriverVersion()
148
+ >>> print(version)
149
+ ... 11.520.75
150
+ >>> nvmlShutdown()
151
+ ```
152
+
153
+ For usage information see the NVML documentation.
154
+
155
+ VARIABLES
156
+ ---------
157
+ All meaningful NVML constants and enums are exposed in Python.
158
+
159
+ The NVML_VALUE_NOT_AVAILABLE constant is not used. Instead None is mapped to the field.
160
+
161
+ EXCEPTIONS
162
+ ----------
163
+ Since the C library uses return codes and python prefers exception handling, the
164
+ library converts all return codes to various exceptions. The exceptions are generated
165
+ automatically via a function at run time instead of being defined manually.
166
+
167
+ The list of exceptions can be found in NVMLError base class.
168
+
169
+ The example seen above in the FUNCTIONS section:
170
+
171
+ ```
172
+ >>> try:
173
+ ... nvmlDeviceGetCount()
174
+ ... except NVMLError as error:
175
+ ... print(error)
176
+ ...
177
+ Uninitialized
178
+ ```
179
+
180
+ Can be more accurately caught like this:
181
+
182
+ ```
183
+ >>> try:
184
+ ... nvmlDeviceGetCount()
185
+ ... except NVMLError_Uninitialized as error:
186
+ ... print(error)
187
+ ...
188
+ Uninitialized
189
+ ```
190
+
191
+ The conversion from name to exception is like this for all exceptions:
192
+ * `NVML_ERROR_UNINITIALIZED` => `NVMLError_Uninitialized`
193
+ * `NVML_ERROR_LIBRARY_NOT_FOUND` => `NVMLError_LibraryNotFound`
194
+ * `NVML_ERROR_ALREADY_INITIALIZED` => `NVMLError_AlreadyInitialized`
195
+
196
+ RELEASE NOTES
197
+ -------------
198
+ Version 2.285.0
199
+ - Added new functions for NVML 2.285. See NVML documentation for more information.
200
+ - Ported to support Python 3.0 and Python 2.0 syntax.
201
+ - Added nvidia_smi.py tool as a sample app.
202
+
203
+ Version 3.295.0
204
+ - Added new functions for NVML 3.295. See NVML documentation for more information.
205
+ - Updated nvidia_smi.py tool
206
+ - Includes additional error handling
207
+
208
+ Version 4.304.0
209
+ - Added new functions for NVML 4.304. See NVML documentation for more information.
210
+ - Updated nvidia_smi.py tool
211
+
212
+ Version 4.304.3
213
+ - Fixing nvmlUnitGetDeviceCount bug
214
+
215
+ Version 5.319.0
216
+ - Added new functions for NVML 5.319. See NVML documentation for more information.
217
+
218
+ Version 6.340.0
219
+ - Added new functions for NVML 6.340. See NVML documentation for more information.
220
+
221
+ Version 7.346.0
222
+ - Added new functions for NVML 7.346. See NVML documentation for more information.
223
+
224
+ Version 7.352.0
225
+ - Added new functions for NVML 7.352. See NVML documentation for more information.
226
+
227
+ Version 10.418
228
+ - Added new functions for NVML 10.418. See NVML documentation for more information.
229
+ - Fixed issues with using the bindings with Python 3.x
230
+ - Replaced sample app nvidia_smi.py with example.py
231
+
232
+ Version 11.515.48
233
+ - Python3 support added
234
+ - Updated API to add function new to NVML, bringing pynvml up to date with NVML
235
+ - Added auto-version to handle byte and string conversion automatically for both structs and functions
236
+ - Minor bug fixes
237
+ - Added README.txt correctly in long_description for pypi.org
238
+
239
+ Version 11.520
240
+ - Updated Long Description to be actual markdown
241
+ - Added new functions for NVML 11.520
242
+
243
+ Version 11.525
244
+ - Added new functions for NVML 11.525
245
+
246
+ COPYRIGHT
247
+ ---------
248
+ Copyright (c) 2011-2023, NVIDIA Corporation. All rights reserved.
249
+
250
+ LICENSE
251
+ -------
252
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
253
+
254
+ - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
255
+
256
+ - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
257
+
258
+ - Neither the name of the NVIDIA Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
259
+
260
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
261
+
.venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/RECORD ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/example.cpython-311.pyc,,
2
+ __pycache__/pynvml.cpython-311.pyc,,
3
+ example.py,sha256=mDXwPVyEDuiKeMApEh53r_M36xuncmzMpFOGA3Q-_Kw,7968
4
+ nvidia_ml_py-12.570.86.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
5
+ nvidia_ml_py-12.570.86.dist-info/METADATA,sha256=vY-jfk5MJsbWGy2jmbgdwfPKG4G0FHbspv-av_h5bEE,8718
6
+ nvidia_ml_py-12.570.86.dist-info/RECORD,,
7
+ nvidia_ml_py-12.570.86.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
8
+ nvidia_ml_py-12.570.86.dist-info/top_level.txt,sha256=wLINSA1WKnhsGgKsb_nuj51ZCQrXaN5qhioTL56g98A,15
9
+ pynvml.py,sha256=PCW5qJPhGshkIhIUOOQyUXsxkCVaPeTi30R7LsJb4YE,234473
.venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
.venv/lib/python3.11/site-packages/nvidia_ml_py-12.570.86.dist-info/top_level.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ example
2
+ pynvml
.venv/lib/python3.11/site-packages/platformdirs-4.3.6.dist-info/METADATA ADDED
@@ -0,0 +1,327 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.3
2
+ Name: platformdirs
3
+ Version: 4.3.6
4
+ Summary: A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`.
5
+ Project-URL: Changelog, https://github.com/tox-dev/platformdirs/releases
6
+ Project-URL: Documentation, https://platformdirs.readthedocs.io
7
+ Project-URL: Homepage, https://github.com/tox-dev/platformdirs
8
+ Project-URL: Source, https://github.com/tox-dev/platformdirs
9
+ Project-URL: Tracker, https://github.com/tox-dev/platformdirs/issues
10
+ Maintainer-email: Bernát Gábor <gaborjbernat@gmail.com>, Julian Berman <Julian@GrayVines.com>, Ofek Lev <oss@ofek.dev>, Ronny Pfannschmidt <opensource@ronnypfannschmidt.de>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: appdirs,application,cache,directory,log,user
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: Implementation :: CPython
27
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
28
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
29
+ Requires-Python: >=3.8
30
+ Provides-Extra: docs
31
+ Requires-Dist: furo>=2024.8.6; extra == 'docs'
32
+ Requires-Dist: proselint>=0.14; extra == 'docs'
33
+ Requires-Dist: sphinx-autodoc-typehints>=2.4; extra == 'docs'
34
+ Requires-Dist: sphinx>=8.0.2; extra == 'docs'
35
+ Provides-Extra: test
36
+ Requires-Dist: appdirs==1.4.4; extra == 'test'
37
+ Requires-Dist: covdefaults>=2.3; extra == 'test'
38
+ Requires-Dist: pytest-cov>=5; extra == 'test'
39
+ Requires-Dist: pytest-mock>=3.14; extra == 'test'
40
+ Requires-Dist: pytest>=8.3.2; extra == 'test'
41
+ Provides-Extra: type
42
+ Requires-Dist: mypy>=1.11.2; extra == 'type'
43
+ Description-Content-Type: text/x-rst
44
+
45
+ The problem
46
+ ===========
47
+
48
+ .. image:: https://badge.fury.io/py/platformdirs.svg
49
+ :target: https://badge.fury.io/py/platformdirs
50
+ .. image:: https://img.shields.io/pypi/pyversions/platformdirs.svg
51
+ :target: https://pypi.python.org/pypi/platformdirs/
52
+ .. image:: https://github.com/tox-dev/platformdirs/actions/workflows/check.yaml/badge.svg
53
+ :target: https://github.com/platformdirs/platformdirs/actions
54
+ .. image:: https://static.pepy.tech/badge/platformdirs/month
55
+ :target: https://pepy.tech/project/platformdirs
56
+
57
+ When writing desktop application, finding the right location to store user data
58
+ and configuration varies per platform. Even for single-platform apps, there
59
+ may by plenty of nuances in figuring out the right location.
60
+
61
+ For example, if running on macOS, you should use::
62
+
63
+ ~/Library/Application Support/<AppName>
64
+
65
+ If on Windows (at least English Win) that should be::
66
+
67
+ C:\Documents and Settings\<User>\Application Data\Local Settings\<AppAuthor>\<AppName>
68
+
69
+ or possibly::
70
+
71
+ C:\Documents and Settings\<User>\Application Data\<AppAuthor>\<AppName>
72
+
73
+ for `roaming profiles <https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc766489(v=ws.10)>`_ but that is another story.
74
+
75
+ On Linux (and other Unices), according to the `XDG Basedir Spec`_, it should be::
76
+
77
+ ~/.local/share/<AppName>
78
+
79
+ .. _XDG Basedir Spec: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
80
+
81
+ ``platformdirs`` to the rescue
82
+ ==============================
83
+
84
+ This kind of thing is what the ``platformdirs`` package is for.
85
+ ``platformdirs`` will help you choose an appropriate:
86
+
87
+ - user data dir (``user_data_dir``)
88
+ - user config dir (``user_config_dir``)
89
+ - user cache dir (``user_cache_dir``)
90
+ - site data dir (``site_data_dir``)
91
+ - site config dir (``site_config_dir``)
92
+ - user log dir (``user_log_dir``)
93
+ - user documents dir (``user_documents_dir``)
94
+ - user downloads dir (``user_downloads_dir``)
95
+ - user pictures dir (``user_pictures_dir``)
96
+ - user videos dir (``user_videos_dir``)
97
+ - user music dir (``user_music_dir``)
98
+ - user desktop dir (``user_desktop_dir``)
99
+ - user runtime dir (``user_runtime_dir``)
100
+
101
+ And also:
102
+
103
+ - Is slightly opinionated on the directory names used. Look for "OPINION" in
104
+ documentation and code for when an opinion is being applied.
105
+
106
+ Example output
107
+ ==============
108
+
109
+ On macOS:
110
+
111
+ .. code-block:: pycon
112
+
113
+ >>> from platformdirs import *
114
+ >>> appname = "SuperApp"
115
+ >>> appauthor = "Acme"
116
+ >>> user_data_dir(appname, appauthor)
117
+ '/Users/trentm/Library/Application Support/SuperApp'
118
+ >>> site_data_dir(appname, appauthor)
119
+ '/Library/Application Support/SuperApp'
120
+ >>> user_cache_dir(appname, appauthor)
121
+ '/Users/trentm/Library/Caches/SuperApp'
122
+ >>> user_log_dir(appname, appauthor)
123
+ '/Users/trentm/Library/Logs/SuperApp'
124
+ >>> user_documents_dir()
125
+ '/Users/trentm/Documents'
126
+ >>> user_downloads_dir()
127
+ '/Users/trentm/Downloads'
128
+ >>> user_pictures_dir()
129
+ '/Users/trentm/Pictures'
130
+ >>> user_videos_dir()
131
+ '/Users/trentm/Movies'
132
+ >>> user_music_dir()
133
+ '/Users/trentm/Music'
134
+ >>> user_desktop_dir()
135
+ '/Users/trentm/Desktop'
136
+ >>> user_runtime_dir(appname, appauthor)
137
+ '/Users/trentm/Library/Caches/TemporaryItems/SuperApp'
138
+
139
+ On Windows:
140
+
141
+ .. code-block:: pycon
142
+
143
+ >>> from platformdirs import *
144
+ >>> appname = "SuperApp"
145
+ >>> appauthor = "Acme"
146
+ >>> user_data_dir(appname, appauthor)
147
+ 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp'
148
+ >>> user_data_dir(appname, appauthor, roaming=True)
149
+ 'C:\\Users\\trentm\\AppData\\Roaming\\Acme\\SuperApp'
150
+ >>> user_cache_dir(appname, appauthor)
151
+ 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Cache'
152
+ >>> user_log_dir(appname, appauthor)
153
+ 'C:\\Users\\trentm\\AppData\\Local\\Acme\\SuperApp\\Logs'
154
+ >>> user_documents_dir()
155
+ 'C:\\Users\\trentm\\Documents'
156
+ >>> user_downloads_dir()
157
+ 'C:\\Users\\trentm\\Downloads'
158
+ >>> user_pictures_dir()
159
+ 'C:\\Users\\trentm\\Pictures'
160
+ >>> user_videos_dir()
161
+ 'C:\\Users\\trentm\\Videos'
162
+ >>> user_music_dir()
163
+ 'C:\\Users\\trentm\\Music'
164
+ >>> user_desktop_dir()
165
+ 'C:\\Users\\trentm\\Desktop'
166
+ >>> user_runtime_dir(appname, appauthor)
167
+ 'C:\\Users\\trentm\\AppData\\Local\\Temp\\Acme\\SuperApp'
168
+
169
+ On Linux:
170
+
171
+ .. code-block:: pycon
172
+
173
+ >>> from platformdirs import *
174
+ >>> appname = "SuperApp"
175
+ >>> appauthor = "Acme"
176
+ >>> user_data_dir(appname, appauthor)
177
+ '/home/trentm/.local/share/SuperApp'
178
+ >>> site_data_dir(appname, appauthor)
179
+ '/usr/local/share/SuperApp'
180
+ >>> site_data_dir(appname, appauthor, multipath=True)
181
+ '/usr/local/share/SuperApp:/usr/share/SuperApp'
182
+ >>> user_cache_dir(appname, appauthor)
183
+ '/home/trentm/.cache/SuperApp'
184
+ >>> user_log_dir(appname, appauthor)
185
+ '/home/trentm/.local/state/SuperApp/log'
186
+ >>> user_config_dir(appname)
187
+ '/home/trentm/.config/SuperApp'
188
+ >>> user_documents_dir()
189
+ '/home/trentm/Documents'
190
+ >>> user_downloads_dir()
191
+ '/home/trentm/Downloads'
192
+ >>> user_pictures_dir()
193
+ '/home/trentm/Pictures'
194
+ >>> user_videos_dir()
195
+ '/home/trentm/Videos'
196
+ >>> user_music_dir()
197
+ '/home/trentm/Music'
198
+ >>> user_desktop_dir()
199
+ '/home/trentm/Desktop'
200
+ >>> user_runtime_dir(appname, appauthor)
201
+ '/run/user/{os.getuid()}/SuperApp'
202
+ >>> site_config_dir(appname)
203
+ '/etc/xdg/SuperApp'
204
+ >>> os.environ["XDG_CONFIG_DIRS"] = "/etc:/usr/local/etc"
205
+ >>> site_config_dir(appname, multipath=True)
206
+ '/etc/SuperApp:/usr/local/etc/SuperApp'
207
+
208
+ On Android::
209
+
210
+ >>> from platformdirs import *
211
+ >>> appname = "SuperApp"
212
+ >>> appauthor = "Acme"
213
+ >>> user_data_dir(appname, appauthor)
214
+ '/data/data/com.myApp/files/SuperApp'
215
+ >>> user_cache_dir(appname, appauthor)
216
+ '/data/data/com.myApp/cache/SuperApp'
217
+ >>> user_log_dir(appname, appauthor)
218
+ '/data/data/com.myApp/cache/SuperApp/log'
219
+ >>> user_config_dir(appname)
220
+ '/data/data/com.myApp/shared_prefs/SuperApp'
221
+ >>> user_documents_dir()
222
+ '/storage/emulated/0/Documents'
223
+ >>> user_downloads_dir()
224
+ '/storage/emulated/0/Downloads'
225
+ >>> user_pictures_dir()
226
+ '/storage/emulated/0/Pictures'
227
+ >>> user_videos_dir()
228
+ '/storage/emulated/0/DCIM/Camera'
229
+ >>> user_music_dir()
230
+ '/storage/emulated/0/Music'
231
+ >>> user_desktop_dir()
232
+ '/storage/emulated/0/Desktop'
233
+ >>> user_runtime_dir(appname, appauthor)
234
+ '/data/data/com.myApp/cache/SuperApp/tmp'
235
+
236
+ Note: Some android apps like Termux and Pydroid are used as shells. These
237
+ apps are used by the end user to emulate Linux environment. Presence of
238
+ ``SHELL`` environment variable is used by Platformdirs to differentiate
239
+ between general android apps and android apps used as shells. Shell android
240
+ apps also support ``XDG_*`` environment variables.
241
+
242
+
243
+ ``PlatformDirs`` for convenience
244
+ ================================
245
+
246
+ .. code-block:: pycon
247
+
248
+ >>> from platformdirs import PlatformDirs
249
+ >>> dirs = PlatformDirs("SuperApp", "Acme")
250
+ >>> dirs.user_data_dir
251
+ '/Users/trentm/Library/Application Support/SuperApp'
252
+ >>> dirs.site_data_dir
253
+ '/Library/Application Support/SuperApp'
254
+ >>> dirs.user_cache_dir
255
+ '/Users/trentm/Library/Caches/SuperApp'
256
+ >>> dirs.user_log_dir
257
+ '/Users/trentm/Library/Logs/SuperApp'
258
+ >>> dirs.user_documents_dir
259
+ '/Users/trentm/Documents'
260
+ >>> dirs.user_downloads_dir
261
+ '/Users/trentm/Downloads'
262
+ >>> dirs.user_pictures_dir
263
+ '/Users/trentm/Pictures'
264
+ >>> dirs.user_videos_dir
265
+ '/Users/trentm/Movies'
266
+ >>> dirs.user_music_dir
267
+ '/Users/trentm/Music'
268
+ >>> dirs.user_desktop_dir
269
+ '/Users/trentm/Desktop'
270
+ >>> dirs.user_runtime_dir
271
+ '/Users/trentm/Library/Caches/TemporaryItems/SuperApp'
272
+
273
+ Per-version isolation
274
+ =====================
275
+
276
+ If you have multiple versions of your app in use that you want to be
277
+ able to run side-by-side, then you may want version-isolation for these
278
+ dirs::
279
+
280
+ >>> from platformdirs import PlatformDirs
281
+ >>> dirs = PlatformDirs("SuperApp", "Acme", version="1.0")
282
+ >>> dirs.user_data_dir
283
+ '/Users/trentm/Library/Application Support/SuperApp/1.0'
284
+ >>> dirs.site_data_dir
285
+ '/Library/Application Support/SuperApp/1.0'
286
+ >>> dirs.user_cache_dir
287
+ '/Users/trentm/Library/Caches/SuperApp/1.0'
288
+ >>> dirs.user_log_dir
289
+ '/Users/trentm/Library/Logs/SuperApp/1.0'
290
+ >>> dirs.user_documents_dir
291
+ '/Users/trentm/Documents'
292
+ >>> dirs.user_downloads_dir
293
+ '/Users/trentm/Downloads'
294
+ >>> dirs.user_pictures_dir
295
+ '/Users/trentm/Pictures'
296
+ >>> dirs.user_videos_dir
297
+ '/Users/trentm/Movies'
298
+ >>> dirs.user_music_dir
299
+ '/Users/trentm/Music'
300
+ >>> dirs.user_desktop_dir
301
+ '/Users/trentm/Desktop'
302
+ >>> dirs.user_runtime_dir
303
+ '/Users/trentm/Library/Caches/TemporaryItems/SuperApp/1.0'
304
+
305
+ Be wary of using this for configuration files though; you'll need to handle
306
+ migrating configuration files manually.
307
+
308
+ Why this Fork?
309
+ ==============
310
+
311
+ This repository is a friendly fork of the wonderful work started by
312
+ `ActiveState <https://github.com/ActiveState/appdirs>`_ who created
313
+ ``appdirs``, this package's ancestor.
314
+
315
+ Maintaining an open source project is no easy task, particularly
316
+ from within an organization, and the Python community is indebted
317
+ to ``appdirs`` (and to Trent Mick and Jeff Rouse in particular) for
318
+ creating an incredibly useful simple module, as evidenced by the wide
319
+ number of users it has attracted over the years.
320
+
321
+ Nonetheless, given the number of long-standing open issues
322
+ and pull requests, and no clear path towards `ensuring
323
+ that maintenance of the package would continue or grow
324
+ <https://github.com/ActiveState/appdirs/issues/79>`_, this fork was
325
+ created.
326
+
327
+ Contributions are most welcome.
.venv/lib/python3.11/site-packages/platformdirs-4.3.6.dist-info/RECORD ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ platformdirs-4.3.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ platformdirs-4.3.6.dist-info/METADATA,sha256=085GgRFo5U1nc9NR8e6unEWKxUjDMsgSHDyaCETsCQ4,11868
3
+ platformdirs-4.3.6.dist-info/RECORD,,
4
+ platformdirs-4.3.6.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
5
+ platformdirs-4.3.6.dist-info/licenses/LICENSE,sha256=KeD9YukphQ6G6yjD_czwzv30-pSHkBHP-z0NS-1tTbY,1089
6
+ platformdirs/__init__.py,sha256=mVCfMmBM4q24lq6336V3VJncdxaOegI4qQSmQCjkR5E,22284
7
+ platformdirs/__main__.py,sha256=HnsUQHpiBaiTxwcmwVw-nFaPdVNZtQIdi1eWDtI-MzI,1493
8
+ platformdirs/__pycache__/__init__.cpython-311.pyc,,
9
+ platformdirs/__pycache__/__main__.cpython-311.pyc,,
10
+ platformdirs/__pycache__/android.cpython-311.pyc,,
11
+ platformdirs/__pycache__/api.cpython-311.pyc,,
12
+ platformdirs/__pycache__/macos.cpython-311.pyc,,
13
+ platformdirs/__pycache__/unix.cpython-311.pyc,,
14
+ platformdirs/__pycache__/version.cpython-311.pyc,,
15
+ platformdirs/__pycache__/windows.cpython-311.pyc,,
16
+ platformdirs/android.py,sha256=kV5oL3V3DZ6WZKu9yFiQupv18yp_jlSV2ChH1TmPcds,9007
17
+ platformdirs/api.py,sha256=2dfUDNbEXeDhDKarqtR5NY7oUikUZ4RZhs3ozstmhBQ,9246
18
+ platformdirs/macos.py,sha256=UlbyFZ8Rzu3xndCqQEHrfsYTeHwYdFap1Ioz-yxveT4,6154
19
+ platformdirs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ platformdirs/unix.py,sha256=uRPJWRyQEtv7yOSvU94rUmsblo5XKDLA1SzFg55kbK0,10393
21
+ platformdirs/version.py,sha256=oH4KgTfK4AklbTYVcV_yynvJ9JLI3pyvDVay0hRsLCs,411
22
+ platformdirs/windows.py,sha256=IFpiohUBwxPtCzlyKwNtxyW4Jk8haa6W8o59mfrDXVo,10125
.venv/lib/python3.11/site-packages/platformdirs-4.3.6.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2010-202x The platformdirs developers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
.venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/METADATA ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: pytest
3
+ Version: 8.3.4
4
+ Summary: pytest: simple powerful testing with Python
5
+ Author: Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin, Others (See AUTHORS)
6
+ License: MIT
7
+ Project-URL: Changelog, https://docs.pytest.org/en/stable/changelog.html
8
+ Project-URL: Homepage, https://docs.pytest.org/en/latest/
9
+ Project-URL: Source, https://github.com/pytest-dev/pytest
10
+ Project-URL: Tracker, https://github.com/pytest-dev/pytest/issues
11
+ Project-URL: Twitter, https://twitter.com/pytestdotorg
12
+ Keywords: test,unittest
13
+ Classifier: Development Status :: 6 - Mature
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: Microsoft :: Windows
18
+ Classifier: Operating System :: POSIX
19
+ Classifier: Operating System :: Unix
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.8
22
+ Classifier: Programming Language :: Python :: 3.9
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Topic :: Software Development :: Libraries
27
+ Classifier: Topic :: Software Development :: Testing
28
+ Classifier: Topic :: Utilities
29
+ Requires-Python: >=3.8
30
+ Description-Content-Type: text/x-rst
31
+ License-File: LICENSE
32
+ License-File: AUTHORS
33
+ Requires-Dist: colorama; sys_platform == "win32"
34
+ Requires-Dist: exceptiongroup>=1.0.0rc8; python_version < "3.11"
35
+ Requires-Dist: iniconfig
36
+ Requires-Dist: packaging
37
+ Requires-Dist: pluggy<2,>=1.5
38
+ Requires-Dist: tomli>=1; python_version < "3.11"
39
+ Provides-Extra: dev
40
+ Requires-Dist: argcomplete; extra == "dev"
41
+ Requires-Dist: attrs>=19.2; extra == "dev"
42
+ Requires-Dist: hypothesis>=3.56; extra == "dev"
43
+ Requires-Dist: mock; extra == "dev"
44
+ Requires-Dist: pygments>=2.7.2; extra == "dev"
45
+ Requires-Dist: requests; extra == "dev"
46
+ Requires-Dist: setuptools; extra == "dev"
47
+ Requires-Dist: xmlschema; extra == "dev"
48
+
49
+ .. image:: https://github.com/pytest-dev/pytest/raw/main/doc/en/img/pytest_logo_curves.svg
50
+ :target: https://docs.pytest.org/en/stable/
51
+ :align: center
52
+ :height: 200
53
+ :alt: pytest
54
+
55
+
56
+ ------
57
+
58
+ .. image:: https://img.shields.io/pypi/v/pytest.svg
59
+ :target: https://pypi.org/project/pytest/
60
+
61
+ .. image:: https://img.shields.io/conda/vn/conda-forge/pytest.svg
62
+ :target: https://anaconda.org/conda-forge/pytest
63
+
64
+ .. image:: https://img.shields.io/pypi/pyversions/pytest.svg
65
+ :target: https://pypi.org/project/pytest/
66
+
67
+ .. image:: https://codecov.io/gh/pytest-dev/pytest/branch/main/graph/badge.svg
68
+ :target: https://codecov.io/gh/pytest-dev/pytest
69
+ :alt: Code coverage Status
70
+
71
+ .. image:: https://github.com/pytest-dev/pytest/actions/workflows/test.yml/badge.svg
72
+ :target: https://github.com/pytest-dev/pytest/actions?query=workflow%3Atest
73
+
74
+ .. image:: https://results.pre-commit.ci/badge/github/pytest-dev/pytest/main.svg
75
+ :target: https://results.pre-commit.ci/latest/github/pytest-dev/pytest/main
76
+ :alt: pre-commit.ci status
77
+
78
+ .. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg
79
+ :target: https://www.codetriage.com/pytest-dev/pytest
80
+
81
+ .. image:: https://readthedocs.org/projects/pytest/badge/?version=latest
82
+ :target: https://pytest.readthedocs.io/en/latest/?badge=latest
83
+ :alt: Documentation Status
84
+
85
+ .. image:: https://img.shields.io/badge/Discord-pytest--dev-blue
86
+ :target: https://discord.com/invite/pytest-dev
87
+ :alt: Discord
88
+
89
+ .. image:: https://img.shields.io/badge/Libera%20chat-%23pytest-orange
90
+ :target: https://web.libera.chat/#pytest
91
+ :alt: Libera chat
92
+
93
+
94
+ The ``pytest`` framework makes it easy to write small tests, yet
95
+ scales to support complex functional testing for applications and libraries.
96
+
97
+ An example of a simple test:
98
+
99
+ .. code-block:: python
100
+
101
+ # content of test_sample.py
102
+ def inc(x):
103
+ return x + 1
104
+
105
+
106
+ def test_answer():
107
+ assert inc(3) == 5
108
+
109
+
110
+ To execute it::
111
+
112
+ $ pytest
113
+ ============================= test session starts =============================
114
+ collected 1 items
115
+
116
+ test_sample.py F
117
+
118
+ ================================== FAILURES ===================================
119
+ _________________________________ test_answer _________________________________
120
+
121
+ def test_answer():
122
+ > assert inc(3) == 5
123
+ E assert 4 == 5
124
+ E + where 4 = inc(3)
125
+
126
+ test_sample.py:5: AssertionError
127
+ ========================== 1 failed in 0.04 seconds ===========================
128
+
129
+
130
+ Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <https://docs.pytest.org/en/stable/getting-started.html#our-first-test-run>`_ for more examples.
131
+
132
+
133
+ Features
134
+ --------
135
+
136
+ - Detailed info on failing `assert statements <https://docs.pytest.org/en/stable/how-to/assert.html>`_ (no need to remember ``self.assert*`` names)
137
+
138
+ - `Auto-discovery
139
+ <https://docs.pytest.org/en/stable/explanation/goodpractices.html#python-test-discovery>`_
140
+ of test modules and functions
141
+
142
+ - `Modular fixtures <https://docs.pytest.org/en/stable/explanation/fixtures.html>`_ for
143
+ managing small or parametrized long-lived test resources
144
+
145
+ - Can run `unittest <https://docs.pytest.org/en/stable/how-to/unittest.html>`_ (or trial)
146
+ test suites out of the box
147
+
148
+ - Python 3.8+ or PyPy3
149
+
150
+ - Rich plugin architecture, with over 1300+ `external plugins <https://docs.pytest.org/en/latest/reference/plugin_list.html>`_ and thriving community
151
+
152
+
153
+ Documentation
154
+ -------------
155
+
156
+ For full documentation, including installation, tutorials and PDF documents, please see https://docs.pytest.org/en/stable/.
157
+
158
+
159
+ Bugs/Requests
160
+ -------------
161
+
162
+ Please use the `GitHub issue tracker <https://github.com/pytest-dev/pytest/issues>`_ to submit bugs or request features.
163
+
164
+
165
+ Changelog
166
+ ---------
167
+
168
+ Consult the `Changelog <https://docs.pytest.org/en/stable/changelog.html>`__ page for fixes and enhancements of each version.
169
+
170
+
171
+ Support pytest
172
+ --------------
173
+
174
+ `Open Collective`_ is an online funding platform for open and transparent communities.
175
+ It provides tools to raise money and share your finances in full transparency.
176
+
177
+ It is the platform of choice for individuals and companies that want to make one-time or
178
+ monthly donations directly to the project.
179
+
180
+ See more details in the `pytest collective`_.
181
+
182
+ .. _Open Collective: https://opencollective.com
183
+ .. _pytest collective: https://opencollective.com/pytest
184
+
185
+
186
+ pytest for enterprise
187
+ ---------------------
188
+
189
+ Available as part of the Tidelift Subscription.
190
+
191
+ The maintainers of pytest and thousands of other packages are working with Tidelift to deliver commercial support and
192
+ maintenance for the open source dependencies you use to build your applications.
193
+ Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.
194
+
195
+ `Learn more. <https://tidelift.com/subscription/pkg/pypi-pytest?utm_source=pypi-pytest&utm_medium=referral&utm_campaign=enterprise&utm_term=repo>`_
196
+
197
+ Security
198
+ ^^^^^^^^
199
+
200
+ pytest has never been associated with a security vulnerability, but in any case, to report a
201
+ security vulnerability please use the `Tidelift security contact <https://tidelift.com/security>`_.
202
+ Tidelift will coordinate the fix and disclosure.
203
+
204
+
205
+ License
206
+ -------
207
+
208
+ Copyright Holger Krekel and others, 2004.
209
+
210
+ Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
211
+
212
+ .. _`MIT`: https://github.com/pytest-dev/pytest/blob/main/LICENSE
.venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/RECORD ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ../../../bin/py.test,sha256=vvHOr9KK5AGKvqYrdl0oQCYePyyaJI8PmXGxzS68qLc,239
2
+ ../../../bin/pytest,sha256=vvHOr9KK5AGKvqYrdl0oQCYePyyaJI8PmXGxzS68qLc,239
3
+ __pycache__/py.cpython-311.pyc,,
4
+ _pytest/__init__.py,sha256=4IdRJhnW5XG2KlaJkOxn5_TC9WeQ5tXDSF7tbb4vEso,391
5
+ _pytest/__pycache__/__init__.cpython-311.pyc,,
6
+ _pytest/__pycache__/_argcomplete.cpython-311.pyc,,
7
+ _pytest/__pycache__/_version.cpython-311.pyc,,
8
+ _pytest/__pycache__/cacheprovider.cpython-311.pyc,,
9
+ _pytest/__pycache__/capture.cpython-311.pyc,,
10
+ _pytest/__pycache__/compat.cpython-311.pyc,,
11
+ _pytest/__pycache__/debugging.cpython-311.pyc,,
12
+ _pytest/__pycache__/deprecated.cpython-311.pyc,,
13
+ _pytest/__pycache__/doctest.cpython-311.pyc,,
14
+ _pytest/__pycache__/faulthandler.cpython-311.pyc,,
15
+ _pytest/__pycache__/fixtures.cpython-311.pyc,,
16
+ _pytest/__pycache__/freeze_support.cpython-311.pyc,,
17
+ _pytest/__pycache__/helpconfig.cpython-311.pyc,,
18
+ _pytest/__pycache__/hookspec.cpython-311.pyc,,
19
+ _pytest/__pycache__/junitxml.cpython-311.pyc,,
20
+ _pytest/__pycache__/legacypath.cpython-311.pyc,,
21
+ _pytest/__pycache__/logging.cpython-311.pyc,,
22
+ _pytest/__pycache__/main.cpython-311.pyc,,
23
+ _pytest/__pycache__/monkeypatch.cpython-311.pyc,,
24
+ _pytest/__pycache__/nodes.cpython-311.pyc,,
25
+ _pytest/__pycache__/outcomes.cpython-311.pyc,,
26
+ _pytest/__pycache__/pastebin.cpython-311.pyc,,
27
+ _pytest/__pycache__/pathlib.cpython-311.pyc,,
28
+ _pytest/__pycache__/pytester.cpython-311.pyc,,
29
+ _pytest/__pycache__/pytester_assertions.cpython-311.pyc,,
30
+ _pytest/__pycache__/python.cpython-311.pyc,,
31
+ _pytest/__pycache__/python_api.cpython-311.pyc,,
32
+ _pytest/__pycache__/python_path.cpython-311.pyc,,
33
+ _pytest/__pycache__/recwarn.cpython-311.pyc,,
34
+ _pytest/__pycache__/reports.cpython-311.pyc,,
35
+ _pytest/__pycache__/runner.cpython-311.pyc,,
36
+ _pytest/__pycache__/scope.cpython-311.pyc,,
37
+ _pytest/__pycache__/setuponly.cpython-311.pyc,,
38
+ _pytest/__pycache__/setupplan.cpython-311.pyc,,
39
+ _pytest/__pycache__/skipping.cpython-311.pyc,,
40
+ _pytest/__pycache__/stash.cpython-311.pyc,,
41
+ _pytest/__pycache__/stepwise.cpython-311.pyc,,
42
+ _pytest/__pycache__/terminal.cpython-311.pyc,,
43
+ _pytest/__pycache__/threadexception.cpython-311.pyc,,
44
+ _pytest/__pycache__/timing.cpython-311.pyc,,
45
+ _pytest/__pycache__/tmpdir.cpython-311.pyc,,
46
+ _pytest/__pycache__/unittest.cpython-311.pyc,,
47
+ _pytest/__pycache__/unraisableexception.cpython-311.pyc,,
48
+ _pytest/__pycache__/warning_types.cpython-311.pyc,,
49
+ _pytest/__pycache__/warnings.cpython-311.pyc,,
50
+ _pytest/_argcomplete.py,sha256=gh0pna66p4LVb2D8ST4568WGxvdInGT43m6slYhqNqU,3776
51
+ _pytest/_code/__init__.py,sha256=5h7R-LFINKh7p8QR1HgdjvSGo1ysVJz28MQ9h7ipHK4,521
52
+ _pytest/_code/__pycache__/__init__.cpython-311.pyc,,
53
+ _pytest/_code/__pycache__/code.cpython-311.pyc,,
54
+ _pytest/_code/__pycache__/source.cpython-311.pyc,,
55
+ _pytest/_code/code.py,sha256=umPdqLxq8UgWKAItTEvF6ZOq5dF65mzCJHFaZHzTNGY,50133
56
+ _pytest/_code/source.py,sha256=2w9OZFOrRpiVaD_UdUS1T2XC7c2Is2GZn0iQy-lZfwk,7278
57
+ _pytest/_io/__init__.py,sha256=pkLF29VEFr6Dlr3eOtJL8sf47RLFt1Jf4X1DZBPlYmc,190
58
+ _pytest/_io/__pycache__/__init__.cpython-311.pyc,,
59
+ _pytest/_io/__pycache__/pprint.cpython-311.pyc,,
60
+ _pytest/_io/__pycache__/saferepr.cpython-311.pyc,,
61
+ _pytest/_io/__pycache__/terminalwriter.cpython-311.pyc,,
62
+ _pytest/_io/__pycache__/wcwidth.cpython-311.pyc,,
63
+ _pytest/_io/pprint.py,sha256=BCe8K7Zc0drYC5_JKZBBMVrhK84ARlmPpk9vSWPYhaE,19633
64
+ _pytest/_io/saferepr.py,sha256=Hhx5F-75iz03hdk-WO86Bmy9RBuRHsuJj-YUzozfrgo,4082
65
+ _pytest/_io/terminalwriter.py,sha256=dQ07zJ1-vlpFqWBBu_c0cHxT0yXcGSu7o7LxDCEyB3s,9319
66
+ _pytest/_io/wcwidth.py,sha256=cUEJ74UhweICwbKvU2q6noZcNgD0QlBEB9CfakGYaqA,1289
67
+ _pytest/_py/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
+ _pytest/_py/__pycache__/__init__.cpython-311.pyc,,
69
+ _pytest/_py/__pycache__/error.cpython-311.pyc,,
70
+ _pytest/_py/__pycache__/path.cpython-311.pyc,,
71
+ _pytest/_py/error.py,sha256=S1BRlfXSD248OFNzAuZ5O9w9W6fr2NUn0X8wYFGMNk0,3015
72
+ _pytest/_py/path.py,sha256=Xl4UspvrwwKYNlLZDGbjhUrnD6fuBmFxxchgltmwGek,49211
73
+ _pytest/_version.py,sha256=lMdMvJTmZKMLyCj9eyDEhOf6ttbh5vLbkANi6yBfmkc,411
74
+ _pytest/assertion/__init__.py,sha256=lK1YNNAk1VqCK-Y5C5hMJMqJQyxQT11HuDH3w85a3Zc,6791
75
+ _pytest/assertion/__pycache__/__init__.cpython-311.pyc,,
76
+ _pytest/assertion/__pycache__/rewrite.cpython-311.pyc,,
77
+ _pytest/assertion/__pycache__/truncate.cpython-311.pyc,,
78
+ _pytest/assertion/__pycache__/util.cpython-311.pyc,,
79
+ _pytest/assertion/rewrite.py,sha256=OltHwIVPXCPe0Ejgta_4hWjY8Xo3BIGbQEyLREfXZCA,48272
80
+ _pytest/assertion/truncate.py,sha256=GYl5iqDXUuKQHgd_mthWl3ZjxBbDVQliBhks1Ty00kE,4459
81
+ _pytest/assertion/util.py,sha256=6Vg5dZDuIXak9OLupvKyavLDroATgpU6ilkclc0OlJY,20265
82
+ _pytest/cacheprovider.py,sha256=BFQVkna56tlO-v9qaNJVHIcF30hIVGrP9St_vMp4w98,22373
83
+ _pytest/capture.py,sha256=iiu_k5_0ASbINS5_o7ZxMShGaWZFQD-y7jtU-NiJtMs,34680
84
+ _pytest/compat.py,sha256=sPcVQwPd45GaqsgIZEbCTR04GKhkVmIfft6QnKj3hmo,11467
85
+ _pytest/config/__init__.py,sha256=Ch5YizaRrCfMykEuZdHF0RaIyvtWvoSXL4v6E1Cu-FY,70645
86
+ _pytest/config/__pycache__/__init__.cpython-311.pyc,,
87
+ _pytest/config/__pycache__/argparsing.cpython-311.pyc,,
88
+ _pytest/config/__pycache__/compat.cpython-311.pyc,,
89
+ _pytest/config/__pycache__/exceptions.cpython-311.pyc,,
90
+ _pytest/config/__pycache__/findpaths.cpython-311.pyc,,
91
+ _pytest/config/argparsing.py,sha256=dNjEvFh2C34XMoiE_R7liJv5cryXUz2WR2VsxdnQdjo,20562
92
+ _pytest/config/compat.py,sha256=-m8G4-LLezCd4KZO6JQufEz7cRDqUSOjIwCtiKWpJvY,2938
93
+ _pytest/config/exceptions.py,sha256=lUKnOtpRqK-qNL6JfOP-8tRqpmHU34CVxguR5y0Qfbw,288
94
+ _pytest/config/findpaths.py,sha256=h4zq5AbLaZGpkeEcD2Xg-rJimh9I5pE042qQOTZT7NM,8062
95
+ _pytest/debugging.py,sha256=yRmmOexsaDeFky37IrD2e9svz8CWebB7L2fSUy4LvuE,13260
96
+ _pytest/deprecated.py,sha256=sO9UiqEdy9Z-NCvDoYYA0QtafYogAb7lP5M9N_Hpnak,3147
97
+ _pytest/doctest.py,sha256=7WJprJGYj7_9Lyr-L49wJ7q5ZwDVj1FBhA9_CX7JdLc,26255
98
+ _pytest/faulthandler.py,sha256=dT0H-MLi62SXeiKjLQJ0EVPuxkTlNOxpWtNxA5uBJPs,3674
99
+ _pytest/fixtures.py,sha256=I5t3pW2lHaVPbN1rAQ9sdX0a3QrpoW_U5VP-Vxejxmg,73550
100
+ _pytest/freeze_support.py,sha256=1EfzuxPd2oV9Ira26K5J4r9ppFZjnGi-xKzsBXe8B4g,1291
101
+ _pytest/helpconfig.py,sha256=ibnZNxKzToLmx-2ZrZKCP9t6jJvpAIlmqdf9a0rhOoI,8895
102
+ _pytest/hookspec.py,sha256=G-wKdmV3pecpeeiIAmzgPUMr22kz-CsqSpWEM-uiamg,42825
103
+ _pytest/junitxml.py,sha256=FnYwq0wAR4Cixzj-a9qhyulUSEpMyjX9ALbjza_We74,25574
104
+ _pytest/legacypath.py,sha256=_l6v8akNMfTc5TAjvbc6M-_t157p9QE6-118WM0DRt8,16588
105
+ _pytest/logging.py,sha256=QfaUUx-T0FiKBJBBb3bDllt8O8eTE7Mpigq7wvDepRc,35124
106
+ _pytest/main.py,sha256=Oowez36UkOwJXkTRq4rVuJRRr18ItBnz_YDjgAmFCV8,37416
107
+ _pytest/mark/__init__.py,sha256=bHORyCAsGnGJq7Tpm7A2sNQX31jwU1TgufM9DYcrTfQ,9307
108
+ _pytest/mark/__pycache__/__init__.cpython-311.pyc,,
109
+ _pytest/mark/__pycache__/expression.cpython-311.pyc,,
110
+ _pytest/mark/__pycache__/structures.cpython-311.pyc,,
111
+ _pytest/mark/expression.py,sha256=H6LmX0MWlxe0uBmuXIpQEntrLtyqIhEJv07YvA79eDQ,10152
112
+ _pytest/mark/structures.py,sha256=6hiIR3d4zxy35Yiw961r9sYrNl-T5WS8_0auSmpdiB0,21039
113
+ _pytest/monkeypatch.py,sha256=SKgteVJz1puqYQ3el6-ju5ZsNABqpoMUuRC6nn3tFpc,14598
114
+ _pytest/nodes.py,sha256=Hqyplow99hb-Zz0KKzL0K3cQ0rCgDXK65vBp6ave3u8,26483
115
+ _pytest/outcomes.py,sha256=SeW14rRKnGSt7K_NxY7HGnedoJawFHwQi2anAYYugk8,10532
116
+ _pytest/pastebin.py,sha256=Ja1z3Z6cXNElobpwy97FiyR5DDexZrDEB6vufmNvE4o,3978
117
+ _pytest/pathlib.py,sha256=onXoMMo4cbp-DR03XQuRimuIm_DrHNg3RujwP4Z7tic,36617
118
+ _pytest/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
+ _pytest/pytester.py,sha256=-D_SNLfp_AQRMP7GOo6NsXlektiYod79pxBY-2RdUT0,61552
120
+ _pytest/pytester_assertions.py,sha256=EIHeb1llN9TVRfBJqQnwvjKeG-KpzURNq8mtbK7vcyA,2244
121
+ _pytest/python.py,sha256=mkJek4hqp7GMIyk6uPNWclI2dYlg78tTjymdcZViTJM,64851
122
+ _pytest/python_api.py,sha256=KyIP4xCyd2BpNFlY-28a0E50XxMXy7HSQi6ZaCw3qZg,40122
123
+ _pytest/python_path.py,sha256=fGP7iR_XMFRPijg4niILo44gWUWLlD635fYO5Abd6IM,745
124
+ _pytest/recwarn.py,sha256=M_xZw1EMireN8CZMmlI_sCiVsun8Rcq0FlnRkPeWdYQ,13227
125
+ _pytest/reports.py,sha256=5OM_OyQHIS09PW6T_8kAJNS67GvcpvP-lKcna2LcSZ0,21331
126
+ _pytest/runner.py,sha256=LDWKfhiIzWNkXqr1xwex-l1yhsWkdWCJko4bYM-etQ8,19436
127
+ _pytest/scope.py,sha256=MyzqXUuWP1-BgbbCBzJyILiS_jicZO2LNUMUjv7vhh0,2798
128
+ _pytest/setuponly.py,sha256=HNY9Ern-wex9iWSHxJU6ODA0yzYIH65QCkgNZ_BmbuA,3306
129
+ _pytest/setupplan.py,sha256=l-ycFNxDZPyY52wh4f7yaqhzZ7SW1ijSKnQLmqzDZWA,1184
130
+ _pytest/skipping.py,sha256=XbZKDPek9ex8aRXEoEy5iv0_e1b0sUi0PZrWqLBapek,10217
131
+ _pytest/stash.py,sha256=5pE3kDx4q855TW9aVvYTdrkkKlMDU6-xiX4luKpJEgI,3090
132
+ _pytest/stepwise.py,sha256=lYFm6kg000n_WEGOEQAho0j6dRCKJvgKz1Ya2Zz-0Zc,4596
133
+ _pytest/terminal.py,sha256=-xT17xSJs9bu90wqRBc3WckaWTNTPOmVkZlO1X16Wyo,57393
134
+ _pytest/threadexception.py,sha256=GHLYwCYK6I13Xv6bISO2crvPj9Z5ADKgVnUD7m1Oa14,3005
135
+ _pytest/timing.py,sha256=URwa2JENXYkIN_9LFgEmJ4ric7SW8O6a8woS_TN6jXI,413
136
+ _pytest/tmpdir.py,sha256=bo40r_gpxS7AdB_BANpSgh_fejHiXaGWrBxHpax9wtw,11375
137
+ _pytest/unittest.py,sha256=wew7w2q5SqgdPppFzv0evwrTLWmMCwKFQvSUyEX2C0Q,15614
138
+ _pytest/unraisableexception.py,sha256=-L6ln8mRnqqPBskzarua49st4ioXoKgllZ3oMmRuCKU,3252
139
+ _pytest/warning_types.py,sha256=m2_Y3zydUZNzPpu88n8wPNWqaxfaATMKEo_zAgXMqyY,4388
140
+ _pytest/warnings.py,sha256=ExyXdM9ZsIUX4o5GCt43fR-YWhIHSuUbV6GbKEVXeiA,5211
141
+ py.py,sha256=txZ1tdmEW6CBTp6Idn-I2sOzzA0xKNoCi9Re27Uj6HE,329
142
+ pytest-8.3.4.dist-info/AUTHORS,sha256=XobBrGbApvzdviFsaW1chh5icAuN555aWaMBHcmuqQE,7026
143
+ pytest-8.3.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
144
+ pytest-8.3.4.dist-info/LICENSE,sha256=yoNqX57Mo7LzUCMPqiCkj7ixRWU7VWjXhIYt-GRwa5s,1091
145
+ pytest-8.3.4.dist-info/METADATA,sha256=f5v2O_PCDdT8dVKotHCLiHzXKMTS9hTO2YsKQ6_P3ig,7510
146
+ pytest-8.3.4.dist-info/RECORD,,
147
+ pytest-8.3.4.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
148
+ pytest-8.3.4.dist-info/entry_points.txt,sha256=8IPrHPH3LNZQ7v5tNEOcNTZYk_SheNg64jsTM9erqL4,77
149
+ pytest-8.3.4.dist-info/top_level.txt,sha256=yyhjvmXH7-JOaoQIdmNQHPuoBCxOyXS3jIths_6C8A4,18
150
+ pytest/__init__.py,sha256=jm6h0ZECJdDXlX0i5F20mN3ypV--T7osmtMHzzzY8ug,5169
151
+ pytest/__main__.py,sha256=oVDrGGo7N0TNyzXntUblcgTKbhHGWtivcX5TC7tEcKo,154
152
+ pytest/__pycache__/__init__.cpython-311.pyc,,
153
+ pytest/__pycache__/__main__.cpython-311.pyc,,
154
+ pytest/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
.venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.6.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
.venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/entry_points.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [console_scripts]
2
+ py.test = pytest:console_main
3
+ pytest = pytest:console_main
.venv/lib/python3.11/site-packages/pytest-8.3.4.dist-info/top_level.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ _pytest
2
+ py
3
+ pytest
.venv/lib/python3.11/site-packages/uvloop/__init__.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio as __asyncio
2
+ import typing as _typing
3
+ import sys as _sys
4
+ import warnings as _warnings
5
+
6
+ from asyncio.events import BaseDefaultEventLoopPolicy as __BasePolicy
7
+
8
+ from . import includes as __includes # NOQA
9
+ from .loop import Loop as __BaseLoop # NOQA
10
+ from ._version import __version__ # NOQA
11
+
12
+
13
+ __all__ = ('new_event_loop', 'install', 'EventLoopPolicy')
14
+
15
+
16
+ _T = _typing.TypeVar("_T")
17
+
18
+
19
+ class Loop(__BaseLoop, __asyncio.AbstractEventLoop): # type: ignore[misc]
20
+ pass
21
+
22
+
23
+ def new_event_loop() -> Loop:
24
+ """Return a new event loop."""
25
+ return Loop()
26
+
27
+
28
+ def install() -> None:
29
+ """A helper function to install uvloop policy."""
30
+ if _sys.version_info[:2] >= (3, 12):
31
+ _warnings.warn(
32
+ 'uvloop.install() is deprecated in favor of uvloop.run() '
33
+ 'starting with Python 3.12.',
34
+ DeprecationWarning,
35
+ stacklevel=1,
36
+ )
37
+ __asyncio.set_event_loop_policy(EventLoopPolicy())
38
+
39
+
40
+ if _typing.TYPE_CHECKING:
41
+ def run(
42
+ main: _typing.Coroutine[_typing.Any, _typing.Any, _T],
43
+ *,
44
+ loop_factory: _typing.Optional[
45
+ _typing.Callable[[], Loop]
46
+ ] = new_event_loop,
47
+ debug: _typing.Optional[bool]=None,
48
+ ) -> _T:
49
+ """The preferred way of running a coroutine with uvloop."""
50
+ else:
51
+ def run(main, *, loop_factory=new_event_loop, debug=None, **run_kwargs):
52
+ """The preferred way of running a coroutine with uvloop."""
53
+
54
+ async def wrapper():
55
+ # If `loop_factory` is provided we want it to return
56
+ # either uvloop.Loop or a subtype of it, assuming the user
57
+ # is using `uvloop.run()` intentionally.
58
+ loop = __asyncio._get_running_loop()
59
+ if not isinstance(loop, Loop):
60
+ raise TypeError('uvloop.run() uses a non-uvloop event loop')
61
+ return await main
62
+
63
+ vi = _sys.version_info[:2]
64
+
65
+ if vi <= (3, 10):
66
+ # Copied from python/cpython
67
+
68
+ if __asyncio._get_running_loop() is not None:
69
+ raise RuntimeError(
70
+ "asyncio.run() cannot be called from a running event loop")
71
+
72
+ if not __asyncio.iscoroutine(main):
73
+ raise ValueError(
74
+ "a coroutine was expected, got {!r}".format(main)
75
+ )
76
+
77
+ loop = loop_factory()
78
+ try:
79
+ __asyncio.set_event_loop(loop)
80
+ if debug is not None:
81
+ loop.set_debug(debug)
82
+ return loop.run_until_complete(wrapper())
83
+ finally:
84
+ try:
85
+ _cancel_all_tasks(loop)
86
+ loop.run_until_complete(loop.shutdown_asyncgens())
87
+ if hasattr(loop, 'shutdown_default_executor'):
88
+ loop.run_until_complete(
89
+ loop.shutdown_default_executor()
90
+ )
91
+ finally:
92
+ __asyncio.set_event_loop(None)
93
+ loop.close()
94
+
95
+ elif vi == (3, 11):
96
+ if __asyncio._get_running_loop() is not None:
97
+ raise RuntimeError(
98
+ "asyncio.run() cannot be called from a running event loop")
99
+
100
+ with __asyncio.Runner(
101
+ loop_factory=loop_factory,
102
+ debug=debug,
103
+ **run_kwargs
104
+ ) as runner:
105
+ return runner.run(wrapper())
106
+
107
+ else:
108
+ assert vi >= (3, 12)
109
+ return __asyncio.run(
110
+ wrapper(),
111
+ loop_factory=loop_factory,
112
+ debug=debug,
113
+ **run_kwargs
114
+ )
115
+
116
+
117
+ def _cancel_all_tasks(loop: __asyncio.AbstractEventLoop) -> None:
118
+ # Copied from python/cpython
119
+
120
+ to_cancel = __asyncio.all_tasks(loop)
121
+ if not to_cancel:
122
+ return
123
+
124
+ for task in to_cancel:
125
+ task.cancel()
126
+
127
+ loop.run_until_complete(
128
+ __asyncio.gather(*to_cancel, return_exceptions=True)
129
+ )
130
+
131
+ for task in to_cancel:
132
+ if task.cancelled():
133
+ continue
134
+ if task.exception() is not None:
135
+ loop.call_exception_handler({
136
+ 'message': 'unhandled exception during asyncio.run() shutdown',
137
+ 'exception': task.exception(),
138
+ 'task': task,
139
+ })
140
+
141
+
142
+ class EventLoopPolicy(__BasePolicy):
143
+ """Event loop policy.
144
+
145
+ The preferred way to make your application use uvloop:
146
+
147
+ >>> import asyncio
148
+ >>> import uvloop
149
+ >>> asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
150
+ >>> asyncio.get_event_loop()
151
+ <uvloop.Loop running=False closed=False debug=False>
152
+ """
153
+
154
+ def _loop_factory(self) -> Loop:
155
+ return new_event_loop()
156
+
157
+ if _typing.TYPE_CHECKING:
158
+ # EventLoopPolicy doesn't implement these, but since they are marked
159
+ # as abstract in typeshed, we have to put them in so mypy thinks
160
+ # the base methods are overridden. This is the same approach taken
161
+ # for the Windows event loop policy classes in typeshed.
162
+ def get_child_watcher(self) -> _typing.NoReturn:
163
+ ...
164
+
165
+ def set_child_watcher(
166
+ self, watcher: _typing.Any
167
+ ) -> _typing.NoReturn:
168
+ ...
.venv/lib/python3.11/site-packages/uvloop/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (7.92 kB). View file
 
.venv/lib/python3.11/site-packages/uvloop/__pycache__/_noop.cpython-311.pyc ADDED
Binary file (355 Bytes). View file
 
.venv/lib/python3.11/site-packages/uvloop/__pycache__/_testbase.cpython-311.pyc ADDED
Binary file (32 kB). View file
 
.venv/lib/python3.11/site-packages/uvloop/__pycache__/_version.cpython-311.pyc ADDED
Binary file (202 Bytes). View file
 
.venv/lib/python3.11/site-packages/uvloop/_noop.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ def noop() -> None:
2
+ """Empty function to invoke CPython ceval loop."""
3
+ return
.venv/lib/python3.11/site-packages/uvloop/_testbase.py ADDED
@@ -0,0 +1,552 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Test utilities. Don't use outside of the uvloop project."""
2
+
3
+
4
+ import asyncio
5
+ import asyncio.events
6
+ import collections
7
+ import contextlib
8
+ import gc
9
+ import logging
10
+ import os
11
+ import pprint
12
+ import re
13
+ import select
14
+ import socket
15
+ import ssl
16
+ import sys
17
+ import tempfile
18
+ import threading
19
+ import time
20
+ import unittest
21
+ import uvloop
22
+
23
+
24
+ class MockPattern(str):
25
+ def __eq__(self, other):
26
+ return bool(re.search(str(self), other, re.S))
27
+
28
+
29
+ class TestCaseDict(collections.UserDict):
30
+
31
+ def __init__(self, name):
32
+ super().__init__()
33
+ self.name = name
34
+
35
+ def __setitem__(self, key, value):
36
+ if key in self.data:
37
+ raise RuntimeError('duplicate test {}.{}'.format(
38
+ self.name, key))
39
+ super().__setitem__(key, value)
40
+
41
+
42
+ class BaseTestCaseMeta(type):
43
+
44
+ @classmethod
45
+ def __prepare__(mcls, name, bases):
46
+ return TestCaseDict(name)
47
+
48
+ def __new__(mcls, name, bases, dct):
49
+ for test_name in dct:
50
+ if not test_name.startswith('test_'):
51
+ continue
52
+ for base in bases:
53
+ if hasattr(base, test_name):
54
+ raise RuntimeError(
55
+ 'duplicate test {}.{} (also defined in {} '
56
+ 'parent class)'.format(
57
+ name, test_name, base.__name__))
58
+
59
+ return super().__new__(mcls, name, bases, dict(dct))
60
+
61
+
62
+ class BaseTestCase(unittest.TestCase, metaclass=BaseTestCaseMeta):
63
+
64
+ def new_loop(self):
65
+ raise NotImplementedError
66
+
67
+ def new_policy(self):
68
+ raise NotImplementedError
69
+
70
+ def mock_pattern(self, str):
71
+ return MockPattern(str)
72
+
73
+ async def wait_closed(self, obj):
74
+ if not isinstance(obj, asyncio.StreamWriter):
75
+ return
76
+ try:
77
+ await obj.wait_closed()
78
+ except (BrokenPipeError, ConnectionError):
79
+ pass
80
+
81
+ def is_asyncio_loop(self):
82
+ return type(self.loop).__module__.startswith('asyncio.')
83
+
84
+ def run_loop_briefly(self, *, delay=0.01):
85
+ self.loop.run_until_complete(asyncio.sleep(delay))
86
+
87
+ def loop_exception_handler(self, loop, context):
88
+ self.__unhandled_exceptions.append(context)
89
+ self.loop.default_exception_handler(context)
90
+
91
+ def setUp(self):
92
+ self.loop = self.new_loop()
93
+ asyncio.set_event_loop_policy(self.new_policy())
94
+ asyncio.set_event_loop(self.loop)
95
+ self._check_unclosed_resources_in_debug = True
96
+
97
+ self.loop.set_exception_handler(self.loop_exception_handler)
98
+ self.__unhandled_exceptions = []
99
+
100
+ def tearDown(self):
101
+ self.loop.close()
102
+
103
+ if self.__unhandled_exceptions:
104
+ print('Unexpected calls to loop.call_exception_handler():')
105
+ pprint.pprint(self.__unhandled_exceptions)
106
+ self.fail('unexpected calls to loop.call_exception_handler()')
107
+ return
108
+
109
+ if not self._check_unclosed_resources_in_debug:
110
+ return
111
+
112
+ # GC to show any resource warnings as the test completes
113
+ gc.collect()
114
+ gc.collect()
115
+ gc.collect()
116
+
117
+ if getattr(self.loop, '_debug_cc', False):
118
+ gc.collect()
119
+ gc.collect()
120
+ gc.collect()
121
+
122
+ self.assertEqual(
123
+ self.loop._debug_uv_handles_total,
124
+ self.loop._debug_uv_handles_freed,
125
+ 'not all uv_handle_t handles were freed')
126
+
127
+ self.assertEqual(
128
+ self.loop._debug_cb_handles_count, 0,
129
+ 'not all callbacks (call_soon) are GCed')
130
+
131
+ self.assertEqual(
132
+ self.loop._debug_cb_timer_handles_count, 0,
133
+ 'not all timer callbacks (call_later) are GCed')
134
+
135
+ self.assertEqual(
136
+ self.loop._debug_stream_write_ctx_cnt, 0,
137
+ 'not all stream write contexts are GCed')
138
+
139
+ for h_name, h_cnt in self.loop._debug_handles_current.items():
140
+ with self.subTest('Alive handle after test',
141
+ handle_name=h_name):
142
+ self.assertEqual(
143
+ h_cnt, 0,
144
+ 'alive {} after test'.format(h_name))
145
+
146
+ for h_name, h_cnt in self.loop._debug_handles_total.items():
147
+ with self.subTest('Total/closed handles',
148
+ handle_name=h_name):
149
+ self.assertEqual(
150
+ h_cnt, self.loop._debug_handles_closed[h_name],
151
+ 'total != closed for {}'.format(h_name))
152
+
153
+ asyncio.set_event_loop(None)
154
+ asyncio.set_event_loop_policy(None)
155
+ self.loop = None
156
+
157
+ def skip_unclosed_handles_check(self):
158
+ self._check_unclosed_resources_in_debug = False
159
+
160
+ def tcp_server(self, server_prog, *,
161
+ family=socket.AF_INET,
162
+ addr=None,
163
+ timeout=5,
164
+ backlog=1,
165
+ max_clients=10):
166
+
167
+ if addr is None:
168
+ if family == socket.AF_UNIX:
169
+ with tempfile.NamedTemporaryFile() as tmp:
170
+ addr = tmp.name
171
+ else:
172
+ addr = ('127.0.0.1', 0)
173
+
174
+ sock = socket.socket(family, socket.SOCK_STREAM)
175
+
176
+ if timeout is None:
177
+ raise RuntimeError('timeout is required')
178
+ if timeout <= 0:
179
+ raise RuntimeError('only blocking sockets are supported')
180
+ sock.settimeout(timeout)
181
+
182
+ try:
183
+ sock.bind(addr)
184
+ sock.listen(backlog)
185
+ except OSError as ex:
186
+ sock.close()
187
+ raise ex
188
+
189
+ return TestThreadedServer(
190
+ self, sock, server_prog, timeout, max_clients)
191
+
192
+ def tcp_client(self, client_prog,
193
+ family=socket.AF_INET,
194
+ timeout=10):
195
+
196
+ sock = socket.socket(family, socket.SOCK_STREAM)
197
+
198
+ if timeout is None:
199
+ raise RuntimeError('timeout is required')
200
+ if timeout <= 0:
201
+ raise RuntimeError('only blocking sockets are supported')
202
+ sock.settimeout(timeout)
203
+
204
+ return TestThreadedClient(
205
+ self, sock, client_prog, timeout)
206
+
207
+ def unix_server(self, *args, **kwargs):
208
+ return self.tcp_server(*args, family=socket.AF_UNIX, **kwargs)
209
+
210
+ def unix_client(self, *args, **kwargs):
211
+ return self.tcp_client(*args, family=socket.AF_UNIX, **kwargs)
212
+
213
+ @contextlib.contextmanager
214
+ def unix_sock_name(self):
215
+ with tempfile.TemporaryDirectory() as td:
216
+ fn = os.path.join(td, 'sock')
217
+ try:
218
+ yield fn
219
+ finally:
220
+ try:
221
+ os.unlink(fn)
222
+ except OSError:
223
+ pass
224
+
225
+ def _abort_socket_test(self, ex):
226
+ try:
227
+ self.loop.stop()
228
+ finally:
229
+ self.fail(ex)
230
+
231
+
232
+ def _cert_fullname(test_file_name, cert_file_name):
233
+ fullname = os.path.abspath(os.path.join(
234
+ os.path.dirname(test_file_name), 'certs', cert_file_name))
235
+ assert os.path.isfile(fullname)
236
+ return fullname
237
+
238
+
239
+ @contextlib.contextmanager
240
+ def silence_long_exec_warning():
241
+
242
+ class Filter(logging.Filter):
243
+ def filter(self, record):
244
+ return not (record.msg.startswith('Executing') and
245
+ record.msg.endswith('seconds'))
246
+
247
+ logger = logging.getLogger('asyncio')
248
+ filter = Filter()
249
+ logger.addFilter(filter)
250
+ try:
251
+ yield
252
+ finally:
253
+ logger.removeFilter(filter)
254
+
255
+
256
+ def find_free_port(start_from=50000):
257
+ for port in range(start_from, start_from + 500):
258
+ sock = socket.socket()
259
+ with sock:
260
+ try:
261
+ sock.bind(('', port))
262
+ except socket.error:
263
+ continue
264
+ else:
265
+ return port
266
+ raise RuntimeError('could not find a free port')
267
+
268
+
269
+ class SSLTestCase:
270
+
271
+ def _create_server_ssl_context(self, certfile, keyfile=None):
272
+ if hasattr(ssl, 'PROTOCOL_TLS_SERVER'):
273
+ sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
274
+ elif hasattr(ssl, 'PROTOCOL_TLS'):
275
+ sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS)
276
+ else:
277
+ sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
278
+ sslcontext.options |= ssl.OP_NO_SSLv2
279
+ sslcontext.load_cert_chain(certfile, keyfile)
280
+ return sslcontext
281
+
282
+ def _create_client_ssl_context(self, *, disable_verify=True):
283
+ sslcontext = ssl.create_default_context()
284
+ sslcontext.check_hostname = False
285
+ if disable_verify:
286
+ sslcontext.verify_mode = ssl.CERT_NONE
287
+ return sslcontext
288
+
289
+ @contextlib.contextmanager
290
+ def _silence_eof_received_warning(self):
291
+ # TODO This warning has to be fixed in asyncio.
292
+ logger = logging.getLogger('asyncio')
293
+ filter = logging.Filter('has no effect when using ssl')
294
+ logger.addFilter(filter)
295
+ try:
296
+ yield
297
+ finally:
298
+ logger.removeFilter(filter)
299
+
300
+
301
+ class UVTestCase(BaseTestCase):
302
+
303
+ implementation = 'uvloop'
304
+
305
+ def new_loop(self):
306
+ return uvloop.new_event_loop()
307
+
308
+ def new_policy(self):
309
+ return uvloop.EventLoopPolicy()
310
+
311
+
312
+ class AIOTestCase(BaseTestCase):
313
+
314
+ implementation = 'asyncio'
315
+
316
+ def setUp(self):
317
+ super().setUp()
318
+
319
+ if sys.version_info < (3, 12):
320
+ watcher = asyncio.SafeChildWatcher()
321
+ watcher.attach_loop(self.loop)
322
+ asyncio.set_child_watcher(watcher)
323
+
324
+ def tearDown(self):
325
+ if sys.version_info < (3, 12):
326
+ asyncio.set_child_watcher(None)
327
+ super().tearDown()
328
+
329
+ def new_loop(self):
330
+ return asyncio.new_event_loop()
331
+
332
+ def new_policy(self):
333
+ return asyncio.DefaultEventLoopPolicy()
334
+
335
+
336
+ def has_IPv6():
337
+ server_sock = socket.socket(socket.AF_INET6)
338
+ with server_sock:
339
+ try:
340
+ server_sock.bind(('::1', 0))
341
+ except OSError:
342
+ return False
343
+ else:
344
+ return True
345
+
346
+
347
+ has_IPv6 = has_IPv6()
348
+
349
+
350
+ ###############################################################################
351
+ # Socket Testing Utilities
352
+ ###############################################################################
353
+
354
+
355
+ class TestSocketWrapper:
356
+
357
+ def __init__(self, sock):
358
+ self.__sock = sock
359
+
360
+ def recv_all(self, n):
361
+ buf = b''
362
+ while len(buf) < n:
363
+ data = self.recv(n - len(buf))
364
+ if data == b'':
365
+ raise ConnectionAbortedError
366
+ buf += data
367
+ return buf
368
+
369
+ def starttls(self, ssl_context, *,
370
+ server_side=False,
371
+ server_hostname=None,
372
+ do_handshake_on_connect=True):
373
+
374
+ assert isinstance(ssl_context, ssl.SSLContext)
375
+
376
+ ssl_sock = ssl_context.wrap_socket(
377
+ self.__sock, server_side=server_side,
378
+ server_hostname=server_hostname,
379
+ do_handshake_on_connect=do_handshake_on_connect)
380
+
381
+ if server_side:
382
+ ssl_sock.do_handshake()
383
+
384
+ self.__sock.close()
385
+ self.__sock = ssl_sock
386
+
387
+ def __getattr__(self, name):
388
+ return getattr(self.__sock, name)
389
+
390
+ def __repr__(self):
391
+ return '<{} {!r}>'.format(type(self).__name__, self.__sock)
392
+
393
+
394
+ class SocketThread(threading.Thread):
395
+
396
+ def stop(self):
397
+ self._active = False
398
+ self.join()
399
+
400
+ def __enter__(self):
401
+ self.start()
402
+ return self
403
+
404
+ def __exit__(self, *exc):
405
+ self.stop()
406
+
407
+
408
+ class TestThreadedClient(SocketThread):
409
+
410
+ def __init__(self, test, sock, prog, timeout):
411
+ threading.Thread.__init__(self, None, None, 'test-client')
412
+ self.daemon = True
413
+
414
+ self._timeout = timeout
415
+ self._sock = sock
416
+ self._active = True
417
+ self._prog = prog
418
+ self._test = test
419
+
420
+ def run(self):
421
+ try:
422
+ self._prog(TestSocketWrapper(self._sock))
423
+ except (KeyboardInterrupt, SystemExit):
424
+ raise
425
+ except BaseException as ex:
426
+ self._test._abort_socket_test(ex)
427
+
428
+
429
+ class TestThreadedServer(SocketThread):
430
+
431
+ def __init__(self, test, sock, prog, timeout, max_clients):
432
+ threading.Thread.__init__(self, None, None, 'test-server')
433
+ self.daemon = True
434
+
435
+ self._clients = 0
436
+ self._finished_clients = 0
437
+ self._max_clients = max_clients
438
+ self._timeout = timeout
439
+ self._sock = sock
440
+ self._active = True
441
+
442
+ self._prog = prog
443
+
444
+ self._s1, self._s2 = socket.socketpair()
445
+ self._s1.setblocking(False)
446
+
447
+ self._test = test
448
+
449
+ def stop(self):
450
+ try:
451
+ if self._s2 and self._s2.fileno() != -1:
452
+ try:
453
+ self._s2.send(b'stop')
454
+ except OSError:
455
+ pass
456
+ finally:
457
+ super().stop()
458
+
459
+ def run(self):
460
+ try:
461
+ with self._sock:
462
+ self._sock.setblocking(0)
463
+ self._run()
464
+ finally:
465
+ self._s1.close()
466
+ self._s2.close()
467
+
468
+ def _run(self):
469
+ while self._active:
470
+ if self._clients >= self._max_clients:
471
+ return
472
+
473
+ r, w, x = select.select(
474
+ [self._sock, self._s1], [], [], self._timeout)
475
+
476
+ if self._s1 in r:
477
+ return
478
+
479
+ if self._sock in r:
480
+ try:
481
+ conn, addr = self._sock.accept()
482
+ except BlockingIOError:
483
+ continue
484
+ except socket.timeout:
485
+ if not self._active:
486
+ return
487
+ else:
488
+ raise
489
+ else:
490
+ self._clients += 1
491
+ conn.settimeout(self._timeout)
492
+ try:
493
+ with conn:
494
+ self._handle_client(conn)
495
+ except (KeyboardInterrupt, SystemExit):
496
+ raise
497
+ except BaseException as ex:
498
+ self._active = False
499
+ try:
500
+ raise
501
+ finally:
502
+ self._test._abort_socket_test(ex)
503
+
504
+ def _handle_client(self, sock):
505
+ self._prog(TestSocketWrapper(sock))
506
+
507
+ @property
508
+ def addr(self):
509
+ return self._sock.getsockname()
510
+
511
+
512
+ ###############################################################################
513
+ # A few helpers from asyncio/tests/testutils.py
514
+ ###############################################################################
515
+
516
+
517
+ def run_briefly(loop):
518
+ async def once():
519
+ pass
520
+ gen = once()
521
+ t = loop.create_task(gen)
522
+ # Don't log a warning if the task is not done after run_until_complete().
523
+ # It occurs if the loop is stopped or if a task raises a BaseException.
524
+ t._log_destroy_pending = False
525
+ try:
526
+ loop.run_until_complete(t)
527
+ finally:
528
+ gen.close()
529
+
530
+
531
+ def run_until(loop, pred, timeout=30):
532
+ deadline = time.time() + timeout
533
+ while not pred():
534
+ if timeout is not None:
535
+ timeout = deadline - time.time()
536
+ if timeout <= 0:
537
+ raise asyncio.futures.TimeoutError()
538
+ loop.run_until_complete(asyncio.tasks.sleep(0.001))
539
+
540
+
541
+ @contextlib.contextmanager
542
+ def disable_logger():
543
+ """Context manager to disable asyncio logger.
544
+
545
+ For example, it can be used to ignore warnings in debug mode.
546
+ """
547
+ old_level = asyncio.log.logger.level
548
+ try:
549
+ asyncio.log.logger.setLevel(logging.CRITICAL + 1)
550
+ yield
551
+ finally:
552
+ asyncio.log.logger.setLevel(old_level)
.venv/lib/python3.11/site-packages/uvloop/_version.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file MUST NOT contain anything but the __version__ assignment.
2
+ #
3
+ # When making a release, change the value of __version__
4
+ # to an appropriate value, and open a pull request against
5
+ # the correct branch (master if making a new feature release).
6
+ # The commit message MUST contain a properly formatted release
7
+ # log, and the commit must be signed.
8
+ #
9
+ # The release automation will: build and test the packages for the
10
+ # supported platforms, publish the packages on PyPI, merge the PR
11
+ # to the target branch, create a Git tag pointing to the commit.
12
+
13
+ __version__ = '0.21.0'
.venv/lib/python3.11/site-packages/uvloop/cbhandles.pxd ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class Handle:
2
+ cdef:
3
+ Loop loop
4
+ object context
5
+ bint _cancelled
6
+
7
+ str meth_name
8
+ int cb_type
9
+ void *callback
10
+ object arg1, arg2, arg3, arg4
11
+
12
+ object __weakref__
13
+
14
+ readonly _source_traceback
15
+
16
+ cdef inline _set_loop(self, Loop loop)
17
+ cdef inline _set_context(self, object context)
18
+
19
+ cdef inline _run(self)
20
+ cdef _cancel(self)
21
+
22
+ cdef _format_handle(self)
23
+
24
+
25
+ cdef class TimerHandle:
26
+ cdef:
27
+ object callback
28
+ tuple args
29
+ bint _cancelled
30
+ UVTimer timer
31
+ Loop loop
32
+ object context
33
+ tuple _debug_info
34
+ object __weakref__
35
+ object _when
36
+
37
+ cdef _run(self)
38
+ cdef _cancel(self)
39
+ cdef inline _clear(self)
.venv/lib/python3.11/site-packages/uvloop/cbhandles.pyx ADDED
@@ -0,0 +1,434 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @cython.no_gc_clear
2
+ @cython.freelist(DEFAULT_FREELIST_SIZE)
3
+ cdef class Handle:
4
+ def __cinit__(self):
5
+ self._cancelled = 0
6
+ self.cb_type = 0
7
+ self._source_traceback = None
8
+
9
+ cdef inline _set_loop(self, Loop loop):
10
+ self.loop = loop
11
+ if UVLOOP_DEBUG:
12
+ loop._debug_cb_handles_total += 1
13
+ loop._debug_cb_handles_count += 1
14
+ if loop._debug:
15
+ self._source_traceback = extract_stack()
16
+
17
+ cdef inline _set_context(self, object context):
18
+ if context is None:
19
+ context = Context_CopyCurrent()
20
+ self.context = context
21
+
22
+ def __dealloc__(self):
23
+ if UVLOOP_DEBUG and self.loop is not None:
24
+ self.loop._debug_cb_handles_count -= 1
25
+ if self.loop is None:
26
+ raise RuntimeError('Handle.loop is None in Handle.__dealloc__')
27
+
28
+ def __init__(self):
29
+ raise TypeError(
30
+ '{} is not supposed to be instantiated from Python'.format(
31
+ self.__class__.__name__))
32
+
33
+ cdef inline _run(self):
34
+ cdef:
35
+ int cb_type
36
+ object callback
37
+
38
+ if self._cancelled:
39
+ return
40
+
41
+ cb_type = self.cb_type
42
+
43
+ # Since _run is a cdef and there's no BoundMethod,
44
+ # we guard 'self' manually (since the callback
45
+ # might cause GC of the handle.)
46
+ Py_INCREF(self)
47
+
48
+ try:
49
+ assert self.context is not None
50
+ Context_Enter(self.context)
51
+
52
+ if cb_type == 1:
53
+ callback = self.arg1
54
+ if callback is None:
55
+ raise RuntimeError(
56
+ 'cannot run Handle; callback is not set')
57
+
58
+ args = self.arg2
59
+
60
+ if args is None:
61
+ callback()
62
+ else:
63
+ callback(*args)
64
+
65
+ elif cb_type == 2:
66
+ (<method_t>self.callback)(self.arg1)
67
+
68
+ elif cb_type == 3:
69
+ (<method1_t>self.callback)(self.arg1, self.arg2)
70
+
71
+ elif cb_type == 4:
72
+ (<method2_t>self.callback)(self.arg1, self.arg2, self.arg3)
73
+
74
+ elif cb_type == 5:
75
+ (<method3_t>self.callback)(
76
+ self.arg1, self.arg2, self.arg3, self.arg4)
77
+
78
+ else:
79
+ raise RuntimeError('invalid Handle.cb_type: {}'.format(
80
+ cb_type))
81
+
82
+ except (KeyboardInterrupt, SystemExit):
83
+ raise
84
+ except BaseException as ex:
85
+ if cb_type == 1:
86
+ msg = 'Exception in callback {}'.format(callback)
87
+ else:
88
+ msg = 'Exception in callback {}'.format(self.meth_name)
89
+
90
+ context = {
91
+ 'message': msg,
92
+ 'exception': ex,
93
+ 'handle': self,
94
+ }
95
+
96
+ if self._source_traceback is not None:
97
+ context['source_traceback'] = self._source_traceback
98
+
99
+ self.loop.call_exception_handler(context)
100
+
101
+ finally:
102
+ context = self.context
103
+ Py_DECREF(self)
104
+ Context_Exit(context)
105
+
106
+ cdef _cancel(self):
107
+ self._cancelled = 1
108
+ self.callback = NULL
109
+ self.arg1 = self.arg2 = self.arg3 = self.arg4 = None
110
+
111
+ cdef _format_handle(self):
112
+ # Mirrors `asyncio.base_events._format_handle`.
113
+ if self.cb_type == 1 and self.arg1 is not None:
114
+ cb = self.arg1
115
+ if isinstance(getattr(cb, '__self__', None), aio_Task):
116
+ try:
117
+ return repr(cb.__self__)
118
+ except (AttributeError, TypeError, ValueError) as ex:
119
+ # Cython generates empty __code__ objects for coroutines
120
+ # that can crash asyncio.Task.__repr__ with an
121
+ # AttributeError etc. Guard against that.
122
+ self.loop.call_exception_handler({
123
+ 'message': 'exception in Task.__repr__',
124
+ 'task': cb.__self__,
125
+ 'exception': ex,
126
+ 'handle': self,
127
+ })
128
+ return repr(self)
129
+
130
+ # Public API
131
+
132
+ def __repr__(self):
133
+ info = [self.__class__.__name__]
134
+
135
+ if self._cancelled:
136
+ info.append('cancelled')
137
+
138
+ if self.cb_type == 1 and self.arg1 is not None:
139
+ func = self.arg1
140
+ # Cython can unset func.__qualname__/__name__, hence the checks.
141
+ if hasattr(func, '__qualname__') and func.__qualname__:
142
+ cb_name = func.__qualname__
143
+ elif hasattr(func, '__name__') and func.__name__:
144
+ cb_name = func.__name__
145
+ else:
146
+ cb_name = repr(func)
147
+
148
+ info.append(cb_name)
149
+ elif self.meth_name is not None:
150
+ info.append(self.meth_name)
151
+
152
+ if self._source_traceback is not None:
153
+ frame = self._source_traceback[-1]
154
+ info.append('created at {}:{}'.format(frame[0], frame[1]))
155
+
156
+ return '<' + ' '.join(info) + '>'
157
+
158
+ def cancel(self):
159
+ self._cancel()
160
+
161
+ def cancelled(self):
162
+ return self._cancelled
163
+
164
+
165
+ @cython.no_gc_clear
166
+ @cython.freelist(DEFAULT_FREELIST_SIZE)
167
+ cdef class TimerHandle:
168
+ def __cinit__(self, Loop loop, object callback, object args,
169
+ uint64_t delay, object context):
170
+
171
+ self.loop = loop
172
+ self.callback = callback
173
+ self.args = args
174
+ self._cancelled = 0
175
+
176
+ if UVLOOP_DEBUG:
177
+ self.loop._debug_cb_timer_handles_total += 1
178
+ self.loop._debug_cb_timer_handles_count += 1
179
+
180
+ if context is None:
181
+ context = Context_CopyCurrent()
182
+ self.context = context
183
+
184
+ if loop._debug:
185
+ self._debug_info = (
186
+ format_callback_name(callback),
187
+ extract_stack()
188
+ )
189
+ else:
190
+ self._debug_info = None
191
+
192
+ self.timer = UVTimer.new(
193
+ loop, <method_t>self._run, self, delay)
194
+
195
+ self.timer.start()
196
+ self._when = self.timer.get_when() * 1e-3
197
+
198
+ # Only add to loop._timers when `self.timer` is successfully created
199
+ loop._timers.add(self)
200
+
201
+ property _source_traceback:
202
+ def __get__(self):
203
+ if self._debug_info is not None:
204
+ return self._debug_info[1]
205
+
206
+ def __dealloc__(self):
207
+ if UVLOOP_DEBUG:
208
+ self.loop._debug_cb_timer_handles_count -= 1
209
+ if self.timer is not None:
210
+ raise RuntimeError('active TimerHandle is deallacating')
211
+
212
+ cdef _cancel(self):
213
+ if self._cancelled == 1:
214
+ return
215
+ self._cancelled = 1
216
+ self._clear()
217
+
218
+ cdef inline _clear(self):
219
+ if self.timer is None:
220
+ return
221
+
222
+ self.callback = None
223
+ self.args = None
224
+
225
+ try:
226
+ self.loop._timers.remove(self)
227
+ finally:
228
+ self.timer._close()
229
+ self.timer = None # let the UVTimer handle GC
230
+
231
+ cdef _run(self):
232
+ if self._cancelled == 1:
233
+ return
234
+ if self.callback is None:
235
+ raise RuntimeError('cannot run TimerHandle; callback is not set')
236
+
237
+ callback = self.callback
238
+ args = self.args
239
+
240
+ # Since _run is a cdef and there's no BoundMethod,
241
+ # we guard 'self' manually.
242
+ Py_INCREF(self)
243
+
244
+ if self.loop._debug:
245
+ started = time_monotonic()
246
+ try:
247
+ assert self.context is not None
248
+ Context_Enter(self.context)
249
+
250
+ if args is not None:
251
+ callback(*args)
252
+ else:
253
+ callback()
254
+ except (KeyboardInterrupt, SystemExit):
255
+ raise
256
+ except BaseException as ex:
257
+ context = {
258
+ 'message': 'Exception in callback {}'.format(callback),
259
+ 'exception': ex,
260
+ 'handle': self,
261
+ }
262
+
263
+ if self._debug_info is not None:
264
+ context['source_traceback'] = self._debug_info[1]
265
+
266
+ self.loop.call_exception_handler(context)
267
+ else:
268
+ if self.loop._debug:
269
+ delta = time_monotonic() - started
270
+ if delta > self.loop.slow_callback_duration:
271
+ aio_logger.warning(
272
+ 'Executing %r took %.3f seconds',
273
+ self, delta)
274
+ finally:
275
+ context = self.context
276
+ Py_DECREF(self)
277
+ Context_Exit(context)
278
+ self._clear()
279
+
280
+ # Public API
281
+
282
+ def __repr__(self):
283
+ info = [self.__class__.__name__]
284
+
285
+ if self._cancelled:
286
+ info.append('cancelled')
287
+
288
+ if self._debug_info is not None:
289
+ callback_name = self._debug_info[0]
290
+ source_traceback = self._debug_info[1]
291
+ else:
292
+ callback_name = None
293
+ source_traceback = None
294
+
295
+ if callback_name is not None:
296
+ info.append(callback_name)
297
+ elif self.callback is not None:
298
+ info.append(format_callback_name(self.callback))
299
+
300
+ if source_traceback is not None:
301
+ frame = source_traceback[-1]
302
+ info.append('created at {}:{}'.format(frame[0], frame[1]))
303
+
304
+ return '<' + ' '.join(info) + '>'
305
+
306
+ def cancelled(self):
307
+ return self._cancelled
308
+
309
+ def cancel(self):
310
+ self._cancel()
311
+
312
+ def when(self):
313
+ return self._when
314
+
315
+
316
+ cdef format_callback_name(func):
317
+ if hasattr(func, '__qualname__'):
318
+ cb_name = getattr(func, '__qualname__')
319
+ elif hasattr(func, '__name__'):
320
+ cb_name = getattr(func, '__name__')
321
+ else:
322
+ cb_name = repr(func)
323
+ return cb_name
324
+
325
+
326
+ cdef new_Handle(Loop loop, object callback, object args, object context):
327
+ cdef Handle handle
328
+ handle = Handle.__new__(Handle)
329
+ handle._set_loop(loop)
330
+ handle._set_context(context)
331
+
332
+ handle.cb_type = 1
333
+
334
+ handle.arg1 = callback
335
+ handle.arg2 = args
336
+
337
+ return handle
338
+
339
+
340
+ cdef new_MethodHandle(Loop loop, str name, method_t callback, object context,
341
+ object bound_to):
342
+ cdef Handle handle
343
+ handle = Handle.__new__(Handle)
344
+ handle._set_loop(loop)
345
+ handle._set_context(context)
346
+
347
+ handle.cb_type = 2
348
+ handle.meth_name = name
349
+
350
+ handle.callback = <void*> callback
351
+ handle.arg1 = bound_to
352
+
353
+ return handle
354
+
355
+
356
+ cdef new_MethodHandle1(Loop loop, str name, method1_t callback, object context,
357
+ object bound_to, object arg):
358
+
359
+ cdef Handle handle
360
+ handle = Handle.__new__(Handle)
361
+ handle._set_loop(loop)
362
+ handle._set_context(context)
363
+
364
+ handle.cb_type = 3
365
+ handle.meth_name = name
366
+
367
+ handle.callback = <void*> callback
368
+ handle.arg1 = bound_to
369
+ handle.arg2 = arg
370
+
371
+ return handle
372
+
373
+
374
+ cdef new_MethodHandle2(Loop loop, str name, method2_t callback, object context,
375
+ object bound_to, object arg1, object arg2):
376
+
377
+ cdef Handle handle
378
+ handle = Handle.__new__(Handle)
379
+ handle._set_loop(loop)
380
+ handle._set_context(context)
381
+
382
+ handle.cb_type = 4
383
+ handle.meth_name = name
384
+
385
+ handle.callback = <void*> callback
386
+ handle.arg1 = bound_to
387
+ handle.arg2 = arg1
388
+ handle.arg3 = arg2
389
+
390
+ return handle
391
+
392
+
393
+ cdef new_MethodHandle3(Loop loop, str name, method3_t callback, object context,
394
+ object bound_to, object arg1, object arg2, object arg3):
395
+
396
+ cdef Handle handle
397
+ handle = Handle.__new__(Handle)
398
+ handle._set_loop(loop)
399
+ handle._set_context(context)
400
+
401
+ handle.cb_type = 5
402
+ handle.meth_name = name
403
+
404
+ handle.callback = <void*> callback
405
+ handle.arg1 = bound_to
406
+ handle.arg2 = arg1
407
+ handle.arg3 = arg2
408
+ handle.arg4 = arg3
409
+
410
+ return handle
411
+
412
+
413
+ cdef extract_stack():
414
+ """Replacement for traceback.extract_stack() that only does the
415
+ necessary work for asyncio debug mode.
416
+ """
417
+ try:
418
+ f = sys_getframe()
419
+ # sys._getframe() might raise ValueError if being called without a frame, e.g.
420
+ # from Cython or similar C extensions.
421
+ except ValueError:
422
+ return None
423
+ if f is None:
424
+ return
425
+
426
+ try:
427
+ stack = tb_StackSummary.extract(tb_walk_stack(f),
428
+ limit=DEBUG_STACK_DEPTH,
429
+ lookup_lines=False)
430
+ finally:
431
+ f = None
432
+
433
+ stack.reverse()
434
+ return stack
.venv/lib/python3.11/site-packages/uvloop/dns.pyx ADDED
@@ -0,0 +1,479 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef __port_to_int(port, proto):
2
+ if type(port) is int:
3
+ return port
4
+
5
+ if port is None or port == '' or port == b'':
6
+ return 0
7
+
8
+ try:
9
+ return int(port)
10
+ except (ValueError, TypeError):
11
+ pass
12
+
13
+ if isinstance(port, bytes):
14
+ port = port.decode()
15
+
16
+ if isinstance(port, str) and proto is not None:
17
+ if proto == uv.IPPROTO_TCP:
18
+ return socket_getservbyname(port, 'tcp')
19
+ elif proto == uv.IPPROTO_UDP:
20
+ return socket_getservbyname(port, 'udp')
21
+
22
+ raise OSError('service/proto not found')
23
+
24
+
25
+ cdef __convert_sockaddr_to_pyaddr(const system.sockaddr* addr):
26
+ # Converts sockaddr structs into what Python socket
27
+ # module can understand:
28
+ # - for IPv4 a tuple of (host, port)
29
+ # - for IPv6 a tuple of (host, port, flowinfo, scope_id)
30
+
31
+ cdef:
32
+ char buf[128] # INET6_ADDRSTRLEN is usually 46
33
+ int err
34
+ system.sockaddr_in *addr4
35
+ system.sockaddr_in6 *addr6
36
+ system.sockaddr_un *addr_un
37
+
38
+ if addr.sa_family == uv.AF_INET:
39
+ addr4 = <system.sockaddr_in*>addr
40
+
41
+ err = uv.uv_ip4_name(addr4, buf, sizeof(buf))
42
+ if err < 0:
43
+ raise convert_error(err)
44
+
45
+ return (
46
+ PyUnicode_FromString(buf),
47
+ system.ntohs(addr4.sin_port)
48
+ )
49
+
50
+ elif addr.sa_family == uv.AF_INET6:
51
+ addr6 = <system.sockaddr_in6*>addr
52
+
53
+ err = uv.uv_ip6_name(addr6, buf, sizeof(buf))
54
+ if err < 0:
55
+ raise convert_error(err)
56
+
57
+ return (
58
+ PyUnicode_FromString(buf),
59
+ system.ntohs(addr6.sin6_port),
60
+ system.ntohl(addr6.sin6_flowinfo),
61
+ addr6.sin6_scope_id
62
+ )
63
+
64
+ elif addr.sa_family == uv.AF_UNIX:
65
+ addr_un = <system.sockaddr_un*>addr
66
+ return system.MakeUnixSockPyAddr(addr_un)
67
+
68
+ raise RuntimeError("cannot convert sockaddr into Python object")
69
+
70
+
71
+ @cython.freelist(DEFAULT_FREELIST_SIZE)
72
+ cdef class SockAddrHolder:
73
+ cdef:
74
+ int family
75
+ system.sockaddr_storage addr
76
+ Py_ssize_t addr_size
77
+
78
+
79
+ cdef LruCache sockaddrs = LruCache(maxsize=DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE)
80
+
81
+
82
+ cdef __convert_pyaddr_to_sockaddr(int family, object addr,
83
+ system.sockaddr* res):
84
+ cdef:
85
+ int err
86
+ int addr_len
87
+ int scope_id = 0
88
+ int flowinfo = 0
89
+ char *buf
90
+ Py_ssize_t buflen
91
+ SockAddrHolder ret
92
+
93
+ ret = sockaddrs.get(addr, None)
94
+ if ret is not None and ret.family == family:
95
+ memcpy(res, &ret.addr, ret.addr_size)
96
+ return
97
+
98
+ ret = SockAddrHolder.__new__(SockAddrHolder)
99
+ if family == uv.AF_INET:
100
+ if not isinstance(addr, tuple):
101
+ raise TypeError('AF_INET address must be tuple')
102
+ if len(addr) != 2:
103
+ raise ValueError('AF_INET address must be tuple of (host, port)')
104
+ host, port = addr
105
+ if isinstance(host, str):
106
+ try:
107
+ # idna codec is rather slow, so we try ascii first.
108
+ host = host.encode('ascii')
109
+ except UnicodeEncodeError:
110
+ host = host.encode('idna')
111
+ if not isinstance(host, (bytes, bytearray)):
112
+ raise TypeError('host must be a string or bytes object')
113
+
114
+ port = __port_to_int(port, None)
115
+
116
+ ret.addr_size = sizeof(system.sockaddr_in)
117
+ err = uv.uv_ip4_addr(host, <int>port, <system.sockaddr_in*>&ret.addr)
118
+ if err < 0:
119
+ raise convert_error(err)
120
+
121
+ elif family == uv.AF_INET6:
122
+ if not isinstance(addr, tuple):
123
+ raise TypeError('AF_INET6 address must be tuple')
124
+
125
+ addr_len = len(addr)
126
+ if addr_len < 2 or addr_len > 4:
127
+ raise ValueError(
128
+ 'AF_INET6 must be a tuple of 2-4 parameters: '
129
+ '(host, port, flowinfo?, scope_id?)')
130
+
131
+ host = addr[0]
132
+ if isinstance(host, str):
133
+ try:
134
+ # idna codec is rather slow, so we try ascii first.
135
+ host = host.encode('ascii')
136
+ except UnicodeEncodeError:
137
+ host = host.encode('idna')
138
+ if not isinstance(host, (bytes, bytearray)):
139
+ raise TypeError('host must be a string or bytes object')
140
+
141
+ port = __port_to_int(addr[1], None)
142
+
143
+ if addr_len > 2:
144
+ flowinfo = addr[2]
145
+ if addr_len > 3:
146
+ scope_id = addr[3]
147
+
148
+ ret.addr_size = sizeof(system.sockaddr_in6)
149
+
150
+ err = uv.uv_ip6_addr(host, port, <system.sockaddr_in6*>&ret.addr)
151
+ if err < 0:
152
+ raise convert_error(err)
153
+
154
+ (<system.sockaddr_in6*>&ret.addr).sin6_flowinfo = flowinfo
155
+ (<system.sockaddr_in6*>&ret.addr).sin6_scope_id = scope_id
156
+
157
+ elif family == uv.AF_UNIX:
158
+ if isinstance(addr, str):
159
+ addr = addr.encode(sys_getfilesystemencoding())
160
+ elif not isinstance(addr, bytes):
161
+ raise TypeError('AF_UNIX address must be a str or a bytes object')
162
+
163
+ PyBytes_AsStringAndSize(addr, &buf, &buflen)
164
+ if buflen > 107:
165
+ raise ValueError(
166
+ f'unix socket path {addr!r} is longer than 107 characters')
167
+
168
+ ret.addr_size = sizeof(system.sockaddr_un)
169
+ memset(&ret.addr, 0, sizeof(system.sockaddr_un))
170
+ (<system.sockaddr_un*>&ret.addr).sun_family = uv.AF_UNIX
171
+ memcpy((<system.sockaddr_un*>&ret.addr).sun_path, buf, buflen)
172
+
173
+ else:
174
+ raise ValueError(
175
+ f'expected AF_INET, AF_INET6, or AF_UNIX family, got {family}')
176
+
177
+ ret.family = family
178
+ sockaddrs[addr] = ret
179
+ memcpy(res, &ret.addr, ret.addr_size)
180
+
181
+
182
+ cdef __static_getaddrinfo(object host, object port,
183
+ int family, int type,
184
+ int proto,
185
+ system.sockaddr *addr):
186
+
187
+ if proto not in {0, uv.IPPROTO_TCP, uv.IPPROTO_UDP}:
188
+ return
189
+
190
+ if _is_sock_stream(type):
191
+ proto = uv.IPPROTO_TCP
192
+ elif _is_sock_dgram(type):
193
+ proto = uv.IPPROTO_UDP
194
+ else:
195
+ return
196
+
197
+ try:
198
+ port = __port_to_int(port, proto)
199
+ except Exception:
200
+ return
201
+
202
+ hp = (host, port)
203
+ if family == uv.AF_UNSPEC:
204
+ try:
205
+ __convert_pyaddr_to_sockaddr(uv.AF_INET, hp, addr)
206
+ except Exception:
207
+ pass
208
+ else:
209
+ return (uv.AF_INET, type, proto)
210
+
211
+ try:
212
+ __convert_pyaddr_to_sockaddr(uv.AF_INET6, hp, addr)
213
+ except Exception:
214
+ pass
215
+ else:
216
+ return (uv.AF_INET6, type, proto)
217
+
218
+ else:
219
+ try:
220
+ __convert_pyaddr_to_sockaddr(family, hp, addr)
221
+ except Exception:
222
+ pass
223
+ else:
224
+ return (family, type, proto)
225
+
226
+
227
+ cdef __static_getaddrinfo_pyaddr(object host, object port,
228
+ int family, int type,
229
+ int proto, int flags):
230
+
231
+ cdef:
232
+ system.sockaddr_storage addr
233
+ object triplet
234
+
235
+ triplet = __static_getaddrinfo(
236
+ host, port, family, type,
237
+ proto, <system.sockaddr*>&addr)
238
+ if triplet is None:
239
+ return
240
+
241
+ af, type, proto = triplet
242
+
243
+ try:
244
+ pyaddr = __convert_sockaddr_to_pyaddr(<system.sockaddr*>&addr)
245
+ except Exception:
246
+ return
247
+
248
+ # When the host is an IP while type is one of TCP or UDP, different libc
249
+ # implementations of getaddrinfo() behave differently:
250
+ # 1. When AI_CANONNAME is set:
251
+ # * glibc: returns ai_canonname
252
+ # * musl: returns ai_canonname
253
+ # * macOS: returns an empty string for ai_canonname
254
+ # 2. When AI_CANONNAME is NOT set:
255
+ # * glibc: returns an empty string for ai_canonname
256
+ # * musl: returns ai_canonname
257
+ # * macOS: returns an empty string for ai_canonname
258
+ # At the same time, libuv and CPython both uses libc directly, even though
259
+ # this different behavior is violating what is in the documentation.
260
+ #
261
+ # uvloop potentially should be a 100% drop-in replacement for asyncio,
262
+ # doing whatever asyncio does, especially when the libc implementations are
263
+ # also different in the same way. However, making our implementation to be
264
+ # consistent with libc/CPython would be complex and hard to maintain
265
+ # (including caching libc behaviors when flag is/not set), therefore we
266
+ # decided to simply normalize the behavior in uvloop for this very marginal
267
+ # case following the documentation, even though uvloop would behave
268
+ # differently to asyncio on macOS and musl platforms, when again the host
269
+ # is an IP and type is one of TCP or UDP.
270
+ # All other cases are still asyncio-compatible.
271
+ if flags & socket_AI_CANONNAME:
272
+ if isinstance(host, str):
273
+ canon_name = host
274
+ else:
275
+ canon_name = host.decode('ascii')
276
+ else:
277
+ canon_name = ''
278
+
279
+ return (
280
+ _intenum_converter(af, socket_AddressFamily),
281
+ _intenum_converter(type, socket_SocketKind),
282
+ proto,
283
+ canon_name,
284
+ pyaddr,
285
+ )
286
+
287
+
288
+ @cython.freelist(DEFAULT_FREELIST_SIZE)
289
+ cdef class AddrInfo:
290
+ cdef:
291
+ system.addrinfo *data
292
+
293
+ def __cinit__(self):
294
+ self.data = NULL
295
+
296
+ def __dealloc__(self):
297
+ if self.data is not NULL:
298
+ uv.uv_freeaddrinfo(self.data) # returns void
299
+ self.data = NULL
300
+
301
+ cdef void set_data(self, system.addrinfo *data) noexcept:
302
+ self.data = data
303
+
304
+ cdef unpack(self):
305
+ cdef:
306
+ list result = []
307
+ system.addrinfo *ptr
308
+
309
+ if self.data is NULL:
310
+ raise RuntimeError('AddrInfo.data is NULL')
311
+
312
+ ptr = self.data
313
+ while ptr != NULL:
314
+ if ptr.ai_addr.sa_family in (uv.AF_INET, uv.AF_INET6):
315
+ result.append((
316
+ _intenum_converter(ptr.ai_family, socket_AddressFamily),
317
+ _intenum_converter(ptr.ai_socktype, socket_SocketKind),
318
+ ptr.ai_protocol,
319
+ ('' if ptr.ai_canonname is NULL else
320
+ (<bytes>ptr.ai_canonname).decode()),
321
+ __convert_sockaddr_to_pyaddr(ptr.ai_addr)
322
+ ))
323
+
324
+ ptr = ptr.ai_next
325
+
326
+ return result
327
+
328
+ @staticmethod
329
+ cdef int isinstance(object other):
330
+ return type(other) is AddrInfo
331
+
332
+
333
+ cdef class AddrInfoRequest(UVRequest):
334
+ cdef:
335
+ system.addrinfo hints
336
+ object callback
337
+ uv.uv_getaddrinfo_t _req_data
338
+
339
+ def __cinit__(self, Loop loop,
340
+ bytes host, bytes port,
341
+ int family, int type, int proto, int flags,
342
+ object callback):
343
+
344
+ cdef:
345
+ int err
346
+ char *chost
347
+ char *cport
348
+
349
+ if host is None:
350
+ chost = NULL
351
+ elif host == b'' and sys.platform == 'darwin':
352
+ # It seems `getaddrinfo("", ...)` on macOS is equivalent to
353
+ # `getaddrinfo("localhost", ...)`. This is inconsistent with
354
+ # libuv 1.48 which treats empty nodename as EINVAL.
355
+ chost = <char*>'localhost'
356
+ else:
357
+ chost = <char*>host
358
+
359
+ if port is None:
360
+ cport = NULL
361
+ else:
362
+ cport = <char*>port
363
+
364
+ memset(&self.hints, 0, sizeof(system.addrinfo))
365
+ self.hints.ai_flags = flags
366
+ self.hints.ai_family = family
367
+ self.hints.ai_socktype = type
368
+ self.hints.ai_protocol = proto
369
+
370
+ self.request = <uv.uv_req_t*> &self._req_data
371
+ self.callback = callback
372
+ self.request.data = <void*>self
373
+
374
+ err = uv.uv_getaddrinfo(loop.uvloop,
375
+ <uv.uv_getaddrinfo_t*>self.request,
376
+ __on_addrinfo_resolved,
377
+ chost,
378
+ cport,
379
+ &self.hints)
380
+
381
+ if err < 0:
382
+ self.on_done()
383
+ try:
384
+ if err == uv.UV_EINVAL:
385
+ # Convert UV_EINVAL to EAI_NONAME to match libc behavior
386
+ msg = system.gai_strerror(socket_EAI_NONAME).decode('utf-8')
387
+ ex = socket_gaierror(socket_EAI_NONAME, msg)
388
+ else:
389
+ ex = convert_error(err)
390
+ except Exception as ex:
391
+ callback(ex)
392
+ else:
393
+ callback(ex)
394
+
395
+
396
+ cdef class NameInfoRequest(UVRequest):
397
+ cdef:
398
+ object callback
399
+ uv.uv_getnameinfo_t _req_data
400
+
401
+ def __cinit__(self, Loop loop, callback):
402
+ self.request = <uv.uv_req_t*> &self._req_data
403
+ self.callback = callback
404
+ self.request.data = <void*>self
405
+
406
+ cdef query(self, system.sockaddr *addr, int flags):
407
+ cdef int err
408
+ err = uv.uv_getnameinfo(self.loop.uvloop,
409
+ <uv.uv_getnameinfo_t*>self.request,
410
+ __on_nameinfo_resolved,
411
+ addr,
412
+ flags)
413
+ if err < 0:
414
+ self.on_done()
415
+ self.callback(convert_error(err))
416
+
417
+
418
+ cdef _intenum_converter(value, enum_klass):
419
+ try:
420
+ return enum_klass(value)
421
+ except ValueError:
422
+ return value
423
+
424
+
425
+ cdef void __on_addrinfo_resolved(
426
+ uv.uv_getaddrinfo_t *resolver,
427
+ int status,
428
+ system.addrinfo *res,
429
+ ) noexcept with gil:
430
+
431
+ if resolver.data is NULL:
432
+ aio_logger.error(
433
+ 'AddrInfoRequest callback called with NULL resolver.data')
434
+ return
435
+
436
+ cdef:
437
+ AddrInfoRequest request = <AddrInfoRequest> resolver.data
438
+ Loop loop = request.loop
439
+ object callback = request.callback
440
+ AddrInfo ai
441
+
442
+ try:
443
+ if status < 0:
444
+ callback(convert_error(status))
445
+ else:
446
+ ai = AddrInfo()
447
+ ai.set_data(res)
448
+ callback(ai)
449
+ except (KeyboardInterrupt, SystemExit):
450
+ raise
451
+ except BaseException as ex:
452
+ loop._handle_exception(ex)
453
+ finally:
454
+ request.on_done()
455
+
456
+
457
+ cdef void __on_nameinfo_resolved(
458
+ uv.uv_getnameinfo_t* req,
459
+ int status,
460
+ const char* hostname,
461
+ const char* service,
462
+ ) noexcept with gil:
463
+ cdef:
464
+ NameInfoRequest request = <NameInfoRequest> req.data
465
+ Loop loop = request.loop
466
+ object callback = request.callback
467
+
468
+ try:
469
+ if status < 0:
470
+ callback(convert_error(status))
471
+ else:
472
+ callback(((<bytes>hostname).decode(),
473
+ (<bytes>service).decode()))
474
+ except (KeyboardInterrupt, SystemExit):
475
+ raise
476
+ except BaseException as ex:
477
+ loop._handle_exception(ex)
478
+ finally:
479
+ request.on_done()
.venv/lib/python3.11/site-packages/uvloop/errors.pyx ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef str __strerr(int errno):
2
+ return strerror(errno).decode()
3
+
4
+
5
+ cdef __convert_python_error(int uverr):
6
+ # XXX Won't work for Windows:
7
+ # From libuv docs:
8
+ # Implementation detail: on Unix error codes are the
9
+ # negated errno (or -errno), while on Windows they
10
+ # are defined by libuv to arbitrary negative numbers.
11
+ cdef int oserr = -uverr
12
+
13
+ exc = OSError
14
+
15
+ if uverr in (uv.UV_EACCES, uv.UV_EPERM):
16
+ exc = PermissionError
17
+
18
+ elif uverr in (uv.UV_EAGAIN, uv.UV_EALREADY):
19
+ exc = BlockingIOError
20
+
21
+ elif uverr in (uv.UV_EPIPE, uv.UV_ESHUTDOWN):
22
+ exc = BrokenPipeError
23
+
24
+ elif uverr == uv.UV_ECONNABORTED:
25
+ exc = ConnectionAbortedError
26
+
27
+ elif uverr == uv.UV_ECONNREFUSED:
28
+ exc = ConnectionRefusedError
29
+
30
+ elif uverr == uv.UV_ECONNRESET:
31
+ exc = ConnectionResetError
32
+
33
+ elif uverr == uv.UV_EEXIST:
34
+ exc = FileExistsError
35
+
36
+ elif uverr == uv.UV_ENOENT:
37
+ exc = FileNotFoundError
38
+
39
+ elif uverr == uv.UV_EINTR:
40
+ exc = InterruptedError
41
+
42
+ elif uverr == uv.UV_EISDIR:
43
+ exc = IsADirectoryError
44
+
45
+ elif uverr == uv.UV_ESRCH:
46
+ exc = ProcessLookupError
47
+
48
+ elif uverr == uv.UV_ETIMEDOUT:
49
+ exc = TimeoutError
50
+
51
+ return exc(oserr, __strerr(oserr))
52
+
53
+
54
+ cdef int __convert_socket_error(int uverr):
55
+ cdef int sock_err = 0
56
+
57
+ if uverr == uv.UV_EAI_ADDRFAMILY:
58
+ sock_err = socket_EAI_ADDRFAMILY
59
+
60
+ elif uverr == uv.UV_EAI_AGAIN:
61
+ sock_err = socket_EAI_AGAIN
62
+
63
+ elif uverr == uv.UV_EAI_BADFLAGS:
64
+ sock_err = socket_EAI_BADFLAGS
65
+
66
+ elif uverr == uv.UV_EAI_BADHINTS:
67
+ sock_err = socket_EAI_BADHINTS
68
+
69
+ elif uverr == uv.UV_EAI_CANCELED:
70
+ sock_err = socket_EAI_CANCELED
71
+
72
+ elif uverr == uv.UV_EAI_FAIL:
73
+ sock_err = socket_EAI_FAIL
74
+
75
+ elif uverr == uv.UV_EAI_FAMILY:
76
+ sock_err = socket_EAI_FAMILY
77
+
78
+ elif uverr == uv.UV_EAI_MEMORY:
79
+ sock_err = socket_EAI_MEMORY
80
+
81
+ elif uverr == uv.UV_EAI_NODATA:
82
+ sock_err = socket_EAI_NODATA
83
+
84
+ elif uverr == uv.UV_EAI_NONAME:
85
+ sock_err = socket_EAI_NONAME
86
+
87
+ elif uverr == uv.UV_EAI_OVERFLOW:
88
+ sock_err = socket_EAI_OVERFLOW
89
+
90
+ elif uverr == uv.UV_EAI_PROTOCOL:
91
+ sock_err = socket_EAI_PROTOCOL
92
+
93
+ elif uverr == uv.UV_EAI_SERVICE:
94
+ sock_err = socket_EAI_SERVICE
95
+
96
+ elif uverr == uv.UV_EAI_SOCKTYPE:
97
+ sock_err = socket_EAI_SOCKTYPE
98
+
99
+ return sock_err
100
+
101
+
102
+ cdef convert_error(int uverr):
103
+ cdef int sock_err
104
+
105
+ if uverr == uv.UV_ECANCELED:
106
+ return aio_CancelledError()
107
+
108
+ sock_err = __convert_socket_error(uverr)
109
+ if sock_err:
110
+ msg = system.gai_strerror(sock_err).decode('utf-8')
111
+ return socket_gaierror(sock_err, msg)
112
+
113
+ return __convert_python_error(uverr)
.venv/lib/python3.11/site-packages/uvloop/handles/async_.pxd ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVAsync(UVHandle):
2
+ cdef:
3
+ method_t callback
4
+ object ctx
5
+
6
+ cdef _init(self, Loop loop, method_t callback, object ctx)
7
+
8
+ cdef send(self)
9
+
10
+ @staticmethod
11
+ cdef UVAsync new(Loop loop, method_t callback, object ctx)
.venv/lib/python3.11/site-packages/uvloop/handles/async_.pyx ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @cython.no_gc_clear
2
+ cdef class UVAsync(UVHandle):
3
+ cdef _init(self, Loop loop, method_t callback, object ctx):
4
+ cdef int err
5
+
6
+ self._start_init(loop)
7
+
8
+ self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_async_t))
9
+ if self._handle is NULL:
10
+ self._abort_init()
11
+ raise MemoryError()
12
+
13
+ err = uv.uv_async_init(self._loop.uvloop,
14
+ <uv.uv_async_t*>self._handle,
15
+ __uvasync_callback)
16
+ if err < 0:
17
+ self._abort_init()
18
+ raise convert_error(err)
19
+
20
+ self._finish_init()
21
+
22
+ self.callback = callback
23
+ self.ctx = ctx
24
+
25
+ cdef send(self):
26
+ cdef int err
27
+
28
+ self._ensure_alive()
29
+
30
+ err = uv.uv_async_send(<uv.uv_async_t*>self._handle)
31
+ if err < 0:
32
+ exc = convert_error(err)
33
+ self._fatal_error(exc, True)
34
+ return
35
+
36
+ @staticmethod
37
+ cdef UVAsync new(Loop loop, method_t callback, object ctx):
38
+ cdef UVAsync handle
39
+ handle = UVAsync.__new__(UVAsync)
40
+ handle._init(loop, callback, ctx)
41
+ return handle
42
+
43
+
44
+ cdef void __uvasync_callback(
45
+ uv.uv_async_t* handle,
46
+ ) noexcept with gil:
47
+ if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVAsync callback") == 0:
48
+ return
49
+
50
+ cdef:
51
+ UVAsync async_ = <UVAsync> handle.data
52
+ method_t cb = async_.callback
53
+ try:
54
+ cb(async_.ctx)
55
+ except BaseException as ex:
56
+ async_._error(ex, False)
.venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pxd ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVBaseTransport(UVSocketHandle):
2
+
3
+ cdef:
4
+ readonly bint _closing
5
+
6
+ bint _protocol_connected
7
+ bint _protocol_paused
8
+ object _protocol_data_received
9
+ size_t _high_water
10
+ size_t _low_water
11
+
12
+ object _protocol
13
+ Server _server
14
+ object _waiter
15
+
16
+ dict _extra_info
17
+
18
+ uint32_t _conn_lost
19
+
20
+ object __weakref__
21
+
22
+ # All "inline" methods are final
23
+
24
+ cdef inline _maybe_pause_protocol(self)
25
+ cdef inline _maybe_resume_protocol(self)
26
+
27
+ cdef inline _schedule_call_connection_made(self)
28
+ cdef inline _schedule_call_connection_lost(self, exc)
29
+
30
+ cdef _wakeup_waiter(self)
31
+ cdef _call_connection_made(self)
32
+ cdef _call_connection_lost(self, exc)
33
+
34
+ # Overloads of UVHandle methods:
35
+ cdef _fatal_error(self, exc, throw, reason=?)
36
+ cdef _close(self)
37
+
38
+ cdef inline _set_server(self, Server server)
39
+ cdef inline _set_waiter(self, object waiter)
40
+
41
+ cdef _set_protocol(self, object protocol)
42
+ cdef _clear_protocol(self)
43
+
44
+ cdef inline _init_protocol(self)
45
+ cdef inline _add_extra_info(self, str name, object obj)
46
+
47
+ # === overloads ===
48
+
49
+ cdef _new_socket(self)
50
+ cdef size_t _get_write_buffer_size(self)
51
+
52
+ cdef bint _is_reading(self)
53
+ cdef _start_reading(self)
54
+ cdef _stop_reading(self)
.venv/lib/python3.11/site-packages/uvloop/handles/basetransport.pyx ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVBaseTransport(UVSocketHandle):
2
+
3
+ def __cinit__(self):
4
+ # Flow control
5
+ self._high_water = FLOW_CONTROL_HIGH_WATER * 1024
6
+ self._low_water = FLOW_CONTROL_HIGH_WATER // 4
7
+
8
+ self._protocol = None
9
+ self._protocol_connected = 0
10
+ self._protocol_paused = 0
11
+ self._protocol_data_received = None
12
+
13
+ self._server = None
14
+ self._waiter = None
15
+ self._extra_info = None
16
+
17
+ self._conn_lost = 0
18
+
19
+ self._closing = 0
20
+
21
+ cdef size_t _get_write_buffer_size(self):
22
+ return 0
23
+
24
+ cdef inline _schedule_call_connection_made(self):
25
+ self._loop._call_soon_handle(
26
+ new_MethodHandle(self._loop,
27
+ "UVTransport._call_connection_made",
28
+ <method_t>self._call_connection_made,
29
+ self.context,
30
+ self))
31
+
32
+ cdef inline _schedule_call_connection_lost(self, exc):
33
+ self._loop._call_soon_handle(
34
+ new_MethodHandle1(self._loop,
35
+ "UVTransport._call_connection_lost",
36
+ <method1_t>self._call_connection_lost,
37
+ self.context,
38
+ self, exc))
39
+
40
+ cdef _fatal_error(self, exc, throw, reason=None):
41
+ # Overload UVHandle._fatal_error
42
+
43
+ self._force_close(exc)
44
+
45
+ if not isinstance(exc, OSError):
46
+
47
+ if throw or self._loop is None:
48
+ raise exc
49
+
50
+ msg = f'Fatal error on transport {self.__class__.__name__}'
51
+ if reason is not None:
52
+ msg = f'{msg} ({reason})'
53
+
54
+ self._loop.call_exception_handler({
55
+ 'message': msg,
56
+ 'exception': exc,
57
+ 'transport': self,
58
+ 'protocol': self._protocol,
59
+ })
60
+
61
+ cdef inline _maybe_pause_protocol(self):
62
+ cdef:
63
+ size_t size = self._get_write_buffer_size()
64
+
65
+ if size <= self._high_water:
66
+ return
67
+
68
+ if not self._protocol_paused:
69
+ self._protocol_paused = 1
70
+ try:
71
+ # _maybe_pause_protocol() is always triggered from user-calls,
72
+ # so we must copy the context to avoid entering context twice
73
+ run_in_context(
74
+ self.context.copy(), self._protocol.pause_writing,
75
+ )
76
+ except (KeyboardInterrupt, SystemExit):
77
+ raise
78
+ except BaseException as exc:
79
+ self._loop.call_exception_handler({
80
+ 'message': 'protocol.pause_writing() failed',
81
+ 'exception': exc,
82
+ 'transport': self,
83
+ 'protocol': self._protocol,
84
+ })
85
+
86
+ cdef inline _maybe_resume_protocol(self):
87
+ cdef:
88
+ size_t size = self._get_write_buffer_size()
89
+
90
+ if self._protocol_paused and size <= self._low_water:
91
+ self._protocol_paused = 0
92
+ try:
93
+ # We're copying the context to avoid entering context twice,
94
+ # even though it's not always necessary to copy - it's easier
95
+ # to copy here than passing down a copied context.
96
+ run_in_context(
97
+ self.context.copy(), self._protocol.resume_writing,
98
+ )
99
+ except (KeyboardInterrupt, SystemExit):
100
+ raise
101
+ except BaseException as exc:
102
+ self._loop.call_exception_handler({
103
+ 'message': 'protocol.resume_writing() failed',
104
+ 'exception': exc,
105
+ 'transport': self,
106
+ 'protocol': self._protocol,
107
+ })
108
+
109
+ cdef _wakeup_waiter(self):
110
+ if self._waiter is not None:
111
+ if not self._waiter.cancelled():
112
+ if not self._is_alive():
113
+ self._waiter.set_exception(
114
+ RuntimeError(
115
+ 'closed Transport handle and unset waiter'))
116
+ else:
117
+ self._waiter.set_result(True)
118
+ self._waiter = None
119
+
120
+ cdef _call_connection_made(self):
121
+ if self._protocol is None:
122
+ raise RuntimeError(
123
+ 'protocol is not set, cannot call connection_made()')
124
+
125
+ # We use `_is_alive()` and not `_closing`, because we call
126
+ # `transport._close()` in `loop.create_connection()` if an
127
+ # exception happens during `await waiter`.
128
+ if not self._is_alive():
129
+ # A connection waiter can be cancelled between
130
+ # 'await loop.create_connection()' and
131
+ # `_schedule_call_connection_made` and
132
+ # the actual `_call_connection_made`.
133
+ self._wakeup_waiter()
134
+ return
135
+
136
+ # Set _protocol_connected to 1 before calling "connection_made":
137
+ # if transport is aborted or closed, "connection_lost" will
138
+ # still be scheduled.
139
+ self._protocol_connected = 1
140
+
141
+ try:
142
+ self._protocol.connection_made(self)
143
+ except BaseException:
144
+ self._wakeup_waiter()
145
+ raise
146
+
147
+ if not self._is_alive():
148
+ # This might happen when "transport.abort()" is called
149
+ # from "Protocol.connection_made".
150
+ self._wakeup_waiter()
151
+ return
152
+
153
+ self._start_reading()
154
+ self._wakeup_waiter()
155
+
156
+ cdef _call_connection_lost(self, exc):
157
+ if self._waiter is not None:
158
+ if not self._waiter.done():
159
+ self._waiter.set_exception(exc)
160
+ self._waiter = None
161
+
162
+ if self._closed:
163
+ # The handle is closed -- likely, _call_connection_lost
164
+ # was already called before.
165
+ return
166
+
167
+ try:
168
+ if self._protocol_connected:
169
+ self._protocol.connection_lost(exc)
170
+ finally:
171
+ self._clear_protocol()
172
+
173
+ self._close()
174
+
175
+ server = self._server
176
+ if server is not None:
177
+ (<Server>server)._detach()
178
+ self._server = None
179
+
180
+ cdef inline _set_server(self, Server server):
181
+ self._server = server
182
+ (<Server>server)._attach()
183
+
184
+ cdef inline _set_waiter(self, object waiter):
185
+ if waiter is not None and not isfuture(waiter):
186
+ raise TypeError(
187
+ f'invalid waiter object {waiter!r}, expected asyncio.Future')
188
+
189
+ self._waiter = waiter
190
+
191
+ cdef _set_protocol(self, object protocol):
192
+ self._protocol = protocol
193
+ # Store a reference to the bound method directly
194
+ try:
195
+ self._protocol_data_received = protocol.data_received
196
+ except AttributeError:
197
+ pass
198
+
199
+ cdef _clear_protocol(self):
200
+ self._protocol = None
201
+ self._protocol_data_received = None
202
+
203
+ cdef inline _init_protocol(self):
204
+ self._loop._track_transport(self)
205
+ if self._protocol is None:
206
+ raise RuntimeError('invalid _init_protocol call')
207
+ self._schedule_call_connection_made()
208
+
209
+ cdef inline _add_extra_info(self, str name, object obj):
210
+ if self._extra_info is None:
211
+ self._extra_info = {}
212
+ self._extra_info[name] = obj
213
+
214
+ cdef bint _is_reading(self):
215
+ raise NotImplementedError
216
+
217
+ cdef _start_reading(self):
218
+ raise NotImplementedError
219
+
220
+ cdef _stop_reading(self):
221
+ raise NotImplementedError
222
+
223
+ # === Public API ===
224
+
225
+ property _paused:
226
+ # Used by SSLProto. Might be removed in the future.
227
+ def __get__(self):
228
+ return bool(not self._is_reading())
229
+
230
+ def get_protocol(self):
231
+ return self._protocol
232
+
233
+ def set_protocol(self, protocol):
234
+ self._set_protocol(protocol)
235
+ if self._is_reading():
236
+ self._stop_reading()
237
+ self._start_reading()
238
+
239
+ def _force_close(self, exc):
240
+ # Used by SSLProto. Might be removed in the future.
241
+ if self._conn_lost or self._closed:
242
+ return
243
+ if not self._closing:
244
+ self._closing = 1
245
+ self._stop_reading()
246
+ self._conn_lost += 1
247
+ self._schedule_call_connection_lost(exc)
248
+
249
+ def abort(self):
250
+ self._force_close(None)
251
+
252
+ def close(self):
253
+ if self._closing or self._closed:
254
+ return
255
+
256
+ self._closing = 1
257
+ self._stop_reading()
258
+
259
+ if not self._get_write_buffer_size():
260
+ # The write buffer is empty
261
+ self._conn_lost += 1
262
+ self._schedule_call_connection_lost(None)
263
+
264
+ def is_closing(self):
265
+ return self._closing
266
+
267
+ def get_write_buffer_size(self):
268
+ return self._get_write_buffer_size()
269
+
270
+ def set_write_buffer_limits(self, high=None, low=None):
271
+ self._ensure_alive()
272
+
273
+ self._high_water, self._low_water = add_flowcontrol_defaults(
274
+ high, low, FLOW_CONTROL_HIGH_WATER)
275
+
276
+ self._maybe_pause_protocol()
277
+
278
+ def get_write_buffer_limits(self):
279
+ return (self._low_water, self._high_water)
280
+
281
+ def get_extra_info(self, name, default=None):
282
+ if self._extra_info is not None and name in self._extra_info:
283
+ return self._extra_info[name]
284
+ if name == 'socket':
285
+ return self._get_socket()
286
+ if name == 'sockname':
287
+ return self._get_socket().getsockname()
288
+ if name == 'peername':
289
+ try:
290
+ return self._get_socket().getpeername()
291
+ except socket_error:
292
+ return default
293
+ return default
.venv/lib/python3.11/site-packages/uvloop/handles/check.pxd ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVCheck(UVHandle):
2
+ cdef:
3
+ Handle h
4
+ bint running
5
+
6
+ # All "inline" methods are final
7
+
8
+ cdef _init(self, Loop loop, Handle h)
9
+
10
+ cdef inline stop(self)
11
+ cdef inline start(self)
12
+
13
+ @staticmethod
14
+ cdef UVCheck new(Loop loop, Handle h)
.venv/lib/python3.11/site-packages/uvloop/handles/check.pyx ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @cython.no_gc_clear
2
+ cdef class UVCheck(UVHandle):
3
+ cdef _init(self, Loop loop, Handle h):
4
+ cdef int err
5
+
6
+ self._start_init(loop)
7
+
8
+ self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_check_t))
9
+ if self._handle is NULL:
10
+ self._abort_init()
11
+ raise MemoryError()
12
+
13
+ err = uv.uv_check_init(self._loop.uvloop, <uv.uv_check_t*>self._handle)
14
+ if err < 0:
15
+ self._abort_init()
16
+ raise convert_error(err)
17
+
18
+ self._finish_init()
19
+
20
+ self.h = h
21
+ self.running = 0
22
+
23
+ cdef inline stop(self):
24
+ cdef int err
25
+
26
+ if not self._is_alive():
27
+ self.running = 0
28
+ return
29
+
30
+ if self.running == 1:
31
+ err = uv.uv_check_stop(<uv.uv_check_t*>self._handle)
32
+ self.running = 0
33
+ if err < 0:
34
+ exc = convert_error(err)
35
+ self._fatal_error(exc, True)
36
+ return
37
+
38
+ cdef inline start(self):
39
+ cdef int err
40
+
41
+ self._ensure_alive()
42
+
43
+ if self.running == 0:
44
+ err = uv.uv_check_start(<uv.uv_check_t*>self._handle,
45
+ cb_check_callback)
46
+ if err < 0:
47
+ exc = convert_error(err)
48
+ self._fatal_error(exc, True)
49
+ return
50
+ self.running = 1
51
+
52
+ @staticmethod
53
+ cdef UVCheck new(Loop loop, Handle h):
54
+ cdef UVCheck handle
55
+ handle = UVCheck.__new__(UVCheck)
56
+ handle._init(loop, h)
57
+ return handle
58
+
59
+
60
+ cdef void cb_check_callback(
61
+ uv.uv_check_t* handle,
62
+ ) noexcept with gil:
63
+ if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVCheck callback") == 0:
64
+ return
65
+
66
+ cdef:
67
+ UVCheck check = <UVCheck> handle.data
68
+ Handle h = check.h
69
+ try:
70
+ h._run()
71
+ except BaseException as ex:
72
+ check._error(ex, False)
.venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pxd ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVFSEvent(UVHandle):
2
+ cdef:
3
+ object callback
4
+ bint running
5
+
6
+ cdef _init(self, Loop loop, object callback, object context)
7
+ cdef _close(self)
8
+ cdef start(self, char* path, int flags)
9
+ cdef stop(self)
10
+
11
+ @staticmethod
12
+ cdef UVFSEvent new(Loop loop, object callback, object context)
.venv/lib/python3.11/site-packages/uvloop/handles/fsevent.pyx ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import enum
2
+
3
+
4
+ class FileSystemEvent(enum.IntEnum):
5
+ RENAME = uv.UV_RENAME
6
+ CHANGE = uv.UV_CHANGE
7
+ RENAME_CHANGE = RENAME | CHANGE
8
+
9
+
10
+ @cython.no_gc_clear
11
+ cdef class UVFSEvent(UVHandle):
12
+ cdef _init(self, Loop loop, object callback, object context):
13
+ cdef int err
14
+
15
+ self._start_init(loop)
16
+
17
+ self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(
18
+ sizeof(uv.uv_fs_event_t)
19
+ )
20
+ if self._handle is NULL:
21
+ self._abort_init()
22
+ raise MemoryError()
23
+
24
+ err = uv.uv_fs_event_init(
25
+ self._loop.uvloop, <uv.uv_fs_event_t*>self._handle
26
+ )
27
+ if err < 0:
28
+ self._abort_init()
29
+ raise convert_error(err)
30
+
31
+ self._finish_init()
32
+
33
+ self.running = 0
34
+ self.callback = callback
35
+ if context is None:
36
+ context = Context_CopyCurrent()
37
+ self.context = context
38
+
39
+ cdef start(self, char* path, int flags):
40
+ cdef int err
41
+
42
+ self._ensure_alive()
43
+
44
+ if self.running == 0:
45
+ err = uv.uv_fs_event_start(
46
+ <uv.uv_fs_event_t*>self._handle,
47
+ __uvfsevent_callback,
48
+ path,
49
+ flags,
50
+ )
51
+ if err < 0:
52
+ exc = convert_error(err)
53
+ self._fatal_error(exc, True)
54
+ return
55
+ self.running = 1
56
+
57
+ cdef stop(self):
58
+ cdef int err
59
+
60
+ if not self._is_alive():
61
+ self.running = 0
62
+ return
63
+
64
+ if self.running == 1:
65
+ err = uv.uv_fs_event_stop(<uv.uv_fs_event_t*>self._handle)
66
+ self.running = 0
67
+ if err < 0:
68
+ exc = convert_error(err)
69
+ self._fatal_error(exc, True)
70
+ return
71
+
72
+ cdef _close(self):
73
+ try:
74
+ self.stop()
75
+ finally:
76
+ UVHandle._close(<UVHandle>self)
77
+
78
+ def cancel(self):
79
+ self._close()
80
+
81
+ def cancelled(self):
82
+ return self.running == 0
83
+
84
+ @staticmethod
85
+ cdef UVFSEvent new(Loop loop, object callback, object context):
86
+ cdef UVFSEvent handle
87
+ handle = UVFSEvent.__new__(UVFSEvent)
88
+ handle._init(loop, callback, context)
89
+ return handle
90
+
91
+
92
+ cdef void __uvfsevent_callback(
93
+ uv.uv_fs_event_t* handle,
94
+ const char *filename,
95
+ int events,
96
+ int status,
97
+ ) noexcept with gil:
98
+ if __ensure_handle_data(
99
+ <uv.uv_handle_t*>handle, "UVFSEvent callback"
100
+ ) == 0:
101
+ return
102
+
103
+ cdef:
104
+ UVFSEvent fs_event = <UVFSEvent> handle.data
105
+ Handle h
106
+
107
+ try:
108
+ h = new_Handle(
109
+ fs_event._loop,
110
+ fs_event.callback,
111
+ (filename, FileSystemEvent(events)),
112
+ fs_event.context,
113
+ )
114
+ h._run()
115
+ except BaseException as ex:
116
+ fs_event._error(ex, False)
.venv/lib/python3.11/site-packages/uvloop/handles/handle.pxd ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVHandle:
2
+ cdef:
3
+ uv.uv_handle_t *_handle
4
+ Loop _loop
5
+ readonly _source_traceback
6
+ bint _closed
7
+ bint _inited
8
+ object context
9
+
10
+ # Added to enable current UDPTransport implementation,
11
+ # which doesn't use libuv handles.
12
+ bint _has_handle
13
+
14
+ # All "inline" methods are final
15
+
16
+ cdef inline _start_init(self, Loop loop)
17
+ cdef inline _abort_init(self)
18
+ cdef inline _finish_init(self)
19
+
20
+ cdef inline bint _is_alive(self)
21
+ cdef inline _ensure_alive(self)
22
+
23
+ cdef _error(self, exc, throw)
24
+ cdef _fatal_error(self, exc, throw, reason=?)
25
+
26
+ cdef _warn_unclosed(self)
27
+
28
+ cdef _free(self)
29
+ cdef _close(self)
30
+
31
+
32
+ cdef class UVSocketHandle(UVHandle):
33
+ cdef:
34
+ # Points to a Python file-object that should be closed
35
+ # when the transport is closing. Used by pipes. This
36
+ # should probably be refactored somehow.
37
+ object _fileobj
38
+ object __cached_socket
39
+
40
+ # All "inline" methods are final
41
+
42
+ cdef _fileno(self)
43
+
44
+ cdef _new_socket(self)
45
+ cdef inline _get_socket(self)
46
+ cdef inline _attach_fileobj(self, object file)
47
+
48
+ cdef _open(self, int sockfd)
.venv/lib/python3.11/site-packages/uvloop/handles/handle.pyx ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVHandle:
2
+ """A base class for all libuv handles.
3
+
4
+ Automatically manages memory deallocation and closing.
5
+
6
+ Important:
7
+
8
+ 1. call "_ensure_alive()" before calling any libuv functions on
9
+ your handles.
10
+
11
+ 2. call "__ensure_handle_data" in *all* libuv handle callbacks.
12
+ """
13
+
14
+ def __cinit__(self):
15
+ self._closed = 0
16
+ self._inited = 0
17
+ self._has_handle = 1
18
+ self._handle = NULL
19
+ self._loop = None
20
+ self._source_traceback = None
21
+
22
+ def __init__(self):
23
+ raise TypeError(
24
+ '{} is not supposed to be instantiated from Python'.format(
25
+ self.__class__.__name__))
26
+
27
+ def __dealloc__(self):
28
+ if UVLOOP_DEBUG:
29
+ if self._loop is not None:
30
+ if self._inited:
31
+ self._loop._debug_handles_current.subtract([
32
+ self.__class__.__name__])
33
+ else:
34
+ # No "@cython.no_gc_clear" decorator on this UVHandle
35
+ raise RuntimeError(
36
+ '{} without @no_gc_clear; loop was set to None by GC'
37
+ .format(self.__class__.__name__))
38
+
39
+ if self._handle is NULL:
40
+ return
41
+
42
+ # -> When we're at this point, something is wrong <-
43
+
44
+ if self._handle.loop is NULL:
45
+ # The handle wasn't initialized with "uv_{handle}_init"
46
+ self._closed = 1
47
+ self._free()
48
+ raise RuntimeError(
49
+ '{} is open in __dealloc__ with loop set to NULL'
50
+ .format(self.__class__.__name__))
51
+
52
+ if self._closed:
53
+ # So _handle is not NULL and self._closed == 1?
54
+ raise RuntimeError(
55
+ '{}.__dealloc__: _handle is NULL, _closed == 1'.format(
56
+ self.__class__.__name__))
57
+
58
+ # The handle is dealloced while open. Let's try to close it.
59
+ # Situations when this is possible include unhandled exceptions,
60
+ # errors during Handle.__cinit__/__init__ etc.
61
+ if self._inited:
62
+ self._handle.data = NULL
63
+ uv.uv_close(self._handle, __uv_close_handle_cb) # void; no errors
64
+ self._handle = NULL
65
+ self._warn_unclosed()
66
+ else:
67
+ # The handle was allocated, but not initialized
68
+ self._closed = 1
69
+ self._free()
70
+
71
+ cdef _free(self):
72
+ if self._handle == NULL:
73
+ return
74
+
75
+ if UVLOOP_DEBUG and self._inited:
76
+ self._loop._debug_uv_handles_freed += 1
77
+
78
+ PyMem_RawFree(self._handle)
79
+ self._handle = NULL
80
+
81
+ cdef _warn_unclosed(self):
82
+ if self._source_traceback is not None:
83
+ try:
84
+ tb = ''.join(tb_format_list(self._source_traceback))
85
+ tb = 'object created at (most recent call last):\n{}'.format(
86
+ tb.rstrip())
87
+ except Exception as ex:
88
+ msg = (
89
+ 'unclosed resource {!r}; could not serialize '
90
+ 'debug traceback: {}: {}'
91
+ ).format(self, type(ex).__name__, ex)
92
+ else:
93
+ msg = 'unclosed resource {!r}; {}'.format(self, tb)
94
+ else:
95
+ msg = 'unclosed resource {!r}'.format(self)
96
+ warnings_warn(msg, ResourceWarning)
97
+
98
+ cdef inline _abort_init(self):
99
+ if self._handle is not NULL:
100
+ self._free()
101
+
102
+ try:
103
+ if UVLOOP_DEBUG:
104
+ name = self.__class__.__name__
105
+ if self._inited:
106
+ raise RuntimeError(
107
+ '_abort_init: {}._inited is set'.format(name))
108
+ if self._closed:
109
+ raise RuntimeError(
110
+ '_abort_init: {}._closed is set'.format(name))
111
+ finally:
112
+ self._closed = 1
113
+
114
+ cdef inline _finish_init(self):
115
+ self._inited = 1
116
+ if self._has_handle == 1:
117
+ self._handle.data = <void*>self
118
+ if self._loop._debug:
119
+ self._source_traceback = extract_stack()
120
+ if UVLOOP_DEBUG:
121
+ cls_name = self.__class__.__name__
122
+ self._loop._debug_uv_handles_total += 1
123
+ self._loop._debug_handles_total.update([cls_name])
124
+ self._loop._debug_handles_current.update([cls_name])
125
+
126
+ cdef inline _start_init(self, Loop loop):
127
+ if UVLOOP_DEBUG:
128
+ if self._loop is not None:
129
+ raise RuntimeError(
130
+ '{}._start_init can only be called once'.format(
131
+ self.__class__.__name__))
132
+
133
+ self._loop = loop
134
+
135
+ cdef inline bint _is_alive(self):
136
+ cdef bint res
137
+ res = self._closed != 1 and self._inited == 1
138
+ if UVLOOP_DEBUG:
139
+ if res and self._has_handle == 1:
140
+ name = self.__class__.__name__
141
+ if self._handle is NULL:
142
+ raise RuntimeError(
143
+ '{} is alive, but _handle is NULL'.format(name))
144
+ if self._loop is None:
145
+ raise RuntimeError(
146
+ '{} is alive, but _loop is None'.format(name))
147
+ if self._handle.loop is not self._loop.uvloop:
148
+ raise RuntimeError(
149
+ '{} is alive, but _handle.loop is not '
150
+ 'initialized'.format(name))
151
+ if self._handle.data is not <void*>self:
152
+ raise RuntimeError(
153
+ '{} is alive, but _handle.data is not '
154
+ 'initialized'.format(name))
155
+ return res
156
+
157
+ cdef inline _ensure_alive(self):
158
+ if not self._is_alive():
159
+ raise RuntimeError(
160
+ 'unable to perform operation on {!r}; '
161
+ 'the handler is closed'.format(self))
162
+
163
+ cdef _fatal_error(self, exc, throw, reason=None):
164
+ # Fatal error means an error that was returned by the
165
+ # underlying libuv handle function. We usually can't
166
+ # recover from that, hence we just close the handle.
167
+ self._close()
168
+
169
+ if throw or self._loop is None:
170
+ raise exc
171
+ else:
172
+ self._loop._handle_exception(exc)
173
+
174
+ cdef _error(self, exc, throw):
175
+ # A non-fatal error is usually an error that was caught
176
+ # by the handler, but was originated in the client code
177
+ # (not in libuv). In this case we either want to simply
178
+ # raise or log it.
179
+ if throw or self._loop is None:
180
+ raise exc
181
+ else:
182
+ self._loop._handle_exception(exc)
183
+
184
+ cdef _close(self):
185
+ if self._closed == 1:
186
+ return
187
+
188
+ self._closed = 1
189
+
190
+ if self._handle is NULL:
191
+ return
192
+
193
+ if UVLOOP_DEBUG:
194
+ if self._handle.data is NULL:
195
+ raise RuntimeError(
196
+ '{}._close: _handle.data is NULL'.format(
197
+ self.__class__.__name__))
198
+
199
+ if <object>self._handle.data is not self:
200
+ raise RuntimeError(
201
+ '{}._close: _handle.data is not UVHandle/self'.format(
202
+ self.__class__.__name__))
203
+
204
+ if uv.uv_is_closing(self._handle):
205
+ raise RuntimeError(
206
+ '{}._close: uv_is_closing() is true'.format(
207
+ self.__class__.__name__))
208
+
209
+ # We want the handle wrapper (UVHandle) to stay alive until
210
+ # the closing callback fires.
211
+ Py_INCREF(self)
212
+ uv.uv_close(self._handle, __uv_close_handle_cb) # void; no errors
213
+
214
+ def __repr__(self):
215
+ return '<{} closed={} {:#x}>'.format(
216
+ self.__class__.__name__,
217
+ self._closed,
218
+ id(self))
219
+
220
+
221
+ cdef class UVSocketHandle(UVHandle):
222
+
223
+ def __cinit__(self):
224
+ self._fileobj = None
225
+ self.__cached_socket = None
226
+
227
+ cdef _fileno(self):
228
+ cdef:
229
+ int fd
230
+ int err
231
+
232
+ self._ensure_alive()
233
+ err = uv.uv_fileno(self._handle, <uv.uv_os_fd_t*>&fd)
234
+ if err < 0:
235
+ raise convert_error(err)
236
+
237
+ return fd
238
+
239
+ cdef _new_socket(self):
240
+ raise NotImplementedError
241
+
242
+ cdef inline _get_socket(self):
243
+ if self.__cached_socket is not None:
244
+ return self.__cached_socket
245
+
246
+ if not self._is_alive():
247
+ return None
248
+
249
+ self.__cached_socket = self._new_socket()
250
+ if UVLOOP_DEBUG:
251
+ # We don't "dup" for the "__cached_socket".
252
+ assert self.__cached_socket.fileno() == self._fileno()
253
+ return self.__cached_socket
254
+
255
+ cdef inline _attach_fileobj(self, object file):
256
+ # When we create a TCP/PIPE/etc connection/server based on
257
+ # a Python file object, we need to close the file object when
258
+ # the uv handle is closed.
259
+ socket_inc_io_ref(file)
260
+ self._fileobj = file
261
+
262
+ cdef _close(self):
263
+ if self.__cached_socket is not None:
264
+ (<PseudoSocket>self.__cached_socket)._fd = -1
265
+
266
+ UVHandle._close(self)
267
+
268
+ try:
269
+ # This code will only run for transports created from
270
+ # Python sockets, i.e. with `loop.create_server(sock=sock)` etc.
271
+ if self._fileobj is not None:
272
+ if isinstance(self._fileobj, socket_socket):
273
+ # Detaching the socket object is the ideal solution:
274
+ # * libuv will actually close the FD;
275
+ # * detach() call will reset FD for the Python socket
276
+ # object, which means that it won't be closed 2nd time
277
+ # when the socket object is GCed.
278
+ #
279
+ # No need to call `socket_dec_io_ref()`, as
280
+ # `socket.detach()` ignores `socket._io_refs`.
281
+ self._fileobj.detach()
282
+ else:
283
+ try:
284
+ # `socket.close()` will raise an EBADF because libuv
285
+ # has already closed the underlying FD.
286
+ self._fileobj.close()
287
+ except OSError as ex:
288
+ if ex.errno != errno_EBADF:
289
+ raise
290
+ except Exception as ex:
291
+ self._loop.call_exception_handler({
292
+ 'exception': ex,
293
+ 'transport': self,
294
+ 'message': f'could not close attached file object '
295
+ f'{self._fileobj!r}',
296
+ })
297
+ finally:
298
+ self._fileobj = None
299
+
300
+ cdef _open(self, int sockfd):
301
+ raise NotImplementedError
302
+
303
+
304
+ cdef inline bint __ensure_handle_data(uv.uv_handle_t* handle,
305
+ const char* handle_ctx):
306
+
307
+ cdef Loop loop
308
+
309
+ if UVLOOP_DEBUG:
310
+ if handle.loop is NULL:
311
+ raise RuntimeError(
312
+ 'handle.loop is NULL in __ensure_handle_data')
313
+
314
+ if handle.loop.data is NULL:
315
+ raise RuntimeError(
316
+ 'handle.loop.data is NULL in __ensure_handle_data')
317
+
318
+ if handle.data is NULL:
319
+ loop = <Loop>handle.loop.data
320
+ loop.call_exception_handler({
321
+ 'message': '{} called with handle.data == NULL'.format(
322
+ handle_ctx.decode('latin-1'))
323
+ })
324
+ return 0
325
+
326
+ if handle.data is NULL:
327
+ # The underlying UVHandle object was GCed with an open uv_handle_t.
328
+ loop = <Loop>handle.loop.data
329
+ loop.call_exception_handler({
330
+ 'message': '{} called after destroying the UVHandle'.format(
331
+ handle_ctx.decode('latin-1'))
332
+ })
333
+ return 0
334
+
335
+ return 1
336
+
337
+
338
+ cdef void __uv_close_handle_cb(uv.uv_handle_t* handle) noexcept with gil:
339
+ cdef UVHandle h
340
+
341
+ if handle.data is NULL:
342
+ # The original UVHandle is long dead. Just free the mem of
343
+ # the uv_handle_t* handler.
344
+
345
+ if UVLOOP_DEBUG:
346
+ if handle.loop == NULL or handle.loop.data == NULL:
347
+ raise RuntimeError(
348
+ '__uv_close_handle_cb: handle.loop is invalid')
349
+ (<Loop>handle.loop.data)._debug_uv_handles_freed += 1
350
+
351
+ PyMem_RawFree(handle)
352
+ else:
353
+ h = <UVHandle>handle.data
354
+ try:
355
+ if UVLOOP_DEBUG:
356
+ if not h._has_handle:
357
+ raise RuntimeError(
358
+ 'has_handle=0 in __uv_close_handle_cb')
359
+ h._loop._debug_handles_closed.update([
360
+ h.__class__.__name__])
361
+ h._free()
362
+ finally:
363
+ Py_DECREF(h) # Was INCREFed in UVHandle._close
364
+
365
+
366
+ cdef void __close_all_handles(Loop loop) noexcept:
367
+ uv.uv_walk(loop.uvloop,
368
+ __uv_walk_close_all_handles_cb,
369
+ <void*>loop) # void
370
+
371
+
372
+ cdef void __uv_walk_close_all_handles_cb(
373
+ uv.uv_handle_t* handle,
374
+ void* arg,
375
+ ) noexcept with gil:
376
+
377
+ cdef:
378
+ Loop loop = <Loop>arg
379
+ UVHandle h
380
+
381
+ if uv.uv_is_closing(handle):
382
+ # The handle is closed or is closing.
383
+ return
384
+
385
+ if handle.data is NULL:
386
+ # This shouldn't happen. Ever.
387
+ loop.call_exception_handler({
388
+ 'message': 'handle.data is NULL in __close_all_handles_cb'
389
+ })
390
+ return
391
+
392
+ h = <UVHandle>handle.data
393
+ if not h._closed:
394
+ h._warn_unclosed()
395
+ h._close()
.venv/lib/python3.11/site-packages/uvloop/handles/idle.pxd ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVIdle(UVHandle):
2
+ cdef:
3
+ Handle h
4
+ bint running
5
+
6
+ # All "inline" methods are final
7
+
8
+ cdef _init(self, Loop loop, Handle h)
9
+
10
+ cdef inline stop(self)
11
+ cdef inline start(self)
12
+
13
+ @staticmethod
14
+ cdef UVIdle new(Loop loop, Handle h)
.venv/lib/python3.11/site-packages/uvloop/handles/idle.pyx ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @cython.no_gc_clear
2
+ cdef class UVIdle(UVHandle):
3
+ cdef _init(self, Loop loop, Handle h):
4
+ cdef int err
5
+
6
+ self._start_init(loop)
7
+
8
+ self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_idle_t))
9
+ if self._handle is NULL:
10
+ self._abort_init()
11
+ raise MemoryError()
12
+
13
+ err = uv.uv_idle_init(self._loop.uvloop, <uv.uv_idle_t*>self._handle)
14
+ if err < 0:
15
+ self._abort_init()
16
+ raise convert_error(err)
17
+
18
+ self._finish_init()
19
+
20
+ self.h = h
21
+ self.running = 0
22
+
23
+ cdef inline stop(self):
24
+ cdef int err
25
+
26
+ if not self._is_alive():
27
+ self.running = 0
28
+ return
29
+
30
+ if self.running == 1:
31
+ err = uv.uv_idle_stop(<uv.uv_idle_t*>self._handle)
32
+ self.running = 0
33
+ if err < 0:
34
+ exc = convert_error(err)
35
+ self._fatal_error(exc, True)
36
+ return
37
+
38
+ cdef inline start(self):
39
+ cdef int err
40
+
41
+ self._ensure_alive()
42
+
43
+ if self.running == 0:
44
+ err = uv.uv_idle_start(<uv.uv_idle_t*>self._handle,
45
+ cb_idle_callback)
46
+ if err < 0:
47
+ exc = convert_error(err)
48
+ self._fatal_error(exc, True)
49
+ return
50
+ self.running = 1
51
+
52
+ @staticmethod
53
+ cdef UVIdle new(Loop loop, Handle h):
54
+ cdef UVIdle handle
55
+ handle = UVIdle.__new__(UVIdle)
56
+ handle._init(loop, h)
57
+ return handle
58
+
59
+
60
+ cdef void cb_idle_callback(
61
+ uv.uv_idle_t* handle,
62
+ ) noexcept with gil:
63
+ if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVIdle callback") == 0:
64
+ return
65
+
66
+ cdef:
67
+ UVIdle idle = <UVIdle> handle.data
68
+ Handle h = idle.h
69
+ try:
70
+ h._run()
71
+ except BaseException as ex:
72
+ idle._error(ex, False)
.venv/lib/python3.11/site-packages/uvloop/handles/pipe.pxd ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UnixServer(UVStreamServer):
2
+
3
+ cdef bind(self, str path)
4
+
5
+ @staticmethod
6
+ cdef UnixServer new(Loop loop, object protocol_factory, Server server,
7
+ object backlog,
8
+ object ssl,
9
+ object ssl_handshake_timeout,
10
+ object ssl_shutdown_timeout)
11
+
12
+
13
+ cdef class UnixTransport(UVStream):
14
+
15
+ @staticmethod
16
+ cdef UnixTransport new(Loop loop, object protocol, Server server,
17
+ object waiter, object context)
18
+
19
+ cdef connect(self, char* addr)
20
+
21
+
22
+ cdef class ReadUnixTransport(UVStream):
23
+
24
+ @staticmethod
25
+ cdef ReadUnixTransport new(Loop loop, object protocol, Server server,
26
+ object waiter)
27
+
28
+
29
+ cdef class WriteUnixTransport(UVStream):
30
+
31
+ @staticmethod
32
+ cdef WriteUnixTransport new(Loop loop, object protocol, Server server,
33
+ object waiter)
.venv/lib/python3.11/site-packages/uvloop/handles/pipe.pyx ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef __pipe_init_uv_handle(UVStream handle, Loop loop):
2
+ cdef int err
3
+
4
+ handle._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_pipe_t))
5
+ if handle._handle is NULL:
6
+ handle._abort_init()
7
+ raise MemoryError()
8
+
9
+ # Initialize pipe handle with ipc=0.
10
+ # ipc=1 means that libuv will use recvmsg/sendmsg
11
+ # instead of recv/send.
12
+ err = uv.uv_pipe_init(handle._loop.uvloop,
13
+ <uv.uv_pipe_t*>handle._handle,
14
+ 0)
15
+ # UV_HANDLE_READABLE allows calling uv_read_start() on this pipe
16
+ # even if it is O_WRONLY, see also #317, libuv/libuv#2058
17
+ handle._handle.flags |= uv.UV_INTERNAL_HANDLE_READABLE
18
+ if err < 0:
19
+ handle._abort_init()
20
+ raise convert_error(err)
21
+
22
+ handle._finish_init()
23
+
24
+
25
+ cdef __pipe_open(UVStream handle, int fd):
26
+ cdef int err
27
+ err = uv.uv_pipe_open(<uv.uv_pipe_t *>handle._handle,
28
+ <uv.uv_os_fd_t>fd)
29
+ if err < 0:
30
+ exc = convert_error(err)
31
+ raise exc
32
+
33
+
34
+ cdef __pipe_get_socket(UVSocketHandle handle):
35
+ fileno = handle._fileno()
36
+ return PseudoSocket(uv.AF_UNIX, uv.SOCK_STREAM, 0, fileno)
37
+
38
+
39
+ @cython.no_gc_clear
40
+ cdef class UnixServer(UVStreamServer):
41
+
42
+ @staticmethod
43
+ cdef UnixServer new(Loop loop, object protocol_factory, Server server,
44
+ object backlog,
45
+ object ssl,
46
+ object ssl_handshake_timeout,
47
+ object ssl_shutdown_timeout):
48
+
49
+ cdef UnixServer handle
50
+ handle = UnixServer.__new__(UnixServer)
51
+ handle._init(loop, protocol_factory, server, backlog,
52
+ ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
53
+ __pipe_init_uv_handle(<UVStream>handle, loop)
54
+ return handle
55
+
56
+ cdef _new_socket(self):
57
+ return __pipe_get_socket(<UVSocketHandle>self)
58
+
59
+ cdef _open(self, int sockfd):
60
+ self._ensure_alive()
61
+ __pipe_open(<UVStream>self, sockfd)
62
+ self._mark_as_open()
63
+
64
+ cdef bind(self, str path):
65
+ cdef int err
66
+ self._ensure_alive()
67
+ err = uv.uv_pipe_bind(<uv.uv_pipe_t *>self._handle,
68
+ path.encode())
69
+ if err < 0:
70
+ exc = convert_error(err)
71
+ self._fatal_error(exc, True)
72
+ return
73
+
74
+ self._mark_as_open()
75
+
76
+ cdef UVStream _make_new_transport(self, object protocol, object waiter,
77
+ object context):
78
+ cdef UnixTransport tr
79
+ tr = UnixTransport.new(self._loop, protocol, self._server, waiter,
80
+ context)
81
+ return <UVStream>tr
82
+
83
+ cdef _close(self):
84
+ sock = self._fileobj
85
+ if sock is not None and sock in self._loop._unix_server_sockets:
86
+ path = sock.getsockname()
87
+ else:
88
+ path = None
89
+
90
+ UVStreamServer._close(self)
91
+
92
+ if path is not None:
93
+ prev_ino = self._loop._unix_server_sockets[sock]
94
+ del self._loop._unix_server_sockets[sock]
95
+ try:
96
+ if os_stat(path).st_ino == prev_ino:
97
+ os_unlink(path)
98
+ except FileNotFoundError:
99
+ pass
100
+ except OSError as err:
101
+ aio_logger.error('Unable to clean up listening UNIX socket '
102
+ '%r: %r', path, err)
103
+
104
+
105
+ @cython.no_gc_clear
106
+ cdef class UnixTransport(UVStream):
107
+
108
+ @staticmethod
109
+ cdef UnixTransport new(Loop loop, object protocol, Server server,
110
+ object waiter, object context):
111
+
112
+ cdef UnixTransport handle
113
+ handle = UnixTransport.__new__(UnixTransport)
114
+ handle._init(loop, protocol, server, waiter, context)
115
+ __pipe_init_uv_handle(<UVStream>handle, loop)
116
+ return handle
117
+
118
+ cdef _new_socket(self):
119
+ return __pipe_get_socket(<UVSocketHandle>self)
120
+
121
+ cdef _open(self, int sockfd):
122
+ __pipe_open(<UVStream>self, sockfd)
123
+
124
+ cdef connect(self, char* addr):
125
+ cdef _PipeConnectRequest req
126
+ req = _PipeConnectRequest(self._loop, self)
127
+ req.connect(addr)
128
+
129
+
130
+ @cython.no_gc_clear
131
+ cdef class ReadUnixTransport(UVStream):
132
+
133
+ @staticmethod
134
+ cdef ReadUnixTransport new(Loop loop, object protocol, Server server,
135
+ object waiter):
136
+ cdef ReadUnixTransport handle
137
+ handle = ReadUnixTransport.__new__(ReadUnixTransport)
138
+ # This is only used in connect_read_pipe() and subprocess_shell/exec()
139
+ # directly, we could simply copy the current context.
140
+ handle._init(loop, protocol, server, waiter, Context_CopyCurrent())
141
+ __pipe_init_uv_handle(<UVStream>handle, loop)
142
+ return handle
143
+
144
+ cdef _new_socket(self):
145
+ return __pipe_get_socket(<UVSocketHandle>self)
146
+
147
+ cdef _open(self, int sockfd):
148
+ __pipe_open(<UVStream>self, sockfd)
149
+
150
+ def get_write_buffer_limits(self):
151
+ raise NotImplementedError
152
+
153
+ def set_write_buffer_limits(self, high=None, low=None):
154
+ raise NotImplementedError
155
+
156
+ def get_write_buffer_size(self):
157
+ raise NotImplementedError
158
+
159
+ def write(self, data):
160
+ raise NotImplementedError
161
+
162
+ def writelines(self, list_of_data):
163
+ raise NotImplementedError
164
+
165
+ def write_eof(self):
166
+ raise NotImplementedError
167
+
168
+ def can_write_eof(self):
169
+ raise NotImplementedError
170
+
171
+ def abort(self):
172
+ raise NotImplementedError
173
+
174
+
175
+ @cython.no_gc_clear
176
+ cdef class WriteUnixTransport(UVStream):
177
+
178
+ @staticmethod
179
+ cdef WriteUnixTransport new(Loop loop, object protocol, Server server,
180
+ object waiter):
181
+ cdef WriteUnixTransport handle
182
+ handle = WriteUnixTransport.__new__(WriteUnixTransport)
183
+
184
+ # We listen for read events on write-end of the pipe. When
185
+ # the read-end is close, the uv_stream_t.read callback will
186
+ # receive an error -- we want to silence that error, and just
187
+ # close the transport.
188
+ handle._close_on_read_error()
189
+
190
+ # This is only used in connect_write_pipe() and subprocess_shell/exec()
191
+ # directly, we could simply copy the current context.
192
+ handle._init(loop, protocol, server, waiter, Context_CopyCurrent())
193
+ __pipe_init_uv_handle(<UVStream>handle, loop)
194
+ return handle
195
+
196
+ cdef _new_socket(self):
197
+ return __pipe_get_socket(<UVSocketHandle>self)
198
+
199
+ cdef _open(self, int sockfd):
200
+ __pipe_open(<UVStream>self, sockfd)
201
+
202
+ def pause_reading(self):
203
+ raise NotImplementedError
204
+
205
+ def resume_reading(self):
206
+ raise NotImplementedError
207
+
208
+
209
+ cdef class _PipeConnectRequest(UVRequest):
210
+ cdef:
211
+ UnixTransport transport
212
+ uv.uv_connect_t _req_data
213
+
214
+ def __cinit__(self, loop, transport):
215
+ self.request = <uv.uv_req_t*> &self._req_data
216
+ self.request.data = <void*>self
217
+ self.transport = transport
218
+
219
+ cdef connect(self, char* addr):
220
+ # uv_pipe_connect returns void
221
+ uv.uv_pipe_connect(<uv.uv_connect_t*>self.request,
222
+ <uv.uv_pipe_t*>self.transport._handle,
223
+ addr,
224
+ __pipe_connect_callback)
225
+
226
+ cdef void __pipe_connect_callback(
227
+ uv.uv_connect_t* req,
228
+ int status,
229
+ ) noexcept with gil:
230
+ cdef:
231
+ _PipeConnectRequest wrapper
232
+ UnixTransport transport
233
+
234
+ wrapper = <_PipeConnectRequest> req.data
235
+ transport = wrapper.transport
236
+
237
+ if status < 0:
238
+ exc = convert_error(status)
239
+ else:
240
+ exc = None
241
+
242
+ try:
243
+ transport._on_connect(exc)
244
+ except BaseException as ex:
245
+ wrapper.transport._fatal_error(ex, False)
246
+ finally:
247
+ wrapper.on_done()
.venv/lib/python3.11/site-packages/uvloop/handles/poll.pxd ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVPoll(UVHandle):
2
+ cdef:
3
+ int fd
4
+ Handle reading_handle
5
+ Handle writing_handle
6
+
7
+ cdef _init(self, Loop loop, int fd)
8
+ cdef _close(self)
9
+
10
+ cdef inline _poll_start(self, int flags)
11
+ cdef inline _poll_stop(self)
12
+
13
+ cdef int is_active(self) noexcept
14
+
15
+ cdef is_reading(self)
16
+ cdef is_writing(self)
17
+
18
+ cdef start_reading(self, Handle callback)
19
+ cdef start_writing(self, Handle callback)
20
+ cdef stop_reading(self)
21
+ cdef stop_writing(self)
22
+ cdef stop(self)
23
+
24
+ @staticmethod
25
+ cdef UVPoll new(Loop loop, int fd)
.venv/lib/python3.11/site-packages/uvloop/handles/poll.pyx ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @cython.no_gc_clear
2
+ cdef class UVPoll(UVHandle):
3
+ cdef _init(self, Loop loop, int fd):
4
+ cdef int err
5
+
6
+ self._start_init(loop)
7
+
8
+ self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_poll_t))
9
+ if self._handle is NULL:
10
+ self._abort_init()
11
+ raise MemoryError()
12
+
13
+ err = uv.uv_poll_init(self._loop.uvloop,
14
+ <uv.uv_poll_t *>self._handle, fd)
15
+ if err < 0:
16
+ self._abort_init()
17
+ raise convert_error(err)
18
+
19
+ self._finish_init()
20
+
21
+ self.fd = fd
22
+ self.reading_handle = None
23
+ self.writing_handle = None
24
+
25
+ @staticmethod
26
+ cdef UVPoll new(Loop loop, int fd):
27
+ cdef UVPoll handle
28
+ handle = UVPoll.__new__(UVPoll)
29
+ handle._init(loop, fd)
30
+ return handle
31
+
32
+ cdef int is_active(self) noexcept:
33
+ return (self.reading_handle is not None or
34
+ self.writing_handle is not None)
35
+
36
+ cdef inline _poll_start(self, int flags):
37
+ cdef int err
38
+
39
+ self._ensure_alive()
40
+
41
+ err = uv.uv_poll_start(
42
+ <uv.uv_poll_t*>self._handle,
43
+ flags,
44
+ __on_uvpoll_event)
45
+
46
+ if err < 0:
47
+ exc = convert_error(err)
48
+ self._fatal_error(exc, True)
49
+ return
50
+
51
+ cdef inline _poll_stop(self):
52
+ cdef int err
53
+
54
+ if not self._is_alive():
55
+ return
56
+
57
+ err = uv.uv_poll_stop(<uv.uv_poll_t*>self._handle)
58
+ if err < 0:
59
+ exc = convert_error(err)
60
+ self._fatal_error(exc, True)
61
+ return
62
+
63
+ cdef:
64
+ int backend_id
65
+ system.epoll_event dummy_event
66
+
67
+ if system.PLATFORM_IS_LINUX:
68
+ # libuv doesn't remove the FD from epoll immediately
69
+ # after uv_poll_stop or uv_poll_close, causing hard
70
+ # to debug issue with dup-ed file descriptors causing
71
+ # CPU burn in epoll/epoll_ctl:
72
+ # https://github.com/MagicStack/uvloop/issues/61
73
+ #
74
+ # It's safe though to manually call epoll_ctl here,
75
+ # after calling uv_poll_stop.
76
+
77
+ backend_id = uv.uv_backend_fd(self._loop.uvloop)
78
+ if backend_id != -1:
79
+ memset(&dummy_event, 0, sizeof(dummy_event))
80
+ system.epoll_ctl(
81
+ backend_id,
82
+ system.EPOLL_CTL_DEL,
83
+ self.fd,
84
+ &dummy_event) # ignore errors
85
+
86
+ cdef is_reading(self):
87
+ return self._is_alive() and self.reading_handle is not None
88
+
89
+ cdef is_writing(self):
90
+ return self._is_alive() and self.writing_handle is not None
91
+
92
+ cdef start_reading(self, Handle callback):
93
+ cdef:
94
+ int mask = 0
95
+
96
+ if self.reading_handle is None:
97
+ # not reading right now, setup the handle
98
+
99
+ mask = uv.UV_READABLE
100
+ if self.writing_handle is not None:
101
+ # are we writing right now?
102
+ mask |= uv.UV_WRITABLE
103
+
104
+ self._poll_start(mask)
105
+ else:
106
+ self.reading_handle._cancel()
107
+
108
+ self.reading_handle = callback
109
+
110
+ cdef start_writing(self, Handle callback):
111
+ cdef:
112
+ int mask = 0
113
+
114
+ if self.writing_handle is None:
115
+ # not writing right now, setup the handle
116
+
117
+ mask = uv.UV_WRITABLE
118
+ if self.reading_handle is not None:
119
+ # are we reading right now?
120
+ mask |= uv.UV_READABLE
121
+
122
+ self._poll_start(mask)
123
+ else:
124
+ self.writing_handle._cancel()
125
+
126
+ self.writing_handle = callback
127
+
128
+ cdef stop_reading(self):
129
+ if self.reading_handle is None:
130
+ return False
131
+
132
+ self.reading_handle._cancel()
133
+ self.reading_handle = None
134
+
135
+ if self.writing_handle is None:
136
+ self.stop()
137
+ else:
138
+ self._poll_start(uv.UV_WRITABLE)
139
+
140
+ return True
141
+
142
+ cdef stop_writing(self):
143
+ if self.writing_handle is None:
144
+ return False
145
+
146
+ self.writing_handle._cancel()
147
+ self.writing_handle = None
148
+
149
+ if self.reading_handle is None:
150
+ self.stop()
151
+ else:
152
+ self._poll_start(uv.UV_READABLE)
153
+
154
+ return True
155
+
156
+ cdef stop(self):
157
+ if self.reading_handle is not None:
158
+ self.reading_handle._cancel()
159
+ self.reading_handle = None
160
+
161
+ if self.writing_handle is not None:
162
+ self.writing_handle._cancel()
163
+ self.writing_handle = None
164
+
165
+ self._poll_stop()
166
+
167
+ cdef _close(self):
168
+ if self.is_active():
169
+ self.stop()
170
+
171
+ UVHandle._close(<UVHandle>self)
172
+
173
+ cdef _fatal_error(self, exc, throw, reason=None):
174
+ try:
175
+ if self.reading_handle is not None:
176
+ try:
177
+ self.reading_handle._run()
178
+ except BaseException as ex:
179
+ self._loop._handle_exception(ex)
180
+ self.reading_handle = None
181
+
182
+ if self.writing_handle is not None:
183
+ try:
184
+ self.writing_handle._run()
185
+ except BaseException as ex:
186
+ self._loop._handle_exception(ex)
187
+ self.writing_handle = None
188
+
189
+ finally:
190
+ self._close()
191
+
192
+
193
+ cdef void __on_uvpoll_event(
194
+ uv.uv_poll_t* handle,
195
+ int status,
196
+ int events,
197
+ ) noexcept with gil:
198
+
199
+ if __ensure_handle_data(<uv.uv_handle_t*>handle, "UVPoll callback") == 0:
200
+ return
201
+
202
+ cdef:
203
+ UVPoll poll = <UVPoll> handle.data
204
+
205
+ if status < 0:
206
+ exc = convert_error(status)
207
+ poll._fatal_error(exc, False)
208
+ return
209
+
210
+ if ((events & (uv.UV_READABLE | uv.UV_DISCONNECT)) and
211
+ poll.reading_handle is not None):
212
+
213
+ try:
214
+ if UVLOOP_DEBUG:
215
+ poll._loop._poll_read_events_total += 1
216
+ poll.reading_handle._run()
217
+ except BaseException as ex:
218
+ if UVLOOP_DEBUG:
219
+ poll._loop._poll_read_cb_errors_total += 1
220
+ poll._error(ex, False)
221
+ # continue code execution
222
+
223
+ if ((events & (uv.UV_WRITABLE | uv.UV_DISCONNECT)) and
224
+ poll.writing_handle is not None):
225
+
226
+ try:
227
+ if UVLOOP_DEBUG:
228
+ poll._loop._poll_write_events_total += 1
229
+ poll.writing_handle._run()
230
+ except BaseException as ex:
231
+ if UVLOOP_DEBUG:
232
+ poll._loop._poll_write_cb_errors_total += 1
233
+ poll._error(ex, False)
.venv/lib/python3.11/site-packages/uvloop/handles/process.pxd ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVProcess(UVHandle):
2
+ cdef:
3
+ object _returncode
4
+ object _pid
5
+
6
+ object _errpipe_read
7
+ object _errpipe_write
8
+ object _preexec_fn
9
+ bint _restore_signals
10
+
11
+ list _fds_to_close
12
+
13
+ # Attributes used to compose uv_process_options_t:
14
+ uv.uv_process_options_t options
15
+ uv.uv_stdio_container_t[3] iocnt
16
+ list __env
17
+ char **uv_opt_env
18
+ list __args
19
+ char **uv_opt_args
20
+ char *uv_opt_file
21
+ bytes __cwd
22
+
23
+ cdef _close_process_handle(self)
24
+
25
+ cdef _init(self, Loop loop, list args, dict env, cwd,
26
+ start_new_session,
27
+ _stdin, _stdout, _stderr, pass_fds,
28
+ debug_flags, preexec_fn, restore_signals)
29
+
30
+ cdef _after_fork(self)
31
+
32
+ cdef char** __to_cstring_array(self, list arr)
33
+ cdef _init_args(self, list args)
34
+ cdef _init_env(self, dict env)
35
+ cdef _init_files(self, _stdin, _stdout, _stderr)
36
+ cdef _init_options(self, list args, dict env, cwd, start_new_session,
37
+ _stdin, _stdout, _stderr, bint force_fork)
38
+
39
+ cdef _close_after_spawn(self, int fd)
40
+
41
+ cdef _on_exit(self, int64_t exit_status, int term_signal)
42
+ cdef _kill(self, int signum)
43
+
44
+
45
+ cdef class UVProcessTransport(UVProcess):
46
+ cdef:
47
+ list _exit_waiters
48
+ list _init_futs
49
+ bint _stdio_ready
50
+ list _pending_calls
51
+ object _protocol
52
+ bint _finished
53
+
54
+ WriteUnixTransport _stdin
55
+ ReadUnixTransport _stdout
56
+ ReadUnixTransport _stderr
57
+
58
+ object stdin_proto
59
+ object stdout_proto
60
+ object stderr_proto
61
+
62
+ cdef _file_redirect_stdio(self, int fd)
63
+ cdef _file_devnull(self)
64
+ cdef _file_inpipe(self)
65
+ cdef _file_outpipe(self)
66
+
67
+ cdef _check_proc(self)
68
+ cdef _pipe_connection_lost(self, int fd, exc)
69
+ cdef _pipe_data_received(self, int fd, data)
70
+
71
+ cdef _call_connection_made(self, waiter)
72
+ cdef _try_finish(self)
73
+
74
+ @staticmethod
75
+ cdef UVProcessTransport new(Loop loop, protocol, args, env, cwd,
76
+ start_new_session,
77
+ _stdin, _stdout, _stderr, pass_fds,
78
+ waiter,
79
+ debug_flags,
80
+ preexec_fn, restore_signals)
.venv/lib/python3.11/site-packages/uvloop/handles/process.pyx ADDED
@@ -0,0 +1,792 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @cython.no_gc_clear
2
+ cdef class UVProcess(UVHandle):
3
+ """Abstract class; wrapper over uv_process_t handle."""
4
+
5
+ def __cinit__(self):
6
+ self.uv_opt_env = NULL
7
+ self.uv_opt_args = NULL
8
+ self._returncode = None
9
+ self._pid = None
10
+ self._fds_to_close = list()
11
+ self._preexec_fn = None
12
+ self._restore_signals = True
13
+ self.context = Context_CopyCurrent()
14
+
15
+ cdef _close_process_handle(self):
16
+ # XXX: This is a workaround for a libuv bug:
17
+ # - https://github.com/libuv/libuv/issues/1933
18
+ # - https://github.com/libuv/libuv/pull/551
19
+ if self._handle is NULL:
20
+ return
21
+ self._handle.data = NULL
22
+ uv.uv_close(self._handle, __uv_close_process_handle_cb)
23
+ self._handle = NULL # close callback will free() the memory
24
+
25
+ cdef _init(self, Loop loop, list args, dict env,
26
+ cwd, start_new_session,
27
+ _stdin, _stdout, _stderr, # std* can be defined as macros in C
28
+ pass_fds, debug_flags, preexec_fn, restore_signals):
29
+
30
+ global __forking
31
+ global __forking_loop
32
+ global __forkHandler
33
+
34
+ cdef int err
35
+
36
+ self._start_init(loop)
37
+
38
+ self._handle = <uv.uv_handle_t*>PyMem_RawMalloc(
39
+ sizeof(uv.uv_process_t))
40
+ if self._handle is NULL:
41
+ self._abort_init()
42
+ raise MemoryError()
43
+
44
+ # Too early to call _finish_init, but still a lot of work to do.
45
+ # Let's set handle.data to NULL, so in case something goes wrong,
46
+ # callbacks have a chance to avoid casting *something* into UVHandle.
47
+ self._handle.data = NULL
48
+
49
+ force_fork = False
50
+ if system.PLATFORM_IS_APPLE and not (
51
+ preexec_fn is None
52
+ and not pass_fds
53
+ ):
54
+ # see _execute_child() in CPython/subprocess.py
55
+ force_fork = True
56
+
57
+ try:
58
+ self._init_options(args, env, cwd, start_new_session,
59
+ _stdin, _stdout, _stderr, force_fork)
60
+
61
+ restore_inheritable = set()
62
+ if pass_fds:
63
+ for fd in pass_fds:
64
+ if not os_get_inheritable(fd):
65
+ restore_inheritable.add(fd)
66
+ os_set_inheritable(fd, True)
67
+ except Exception:
68
+ self._abort_init()
69
+ raise
70
+
71
+ if __forking or loop.active_process_handler is not None:
72
+ # Our pthread_atfork handlers won't work correctly when
73
+ # another loop is forking in another thread (even though
74
+ # GIL should help us to avoid that.)
75
+ self._abort_init()
76
+ raise RuntimeError(
77
+ 'Racing with another loop to spawn a process.')
78
+
79
+ self._errpipe_read, self._errpipe_write = os_pipe()
80
+ fds_to_close = self._fds_to_close
81
+ self._fds_to_close = None
82
+ fds_to_close.append(self._errpipe_read)
83
+ # add the write pipe last so we can close it early
84
+ fds_to_close.append(self._errpipe_write)
85
+ try:
86
+ os_set_inheritable(self._errpipe_write, True)
87
+
88
+ self._preexec_fn = preexec_fn
89
+ self._restore_signals = restore_signals
90
+
91
+ loop.active_process_handler = self
92
+ __forking = 1
93
+ __forking_loop = loop
94
+ system.setForkHandler(<system.OnForkHandler>&__get_fork_handler)
95
+
96
+ PyOS_BeforeFork()
97
+
98
+ err = uv.uv_spawn(loop.uvloop,
99
+ <uv.uv_process_t*>self._handle,
100
+ &self.options)
101
+
102
+ __forking = 0
103
+ __forking_loop = None
104
+ system.resetForkHandler()
105
+ loop.active_process_handler = None
106
+
107
+ PyOS_AfterFork_Parent()
108
+
109
+ if err < 0:
110
+ self._close_process_handle()
111
+ self._abort_init()
112
+ raise convert_error(err)
113
+
114
+ self._finish_init()
115
+
116
+ # close the write pipe early
117
+ os_close(fds_to_close.pop())
118
+
119
+ if preexec_fn is not None:
120
+ errpipe_data = bytearray()
121
+ while True:
122
+ # XXX: This is a blocking code that has to be
123
+ # rewritten (using loop.connect_read_pipe() or
124
+ # otherwise.)
125
+ part = os_read(self._errpipe_read, 50000)
126
+ errpipe_data += part
127
+ if not part or len(errpipe_data) > 50000:
128
+ break
129
+
130
+ finally:
131
+ while fds_to_close:
132
+ os_close(fds_to_close.pop())
133
+
134
+ for fd in restore_inheritable:
135
+ os_set_inheritable(fd, False)
136
+
137
+ # asyncio caches the PID in BaseSubprocessTransport,
138
+ # so that the transport knows what the PID was even
139
+ # after the process is finished.
140
+ self._pid = (<uv.uv_process_t*>self._handle).pid
141
+
142
+ # Track the process handle (create a strong ref to it)
143
+ # to guarantee that __dealloc__ doesn't happen in an
144
+ # uncontrolled fashion. We want to wait until the process
145
+ # exits and libuv calls __uvprocess_on_exit_callback,
146
+ # which will call `UVProcess._close()`, which will, in turn,
147
+ # untrack this handle.
148
+ self._loop._track_process(self)
149
+
150
+ if debug_flags & __PROCESS_DEBUG_SLEEP_AFTER_FORK:
151
+ time_sleep(1)
152
+
153
+ if preexec_fn is not None and errpipe_data:
154
+ # preexec_fn has raised an exception. The child
155
+ # process must be dead now.
156
+ try:
157
+ exc_name, exc_msg = errpipe_data.split(b':', 1)
158
+ exc_name = exc_name.decode()
159
+ exc_msg = exc_msg.decode()
160
+ except Exception:
161
+ self._close()
162
+ raise subprocess_SubprocessError(
163
+ 'Bad exception data from child: {!r}'.format(
164
+ errpipe_data))
165
+ exc_cls = getattr(__builtins__, exc_name,
166
+ subprocess_SubprocessError)
167
+
168
+ exc = subprocess_SubprocessError(
169
+ 'Exception occurred in preexec_fn.')
170
+ exc.__cause__ = exc_cls(exc_msg)
171
+ self._close()
172
+ raise exc
173
+
174
+ cdef _after_fork(self):
175
+ # See CPython/_posixsubprocess.c for details
176
+ cdef int err
177
+
178
+ if self._restore_signals:
179
+ _Py_RestoreSignals()
180
+
181
+ PyOS_AfterFork_Child()
182
+
183
+ err = uv.uv_loop_fork(self._loop.uvloop)
184
+ if err < 0:
185
+ raise convert_error(err)
186
+
187
+ if self._preexec_fn is not None:
188
+ try:
189
+ gc_disable()
190
+ self._preexec_fn()
191
+ except BaseException as ex:
192
+ try:
193
+ with open(self._errpipe_write, 'wb') as f:
194
+ f.write(str(ex.__class__.__name__).encode())
195
+ f.write(b':')
196
+ f.write(str(ex.args[0]).encode())
197
+ finally:
198
+ system._exit(255)
199
+ return
200
+ else:
201
+ os_close(self._errpipe_write)
202
+ else:
203
+ os_close(self._errpipe_write)
204
+
205
+ cdef _close_after_spawn(self, int fd):
206
+ if self._fds_to_close is None:
207
+ raise RuntimeError(
208
+ 'UVProcess._close_after_spawn called after uv_spawn')
209
+ self._fds_to_close.append(fd)
210
+
211
+ def __dealloc__(self):
212
+ if self.uv_opt_env is not NULL:
213
+ PyMem_RawFree(self.uv_opt_env)
214
+ self.uv_opt_env = NULL
215
+
216
+ if self.uv_opt_args is not NULL:
217
+ PyMem_RawFree(self.uv_opt_args)
218
+ self.uv_opt_args = NULL
219
+
220
+ cdef char** __to_cstring_array(self, list arr):
221
+ cdef:
222
+ int i
223
+ ssize_t arr_len = len(arr)
224
+ bytes el
225
+
226
+ char **ret
227
+
228
+ ret = <char **>PyMem_RawMalloc((arr_len + 1) * sizeof(char *))
229
+ if ret is NULL:
230
+ raise MemoryError()
231
+
232
+ for i in range(arr_len):
233
+ el = arr[i]
234
+ # NB: PyBytes_AsString doesn't copy the data;
235
+ # we have to be careful when the "arr" is GCed,
236
+ # and it shouldn't be ever mutated.
237
+ ret[i] = PyBytes_AsString(el)
238
+
239
+ ret[arr_len] = NULL
240
+ return ret
241
+
242
+ cdef _init_options(self, list args, dict env, cwd, start_new_session,
243
+ _stdin, _stdout, _stderr, bint force_fork):
244
+
245
+ memset(&self.options, 0, sizeof(uv.uv_process_options_t))
246
+
247
+ self._init_env(env)
248
+ self.options.env = self.uv_opt_env
249
+
250
+ self._init_args(args)
251
+ self.options.file = self.uv_opt_file
252
+ self.options.args = self.uv_opt_args
253
+
254
+ if start_new_session:
255
+ self.options.flags |= uv.UV_PROCESS_DETACHED
256
+
257
+ if force_fork:
258
+ # This is a hack to work around the change in libuv 1.44:
259
+ # > macos: use posix_spawn instead of fork
260
+ # where Python subprocess options like preexec_fn are
261
+ # crippled. CPython only uses posix_spawn under a pretty
262
+ # strict list of conditions (see subprocess.py), and falls
263
+ # back to using fork() otherwise. We'd like to simulate such
264
+ # behavior with libuv, but unfortunately libuv doesn't
265
+ # provide explicit API to choose such implementation detail.
266
+ # Based on current (libuv 1.46) behavior, setting
267
+ # UV_PROCESS_SETUID or UV_PROCESS_SETGID would reliably make
268
+ # libuv fallback to use fork, so let's just use it for now.
269
+ self.options.flags |= uv.UV_PROCESS_SETUID
270
+ self.options.uid = uv.getuid()
271
+
272
+ if cwd is not None:
273
+ cwd = os_fspath(cwd)
274
+
275
+ if isinstance(cwd, str):
276
+ cwd = PyUnicode_EncodeFSDefault(cwd)
277
+ if not isinstance(cwd, bytes):
278
+ raise ValueError('cwd must be a str or bytes object')
279
+
280
+ self.__cwd = cwd
281
+ self.options.cwd = PyBytes_AsString(self.__cwd)
282
+
283
+ self.options.exit_cb = &__uvprocess_on_exit_callback
284
+
285
+ self._init_files(_stdin, _stdout, _stderr)
286
+
287
+ cdef _init_args(self, list args):
288
+ cdef:
289
+ bytes path
290
+ int an = len(args)
291
+
292
+ if an < 1:
293
+ raise ValueError('cannot spawn a process: args are empty')
294
+
295
+ self.__args = args.copy()
296
+ for i in range(an):
297
+ arg = os_fspath(args[i])
298
+ if isinstance(arg, str):
299
+ self.__args[i] = PyUnicode_EncodeFSDefault(arg)
300
+ elif not isinstance(arg, bytes):
301
+ raise TypeError('all args must be str or bytes')
302
+
303
+ path = self.__args[0]
304
+ self.uv_opt_file = PyBytes_AsString(path)
305
+ self.uv_opt_args = self.__to_cstring_array(self.__args)
306
+
307
+ cdef _init_env(self, dict env):
308
+ if env is not None:
309
+ self.__env = list()
310
+ for key in env:
311
+ val = env[key]
312
+
313
+ if isinstance(key, str):
314
+ key = PyUnicode_EncodeFSDefault(key)
315
+ elif not isinstance(key, bytes):
316
+ raise TypeError(
317
+ 'all environment vars must be bytes or str')
318
+
319
+ if isinstance(val, str):
320
+ val = PyUnicode_EncodeFSDefault(val)
321
+ elif not isinstance(val, bytes):
322
+ raise TypeError(
323
+ 'all environment values must be bytes or str')
324
+
325
+ self.__env.append(key + b'=' + val)
326
+
327
+ self.uv_opt_env = self.__to_cstring_array(self.__env)
328
+ else:
329
+ self.__env = None
330
+
331
+ cdef _init_files(self, _stdin, _stdout, _stderr):
332
+ self.options.stdio_count = 0
333
+
334
+ cdef _kill(self, int signum):
335
+ cdef int err
336
+ self._ensure_alive()
337
+ err = uv.uv_process_kill(<uv.uv_process_t*>self._handle, signum)
338
+ if err < 0:
339
+ raise convert_error(err)
340
+
341
+ cdef _on_exit(self, int64_t exit_status, int term_signal):
342
+ if term_signal:
343
+ # From Python docs:
344
+ # A negative value -N indicates that the child was
345
+ # terminated by signal N (POSIX only).
346
+ self._returncode = -term_signal
347
+ else:
348
+ self._returncode = exit_status
349
+
350
+ self._close()
351
+
352
+ cdef _close(self):
353
+ try:
354
+ if self._loop is not None:
355
+ self._loop._untrack_process(self)
356
+ finally:
357
+ UVHandle._close(self)
358
+
359
+
360
+ DEF _CALL_PIPE_DATA_RECEIVED = 0
361
+ DEF _CALL_PIPE_CONNECTION_LOST = 1
362
+ DEF _CALL_PROCESS_EXITED = 2
363
+ DEF _CALL_CONNECTION_LOST = 3
364
+
365
+
366
+ @cython.no_gc_clear
367
+ cdef class UVProcessTransport(UVProcess):
368
+ def __cinit__(self):
369
+ self._exit_waiters = []
370
+ self._protocol = None
371
+
372
+ self._init_futs = []
373
+ self._pending_calls = []
374
+ self._stdio_ready = 0
375
+
376
+ self._stdin = self._stdout = self._stderr = None
377
+ self.stdin_proto = self.stdout_proto = self.stderr_proto = None
378
+
379
+ self._finished = 0
380
+
381
+ cdef _on_exit(self, int64_t exit_status, int term_signal):
382
+ UVProcess._on_exit(self, exit_status, term_signal)
383
+
384
+ if self._stdio_ready:
385
+ self._loop.call_soon(self._protocol.process_exited,
386
+ context=self.context)
387
+ else:
388
+ self._pending_calls.append((_CALL_PROCESS_EXITED, None, None))
389
+
390
+ self._try_finish()
391
+
392
+ for waiter in self._exit_waiters:
393
+ if not waiter.cancelled():
394
+ waiter.set_result(self._returncode)
395
+ self._exit_waiters.clear()
396
+
397
+ self._close()
398
+
399
+ cdef _check_proc(self):
400
+ if not self._is_alive() or self._returncode is not None:
401
+ raise ProcessLookupError()
402
+
403
+ cdef _pipe_connection_lost(self, int fd, exc):
404
+ if self._stdio_ready:
405
+ self._loop.call_soon(self._protocol.pipe_connection_lost, fd, exc,
406
+ context=self.context)
407
+ self._try_finish()
408
+ else:
409
+ self._pending_calls.append((_CALL_PIPE_CONNECTION_LOST, fd, exc))
410
+
411
+ cdef _pipe_data_received(self, int fd, data):
412
+ if self._stdio_ready:
413
+ self._loop.call_soon(self._protocol.pipe_data_received, fd, data,
414
+ context=self.context)
415
+ else:
416
+ self._pending_calls.append((_CALL_PIPE_DATA_RECEIVED, fd, data))
417
+
418
+ cdef _file_redirect_stdio(self, int fd):
419
+ fd = os_dup(fd)
420
+ os_set_inheritable(fd, True)
421
+ self._close_after_spawn(fd)
422
+ return fd
423
+
424
+ cdef _file_devnull(self):
425
+ dn = os_open(os_devnull, os_O_RDWR)
426
+ os_set_inheritable(dn, True)
427
+ self._close_after_spawn(dn)
428
+ return dn
429
+
430
+ cdef _file_outpipe(self):
431
+ r, w = __socketpair()
432
+ os_set_inheritable(w, True)
433
+ self._close_after_spawn(w)
434
+ return r, w
435
+
436
+ cdef _file_inpipe(self):
437
+ r, w = __socketpair()
438
+ os_set_inheritable(r, True)
439
+ self._close_after_spawn(r)
440
+ return r, w
441
+
442
+ cdef _init_files(self, _stdin, _stdout, _stderr):
443
+ cdef uv.uv_stdio_container_t *iocnt
444
+
445
+ UVProcess._init_files(self, _stdin, _stdout, _stderr)
446
+
447
+ io = [None, None, None]
448
+
449
+ self.options.stdio_count = 3
450
+ self.options.stdio = self.iocnt
451
+
452
+ if _stdin is not None:
453
+ if _stdin == subprocess_PIPE:
454
+ r, w = self._file_inpipe()
455
+ io[0] = r
456
+
457
+ self.stdin_proto = WriteSubprocessPipeProto(self, 0)
458
+ waiter = self._loop._new_future()
459
+ self._stdin = WriteUnixTransport.new(
460
+ self._loop, self.stdin_proto, None, waiter)
461
+ self._init_futs.append(waiter)
462
+ self._stdin._open(w)
463
+ self._stdin._init_protocol()
464
+ elif _stdin == subprocess_DEVNULL:
465
+ io[0] = self._file_devnull()
466
+ elif _stdout == subprocess_STDOUT:
467
+ raise ValueError(
468
+ 'subprocess.STDOUT is supported only by stderr parameter')
469
+ else:
470
+ io[0] = self._file_redirect_stdio(_stdin)
471
+ else:
472
+ io[0] = self._file_redirect_stdio(0)
473
+
474
+ if _stdout is not None:
475
+ if _stdout == subprocess_PIPE:
476
+ # We can't use UV_CREATE_PIPE here, since 'stderr' might be
477
+ # set to 'subprocess.STDOUT', and there is no way to
478
+ # emulate that functionality with libuv high-level
479
+ # streams API. Therefore, we create pipes for stdout and
480
+ # stderr manually.
481
+
482
+ r, w = self._file_outpipe()
483
+ io[1] = w
484
+
485
+ self.stdout_proto = ReadSubprocessPipeProto(self, 1)
486
+ waiter = self._loop._new_future()
487
+ self._stdout = ReadUnixTransport.new(
488
+ self._loop, self.stdout_proto, None, waiter)
489
+ self._init_futs.append(waiter)
490
+ self._stdout._open(r)
491
+ self._stdout._init_protocol()
492
+ elif _stdout == subprocess_DEVNULL:
493
+ io[1] = self._file_devnull()
494
+ elif _stdout == subprocess_STDOUT:
495
+ raise ValueError(
496
+ 'subprocess.STDOUT is supported only by stderr parameter')
497
+ else:
498
+ io[1] = self._file_redirect_stdio(_stdout)
499
+ else:
500
+ io[1] = self._file_redirect_stdio(1)
501
+
502
+ if _stderr is not None:
503
+ if _stderr == subprocess_PIPE:
504
+ r, w = self._file_outpipe()
505
+ io[2] = w
506
+
507
+ self.stderr_proto = ReadSubprocessPipeProto(self, 2)
508
+ waiter = self._loop._new_future()
509
+ self._stderr = ReadUnixTransport.new(
510
+ self._loop, self.stderr_proto, None, waiter)
511
+ self._init_futs.append(waiter)
512
+ self._stderr._open(r)
513
+ self._stderr._init_protocol()
514
+ elif _stderr == subprocess_STDOUT:
515
+ if io[1] is None:
516
+ # shouldn't ever happen
517
+ raise RuntimeError('cannot apply subprocess.STDOUT')
518
+
519
+ io[2] = self._file_redirect_stdio(io[1])
520
+ elif _stderr == subprocess_DEVNULL:
521
+ io[2] = self._file_devnull()
522
+ else:
523
+ io[2] = self._file_redirect_stdio(_stderr)
524
+ else:
525
+ io[2] = self._file_redirect_stdio(2)
526
+
527
+ assert len(io) == 3
528
+ for idx in range(3):
529
+ iocnt = &self.iocnt[idx]
530
+ if io[idx] is not None:
531
+ iocnt.flags = uv.UV_INHERIT_FD
532
+ iocnt.data.fd = io[idx]
533
+ else:
534
+ iocnt.flags = uv.UV_IGNORE
535
+
536
+ cdef _call_connection_made(self, waiter):
537
+ try:
538
+ # we're always called in the right context, so just call the user's
539
+ self._protocol.connection_made(self)
540
+ except (KeyboardInterrupt, SystemExit):
541
+ raise
542
+ except BaseException as ex:
543
+ if waiter is not None and not waiter.cancelled():
544
+ waiter.set_exception(ex)
545
+ else:
546
+ raise
547
+ else:
548
+ if waiter is not None and not waiter.cancelled():
549
+ waiter.set_result(True)
550
+
551
+ self._stdio_ready = 1
552
+ if self._pending_calls:
553
+ pending_calls = self._pending_calls.copy()
554
+ self._pending_calls.clear()
555
+ for (type, fd, arg) in pending_calls:
556
+ if type == _CALL_PIPE_CONNECTION_LOST:
557
+ self._pipe_connection_lost(fd, arg)
558
+ elif type == _CALL_PIPE_DATA_RECEIVED:
559
+ self._pipe_data_received(fd, arg)
560
+ elif type == _CALL_PROCESS_EXITED:
561
+ self._loop.call_soon(self._protocol.process_exited)
562
+ elif type == _CALL_CONNECTION_LOST:
563
+ self._loop.call_soon(self._protocol.connection_lost, None)
564
+
565
+ cdef _try_finish(self):
566
+ if self._returncode is None or self._finished:
567
+ return
568
+
569
+ if ((self.stdin_proto is None or self.stdin_proto.disconnected) and
570
+ (self.stdout_proto is None or
571
+ self.stdout_proto.disconnected) and
572
+ (self.stderr_proto is None or
573
+ self.stderr_proto.disconnected)):
574
+
575
+ self._finished = 1
576
+
577
+ if self._stdio_ready:
578
+ # copy self.context for simplicity
579
+ self._loop.call_soon(self._protocol.connection_lost, None,
580
+ context=self.context)
581
+ else:
582
+ self._pending_calls.append((_CALL_CONNECTION_LOST, None, None))
583
+
584
+ def __stdio_inited(self, waiter, stdio_fut):
585
+ exc = stdio_fut.exception()
586
+ if exc is not None:
587
+ if waiter is None:
588
+ raise exc
589
+ else:
590
+ waiter.set_exception(exc)
591
+ else:
592
+ self._loop._call_soon_handle(
593
+ new_MethodHandle1(self._loop,
594
+ "UVProcessTransport._call_connection_made",
595
+ <method1_t>self._call_connection_made,
596
+ None, # means to copy the current context
597
+ self, waiter))
598
+
599
+ @staticmethod
600
+ cdef UVProcessTransport new(Loop loop, protocol, args, env,
601
+ cwd, start_new_session,
602
+ _stdin, _stdout, _stderr, pass_fds,
603
+ waiter,
604
+ debug_flags,
605
+ preexec_fn,
606
+ restore_signals):
607
+
608
+ cdef UVProcessTransport handle
609
+ handle = UVProcessTransport.__new__(UVProcessTransport)
610
+ handle._protocol = protocol
611
+ handle._init(loop, args, env, cwd, start_new_session,
612
+ __process_convert_fileno(_stdin),
613
+ __process_convert_fileno(_stdout),
614
+ __process_convert_fileno(_stderr),
615
+ pass_fds,
616
+ debug_flags,
617
+ preexec_fn,
618
+ restore_signals)
619
+
620
+ if handle._init_futs:
621
+ handle._stdio_ready = 0
622
+ init_fut = aio_gather(*handle._init_futs)
623
+ # add_done_callback will copy the current context and run the
624
+ # callback within the context
625
+ init_fut.add_done_callback(
626
+ ft_partial(handle.__stdio_inited, waiter))
627
+ else:
628
+ handle._stdio_ready = 1
629
+ loop._call_soon_handle(
630
+ new_MethodHandle1(loop,
631
+ "UVProcessTransport._call_connection_made",
632
+ <method1_t>handle._call_connection_made,
633
+ None, # means to copy the current context
634
+ handle, waiter))
635
+
636
+ return handle
637
+
638
+ def get_protocol(self):
639
+ return self._protocol
640
+
641
+ def set_protocol(self, protocol):
642
+ self._protocol = protocol
643
+
644
+ def get_pid(self):
645
+ return self._pid
646
+
647
+ def get_returncode(self):
648
+ return self._returncode
649
+
650
+ def get_pipe_transport(self, fd):
651
+ if fd == 0:
652
+ return self._stdin
653
+ elif fd == 1:
654
+ return self._stdout
655
+ elif fd == 2:
656
+ return self._stderr
657
+
658
+ def terminate(self):
659
+ self._check_proc()
660
+ self._kill(uv.SIGTERM)
661
+
662
+ def kill(self):
663
+ self._check_proc()
664
+ self._kill(uv.SIGKILL)
665
+
666
+ def send_signal(self, int signal):
667
+ self._check_proc()
668
+ self._kill(signal)
669
+
670
+ def is_closing(self):
671
+ return self._closed
672
+
673
+ def close(self):
674
+ if self._returncode is None:
675
+ self._kill(uv.SIGKILL)
676
+
677
+ if self._stdin is not None:
678
+ self._stdin.close()
679
+ if self._stdout is not None:
680
+ self._stdout.close()
681
+ if self._stderr is not None:
682
+ self._stderr.close()
683
+
684
+ if self._returncode is not None:
685
+ # The process is dead, just close the UV handle.
686
+ #
687
+ # (If "self._returncode is None", the process should have been
688
+ # killed already and we're just waiting for a SIGCHLD; after
689
+ # which the transport will be GC'ed and the uvhandle will be
690
+ # closed in UVHandle.__dealloc__.)
691
+ self._close()
692
+
693
+ def get_extra_info(self, name, default=None):
694
+ return default
695
+
696
+ def _wait(self):
697
+ fut = self._loop._new_future()
698
+ if self._returncode is not None:
699
+ fut.set_result(self._returncode)
700
+ return fut
701
+
702
+ self._exit_waiters.append(fut)
703
+ return fut
704
+
705
+
706
+ class WriteSubprocessPipeProto(aio_BaseProtocol):
707
+
708
+ def __init__(self, proc, fd):
709
+ if UVLOOP_DEBUG:
710
+ if type(proc) is not UVProcessTransport:
711
+ raise TypeError
712
+ if not isinstance(fd, int):
713
+ raise TypeError
714
+ self.proc = proc
715
+ self.fd = fd
716
+ self.pipe = None
717
+ self.disconnected = False
718
+
719
+ def connection_made(self, transport):
720
+ self.pipe = transport
721
+
722
+ def __repr__(self):
723
+ return ('<%s fd=%s pipe=%r>'
724
+ % (self.__class__.__name__, self.fd, self.pipe))
725
+
726
+ def connection_lost(self, exc):
727
+ self.disconnected = True
728
+ (<UVProcessTransport>self.proc)._pipe_connection_lost(self.fd, exc)
729
+ self.proc = None
730
+
731
+ def pause_writing(self):
732
+ (<UVProcessTransport>self.proc)._protocol.pause_writing()
733
+
734
+ def resume_writing(self):
735
+ (<UVProcessTransport>self.proc)._protocol.resume_writing()
736
+
737
+
738
+ class ReadSubprocessPipeProto(WriteSubprocessPipeProto,
739
+ aio_Protocol):
740
+
741
+ def data_received(self, data):
742
+ (<UVProcessTransport>self.proc)._pipe_data_received(self.fd, data)
743
+
744
+
745
+ cdef __process_convert_fileno(object obj):
746
+ if obj is None or isinstance(obj, int):
747
+ return obj
748
+
749
+ fileno = obj.fileno()
750
+ if not isinstance(fileno, int):
751
+ raise TypeError(
752
+ '{!r}.fileno() returned non-integer'.format(obj))
753
+ return fileno
754
+
755
+
756
+ cdef void __uvprocess_on_exit_callback(
757
+ uv.uv_process_t *handle,
758
+ int64_t exit_status,
759
+ int term_signal,
760
+ ) noexcept with gil:
761
+
762
+ if __ensure_handle_data(<uv.uv_handle_t*>handle,
763
+ "UVProcess exit callback") == 0:
764
+ return
765
+
766
+ cdef UVProcess proc = <UVProcess> handle.data
767
+ try:
768
+ proc._on_exit(exit_status, term_signal)
769
+ except BaseException as ex:
770
+ proc._error(ex, False)
771
+
772
+
773
+ cdef __socketpair():
774
+ cdef:
775
+ int fds[2]
776
+ int err
777
+
778
+ err = system.socketpair(uv.AF_UNIX, uv.SOCK_STREAM, 0, fds)
779
+ if err:
780
+ exc = convert_error(-err)
781
+ raise exc
782
+
783
+ os_set_inheritable(fds[0], False)
784
+ os_set_inheritable(fds[1], False)
785
+
786
+ return fds[0], fds[1]
787
+
788
+
789
+ cdef void __uv_close_process_handle_cb(
790
+ uv.uv_handle_t* handle
791
+ ) noexcept with gil:
792
+ PyMem_RawFree(handle)
.venv/lib/python3.11/site-packages/uvloop/handles/stream.pxd ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVStream(UVBaseTransport):
2
+ cdef:
3
+ uv.uv_shutdown_t _shutdown_req
4
+ bint __shutting_down
5
+ bint __reading
6
+ bint __read_error_close
7
+
8
+ bint __buffered
9
+ object _protocol_get_buffer
10
+ object _protocol_buffer_updated
11
+
12
+ bint _eof
13
+ list _buffer
14
+ size_t _buffer_size
15
+
16
+ Py_buffer _read_pybuf
17
+ bint _read_pybuf_acquired
18
+
19
+ # All "inline" methods are final
20
+
21
+ cdef inline _init(self, Loop loop, object protocol, Server server,
22
+ object waiter, object context)
23
+
24
+
25
+ cdef inline _shutdown(self)
26
+ cdef inline _accept(self, UVStream server)
27
+
28
+ cdef inline _close_on_read_error(self)
29
+
30
+ cdef inline __reading_started(self)
31
+ cdef inline __reading_stopped(self)
32
+
33
+ # The user API write() and writelines() firstly call _buffer_write() to
34
+ # buffer up user data chunks, potentially multiple times in writelines(),
35
+ # and then call _initiate_write() to start writing either immediately or in
36
+ # the next iteration (loop._queue_write()).
37
+ cdef inline _buffer_write(self, object data)
38
+ cdef inline _initiate_write(self)
39
+
40
+ # _exec_write() is the method that does the actual send, and _try_write()
41
+ # is a fast-path used in _exec_write() to send a single chunk.
42
+ cdef inline _exec_write(self)
43
+ cdef inline _try_write(self, object data)
44
+
45
+ cdef _close(self)
46
+
47
+ cdef inline _on_accept(self)
48
+ cdef inline _on_eof(self)
49
+ cdef inline _on_write(self)
50
+ cdef inline _on_connect(self, object exc)
.venv/lib/python3.11/site-packages/uvloop/handles/stream.pyx ADDED
@@ -0,0 +1,1019 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef extern from *:
2
+ '''
3
+ enum {__PREALLOCED_BUFS = 4};
4
+ '''
5
+ const bint __PREALLOCED_BUFS
6
+
7
+
8
+ @cython.no_gc_clear
9
+ @cython.freelist(DEFAULT_FREELIST_SIZE)
10
+ cdef class _StreamWriteContext:
11
+ # used to hold additional write request information for uv_write
12
+
13
+ cdef:
14
+ uv.uv_write_t req
15
+
16
+ list buffers
17
+
18
+ uv.uv_buf_t uv_bufs_sml[__PREALLOCED_BUFS]
19
+ Py_buffer py_bufs_sml[__PREALLOCED_BUFS]
20
+ bint py_bufs_sml_inuse
21
+
22
+ uv.uv_buf_t* uv_bufs
23
+ Py_buffer* py_bufs
24
+ size_t py_bufs_len
25
+
26
+ uv.uv_buf_t* uv_bufs_start
27
+ size_t uv_bufs_len
28
+
29
+ UVStream stream
30
+
31
+ bint closed
32
+
33
+ cdef free_bufs(self):
34
+ cdef size_t i
35
+
36
+ if self.uv_bufs is not NULL:
37
+ PyMem_RawFree(self.uv_bufs)
38
+ self.uv_bufs = NULL
39
+ if UVLOOP_DEBUG:
40
+ if self.py_bufs_sml_inuse:
41
+ raise RuntimeError(
42
+ '_StreamWriteContext.close: uv_bufs != NULL and '
43
+ 'py_bufs_sml_inuse is True')
44
+
45
+ if self.py_bufs is not NULL:
46
+ for i from 0 <= i < self.py_bufs_len:
47
+ PyBuffer_Release(&self.py_bufs[i])
48
+ PyMem_RawFree(self.py_bufs)
49
+ self.py_bufs = NULL
50
+ if UVLOOP_DEBUG:
51
+ if self.py_bufs_sml_inuse:
52
+ raise RuntimeError(
53
+ '_StreamWriteContext.close: py_bufs != NULL and '
54
+ 'py_bufs_sml_inuse is True')
55
+
56
+ if self.py_bufs_sml_inuse:
57
+ for i from 0 <= i < self.py_bufs_len:
58
+ PyBuffer_Release(&self.py_bufs_sml[i])
59
+ self.py_bufs_sml_inuse = 0
60
+
61
+ self.py_bufs_len = 0
62
+ self.buffers = None
63
+
64
+ cdef close(self):
65
+ if self.closed:
66
+ return
67
+ self.closed = 1
68
+ self.free_bufs()
69
+ Py_DECREF(self)
70
+
71
+ cdef advance_uv_buf(self, size_t sent):
72
+ # Advance the pointer to first uv_buf and the
73
+ # pointer to first byte in that buffer.
74
+ #
75
+ # We do this after a "uv_try_write" call, which
76
+ # sometimes sends only a portion of data.
77
+ # We then call "advance_uv_buf" on the write
78
+ # context, and reuse it in a "uv_write" call.
79
+
80
+ cdef:
81
+ uv.uv_buf_t* buf
82
+ size_t idx
83
+
84
+ for idx from 0 <= idx < self.uv_bufs_len:
85
+ buf = &self.uv_bufs_start[idx]
86
+ if buf.len > sent:
87
+ buf.len -= sent
88
+ buf.base = buf.base + sent
89
+ self.uv_bufs_start = buf
90
+ self.uv_bufs_len -= idx
91
+ return
92
+ else:
93
+ sent -= self.uv_bufs_start[idx].len
94
+
95
+ if UVLOOP_DEBUG:
96
+ if sent < 0:
97
+ raise RuntimeError('fatal: sent < 0 in advance_uv_buf')
98
+
99
+ raise RuntimeError('fatal: Could not advance _StreamWriteContext')
100
+
101
+ @staticmethod
102
+ cdef _StreamWriteContext new(UVStream stream, list buffers):
103
+ cdef:
104
+ _StreamWriteContext ctx
105
+ int uv_bufs_idx = 0
106
+ size_t py_bufs_len = 0
107
+ int i
108
+
109
+ Py_buffer* p_pybufs
110
+ uv.uv_buf_t* p_uvbufs
111
+
112
+ ctx = _StreamWriteContext.__new__(_StreamWriteContext)
113
+ ctx.stream = None
114
+ ctx.closed = 1
115
+ ctx.py_bufs_len = 0
116
+ ctx.py_bufs_sml_inuse = 0
117
+ ctx.uv_bufs = NULL
118
+ ctx.py_bufs = NULL
119
+ ctx.buffers = buffers
120
+ ctx.stream = stream
121
+
122
+ if len(buffers) <= __PREALLOCED_BUFS:
123
+ # We've got a small number of buffers to write, don't
124
+ # need to use malloc.
125
+ ctx.py_bufs_sml_inuse = 1
126
+ p_pybufs = <Py_buffer*>&ctx.py_bufs_sml
127
+ p_uvbufs = <uv.uv_buf_t*>&ctx.uv_bufs_sml
128
+
129
+ else:
130
+ for buf in buffers:
131
+ if UVLOOP_DEBUG:
132
+ if not isinstance(buf, (bytes, bytearray, memoryview)):
133
+ raise RuntimeError(
134
+ 'invalid data in writebuf: an instance of '
135
+ 'bytes, bytearray or memoryview was expected, '
136
+ 'got {}'.format(type(buf)))
137
+
138
+ if not PyBytes_CheckExact(buf):
139
+ py_bufs_len += 1
140
+
141
+ if py_bufs_len > 0:
142
+ ctx.py_bufs = <Py_buffer*>PyMem_RawMalloc(
143
+ py_bufs_len * sizeof(Py_buffer))
144
+ if ctx.py_bufs is NULL:
145
+ raise MemoryError()
146
+
147
+ ctx.uv_bufs = <uv.uv_buf_t*>PyMem_RawMalloc(
148
+ len(buffers) * sizeof(uv.uv_buf_t))
149
+ if ctx.uv_bufs is NULL:
150
+ raise MemoryError()
151
+
152
+ p_pybufs = ctx.py_bufs
153
+ p_uvbufs = ctx.uv_bufs
154
+
155
+ py_bufs_len = 0
156
+ for buf in buffers:
157
+ if PyBytes_CheckExact(buf):
158
+ # We can only use this hack for bytes since it's
159
+ # immutable. For everything else it is only safe to
160
+ # use buffer protocol.
161
+ p_uvbufs[uv_bufs_idx].base = PyBytes_AS_STRING(buf)
162
+ p_uvbufs[uv_bufs_idx].len = Py_SIZE(buf)
163
+
164
+ else:
165
+ try:
166
+ PyObject_GetBuffer(
167
+ buf, &p_pybufs[py_bufs_len], PyBUF_SIMPLE)
168
+ except Exception:
169
+ # This shouldn't ever happen, as `UVStream._buffer_write`
170
+ # casts non-bytes objects to `memoryviews`.
171
+ ctx.py_bufs_len = py_bufs_len
172
+ ctx.free_bufs()
173
+ raise
174
+
175
+ p_uvbufs[uv_bufs_idx].base = <char*>p_pybufs[py_bufs_len].buf
176
+ p_uvbufs[uv_bufs_idx].len = p_pybufs[py_bufs_len].len
177
+
178
+ py_bufs_len += 1
179
+
180
+ uv_bufs_idx += 1
181
+
182
+ ctx.uv_bufs_start = p_uvbufs
183
+ ctx.uv_bufs_len = uv_bufs_idx
184
+
185
+ ctx.py_bufs_len = py_bufs_len
186
+ ctx.req.data = <void*> ctx
187
+
188
+ if UVLOOP_DEBUG:
189
+ stream._loop._debug_stream_write_ctx_total += 1
190
+ stream._loop._debug_stream_write_ctx_cnt += 1
191
+
192
+ # Do incref after everything else is done.
193
+ # Under no circumstances we want `ctx` to be GCed while
194
+ # libuv is still working with `ctx.uv_bufs`.
195
+ Py_INCREF(ctx)
196
+ ctx.closed = 0
197
+ return ctx
198
+
199
+ def __dealloc__(self):
200
+ if not self.closed:
201
+ # Because we do an INCREF in _StreamWriteContext.new,
202
+ # __dealloc__ shouldn't ever happen with `self.closed == 1`
203
+ raise RuntimeError(
204
+ 'open _StreamWriteContext is being deallocated')
205
+
206
+ if UVLOOP_DEBUG:
207
+ if self.stream is not None:
208
+ self.stream._loop._debug_stream_write_ctx_cnt -= 1
209
+ self.stream = None
210
+
211
+
212
+ @cython.no_gc_clear
213
+ cdef class UVStream(UVBaseTransport):
214
+
215
+ def __cinit__(self):
216
+ self.__shutting_down = 0
217
+ self.__reading = 0
218
+ self.__read_error_close = 0
219
+ self.__buffered = 0
220
+ self._eof = 0
221
+ self._buffer = []
222
+ self._buffer_size = 0
223
+
224
+ self._protocol_get_buffer = None
225
+ self._protocol_buffer_updated = None
226
+
227
+ self._read_pybuf_acquired = False
228
+
229
+ cdef _set_protocol(self, object protocol):
230
+ if protocol is None:
231
+ raise TypeError('protocol is required')
232
+
233
+ UVBaseTransport._set_protocol(self, protocol)
234
+
235
+ if (hasattr(protocol, 'get_buffer') and
236
+ not isinstance(protocol, aio_Protocol)):
237
+ try:
238
+ self._protocol_get_buffer = protocol.get_buffer
239
+ self._protocol_buffer_updated = protocol.buffer_updated
240
+ self.__buffered = 1
241
+ except AttributeError:
242
+ pass
243
+ else:
244
+ self.__buffered = 0
245
+
246
+ cdef _clear_protocol(self):
247
+ UVBaseTransport._clear_protocol(self)
248
+ self._protocol_get_buffer = None
249
+ self._protocol_buffer_updated = None
250
+ self.__buffered = 0
251
+
252
+ cdef inline _shutdown(self):
253
+ cdef int err
254
+
255
+ if self.__shutting_down:
256
+ return
257
+ self.__shutting_down = 1
258
+
259
+ self._ensure_alive()
260
+
261
+ self._shutdown_req.data = <void*> self
262
+ err = uv.uv_shutdown(&self._shutdown_req,
263
+ <uv.uv_stream_t*> self._handle,
264
+ __uv_stream_on_shutdown)
265
+ if err < 0:
266
+ exc = convert_error(err)
267
+ self._fatal_error(exc, True)
268
+ return
269
+
270
+ cdef inline _accept(self, UVStream server):
271
+ cdef int err
272
+ self._ensure_alive()
273
+
274
+ err = uv.uv_accept(<uv.uv_stream_t*>server._handle,
275
+ <uv.uv_stream_t*>self._handle)
276
+ if err < 0:
277
+ exc = convert_error(err)
278
+ self._fatal_error(exc, True)
279
+ return
280
+
281
+ self._on_accept()
282
+
283
+ cdef inline _close_on_read_error(self):
284
+ self.__read_error_close = 1
285
+
286
+ cdef bint _is_reading(self):
287
+ return self.__reading
288
+
289
+ cdef _start_reading(self):
290
+ cdef int err
291
+
292
+ if self._closing:
293
+ return
294
+
295
+ self._ensure_alive()
296
+
297
+ if self.__reading:
298
+ return
299
+
300
+ if self.__buffered:
301
+ err = uv.uv_read_start(<uv.uv_stream_t*>self._handle,
302
+ __uv_stream_buffered_alloc,
303
+ __uv_stream_buffered_on_read)
304
+ else:
305
+ err = uv.uv_read_start(<uv.uv_stream_t*>self._handle,
306
+ __loop_alloc_buffer,
307
+ __uv_stream_on_read)
308
+ if err < 0:
309
+ exc = convert_error(err)
310
+ self._fatal_error(exc, True)
311
+ return
312
+ else:
313
+ # UVStream must live until the read callback is called
314
+ self.__reading_started()
315
+
316
+ cdef inline __reading_started(self):
317
+ if self.__reading:
318
+ return
319
+ self.__reading = 1
320
+ Py_INCREF(self)
321
+
322
+ cdef inline __reading_stopped(self):
323
+ if not self.__reading:
324
+ return
325
+ self.__reading = 0
326
+ Py_DECREF(self)
327
+
328
+ cdef _stop_reading(self):
329
+ cdef int err
330
+
331
+ if not self.__reading:
332
+ return
333
+
334
+ self._ensure_alive()
335
+
336
+ # From libuv docs:
337
+ # This function is idempotent and may be safely
338
+ # called on a stopped stream.
339
+ err = uv.uv_read_stop(<uv.uv_stream_t*>self._handle)
340
+ if err < 0:
341
+ exc = convert_error(err)
342
+ self._fatal_error(exc, True)
343
+ return
344
+ else:
345
+ self.__reading_stopped()
346
+
347
+ cdef inline _try_write(self, object data):
348
+ cdef:
349
+ ssize_t written
350
+ bint used_buf = 0
351
+ Py_buffer py_buf
352
+ void* buf
353
+ size_t blen
354
+ int saved_errno
355
+ int fd
356
+
357
+ if (<uv.uv_stream_t*>self._handle).write_queue_size != 0:
358
+ raise RuntimeError(
359
+ 'UVStream._try_write called with data in uv buffers')
360
+
361
+ if PyBytes_CheckExact(data):
362
+ # We can only use this hack for bytes since it's
363
+ # immutable. For everything else it is only safe to
364
+ # use buffer protocol.
365
+ buf = <void*>PyBytes_AS_STRING(data)
366
+ blen = Py_SIZE(data)
367
+ else:
368
+ PyObject_GetBuffer(data, &py_buf, PyBUF_SIMPLE)
369
+ used_buf = 1
370
+ buf = py_buf.buf
371
+ blen = py_buf.len
372
+
373
+ if blen == 0:
374
+ # Empty data, do nothing.
375
+ return 0
376
+
377
+ fd = self._fileno()
378
+ # Use `unistd.h/write` directly, it's faster than
379
+ # uv_try_write -- less layers of code. The error
380
+ # checking logic is copied from libuv.
381
+ written = system.write(fd, buf, blen)
382
+ while written == -1 and (
383
+ errno.errno == errno.EINTR or
384
+ (system.PLATFORM_IS_APPLE and
385
+ errno.errno == errno.EPROTOTYPE)):
386
+ # From libuv code (unix/stream.c):
387
+ # Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
388
+ # EPROTOTYPE can be returned while trying to write to a socket
389
+ # that is shutting down. If we retry the write, we should get
390
+ # the expected EPIPE instead.
391
+ written = system.write(fd, buf, blen)
392
+ saved_errno = errno.errno
393
+
394
+ if used_buf:
395
+ PyBuffer_Release(&py_buf)
396
+
397
+ if written < 0:
398
+ if saved_errno == errno.EAGAIN or \
399
+ saved_errno == system.EWOULDBLOCK:
400
+ return -1
401
+ else:
402
+ exc = convert_error(-saved_errno)
403
+ self._fatal_error(exc, True)
404
+ return
405
+
406
+ if UVLOOP_DEBUG:
407
+ self._loop._debug_stream_write_tries += 1
408
+
409
+ if <size_t>written == blen:
410
+ return 0
411
+
412
+ return written
413
+
414
+ cdef inline _buffer_write(self, object data):
415
+ cdef int dlen
416
+
417
+ if not PyBytes_CheckExact(data):
418
+ data = memoryview(data).cast('b')
419
+
420
+ dlen = len(data)
421
+ if not dlen:
422
+ return
423
+
424
+ self._buffer_size += dlen
425
+ self._buffer.append(data)
426
+
427
+ cdef inline _initiate_write(self):
428
+ if (not self._protocol_paused and
429
+ (<uv.uv_stream_t*>self._handle).write_queue_size == 0 and
430
+ self._buffer_size > self._high_water):
431
+ # Fast-path. If:
432
+ # - the protocol isn't yet paused,
433
+ # - there is no data in libuv buffers for this stream,
434
+ # - the protocol will be paused if we continue to buffer data
435
+ #
436
+ # Then:
437
+ # - Try to write all buffered data right now.
438
+ all_sent = self._exec_write()
439
+ if UVLOOP_DEBUG:
440
+ if self._buffer_size != 0 or self._buffer != []:
441
+ raise RuntimeError(
442
+ '_buffer_size is not 0 after a successful _exec_write')
443
+
444
+ # There is no need to call `_queue_write` anymore,
445
+ # as `uv_write` should be called already.
446
+
447
+ if not all_sent:
448
+ # If not all of the data was sent successfully,
449
+ # we might need to pause the protocol.
450
+ self._maybe_pause_protocol()
451
+
452
+ elif self._buffer_size > 0:
453
+ self._maybe_pause_protocol()
454
+ self._loop._queue_write(self)
455
+
456
+ cdef inline _exec_write(self):
457
+ cdef:
458
+ int err
459
+ int buf_len
460
+ _StreamWriteContext ctx = None
461
+
462
+ if self._closed:
463
+ # If the handle is closed, just return, it's too
464
+ # late to do anything.
465
+ return
466
+
467
+ buf_len = len(self._buffer)
468
+ if not buf_len:
469
+ return
470
+
471
+ if (<uv.uv_stream_t*>self._handle).write_queue_size == 0:
472
+ # libuv internal write buffers for this stream are empty.
473
+ if buf_len == 1:
474
+ # If we only have one piece of data to send, let's
475
+ # use our fast implementation of try_write.
476
+ data = self._buffer[0]
477
+ sent = self._try_write(data)
478
+
479
+ if sent is None:
480
+ # A `self._fatal_error` was called.
481
+ # It might not raise an exception under some
482
+ # conditions.
483
+ self._buffer_size = 0
484
+ self._buffer.clear()
485
+ if not self._closing:
486
+ # This should never happen.
487
+ raise RuntimeError(
488
+ 'stream is open after UVStream._try_write '
489
+ 'returned None')
490
+ return
491
+
492
+ if sent == 0:
493
+ # All data was successfully written.
494
+ self._buffer_size = 0
495
+ self._buffer.clear()
496
+ # on_write will call "maybe_resume_protocol".
497
+ self._on_write()
498
+ return True
499
+
500
+ if sent > 0:
501
+ if UVLOOP_DEBUG:
502
+ if sent == len(data):
503
+ raise RuntimeError(
504
+ '_try_write sent all data and returned '
505
+ 'non-zero')
506
+
507
+ if PyBytes_CheckExact(data):
508
+ # Cast bytes to memoryview to avoid copying
509
+ # data that wasn't sent.
510
+ data = memoryview(data)
511
+ data = data[sent:]
512
+
513
+ self._buffer_size -= sent
514
+ self._buffer[0] = data
515
+
516
+ # At this point it's either data was sent partially,
517
+ # or an EAGAIN has happened.
518
+
519
+ else:
520
+ ctx = _StreamWriteContext.new(self, self._buffer)
521
+
522
+ err = uv.uv_try_write(<uv.uv_stream_t*>self._handle,
523
+ ctx.uv_bufs_start,
524
+ ctx.uv_bufs_len)
525
+
526
+ if err > 0:
527
+ # Some data was successfully sent.
528
+
529
+ if <size_t>err == self._buffer_size:
530
+ # Everything was sent.
531
+ ctx.close()
532
+ self._buffer.clear()
533
+ self._buffer_size = 0
534
+ # on_write will call "maybe_resume_protocol".
535
+ self._on_write()
536
+ return True
537
+
538
+ try:
539
+ # Advance pointers to uv_bufs in `ctx`,
540
+ # we will reuse it soon for a uv_write
541
+ # call.
542
+ ctx.advance_uv_buf(<ssize_t>err)
543
+ except Exception as ex: # This should never happen.
544
+ # Let's try to close the `ctx` anyways.
545
+ ctx.close()
546
+ self._fatal_error(ex, True)
547
+ self._buffer.clear()
548
+ self._buffer_size = 0
549
+ return
550
+
551
+ elif err != uv.UV_EAGAIN:
552
+ ctx.close()
553
+ exc = convert_error(err)
554
+ self._fatal_error(exc, True)
555
+ self._buffer.clear()
556
+ self._buffer_size = 0
557
+ return
558
+
559
+ # fall through
560
+
561
+ if ctx is None:
562
+ ctx = _StreamWriteContext.new(self, self._buffer)
563
+
564
+ err = uv.uv_write(&ctx.req,
565
+ <uv.uv_stream_t*>self._handle,
566
+ ctx.uv_bufs_start,
567
+ ctx.uv_bufs_len,
568
+ __uv_stream_on_write)
569
+
570
+ self._buffer_size = 0
571
+ # Can't use `_buffer.clear()` here: `ctx` holds a reference to
572
+ # the `_buffer`.
573
+ self._buffer = []
574
+
575
+ if err < 0:
576
+ # close write context
577
+ ctx.close()
578
+
579
+ exc = convert_error(err)
580
+ self._fatal_error(exc, True)
581
+ return
582
+
583
+ self._maybe_resume_protocol()
584
+
585
+ cdef size_t _get_write_buffer_size(self):
586
+ if self._handle is NULL:
587
+ return 0
588
+ return ((<uv.uv_stream_t*>self._handle).write_queue_size +
589
+ self._buffer_size)
590
+
591
+ cdef _close(self):
592
+ try:
593
+ if self._read_pybuf_acquired:
594
+ # Should never happen. libuv always calls uv_alloc/uv_read
595
+ # in pairs.
596
+ self._loop.call_exception_handler({
597
+ 'transport': self,
598
+ 'message': 'XXX: an allocated buffer in transport._close()'
599
+ })
600
+ self._read_pybuf_acquired = 0
601
+ PyBuffer_Release(&self._read_pybuf)
602
+
603
+ self._stop_reading()
604
+ finally:
605
+ UVSocketHandle._close(<UVHandle>self)
606
+
607
+ cdef inline _on_accept(self):
608
+ # Ultimately called by __uv_stream_on_listen.
609
+ self._init_protocol()
610
+
611
+ cdef inline _on_eof(self):
612
+ # Any exception raised here will be caught in
613
+ # __uv_stream_on_read.
614
+
615
+ try:
616
+ meth = self._protocol.eof_received
617
+ except AttributeError:
618
+ keep_open = False
619
+ else:
620
+ keep_open = run_in_context(self.context, meth)
621
+
622
+ if keep_open:
623
+ # We're keeping the connection open so the
624
+ # protocol can write more, but we still can't
625
+ # receive more, so remove the reader callback.
626
+ self._stop_reading()
627
+ else:
628
+ self.close()
629
+
630
+ cdef inline _on_write(self):
631
+ self._maybe_resume_protocol()
632
+ if not self._get_write_buffer_size():
633
+ if self._closing:
634
+ self._schedule_call_connection_lost(None)
635
+ elif self._eof:
636
+ self._shutdown()
637
+
638
+ cdef inline _init(self, Loop loop, object protocol, Server server,
639
+ object waiter, object context):
640
+ self.context = context
641
+ self._set_protocol(protocol)
642
+ self._start_init(loop)
643
+
644
+ if server is not None:
645
+ self._set_server(server)
646
+
647
+ if waiter is not None:
648
+ self._set_waiter(waiter)
649
+
650
+ cdef inline _on_connect(self, object exc):
651
+ # Called from __tcp_connect_callback (tcp.pyx) and
652
+ # __pipe_connect_callback (pipe.pyx).
653
+ if exc is None:
654
+ self._init_protocol()
655
+ else:
656
+ if self._waiter is None:
657
+ self._fatal_error(exc, False, "connect failed")
658
+ elif self._waiter.cancelled():
659
+ # Connect call was cancelled; just close the transport
660
+ # silently.
661
+ self._close()
662
+ elif self._waiter.done():
663
+ self._fatal_error(exc, False, "connect failed")
664
+ else:
665
+ self._waiter.set_exception(exc)
666
+ self._close()
667
+
668
+ # === Public API ===
669
+
670
+ def __repr__(self):
671
+ return '<{} closed={} reading={} {:#x}>'.format(
672
+ self.__class__.__name__,
673
+ self._closed,
674
+ self.__reading,
675
+ id(self))
676
+
677
+ def write(self, object buf):
678
+ self._ensure_alive()
679
+
680
+ if self._eof:
681
+ raise RuntimeError('Cannot call write() after write_eof()')
682
+ if not buf:
683
+ return
684
+ if self._conn_lost:
685
+ self._conn_lost += 1
686
+ return
687
+ self._buffer_write(buf)
688
+ self._initiate_write()
689
+
690
+ def writelines(self, bufs):
691
+ self._ensure_alive()
692
+
693
+ if self._eof:
694
+ raise RuntimeError('Cannot call writelines() after write_eof()')
695
+ if self._conn_lost:
696
+ self._conn_lost += 1
697
+ return
698
+ for buf in bufs:
699
+ self._buffer_write(buf)
700
+ self._initiate_write()
701
+
702
+ def write_eof(self):
703
+ self._ensure_alive()
704
+
705
+ if self._eof:
706
+ return
707
+
708
+ self._eof = 1
709
+ if not self._get_write_buffer_size():
710
+ self._shutdown()
711
+
712
+ def can_write_eof(self):
713
+ return True
714
+
715
+ def is_reading(self):
716
+ return self._is_reading()
717
+
718
+ def pause_reading(self):
719
+ if self._closing or not self._is_reading():
720
+ return
721
+ self._stop_reading()
722
+
723
+ def resume_reading(self):
724
+ if self._is_reading() or self._closing:
725
+ return
726
+ self._start_reading()
727
+
728
+
729
+ cdef void __uv_stream_on_shutdown(uv.uv_shutdown_t* req,
730
+ int status) noexcept with gil:
731
+
732
+ # callback for uv_shutdown
733
+
734
+ if req.data is NULL:
735
+ aio_logger.error(
736
+ 'UVStream.shutdown callback called with NULL req.data, status=%r',
737
+ status)
738
+ return
739
+
740
+ cdef UVStream stream = <UVStream> req.data
741
+
742
+ if status < 0 and status != uv.UV_ECANCELED:
743
+ # From libuv source code:
744
+ # The ECANCELED error code is a lie, the shutdown(2) syscall is a
745
+ # fait accompli at this point. Maybe we should revisit this in
746
+ # v0.11. A possible reason for leaving it unchanged is that it
747
+ # informs the callee that the handle has been destroyed.
748
+
749
+ if UVLOOP_DEBUG:
750
+ stream._loop._debug_stream_shutdown_errors_total += 1
751
+
752
+ exc = convert_error(status)
753
+ stream._fatal_error(
754
+ exc, False, "error status in uv_stream_t.shutdown callback")
755
+ return
756
+
757
+
758
+ cdef inline bint __uv_stream_on_read_common(
759
+ UVStream sc,
760
+ Loop loop,
761
+ ssize_t nread,
762
+ ):
763
+ if sc._closed:
764
+ # The stream was closed, there is no reason to
765
+ # do any work now.
766
+ sc.__reading_stopped() # Just in case.
767
+ return True
768
+
769
+ if nread == uv.UV_EOF:
770
+ # From libuv docs:
771
+ # The callee is responsible for stopping closing the stream
772
+ # when an error happens by calling uv_read_stop() or uv_close().
773
+ # Trying to read from the stream again is undefined.
774
+ try:
775
+ if UVLOOP_DEBUG:
776
+ loop._debug_stream_read_eof_total += 1
777
+
778
+ sc._stop_reading()
779
+ sc._on_eof()
780
+ except BaseException as ex:
781
+ if UVLOOP_DEBUG:
782
+ loop._debug_stream_read_eof_cb_errors_total += 1
783
+
784
+ sc._fatal_error(ex, False)
785
+ finally:
786
+ return True
787
+
788
+ if nread == 0:
789
+ # From libuv docs:
790
+ # nread might be 0, which does not indicate an error or EOF.
791
+ # This is equivalent to EAGAIN or EWOULDBLOCK under read(2).
792
+ return True
793
+
794
+ if nread < 0:
795
+ # From libuv docs:
796
+ # The callee is responsible for stopping closing the stream
797
+ # when an error happens by calling uv_read_stop() or uv_close().
798
+ # Trying to read from the stream again is undefined.
799
+ #
800
+ # Therefore, we're closing the stream. Since "UVHandle._close()"
801
+ # doesn't raise exceptions unless uvloop is built with DEBUG=1,
802
+ # we don't need try...finally here.
803
+
804
+ if UVLOOP_DEBUG:
805
+ loop._debug_stream_read_errors_total += 1
806
+
807
+ if sc.__read_error_close:
808
+ # Used for getting notified when a pipe is closed.
809
+ # See WriteUnixTransport for the explanation.
810
+ sc._on_eof()
811
+ return True
812
+
813
+ exc = convert_error(nread)
814
+ sc._fatal_error(
815
+ exc, False, "error status in uv_stream_t.read callback")
816
+ return True
817
+
818
+ return False
819
+
820
+
821
+ cdef inline void __uv_stream_on_read_impl(
822
+ uv.uv_stream_t* stream,
823
+ ssize_t nread,
824
+ const uv.uv_buf_t* buf,
825
+ ):
826
+ cdef:
827
+ UVStream sc = <UVStream>stream.data
828
+ Loop loop = sc._loop
829
+
830
+ # It's OK to free the buffer early, since nothing will
831
+ # be able to touch it until this method is done.
832
+ __loop_free_buffer(loop)
833
+
834
+ if __uv_stream_on_read_common(sc, loop, nread):
835
+ return
836
+
837
+ try:
838
+ if UVLOOP_DEBUG:
839
+ loop._debug_stream_read_cb_total += 1
840
+
841
+ run_in_context1(
842
+ sc.context,
843
+ sc._protocol_data_received,
844
+ loop._recv_buffer[:nread],
845
+ )
846
+ except BaseException as exc:
847
+ if UVLOOP_DEBUG:
848
+ loop._debug_stream_read_cb_errors_total += 1
849
+
850
+ sc._fatal_error(exc, False)
851
+
852
+
853
+ cdef inline void __uv_stream_on_write_impl(
854
+ uv.uv_write_t* req,
855
+ int status,
856
+ ):
857
+ cdef:
858
+ _StreamWriteContext ctx = <_StreamWriteContext> req.data
859
+ UVStream stream = <UVStream>ctx.stream
860
+
861
+ ctx.close()
862
+
863
+ if stream._closed:
864
+ # The stream was closed, there is nothing to do.
865
+ # Even if there is an error, like EPIPE, there
866
+ # is no reason to report it.
867
+ return
868
+
869
+ if status < 0:
870
+ if UVLOOP_DEBUG:
871
+ stream._loop._debug_stream_write_errors_total += 1
872
+
873
+ exc = convert_error(status)
874
+ stream._fatal_error(
875
+ exc, False, "error status in uv_stream_t.write callback")
876
+ return
877
+
878
+ try:
879
+ stream._on_write()
880
+ except BaseException as exc:
881
+ if UVLOOP_DEBUG:
882
+ stream._loop._debug_stream_write_cb_errors_total += 1
883
+
884
+ stream._fatal_error(exc, False)
885
+
886
+
887
+ cdef void __uv_stream_on_read(
888
+ uv.uv_stream_t* stream,
889
+ ssize_t nread,
890
+ const uv.uv_buf_t* buf,
891
+ ) noexcept with gil:
892
+
893
+ if __ensure_handle_data(<uv.uv_handle_t*>stream,
894
+ "UVStream read callback") == 0:
895
+ return
896
+
897
+ # Don't need try-finally, __uv_stream_on_read_impl is void
898
+ __uv_stream_on_read_impl(stream, nread, buf)
899
+
900
+
901
+ cdef void __uv_stream_on_write(
902
+ uv.uv_write_t* req,
903
+ int status,
904
+ ) noexcept with gil:
905
+
906
+ if UVLOOP_DEBUG:
907
+ if req.data is NULL:
908
+ aio_logger.error(
909
+ 'UVStream.write callback called with NULL req.data, status=%r',
910
+ status)
911
+ return
912
+
913
+ # Don't need try-finally, __uv_stream_on_write_impl is void
914
+ __uv_stream_on_write_impl(req, status)
915
+
916
+
917
+ cdef void __uv_stream_buffered_alloc(
918
+ uv.uv_handle_t* stream,
919
+ size_t suggested_size,
920
+ uv.uv_buf_t* uvbuf,
921
+ ) noexcept with gil:
922
+
923
+ if __ensure_handle_data(<uv.uv_handle_t*>stream,
924
+ "UVStream alloc buffer callback") == 0:
925
+ return
926
+
927
+ cdef:
928
+ UVStream sc = <UVStream>stream.data
929
+ Loop loop = sc._loop
930
+ Py_buffer* pybuf = &sc._read_pybuf
931
+ int got_buf = 0
932
+
933
+ if sc._read_pybuf_acquired:
934
+ uvbuf.len = 0
935
+ uvbuf.base = NULL
936
+ return
937
+
938
+ sc._read_pybuf_acquired = 0
939
+ try:
940
+ buf = run_in_context1(
941
+ sc.context,
942
+ sc._protocol_get_buffer,
943
+ suggested_size,
944
+ )
945
+ PyObject_GetBuffer(buf, pybuf, PyBUF_WRITABLE)
946
+ got_buf = 1
947
+ except BaseException as exc:
948
+ # Can't call 'sc._fatal_error' or 'sc._close', libuv will SF.
949
+ # We'll do it later in __uv_stream_buffered_on_read when we
950
+ # receive UV_ENOBUFS.
951
+ uvbuf.len = 0
952
+ uvbuf.base = NULL
953
+ return
954
+
955
+ if not pybuf.len:
956
+ uvbuf.len = 0
957
+ uvbuf.base = NULL
958
+ if got_buf:
959
+ PyBuffer_Release(pybuf)
960
+ return
961
+
962
+ sc._read_pybuf_acquired = 1
963
+ uvbuf.base = <char*>pybuf.buf
964
+ uvbuf.len = pybuf.len
965
+
966
+
967
+ cdef void __uv_stream_buffered_on_read(
968
+ uv.uv_stream_t* stream,
969
+ ssize_t nread,
970
+ const uv.uv_buf_t* buf,
971
+ ) noexcept with gil:
972
+
973
+ if __ensure_handle_data(<uv.uv_handle_t*>stream,
974
+ "UVStream buffered read callback") == 0:
975
+ return
976
+
977
+ cdef:
978
+ UVStream sc = <UVStream>stream.data
979
+ Loop loop = sc._loop
980
+ Py_buffer* pybuf = &sc._read_pybuf
981
+
982
+ if nread == uv.UV_ENOBUFS:
983
+ sc._fatal_error(
984
+ RuntimeError(
985
+ 'unhandled error (or an empty buffer) in get_buffer()'),
986
+ False)
987
+ return
988
+
989
+ try:
990
+ if nread > 0 and not sc._read_pybuf_acquired:
991
+ # From libuv docs:
992
+ # nread is > 0 if there is data available or < 0 on error. When
993
+ # we’ve reached EOF, nread will be set to UV_EOF. When
994
+ # nread < 0, the buf parameter might not point to a valid
995
+ # buffer; in that case buf.len and buf.base are both set to 0.
996
+ raise RuntimeError(
997
+ f'no python buffer is allocated in on_read; nread={nread}')
998
+
999
+ if nread == 0:
1000
+ # From libuv docs:
1001
+ # nread might be 0, which does not indicate an error or EOF.
1002
+ # This is equivalent to EAGAIN or EWOULDBLOCK under read(2).
1003
+ return
1004
+
1005
+ if __uv_stream_on_read_common(sc, loop, nread):
1006
+ return
1007
+
1008
+ if UVLOOP_DEBUG:
1009
+ loop._debug_stream_read_cb_total += 1
1010
+
1011
+ run_in_context1(sc.context, sc._protocol_buffer_updated, nread)
1012
+ except BaseException as exc:
1013
+ if UVLOOP_DEBUG:
1014
+ loop._debug_stream_read_cb_errors_total += 1
1015
+
1016
+ sc._fatal_error(exc, False)
1017
+ finally:
1018
+ sc._read_pybuf_acquired = 0
1019
+ PyBuffer_Release(pybuf)
.venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pxd ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class UVStreamServer(UVSocketHandle):
2
+ cdef:
3
+ int backlog
4
+ object ssl
5
+ object ssl_handshake_timeout
6
+ object ssl_shutdown_timeout
7
+ object protocol_factory
8
+ bint opened
9
+ Server _server
10
+
11
+ # All "inline" methods are final
12
+
13
+ cdef inline _init(self, Loop loop, object protocol_factory,
14
+ Server server,
15
+ object backlog,
16
+ object ssl,
17
+ object ssl_handshake_timeout,
18
+ object ssl_shutdown_timeout)
19
+
20
+ cdef inline _mark_as_open(self)
21
+
22
+ cdef inline listen(self)
23
+ cdef inline _on_listen(self)
24
+
25
+ cdef UVStream _make_new_transport(self, object protocol, object waiter,
26
+ object context)
.venv/lib/python3.11/site-packages/uvloop/handles/streamserver.pyx ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @cython.no_gc_clear
2
+ cdef class UVStreamServer(UVSocketHandle):
3
+
4
+ def __cinit__(self):
5
+ self.opened = 0
6
+ self._server = None
7
+ self.ssl = None
8
+ self.ssl_handshake_timeout = None
9
+ self.ssl_shutdown_timeout = None
10
+ self.protocol_factory = None
11
+
12
+ cdef inline _init(self, Loop loop, object protocol_factory,
13
+ Server server,
14
+ object backlog,
15
+ object ssl,
16
+ object ssl_handshake_timeout,
17
+ object ssl_shutdown_timeout):
18
+
19
+ if not isinstance(backlog, int):
20
+ # Don't allow floats
21
+ raise TypeError('integer argument expected, got {}'.format(
22
+ type(backlog).__name__))
23
+
24
+ if ssl is not None:
25
+ if not isinstance(ssl, ssl_SSLContext):
26
+ raise TypeError(
27
+ 'ssl is expected to be None or an instance of '
28
+ 'ssl.SSLContext, got {!r}'.format(ssl))
29
+ else:
30
+ if ssl_handshake_timeout is not None:
31
+ raise ValueError(
32
+ 'ssl_handshake_timeout is only meaningful with ssl')
33
+ if ssl_shutdown_timeout is not None:
34
+ raise ValueError(
35
+ 'ssl_shutdown_timeout is only meaningful with ssl')
36
+
37
+ self.backlog = backlog
38
+ self.ssl = ssl
39
+ self.ssl_handshake_timeout = ssl_handshake_timeout
40
+ self.ssl_shutdown_timeout = ssl_shutdown_timeout
41
+
42
+ self._start_init(loop)
43
+ self.protocol_factory = protocol_factory
44
+ self._server = server
45
+
46
+ cdef inline listen(self):
47
+ cdef int err
48
+ self._ensure_alive()
49
+
50
+ if self.protocol_factory is None:
51
+ raise RuntimeError('unable to listen(); no protocol_factory')
52
+
53
+ if self.opened != 1:
54
+ raise RuntimeError('unopened TCPServer')
55
+
56
+ self.context = Context_CopyCurrent()
57
+
58
+ err = uv.uv_listen(<uv.uv_stream_t*> self._handle,
59
+ self.backlog,
60
+ __uv_streamserver_on_listen)
61
+ if err < 0:
62
+ exc = convert_error(err)
63
+ self._fatal_error(exc, True)
64
+ return
65
+
66
+ cdef inline _on_listen(self):
67
+ cdef UVStream client
68
+
69
+ protocol = run_in_context(self.context, self.protocol_factory)
70
+
71
+ if self.ssl is None:
72
+ client = self._make_new_transport(protocol, None, self.context)
73
+
74
+ else:
75
+ waiter = self._loop._new_future()
76
+
77
+ ssl_protocol = SSLProtocol(
78
+ self._loop, protocol, self.ssl,
79
+ waiter,
80
+ server_side=True,
81
+ server_hostname=None,
82
+ ssl_handshake_timeout=self.ssl_handshake_timeout,
83
+ ssl_shutdown_timeout=self.ssl_shutdown_timeout)
84
+
85
+ client = self._make_new_transport(ssl_protocol, None, self.context)
86
+
87
+ waiter.add_done_callback(
88
+ ft_partial(self.__on_ssl_connected, client))
89
+
90
+ client._accept(<UVStream>self)
91
+
92
+ cdef _fatal_error(self, exc, throw, reason=None):
93
+ # Overload UVHandle._fatal_error
94
+
95
+ self._close()
96
+
97
+ if not isinstance(exc, OSError):
98
+
99
+ if throw or self._loop is None:
100
+ raise exc
101
+
102
+ msg = f'Fatal error on server {self.__class__.__name__}'
103
+ if reason is not None:
104
+ msg = f'{msg} ({reason})'
105
+
106
+ self._loop.call_exception_handler({
107
+ 'message': msg,
108
+ 'exception': exc,
109
+ })
110
+
111
+ cdef inline _mark_as_open(self):
112
+ self.opened = 1
113
+
114
+ cdef UVStream _make_new_transport(self, object protocol, object waiter,
115
+ object context):
116
+ raise NotImplementedError
117
+
118
+ def __on_ssl_connected(self, transport, fut):
119
+ exc = fut.exception()
120
+ if exc is not None:
121
+ transport._force_close(exc)
122
+
123
+
124
+ cdef void __uv_streamserver_on_listen(
125
+ uv.uv_stream_t* handle,
126
+ int status,
127
+ ) noexcept with gil:
128
+
129
+ # callback for uv_listen
130
+
131
+ if __ensure_handle_data(<uv.uv_handle_t*>handle,
132
+ "UVStream listen callback") == 0:
133
+ return
134
+
135
+ cdef:
136
+ UVStreamServer stream = <UVStreamServer> handle.data
137
+
138
+ if status < 0:
139
+ if UVLOOP_DEBUG:
140
+ stream._loop._debug_stream_listen_errors_total += 1
141
+
142
+ exc = convert_error(status)
143
+ stream._fatal_error(
144
+ exc, False, "error status in uv_stream_t.listen callback")
145
+ return
146
+
147
+ try:
148
+ stream._on_listen()
149
+ except BaseException as exc:
150
+ stream._error(exc, False)
.venv/lib/python3.11/site-packages/uvloop/handles/tcp.pxd ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef class TCPServer(UVStreamServer):
2
+ cdef bind(self, system.sockaddr* addr, unsigned int flags=*)
3
+
4
+ @staticmethod
5
+ cdef TCPServer new(Loop loop, object protocol_factory, Server server,
6
+ unsigned int flags,
7
+ object backlog,
8
+ object ssl,
9
+ object ssl_handshake_timeout,
10
+ object ssl_shutdown_timeout)
11
+
12
+
13
+ cdef class TCPTransport(UVStream):
14
+ cdef:
15
+ bint __peername_set
16
+ bint __sockname_set
17
+ system.sockaddr_storage __peername
18
+ system.sockaddr_storage __sockname
19
+
20
+ cdef bind(self, system.sockaddr* addr, unsigned int flags=*)
21
+ cdef connect(self, system.sockaddr* addr)
22
+ cdef _set_nodelay(self)
23
+
24
+ @staticmethod
25
+ cdef TCPTransport new(Loop loop, object protocol, Server server,
26
+ object waiter, object context)
.venv/lib/python3.11/site-packages/uvloop/handles/tcp.pyx ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cdef __tcp_init_uv_handle(UVStream handle, Loop loop, unsigned int flags):
2
+ cdef int err
3
+
4
+ handle._handle = <uv.uv_handle_t*>PyMem_RawMalloc(sizeof(uv.uv_tcp_t))
5
+ if handle._handle is NULL:
6
+ handle._abort_init()
7
+ raise MemoryError()
8
+
9
+ err = uv.uv_tcp_init_ex(handle._loop.uvloop,
10
+ <uv.uv_tcp_t*>handle._handle,
11
+ flags)
12
+ if err < 0:
13
+ handle._abort_init()
14
+ raise convert_error(err)
15
+
16
+ handle._finish_init()
17
+
18
+
19
+ cdef __tcp_bind(UVStream handle, system.sockaddr* addr, unsigned int flags):
20
+ cdef int err
21
+ err = uv.uv_tcp_bind(<uv.uv_tcp_t *>handle._handle,
22
+ addr, flags)
23
+ if err < 0:
24
+ exc = convert_error(err)
25
+ raise exc
26
+
27
+
28
+ cdef __tcp_open(UVStream handle, int sockfd):
29
+ cdef int err
30
+ err = uv.uv_tcp_open(<uv.uv_tcp_t *>handle._handle,
31
+ <uv.uv_os_sock_t>sockfd)
32
+ if err < 0:
33
+ exc = convert_error(err)
34
+ raise exc
35
+
36
+
37
+ cdef __tcp_get_socket(UVSocketHandle handle):
38
+ cdef:
39
+ int buf_len = sizeof(system.sockaddr_storage)
40
+ int fileno
41
+ int err
42
+ system.sockaddr_storage buf
43
+
44
+ fileno = handle._fileno()
45
+
46
+ err = uv.uv_tcp_getsockname(<uv.uv_tcp_t*>handle._handle,
47
+ <system.sockaddr*>&buf,
48
+ &buf_len)
49
+ if err < 0:
50
+ raise convert_error(err)
51
+
52
+ return PseudoSocket(buf.ss_family, uv.SOCK_STREAM, 0, fileno)
53
+
54
+
55
+ @cython.no_gc_clear
56
+ cdef class TCPServer(UVStreamServer):
57
+
58
+ @staticmethod
59
+ cdef TCPServer new(Loop loop, object protocol_factory, Server server,
60
+ unsigned int flags,
61
+ object backlog,
62
+ object ssl,
63
+ object ssl_handshake_timeout,
64
+ object ssl_shutdown_timeout):
65
+
66
+ cdef TCPServer handle
67
+ handle = TCPServer.__new__(TCPServer)
68
+ handle._init(loop, protocol_factory, server, backlog,
69
+ ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
70
+ __tcp_init_uv_handle(<UVStream>handle, loop, flags)
71
+ return handle
72
+
73
+ cdef _new_socket(self):
74
+ return __tcp_get_socket(<UVSocketHandle>self)
75
+
76
+ cdef _open(self, int sockfd):
77
+ self._ensure_alive()
78
+ try:
79
+ __tcp_open(<UVStream>self, sockfd)
80
+ except Exception as exc:
81
+ self._fatal_error(exc, True)
82
+ else:
83
+ self._mark_as_open()
84
+
85
+ cdef bind(self, system.sockaddr* addr, unsigned int flags=0):
86
+ self._ensure_alive()
87
+ try:
88
+ __tcp_bind(<UVStream>self, addr, flags)
89
+ except Exception as exc:
90
+ self._fatal_error(exc, True)
91
+ else:
92
+ self._mark_as_open()
93
+
94
+ cdef UVStream _make_new_transport(self, object protocol, object waiter,
95
+ object context):
96
+ cdef TCPTransport tr
97
+ tr = TCPTransport.new(self._loop, protocol, self._server, waiter,
98
+ context)
99
+ return <UVStream>tr
100
+
101
+
102
+ @cython.no_gc_clear
103
+ cdef class TCPTransport(UVStream):
104
+
105
+ @staticmethod
106
+ cdef TCPTransport new(Loop loop, object protocol, Server server,
107
+ object waiter, object context):
108
+
109
+ cdef TCPTransport handle
110
+ handle = TCPTransport.__new__(TCPTransport)
111
+ handle._init(loop, protocol, server, waiter, context)
112
+ __tcp_init_uv_handle(<UVStream>handle, loop, uv.AF_UNSPEC)
113
+ handle.__peername_set = 0
114
+ handle.__sockname_set = 0
115
+ handle._set_nodelay()
116
+ return handle
117
+
118
+ cdef _set_nodelay(self):
119
+ cdef int err
120
+ self._ensure_alive()
121
+ err = uv.uv_tcp_nodelay(<uv.uv_tcp_t*>self._handle, 1)
122
+ if err < 0:
123
+ raise convert_error(err)
124
+
125
+ cdef _call_connection_made(self):
126
+ # asyncio saves peername & sockname when transports are instantiated,
127
+ # so that they're accessible even after the transport is closed.
128
+ # We are doing the same thing here, except that we create Python
129
+ # objects lazily, on request in get_extra_info()
130
+
131
+ cdef:
132
+ int err
133
+ int buf_len
134
+
135
+ buf_len = sizeof(system.sockaddr_storage)
136
+ err = uv.uv_tcp_getsockname(<uv.uv_tcp_t*>self._handle,
137
+ <system.sockaddr*>&self.__sockname,
138
+ &buf_len)
139
+ if err >= 0:
140
+ # Ignore errors, this is an optional thing.
141
+ # If something serious is going on, the transport
142
+ # will crash later (in roughly the same way how
143
+ # an asyncio transport would.)
144
+ self.__sockname_set = 1
145
+
146
+ buf_len = sizeof(system.sockaddr_storage)
147
+ err = uv.uv_tcp_getpeername(<uv.uv_tcp_t*>self._handle,
148
+ <system.sockaddr*>&self.__peername,
149
+ &buf_len)
150
+ if err >= 0:
151
+ # Same as few lines above -- we don't really care
152
+ # about error case here.
153
+ self.__peername_set = 1
154
+
155
+ UVBaseTransport._call_connection_made(self)
156
+
157
+ def get_extra_info(self, name, default=None):
158
+ if name == 'sockname':
159
+ if self.__sockname_set:
160
+ return __convert_sockaddr_to_pyaddr(
161
+ <system.sockaddr*>&self.__sockname)
162
+ elif name == 'peername':
163
+ if self.__peername_set:
164
+ return __convert_sockaddr_to_pyaddr(
165
+ <system.sockaddr*>&self.__peername)
166
+ return super().get_extra_info(name, default)
167
+
168
+ cdef _new_socket(self):
169
+ return __tcp_get_socket(<UVSocketHandle>self)
170
+
171
+ cdef bind(self, system.sockaddr* addr, unsigned int flags=0):
172
+ self._ensure_alive()
173
+ __tcp_bind(<UVStream>self, addr, flags)
174
+
175
+ cdef _open(self, int sockfd):
176
+ self._ensure_alive()
177
+ __tcp_open(<UVStream>self, sockfd)
178
+
179
+ cdef connect(self, system.sockaddr* addr):
180
+ cdef _TCPConnectRequest req
181
+ req = _TCPConnectRequest(self._loop, self)
182
+ req.connect(addr)
183
+
184
+
185
+ cdef class _TCPConnectRequest(UVRequest):
186
+ cdef:
187
+ TCPTransport transport
188
+ uv.uv_connect_t _req_data
189
+
190
+ def __cinit__(self, loop, transport):
191
+ self.request = <uv.uv_req_t*>&self._req_data
192
+ self.request.data = <void*>self
193
+ self.transport = transport
194
+
195
+ cdef connect(self, system.sockaddr* addr):
196
+ cdef int err
197
+ err = uv.uv_tcp_connect(<uv.uv_connect_t*>self.request,
198
+ <uv.uv_tcp_t*>self.transport._handle,
199
+ addr,
200
+ __tcp_connect_callback)
201
+ if err < 0:
202
+ exc = convert_error(err)
203
+ self.on_done()
204
+ raise exc
205
+
206
+
207
+ cdef void __tcp_connect_callback(
208
+ uv.uv_connect_t* req,
209
+ int status,
210
+ ) noexcept with gil:
211
+ cdef:
212
+ _TCPConnectRequest wrapper
213
+ TCPTransport transport
214
+
215
+ wrapper = <_TCPConnectRequest> req.data
216
+ transport = wrapper.transport
217
+
218
+ if status < 0:
219
+ exc = convert_error(status)
220
+ else:
221
+ exc = None
222
+
223
+ try:
224
+ transport._on_connect(exc)
225
+ except BaseException as ex:
226
+ wrapper.transport._fatal_error(ex, False)
227
+ finally:
228
+ wrapper.on_done()