Browse Source

first commit

dq1968 2 weeks ago
commit
ed0fdd5afc
100 changed files with 11212 additions and 0 deletions
  1. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/_bootlocale.cpython-39.pyc
  2. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/_collections_abc.cpython-39.pyc
  3. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/_sitebuiltins.cpython-39.pyc
  4. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/_weakrefset.cpython-39.pyc
  5. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/abc.cpython-39.pyc
  6. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/codecs.cpython-39.pyc
  7. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/collections/__init__.cpython-39.pyc
  8. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/collections/abc.cpython-39.pyc
  9. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/contextlib.cpython-39.pyc
  10. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/copyreg.cpython-39.pyc
  11. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/__init__.cpython-39.pyc
  12. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/aliases.cpython-39.pyc
  13. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/cp437.cpython-39.pyc
  14. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/latin_1.cpython-39.pyc
  15. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/utf_8.cpython-39.pyc
  16. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/enum.cpython-39.pyc
  17. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/functools.cpython-39.pyc
  18. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/genericpath.cpython-39.pyc
  19. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/heapq.cpython-39.pyc
  20. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/__init__.cpython-39.pyc
  21. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/abc.cpython-39.pyc
  22. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/machinery.cpython-39.pyc
  23. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/util.cpython-39.pyc
  24. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/io.cpython-39.pyc
  25. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/keyword.cpython-39.pyc
  26. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/linecache.cpython-39.pyc
  27. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/operator.cpython-39.pyc
  28. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/os.cpython-39.pyc
  29. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/pkgutil.cpython-39.pyc
  30. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/posixpath.cpython-39.pyc
  31. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/py_compile.cpython-39.pyc
  32. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/re.cpython-39.pyc
  33. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/reprlib.cpython-39.pyc
  34. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/runpy.cpython-39.pyc
  35. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site.cpython-39.pyc
  36. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/sre_compile.cpython-39.pyc
  37. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/sre_constants.cpython-39.pyc
  38. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/sre_parse.cpython-39.pyc
  39. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/stat.cpython-39.pyc
  40. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/token.cpython-39.pyc
  41. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/tokenize.cpython-39.pyc
  42. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/traceback.cpython-39.pyc
  43. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/types.cpython-39.pyc
  44. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/typing.cpython-39.pyc
  45. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/warnings.cpython-39.pyc
  46. BIN
      .pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/weakref.cpython-39.pyc
  47. BIN
      .pycache_check/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/app/main.cpython-39.pyc
  48. 241 0
      .venv/bin/Activate.ps1
  49. 66 0
      .venv/bin/activate
  50. 25 0
      .venv/bin/activate.csh
  51. 64 0
      .venv/bin/activate.fish
  52. 8 0
      .venv/bin/fastapi
  53. 8 0
      .venv/bin/idna
  54. 8 0
      .venv/bin/pip
  55. 8 0
      .venv/bin/pip3
  56. 8 0
      .venv/bin/pip3.9
  57. 1 0
      .venv/bin/python
  58. 1 0
      .venv/bin/python3
  59. 1 0
      .venv/bin/python3.9
  60. 8 0
      .venv/bin/uvicorn
  61. 128 0
      .venv/lib/python3.9/site-packages/_distutils_hack/__init__.py
  62. 1 0
      .venv/lib/python3.9/site-packages/_distutils_hack/override.py
  63. 1 0
      .venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/INSTALLER
  64. 295 0
      .venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/METADATA
  65. 10 0
      .venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/RECORD
  66. 4 0
      .venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/WHEEL
  67. 21 0
      .venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE
  68. 432 0
      .venv/lib/python3.9/site-packages/annotated_types/__init__.py
  69. 0 0
      .venv/lib/python3.9/site-packages/annotated_types/py.typed
  70. 151 0
      .venv/lib/python3.9/site-packages/annotated_types/test_cases.py
  71. 1 0
      .venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/INSTALLER
  72. 96 0
      .venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/METADATA
  73. 92 0
      .venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/RECORD
  74. 5 0
      .venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/WHEEL
  75. 2 0
      .venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/entry_points.txt
  76. 20 0
      .venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE
  77. 1 0
      .venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/top_level.txt
  78. 111 0
      .venv/lib/python3.9/site-packages/anyio/__init__.py
  79. 0 0
      .venv/lib/python3.9/site-packages/anyio/_backends/__init__.py
  80. 2980 0
      .venv/lib/python3.9/site-packages/anyio/_backends/_asyncio.py
  81. 1346 0
      .venv/lib/python3.9/site-packages/anyio/_backends/_trio.py
  82. 0 0
      .venv/lib/python3.9/site-packages/anyio/_core/__init__.py
  83. 167 0
      .venv/lib/python3.9/site-packages/anyio/_core/_asyncio_selector_thread.py
  84. 200 0
      .venv/lib/python3.9/site-packages/anyio/_core/_contextmanagers.py
  85. 234 0
      .venv/lib/python3.9/site-packages/anyio/_core/_eventloop.py
  86. 156 0
      .venv/lib/python3.9/site-packages/anyio/_core/_exceptions.py
  87. 797 0
      .venv/lib/python3.9/site-packages/anyio/_core/_fileio.py
  88. 18 0
      .venv/lib/python3.9/site-packages/anyio/_core/_resources.py
  89. 29 0
      .venv/lib/python3.9/site-packages/anyio/_core/_signals.py
  90. 1003 0
      .venv/lib/python3.9/site-packages/anyio/_core/_sockets.py
  91. 52 0
      .venv/lib/python3.9/site-packages/anyio/_core/_streams.py
  92. 202 0
      .venv/lib/python3.9/site-packages/anyio/_core/_subprocesses.py
  93. 753 0
      .venv/lib/python3.9/site-packages/anyio/_core/_synchronization.py
  94. 173 0
      .venv/lib/python3.9/site-packages/anyio/_core/_tasks.py
  95. 616 0
      .venv/lib/python3.9/site-packages/anyio/_core/_tempfile.py
  96. 82 0
      .venv/lib/python3.9/site-packages/anyio/_core/_testing.py
  97. 81 0
      .venv/lib/python3.9/site-packages/anyio/_core/_typedattr.py
  98. 58 0
      .venv/lib/python3.9/site-packages/anyio/abc/__init__.py
  99. 414 0
      .venv/lib/python3.9/site-packages/anyio/abc/_eventloop.py
  100. 33 0
      .venv/lib/python3.9/site-packages/anyio/abc/_resources.py

BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/_bootlocale.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/_collections_abc.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/_sitebuiltins.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/_weakrefset.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/abc.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/codecs.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/collections/__init__.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/collections/abc.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/contextlib.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/copyreg.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/__init__.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/aliases.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/cp437.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/latin_1.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/encodings/utf_8.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/enum.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/functools.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/genericpath.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/heapq.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/__init__.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/abc.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/machinery.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/util.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/io.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/keyword.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/linecache.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/operator.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/os.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/pkgutil.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/posixpath.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/py_compile.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/re.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/reprlib.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/runpy.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/site.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/sre_compile.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/sre_constants.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/sre_parse.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/stat.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/token.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/tokenize.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/traceback.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/types.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/typing.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/warnings.cpython-39.pyc


BIN
.pycache_check/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/weakref.cpython-39.pyc


BIN
.pycache_check/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/app/main.cpython-39.pyc


+ 241 - 0
.venv/bin/Activate.ps1

@@ -0,0 +1,241 @@
+<#
+.Synopsis
+Activate a Python virtual environment for the current PowerShell session.
+
+.Description
+Pushes the python executable for a virtual environment to the front of the
+$Env:PATH environment variable and sets the prompt to signify that you are
+in a Python virtual environment. Makes use of the command line switches as
+well as the `pyvenv.cfg` file values present in the virtual environment.
+
+.Parameter VenvDir
+Path to the directory that contains the virtual environment to activate. The
+default value for this is the parent of the directory that the Activate.ps1
+script is located within.
+
+.Parameter Prompt
+The prompt prefix to display when this virtual environment is activated. By
+default, this prompt is the name of the virtual environment folder (VenvDir)
+surrounded by parentheses and followed by a single space (ie. '(.venv) ').
+
+.Example
+Activate.ps1
+Activates the Python virtual environment that contains the Activate.ps1 script.
+
+.Example
+Activate.ps1 -Verbose
+Activates the Python virtual environment that contains the Activate.ps1 script,
+and shows extra information about the activation as it executes.
+
+.Example
+Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
+Activates the Python virtual environment located in the specified location.
+
+.Example
+Activate.ps1 -Prompt "MyPython"
+Activates the Python virtual environment that contains the Activate.ps1 script,
+and prefixes the current prompt with the specified string (surrounded in
+parentheses) while the virtual environment is active.
+
+.Notes
+On Windows, it may be required to enable this Activate.ps1 script by setting the
+execution policy for the user. You can do this by issuing the following PowerShell
+command:
+
+PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
+
+For more information on Execution Policies: 
+https://go.microsoft.com/fwlink/?LinkID=135170
+
+#>
+Param(
+    [Parameter(Mandatory = $false)]
+    [String]
+    $VenvDir,
+    [Parameter(Mandatory = $false)]
+    [String]
+    $Prompt
+)
+
+<# Function declarations --------------------------------------------------- #>
+
+<#
+.Synopsis
+Remove all shell session elements added by the Activate script, including the
+addition of the virtual environment's Python executable from the beginning of
+the PATH variable.
+
+.Parameter NonDestructive
+If present, do not remove this function from the global namespace for the
+session.
+
+#>
+function global:deactivate ([switch]$NonDestructive) {
+    # Revert to original values
+
+    # The prior prompt:
+    if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
+        Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
+        Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
+    }
+
+    # The prior PYTHONHOME:
+    if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
+        Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
+        Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
+    }
+
+    # The prior PATH:
+    if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
+        Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
+        Remove-Item -Path Env:_OLD_VIRTUAL_PATH
+    }
+
+    # Just remove the VIRTUAL_ENV altogether:
+    if (Test-Path -Path Env:VIRTUAL_ENV) {
+        Remove-Item -Path env:VIRTUAL_ENV
+    }
+
+    # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
+    if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
+        Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
+    }
+
+    # Leave deactivate function in the global namespace if requested:
+    if (-not $NonDestructive) {
+        Remove-Item -Path function:deactivate
+    }
+}
+
+<#
+.Description
+Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
+given folder, and returns them in a map.
+
+For each line in the pyvenv.cfg file, if that line can be parsed into exactly
+two strings separated by `=` (with any amount of whitespace surrounding the =)
+then it is considered a `key = value` line. The left hand string is the key,
+the right hand is the value.
+
+If the value starts with a `'` or a `"` then the first and last character is
+stripped from the value before being captured.
+
+.Parameter ConfigDir
+Path to the directory that contains the `pyvenv.cfg` file.
+#>
+function Get-PyVenvConfig(
+    [String]
+    $ConfigDir
+) {
+    Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
+
+    # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
+    $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
+
+    # An empty map will be returned if no config file is found.
+    $pyvenvConfig = @{ }
+
+    if ($pyvenvConfigPath) {
+
+        Write-Verbose "File exists, parse `key = value` lines"
+        $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
+
+        $pyvenvConfigContent | ForEach-Object {
+            $keyval = $PSItem -split "\s*=\s*", 2
+            if ($keyval[0] -and $keyval[1]) {
+                $val = $keyval[1]
+
+                # Remove extraneous quotations around a string value.
+                if ("'""".Contains($val.Substring(0, 1))) {
+                    $val = $val.Substring(1, $val.Length - 2)
+                }
+
+                $pyvenvConfig[$keyval[0]] = $val
+                Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
+            }
+        }
+    }
+    return $pyvenvConfig
+}
+
+
+<# Begin Activate script --------------------------------------------------- #>
+
+# Determine the containing directory of this script
+$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
+$VenvExecDir = Get-Item -Path $VenvExecPath
+
+Write-Verbose "Activation script is located in path: '$VenvExecPath'"
+Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
+Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
+
+# Set values required in priority: CmdLine, ConfigFile, Default
+# First, get the location of the virtual environment, it might not be
+# VenvExecDir if specified on the command line.
+if ($VenvDir) {
+    Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
+}
+else {
+    Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
+    $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
+    Write-Verbose "VenvDir=$VenvDir"
+}
+
+# Next, read the `pyvenv.cfg` file to determine any required value such
+# as `prompt`.
+$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
+
+# Next, set the prompt from the command line, or the config file, or
+# just use the name of the virtual environment folder.
+if ($Prompt) {
+    Write-Verbose "Prompt specified as argument, using '$Prompt'"
+}
+else {
+    Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
+    if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
+        Write-Verbose "  Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
+        $Prompt = $pyvenvCfg['prompt'];
+    }
+    else {
+        Write-Verbose "  Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)"
+        Write-Verbose "  Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
+        $Prompt = Split-Path -Path $venvDir -Leaf
+    }
+}
+
+Write-Verbose "Prompt = '$Prompt'"
+Write-Verbose "VenvDir='$VenvDir'"
+
+# Deactivate any currently active virtual environment, but leave the
+# deactivate function in place.
+deactivate -nondestructive
+
+# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
+# that there is an activated venv.
+$env:VIRTUAL_ENV = $VenvDir
+
+if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
+
+    Write-Verbose "Setting prompt to '$Prompt'"
+
+    # Set the prompt to include the env name
+    # Make sure _OLD_VIRTUAL_PROMPT is global
+    function global:_OLD_VIRTUAL_PROMPT { "" }
+    Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
+    New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
+
+    function global:prompt {
+        Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
+        _OLD_VIRTUAL_PROMPT
+    }
+}
+
+# Clear PYTHONHOME
+if (Test-Path -Path Env:PYTHONHOME) {
+    Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
+    Remove-Item -Path Env:PYTHONHOME
+}
+
+# Add the venv to the PATH
+Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
+$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"

+ 66 - 0
.venv/bin/activate

@@ -0,0 +1,66 @@
+# This file must be used with "source bin/activate" *from bash*
+# you cannot run it directly
+
+deactivate () {
+    # reset old environment variables
+    if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
+        PATH="${_OLD_VIRTUAL_PATH:-}"
+        export PATH
+        unset _OLD_VIRTUAL_PATH
+    fi
+    if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
+        PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
+        export PYTHONHOME
+        unset _OLD_VIRTUAL_PYTHONHOME
+    fi
+
+    # This should detect bash and zsh, which have a hash command that must
+    # be called to get it to forget past commands.  Without forgetting
+    # past commands the $PATH changes we made may not be respected
+    if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
+        hash -r 2> /dev/null
+    fi
+
+    if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
+        PS1="${_OLD_VIRTUAL_PS1:-}"
+        export PS1
+        unset _OLD_VIRTUAL_PS1
+    fi
+
+    unset VIRTUAL_ENV
+    if [ ! "${1:-}" = "nondestructive" ] ; then
+    # Self destruct!
+        unset -f deactivate
+    fi
+}
+
+# unset irrelevant variables
+deactivate nondestructive
+
+VIRTUAL_ENV="/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv"
+export VIRTUAL_ENV
+
+_OLD_VIRTUAL_PATH="$PATH"
+PATH="$VIRTUAL_ENV/bin:$PATH"
+export PATH
+
+# unset PYTHONHOME if set
+# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
+# could use `if (set -u; : $PYTHONHOME) ;` in bash
+if [ -n "${PYTHONHOME:-}" ] ; then
+    _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
+    unset PYTHONHOME
+fi
+
+if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
+    _OLD_VIRTUAL_PS1="${PS1:-}"
+    PS1="(.venv) ${PS1:-}"
+    export PS1
+fi
+
+# This should detect bash and zsh, which have a hash command that must
+# be called to get it to forget past commands.  Without forgetting
+# past commands the $PATH changes we made may not be respected
+if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
+    hash -r 2> /dev/null
+fi

+ 25 - 0
.venv/bin/activate.csh

@@ -0,0 +1,25 @@
+# This file must be used with "source bin/activate.csh" *from csh*.
+# You cannot run it directly.
+# Created by Davide Di Blasi <davidedb@gmail.com>.
+# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
+
+alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate'
+
+# Unset irrelevant variables.
+deactivate nondestructive
+
+setenv VIRTUAL_ENV "/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv"
+
+set _OLD_VIRTUAL_PATH="$PATH"
+setenv PATH "$VIRTUAL_ENV/bin:$PATH"
+
+
+set _OLD_VIRTUAL_PROMPT="$prompt"
+
+if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
+    set prompt = "(.venv) $prompt"
+endif
+
+alias pydoc python -m pydoc
+
+rehash

+ 64 - 0
.venv/bin/activate.fish

@@ -0,0 +1,64 @@
+# This file must be used with "source <venv>/bin/activate.fish" *from fish*
+# (https://fishshell.com/); you cannot run it directly.
+
+function deactivate  -d "Exit virtual environment and return to normal shell environment"
+    # reset old environment variables
+    if test -n "$_OLD_VIRTUAL_PATH"
+        set -gx PATH $_OLD_VIRTUAL_PATH
+        set -e _OLD_VIRTUAL_PATH
+    end
+    if test -n "$_OLD_VIRTUAL_PYTHONHOME"
+        set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
+        set -e _OLD_VIRTUAL_PYTHONHOME
+    end
+
+    if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
+        functions -e fish_prompt
+        set -e _OLD_FISH_PROMPT_OVERRIDE
+        functions -c _old_fish_prompt fish_prompt
+        functions -e _old_fish_prompt
+    end
+
+    set -e VIRTUAL_ENV
+    if test "$argv[1]" != "nondestructive"
+        # Self-destruct!
+        functions -e deactivate
+    end
+end
+
+# Unset irrelevant variables.
+deactivate nondestructive
+
+set -gx VIRTUAL_ENV "/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv"
+
+set -gx _OLD_VIRTUAL_PATH $PATH
+set -gx PATH "$VIRTUAL_ENV/bin" $PATH
+
+# Unset PYTHONHOME if set.
+if set -q PYTHONHOME
+    set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
+    set -e PYTHONHOME
+end
+
+if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
+    # fish uses a function instead of an env var to generate the prompt.
+
+    # Save the current fish_prompt function as the function _old_fish_prompt.
+    functions -c fish_prompt _old_fish_prompt
+
+    # With the original prompt function renamed, we can override with our own.
+    function fish_prompt
+        # Save the return status of the last command.
+        set -l old_status $status
+
+        # Output the venv prompt; color taken from the blue of the Python logo.
+        printf "%s%s%s" (set_color 4B8BBE) "(.venv) " (set_color normal)
+
+        # Restore the return status of the previous command.
+        echo "exit $old_status" | .
+        # Output the original/"old" prompt.
+        _old_fish_prompt
+    end
+
+    set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
+end

+ 8 - 0
.venv/bin/fastapi

@@ -0,0 +1,8 @@
+#!/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/bin/python3
+# -*- coding: utf-8 -*-
+import re
+import sys
+from fastapi.cli import main
+if __name__ == '__main__':
+    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+    sys.exit(main())

+ 8 - 0
.venv/bin/idna

@@ -0,0 +1,8 @@
+#!/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/bin/python3
+# -*- coding: utf-8 -*-
+import re
+import sys
+from idna.cli import main
+if __name__ == '__main__':
+    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+    sys.exit(main())

+ 8 - 0
.venv/bin/pip

@@ -0,0 +1,8 @@
+#!/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/bin/python3
+# -*- coding: utf-8 -*-
+import re
+import sys
+from pip._internal.cli.main import main
+if __name__ == '__main__':
+    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+    sys.exit(main())

+ 8 - 0
.venv/bin/pip3

@@ -0,0 +1,8 @@
+#!/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/bin/python3
+# -*- coding: utf-8 -*-
+import re
+import sys
+from pip._internal.cli.main import main
+if __name__ == '__main__':
+    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+    sys.exit(main())

+ 8 - 0
.venv/bin/pip3.9

@@ -0,0 +1,8 @@
+#!/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/bin/python3
+# -*- coding: utf-8 -*-
+import re
+import sys
+from pip._internal.cli.main import main
+if __name__ == '__main__':
+    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+    sys.exit(main())

+ 1 - 0
.venv/bin/python

@@ -0,0 +1 @@
+python3

+ 1 - 0
.venv/bin/python3

@@ -0,0 +1 @@
+/Library/Developer/CommandLineTools/usr/bin/python3

+ 1 - 0
.venv/bin/python3.9

@@ -0,0 +1 @@
+python3

+ 8 - 0
.venv/bin/uvicorn

@@ -0,0 +1,8 @@
+#!/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/bin/python3
+# -*- coding: utf-8 -*-
+import re
+import sys
+from uvicorn.main import main
+if __name__ == '__main__':
+    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+    sys.exit(main())

+ 128 - 0
.venv/lib/python3.9/site-packages/_distutils_hack/__init__.py

@@ -0,0 +1,128 @@
+import sys
+import os
+import re
+import importlib
+import warnings
+
+
+is_pypy = '__pypy__' in sys.builtin_module_names
+
+
+warnings.filterwarnings('ignore',
+                        r'.+ distutils\b.+ deprecated',
+                        DeprecationWarning)
+
+
+def warn_distutils_present():
+    if 'distutils' not in sys.modules:
+        return
+    if is_pypy and sys.version_info < (3, 7):
+        # PyPy for 3.6 unconditionally imports distutils, so bypass the warning
+        # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
+        return
+    warnings.warn(
+        "Distutils was imported before Setuptools, but importing Setuptools "
+        "also replaces the `distutils` module in `sys.modules`. This may lead "
+        "to undesirable behaviors or errors. To avoid these issues, avoid "
+        "using distutils directly, ensure that setuptools is installed in the "
+        "traditional way (e.g. not an editable install), and/or make sure "
+        "that setuptools is always imported before distutils.")
+
+
+def clear_distutils():
+    if 'distutils' not in sys.modules:
+        return
+    warnings.warn("Setuptools is replacing distutils.")
+    mods = [name for name in sys.modules if re.match(r'distutils\b', name)]
+    for name in mods:
+        del sys.modules[name]
+
+
+def enabled():
+    """
+    Allow selection of distutils by environment variable.
+    """
+    which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib')
+    return which == 'local'
+
+
+def ensure_local_distutils():
+    clear_distutils()
+    distutils = importlib.import_module('setuptools._distutils')
+    distutils.__name__ = 'distutils'
+    sys.modules['distutils'] = distutils
+
+    # sanity check that submodules load as expected
+    core = importlib.import_module('distutils.core')
+    assert '_distutils' in core.__file__, core.__file__
+
+
+def do_override():
+    """
+    Ensure that the local copy of distutils is preferred over stdlib.
+
+    See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
+    for more motivation.
+    """
+    if enabled():
+        warn_distutils_present()
+        ensure_local_distutils()
+
+
+class DistutilsMetaFinder:
+    def find_spec(self, fullname, path, target=None):
+        if path is not None:
+            return
+
+        method_name = 'spec_for_{fullname}'.format(**locals())
+        method = getattr(self, method_name, lambda: None)
+        return method()
+
+    def spec_for_distutils(self):
+        import importlib.abc
+        import importlib.util
+
+        class DistutilsLoader(importlib.abc.Loader):
+
+            def create_module(self, spec):
+                return importlib.import_module('setuptools._distutils')
+
+            def exec_module(self, module):
+                pass
+
+        return importlib.util.spec_from_loader('distutils', DistutilsLoader())
+
+    def spec_for_pip(self):
+        """
+        Ensure stdlib distutils when running under pip.
+        See pypa/pip#8761 for rationale.
+        """
+        if self.pip_imported_during_build():
+            return
+        clear_distutils()
+        self.spec_for_distutils = lambda: None
+
+    @staticmethod
+    def pip_imported_during_build():
+        """
+        Detect if pip is being imported in a build script. Ref #2355.
+        """
+        import traceback
+        return any(
+            frame.f_globals['__file__'].endswith('setup.py')
+            for frame, line in traceback.walk_stack(None)
+        )
+
+
+DISTUTILS_FINDER = DistutilsMetaFinder()
+
+
+def add_shim():
+    sys.meta_path.insert(0, DISTUTILS_FINDER)
+
+
+def remove_shim():
+    try:
+        sys.meta_path.remove(DISTUTILS_FINDER)
+    except ValueError:
+        pass

+ 1 - 0
.venv/lib/python3.9/site-packages/_distutils_hack/override.py

@@ -0,0 +1 @@
+__import__('_distutils_hack').do_override()

+ 1 - 0
.venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/INSTALLER

@@ -0,0 +1 @@
+pip

+ 295 - 0
.venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/METADATA

@@ -0,0 +1,295 @@
+Metadata-Version: 2.3
+Name: annotated-types
+Version: 0.7.0
+Summary: Reusable constraint types to use with typing.Annotated
+Project-URL: Homepage, https://github.com/annotated-types/annotated-types
+Project-URL: Source, https://github.com/annotated-types/annotated-types
+Project-URL: Changelog, https://github.com/annotated-types/annotated-types/releases
+Author-email: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, Samuel Colvin <s@muelcolvin.com>, Zac Hatfield-Dodds <zac@zhd.dev>
+License-File: LICENSE
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Console
+Classifier: Environment :: MacOS X
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Operating System :: Unix
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Typing :: Typed
+Requires-Python: >=3.8
+Requires-Dist: typing-extensions>=4.0.0; python_version < '3.9'
+Description-Content-Type: text/markdown
+
+# annotated-types
+
+[![CI](https://github.com/annotated-types/annotated-types/workflows/CI/badge.svg?event=push)](https://github.com/annotated-types/annotated-types/actions?query=event%3Apush+branch%3Amain+workflow%3ACI)
+[![pypi](https://img.shields.io/pypi/v/annotated-types.svg)](https://pypi.python.org/pypi/annotated-types)
+[![versions](https://img.shields.io/pypi/pyversions/annotated-types.svg)](https://github.com/annotated-types/annotated-types)
+[![license](https://img.shields.io/github/license/annotated-types/annotated-types.svg)](https://github.com/annotated-types/annotated-types/blob/main/LICENSE)
+
+[PEP-593](https://peps.python.org/pep-0593/) added `typing.Annotated` as a way of
+adding context-specific metadata to existing types, and specifies that
+`Annotated[T, x]` _should_ be treated as `T` by any tool or library without special
+logic for `x`.
+
+This package provides metadata objects which can be used to represent common
+constraints such as upper and lower bounds on scalar values and collection sizes,
+a `Predicate` marker for runtime checks, and
+descriptions of how we intend these metadata to be interpreted. In some cases,
+we also note alternative representations which do not require this package.
+
+## Install
+
+```bash
+pip install annotated-types
+```
+
+## Examples
+
+```python
+from typing import Annotated
+from annotated_types import Gt, Len, Predicate
+
+class MyClass:
+    age: Annotated[int, Gt(18)]                         # Valid: 19, 20, ...
+                                                        # Invalid: 17, 18, "19", 19.0, ...
+    factors: list[Annotated[int, Predicate(is_prime)]]  # Valid: 2, 3, 5, 7, 11, ...
+                                                        # Invalid: 4, 8, -2, 5.0, "prime", ...
+
+    my_list: Annotated[list[int], Len(0, 10)]           # Valid: [], [10, 20, 30, 40, 50]
+                                                        # Invalid: (1, 2), ["abc"], [0] * 20
+```
+
+## Documentation
+
+_While `annotated-types` avoids runtime checks for performance, users should not
+construct invalid combinations such as `MultipleOf("non-numeric")` or `Annotated[int, Len(3)]`.
+Downstream implementors may choose to raise an error, emit a warning, silently ignore
+a metadata item, etc., if the metadata objects described below are used with an
+incompatible type - or for any other reason!_
+
+### Gt, Ge, Lt, Le
+
+Express inclusive and/or exclusive bounds on orderable values - which may be numbers,
+dates, times, strings, sets, etc. Note that the boundary value need not be of the
+same type that was annotated, so long as they can be compared: `Annotated[int, Gt(1.5)]`
+is fine, for example, and implies that the value is an integer x such that `x > 1.5`.
+
+We suggest that implementors may also interpret `functools.partial(operator.le, 1.5)`
+as being equivalent to `Gt(1.5)`, for users who wish to avoid a runtime dependency on
+the `annotated-types` package.
+
+To be explicit, these types have the following meanings:
+
+* `Gt(x)` - value must be "Greater Than" `x` - equivalent to exclusive minimum
+* `Ge(x)` - value must be "Greater than or Equal" to `x` - equivalent to inclusive minimum
+* `Lt(x)` - value must be "Less Than" `x` - equivalent to exclusive maximum
+* `Le(x)` - value must be "Less than or Equal" to `x` - equivalent to inclusive maximum
+
+### Interval
+
+`Interval(gt, ge, lt, le)` allows you to specify an upper and lower bound with a single
+metadata object. `None` attributes should be ignored, and non-`None` attributes
+treated as per the single bounds above.
+
+### MultipleOf
+
+`MultipleOf(multiple_of=x)` might be interpreted in two ways:
+
+1. Python semantics, implying `value % multiple_of == 0`, or
+2. [JSONschema semantics](https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.2.1),
+   where `int(value / multiple_of) == value / multiple_of`.
+
+We encourage users to be aware of these two common interpretations and their
+distinct behaviours, especially since very large or non-integer numbers make
+it easy to cause silent data corruption due to floating-point imprecision.
+
+We encourage libraries to carefully document which interpretation they implement.
+
+### MinLen, MaxLen, Len
+
+`Len()` implies that `min_length <= len(value) <= max_length` - lower and upper bounds are inclusive.
+
+As well as `Len()` which can optionally include upper and lower bounds, we also
+provide `MinLen(x)` and `MaxLen(y)` which are equivalent to `Len(min_length=x)`
+and `Len(max_length=y)` respectively.
+
+`Len`, `MinLen`, and `MaxLen` may be used with any type which supports `len(value)`.
+
+Examples of usage:
+
+* `Annotated[list, MaxLen(10)]` (or `Annotated[list, Len(max_length=10))`) - list must have a length of 10 or less
+* `Annotated[str, MaxLen(10)]` - string must have a length of 10 or less
+* `Annotated[list, MinLen(3))` (or `Annotated[list, Len(min_length=3))`) - list must have a length of 3 or more
+* `Annotated[list, Len(4, 6)]` - list must have a length of 4, 5, or 6
+* `Annotated[list, Len(8, 8)]` - list must have a length of exactly 8
+
+#### Changed in v0.4.0
+
+* `min_inclusive` has been renamed to `min_length`, no change in meaning
+* `max_exclusive` has been renamed to `max_length`, upper bound is now **inclusive** instead of **exclusive**
+* The recommendation that slices are interpreted as `Len` has been removed due to ambiguity and different semantic
+  meaning of the upper bound in slices vs. `Len`
+
+See [issue #23](https://github.com/annotated-types/annotated-types/issues/23) for discussion.
+
+### Timezone
+
+`Timezone` can be used with a `datetime` or a `time` to express which timezones
+are allowed. `Annotated[datetime, Timezone(None)]` must be a naive datetime.
+`Timezone[...]` ([literal ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis))
+expresses that any timezone-aware datetime is allowed. You may also pass a specific
+timezone string or [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects)
+object such as `Timezone(timezone.utc)` or `Timezone("Africa/Abidjan")` to express that you only
+allow a specific timezone, though we note that this is often a symptom of fragile design.
+
+#### Changed in v0.x.x
+
+* `Timezone` accepts [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects) objects instead of
+  `timezone`, extending compatibility to [`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html) and third party libraries.
+
+### Unit
+
+`Unit(unit: str)` expresses that the annotated numeric value is the magnitude of
+a quantity with the specified unit. For example, `Annotated[float, Unit("m/s")]`
+would be a float representing a velocity in meters per second.
+
+Please note that `annotated_types` itself makes no attempt to parse or validate
+the unit string in any way. That is left entirely to downstream libraries,
+such as [`pint`](https://pint.readthedocs.io) or
+[`astropy.units`](https://docs.astropy.org/en/stable/units/).
+
+An example of how a library might use this metadata:
+
+```python
+from annotated_types import Unit
+from typing import Annotated, TypeVar, Callable, Any, get_origin, get_args
+
+# given a type annotated with a unit:
+Meters = Annotated[float, Unit("m")]
+
+
+# you can cast the annotation to a specific unit type with any
+# callable that accepts a string and returns the desired type
+T = TypeVar("T")
+def cast_unit(tp: Any, unit_cls: Callable[[str], T]) -> T | None:
+    if get_origin(tp) is Annotated:
+        for arg in get_args(tp):
+            if isinstance(arg, Unit):
+                return unit_cls(arg.unit)
+    return None
+
+
+# using `pint`
+import pint
+pint_unit = cast_unit(Meters, pint.Unit)
+
+
+# using `astropy.units`
+import astropy.units as u
+astropy_unit = cast_unit(Meters, u.Unit)
+```
+
+### Predicate
+
+`Predicate(func: Callable)` expresses that `func(value)` is truthy for valid values.
+Users should prefer the statically inspectable metadata above, but if you need
+the full power and flexibility of arbitrary runtime predicates... here it is.
+
+For some common constraints, we provide generic types:
+
+* `IsLower       = Annotated[T, Predicate(str.islower)]`
+* `IsUpper       = Annotated[T, Predicate(str.isupper)]`
+* `IsDigit       = Annotated[T, Predicate(str.isdigit)]`
+* `IsFinite      = Annotated[T, Predicate(math.isfinite)]`
+* `IsNotFinite   = Annotated[T, Predicate(Not(math.isfinite))]`
+* `IsNan         = Annotated[T, Predicate(math.isnan)]`
+* `IsNotNan      = Annotated[T, Predicate(Not(math.isnan))]`
+* `IsInfinite    = Annotated[T, Predicate(math.isinf)]`
+* `IsNotInfinite = Annotated[T, Predicate(Not(math.isinf))]`
+
+so that you can write e.g. `x: IsFinite[float] = 2.0` instead of the longer
+(but exactly equivalent) `x: Annotated[float, Predicate(math.isfinite)] = 2.0`.
+
+Some libraries might have special logic to handle known or understandable predicates,
+for example by checking for `str.isdigit` and using its presence to both call custom
+logic to enforce digit-only strings, and customise some generated external schema.
+Users are therefore encouraged to avoid indirection like `lambda s: s.lower()`, in
+favor of introspectable methods such as `str.lower` or `re.compile("pattern").search`.
+
+To enable basic negation of commonly used predicates like `math.isnan` without introducing introspection that makes it impossible for implementers to introspect the predicate we provide a `Not` wrapper that simply negates the predicate in an introspectable manner. Several of the predicates listed above are created in this manner.
+
+We do not specify what behaviour should be expected for predicates that raise
+an exception.  For example `Annotated[int, Predicate(str.isdigit)]` might silently
+skip invalid constraints, or statically raise an error; or it might try calling it
+and then propagate or discard the resulting
+`TypeError: descriptor 'isdigit' for 'str' objects doesn't apply to a 'int' object`
+exception.  We encourage libraries to document the behaviour they choose.
+
+### Doc
+
+`doc()` can be used to add documentation information in `Annotated`, for function and method parameters, variables, class attributes, return types, and any place where `Annotated` can be used.
+
+It expects a value that can be statically analyzed, as the main use case is for static analysis, editors, documentation generators, and similar tools.
+
+It returns a `DocInfo` class with a single attribute `documentation` containing the value passed to `doc()`.
+
+This is the early adopter's alternative form of the [`typing-doc` proposal](https://github.com/tiangolo/fastapi/blob/typing-doc/typing_doc.md).
+
+### Integrating downstream types with `GroupedMetadata`
+
+Implementers may choose to provide a convenience wrapper that groups multiple pieces of metadata.
+This can help reduce verbosity and cognitive overhead for users.
+For example, an implementer like Pydantic might provide a `Field` or `Meta` type that accepts keyword arguments and transforms these into low-level metadata:
+
+```python
+from dataclasses import dataclass
+from typing import Iterator
+from annotated_types import GroupedMetadata, Ge
+
+@dataclass
+class Field(GroupedMetadata):
+    ge: int | None = None
+    description: str | None = None
+
+    def __iter__(self) -> Iterator[object]:
+        # Iterating over a GroupedMetadata object should yield annotated-types
+        # constraint metadata objects which describe it as fully as possible,
+        # and may include other unknown objects too.
+        if self.ge is not None:
+            yield Ge(self.ge)
+        if self.description is not None:
+            yield Description(self.description)
+```
+
+Libraries consuming annotated-types constraints should check for `GroupedMetadata` and unpack it by iterating over the object and treating the results as if they had been "unpacked" in the `Annotated` type.  The same logic should be applied to the [PEP 646 `Unpack` type](https://peps.python.org/pep-0646/), so that `Annotated[T, Field(...)]`, `Annotated[T, Unpack[Field(...)]]` and `Annotated[T, *Field(...)]` are all treated consistently.
+
+Libraries consuming annotated-types should also ignore any metadata they do not recongize that came from unpacking a `GroupedMetadata`, just like they ignore unrecognized metadata in `Annotated` itself.
+
+Our own `annotated_types.Interval` class is a `GroupedMetadata` which unpacks itself into `Gt`, `Lt`, etc., so this is not an abstract concern.  Similarly, `annotated_types.Len` is a `GroupedMetadata` which unpacks itself into `MinLen` (optionally) and `MaxLen`.
+
+### Consuming metadata
+
+We intend to not be prescriptive as to _how_ the metadata and constraints are used, but as an example of how one might parse constraints from types annotations see our [implementation in `test_main.py`](https://github.com/annotated-types/annotated-types/blob/f59cf6d1b5255a0fe359b93896759a180bec30ae/tests/test_main.py#L94-L103).
+
+It is up to the implementer to determine how this metadata is used.
+You could use the metadata for runtime type checking, for generating schemas or to generate example data, amongst other use cases.
+
+## Design & History
+
+This package was designed at the PyCon 2022 sprints by the maintainers of Pydantic
+and Hypothesis, with the goal of making it as easy as possible for end-users to
+provide more informative annotations for use by runtime libraries.
+
+It is deliberately minimal, and following PEP-593 allows considerable downstream
+discretion in what (if anything!) they choose to support. Nonetheless, we expect
+that staying simple and covering _only_ the most common use-cases will give users
+and maintainers the best experience we can. If you'd like more constraints for your
+types - follow our lead, by defining them and documenting them downstream!

+ 10 - 0
.venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/RECORD

@@ -0,0 +1,10 @@
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/annotated_types/__init__.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/annotated_types/test_cases.cpython-39.pyc,,
+annotated_types-0.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+annotated_types-0.7.0.dist-info/METADATA,sha256=7ltqxksJJ0wCYFGBNIQCWTlWQGeAH0hRFdnK3CB895E,15046
+annotated_types-0.7.0.dist-info/RECORD,,
+annotated_types-0.7.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
+annotated_types-0.7.0.dist-info/licenses/LICENSE,sha256=_hBJiEsaDZNCkB6I4H8ykl0ksxIdmXK2poBfuYJLCV0,1083
+annotated_types/__init__.py,sha256=RynLsRKUEGI0KimXydlD1fZEfEzWwDo0Uon3zOKhG1Q,13819
+annotated_types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+annotated_types/test_cases.py,sha256=zHFX6EpcMbGJ8FzBYDbO56bPwx_DYIVSKbZM-4B3_lg,6421

+ 4 - 0
.venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/WHEEL

@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: hatchling 1.24.2
+Root-Is-Purelib: true
+Tag: py3-none-any

+ 21 - 0
.venv/lib/python3.9/site-packages/annotated_types-0.7.0.dist-info/licenses/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2022 the contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 432 - 0
.venv/lib/python3.9/site-packages/annotated_types/__init__.py

@@ -0,0 +1,432 @@
+import math
+import sys
+import types
+from dataclasses import dataclass
+from datetime import tzinfo
+from typing import TYPE_CHECKING, Any, Callable, Iterator, Optional, SupportsFloat, SupportsIndex, TypeVar, Union
+
+if sys.version_info < (3, 8):
+    from typing_extensions import Protocol, runtime_checkable
+else:
+    from typing import Protocol, runtime_checkable
+
+if sys.version_info < (3, 9):
+    from typing_extensions import Annotated, Literal
+else:
+    from typing import Annotated, Literal
+
+if sys.version_info < (3, 10):
+    EllipsisType = type(Ellipsis)
+    KW_ONLY = {}
+    SLOTS = {}
+else:
+    from types import EllipsisType
+
+    KW_ONLY = {"kw_only": True}
+    SLOTS = {"slots": True}
+
+
+__all__ = (
+    'BaseMetadata',
+    'GroupedMetadata',
+    'Gt',
+    'Ge',
+    'Lt',
+    'Le',
+    'Interval',
+    'MultipleOf',
+    'MinLen',
+    'MaxLen',
+    'Len',
+    'Timezone',
+    'Predicate',
+    'LowerCase',
+    'UpperCase',
+    'IsDigits',
+    'IsFinite',
+    'IsNotFinite',
+    'IsNan',
+    'IsNotNan',
+    'IsInfinite',
+    'IsNotInfinite',
+    'doc',
+    'DocInfo',
+    '__version__',
+)
+
+__version__ = '0.7.0'
+
+
+T = TypeVar('T')
+
+
+# arguments that start with __ are considered
+# positional only
+# see https://peps.python.org/pep-0484/#positional-only-arguments
+
+
+class SupportsGt(Protocol):
+    def __gt__(self: T, __other: T) -> bool:
+        ...
+
+
+class SupportsGe(Protocol):
+    def __ge__(self: T, __other: T) -> bool:
+        ...
+
+
+class SupportsLt(Protocol):
+    def __lt__(self: T, __other: T) -> bool:
+        ...
+
+
+class SupportsLe(Protocol):
+    def __le__(self: T, __other: T) -> bool:
+        ...
+
+
+class SupportsMod(Protocol):
+    def __mod__(self: T, __other: T) -> T:
+        ...
+
+
+class SupportsDiv(Protocol):
+    def __div__(self: T, __other: T) -> T:
+        ...
+
+
+class BaseMetadata:
+    """Base class for all metadata.
+
+    This exists mainly so that implementers
+    can do `isinstance(..., BaseMetadata)` while traversing field annotations.
+    """
+
+    __slots__ = ()
+
+
+@dataclass(frozen=True, **SLOTS)
+class Gt(BaseMetadata):
+    """Gt(gt=x) implies that the value must be greater than x.
+
+    It can be used with any type that supports the ``>`` operator,
+    including numbers, dates and times, strings, sets, and so on.
+    """
+
+    gt: SupportsGt
+
+
+@dataclass(frozen=True, **SLOTS)
+class Ge(BaseMetadata):
+    """Ge(ge=x) implies that the value must be greater than or equal to x.
+
+    It can be used with any type that supports the ``>=`` operator,
+    including numbers, dates and times, strings, sets, and so on.
+    """
+
+    ge: SupportsGe
+
+
+@dataclass(frozen=True, **SLOTS)
+class Lt(BaseMetadata):
+    """Lt(lt=x) implies that the value must be less than x.
+
+    It can be used with any type that supports the ``<`` operator,
+    including numbers, dates and times, strings, sets, and so on.
+    """
+
+    lt: SupportsLt
+
+
+@dataclass(frozen=True, **SLOTS)
+class Le(BaseMetadata):
+    """Le(le=x) implies that the value must be less than or equal to x.
+
+    It can be used with any type that supports the ``<=`` operator,
+    including numbers, dates and times, strings, sets, and so on.
+    """
+
+    le: SupportsLe
+
+
+@runtime_checkable
+class GroupedMetadata(Protocol):
+    """A grouping of multiple objects, like typing.Unpack.
+
+    `GroupedMetadata` on its own is not metadata and has no meaning.
+    All of the constraints and metadata should be fully expressable
+    in terms of the `BaseMetadata`'s returned by `GroupedMetadata.__iter__()`.
+
+    Concrete implementations should override `GroupedMetadata.__iter__()`
+    to add their own metadata.
+    For example:
+
+    >>> @dataclass
+    >>> class Field(GroupedMetadata):
+    >>>     gt: float | None = None
+    >>>     description: str | None = None
+    ...
+    >>>     def __iter__(self) -> Iterable[object]:
+    >>>         if self.gt is not None:
+    >>>             yield Gt(self.gt)
+    >>>         if self.description is not None:
+    >>>             yield Description(self.gt)
+
+    Also see the implementation of `Interval` below for an example.
+
+    Parsers should recognize this and unpack it so that it can be used
+    both with and without unpacking:
+
+    - `Annotated[int, Field(...)]` (parser must unpack Field)
+    - `Annotated[int, *Field(...)]` (PEP-646)
+    """  # noqa: trailing-whitespace
+
+    @property
+    def __is_annotated_types_grouped_metadata__(self) -> Literal[True]:
+        return True
+
+    def __iter__(self) -> Iterator[object]:
+        ...
+
+    if not TYPE_CHECKING:
+        __slots__ = ()  # allow subclasses to use slots
+
+        def __init_subclass__(cls, *args: Any, **kwargs: Any) -> None:
+            # Basic ABC like functionality without the complexity of an ABC
+            super().__init_subclass__(*args, **kwargs)
+            if cls.__iter__ is GroupedMetadata.__iter__:
+                raise TypeError("Can't subclass GroupedMetadata without implementing __iter__")
+
+        def __iter__(self) -> Iterator[object]:  # noqa: F811
+            raise NotImplementedError  # more helpful than "None has no attribute..." type errors
+
+
+@dataclass(frozen=True, **KW_ONLY, **SLOTS)
+class Interval(GroupedMetadata):
+    """Interval can express inclusive or exclusive bounds with a single object.
+
+    It accepts keyword arguments ``gt``, ``ge``, ``lt``, and/or ``le``, which
+    are interpreted the same way as the single-bound constraints.
+    """
+
+    gt: Union[SupportsGt, None] = None
+    ge: Union[SupportsGe, None] = None
+    lt: Union[SupportsLt, None] = None
+    le: Union[SupportsLe, None] = None
+
+    def __iter__(self) -> Iterator[BaseMetadata]:
+        """Unpack an Interval into zero or more single-bounds."""
+        if self.gt is not None:
+            yield Gt(self.gt)
+        if self.ge is not None:
+            yield Ge(self.ge)
+        if self.lt is not None:
+            yield Lt(self.lt)
+        if self.le is not None:
+            yield Le(self.le)
+
+
+@dataclass(frozen=True, **SLOTS)
+class MultipleOf(BaseMetadata):
+    """MultipleOf(multiple_of=x) might be interpreted in two ways:
+
+    1. Python semantics, implying ``value % multiple_of == 0``, or
+    2. JSONschema semantics, where ``int(value / multiple_of) == value / multiple_of``
+
+    We encourage users to be aware of these two common interpretations,
+    and libraries to carefully document which they implement.
+    """
+
+    multiple_of: Union[SupportsDiv, SupportsMod]
+
+
+@dataclass(frozen=True, **SLOTS)
+class MinLen(BaseMetadata):
+    """
+    MinLen() implies minimum inclusive length,
+    e.g. ``len(value) >= min_length``.
+    """
+
+    min_length: Annotated[int, Ge(0)]
+
+
+@dataclass(frozen=True, **SLOTS)
+class MaxLen(BaseMetadata):
+    """
+    MaxLen() implies maximum inclusive length,
+    e.g. ``len(value) <= max_length``.
+    """
+
+    max_length: Annotated[int, Ge(0)]
+
+
+@dataclass(frozen=True, **SLOTS)
+class Len(GroupedMetadata):
+    """
+    Len() implies that ``min_length <= len(value) <= max_length``.
+
+    Upper bound may be omitted or ``None`` to indicate no upper length bound.
+    """
+
+    min_length: Annotated[int, Ge(0)] = 0
+    max_length: Optional[Annotated[int, Ge(0)]] = None
+
+    def __iter__(self) -> Iterator[BaseMetadata]:
+        """Unpack a Len into zone or more single-bounds."""
+        if self.min_length > 0:
+            yield MinLen(self.min_length)
+        if self.max_length is not None:
+            yield MaxLen(self.max_length)
+
+
+@dataclass(frozen=True, **SLOTS)
+class Timezone(BaseMetadata):
+    """Timezone(tz=...) requires a datetime to be aware (or ``tz=None``, naive).
+
+    ``Annotated[datetime, Timezone(None)]`` must be a naive datetime.
+    ``Timezone[...]`` (the ellipsis literal) expresses that the datetime must be
+    tz-aware but any timezone is allowed.
+
+    You may also pass a specific timezone string or tzinfo object such as
+    ``Timezone(timezone.utc)`` or ``Timezone("Africa/Abidjan")`` to express that
+    you only allow a specific timezone, though we note that this is often
+    a symptom of poor design.
+    """
+
+    tz: Union[str, tzinfo, EllipsisType, None]
+
+
+@dataclass(frozen=True, **SLOTS)
+class Unit(BaseMetadata):
+    """Indicates that the value is a physical quantity with the specified unit.
+
+    It is intended for usage with numeric types, where the value represents the
+    magnitude of the quantity. For example, ``distance: Annotated[float, Unit('m')]``
+    or ``speed: Annotated[float, Unit('m/s')]``.
+
+    Interpretation of the unit string is left to the discretion of the consumer.
+    It is suggested to follow conventions established by python libraries that work
+    with physical quantities, such as
+
+    - ``pint`` : <https://pint.readthedocs.io/en/stable/>
+    - ``astropy.units``: <https://docs.astropy.org/en/stable/units/>
+
+    For indicating a quantity with a certain dimensionality but without a specific unit
+    it is recommended to use square brackets, e.g. `Annotated[float, Unit('[time]')]`.
+    Note, however, ``annotated_types`` itself makes no use of the unit string.
+    """
+
+    unit: str
+
+
+@dataclass(frozen=True, **SLOTS)
+class Predicate(BaseMetadata):
+    """``Predicate(func: Callable)`` implies `func(value)` is truthy for valid values.
+
+    Users should prefer statically inspectable metadata, but if you need the full
+    power and flexibility of arbitrary runtime predicates... here it is.
+
+    We provide a few predefined predicates for common string constraints:
+    ``IsLower = Predicate(str.islower)``, ``IsUpper = Predicate(str.isupper)``, and
+    ``IsDigits = Predicate(str.isdigit)``. Users are encouraged to use methods which
+    can be given special handling, and avoid indirection like ``lambda s: s.lower()``.
+
+    Some libraries might have special logic to handle certain predicates, e.g. by
+    checking for `str.isdigit` and using its presence to both call custom logic to
+    enforce digit-only strings, and customise some generated external schema.
+
+    We do not specify what behaviour should be expected for predicates that raise
+    an exception.  For example `Annotated[int, Predicate(str.isdigit)]` might silently
+    skip invalid constraints, or statically raise an error; or it might try calling it
+    and then propagate or discard the resulting exception.
+    """
+
+    func: Callable[[Any], bool]
+
+    def __repr__(self) -> str:
+        if getattr(self.func, "__name__", "<lambda>") == "<lambda>":
+            return f"{self.__class__.__name__}({self.func!r})"
+        if isinstance(self.func, (types.MethodType, types.BuiltinMethodType)) and (
+            namespace := getattr(self.func.__self__, "__name__", None)
+        ):
+            return f"{self.__class__.__name__}({namespace}.{self.func.__name__})"
+        if isinstance(self.func, type(str.isascii)):  # method descriptor
+            return f"{self.__class__.__name__}({self.func.__qualname__})"
+        return f"{self.__class__.__name__}({self.func.__name__})"
+
+
+@dataclass
+class Not:
+    func: Callable[[Any], bool]
+
+    def __call__(self, __v: Any) -> bool:
+        return not self.func(__v)
+
+
+_StrType = TypeVar("_StrType", bound=str)
+
+LowerCase = Annotated[_StrType, Predicate(str.islower)]
+"""
+Return True if the string is a lowercase string, False otherwise.
+
+A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string.
+"""  # noqa: E501
+UpperCase = Annotated[_StrType, Predicate(str.isupper)]
+"""
+Return True if the string is an uppercase string, False otherwise.
+
+A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string.
+"""  # noqa: E501
+IsDigit = Annotated[_StrType, Predicate(str.isdigit)]
+IsDigits = IsDigit  # type: ignore  # plural for backwards compatibility, see #63
+"""
+Return True if the string is a digit string, False otherwise.
+
+A string is a digit string if all characters in the string are digits and there is at least one character in the string.
+"""  # noqa: E501
+IsAscii = Annotated[_StrType, Predicate(str.isascii)]
+"""
+Return True if all characters in the string are ASCII, False otherwise.
+
+ASCII characters have code points in the range U+0000-U+007F. Empty string is ASCII too.
+"""
+
+_NumericType = TypeVar('_NumericType', bound=Union[SupportsFloat, SupportsIndex])
+IsFinite = Annotated[_NumericType, Predicate(math.isfinite)]
+"""Return True if x is neither an infinity nor a NaN, and False otherwise."""
+IsNotFinite = Annotated[_NumericType, Predicate(Not(math.isfinite))]
+"""Return True if x is one of infinity or NaN, and False otherwise"""
+IsNan = Annotated[_NumericType, Predicate(math.isnan)]
+"""Return True if x is a NaN (not a number), and False otherwise."""
+IsNotNan = Annotated[_NumericType, Predicate(Not(math.isnan))]
+"""Return True if x is anything but NaN (not a number), and False otherwise."""
+IsInfinite = Annotated[_NumericType, Predicate(math.isinf)]
+"""Return True if x is a positive or negative infinity, and False otherwise."""
+IsNotInfinite = Annotated[_NumericType, Predicate(Not(math.isinf))]
+"""Return True if x is neither a positive or negative infinity, and False otherwise."""
+
+try:
+    from typing_extensions import DocInfo, doc  # type: ignore [attr-defined]
+except ImportError:
+
+    @dataclass(frozen=True, **SLOTS)
+    class DocInfo:  # type: ignore [no-redef]
+        """ "
+        The return value of doc(), mainly to be used by tools that want to extract the
+        Annotated documentation at runtime.
+        """
+
+        documentation: str
+        """The documentation string passed to doc()."""
+
+    def doc(
+        documentation: str,
+    ) -> DocInfo:
+        """
+        Add documentation to a type annotation inside of Annotated.
+
+        For example:
+
+        >>> def hi(name: Annotated[int, doc("The name of the user")]) -> None: ...
+        """
+        return DocInfo(documentation)

+ 0 - 0
.venv/lib/python3.9/site-packages/annotated_types/py.typed


+ 151 - 0
.venv/lib/python3.9/site-packages/annotated_types/test_cases.py

@@ -0,0 +1,151 @@
+import math
+import sys
+from datetime import date, datetime, timedelta, timezone
+from decimal import Decimal
+from typing import Any, Dict, Iterable, Iterator, List, NamedTuple, Set, Tuple
+
+if sys.version_info < (3, 9):
+    from typing_extensions import Annotated
+else:
+    from typing import Annotated
+
+import annotated_types as at
+
+
+class Case(NamedTuple):
+    """
+    A test case for `annotated_types`.
+    """
+
+    annotation: Any
+    valid_cases: Iterable[Any]
+    invalid_cases: Iterable[Any]
+
+
+def cases() -> Iterable[Case]:
+    # Gt, Ge, Lt, Le
+    yield Case(Annotated[int, at.Gt(4)], (5, 6, 1000), (4, 0, -1))
+    yield Case(Annotated[float, at.Gt(0.5)], (0.6, 0.7, 0.8, 0.9), (0.5, 0.0, -0.1))
+    yield Case(
+        Annotated[datetime, at.Gt(datetime(2000, 1, 1))],
+        [datetime(2000, 1, 2), datetime(2000, 1, 3)],
+        [datetime(2000, 1, 1), datetime(1999, 12, 31)],
+    )
+    yield Case(
+        Annotated[datetime, at.Gt(date(2000, 1, 1))],
+        [date(2000, 1, 2), date(2000, 1, 3)],
+        [date(2000, 1, 1), date(1999, 12, 31)],
+    )
+    yield Case(
+        Annotated[datetime, at.Gt(Decimal('1.123'))],
+        [Decimal('1.1231'), Decimal('123')],
+        [Decimal('1.123'), Decimal('0')],
+    )
+
+    yield Case(Annotated[int, at.Ge(4)], (4, 5, 6, 1000, 4), (0, -1))
+    yield Case(Annotated[float, at.Ge(0.5)], (0.5, 0.6, 0.7, 0.8, 0.9), (0.4, 0.0, -0.1))
+    yield Case(
+        Annotated[datetime, at.Ge(datetime(2000, 1, 1))],
+        [datetime(2000, 1, 2), datetime(2000, 1, 3)],
+        [datetime(1998, 1, 1), datetime(1999, 12, 31)],
+    )
+
+    yield Case(Annotated[int, at.Lt(4)], (0, -1), (4, 5, 6, 1000, 4))
+    yield Case(Annotated[float, at.Lt(0.5)], (0.4, 0.0, -0.1), (0.5, 0.6, 0.7, 0.8, 0.9))
+    yield Case(
+        Annotated[datetime, at.Lt(datetime(2000, 1, 1))],
+        [datetime(1999, 12, 31), datetime(1999, 12, 31)],
+        [datetime(2000, 1, 2), datetime(2000, 1, 3)],
+    )
+
+    yield Case(Annotated[int, at.Le(4)], (4, 0, -1), (5, 6, 1000))
+    yield Case(Annotated[float, at.Le(0.5)], (0.5, 0.0, -0.1), (0.6, 0.7, 0.8, 0.9))
+    yield Case(
+        Annotated[datetime, at.Le(datetime(2000, 1, 1))],
+        [datetime(2000, 1, 1), datetime(1999, 12, 31)],
+        [datetime(2000, 1, 2), datetime(2000, 1, 3)],
+    )
+
+    # Interval
+    yield Case(Annotated[int, at.Interval(gt=4)], (5, 6, 1000), (4, 0, -1))
+    yield Case(Annotated[int, at.Interval(gt=4, lt=10)], (5, 6), (4, 10, 1000, 0, -1))
+    yield Case(Annotated[float, at.Interval(ge=0.5, le=1)], (0.5, 0.9, 1), (0.49, 1.1))
+    yield Case(
+        Annotated[datetime, at.Interval(gt=datetime(2000, 1, 1), le=datetime(2000, 1, 3))],
+        [datetime(2000, 1, 2), datetime(2000, 1, 3)],
+        [datetime(2000, 1, 1), datetime(2000, 1, 4)],
+    )
+
+    yield Case(Annotated[int, at.MultipleOf(multiple_of=3)], (0, 3, 9), (1, 2, 4))
+    yield Case(Annotated[float, at.MultipleOf(multiple_of=0.5)], (0, 0.5, 1, 1.5), (0.4, 1.1))
+
+    # lengths
+
+    yield Case(Annotated[str, at.MinLen(3)], ('123', '1234', 'x' * 10), ('', '1', '12'))
+    yield Case(Annotated[str, at.Len(3)], ('123', '1234', 'x' * 10), ('', '1', '12'))
+    yield Case(Annotated[List[int], at.MinLen(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2]))
+    yield Case(Annotated[List[int], at.Len(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2]))
+
+    yield Case(Annotated[str, at.MaxLen(4)], ('', '1234'), ('12345', 'x' * 10))
+    yield Case(Annotated[str, at.Len(0, 4)], ('', '1234'), ('12345', 'x' * 10))
+    yield Case(Annotated[List[str], at.MaxLen(4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10))
+    yield Case(Annotated[List[str], at.Len(0, 4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10))
+
+    yield Case(Annotated[str, at.Len(3, 5)], ('123', '12345'), ('', '1', '12', '123456', 'x' * 10))
+    yield Case(Annotated[str, at.Len(3, 3)], ('123',), ('12', '1234'))
+
+    yield Case(Annotated[Dict[int, int], at.Len(2, 3)], [{1: 1, 2: 2}], [{}, {1: 1}, {1: 1, 2: 2, 3: 3, 4: 4}])
+    yield Case(Annotated[Set[int], at.Len(2, 3)], ({1, 2}, {1, 2, 3}), (set(), {1}, {1, 2, 3, 4}))
+    yield Case(Annotated[Tuple[int, ...], at.Len(2, 3)], ((1, 2), (1, 2, 3)), ((), (1,), (1, 2, 3, 4)))
+
+    # Timezone
+
+    yield Case(
+        Annotated[datetime, at.Timezone(None)], [datetime(2000, 1, 1)], [datetime(2000, 1, 1, tzinfo=timezone.utc)]
+    )
+    yield Case(
+        Annotated[datetime, at.Timezone(...)], [datetime(2000, 1, 1, tzinfo=timezone.utc)], [datetime(2000, 1, 1)]
+    )
+    yield Case(
+        Annotated[datetime, at.Timezone(timezone.utc)],
+        [datetime(2000, 1, 1, tzinfo=timezone.utc)],
+        [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))],
+    )
+    yield Case(
+        Annotated[datetime, at.Timezone('Europe/London')],
+        [datetime(2000, 1, 1, tzinfo=timezone(timedelta(0), name='Europe/London'))],
+        [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))],
+    )
+
+    # Quantity
+
+    yield Case(Annotated[float, at.Unit(unit='m')], (5, 4.2), ('5m', '4.2m'))
+
+    # predicate types
+
+    yield Case(at.LowerCase[str], ['abc', 'foobar'], ['', 'A', 'Boom'])
+    yield Case(at.UpperCase[str], ['ABC', 'DEFO'], ['', 'a', 'abc', 'AbC'])
+    yield Case(at.IsDigit[str], ['123'], ['', 'ab', 'a1b2'])
+    yield Case(at.IsAscii[str], ['123', 'foo bar'], ['£100', '😊', 'whatever 👀'])
+
+    yield Case(Annotated[int, at.Predicate(lambda x: x % 2 == 0)], [0, 2, 4], [1, 3, 5])
+
+    yield Case(at.IsFinite[float], [1.23], [math.nan, math.inf, -math.inf])
+    yield Case(at.IsNotFinite[float], [math.nan, math.inf], [1.23])
+    yield Case(at.IsNan[float], [math.nan], [1.23, math.inf])
+    yield Case(at.IsNotNan[float], [1.23, math.inf], [math.nan])
+    yield Case(at.IsInfinite[float], [math.inf], [math.nan, 1.23])
+    yield Case(at.IsNotInfinite[float], [math.nan, 1.23], [math.inf])
+
+    # check stacked predicates
+    yield Case(at.IsInfinite[Annotated[float, at.Predicate(lambda x: x > 0)]], [math.inf], [-math.inf, 1.23, math.nan])
+
+    # doc
+    yield Case(Annotated[int, at.doc("A number")], [1, 2], [])
+
+    # custom GroupedMetadata
+    class MyCustomGroupedMetadata(at.GroupedMetadata):
+        def __iter__(self) -> Iterator[at.Predicate]:
+            yield at.Predicate(lambda x: float(x).is_integer())
+
+    yield Case(Annotated[float, MyCustomGroupedMetadata()], [0, 2.0], [0.01, 1.5])

+ 1 - 0
.venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/INSTALLER

@@ -0,0 +1 @@
+pip

+ 96 - 0
.venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/METADATA

@@ -0,0 +1,96 @@
+Metadata-Version: 2.4
+Name: anyio
+Version: 4.12.1
+Summary: High-level concurrency and networking framework on top of asyncio or Trio
+Author-email: Alex Grönholm <alex.gronholm@nextday.fi>
+License-Expression: MIT
+Project-URL: Documentation, https://anyio.readthedocs.io/en/latest/
+Project-URL: Changelog, https://anyio.readthedocs.io/en/stable/versionhistory.html
+Project-URL: Source code, https://github.com/agronholm/anyio
+Project-URL: Issue tracker, https://github.com/agronholm/anyio/issues
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: Framework :: AnyIO
+Classifier: Typing :: Typed
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
+Requires-Python: >=3.9
+Description-Content-Type: text/x-rst
+License-File: LICENSE
+Requires-Dist: exceptiongroup>=1.0.2; python_version < "3.11"
+Requires-Dist: idna>=2.8
+Requires-Dist: typing_extensions>=4.5; python_version < "3.13"
+Provides-Extra: trio
+Requires-Dist: trio>=0.32.0; python_version >= "3.10" and extra == "trio"
+Requires-Dist: trio>=0.31.0; python_version < "3.10" and extra == "trio"
+Dynamic: license-file
+
+.. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg
+  :target: https://github.com/agronholm/anyio/actions/workflows/test.yml
+  :alt: Build Status
+.. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master
+  :target: https://coveralls.io/github/agronholm/anyio?branch=master
+  :alt: Code Coverage
+.. image:: https://readthedocs.org/projects/anyio/badge/?version=latest
+  :target: https://anyio.readthedocs.io/en/latest/?badge=latest
+  :alt: Documentation
+.. image:: https://badges.gitter.im/gitterHQ/gitter.svg
+  :target: https://gitter.im/python-trio/AnyIO
+  :alt: Gitter chat
+
+AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or
+Trio_. It implements Trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony
+with the native SC of Trio itself.
+
+Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or
+Trio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full
+refactoring necessary. It will blend in with the native libraries of your chosen backend.
+
+To find out why you might want to use AnyIO's APIs instead of asyncio's, you can read about it
+`here <https://anyio.readthedocs.io/en/stable/why.html>`_.
+
+Documentation
+-------------
+
+View full documentation at: https://anyio.readthedocs.io/
+
+Features
+--------
+
+AnyIO offers the following functionality:
+
+* Task groups (nurseries_ in trio terminology)
+* High-level networking (TCP, UDP and UNIX sockets)
+
+  * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python
+    3.8)
+  * async/await style UDP sockets (unlike asyncio where you still have to use Transports and
+    Protocols)
+
+* A versatile API for byte streams and object streams
+* Inter-task synchronization and communication (locks, conditions, events, semaphores, object
+  streams)
+* Worker threads
+* Subprocesses
+* Subinterpreter support for code parallelization (on Python 3.13 and later)
+* Asynchronous file I/O (using worker threads)
+* Signal handling
+* Asynchronous version of the functools_ module
+
+AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures.
+It even works with the popular Hypothesis_ library.
+
+.. _asyncio: https://docs.python.org/3/library/asyncio.html
+.. _Trio: https://github.com/python-trio/trio
+.. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency
+.. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning
+.. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs
+.. _pytest: https://docs.pytest.org/en/latest/
+.. _functools: https://docs.python.org/3/library/functools.html
+.. _Hypothesis: https://hypothesis.works/

+ 92 - 0
.venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/RECORD

@@ -0,0 +1,92 @@
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/__init__.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_backends/__init__.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_backends/_asyncio.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_backends/_trio.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/__init__.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_asyncio_selector_thread.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_contextmanagers.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_eventloop.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_exceptions.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_fileio.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_resources.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_signals.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_sockets.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_streams.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_subprocesses.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_synchronization.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_tasks.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_tempfile.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_testing.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/_core/_typedattr.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/abc/__init__.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/abc/_eventloop.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/abc/_resources.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/abc/_sockets.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/abc/_streams.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/abc/_subprocesses.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/abc/_tasks.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/abc/_testing.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/from_thread.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/functools.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/lowlevel.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/pytest_plugin.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/streams/__init__.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/streams/buffered.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/streams/file.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/streams/memory.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/streams/stapled.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/streams/text.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/streams/tls.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/to_interpreter.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/to_process.cpython-39.pyc,,
+../../../../../../../../../../Library/Caches/com.apple.python/Users/dq1968/Documents/Codex/2026-07-02/he/outputs/正式使用-格士立本体开发环境/.venv/lib/python3.9/site-packages/anyio/to_thread.cpython-39.pyc,,
+anyio-4.12.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+anyio-4.12.1.dist-info/METADATA,sha256=DfiDab9Tmmcfy802lOLTMEHJQShkOSbopCwqCYbLuJk,4277
+anyio-4.12.1.dist-info/RECORD,,
+anyio-4.12.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
+anyio-4.12.1.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39
+anyio-4.12.1.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081
+anyio-4.12.1.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6
+anyio/__init__.py,sha256=7iDVqMUprUuKNY91FuoKqayAhR-OY136YDPI6P78HHk,6170
+anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+anyio/_backends/_asyncio.py,sha256=xG6qv60mgGnL0mK82dxjH2b8hlkMlJ-x2BqIq3qv70Y,98863
+anyio/_backends/_trio.py,sha256=30Rctb7lm8g63ZHljVPVnj5aH-uK6oQvphjwUBoAzuI,41456
+anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626
+anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215
+anyio/_core/_eventloop.py,sha256=c2EdcBX-xnKwxPcC4Pjn3_qG9I-x4IWFO2R9RqCGjM4,6448
+anyio/_core/_exceptions.py,sha256=Y3aq-Wxd7Q2HqwSg7nZPvRsHEuGazv_qeet6gqEBdPk,4407
+anyio/_core/_fileio.py,sha256=uc7t10Vb-If7GbdWM_zFf-ajUe6uek63fSt7IBLlZW0,25731
+anyio/_core/_resources.py,sha256=NbmU5O5UX3xEyACnkmYX28Fmwdl-f-ny0tHym26e0w0,435
+anyio/_core/_signals.py,sha256=mjTBB2hTKNPRlU0IhnijeQedpWOGERDiMjSlJQsFrug,1016
+anyio/_core/_sockets.py,sha256=RBXHcUqZt5gg_-OOfgHVv8uq2FSKk1uVUzTdpjBoI1o,34977
+anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806
+anyio/_core/_subprocesses.py,sha256=EXm5igL7dj55iYkPlbYVAqtbqxJxjU-6OndSTIx9SRg,8047
+anyio/_core/_synchronization.py,sha256=MgVVqFzvt580tHC31LiOcq1G6aryut--xRG4Ff8KwxQ,20869
+anyio/_core/_tasks.py,sha256=pVB7K6AAulzUM8YgXAeqNZG44nSyZ1bYJjH8GznC00I,5435
+anyio/_core/_tempfile.py,sha256=lHb7CW4FyIlpkf5ADAf4VmLHCKwEHF9nxqNyBCFFUiA,19697
+anyio/_core/_testing.py,sha256=u7MPqGXwpTxqI7hclSdNA30z2GH1Nw258uwKvy_RfBg,2340
+anyio/_core/_typedattr.py,sha256=P4ozZikn3-DbpoYcvyghS_FOYAgbmUxeoU8-L_07pZM,2508
+anyio/abc/__init__.py,sha256=6mWhcl_pGXhrgZVHP_TCfMvIXIOp9mroEFM90fYCU_U,2869
+anyio/abc/_eventloop.py,sha256=GlzgB3UJGgG6Kr7olpjOZ-o00PghecXuofVDQ_5611Q,10749
+anyio/abc/_resources.py,sha256=DrYvkNN1hH6Uvv5_5uKySvDsnknGVDe8FCKfko0VtN8,783
+anyio/abc/_sockets.py,sha256=ECTY0jLEF18gryANHR3vFzXzGdZ-xPwELq1QdgOb0Jo,13258
+anyio/abc/_streams.py,sha256=005GKSCXGprxnhucILboSqc2JFovECZk9m3p-qqxXVc,7640
+anyio/abc/_subprocesses.py,sha256=cumAPJTktOQtw63IqG0lDpyZqu_l1EElvQHMiwJgL08,2067
+anyio/abc/_tasks.py,sha256=KC7wrciE48AINOI-AhPutnFhe1ewfP7QnamFlDzqesQ,3721
+anyio/abc/_testing.py,sha256=tBJUzkSfOXJw23fe8qSJ03kJlShOYjjaEyFB6k6MYT8,1821
+anyio/from_thread.py,sha256=L-0w1HxJ6BSb-KuVi57k5Tkc3yzQrx3QK5tAxMPcY-0,19141
+anyio/functools.py,sha256=HWj7GBEmc0Z-mZg3uok7Z7ZJn0rEC_0Pzbt0nYUDaTQ,10973
+anyio/lowlevel.py,sha256=AyKLVK3LaWSoK39LkCKxE4_GDMLKZBNqTrLUgk63y80,5158
+anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+anyio/pytest_plugin.py,sha256=3jAFQn0jv_pyoWE2GBBlHaj9sqXj4e8vob0_hgrsXE8,10244
+anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+anyio/streams/buffered.py,sha256=2R3PeJhe4EXrdYqz44Y6-Eg9R6DrmlsYrP36Ir43-po,6263
+anyio/streams/file.py,sha256=4WZ7XGz5WNu39FQHvqbe__TQ0HDP9OOhgO1mk9iVpVU,4470
+anyio/streams/memory.py,sha256=F0zwzvFJKAhX_LRZGoKzzqDC2oMM-f-yyTBrEYEGOaU,10740
+anyio/streams/stapled.py,sha256=T8Xqwf8K6EgURPxbt1N4i7A8BAk-gScv-GRhjLXIf_o,4390
+anyio/streams/text.py,sha256=BcVAGJw1VRvtIqnv-o0Rb0pwH7p8vwlvl21xHq522ag,5765
+anyio/streams/tls.py,sha256=Jpxy0Mfbcp1BxHCwE-YjSSFaLnIBbnnwur-excYThs4,15368
+anyio/to_interpreter.py,sha256=_mLngrMy97TMR6VbW4Y6YzDUk9ZuPcQMPlkuyRh3C9k,7100
+anyio/to_process.py,sha256=J7gAA_YOuoHqnpDAf5fm1Qu6kOmTzdFbiDNvnV755vk,9798
+anyio/to_thread.py,sha256=menEgXYmUV7Fjg_9WqCV95P9MAtQS8BzPGGcWB_QnfQ,2687

+ 5 - 0
.venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/WHEEL

@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: setuptools (80.9.0)
+Root-Is-Purelib: true
+Tag: py3-none-any
+

+ 2 - 0
.venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/entry_points.txt

@@ -0,0 +1,2 @@
+[pytest11]
+anyio = anyio.pytest_plugin

+ 20 - 0
.venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/licenses/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Alex Grönholm
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 1 - 0
.venv/lib/python3.9/site-packages/anyio-4.12.1.dist-info/top_level.txt

@@ -0,0 +1 @@
+anyio

+ 111 - 0
.venv/lib/python3.9/site-packages/anyio/__init__.py

@@ -0,0 +1,111 @@
+from __future__ import annotations
+
+from ._core._contextmanagers import AsyncContextManagerMixin as AsyncContextManagerMixin
+from ._core._contextmanagers import ContextManagerMixin as ContextManagerMixin
+from ._core._eventloop import current_time as current_time
+from ._core._eventloop import get_all_backends as get_all_backends
+from ._core._eventloop import get_available_backends as get_available_backends
+from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class
+from ._core._eventloop import run as run
+from ._core._eventloop import sleep as sleep
+from ._core._eventloop import sleep_forever as sleep_forever
+from ._core._eventloop import sleep_until as sleep_until
+from ._core._exceptions import BrokenResourceError as BrokenResourceError
+from ._core._exceptions import BrokenWorkerInterpreter as BrokenWorkerInterpreter
+from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess
+from ._core._exceptions import BusyResourceError as BusyResourceError
+from ._core._exceptions import ClosedResourceError as ClosedResourceError
+from ._core._exceptions import ConnectionFailed as ConnectionFailed
+from ._core._exceptions import DelimiterNotFound as DelimiterNotFound
+from ._core._exceptions import EndOfStream as EndOfStream
+from ._core._exceptions import IncompleteRead as IncompleteRead
+from ._core._exceptions import NoEventLoopError as NoEventLoopError
+from ._core._exceptions import RunFinishedError as RunFinishedError
+from ._core._exceptions import TypedAttributeLookupError as TypedAttributeLookupError
+from ._core._exceptions import WouldBlock as WouldBlock
+from ._core._fileio import AsyncFile as AsyncFile
+from ._core._fileio import Path as Path
+from ._core._fileio import open_file as open_file
+from ._core._fileio import wrap_file as wrap_file
+from ._core._resources import aclose_forcefully as aclose_forcefully
+from ._core._signals import open_signal_receiver as open_signal_receiver
+from ._core._sockets import TCPConnectable as TCPConnectable
+from ._core._sockets import UNIXConnectable as UNIXConnectable
+from ._core._sockets import as_connectable as as_connectable
+from ._core._sockets import connect_tcp as connect_tcp
+from ._core._sockets import connect_unix as connect_unix
+from ._core._sockets import create_connected_udp_socket as create_connected_udp_socket
+from ._core._sockets import (
+    create_connected_unix_datagram_socket as create_connected_unix_datagram_socket,
+)
+from ._core._sockets import create_tcp_listener as create_tcp_listener
+from ._core._sockets import create_udp_socket as create_udp_socket
+from ._core._sockets import create_unix_datagram_socket as create_unix_datagram_socket
+from ._core._sockets import create_unix_listener as create_unix_listener
+from ._core._sockets import getaddrinfo as getaddrinfo
+from ._core._sockets import getnameinfo as getnameinfo
+from ._core._sockets import notify_closing as notify_closing
+from ._core._sockets import wait_readable as wait_readable
+from ._core._sockets import wait_socket_readable as wait_socket_readable
+from ._core._sockets import wait_socket_writable as wait_socket_writable
+from ._core._sockets import wait_writable as wait_writable
+from ._core._streams import create_memory_object_stream as create_memory_object_stream
+from ._core._subprocesses import open_process as open_process
+from ._core._subprocesses import run_process as run_process
+from ._core._synchronization import CapacityLimiter as CapacityLimiter
+from ._core._synchronization import (
+    CapacityLimiterStatistics as CapacityLimiterStatistics,
+)
+from ._core._synchronization import Condition as Condition
+from ._core._synchronization import ConditionStatistics as ConditionStatistics
+from ._core._synchronization import Event as Event
+from ._core._synchronization import EventStatistics as EventStatistics
+from ._core._synchronization import Lock as Lock
+from ._core._synchronization import LockStatistics as LockStatistics
+from ._core._synchronization import ResourceGuard as ResourceGuard
+from ._core._synchronization import Semaphore as Semaphore
+from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics
+from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED
+from ._core._tasks import CancelScope as CancelScope
+from ._core._tasks import create_task_group as create_task_group
+from ._core._tasks import current_effective_deadline as current_effective_deadline
+from ._core._tasks import fail_after as fail_after
+from ._core._tasks import move_on_after as move_on_after
+from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile
+from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile
+from ._core._tempfile import TemporaryDirectory as TemporaryDirectory
+from ._core._tempfile import TemporaryFile as TemporaryFile
+from ._core._tempfile import gettempdir as gettempdir
+from ._core._tempfile import gettempdirb as gettempdirb
+from ._core._tempfile import mkdtemp as mkdtemp
+from ._core._tempfile import mkstemp as mkstemp
+from ._core._testing import TaskInfo as TaskInfo
+from ._core._testing import get_current_task as get_current_task
+from ._core._testing import get_running_tasks as get_running_tasks
+from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked
+from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider
+from ._core._typedattr import TypedAttributeSet as TypedAttributeSet
+from ._core._typedattr import typed_attribute as typed_attribute
+
+# Re-export imports so they look like they live directly in this package
+for __value in list(locals().values()):
+    if getattr(__value, "__module__", "").startswith("anyio."):
+        __value.__module__ = __name__
+
+
+del __value
+
+
+def __getattr__(attr: str) -> type[BrokenWorkerInterpreter]:
+    """Support deprecated aliases."""
+    if attr == "BrokenWorkerIntepreter":
+        import warnings
+
+        warnings.warn(
+            "The 'BrokenWorkerIntepreter' alias is deprecated, use 'BrokenWorkerInterpreter' instead.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        return BrokenWorkerInterpreter
+
+    raise AttributeError(f"module {__name__!r} has no attribute {attr!r}")

+ 0 - 0
.venv/lib/python3.9/site-packages/anyio/_backends/__init__.py


+ 2980 - 0
.venv/lib/python3.9/site-packages/anyio/_backends/_asyncio.py

@@ -0,0 +1,2980 @@
+from __future__ import annotations
+
+import array
+import asyncio
+import concurrent.futures
+import contextvars
+import math
+import os
+import socket
+import sys
+import threading
+import weakref
+from asyncio import (
+    AbstractEventLoop,
+    CancelledError,
+    all_tasks,
+    create_task,
+    current_task,
+    get_running_loop,
+    sleep,
+)
+from asyncio.base_events import _run_until_complete_cb  # type: ignore[attr-defined]
+from collections import OrderedDict, deque
+from collections.abc import (
+    AsyncGenerator,
+    AsyncIterator,
+    Awaitable,
+    Callable,
+    Collection,
+    Coroutine,
+    Iterable,
+    Sequence,
+)
+from concurrent.futures import Future
+from contextlib import AbstractContextManager, suppress
+from contextvars import Context, copy_context
+from dataclasses import dataclass, field
+from functools import partial, wraps
+from inspect import (
+    CORO_RUNNING,
+    CORO_SUSPENDED,
+    getcoroutinestate,
+    iscoroutine,
+)
+from io import IOBase
+from os import PathLike
+from queue import Queue
+from signal import Signals
+from socket import AddressFamily, SocketKind
+from threading import Thread
+from types import CodeType, TracebackType
+from typing import (
+    IO,
+    TYPE_CHECKING,
+    Any,
+    Optional,
+    TypeVar,
+    cast,
+)
+from weakref import WeakKeyDictionary
+
+from .. import (
+    CapacityLimiterStatistics,
+    EventStatistics,
+    LockStatistics,
+    TaskInfo,
+    abc,
+)
+from .._core._eventloop import (
+    claim_worker_thread,
+    set_current_async_library,
+    threadlocals,
+)
+from .._core._exceptions import (
+    BrokenResourceError,
+    BusyResourceError,
+    ClosedResourceError,
+    EndOfStream,
+    RunFinishedError,
+    WouldBlock,
+    iterate_exceptions,
+)
+from .._core._sockets import convert_ipv6_sockaddr
+from .._core._streams import create_memory_object_stream
+from .._core._synchronization import (
+    CapacityLimiter as BaseCapacityLimiter,
+)
+from .._core._synchronization import Event as BaseEvent
+from .._core._synchronization import Lock as BaseLock
+from .._core._synchronization import (
+    ResourceGuard,
+    SemaphoreStatistics,
+)
+from .._core._synchronization import Semaphore as BaseSemaphore
+from .._core._tasks import CancelScope as BaseCancelScope
+from ..abc import (
+    AsyncBackend,
+    IPSockAddrType,
+    SocketListener,
+    UDPPacketType,
+    UNIXDatagramPacketType,
+)
+from ..abc._eventloop import StrOrBytesPath
+from ..lowlevel import RunVar
+from ..streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
+
+if TYPE_CHECKING:
+    from _typeshed import FileDescriptorLike
+else:
+    FileDescriptorLike = object
+
+if sys.version_info >= (3, 10):
+    from typing import ParamSpec
+else:
+    from typing_extensions import ParamSpec
+
+if sys.version_info >= (3, 11):
+    from asyncio import Runner
+    from typing import TypeVarTuple, Unpack
+else:
+    import contextvars
+    import enum
+    import signal
+    from asyncio import coroutines, events, exceptions, tasks
+
+    from exceptiongroup import BaseExceptionGroup
+    from typing_extensions import TypeVarTuple, Unpack
+
+    class _State(enum.Enum):
+        CREATED = "created"
+        INITIALIZED = "initialized"
+        CLOSED = "closed"
+
+    class Runner:
+        # Copied from CPython 3.11
+        def __init__(
+            self,
+            *,
+            debug: bool | None = None,
+            loop_factory: Callable[[], AbstractEventLoop] | None = None,
+        ):
+            self._state = _State.CREATED
+            self._debug = debug
+            self._loop_factory = loop_factory
+            self._loop: AbstractEventLoop | None = None
+            self._context = None
+            self._interrupt_count = 0
+            self._set_event_loop = False
+
+        def __enter__(self) -> Runner:
+            self._lazy_init()
+            return self
+
+        def __exit__(
+            self,
+            exc_type: type[BaseException] | None,
+            exc_val: BaseException | None,
+            exc_tb: TracebackType | None,
+        ) -> None:
+            self.close()
+
+        def close(self) -> None:
+            """Shutdown and close event loop."""
+            loop = self._loop
+            if self._state is not _State.INITIALIZED or loop is None:
+                return
+            try:
+                _cancel_all_tasks(loop)
+                loop.run_until_complete(loop.shutdown_asyncgens())
+                if hasattr(loop, "shutdown_default_executor"):
+                    loop.run_until_complete(loop.shutdown_default_executor())
+                else:
+                    loop.run_until_complete(_shutdown_default_executor(loop))
+            finally:
+                if self._set_event_loop:
+                    events.set_event_loop(None)
+                loop.close()
+                self._loop = None
+                self._state = _State.CLOSED
+
+        def get_loop(self) -> AbstractEventLoop:
+            """Return embedded event loop."""
+            self._lazy_init()
+            return self._loop
+
+        def run(self, coro: Coroutine[T_Retval], *, context=None) -> T_Retval:
+            """Run a coroutine inside the embedded event loop."""
+            if not coroutines.iscoroutine(coro):
+                raise ValueError(f"a coroutine was expected, got {coro!r}")
+
+            if events._get_running_loop() is not None:
+                # fail fast with short traceback
+                raise RuntimeError(
+                    "Runner.run() cannot be called from a running event loop"
+                )
+
+            self._lazy_init()
+
+            if context is None:
+                context = self._context
+            task = context.run(self._loop.create_task, coro)
+
+            if (
+                threading.current_thread() is threading.main_thread()
+                and signal.getsignal(signal.SIGINT) is signal.default_int_handler
+            ):
+                sigint_handler = partial(self._on_sigint, main_task=task)
+                try:
+                    signal.signal(signal.SIGINT, sigint_handler)
+                except ValueError:
+                    # `signal.signal` may throw if `threading.main_thread` does
+                    # not support signals (e.g. embedded interpreter with signals
+                    # not registered - see gh-91880)
+                    sigint_handler = None
+            else:
+                sigint_handler = None
+
+            self._interrupt_count = 0
+            try:
+                return self._loop.run_until_complete(task)
+            except exceptions.CancelledError:
+                if self._interrupt_count > 0:
+                    uncancel = getattr(task, "uncancel", None)
+                    if uncancel is not None and uncancel() == 0:
+                        raise KeyboardInterrupt  # noqa: B904
+                raise  # CancelledError
+            finally:
+                if (
+                    sigint_handler is not None
+                    and signal.getsignal(signal.SIGINT) is sigint_handler
+                ):
+                    signal.signal(signal.SIGINT, signal.default_int_handler)
+
+        def _lazy_init(self) -> None:
+            if self._state is _State.CLOSED:
+                raise RuntimeError("Runner is closed")
+            if self._state is _State.INITIALIZED:
+                return
+            if self._loop_factory is None:
+                self._loop = events.new_event_loop()
+                if not self._set_event_loop:
+                    # Call set_event_loop only once to avoid calling
+                    # attach_loop multiple times on child watchers
+                    events.set_event_loop(self._loop)
+                    self._set_event_loop = True
+            else:
+                self._loop = self._loop_factory()
+            if self._debug is not None:
+                self._loop.set_debug(self._debug)
+            self._context = contextvars.copy_context()
+            self._state = _State.INITIALIZED
+
+        def _on_sigint(self, signum, frame, main_task: asyncio.Task) -> None:
+            self._interrupt_count += 1
+            if self._interrupt_count == 1 and not main_task.done():
+                main_task.cancel()
+                # wakeup loop if it is blocked by select() with long timeout
+                self._loop.call_soon_threadsafe(lambda: None)
+                return
+            raise KeyboardInterrupt()
+
+    def _cancel_all_tasks(loop: AbstractEventLoop) -> None:
+        to_cancel = tasks.all_tasks(loop)
+        if not to_cancel:
+            return
+
+        for task in to_cancel:
+            task.cancel()
+
+        loop.run_until_complete(tasks.gather(*to_cancel, return_exceptions=True))
+
+        for task in to_cancel:
+            if task.cancelled():
+                continue
+            if task.exception() is not None:
+                loop.call_exception_handler(
+                    {
+                        "message": "unhandled exception during asyncio.run() shutdown",
+                        "exception": task.exception(),
+                        "task": task,
+                    }
+                )
+
+    async def _shutdown_default_executor(loop: AbstractEventLoop) -> None:
+        """Schedule the shutdown of the default executor."""
+
+        def _do_shutdown(future: asyncio.futures.Future) -> None:
+            try:
+                loop._default_executor.shutdown(wait=True)  # type: ignore[attr-defined]
+                loop.call_soon_threadsafe(future.set_result, None)
+            except Exception as ex:
+                loop.call_soon_threadsafe(future.set_exception, ex)
+
+        loop._executor_shutdown_called = True
+        if loop._default_executor is None:
+            return
+        future = loop.create_future()
+        thread = threading.Thread(target=_do_shutdown, args=(future,))
+        thread.start()
+        try:
+            await future
+        finally:
+            thread.join()
+
+
+T_Retval = TypeVar("T_Retval")
+T_contra = TypeVar("T_contra", contravariant=True)
+PosArgsT = TypeVarTuple("PosArgsT")
+P = ParamSpec("P")
+
+_root_task: RunVar[asyncio.Task | None] = RunVar("_root_task")
+
+
+def find_root_task() -> asyncio.Task:
+    root_task = _root_task.get(None)
+    if root_task is not None and not root_task.done():
+        return root_task
+
+    # Look for a task that has been started via run_until_complete()
+    for task in all_tasks():
+        if task._callbacks and not task.done():
+            callbacks = [cb for cb, context in task._callbacks]
+            for cb in callbacks:
+                if (
+                    cb is _run_until_complete_cb
+                    or getattr(cb, "__module__", None) == "uvloop.loop"
+                ):
+                    _root_task.set(task)
+                    return task
+
+    # Look up the topmost task in the AnyIO task tree, if possible
+    task = cast(asyncio.Task, current_task())
+    state = _task_states.get(task)
+    if state:
+        cancel_scope = state.cancel_scope
+        while cancel_scope and cancel_scope._parent_scope is not None:
+            cancel_scope = cancel_scope._parent_scope
+
+        if cancel_scope is not None:
+            return cast(asyncio.Task, cancel_scope._host_task)
+
+    return task
+
+
+def get_callable_name(func: Callable) -> str:
+    module = getattr(func, "__module__", None)
+    qualname = getattr(func, "__qualname__", None)
+    return ".".join([x for x in (module, qualname) if x])
+
+
+#
+# Event loop
+#
+
+_run_vars: WeakKeyDictionary[asyncio.AbstractEventLoop, Any] = WeakKeyDictionary()
+
+
+def _task_started(task: asyncio.Task) -> bool:
+    """Return ``True`` if the task has been started and has not finished."""
+    # The task coro should never be None here, as we never add finished tasks to the
+    # task list
+    coro = task.get_coro()
+    assert coro is not None
+    try:
+        return getcoroutinestate(coro) in (CORO_RUNNING, CORO_SUSPENDED)
+    except AttributeError:
+        # task coro is async_genenerator_asend https://bugs.python.org/issue37771
+        raise Exception(f"Cannot determine if task {task} has started or not") from None
+
+
+#
+# Timeouts and cancellation
+#
+
+
+def is_anyio_cancellation(exc: CancelledError) -> bool:
+    # Sometimes third party frameworks catch a CancelledError and raise a new one, so as
+    # a workaround we have to look at the previous ones in __context__ too for a
+    # matching cancel message
+    while True:
+        if (
+            exc.args
+            and isinstance(exc.args[0], str)
+            and exc.args[0].startswith("Cancelled via cancel scope ")
+        ):
+            return True
+
+        if isinstance(exc.__context__, CancelledError):
+            exc = exc.__context__
+            continue
+
+        return False
+
+
+class CancelScope(BaseCancelScope):
+    def __new__(
+        cls, *, deadline: float = math.inf, shield: bool = False
+    ) -> CancelScope:
+        return object.__new__(cls)
+
+    def __init__(self, deadline: float = math.inf, shield: bool = False):
+        self._deadline = deadline
+        self._shield = shield
+        self._parent_scope: CancelScope | None = None
+        self._child_scopes: set[CancelScope] = set()
+        self._cancel_called = False
+        self._cancel_reason: str | None = None
+        self._cancelled_caught = False
+        self._active = False
+        self._timeout_handle: asyncio.TimerHandle | None = None
+        self._cancel_handle: asyncio.Handle | None = None
+        self._tasks: set[asyncio.Task] = set()
+        self._host_task: asyncio.Task | None = None
+        if sys.version_info >= (3, 11):
+            self._pending_uncancellations: int | None = 0
+        else:
+            self._pending_uncancellations = None
+
+    def __enter__(self) -> CancelScope:
+        if self._active:
+            raise RuntimeError(
+                "Each CancelScope may only be used for a single 'with' block"
+            )
+
+        self._host_task = host_task = cast(asyncio.Task, current_task())
+        self._tasks.add(host_task)
+        try:
+            task_state = _task_states[host_task]
+        except KeyError:
+            task_state = TaskState(None, self)
+            _task_states[host_task] = task_state
+        else:
+            self._parent_scope = task_state.cancel_scope
+            task_state.cancel_scope = self
+            if self._parent_scope is not None:
+                # If using an eager task factory, the parent scope may not even contain
+                # the host task
+                self._parent_scope._child_scopes.add(self)
+                self._parent_scope._tasks.discard(host_task)
+
+        self._timeout()
+        self._active = True
+
+        # Start cancelling the host task if the scope was cancelled before entering
+        if self._cancel_called:
+            self._deliver_cancellation(self)
+
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> bool:
+        del exc_tb
+
+        if not self._active:
+            raise RuntimeError("This cancel scope is not active")
+        if current_task() is not self._host_task:
+            raise RuntimeError(
+                "Attempted to exit cancel scope in a different task than it was "
+                "entered in"
+            )
+
+        assert self._host_task is not None
+        host_task_state = _task_states.get(self._host_task)
+        if host_task_state is None or host_task_state.cancel_scope is not self:
+            raise RuntimeError(
+                "Attempted to exit a cancel scope that isn't the current tasks's "
+                "current cancel scope"
+            )
+
+        try:
+            self._active = False
+            if self._timeout_handle:
+                self._timeout_handle.cancel()
+                self._timeout_handle = None
+
+            self._tasks.remove(self._host_task)
+            if self._parent_scope is not None:
+                self._parent_scope._child_scopes.remove(self)
+                self._parent_scope._tasks.add(self._host_task)
+
+            host_task_state.cancel_scope = self._parent_scope
+
+            # Restart the cancellation effort in the closest visible, cancelled parent
+            # scope if necessary
+            self._restart_cancellation_in_parent()
+
+            # We only swallow the exception iff it was an AnyIO CancelledError, either
+            # directly as exc_val or inside an exception group and there are no cancelled
+            # parent cancel scopes visible to us here
+            if self._cancel_called and not self._parent_cancellation_is_visible_to_us:
+                # For each level-cancel() call made on the host task, call uncancel()
+                while self._pending_uncancellations:
+                    self._host_task.uncancel()
+                    self._pending_uncancellations -= 1
+
+                # Update cancelled_caught and check for exceptions we must not swallow
+                cannot_swallow_exc_val = False
+                if exc_val is not None:
+                    for exc in iterate_exceptions(exc_val):
+                        if isinstance(exc, CancelledError) and is_anyio_cancellation(
+                            exc
+                        ):
+                            self._cancelled_caught = True
+                        else:
+                            cannot_swallow_exc_val = True
+
+                return self._cancelled_caught and not cannot_swallow_exc_val
+            else:
+                if self._pending_uncancellations:
+                    assert self._parent_scope is not None
+                    assert self._parent_scope._pending_uncancellations is not None
+                    self._parent_scope._pending_uncancellations += (
+                        self._pending_uncancellations
+                    )
+                    self._pending_uncancellations = 0
+
+                return False
+        finally:
+            self._host_task = None
+            del exc_val
+
+    @property
+    def _effectively_cancelled(self) -> bool:
+        cancel_scope: CancelScope | None = self
+        while cancel_scope is not None:
+            if cancel_scope._cancel_called:
+                return True
+
+            if cancel_scope.shield:
+                return False
+
+            cancel_scope = cancel_scope._parent_scope
+
+        return False
+
+    @property
+    def _parent_cancellation_is_visible_to_us(self) -> bool:
+        return (
+            self._parent_scope is not None
+            and not self.shield
+            and self._parent_scope._effectively_cancelled
+        )
+
+    def _timeout(self) -> None:
+        if self._deadline != math.inf:
+            loop = get_running_loop()
+            if loop.time() >= self._deadline:
+                self.cancel("deadline exceeded")
+            else:
+                self._timeout_handle = loop.call_at(self._deadline, self._timeout)
+
+    def _deliver_cancellation(self, origin: CancelScope) -> bool:
+        """
+        Deliver cancellation to directly contained tasks and nested cancel scopes.
+
+        Schedule another run at the end if we still have tasks eligible for
+        cancellation.
+
+        :param origin: the cancel scope that originated the cancellation
+        :return: ``True`` if the delivery needs to be retried on the next cycle
+
+        """
+        should_retry = False
+        current = current_task()
+        for task in self._tasks:
+            should_retry = True
+            if task._must_cancel:  # type: ignore[attr-defined]
+                continue
+
+            # The task is eligible for cancellation if it has started
+            if task is not current and (task is self._host_task or _task_started(task)):
+                waiter = task._fut_waiter  # type: ignore[attr-defined]
+                if not isinstance(waiter, asyncio.Future) or not waiter.done():
+                    task.cancel(origin._cancel_reason)
+                    if (
+                        task is origin._host_task
+                        and origin._pending_uncancellations is not None
+                    ):
+                        origin._pending_uncancellations += 1
+
+        # Deliver cancellation to child scopes that aren't shielded or running their own
+        # cancellation callbacks
+        for scope in self._child_scopes:
+            if not scope._shield and not scope.cancel_called:
+                should_retry = scope._deliver_cancellation(origin) or should_retry
+
+        # Schedule another callback if there are still tasks left
+        if origin is self:
+            if should_retry:
+                self._cancel_handle = get_running_loop().call_soon(
+                    self._deliver_cancellation, origin
+                )
+            else:
+                self._cancel_handle = None
+
+        return should_retry
+
+    def _restart_cancellation_in_parent(self) -> None:
+        """
+        Restart the cancellation effort in the closest directly cancelled parent scope.
+
+        """
+        scope = self._parent_scope
+        while scope is not None:
+            if scope._cancel_called:
+                if scope._cancel_handle is None:
+                    scope._deliver_cancellation(scope)
+
+                break
+
+            # No point in looking beyond any shielded scope
+            if scope._shield:
+                break
+
+            scope = scope._parent_scope
+
+    def cancel(self, reason: str | None = None) -> None:
+        if not self._cancel_called:
+            if self._timeout_handle:
+                self._timeout_handle.cancel()
+                self._timeout_handle = None
+
+            self._cancel_called = True
+            self._cancel_reason = f"Cancelled via cancel scope {id(self):x}"
+            if task := current_task():
+                self._cancel_reason += f" by {task}"
+
+            if reason:
+                self._cancel_reason += f"; reason: {reason}"
+
+            if self._host_task is not None:
+                self._deliver_cancellation(self)
+
+    @property
+    def deadline(self) -> float:
+        return self._deadline
+
+    @deadline.setter
+    def deadline(self, value: float) -> None:
+        self._deadline = float(value)
+        if self._timeout_handle is not None:
+            self._timeout_handle.cancel()
+            self._timeout_handle = None
+
+        if self._active and not self._cancel_called:
+            self._timeout()
+
+    @property
+    def cancel_called(self) -> bool:
+        return self._cancel_called
+
+    @property
+    def cancelled_caught(self) -> bool:
+        return self._cancelled_caught
+
+    @property
+    def shield(self) -> bool:
+        return self._shield
+
+    @shield.setter
+    def shield(self, value: bool) -> None:
+        if self._shield != value:
+            self._shield = value
+            if not value:
+                self._restart_cancellation_in_parent()
+
+
+#
+# Task states
+#
+
+
+class TaskState:
+    """
+    Encapsulates auxiliary task information that cannot be added to the Task instance
+    itself because there are no guarantees about its implementation.
+    """
+
+    __slots__ = "parent_id", "cancel_scope", "__weakref__"
+
+    def __init__(self, parent_id: int | None, cancel_scope: CancelScope | None):
+        self.parent_id = parent_id
+        self.cancel_scope = cancel_scope
+
+
+_task_states: WeakKeyDictionary[asyncio.Task, TaskState] = WeakKeyDictionary()
+
+
+#
+# Task groups
+#
+
+
+class _AsyncioTaskStatus(abc.TaskStatus):
+    def __init__(self, future: asyncio.Future, parent_id: int):
+        self._future = future
+        self._parent_id = parent_id
+
+    def started(self, value: T_contra | None = None) -> None:
+        try:
+            self._future.set_result(value)
+        except asyncio.InvalidStateError:
+            if not self._future.cancelled():
+                raise RuntimeError(
+                    "called 'started' twice on the same task status"
+                ) from None
+
+        task = cast(asyncio.Task, current_task())
+        _task_states[task].parent_id = self._parent_id
+
+
+if sys.version_info >= (3, 12):
+    _eager_task_factory_code: CodeType | None = asyncio.eager_task_factory.__code__
+else:
+    _eager_task_factory_code = None
+
+
+class TaskGroup(abc.TaskGroup):
+    def __init__(self) -> None:
+        self.cancel_scope: CancelScope = CancelScope()
+        self._active = False
+        self._exceptions: list[BaseException] = []
+        self._tasks: set[asyncio.Task] = set()
+        self._on_completed_fut: asyncio.Future[None] | None = None
+
+    async def __aenter__(self) -> TaskGroup:
+        self.cancel_scope.__enter__()
+        self._active = True
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> bool:
+        try:
+            if exc_val is not None:
+                self.cancel_scope.cancel()
+                if not isinstance(exc_val, CancelledError):
+                    self._exceptions.append(exc_val)
+
+            loop = get_running_loop()
+            try:
+                if self._tasks:
+                    with CancelScope() as wait_scope:
+                        while self._tasks:
+                            self._on_completed_fut = loop.create_future()
+
+                            try:
+                                await self._on_completed_fut
+                            except CancelledError as exc:
+                                # Shield the scope against further cancellation attempts,
+                                # as they're not productive (#695)
+                                wait_scope.shield = True
+                                self.cancel_scope.cancel()
+
+                                # Set exc_val from the cancellation exception if it was
+                                # previously unset. However, we should not replace a native
+                                # cancellation exception with one raise by a cancel scope.
+                                if exc_val is None or (
+                                    isinstance(exc_val, CancelledError)
+                                    and not is_anyio_cancellation(exc)
+                                ):
+                                    exc_val = exc
+
+                            self._on_completed_fut = None
+                else:
+                    # If there are no child tasks to wait on, run at least one checkpoint
+                    # anyway
+                    await AsyncIOBackend.cancel_shielded_checkpoint()
+
+                self._active = False
+                if self._exceptions:
+                    # The exception that got us here should already have been
+                    # added to self._exceptions so it's ok to break exception
+                    # chaining and avoid adding a "During handling of above..."
+                    # for each nesting level.
+                    raise BaseExceptionGroup(
+                        "unhandled errors in a TaskGroup", self._exceptions
+                    ) from None
+                elif exc_val:
+                    raise exc_val
+            except BaseException as exc:
+                if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__):
+                    return True
+
+                raise
+
+            return self.cancel_scope.__exit__(exc_type, exc_val, exc_tb)
+        finally:
+            del exc_val, exc_tb, self._exceptions
+
+    def _spawn(
+        self,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[Any]],
+        args: tuple[Unpack[PosArgsT]],
+        name: object,
+        task_status_future: asyncio.Future | None = None,
+    ) -> asyncio.Task:
+        def task_done(_task: asyncio.Task) -> None:
+            if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None:
+                asyncio.future_discard_from_awaited_by(
+                    _task, self.cancel_scope._host_task
+                )
+
+            task_state = _task_states[_task]
+            assert task_state.cancel_scope is not None
+            assert _task in task_state.cancel_scope._tasks
+            task_state.cancel_scope._tasks.remove(_task)
+            self._tasks.remove(task)
+            del _task_states[_task]
+
+            if self._on_completed_fut is not None and not self._tasks:
+                try:
+                    self._on_completed_fut.set_result(None)
+                except asyncio.InvalidStateError:
+                    pass
+
+            try:
+                exc = _task.exception()
+            except CancelledError as e:
+                while isinstance(e.__context__, CancelledError):
+                    e = e.__context__
+
+                exc = e
+
+            if exc is not None:
+                # The future can only be in the cancelled state if the host task was
+                # cancelled, so return immediately instead of adding one more
+                # CancelledError to the exceptions list
+                if task_status_future is not None and task_status_future.cancelled():
+                    return
+
+                if task_status_future is None or task_status_future.done():
+                    if not isinstance(exc, CancelledError):
+                        self._exceptions.append(exc)
+
+                    if not self.cancel_scope._effectively_cancelled:
+                        self.cancel_scope.cancel()
+                else:
+                    task_status_future.set_exception(exc)
+            elif task_status_future is not None and not task_status_future.done():
+                task_status_future.set_exception(
+                    RuntimeError("Child exited without calling task_status.started()")
+                )
+
+        if not self._active:
+            raise RuntimeError(
+                "This task group is not active; no new tasks can be started."
+            )
+
+        kwargs = {}
+        if task_status_future:
+            parent_id = id(current_task())
+            kwargs["task_status"] = _AsyncioTaskStatus(
+                task_status_future, id(self.cancel_scope._host_task)
+            )
+        else:
+            parent_id = id(self.cancel_scope._host_task)
+
+        coro = func(*args, **kwargs)
+        if not iscoroutine(coro):
+            prefix = f"{func.__module__}." if hasattr(func, "__module__") else ""
+            raise TypeError(
+                f"Expected {prefix}{func.__qualname__}() to return a coroutine, but "
+                f"the return value ({coro!r}) is not a coroutine object"
+            )
+
+        name = get_callable_name(func) if name is None else str(name)
+        loop = asyncio.get_running_loop()
+        if (
+            (factory := loop.get_task_factory())
+            and getattr(factory, "__code__", None) is _eager_task_factory_code
+            and (closure := getattr(factory, "__closure__", None))
+        ):
+            custom_task_constructor = closure[0].cell_contents
+            task = custom_task_constructor(coro, loop=loop, name=name)
+        else:
+            task = create_task(coro, name=name)
+
+        # Make the spawned task inherit the task group's cancel scope
+        _task_states[task] = TaskState(
+            parent_id=parent_id, cancel_scope=self.cancel_scope
+        )
+        self.cancel_scope._tasks.add(task)
+        self._tasks.add(task)
+        if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None:
+            asyncio.future_add_to_awaited_by(task, self.cancel_scope._host_task)
+
+        task.add_done_callback(task_done)
+        return task
+
+    def start_soon(
+        self,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[Any]],
+        *args: Unpack[PosArgsT],
+        name: object = None,
+    ) -> None:
+        self._spawn(func, args, name)
+
+    async def start(
+        self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None
+    ) -> Any:
+        future: asyncio.Future = asyncio.Future()
+        task = self._spawn(func, args, name, future)
+
+        # If the task raises an exception after sending a start value without a switch
+        # point between, the task group is cancelled and this method never proceeds to
+        # process the completed future. That's why we have to have a shielded cancel
+        # scope here.
+        try:
+            return await future
+        except CancelledError:
+            # Cancel the task and wait for it to exit before returning
+            task.cancel()
+            with CancelScope(shield=True), suppress(CancelledError):
+                await task
+
+            raise
+
+
+#
+# Threads
+#
+
+_Retval_Queue_Type = tuple[Optional[T_Retval], Optional[BaseException]]
+
+
+class WorkerThread(Thread):
+    MAX_IDLE_TIME = 10  # seconds
+
+    def __init__(
+        self,
+        root_task: asyncio.Task,
+        workers: set[WorkerThread],
+        idle_workers: deque[WorkerThread],
+    ):
+        super().__init__(name="AnyIO worker thread")
+        self.root_task = root_task
+        self.workers = workers
+        self.idle_workers = idle_workers
+        self.loop = root_task._loop
+        self.queue: Queue[
+            tuple[Context, Callable, tuple, asyncio.Future, CancelScope] | None
+        ] = Queue(2)
+        self.idle_since = AsyncIOBackend.current_time()
+        self.stopping = False
+
+    def _report_result(
+        self, future: asyncio.Future, result: Any, exc: BaseException | None
+    ) -> None:
+        self.idle_since = AsyncIOBackend.current_time()
+        if not self.stopping:
+            self.idle_workers.append(self)
+
+        if not future.cancelled():
+            if exc is not None:
+                if isinstance(exc, StopIteration):
+                    new_exc = RuntimeError("coroutine raised StopIteration")
+                    new_exc.__cause__ = exc
+                    exc = new_exc
+
+                future.set_exception(exc)
+            else:
+                future.set_result(result)
+
+    def run(self) -> None:
+        with claim_worker_thread(AsyncIOBackend, self.loop):
+            while True:
+                item = self.queue.get()
+                if item is None:
+                    # Shutdown command received
+                    return
+
+                context, func, args, future, cancel_scope = item
+                if not future.cancelled():
+                    result = None
+                    exception: BaseException | None = None
+                    threadlocals.current_cancel_scope = cancel_scope
+                    try:
+                        result = context.run(func, *args)
+                    except BaseException as exc:
+                        exception = exc
+                    finally:
+                        del threadlocals.current_cancel_scope
+
+                    if not self.loop.is_closed():
+                        self.loop.call_soon_threadsafe(
+                            self._report_result, future, result, exception
+                        )
+
+                    del result, exception
+
+                self.queue.task_done()
+                del item, context, func, args, future, cancel_scope
+
+    def stop(self, f: asyncio.Task | None = None) -> None:
+        self.stopping = True
+        self.queue.put_nowait(None)
+        self.workers.discard(self)
+        try:
+            self.idle_workers.remove(self)
+        except ValueError:
+            pass
+
+
+_threadpool_idle_workers: RunVar[deque[WorkerThread]] = RunVar(
+    "_threadpool_idle_workers"
+)
+_threadpool_workers: RunVar[set[WorkerThread]] = RunVar("_threadpool_workers")
+
+
+#
+# Subprocesses
+#
+
+
+@dataclass(eq=False)
+class StreamReaderWrapper(abc.ByteReceiveStream):
+    _stream: asyncio.StreamReader
+
+    async def receive(self, max_bytes: int = 65536) -> bytes:
+        data = await self._stream.read(max_bytes)
+        if data:
+            return data
+        else:
+            raise EndOfStream
+
+    async def aclose(self) -> None:
+        self._stream.set_exception(ClosedResourceError())
+        await AsyncIOBackend.checkpoint()
+
+
+@dataclass(eq=False)
+class StreamWriterWrapper(abc.ByteSendStream):
+    _stream: asyncio.StreamWriter
+    _closed: bool = field(init=False, default=False)
+
+    async def send(self, item: bytes) -> None:
+        await AsyncIOBackend.checkpoint_if_cancelled()
+        stream_paused = self._stream._protocol._paused  # type: ignore[attr-defined]
+        try:
+            self._stream.write(item)
+            await self._stream.drain()
+        except (ConnectionResetError, BrokenPipeError, RuntimeError) as exc:
+            # If closed by us and/or the peer:
+            # * on stdlib, drain() raises ConnectionResetError or BrokenPipeError
+            # * on uvloop and Winloop, write() eventually starts raising RuntimeError
+            if self._closed:
+                raise ClosedResourceError from exc
+            elif self._stream.is_closing():
+                raise BrokenResourceError from exc
+
+            raise
+
+        if not stream_paused:
+            await AsyncIOBackend.cancel_shielded_checkpoint()
+
+    async def aclose(self) -> None:
+        self._closed = True
+        self._stream.close()
+        await AsyncIOBackend.checkpoint()
+
+
+@dataclass(eq=False)
+class Process(abc.Process):
+    _process: asyncio.subprocess.Process
+    _stdin: StreamWriterWrapper | None
+    _stdout: StreamReaderWrapper | None
+    _stderr: StreamReaderWrapper | None
+
+    async def aclose(self) -> None:
+        with CancelScope(shield=True) as scope:
+            if self._stdin:
+                await self._stdin.aclose()
+            if self._stdout:
+                await self._stdout.aclose()
+            if self._stderr:
+                await self._stderr.aclose()
+
+            scope.shield = False
+            try:
+                await self.wait()
+            except BaseException:
+                scope.shield = True
+                self.kill()
+                await self.wait()
+                raise
+
+    async def wait(self) -> int:
+        return await self._process.wait()
+
+    def terminate(self) -> None:
+        self._process.terminate()
+
+    def kill(self) -> None:
+        self._process.kill()
+
+    def send_signal(self, signal: int) -> None:
+        self._process.send_signal(signal)
+
+    @property
+    def pid(self) -> int:
+        return self._process.pid
+
+    @property
+    def returncode(self) -> int | None:
+        return self._process.returncode
+
+    @property
+    def stdin(self) -> abc.ByteSendStream | None:
+        return self._stdin
+
+    @property
+    def stdout(self) -> abc.ByteReceiveStream | None:
+        return self._stdout
+
+    @property
+    def stderr(self) -> abc.ByteReceiveStream | None:
+        return self._stderr
+
+
+def _forcibly_shutdown_process_pool_on_exit(
+    workers: set[Process], _task: object
+) -> None:
+    """
+    Forcibly shuts down worker processes belonging to this event loop."""
+    child_watcher: asyncio.AbstractChildWatcher | None = None  # type: ignore[name-defined]
+    if sys.version_info < (3, 12):
+        try:
+            child_watcher = asyncio.get_event_loop_policy().get_child_watcher()
+        except NotImplementedError:
+            pass
+
+    # Close as much as possible (w/o async/await) to avoid warnings
+    for process in workers.copy():
+        if process.returncode is None:
+            continue
+
+        process._stdin._stream._transport.close()  # type: ignore[union-attr]
+        process._stdout._stream._transport.close()  # type: ignore[union-attr]
+        process._stderr._stream._transport.close()  # type: ignore[union-attr]
+        process.kill()
+        if child_watcher:
+            child_watcher.remove_child_handler(process.pid)
+
+
+async def _shutdown_process_pool_on_exit(workers: set[abc.Process]) -> None:
+    """
+    Shuts down worker processes belonging to this event loop.
+
+    NOTE: this only works when the event loop was started using asyncio.run() or
+    anyio.run().
+
+    """
+    process: abc.Process
+    try:
+        await sleep(math.inf)
+    except asyncio.CancelledError:
+        workers = workers.copy()
+        for process in workers:
+            if process.returncode is None:
+                process.kill()
+
+        for process in workers:
+            await process.aclose()
+
+
+#
+# Sockets and networking
+#
+
+
+class StreamProtocol(asyncio.Protocol):
+    read_queue: deque[bytes]
+    read_event: asyncio.Event
+    write_event: asyncio.Event
+    exception: Exception | None = None
+    is_at_eof: bool = False
+
+    def connection_made(self, transport: asyncio.BaseTransport) -> None:
+        self.read_queue = deque()
+        self.read_event = asyncio.Event()
+        self.write_event = asyncio.Event()
+        self.write_event.set()
+        cast(asyncio.Transport, transport).set_write_buffer_limits(0)
+
+    def connection_lost(self, exc: Exception | None) -> None:
+        if exc:
+            self.exception = BrokenResourceError()
+            self.exception.__cause__ = exc
+
+        self.read_event.set()
+        self.write_event.set()
+
+    def data_received(self, data: bytes) -> None:
+        # ProactorEventloop sometimes sends bytearray instead of bytes
+        self.read_queue.append(bytes(data))
+        self.read_event.set()
+
+    def eof_received(self) -> bool | None:
+        self.is_at_eof = True
+        self.read_event.set()
+        return True
+
+    def pause_writing(self) -> None:
+        self.write_event = asyncio.Event()
+
+    def resume_writing(self) -> None:
+        self.write_event.set()
+
+
+class DatagramProtocol(asyncio.DatagramProtocol):
+    read_queue: deque[tuple[bytes, IPSockAddrType]]
+    read_event: asyncio.Event
+    write_event: asyncio.Event
+    exception: Exception | None = None
+
+    def connection_made(self, transport: asyncio.BaseTransport) -> None:
+        self.read_queue = deque(maxlen=100)  # arbitrary value
+        self.read_event = asyncio.Event()
+        self.write_event = asyncio.Event()
+        self.write_event.set()
+
+    def connection_lost(self, exc: Exception | None) -> None:
+        self.read_event.set()
+        self.write_event.set()
+
+    def datagram_received(self, data: bytes, addr: IPSockAddrType) -> None:
+        addr = convert_ipv6_sockaddr(addr)
+        self.read_queue.append((data, addr))
+        self.read_event.set()
+
+    def error_received(self, exc: Exception) -> None:
+        self.exception = exc
+
+    def pause_writing(self) -> None:
+        self.write_event.clear()
+
+    def resume_writing(self) -> None:
+        self.write_event.set()
+
+
+class SocketStream(abc.SocketStream):
+    def __init__(self, transport: asyncio.Transport, protocol: StreamProtocol):
+        self._transport = transport
+        self._protocol = protocol
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+        self._closed = False
+
+    @property
+    def _raw_socket(self) -> socket.socket:
+        return self._transport.get_extra_info("socket")
+
+    async def receive(self, max_bytes: int = 65536) -> bytes:
+        with self._receive_guard:
+            if (
+                not self._protocol.read_event.is_set()
+                and not self._transport.is_closing()
+                and not self._protocol.is_at_eof
+            ):
+                self._transport.resume_reading()
+                await self._protocol.read_event.wait()
+                self._transport.pause_reading()
+            else:
+                await AsyncIOBackend.checkpoint()
+
+            try:
+                chunk = self._protocol.read_queue.popleft()
+            except IndexError:
+                if self._closed:
+                    raise ClosedResourceError from None
+                elif self._protocol.exception:
+                    raise self._protocol.exception from None
+                else:
+                    raise EndOfStream from None
+
+            if len(chunk) > max_bytes:
+                # Split the oversized chunk
+                chunk, leftover = chunk[:max_bytes], chunk[max_bytes:]
+                self._protocol.read_queue.appendleft(leftover)
+
+            # If the read queue is empty, clear the flag so that the next call will
+            # block until data is available
+            if not self._protocol.read_queue:
+                self._protocol.read_event.clear()
+
+        return chunk
+
+    async def send(self, item: bytes) -> None:
+        with self._send_guard:
+            await AsyncIOBackend.checkpoint()
+
+            if self._closed:
+                raise ClosedResourceError
+            elif self._protocol.exception is not None:
+                raise self._protocol.exception
+
+            try:
+                self._transport.write(item)
+            except RuntimeError as exc:
+                if self._transport.is_closing():
+                    raise BrokenResourceError from exc
+                else:
+                    raise
+
+            await self._protocol.write_event.wait()
+
+    async def send_eof(self) -> None:
+        try:
+            self._transport.write_eof()
+        except OSError:
+            pass
+
+    async def aclose(self) -> None:
+        self._closed = True
+        if not self._transport.is_closing():
+            try:
+                self._transport.write_eof()
+            except OSError:
+                pass
+
+            self._transport.close()
+            await sleep(0)
+            self._transport.abort()
+
+
+class _RawSocketMixin:
+    _receive_future: asyncio.Future | None = None
+    _send_future: asyncio.Future | None = None
+    _closing = False
+
+    def __init__(self, raw_socket: socket.socket):
+        self.__raw_socket = raw_socket
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+
+    @property
+    def _raw_socket(self) -> socket.socket:
+        return self.__raw_socket
+
+    def _wait_until_readable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future:
+        def callback(f: object) -> None:
+            del self._receive_future
+            loop.remove_reader(self.__raw_socket)
+
+        f = self._receive_future = asyncio.Future()
+        loop.add_reader(self.__raw_socket, f.set_result, None)
+        f.add_done_callback(callback)
+        return f
+
+    def _wait_until_writable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future:
+        def callback(f: object) -> None:
+            del self._send_future
+            loop.remove_writer(self.__raw_socket)
+
+        f = self._send_future = asyncio.Future()
+        loop.add_writer(self.__raw_socket, f.set_result, None)
+        f.add_done_callback(callback)
+        return f
+
+    async def aclose(self) -> None:
+        if not self._closing:
+            self._closing = True
+            if self.__raw_socket.fileno() != -1:
+                self.__raw_socket.close()
+
+            if self._receive_future:
+                self._receive_future.set_result(None)
+            if self._send_future:
+                self._send_future.set_result(None)
+
+
+class UNIXSocketStream(_RawSocketMixin, abc.UNIXSocketStream):
+    async def send_eof(self) -> None:
+        with self._send_guard:
+            self._raw_socket.shutdown(socket.SHUT_WR)
+
+    async def receive(self, max_bytes: int = 65536) -> bytes:
+        loop = get_running_loop()
+        await AsyncIOBackend.checkpoint()
+        with self._receive_guard:
+            while True:
+                try:
+                    data = self._raw_socket.recv(max_bytes)
+                except BlockingIOError:
+                    await self._wait_until_readable(loop)
+                except OSError as exc:
+                    if self._closing:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+                else:
+                    if not data:
+                        raise EndOfStream
+
+                    return data
+
+    async def send(self, item: bytes) -> None:
+        loop = get_running_loop()
+        await AsyncIOBackend.checkpoint()
+        with self._send_guard:
+            view = memoryview(item)
+            while view:
+                try:
+                    bytes_sent = self._raw_socket.send(view)
+                except BlockingIOError:
+                    await self._wait_until_writable(loop)
+                except OSError as exc:
+                    if self._closing:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+                else:
+                    view = view[bytes_sent:]
+
+    async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
+        if not isinstance(msglen, int) or msglen < 0:
+            raise ValueError("msglen must be a non-negative integer")
+        if not isinstance(maxfds, int) or maxfds < 1:
+            raise ValueError("maxfds must be a positive integer")
+
+        loop = get_running_loop()
+        fds = array.array("i")
+        await AsyncIOBackend.checkpoint()
+        with self._receive_guard:
+            while True:
+                try:
+                    message, ancdata, flags, addr = self._raw_socket.recvmsg(
+                        msglen, socket.CMSG_LEN(maxfds * fds.itemsize)
+                    )
+                except BlockingIOError:
+                    await self._wait_until_readable(loop)
+                except OSError as exc:
+                    if self._closing:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+                else:
+                    if not message and not ancdata:
+                        raise EndOfStream
+
+                    break
+
+        for cmsg_level, cmsg_type, cmsg_data in ancdata:
+            if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS:
+                raise RuntimeError(
+                    f"Received unexpected ancillary data; message = {message!r}, "
+                    f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}"
+                )
+
+            fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
+
+        return message, list(fds)
+
+    async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
+        if not message:
+            raise ValueError("message must not be empty")
+        if not fds:
+            raise ValueError("fds must not be empty")
+
+        loop = get_running_loop()
+        filenos: list[int] = []
+        for fd in fds:
+            if isinstance(fd, int):
+                filenos.append(fd)
+            elif isinstance(fd, IOBase):
+                filenos.append(fd.fileno())
+
+        fdarray = array.array("i", filenos)
+        await AsyncIOBackend.checkpoint()
+        with self._send_guard:
+            while True:
+                try:
+                    # The ignore can be removed after mypy picks up
+                    # https://github.com/python/typeshed/pull/5545
+                    self._raw_socket.sendmsg(
+                        [message], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, fdarray)]
+                    )
+                    break
+                except BlockingIOError:
+                    await self._wait_until_writable(loop)
+                except OSError as exc:
+                    if self._closing:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+
+
+class TCPSocketListener(abc.SocketListener):
+    _accept_scope: CancelScope | None = None
+    _closed = False
+
+    def __init__(self, raw_socket: socket.socket):
+        self.__raw_socket = raw_socket
+        self._loop = cast(asyncio.BaseEventLoop, get_running_loop())
+        self._accept_guard = ResourceGuard("accepting connections from")
+
+    @property
+    def _raw_socket(self) -> socket.socket:
+        return self.__raw_socket
+
+    async def accept(self) -> abc.SocketStream:
+        if self._closed:
+            raise ClosedResourceError
+
+        with self._accept_guard:
+            await AsyncIOBackend.checkpoint()
+            with CancelScope() as self._accept_scope:
+                try:
+                    client_sock, _addr = await self._loop.sock_accept(self._raw_socket)
+                except asyncio.CancelledError:
+                    # Workaround for https://bugs.python.org/issue41317
+                    try:
+                        self._loop.remove_reader(self._raw_socket)
+                    except (ValueError, NotImplementedError):
+                        pass
+
+                    if self._closed:
+                        raise ClosedResourceError from None
+
+                    raise
+                finally:
+                    self._accept_scope = None
+
+        client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+        transport, protocol = await self._loop.connect_accepted_socket(
+            StreamProtocol, client_sock
+        )
+        return SocketStream(transport, protocol)
+
+    async def aclose(self) -> None:
+        if self._closed:
+            return
+
+        self._closed = True
+        if self._accept_scope:
+            # Workaround for https://bugs.python.org/issue41317
+            try:
+                self._loop.remove_reader(self._raw_socket)
+            except (ValueError, NotImplementedError):
+                pass
+
+            self._accept_scope.cancel()
+            await sleep(0)
+
+        self._raw_socket.close()
+
+
+class UNIXSocketListener(abc.SocketListener):
+    def __init__(self, raw_socket: socket.socket):
+        self.__raw_socket = raw_socket
+        self._loop = get_running_loop()
+        self._accept_guard = ResourceGuard("accepting connections from")
+        self._closed = False
+
+    async def accept(self) -> abc.SocketStream:
+        await AsyncIOBackend.checkpoint()
+        with self._accept_guard:
+            while True:
+                try:
+                    client_sock, _ = self.__raw_socket.accept()
+                    client_sock.setblocking(False)
+                    return UNIXSocketStream(client_sock)
+                except BlockingIOError:
+                    f: asyncio.Future = asyncio.Future()
+                    self._loop.add_reader(self.__raw_socket, f.set_result, None)
+                    f.add_done_callback(
+                        lambda _: self._loop.remove_reader(self.__raw_socket)
+                    )
+                    await f
+                except OSError as exc:
+                    if self._closed:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+
+    async def aclose(self) -> None:
+        self._closed = True
+        self.__raw_socket.close()
+
+    @property
+    def _raw_socket(self) -> socket.socket:
+        return self.__raw_socket
+
+
+class UDPSocket(abc.UDPSocket):
+    def __init__(
+        self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol
+    ):
+        self._transport = transport
+        self._protocol = protocol
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+        self._closed = False
+
+    @property
+    def _raw_socket(self) -> socket.socket:
+        return self._transport.get_extra_info("socket")
+
+    async def aclose(self) -> None:
+        self._closed = True
+        if not self._transport.is_closing():
+            self._transport.close()
+
+    async def receive(self) -> tuple[bytes, IPSockAddrType]:
+        with self._receive_guard:
+            await AsyncIOBackend.checkpoint()
+
+            # If the buffer is empty, ask for more data
+            if not self._protocol.read_queue and not self._transport.is_closing():
+                self._protocol.read_event.clear()
+                await self._protocol.read_event.wait()
+
+            try:
+                return self._protocol.read_queue.popleft()
+            except IndexError:
+                if self._closed:
+                    raise ClosedResourceError from None
+                else:
+                    raise BrokenResourceError from None
+
+    async def send(self, item: UDPPacketType) -> None:
+        with self._send_guard:
+            await AsyncIOBackend.checkpoint()
+            await self._protocol.write_event.wait()
+            if self._closed:
+                raise ClosedResourceError
+            elif self._transport.is_closing():
+                raise BrokenResourceError
+            else:
+                self._transport.sendto(*item)
+
+
+class ConnectedUDPSocket(abc.ConnectedUDPSocket):
+    def __init__(
+        self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol
+    ):
+        self._transport = transport
+        self._protocol = protocol
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+        self._closed = False
+
+    @property
+    def _raw_socket(self) -> socket.socket:
+        return self._transport.get_extra_info("socket")
+
+    async def aclose(self) -> None:
+        self._closed = True
+        if not self._transport.is_closing():
+            self._transport.close()
+
+    async def receive(self) -> bytes:
+        with self._receive_guard:
+            await AsyncIOBackend.checkpoint()
+
+            # If the buffer is empty, ask for more data
+            if not self._protocol.read_queue and not self._transport.is_closing():
+                self._protocol.read_event.clear()
+                await self._protocol.read_event.wait()
+
+            try:
+                packet = self._protocol.read_queue.popleft()
+            except IndexError:
+                if self._closed:
+                    raise ClosedResourceError from None
+                else:
+                    raise BrokenResourceError from None
+
+            return packet[0]
+
+    async def send(self, item: bytes) -> None:
+        with self._send_guard:
+            await AsyncIOBackend.checkpoint()
+            await self._protocol.write_event.wait()
+            if self._closed:
+                raise ClosedResourceError
+            elif self._transport.is_closing():
+                raise BrokenResourceError
+            else:
+                self._transport.sendto(item)
+
+
+class UNIXDatagramSocket(_RawSocketMixin, abc.UNIXDatagramSocket):
+    async def receive(self) -> UNIXDatagramPacketType:
+        loop = get_running_loop()
+        await AsyncIOBackend.checkpoint()
+        with self._receive_guard:
+            while True:
+                try:
+                    data = self._raw_socket.recvfrom(65536)
+                except BlockingIOError:
+                    await self._wait_until_readable(loop)
+                except OSError as exc:
+                    if self._closing:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+                else:
+                    return data
+
+    async def send(self, item: UNIXDatagramPacketType) -> None:
+        loop = get_running_loop()
+        await AsyncIOBackend.checkpoint()
+        with self._send_guard:
+            while True:
+                try:
+                    self._raw_socket.sendto(*item)
+                except BlockingIOError:
+                    await self._wait_until_writable(loop)
+                except OSError as exc:
+                    if self._closing:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+                else:
+                    return
+
+
+class ConnectedUNIXDatagramSocket(_RawSocketMixin, abc.ConnectedUNIXDatagramSocket):
+    async def receive(self) -> bytes:
+        loop = get_running_loop()
+        await AsyncIOBackend.checkpoint()
+        with self._receive_guard:
+            while True:
+                try:
+                    data = self._raw_socket.recv(65536)
+                except BlockingIOError:
+                    await self._wait_until_readable(loop)
+                except OSError as exc:
+                    if self._closing:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+                else:
+                    return data
+
+    async def send(self, item: bytes) -> None:
+        loop = get_running_loop()
+        await AsyncIOBackend.checkpoint()
+        with self._send_guard:
+            while True:
+                try:
+                    self._raw_socket.send(item)
+                except BlockingIOError:
+                    await self._wait_until_writable(loop)
+                except OSError as exc:
+                    if self._closing:
+                        raise ClosedResourceError from None
+                    else:
+                        raise BrokenResourceError from exc
+                else:
+                    return
+
+
+_read_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("read_events")
+_write_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("write_events")
+
+
+#
+# Synchronization
+#
+
+
+class Event(BaseEvent):
+    def __new__(cls) -> Event:
+        return object.__new__(cls)
+
+    def __init__(self) -> None:
+        self._event = asyncio.Event()
+
+    def set(self) -> None:
+        self._event.set()
+
+    def is_set(self) -> bool:
+        return self._event.is_set()
+
+    async def wait(self) -> None:
+        if self.is_set():
+            await AsyncIOBackend.checkpoint()
+        else:
+            await self._event.wait()
+
+    def statistics(self) -> EventStatistics:
+        return EventStatistics(len(self._event._waiters))
+
+
+class Lock(BaseLock):
+    def __new__(cls, *, fast_acquire: bool = False) -> Lock:
+        return object.__new__(cls)
+
+    def __init__(self, *, fast_acquire: bool = False) -> None:
+        self._fast_acquire = fast_acquire
+        self._owner_task: asyncio.Task | None = None
+        self._waiters: deque[tuple[asyncio.Task, asyncio.Future]] = deque()
+
+    async def acquire(self) -> None:
+        task = cast(asyncio.Task, current_task())
+        if self._owner_task is None and not self._waiters:
+            await AsyncIOBackend.checkpoint_if_cancelled()
+            self._owner_task = task
+
+            # Unless on the "fast path", yield control of the event loop so that other
+            # tasks can run too
+            if not self._fast_acquire:
+                try:
+                    await AsyncIOBackend.cancel_shielded_checkpoint()
+                except CancelledError:
+                    self.release()
+                    raise
+
+            return
+
+        if self._owner_task == task:
+            raise RuntimeError("Attempted to acquire an already held Lock")
+
+        fut: asyncio.Future[None] = asyncio.Future()
+        item = task, fut
+        self._waiters.append(item)
+        try:
+            await fut
+        except CancelledError:
+            self._waiters.remove(item)
+            if self._owner_task is task:
+                self.release()
+
+            raise
+
+        self._waiters.remove(item)
+
+    def acquire_nowait(self) -> None:
+        task = cast(asyncio.Task, current_task())
+        if self._owner_task is None and not self._waiters:
+            self._owner_task = task
+            return
+
+        if self._owner_task is task:
+            raise RuntimeError("Attempted to acquire an already held Lock")
+
+        raise WouldBlock
+
+    def locked(self) -> bool:
+        return self._owner_task is not None
+
+    def release(self) -> None:
+        if self._owner_task != current_task():
+            raise RuntimeError("The current task is not holding this lock")
+
+        for task, fut in self._waiters:
+            if not fut.cancelled():
+                self._owner_task = task
+                fut.set_result(None)
+                return
+
+        self._owner_task = None
+
+    def statistics(self) -> LockStatistics:
+        task_info = AsyncIOTaskInfo(self._owner_task) if self._owner_task else None
+        return LockStatistics(self.locked(), task_info, len(self._waiters))
+
+
+class Semaphore(BaseSemaphore):
+    def __new__(
+        cls,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> Semaphore:
+        return object.__new__(cls)
+
+    def __init__(
+        self,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ):
+        super().__init__(initial_value, max_value=max_value)
+        self._value = initial_value
+        self._max_value = max_value
+        self._fast_acquire = fast_acquire
+        self._waiters: deque[asyncio.Future[None]] = deque()
+
+    async def acquire(self) -> None:
+        if self._value > 0 and not self._waiters:
+            await AsyncIOBackend.checkpoint_if_cancelled()
+            self._value -= 1
+
+            # Unless on the "fast path", yield control of the event loop so that other
+            # tasks can run too
+            if not self._fast_acquire:
+                try:
+                    await AsyncIOBackend.cancel_shielded_checkpoint()
+                except CancelledError:
+                    self.release()
+                    raise
+
+            return
+
+        fut: asyncio.Future[None] = asyncio.Future()
+        self._waiters.append(fut)
+        try:
+            await fut
+        except CancelledError:
+            try:
+                self._waiters.remove(fut)
+            except ValueError:
+                self.release()
+
+            raise
+
+    def acquire_nowait(self) -> None:
+        if self._value == 0:
+            raise WouldBlock
+
+        self._value -= 1
+
+    def release(self) -> None:
+        if self._max_value is not None and self._value == self._max_value:
+            raise ValueError("semaphore released too many times")
+
+        for fut in self._waiters:
+            if not fut.cancelled():
+                fut.set_result(None)
+                self._waiters.remove(fut)
+                return
+
+        self._value += 1
+
+    @property
+    def value(self) -> int:
+        return self._value
+
+    @property
+    def max_value(self) -> int | None:
+        return self._max_value
+
+    def statistics(self) -> SemaphoreStatistics:
+        return SemaphoreStatistics(len(self._waiters))
+
+
+class CapacityLimiter(BaseCapacityLimiter):
+    _total_tokens: float = 0
+
+    def __new__(cls, total_tokens: float) -> CapacityLimiter:
+        return object.__new__(cls)
+
+    def __init__(self, total_tokens: float):
+        self._borrowers: set[Any] = set()
+        self._wait_queue: OrderedDict[Any, asyncio.Event] = OrderedDict()
+        self.total_tokens = total_tokens
+
+    async def __aenter__(self) -> None:
+        await self.acquire()
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self.release()
+
+    @property
+    def total_tokens(self) -> float:
+        return self._total_tokens
+
+    @total_tokens.setter
+    def total_tokens(self, value: float) -> None:
+        if not isinstance(value, int) and not math.isinf(value):
+            raise TypeError("total_tokens must be an int or math.inf")
+
+        if value < 0:
+            raise ValueError("total_tokens must be >= 0")
+
+        waiters_to_notify = max(value - self._total_tokens, 0)
+        self._total_tokens = value
+
+        # Notify waiting tasks that they have acquired the limiter
+        while self._wait_queue and waiters_to_notify:
+            event = self._wait_queue.popitem(last=False)[1]
+            event.set()
+            waiters_to_notify -= 1
+
+    @property
+    def borrowed_tokens(self) -> int:
+        return len(self._borrowers)
+
+    @property
+    def available_tokens(self) -> float:
+        return self._total_tokens - len(self._borrowers)
+
+    def _notify_next_waiter(self) -> None:
+        """Notify the next task in line if this limiter has free capacity now."""
+        if self._wait_queue and len(self._borrowers) < self._total_tokens:
+            event = self._wait_queue.popitem(last=False)[1]
+            event.set()
+
+    def acquire_nowait(self) -> None:
+        self.acquire_on_behalf_of_nowait(current_task())
+
+    def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
+        if borrower in self._borrowers:
+            raise RuntimeError(
+                "this borrower is already holding one of this CapacityLimiter's tokens"
+            )
+
+        if self._wait_queue or len(self._borrowers) >= self._total_tokens:
+            raise WouldBlock
+
+        self._borrowers.add(borrower)
+
+    async def acquire(self) -> None:
+        return await self.acquire_on_behalf_of(current_task())
+
+    async def acquire_on_behalf_of(self, borrower: object) -> None:
+        await AsyncIOBackend.checkpoint_if_cancelled()
+        try:
+            self.acquire_on_behalf_of_nowait(borrower)
+        except WouldBlock:
+            event = asyncio.Event()
+            self._wait_queue[borrower] = event
+            try:
+                await event.wait()
+            except BaseException:
+                self._wait_queue.pop(borrower, None)
+                if event.is_set():
+                    self._notify_next_waiter()
+
+                raise
+
+            self._borrowers.add(borrower)
+        else:
+            try:
+                await AsyncIOBackend.cancel_shielded_checkpoint()
+            except BaseException:
+                self.release()
+                raise
+
+    def release(self) -> None:
+        self.release_on_behalf_of(current_task())
+
+    def release_on_behalf_of(self, borrower: object) -> None:
+        try:
+            self._borrowers.remove(borrower)
+        except KeyError:
+            raise RuntimeError(
+                "this borrower isn't holding any of this CapacityLimiter's tokens"
+            ) from None
+
+        self._notify_next_waiter()
+
+    def statistics(self) -> CapacityLimiterStatistics:
+        return CapacityLimiterStatistics(
+            self.borrowed_tokens,
+            self.total_tokens,
+            tuple(self._borrowers),
+            len(self._wait_queue),
+        )
+
+
+_default_thread_limiter: RunVar[CapacityLimiter] = RunVar("_default_thread_limiter")
+
+
+#
+# Operating system signals
+#
+
+
+class _SignalReceiver:
+    def __init__(self, signals: tuple[Signals, ...]):
+        self._signals = signals
+        self._loop = get_running_loop()
+        self._signal_queue: deque[Signals] = deque()
+        self._future: asyncio.Future = asyncio.Future()
+        self._handled_signals: set[Signals] = set()
+
+    def _deliver(self, signum: Signals) -> None:
+        self._signal_queue.append(signum)
+        if not self._future.done():
+            self._future.set_result(None)
+
+    def __enter__(self) -> _SignalReceiver:
+        for sig in set(self._signals):
+            self._loop.add_signal_handler(sig, self._deliver, sig)
+            self._handled_signals.add(sig)
+
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        for sig in self._handled_signals:
+            self._loop.remove_signal_handler(sig)
+
+    def __aiter__(self) -> _SignalReceiver:
+        return self
+
+    async def __anext__(self) -> Signals:
+        await AsyncIOBackend.checkpoint()
+        if not self._signal_queue:
+            self._future = asyncio.Future()
+            await self._future
+
+        return self._signal_queue.popleft()
+
+
+#
+# Testing and debugging
+#
+
+
+class AsyncIOTaskInfo(TaskInfo):
+    def __init__(self, task: asyncio.Task):
+        task_state = _task_states.get(task)
+        if task_state is None:
+            parent_id = None
+        else:
+            parent_id = task_state.parent_id
+
+        coro = task.get_coro()
+        assert coro is not None, "created TaskInfo from a completed Task"
+        super().__init__(id(task), parent_id, task.get_name(), coro)
+        self._task = weakref.ref(task)
+
+    def has_pending_cancellation(self) -> bool:
+        if not (task := self._task()):
+            # If the task isn't around anymore, it won't have a pending cancellation
+            return False
+
+        if task._must_cancel:  # type: ignore[attr-defined]
+            return True
+        elif (
+            isinstance(task._fut_waiter, asyncio.Future)  # type: ignore[attr-defined]
+            and task._fut_waiter.cancelled()  # type: ignore[attr-defined]
+        ):
+            return True
+
+        if task_state := _task_states.get(task):
+            if cancel_scope := task_state.cancel_scope:
+                return cancel_scope._effectively_cancelled
+
+        return False
+
+
+class TestRunner(abc.TestRunner):
+    _send_stream: MemoryObjectSendStream[tuple[Awaitable[Any], asyncio.Future[Any]]]
+
+    def __init__(
+        self,
+        *,
+        debug: bool | None = None,
+        use_uvloop: bool = False,
+        loop_factory: Callable[[], AbstractEventLoop] | None = None,
+    ) -> None:
+        if use_uvloop and loop_factory is None:
+            if sys.platform != "win32":
+                import uvloop
+
+                loop_factory = uvloop.new_event_loop
+            else:
+                import winloop
+
+                loop_factory = winloop.new_event_loop
+
+        self._runner = Runner(debug=debug, loop_factory=loop_factory)
+        self._exceptions: list[BaseException] = []
+        self._runner_task: asyncio.Task | None = None
+
+    def __enter__(self) -> TestRunner:
+        self._runner.__enter__()
+        self.get_loop().set_exception_handler(self._exception_handler)
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self._runner.__exit__(exc_type, exc_val, exc_tb)
+
+    def get_loop(self) -> AbstractEventLoop:
+        return self._runner.get_loop()
+
+    def _exception_handler(
+        self, loop: asyncio.AbstractEventLoop, context: dict[str, Any]
+    ) -> None:
+        if isinstance(context.get("exception"), Exception):
+            self._exceptions.append(context["exception"])
+        else:
+            loop.default_exception_handler(context)
+
+    def _raise_async_exceptions(self) -> None:
+        # Re-raise any exceptions raised in asynchronous callbacks
+        if self._exceptions:
+            exceptions, self._exceptions = self._exceptions, []
+            if len(exceptions) == 1:
+                raise exceptions[0]
+            elif exceptions:
+                raise BaseExceptionGroup(
+                    "Multiple exceptions occurred in asynchronous callbacks", exceptions
+                )
+
+    async def _run_tests_and_fixtures(
+        self,
+        receive_stream: MemoryObjectReceiveStream[
+            tuple[Awaitable[T_Retval], asyncio.Future[T_Retval]]
+        ],
+    ) -> None:
+        from _pytest.outcomes import OutcomeException
+
+        with receive_stream, self._send_stream:
+            async for coro, future in receive_stream:
+                try:
+                    retval = await coro
+                except CancelledError as exc:
+                    if not future.cancelled():
+                        future.cancel(*exc.args)
+
+                    raise
+                except BaseException as exc:
+                    if not future.cancelled():
+                        future.set_exception(exc)
+
+                    if not isinstance(exc, (Exception, OutcomeException)):
+                        raise
+                else:
+                    if not future.cancelled():
+                        future.set_result(retval)
+
+    async def _call_in_runner_task(
+        self,
+        func: Callable[P, Awaitable[T_Retval]],
+        *args: P.args,
+        **kwargs: P.kwargs,
+    ) -> T_Retval:
+        if not self._runner_task:
+            self._send_stream, receive_stream = create_memory_object_stream[
+                tuple[Awaitable[Any], asyncio.Future]
+            ](1)
+            self._runner_task = self.get_loop().create_task(
+                self._run_tests_and_fixtures(receive_stream)
+            )
+
+        coro = func(*args, **kwargs)
+        future: asyncio.Future[T_Retval] = self.get_loop().create_future()
+        self._send_stream.send_nowait((coro, future))
+        return await future
+
+    def run_asyncgen_fixture(
+        self,
+        fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]],
+        kwargs: dict[str, Any],
+    ) -> Iterable[T_Retval]:
+        asyncgen = fixture_func(**kwargs)
+        fixturevalue: T_Retval = self.get_loop().run_until_complete(
+            self._call_in_runner_task(asyncgen.asend, None)
+        )
+        self._raise_async_exceptions()
+
+        yield fixturevalue
+
+        try:
+            self.get_loop().run_until_complete(
+                self._call_in_runner_task(asyncgen.asend, None)
+            )
+        except StopAsyncIteration:
+            self._raise_async_exceptions()
+        else:
+            self.get_loop().run_until_complete(asyncgen.aclose())
+            raise RuntimeError("Async generator fixture did not stop")
+
+    def run_fixture(
+        self,
+        fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]],
+        kwargs: dict[str, Any],
+    ) -> T_Retval:
+        retval = self.get_loop().run_until_complete(
+            self._call_in_runner_task(fixture_func, **kwargs)
+        )
+        self._raise_async_exceptions()
+        return retval
+
+    def run_test(
+        self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
+    ) -> None:
+        try:
+            self.get_loop().run_until_complete(
+                self._call_in_runner_task(test_func, **kwargs)
+            )
+        except Exception as exc:
+            self._exceptions.append(exc)
+
+        self._raise_async_exceptions()
+
+
+class AsyncIOBackend(AsyncBackend):
+    @classmethod
+    def run(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+        args: tuple[Unpack[PosArgsT]],
+        kwargs: dict[str, Any],
+        options: dict[str, Any],
+    ) -> T_Retval:
+        @wraps(func)
+        async def wrapper() -> T_Retval:
+            task = cast(asyncio.Task, current_task())
+            task.set_name(get_callable_name(func))
+            _task_states[task] = TaskState(None, None)
+
+            try:
+                return await func(*args)
+            finally:
+                del _task_states[task]
+
+        debug = options.get("debug", None)
+        loop_factory = options.get("loop_factory", None)
+        if loop_factory is None and options.get("use_uvloop", False):
+            if sys.platform != "win32":
+                import uvloop
+
+                loop_factory = uvloop.new_event_loop
+            else:
+                import winloop
+
+                loop_factory = winloop.new_event_loop
+
+        with Runner(debug=debug, loop_factory=loop_factory) as runner:
+            return runner.run(wrapper())
+
+    @classmethod
+    def current_token(cls) -> object:
+        return get_running_loop()
+
+    @classmethod
+    def current_time(cls) -> float:
+        return get_running_loop().time()
+
+    @classmethod
+    def cancelled_exception_class(cls) -> type[BaseException]:
+        return CancelledError
+
+    @classmethod
+    async def checkpoint(cls) -> None:
+        await sleep(0)
+
+    @classmethod
+    async def checkpoint_if_cancelled(cls) -> None:
+        task = current_task()
+        if task is None:
+            return
+
+        try:
+            cancel_scope = _task_states[task].cancel_scope
+        except KeyError:
+            return
+
+        while cancel_scope:
+            if cancel_scope.cancel_called:
+                await sleep(0)
+            elif cancel_scope.shield:
+                break
+            else:
+                cancel_scope = cancel_scope._parent_scope
+
+    @classmethod
+    async def cancel_shielded_checkpoint(cls) -> None:
+        with CancelScope(shield=True):
+            await sleep(0)
+
+    @classmethod
+    async def sleep(cls, delay: float) -> None:
+        await sleep(delay)
+
+    @classmethod
+    def create_cancel_scope(
+        cls, *, deadline: float = math.inf, shield: bool = False
+    ) -> CancelScope:
+        return CancelScope(deadline=deadline, shield=shield)
+
+    @classmethod
+    def current_effective_deadline(cls) -> float:
+        if (task := current_task()) is None:
+            return math.inf
+
+        try:
+            cancel_scope = _task_states[task].cancel_scope
+        except KeyError:
+            return math.inf
+
+        deadline = math.inf
+        while cancel_scope:
+            deadline = min(deadline, cancel_scope.deadline)
+            if cancel_scope._cancel_called:
+                deadline = -math.inf
+                break
+            elif cancel_scope.shield:
+                break
+            else:
+                cancel_scope = cancel_scope._parent_scope
+
+        return deadline
+
+    @classmethod
+    def create_task_group(cls) -> abc.TaskGroup:
+        return TaskGroup()
+
+    @classmethod
+    def create_event(cls) -> abc.Event:
+        return Event()
+
+    @classmethod
+    def create_lock(cls, *, fast_acquire: bool) -> abc.Lock:
+        return Lock(fast_acquire=fast_acquire)
+
+    @classmethod
+    def create_semaphore(
+        cls,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> abc.Semaphore:
+        return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire)
+
+    @classmethod
+    def create_capacity_limiter(cls, total_tokens: float) -> abc.CapacityLimiter:
+        return CapacityLimiter(total_tokens)
+
+    @classmethod
+    async def run_sync_in_worker_thread(  # type: ignore[return]
+        cls,
+        func: Callable[[Unpack[PosArgsT]], T_Retval],
+        args: tuple[Unpack[PosArgsT]],
+        abandon_on_cancel: bool = False,
+        limiter: abc.CapacityLimiter | None = None,
+    ) -> T_Retval:
+        await cls.checkpoint()
+
+        # If this is the first run in this event loop thread, set up the necessary
+        # variables
+        try:
+            idle_workers = _threadpool_idle_workers.get()
+            workers = _threadpool_workers.get()
+        except LookupError:
+            idle_workers = deque()
+            workers = set()
+            _threadpool_idle_workers.set(idle_workers)
+            _threadpool_workers.set(workers)
+
+        async with limiter or cls.current_default_thread_limiter():
+            with CancelScope(shield=not abandon_on_cancel) as scope:
+                future = asyncio.Future[T_Retval]()
+                root_task = find_root_task()
+                if not idle_workers:
+                    worker = WorkerThread(root_task, workers, idle_workers)
+                    worker.start()
+                    workers.add(worker)
+                    root_task.add_done_callback(
+                        worker.stop, context=contextvars.Context()
+                    )
+                else:
+                    worker = idle_workers.pop()
+
+                    # Prune any other workers that have been idle for MAX_IDLE_TIME
+                    # seconds or longer
+                    now = cls.current_time()
+                    while idle_workers:
+                        if (
+                            now - idle_workers[0].idle_since
+                            < WorkerThread.MAX_IDLE_TIME
+                        ):
+                            break
+
+                        expired_worker = idle_workers.popleft()
+                        expired_worker.root_task.remove_done_callback(
+                            expired_worker.stop
+                        )
+                        expired_worker.stop()
+
+                context = copy_context()
+                context.run(set_current_async_library, None)
+                if abandon_on_cancel or scope._parent_scope is None:
+                    worker_scope = scope
+                else:
+                    worker_scope = scope._parent_scope
+
+                worker.queue.put_nowait((context, func, args, future, worker_scope))
+                return await future
+
+    @classmethod
+    def check_cancelled(cls) -> None:
+        scope: CancelScope | None = threadlocals.current_cancel_scope
+        while scope is not None:
+            if scope.cancel_called:
+                raise CancelledError(f"Cancelled by cancel scope {id(scope):x}")
+
+            if scope.shield:
+                return
+
+            scope = scope._parent_scope
+
+    @classmethod
+    def run_async_from_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+        args: tuple[Unpack[PosArgsT]],
+        token: object,
+    ) -> T_Retval:
+        async def task_wrapper() -> T_Retval:
+            __tracebackhide__ = True
+            if scope is not None:
+                task = cast(asyncio.Task, current_task())
+                _task_states[task] = TaskState(None, scope)
+                scope._tasks.add(task)
+            try:
+                return await func(*args)
+            except CancelledError as exc:
+                raise concurrent.futures.CancelledError(str(exc)) from None
+            finally:
+                if scope is not None:
+                    scope._tasks.discard(task)
+
+        loop = cast(
+            "AbstractEventLoop", token or threadlocals.current_token.native_token
+        )
+        if loop.is_closed():
+            raise RunFinishedError
+
+        context = copy_context()
+        context.run(set_current_async_library, "asyncio")
+        scope = getattr(threadlocals, "current_cancel_scope", None)
+        f: concurrent.futures.Future[T_Retval] = context.run(
+            asyncio.run_coroutine_threadsafe, task_wrapper(), loop=loop
+        )
+        return f.result()
+
+    @classmethod
+    def run_sync_from_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], T_Retval],
+        args: tuple[Unpack[PosArgsT]],
+        token: object,
+    ) -> T_Retval:
+        @wraps(func)
+        def wrapper() -> None:
+            try:
+                set_current_async_library("asyncio")
+                f.set_result(func(*args))
+            except BaseException as exc:
+                f.set_exception(exc)
+                if not isinstance(exc, Exception):
+                    raise
+
+        loop = cast(
+            "AbstractEventLoop", token or threadlocals.current_token.native_token
+        )
+        if loop.is_closed():
+            raise RunFinishedError
+
+        f: concurrent.futures.Future[T_Retval] = Future()
+        loop.call_soon_threadsafe(wrapper)
+        return f.result()
+
+    @classmethod
+    async def open_process(
+        cls,
+        command: StrOrBytesPath | Sequence[StrOrBytesPath],
+        *,
+        stdin: int | IO[Any] | None,
+        stdout: int | IO[Any] | None,
+        stderr: int | IO[Any] | None,
+        **kwargs: Any,
+    ) -> Process:
+        await cls.checkpoint()
+        if isinstance(command, PathLike):
+            command = os.fspath(command)
+
+        if isinstance(command, (str, bytes)):
+            process = await asyncio.create_subprocess_shell(
+                command,
+                stdin=stdin,
+                stdout=stdout,
+                stderr=stderr,
+                **kwargs,
+            )
+        else:
+            process = await asyncio.create_subprocess_exec(
+                *command,
+                stdin=stdin,
+                stdout=stdout,
+                stderr=stderr,
+                **kwargs,
+            )
+
+        stdin_stream = StreamWriterWrapper(process.stdin) if process.stdin else None
+        stdout_stream = StreamReaderWrapper(process.stdout) if process.stdout else None
+        stderr_stream = StreamReaderWrapper(process.stderr) if process.stderr else None
+        return Process(process, stdin_stream, stdout_stream, stderr_stream)
+
+    @classmethod
+    def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None:
+        create_task(
+            _shutdown_process_pool_on_exit(workers),
+            name="AnyIO process pool shutdown task",
+        )
+        find_root_task().add_done_callback(
+            partial(_forcibly_shutdown_process_pool_on_exit, workers)  # type:ignore[arg-type]
+        )
+
+    @classmethod
+    async def connect_tcp(
+        cls, host: str, port: int, local_address: IPSockAddrType | None = None
+    ) -> abc.SocketStream:
+        transport, protocol = cast(
+            tuple[asyncio.Transport, StreamProtocol],
+            await get_running_loop().create_connection(
+                StreamProtocol, host, port, local_addr=local_address
+            ),
+        )
+        transport.pause_reading()
+        return SocketStream(transport, protocol)
+
+    @classmethod
+    async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream:
+        await cls.checkpoint()
+        loop = get_running_loop()
+        raw_socket = socket.socket(socket.AF_UNIX)
+        raw_socket.setblocking(False)
+        while True:
+            try:
+                raw_socket.connect(path)
+            except BlockingIOError:
+                f: asyncio.Future = asyncio.Future()
+                loop.add_writer(raw_socket, f.set_result, None)
+                f.add_done_callback(lambda _: loop.remove_writer(raw_socket))
+                await f
+            except BaseException:
+                raw_socket.close()
+                raise
+            else:
+                return UNIXSocketStream(raw_socket)
+
+    @classmethod
+    def create_tcp_listener(cls, sock: socket.socket) -> SocketListener:
+        return TCPSocketListener(sock)
+
+    @classmethod
+    def create_unix_listener(cls, sock: socket.socket) -> SocketListener:
+        return UNIXSocketListener(sock)
+
+    @classmethod
+    async def create_udp_socket(
+        cls,
+        family: AddressFamily,
+        local_address: IPSockAddrType | None,
+        remote_address: IPSockAddrType | None,
+        reuse_port: bool,
+    ) -> UDPSocket | ConnectedUDPSocket:
+        transport, protocol = await get_running_loop().create_datagram_endpoint(
+            DatagramProtocol,
+            local_addr=local_address,
+            remote_addr=remote_address,
+            family=family,
+            reuse_port=reuse_port,
+        )
+        if protocol.exception:
+            transport.close()
+            raise protocol.exception
+
+        if not remote_address:
+            return UDPSocket(transport, protocol)
+        else:
+            return ConnectedUDPSocket(transport, protocol)
+
+    @classmethod
+    async def create_unix_datagram_socket(  # type: ignore[override]
+        cls, raw_socket: socket.socket, remote_path: str | bytes | None
+    ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket:
+        await cls.checkpoint()
+        loop = get_running_loop()
+
+        if remote_path:
+            while True:
+                try:
+                    raw_socket.connect(remote_path)
+                except BlockingIOError:
+                    f: asyncio.Future = asyncio.Future()
+                    loop.add_writer(raw_socket, f.set_result, None)
+                    f.add_done_callback(lambda _: loop.remove_writer(raw_socket))
+                    await f
+                except BaseException:
+                    raw_socket.close()
+                    raise
+                else:
+                    return ConnectedUNIXDatagramSocket(raw_socket)
+        else:
+            return UNIXDatagramSocket(raw_socket)
+
+    @classmethod
+    async def getaddrinfo(
+        cls,
+        host: bytes | str | None,
+        port: str | int | None,
+        *,
+        family: int | AddressFamily = 0,
+        type: int | SocketKind = 0,
+        proto: int = 0,
+        flags: int = 0,
+    ) -> Sequence[
+        tuple[
+            AddressFamily,
+            SocketKind,
+            int,
+            str,
+            tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
+        ]
+    ]:
+        return await get_running_loop().getaddrinfo(
+            host, port, family=family, type=type, proto=proto, flags=flags
+        )
+
+    @classmethod
+    async def getnameinfo(
+        cls, sockaddr: IPSockAddrType, flags: int = 0
+    ) -> tuple[str, str]:
+        return await get_running_loop().getnameinfo(sockaddr, flags)
+
+    @classmethod
+    async def wait_readable(cls, obj: FileDescriptorLike) -> None:
+        try:
+            read_events = _read_events.get()
+        except LookupError:
+            read_events = {}
+            _read_events.set(read_events)
+
+        fd = obj if isinstance(obj, int) else obj.fileno()
+        if read_events.get(fd):
+            raise BusyResourceError("reading from")
+
+        loop = get_running_loop()
+        fut: asyncio.Future[bool] = loop.create_future()
+
+        def cb() -> None:
+            try:
+                del read_events[fd]
+            except KeyError:
+                pass
+            else:
+                remove_reader(fd)
+
+            try:
+                fut.set_result(True)
+            except asyncio.InvalidStateError:
+                pass
+
+        try:
+            loop.add_reader(fd, cb)
+        except NotImplementedError:
+            from anyio._core._asyncio_selector_thread import get_selector
+
+            selector = get_selector()
+            selector.add_reader(fd, cb)
+            remove_reader = selector.remove_reader
+        else:
+            remove_reader = loop.remove_reader
+
+        read_events[fd] = fut
+        try:
+            success = await fut
+        finally:
+            try:
+                del read_events[fd]
+            except KeyError:
+                pass
+            else:
+                remove_reader(fd)
+
+        if not success:
+            raise ClosedResourceError
+
+    @classmethod
+    async def wait_writable(cls, obj: FileDescriptorLike) -> None:
+        try:
+            write_events = _write_events.get()
+        except LookupError:
+            write_events = {}
+            _write_events.set(write_events)
+
+        fd = obj if isinstance(obj, int) else obj.fileno()
+        if write_events.get(fd):
+            raise BusyResourceError("writing to")
+
+        loop = get_running_loop()
+        fut: asyncio.Future[bool] = loop.create_future()
+
+        def cb() -> None:
+            try:
+                del write_events[fd]
+            except KeyError:
+                pass
+            else:
+                remove_writer(fd)
+
+            try:
+                fut.set_result(True)
+            except asyncio.InvalidStateError:
+                pass
+
+        try:
+            loop.add_writer(fd, cb)
+        except NotImplementedError:
+            from anyio._core._asyncio_selector_thread import get_selector
+
+            selector = get_selector()
+            selector.add_writer(fd, cb)
+            remove_writer = selector.remove_writer
+        else:
+            remove_writer = loop.remove_writer
+
+        write_events[fd] = fut
+        try:
+            success = await fut
+        finally:
+            try:
+                del write_events[fd]
+            except KeyError:
+                pass
+            else:
+                remove_writer(fd)
+
+        if not success:
+            raise ClosedResourceError
+
+    @classmethod
+    def notify_closing(cls, obj: FileDescriptorLike) -> None:
+        fd = obj if isinstance(obj, int) else obj.fileno()
+        loop = get_running_loop()
+
+        try:
+            write_events = _write_events.get()
+        except LookupError:
+            pass
+        else:
+            try:
+                fut = write_events.pop(fd)
+            except KeyError:
+                pass
+            else:
+                try:
+                    fut.set_result(False)
+                except asyncio.InvalidStateError:
+                    pass
+
+                try:
+                    loop.remove_writer(fd)
+                except NotImplementedError:
+                    from anyio._core._asyncio_selector_thread import get_selector
+
+                    get_selector().remove_writer(fd)
+
+        try:
+            read_events = _read_events.get()
+        except LookupError:
+            pass
+        else:
+            try:
+                fut = read_events.pop(fd)
+            except KeyError:
+                pass
+            else:
+                try:
+                    fut.set_result(False)
+                except asyncio.InvalidStateError:
+                    pass
+
+                try:
+                    loop.remove_reader(fd)
+                except NotImplementedError:
+                    from anyio._core._asyncio_selector_thread import get_selector
+
+                    get_selector().remove_reader(fd)
+
+    @classmethod
+    async def wrap_listener_socket(cls, sock: socket.socket) -> SocketListener:
+        return TCPSocketListener(sock)
+
+    @classmethod
+    async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream:
+        transport, protocol = await get_running_loop().create_connection(
+            StreamProtocol, sock=sock
+        )
+        return SocketStream(transport, protocol)
+
+    @classmethod
+    async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream:
+        return UNIXSocketStream(sock)
+
+    @classmethod
+    async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket:
+        transport, protocol = await get_running_loop().create_datagram_endpoint(
+            DatagramProtocol, sock=sock
+        )
+        return UDPSocket(transport, protocol)
+
+    @classmethod
+    async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket:
+        transport, protocol = await get_running_loop().create_datagram_endpoint(
+            DatagramProtocol, sock=sock
+        )
+        return ConnectedUDPSocket(transport, protocol)
+
+    @classmethod
+    async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket:
+        return UNIXDatagramSocket(sock)
+
+    @classmethod
+    async def wrap_connected_unix_datagram_socket(
+        cls, sock: socket.socket
+    ) -> ConnectedUNIXDatagramSocket:
+        return ConnectedUNIXDatagramSocket(sock)
+
+    @classmethod
+    def current_default_thread_limiter(cls) -> CapacityLimiter:
+        try:
+            return _default_thread_limiter.get()
+        except LookupError:
+            limiter = CapacityLimiter(40)
+            _default_thread_limiter.set(limiter)
+            return limiter
+
+    @classmethod
+    def open_signal_receiver(
+        cls, *signals: Signals
+    ) -> AbstractContextManager[AsyncIterator[Signals]]:
+        return _SignalReceiver(signals)
+
+    @classmethod
+    def get_current_task(cls) -> TaskInfo:
+        return AsyncIOTaskInfo(current_task())  # type: ignore[arg-type]
+
+    @classmethod
+    def get_running_tasks(cls) -> Sequence[TaskInfo]:
+        return [AsyncIOTaskInfo(task) for task in all_tasks() if not task.done()]
+
+    @classmethod
+    async def wait_all_tasks_blocked(cls) -> None:
+        await cls.checkpoint()
+        this_task = current_task()
+        while True:
+            for task in all_tasks():
+                if task is this_task:
+                    continue
+
+                waiter = task._fut_waiter  # type: ignore[attr-defined]
+                if waiter is None or waiter.done():
+                    await sleep(0.1)
+                    break
+            else:
+                return
+
+    @classmethod
+    def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
+        return TestRunner(**options)
+
+
+backend_class = AsyncIOBackend

+ 1346 - 0
.venv/lib/python3.9/site-packages/anyio/_backends/_trio.py

@@ -0,0 +1,1346 @@
+from __future__ import annotations
+
+import array
+import math
+import os
+import socket
+import sys
+import types
+import weakref
+from collections.abc import (
+    AsyncGenerator,
+    AsyncIterator,
+    Awaitable,
+    Callable,
+    Collection,
+    Coroutine,
+    Iterable,
+    Sequence,
+)
+from contextlib import AbstractContextManager
+from dataclasses import dataclass
+from io import IOBase
+from os import PathLike
+from signal import Signals
+from socket import AddressFamily, SocketKind
+from types import TracebackType
+from typing import (
+    IO,
+    TYPE_CHECKING,
+    Any,
+    Generic,
+    NoReturn,
+    TypeVar,
+    cast,
+    overload,
+)
+
+import trio.from_thread
+import trio.lowlevel
+from outcome import Error, Outcome, Value
+from trio.lowlevel import (
+    current_root_task,
+    current_task,
+    notify_closing,
+    wait_readable,
+    wait_writable,
+)
+from trio.socket import SocketType as TrioSocketType
+from trio.to_thread import run_sync
+
+from .. import (
+    CapacityLimiterStatistics,
+    EventStatistics,
+    LockStatistics,
+    RunFinishedError,
+    TaskInfo,
+    WouldBlock,
+    abc,
+)
+from .._core._eventloop import claim_worker_thread
+from .._core._exceptions import (
+    BrokenResourceError,
+    BusyResourceError,
+    ClosedResourceError,
+    EndOfStream,
+)
+from .._core._sockets import convert_ipv6_sockaddr
+from .._core._streams import create_memory_object_stream
+from .._core._synchronization import (
+    CapacityLimiter as BaseCapacityLimiter,
+)
+from .._core._synchronization import Event as BaseEvent
+from .._core._synchronization import Lock as BaseLock
+from .._core._synchronization import (
+    ResourceGuard,
+    SemaphoreStatistics,
+)
+from .._core._synchronization import Semaphore as BaseSemaphore
+from .._core._tasks import CancelScope as BaseCancelScope
+from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType
+from ..abc._eventloop import AsyncBackend, StrOrBytesPath
+from ..streams.memory import MemoryObjectSendStream
+
+if TYPE_CHECKING:
+    from _typeshed import FileDescriptorLike
+
+if sys.version_info >= (3, 10):
+    from typing import ParamSpec
+else:
+    from typing_extensions import ParamSpec
+
+if sys.version_info >= (3, 11):
+    from typing import TypeVarTuple, Unpack
+else:
+    from exceptiongroup import BaseExceptionGroup
+    from typing_extensions import TypeVarTuple, Unpack
+
+T = TypeVar("T")
+T_Retval = TypeVar("T_Retval")
+T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType)
+PosArgsT = TypeVarTuple("PosArgsT")
+P = ParamSpec("P")
+
+
+#
+# Event loop
+#
+
+RunVar = trio.lowlevel.RunVar
+
+
+#
+# Timeouts and cancellation
+#
+
+
+class CancelScope(BaseCancelScope):
+    def __new__(
+        cls, original: trio.CancelScope | None = None, **kwargs: object
+    ) -> CancelScope:
+        return object.__new__(cls)
+
+    def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None:
+        self.__original = original or trio.CancelScope(**kwargs)
+
+    def __enter__(self) -> CancelScope:
+        self.__original.__enter__()
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> bool:
+        return self.__original.__exit__(exc_type, exc_val, exc_tb)
+
+    def cancel(self, reason: str | None = None) -> None:
+        self.__original.cancel(reason)
+
+    @property
+    def deadline(self) -> float:
+        return self.__original.deadline
+
+    @deadline.setter
+    def deadline(self, value: float) -> None:
+        self.__original.deadline = value
+
+    @property
+    def cancel_called(self) -> bool:
+        return self.__original.cancel_called
+
+    @property
+    def cancelled_caught(self) -> bool:
+        return self.__original.cancelled_caught
+
+    @property
+    def shield(self) -> bool:
+        return self.__original.shield
+
+    @shield.setter
+    def shield(self, value: bool) -> None:
+        self.__original.shield = value
+
+
+#
+# Task groups
+#
+
+
+class TaskGroup(abc.TaskGroup):
+    def __init__(self) -> None:
+        self._active = False
+        self._nursery_manager = trio.open_nursery(strict_exception_groups=True)
+        self.cancel_scope = None  # type: ignore[assignment]
+
+    async def __aenter__(self) -> TaskGroup:
+        self._active = True
+        self._nursery = await self._nursery_manager.__aenter__()
+        self.cancel_scope = CancelScope(self._nursery.cancel_scope)
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> bool:
+        try:
+            # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type
+            return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb)  # type: ignore[return-value]
+        except BaseExceptionGroup as exc:
+            if not exc.split(trio.Cancelled)[1]:
+                raise trio.Cancelled._create() from exc
+
+            raise
+        finally:
+            del exc_val, exc_tb
+            self._active = False
+
+    def start_soon(
+        self,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[Any]],
+        *args: Unpack[PosArgsT],
+        name: object = None,
+    ) -> None:
+        if not self._active:
+            raise RuntimeError(
+                "This task group is not active; no new tasks can be started."
+            )
+
+        self._nursery.start_soon(func, *args, name=name)
+
+    async def start(
+        self, func: Callable[..., Awaitable[Any]], *args: object, name: object = None
+    ) -> Any:
+        if not self._active:
+            raise RuntimeError(
+                "This task group is not active; no new tasks can be started."
+            )
+
+        return await self._nursery.start(func, *args, name=name)
+
+
+#
+# Subprocesses
+#
+
+
+@dataclass(eq=False)
+class ReceiveStreamWrapper(abc.ByteReceiveStream):
+    _stream: trio.abc.ReceiveStream
+
+    async def receive(self, max_bytes: int | None = None) -> bytes:
+        try:
+            data = await self._stream.receive_some(max_bytes)
+        except trio.ClosedResourceError as exc:
+            raise ClosedResourceError from exc.__cause__
+        except trio.BrokenResourceError as exc:
+            raise BrokenResourceError from exc.__cause__
+
+        if data:
+            return bytes(data)
+        else:
+            raise EndOfStream
+
+    async def aclose(self) -> None:
+        await self._stream.aclose()
+
+
+@dataclass(eq=False)
+class SendStreamWrapper(abc.ByteSendStream):
+    _stream: trio.abc.SendStream
+
+    async def send(self, item: bytes) -> None:
+        try:
+            await self._stream.send_all(item)
+        except trio.ClosedResourceError as exc:
+            raise ClosedResourceError from exc.__cause__
+        except trio.BrokenResourceError as exc:
+            raise BrokenResourceError from exc.__cause__
+
+    async def aclose(self) -> None:
+        await self._stream.aclose()
+
+
+@dataclass(eq=False)
+class Process(abc.Process):
+    _process: trio.Process
+    _stdin: abc.ByteSendStream | None
+    _stdout: abc.ByteReceiveStream | None
+    _stderr: abc.ByteReceiveStream | None
+
+    async def aclose(self) -> None:
+        with CancelScope(shield=True):
+            if self._stdin:
+                await self._stdin.aclose()
+            if self._stdout:
+                await self._stdout.aclose()
+            if self._stderr:
+                await self._stderr.aclose()
+
+        try:
+            await self.wait()
+        except BaseException:
+            self.kill()
+            with CancelScope(shield=True):
+                await self.wait()
+            raise
+
+    async def wait(self) -> int:
+        return await self._process.wait()
+
+    def terminate(self) -> None:
+        self._process.terminate()
+
+    def kill(self) -> None:
+        self._process.kill()
+
+    def send_signal(self, signal: Signals) -> None:
+        self._process.send_signal(signal)
+
+    @property
+    def pid(self) -> int:
+        return self._process.pid
+
+    @property
+    def returncode(self) -> int | None:
+        return self._process.returncode
+
+    @property
+    def stdin(self) -> abc.ByteSendStream | None:
+        return self._stdin
+
+    @property
+    def stdout(self) -> abc.ByteReceiveStream | None:
+        return self._stdout
+
+    @property
+    def stderr(self) -> abc.ByteReceiveStream | None:
+        return self._stderr
+
+
+class _ProcessPoolShutdownInstrument(trio.abc.Instrument):
+    def after_run(self) -> None:
+        super().after_run()
+
+
+current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar(
+    "current_default_worker_process_limiter"
+)
+
+
+async def _shutdown_process_pool(workers: set[abc.Process]) -> None:
+    try:
+        await trio.sleep(math.inf)
+    except trio.Cancelled:
+        for process in workers:
+            if process.returncode is None:
+                process.kill()
+
+        with CancelScope(shield=True):
+            for process in workers:
+                await process.aclose()
+
+
+#
+# Sockets and networking
+#
+
+
+class _TrioSocketMixin(Generic[T_SockAddr]):
+    def __init__(self, trio_socket: TrioSocketType) -> None:
+        self._trio_socket = trio_socket
+        self._closed = False
+
+    def _check_closed(self) -> None:
+        if self._closed:
+            raise ClosedResourceError
+        if self._trio_socket.fileno() < 0:
+            raise BrokenResourceError
+
+    @property
+    def _raw_socket(self) -> socket.socket:
+        return self._trio_socket._sock  # type: ignore[attr-defined]
+
+    async def aclose(self) -> None:
+        if self._trio_socket.fileno() >= 0:
+            self._closed = True
+            self._trio_socket.close()
+
+    def _convert_socket_error(self, exc: BaseException) -> NoReturn:
+        if isinstance(exc, trio.ClosedResourceError):
+            raise ClosedResourceError from exc
+        elif self._trio_socket.fileno() < 0 and self._closed:
+            raise ClosedResourceError from None
+        elif isinstance(exc, OSError):
+            raise BrokenResourceError from exc
+        else:
+            raise exc
+
+
+class SocketStream(_TrioSocketMixin, abc.SocketStream):
+    def __init__(self, trio_socket: TrioSocketType) -> None:
+        super().__init__(trio_socket)
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+
+    async def receive(self, max_bytes: int = 65536) -> bytes:
+        with self._receive_guard:
+            try:
+                data = await self._trio_socket.recv(max_bytes)
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+            if data:
+                return data
+            else:
+                raise EndOfStream
+
+    async def send(self, item: bytes) -> None:
+        with self._send_guard:
+            view = memoryview(item)
+            while view:
+                try:
+                    bytes_sent = await self._trio_socket.send(view)
+                except BaseException as exc:
+                    self._convert_socket_error(exc)
+
+                view = view[bytes_sent:]
+
+    async def send_eof(self) -> None:
+        self._trio_socket.shutdown(socket.SHUT_WR)
+
+
+class UNIXSocketStream(SocketStream, abc.UNIXSocketStream):
+    async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]:
+        if not isinstance(msglen, int) or msglen < 0:
+            raise ValueError("msglen must be a non-negative integer")
+        if not isinstance(maxfds, int) or maxfds < 1:
+            raise ValueError("maxfds must be a positive integer")
+
+        fds = array.array("i")
+        await trio.lowlevel.checkpoint()
+        with self._receive_guard:
+            while True:
+                try:
+                    message, ancdata, flags, addr = await self._trio_socket.recvmsg(
+                        msglen, socket.CMSG_LEN(maxfds * fds.itemsize)
+                    )
+                except BaseException as exc:
+                    self._convert_socket_error(exc)
+                else:
+                    if not message and not ancdata:
+                        raise EndOfStream
+
+                    break
+
+        for cmsg_level, cmsg_type, cmsg_data in ancdata:
+            if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS:
+                raise RuntimeError(
+                    f"Received unexpected ancillary data; message = {message!r}, "
+                    f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}"
+                )
+
+            fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
+
+        return message, list(fds)
+
+    async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None:
+        if not message:
+            raise ValueError("message must not be empty")
+        if not fds:
+            raise ValueError("fds must not be empty")
+
+        filenos: list[int] = []
+        for fd in fds:
+            if isinstance(fd, int):
+                filenos.append(fd)
+            elif isinstance(fd, IOBase):
+                filenos.append(fd.fileno())
+
+        fdarray = array.array("i", filenos)
+        await trio.lowlevel.checkpoint()
+        with self._send_guard:
+            while True:
+                try:
+                    await self._trio_socket.sendmsg(
+                        [message],
+                        [
+                            (
+                                socket.SOL_SOCKET,
+                                socket.SCM_RIGHTS,
+                                fdarray,
+                            )
+                        ],
+                    )
+                    break
+                except BaseException as exc:
+                    self._convert_socket_error(exc)
+
+
+class TCPSocketListener(_TrioSocketMixin, abc.SocketListener):
+    def __init__(self, raw_socket: socket.socket):
+        super().__init__(trio.socket.from_stdlib_socket(raw_socket))
+        self._accept_guard = ResourceGuard("accepting connections from")
+
+    async def accept(self) -> SocketStream:
+        with self._accept_guard:
+            try:
+                trio_socket, _addr = await self._trio_socket.accept()
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+        trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+        return SocketStream(trio_socket)
+
+
+class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener):
+    def __init__(self, raw_socket: socket.socket):
+        super().__init__(trio.socket.from_stdlib_socket(raw_socket))
+        self._accept_guard = ResourceGuard("accepting connections from")
+
+    async def accept(self) -> UNIXSocketStream:
+        with self._accept_guard:
+            try:
+                trio_socket, _addr = await self._trio_socket.accept()
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+        return UNIXSocketStream(trio_socket)
+
+
+class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket):
+    def __init__(self, trio_socket: TrioSocketType) -> None:
+        super().__init__(trio_socket)
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+
+    async def receive(self) -> tuple[bytes, IPSockAddrType]:
+        with self._receive_guard:
+            try:
+                data, addr = await self._trio_socket.recvfrom(65536)
+                return data, convert_ipv6_sockaddr(addr)
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+    async def send(self, item: UDPPacketType) -> None:
+        with self._send_guard:
+            try:
+                await self._trio_socket.sendto(*item)
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+
+class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket):
+    def __init__(self, trio_socket: TrioSocketType) -> None:
+        super().__init__(trio_socket)
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+
+    async def receive(self) -> bytes:
+        with self._receive_guard:
+            try:
+                return await self._trio_socket.recv(65536)
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+    async def send(self, item: bytes) -> None:
+        with self._send_guard:
+            try:
+                await self._trio_socket.send(item)
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+
+class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket):
+    def __init__(self, trio_socket: TrioSocketType) -> None:
+        super().__init__(trio_socket)
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+
+    async def receive(self) -> UNIXDatagramPacketType:
+        with self._receive_guard:
+            try:
+                data, addr = await self._trio_socket.recvfrom(65536)
+                return data, addr
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+    async def send(self, item: UNIXDatagramPacketType) -> None:
+        with self._send_guard:
+            try:
+                await self._trio_socket.sendto(*item)
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+
+class ConnectedUNIXDatagramSocket(
+    _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket
+):
+    def __init__(self, trio_socket: TrioSocketType) -> None:
+        super().__init__(trio_socket)
+        self._receive_guard = ResourceGuard("reading from")
+        self._send_guard = ResourceGuard("writing to")
+
+    async def receive(self) -> bytes:
+        with self._receive_guard:
+            try:
+                return await self._trio_socket.recv(65536)
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+    async def send(self, item: bytes) -> None:
+        with self._send_guard:
+            try:
+                await self._trio_socket.send(item)
+            except BaseException as exc:
+                self._convert_socket_error(exc)
+
+
+#
+# Synchronization
+#
+
+
+class Event(BaseEvent):
+    def __new__(cls) -> Event:
+        return object.__new__(cls)
+
+    def __init__(self) -> None:
+        self.__original = trio.Event()
+
+    def is_set(self) -> bool:
+        return self.__original.is_set()
+
+    async def wait(self) -> None:
+        return await self.__original.wait()
+
+    def statistics(self) -> EventStatistics:
+        orig_statistics = self.__original.statistics()
+        return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting)
+
+    def set(self) -> None:
+        self.__original.set()
+
+
+class Lock(BaseLock):
+    def __new__(cls, *, fast_acquire: bool = False) -> Lock:
+        return object.__new__(cls)
+
+    def __init__(self, *, fast_acquire: bool = False) -> None:
+        self._fast_acquire = fast_acquire
+        self.__original = trio.Lock()
+
+    @staticmethod
+    def _convert_runtime_error_msg(exc: RuntimeError) -> None:
+        if exc.args == ("attempt to re-acquire an already held Lock",):
+            exc.args = ("Attempted to acquire an already held Lock",)
+
+    async def acquire(self) -> None:
+        if not self._fast_acquire:
+            try:
+                await self.__original.acquire()
+            except RuntimeError as exc:
+                self._convert_runtime_error_msg(exc)
+                raise
+
+            return
+
+        # This is the "fast path" where we don't let other tasks run
+        await trio.lowlevel.checkpoint_if_cancelled()
+        try:
+            self.__original.acquire_nowait()
+        except trio.WouldBlock:
+            await self.__original._lot.park()
+        except RuntimeError as exc:
+            self._convert_runtime_error_msg(exc)
+            raise
+
+    def acquire_nowait(self) -> None:
+        try:
+            self.__original.acquire_nowait()
+        except trio.WouldBlock:
+            raise WouldBlock from None
+        except RuntimeError as exc:
+            self._convert_runtime_error_msg(exc)
+            raise
+
+    def locked(self) -> bool:
+        return self.__original.locked()
+
+    def release(self) -> None:
+        self.__original.release()
+
+    def statistics(self) -> LockStatistics:
+        orig_statistics = self.__original.statistics()
+        owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None
+        return LockStatistics(
+            orig_statistics.locked, owner, orig_statistics.tasks_waiting
+        )
+
+
+class Semaphore(BaseSemaphore):
+    def __new__(
+        cls,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> Semaphore:
+        return object.__new__(cls)
+
+    def __init__(
+        self,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> None:
+        super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
+        self.__original = trio.Semaphore(initial_value, max_value=max_value)
+
+    async def acquire(self) -> None:
+        if not self._fast_acquire:
+            await self.__original.acquire()
+            return
+
+        # This is the "fast path" where we don't let other tasks run
+        await trio.lowlevel.checkpoint_if_cancelled()
+        try:
+            self.__original.acquire_nowait()
+        except trio.WouldBlock:
+            await self.__original._lot.park()
+
+    def acquire_nowait(self) -> None:
+        try:
+            self.__original.acquire_nowait()
+        except trio.WouldBlock:
+            raise WouldBlock from None
+
+    @property
+    def max_value(self) -> int | None:
+        return self.__original.max_value
+
+    @property
+    def value(self) -> int:
+        return self.__original.value
+
+    def release(self) -> None:
+        self.__original.release()
+
+    def statistics(self) -> SemaphoreStatistics:
+        orig_statistics = self.__original.statistics()
+        return SemaphoreStatistics(orig_statistics.tasks_waiting)
+
+
+class CapacityLimiter(BaseCapacityLimiter):
+    def __new__(
+        cls,
+        total_tokens: float | None = None,
+        *,
+        original: trio.CapacityLimiter | None = None,
+    ) -> CapacityLimiter:
+        return object.__new__(cls)
+
+    def __init__(
+        self,
+        total_tokens: float | None = None,
+        *,
+        original: trio.CapacityLimiter | None = None,
+    ) -> None:
+        if original is not None:
+            self.__original = original
+        else:
+            assert total_tokens is not None
+            self.__original = trio.CapacityLimiter(total_tokens)
+
+    async def __aenter__(self) -> None:
+        return await self.__original.__aenter__()
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        await self.__original.__aexit__(exc_type, exc_val, exc_tb)
+
+    @property
+    def total_tokens(self) -> float:
+        return self.__original.total_tokens
+
+    @total_tokens.setter
+    def total_tokens(self, value: float) -> None:
+        self.__original.total_tokens = value
+
+    @property
+    def borrowed_tokens(self) -> int:
+        return self.__original.borrowed_tokens
+
+    @property
+    def available_tokens(self) -> float:
+        return self.__original.available_tokens
+
+    def acquire_nowait(self) -> None:
+        self.__original.acquire_nowait()
+
+    def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
+        self.__original.acquire_on_behalf_of_nowait(borrower)
+
+    async def acquire(self) -> None:
+        await self.__original.acquire()
+
+    async def acquire_on_behalf_of(self, borrower: object) -> None:
+        await self.__original.acquire_on_behalf_of(borrower)
+
+    def release(self) -> None:
+        return self.__original.release()
+
+    def release_on_behalf_of(self, borrower: object) -> None:
+        return self.__original.release_on_behalf_of(borrower)
+
+    def statistics(self) -> CapacityLimiterStatistics:
+        orig = self.__original.statistics()
+        return CapacityLimiterStatistics(
+            borrowed_tokens=orig.borrowed_tokens,
+            total_tokens=orig.total_tokens,
+            borrowers=tuple(orig.borrowers),
+            tasks_waiting=orig.tasks_waiting,
+        )
+
+
+_capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper")
+
+
+#
+# Signal handling
+#
+
+
+class _SignalReceiver:
+    _iterator: AsyncIterator[int]
+
+    def __init__(self, signals: tuple[Signals, ...]):
+        self._signals = signals
+
+    def __enter__(self) -> _SignalReceiver:
+        self._cm = trio.open_signal_receiver(*self._signals)
+        self._iterator = self._cm.__enter__()
+        return self
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> bool | None:
+        return self._cm.__exit__(exc_type, exc_val, exc_tb)
+
+    def __aiter__(self) -> _SignalReceiver:
+        return self
+
+    async def __anext__(self) -> Signals:
+        signum = await self._iterator.__anext__()
+        return Signals(signum)
+
+
+#
+# Testing and debugging
+#
+
+
+class TestRunner(abc.TestRunner):
+    def __init__(self, **options: Any) -> None:
+        from queue import Queue
+
+        self._call_queue: Queue[Callable[[], object]] = Queue()
+        self._send_stream: MemoryObjectSendStream | None = None
+        self._options = options
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: types.TracebackType | None,
+    ) -> None:
+        if self._send_stream:
+            self._send_stream.close()
+            while self._send_stream is not None:
+                self._call_queue.get()()
+
+    async def _run_tests_and_fixtures(self) -> None:
+        self._send_stream, receive_stream = create_memory_object_stream(1)
+        with receive_stream:
+            async for coro, outcome_holder in receive_stream:
+                try:
+                    retval = await coro
+                except BaseException as exc:
+                    outcome_holder.append(Error(exc))
+                else:
+                    outcome_holder.append(Value(retval))
+
+    def _main_task_finished(self, outcome: object) -> None:
+        self._send_stream = None
+
+    def _call_in_runner_task(
+        self,
+        func: Callable[P, Awaitable[T_Retval]],
+        *args: P.args,
+        **kwargs: P.kwargs,
+    ) -> T_Retval:
+        if self._send_stream is None:
+            trio.lowlevel.start_guest_run(
+                self._run_tests_and_fixtures,
+                run_sync_soon_threadsafe=self._call_queue.put,
+                done_callback=self._main_task_finished,
+                **self._options,
+            )
+            while self._send_stream is None:
+                self._call_queue.get()()
+
+        outcome_holder: list[Outcome] = []
+        self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder))
+        while not outcome_holder:
+            self._call_queue.get()()
+
+        return outcome_holder[0].unwrap()
+
+    def run_asyncgen_fixture(
+        self,
+        fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]],
+        kwargs: dict[str, Any],
+    ) -> Iterable[T_Retval]:
+        asyncgen = fixture_func(**kwargs)
+        fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None)
+
+        yield fixturevalue
+
+        try:
+            self._call_in_runner_task(asyncgen.asend, None)
+        except StopAsyncIteration:
+            pass
+        else:
+            self._call_in_runner_task(asyncgen.aclose)
+            raise RuntimeError("Async generator fixture did not stop")
+
+    def run_fixture(
+        self,
+        fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]],
+        kwargs: dict[str, Any],
+    ) -> T_Retval:
+        return self._call_in_runner_task(fixture_func, **kwargs)
+
+    def run_test(
+        self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any]
+    ) -> None:
+        self._call_in_runner_task(test_func, **kwargs)
+
+
+class TrioTaskInfo(TaskInfo):
+    def __init__(self, task: trio.lowlevel.Task):
+        parent_id = None
+        if task.parent_nursery and task.parent_nursery.parent_task:
+            parent_id = id(task.parent_nursery.parent_task)
+
+        super().__init__(id(task), parent_id, task.name, task.coro)
+        self._task = weakref.proxy(task)
+
+    def has_pending_cancellation(self) -> bool:
+        try:
+            return self._task._cancel_status.effectively_cancelled
+        except ReferenceError:
+            # If the task is no longer around, it surely doesn't have a cancellation
+            # pending
+            return False
+
+
+class TrioBackend(AsyncBackend):
+    @classmethod
+    def run(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+        args: tuple[Unpack[PosArgsT]],
+        kwargs: dict[str, Any],
+        options: dict[str, Any],
+    ) -> T_Retval:
+        return trio.run(func, *args)
+
+    @classmethod
+    def current_token(cls) -> object:
+        return trio.lowlevel.current_trio_token()
+
+    @classmethod
+    def current_time(cls) -> float:
+        return trio.current_time()
+
+    @classmethod
+    def cancelled_exception_class(cls) -> type[BaseException]:
+        return trio.Cancelled
+
+    @classmethod
+    async def checkpoint(cls) -> None:
+        await trio.lowlevel.checkpoint()
+
+    @classmethod
+    async def checkpoint_if_cancelled(cls) -> None:
+        await trio.lowlevel.checkpoint_if_cancelled()
+
+    @classmethod
+    async def cancel_shielded_checkpoint(cls) -> None:
+        await trio.lowlevel.cancel_shielded_checkpoint()
+
+    @classmethod
+    async def sleep(cls, delay: float) -> None:
+        await trio.sleep(delay)
+
+    @classmethod
+    def create_cancel_scope(
+        cls, *, deadline: float = math.inf, shield: bool = False
+    ) -> abc.CancelScope:
+        return CancelScope(deadline=deadline, shield=shield)
+
+    @classmethod
+    def current_effective_deadline(cls) -> float:
+        return trio.current_effective_deadline()
+
+    @classmethod
+    def create_task_group(cls) -> abc.TaskGroup:
+        return TaskGroup()
+
+    @classmethod
+    def create_event(cls) -> abc.Event:
+        return Event()
+
+    @classmethod
+    def create_lock(cls, *, fast_acquire: bool) -> Lock:
+        return Lock(fast_acquire=fast_acquire)
+
+    @classmethod
+    def create_semaphore(
+        cls,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> abc.Semaphore:
+        return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire)
+
+    @classmethod
+    def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
+        return CapacityLimiter(total_tokens)
+
+    @classmethod
+    async def run_sync_in_worker_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], T_Retval],
+        args: tuple[Unpack[PosArgsT]],
+        abandon_on_cancel: bool = False,
+        limiter: abc.CapacityLimiter | None = None,
+    ) -> T_Retval:
+        def wrapper() -> T_Retval:
+            with claim_worker_thread(TrioBackend, token):
+                return func(*args)
+
+        token = TrioBackend.current_token()
+        return await run_sync(
+            wrapper,
+            abandon_on_cancel=abandon_on_cancel,
+            limiter=cast(trio.CapacityLimiter, limiter),
+        )
+
+    @classmethod
+    def check_cancelled(cls) -> None:
+        trio.from_thread.check_cancelled()
+
+    @classmethod
+    def run_async_from_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+        args: tuple[Unpack[PosArgsT]],
+        token: object,
+    ) -> T_Retval:
+        trio_token = cast("trio.lowlevel.TrioToken | None", token)
+        try:
+            return trio.from_thread.run(func, *args, trio_token=trio_token)
+        except trio.RunFinishedError:
+            raise RunFinishedError from None
+
+    @classmethod
+    def run_sync_from_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], T_Retval],
+        args: tuple[Unpack[PosArgsT]],
+        token: object,
+    ) -> T_Retval:
+        trio_token = cast("trio.lowlevel.TrioToken | None", token)
+        try:
+            return trio.from_thread.run_sync(func, *args, trio_token=trio_token)
+        except trio.RunFinishedError:
+            raise RunFinishedError from None
+
+    @classmethod
+    async def open_process(
+        cls,
+        command: StrOrBytesPath | Sequence[StrOrBytesPath],
+        *,
+        stdin: int | IO[Any] | None,
+        stdout: int | IO[Any] | None,
+        stderr: int | IO[Any] | None,
+        **kwargs: Any,
+    ) -> Process:
+        def convert_item(item: StrOrBytesPath) -> str:
+            str_or_bytes = os.fspath(item)
+            if isinstance(str_or_bytes, str):
+                return str_or_bytes
+            else:
+                return os.fsdecode(str_or_bytes)
+
+        if isinstance(command, (str, bytes, PathLike)):
+            process = await trio.lowlevel.open_process(
+                convert_item(command),
+                stdin=stdin,
+                stdout=stdout,
+                stderr=stderr,
+                shell=True,
+                **kwargs,
+            )
+        else:
+            process = await trio.lowlevel.open_process(
+                [convert_item(item) for item in command],
+                stdin=stdin,
+                stdout=stdout,
+                stderr=stderr,
+                shell=False,
+                **kwargs,
+            )
+
+        stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None
+        stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None
+        stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None
+        return Process(process, stdin_stream, stdout_stream, stderr_stream)
+
+    @classmethod
+    def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None:
+        trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers)
+
+    @classmethod
+    async def connect_tcp(
+        cls, host: str, port: int, local_address: IPSockAddrType | None = None
+    ) -> SocketStream:
+        family = socket.AF_INET6 if ":" in host else socket.AF_INET
+        trio_socket = trio.socket.socket(family)
+        trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+        if local_address:
+            await trio_socket.bind(local_address)
+
+        try:
+            await trio_socket.connect((host, port))
+        except BaseException:
+            trio_socket.close()
+            raise
+
+        return SocketStream(trio_socket)
+
+    @classmethod
+    async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream:
+        trio_socket = trio.socket.socket(socket.AF_UNIX)
+        try:
+            await trio_socket.connect(path)
+        except BaseException:
+            trio_socket.close()
+            raise
+
+        return UNIXSocketStream(trio_socket)
+
+    @classmethod
+    def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener:
+        return TCPSocketListener(sock)
+
+    @classmethod
+    def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener:
+        return UNIXSocketListener(sock)
+
+    @classmethod
+    async def create_udp_socket(
+        cls,
+        family: socket.AddressFamily,
+        local_address: IPSockAddrType | None,
+        remote_address: IPSockAddrType | None,
+        reuse_port: bool,
+    ) -> UDPSocket | ConnectedUDPSocket:
+        trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM)
+
+        if reuse_port:
+            trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+
+        if local_address:
+            await trio_socket.bind(local_address)
+
+        if remote_address:
+            await trio_socket.connect(remote_address)
+            return ConnectedUDPSocket(trio_socket)
+        else:
+            return UDPSocket(trio_socket)
+
+    @classmethod
+    @overload
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket.socket, remote_path: None
+    ) -> abc.UNIXDatagramSocket: ...
+
+    @classmethod
+    @overload
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket.socket, remote_path: str | bytes
+    ) -> abc.ConnectedUNIXDatagramSocket: ...
+
+    @classmethod
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket.socket, remote_path: str | bytes | None
+    ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket:
+        trio_socket = trio.socket.from_stdlib_socket(raw_socket)
+
+        if remote_path:
+            await trio_socket.connect(remote_path)
+            return ConnectedUNIXDatagramSocket(trio_socket)
+        else:
+            return UNIXDatagramSocket(trio_socket)
+
+    @classmethod
+    async def getaddrinfo(
+        cls,
+        host: bytes | str | None,
+        port: str | int | None,
+        *,
+        family: int | AddressFamily = 0,
+        type: int | SocketKind = 0,
+        proto: int = 0,
+        flags: int = 0,
+    ) -> Sequence[
+        tuple[
+            AddressFamily,
+            SocketKind,
+            int,
+            str,
+            tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
+        ]
+    ]:
+        return await trio.socket.getaddrinfo(host, port, family, type, proto, flags)
+
+    @classmethod
+    async def getnameinfo(
+        cls, sockaddr: IPSockAddrType, flags: int = 0
+    ) -> tuple[str, str]:
+        return await trio.socket.getnameinfo(sockaddr, flags)
+
+    @classmethod
+    async def wait_readable(cls, obj: FileDescriptorLike) -> None:
+        try:
+            await wait_readable(obj)
+        except trio.ClosedResourceError as exc:
+            raise ClosedResourceError().with_traceback(exc.__traceback__) from None
+        except trio.BusyResourceError:
+            raise BusyResourceError("reading from") from None
+
+    @classmethod
+    async def wait_writable(cls, obj: FileDescriptorLike) -> None:
+        try:
+            await wait_writable(obj)
+        except trio.ClosedResourceError as exc:
+            raise ClosedResourceError().with_traceback(exc.__traceback__) from None
+        except trio.BusyResourceError:
+            raise BusyResourceError("writing to") from None
+
+    @classmethod
+    def notify_closing(cls, obj: FileDescriptorLike) -> None:
+        notify_closing(obj)
+
+    @classmethod
+    async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener:
+        return TCPSocketListener(sock)
+
+    @classmethod
+    async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream:
+        trio_sock = trio.socket.from_stdlib_socket(sock)
+        return SocketStream(trio_sock)
+
+    @classmethod
+    async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream:
+        trio_sock = trio.socket.from_stdlib_socket(sock)
+        return UNIXSocketStream(trio_sock)
+
+    @classmethod
+    async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket:
+        trio_sock = trio.socket.from_stdlib_socket(sock)
+        return UDPSocket(trio_sock)
+
+    @classmethod
+    async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket:
+        trio_sock = trio.socket.from_stdlib_socket(sock)
+        return ConnectedUDPSocket(trio_sock)
+
+    @classmethod
+    async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket:
+        trio_sock = trio.socket.from_stdlib_socket(sock)
+        return UNIXDatagramSocket(trio_sock)
+
+    @classmethod
+    async def wrap_connected_unix_datagram_socket(
+        cls, sock: socket.socket
+    ) -> ConnectedUNIXDatagramSocket:
+        trio_sock = trio.socket.from_stdlib_socket(sock)
+        return ConnectedUNIXDatagramSocket(trio_sock)
+
+    @classmethod
+    def current_default_thread_limiter(cls) -> CapacityLimiter:
+        try:
+            return _capacity_limiter_wrapper.get()
+        except LookupError:
+            limiter = CapacityLimiter(
+                original=trio.to_thread.current_default_thread_limiter()
+            )
+            _capacity_limiter_wrapper.set(limiter)
+            return limiter
+
+    @classmethod
+    def open_signal_receiver(
+        cls, *signals: Signals
+    ) -> AbstractContextManager[AsyncIterator[Signals]]:
+        return _SignalReceiver(signals)
+
+    @classmethod
+    def get_current_task(cls) -> TaskInfo:
+        task = current_task()
+        return TrioTaskInfo(task)
+
+    @classmethod
+    def get_running_tasks(cls) -> Sequence[TaskInfo]:
+        root_task = current_root_task()
+        assert root_task
+        task_infos = [TrioTaskInfo(root_task)]
+        nurseries = root_task.child_nurseries
+        while nurseries:
+            new_nurseries: list[trio.Nursery] = []
+            for nursery in nurseries:
+                for task in nursery.child_tasks:
+                    task_infos.append(TrioTaskInfo(task))
+                    new_nurseries.extend(task.child_nurseries)
+
+            nurseries = new_nurseries
+
+        return task_infos
+
+    @classmethod
+    async def wait_all_tasks_blocked(cls) -> None:
+        from trio.testing import wait_all_tasks_blocked
+
+        await wait_all_tasks_blocked()
+
+    @classmethod
+    def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
+        return TestRunner(**options)
+
+
+backend_class = TrioBackend

+ 0 - 0
.venv/lib/python3.9/site-packages/anyio/_core/__init__.py


+ 167 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_asyncio_selector_thread.py

@@ -0,0 +1,167 @@
+from __future__ import annotations
+
+import asyncio
+import socket
+import threading
+from collections.abc import Callable
+from selectors import EVENT_READ, EVENT_WRITE, DefaultSelector
+from typing import TYPE_CHECKING, Any
+
+if TYPE_CHECKING:
+    from _typeshed import FileDescriptorLike
+
+_selector_lock = threading.Lock()
+_selector: Selector | None = None
+
+
+class Selector:
+    def __init__(self) -> None:
+        self._thread = threading.Thread(target=self.run, name="AnyIO socket selector")
+        self._selector = DefaultSelector()
+        self._send, self._receive = socket.socketpair()
+        self._send.setblocking(False)
+        self._receive.setblocking(False)
+        # This somewhat reduces the amount of memory wasted queueing up data
+        # for wakeups. With these settings, maximum number of 1-byte sends
+        # before getting BlockingIOError:
+        #   Linux 4.8: 6
+        #   macOS (darwin 15.5): 1
+        #   Windows 10: 525347
+        # Windows you're weird. (And on Windows setting SNDBUF to 0 makes send
+        # blocking, even on non-blocking sockets, so don't do that.)
+        self._receive.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1)
+        self._send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1)
+        # On Windows this is a TCP socket so this might matter. On other
+        # platforms this fails b/c AF_UNIX sockets aren't actually TCP.
+        try:
+            self._send.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+        except OSError:
+            pass
+
+        self._selector.register(self._receive, EVENT_READ)
+        self._closed = False
+
+    def start(self) -> None:
+        self._thread.start()
+        threading._register_atexit(self._stop)  # type: ignore[attr-defined]
+
+    def _stop(self) -> None:
+        global _selector
+        self._closed = True
+        self._notify_self()
+        self._send.close()
+        self._thread.join()
+        self._selector.unregister(self._receive)
+        self._receive.close()
+        self._selector.close()
+        _selector = None
+        assert not self._selector.get_map(), (
+            "selector still has registered file descriptors after shutdown"
+        )
+
+    def _notify_self(self) -> None:
+        try:
+            self._send.send(b"\x00")
+        except BlockingIOError:
+            pass
+
+    def add_reader(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None:
+        loop = asyncio.get_running_loop()
+        try:
+            key = self._selector.get_key(fd)
+        except KeyError:
+            self._selector.register(fd, EVENT_READ, {EVENT_READ: (loop, callback)})
+        else:
+            if EVENT_READ in key.data:
+                raise ValueError(
+                    "this file descriptor is already registered for reading"
+                )
+
+            key.data[EVENT_READ] = loop, callback
+            self._selector.modify(fd, key.events | EVENT_READ, key.data)
+
+        self._notify_self()
+
+    def add_writer(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None:
+        loop = asyncio.get_running_loop()
+        try:
+            key = self._selector.get_key(fd)
+        except KeyError:
+            self._selector.register(fd, EVENT_WRITE, {EVENT_WRITE: (loop, callback)})
+        else:
+            if EVENT_WRITE in key.data:
+                raise ValueError(
+                    "this file descriptor is already registered for writing"
+                )
+
+            key.data[EVENT_WRITE] = loop, callback
+            self._selector.modify(fd, key.events | EVENT_WRITE, key.data)
+
+        self._notify_self()
+
+    def remove_reader(self, fd: FileDescriptorLike) -> bool:
+        try:
+            key = self._selector.get_key(fd)
+        except KeyError:
+            return False
+
+        if new_events := key.events ^ EVENT_READ:
+            del key.data[EVENT_READ]
+            self._selector.modify(fd, new_events, key.data)
+        else:
+            self._selector.unregister(fd)
+
+        return True
+
+    def remove_writer(self, fd: FileDescriptorLike) -> bool:
+        try:
+            key = self._selector.get_key(fd)
+        except KeyError:
+            return False
+
+        if new_events := key.events ^ EVENT_WRITE:
+            del key.data[EVENT_WRITE]
+            self._selector.modify(fd, new_events, key.data)
+        else:
+            self._selector.unregister(fd)
+
+        return True
+
+    def run(self) -> None:
+        while not self._closed:
+            for key, events in self._selector.select():
+                if key.fileobj is self._receive:
+                    try:
+                        while self._receive.recv(4096):
+                            pass
+                    except BlockingIOError:
+                        pass
+
+                    continue
+
+                if events & EVENT_READ:
+                    loop, callback = key.data[EVENT_READ]
+                    self.remove_reader(key.fd)
+                    try:
+                        loop.call_soon_threadsafe(callback)
+                    except RuntimeError:
+                        pass  # the loop was already closed
+
+                if events & EVENT_WRITE:
+                    loop, callback = key.data[EVENT_WRITE]
+                    self.remove_writer(key.fd)
+                    try:
+                        loop.call_soon_threadsafe(callback)
+                    except RuntimeError:
+                        pass  # the loop was already closed
+
+
+def get_selector() -> Selector:
+    global _selector
+
+    with _selector_lock:
+        if _selector is None:
+            _selector = Selector()
+            _selector.start()
+
+        return _selector

+ 200 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_contextmanagers.py

@@ -0,0 +1,200 @@
+from __future__ import annotations
+
+from abc import abstractmethod
+from contextlib import AbstractAsyncContextManager, AbstractContextManager
+from inspect import isasyncgen, iscoroutine, isgenerator
+from types import TracebackType
+from typing import Protocol, TypeVar, cast, final
+
+_T_co = TypeVar("_T_co", covariant=True)
+_ExitT_co = TypeVar("_ExitT_co", covariant=True, bound="bool | None")
+
+
+class _SupportsCtxMgr(Protocol[_T_co, _ExitT_co]):
+    def __contextmanager__(self) -> AbstractContextManager[_T_co, _ExitT_co]: ...
+
+
+class _SupportsAsyncCtxMgr(Protocol[_T_co, _ExitT_co]):
+    def __asynccontextmanager__(
+        self,
+    ) -> AbstractAsyncContextManager[_T_co, _ExitT_co]: ...
+
+
+class ContextManagerMixin:
+    """
+    Mixin class providing context manager functionality via a generator-based
+    implementation.
+
+    This class allows you to implement a context manager via :meth:`__contextmanager__`
+    which should return a generator. The mechanics are meant to mirror those of
+    :func:`@contextmanager <contextlib.contextmanager>`.
+
+    .. note:: Classes using this mix-in are not reentrant as context managers, meaning
+        that once you enter it, you can't re-enter before first exiting it.
+
+    .. seealso:: :doc:`contextmanagers`
+    """
+
+    __cm: AbstractContextManager[object, bool | None] | None = None
+
+    @final
+    def __enter__(self: _SupportsCtxMgr[_T_co, bool | None]) -> _T_co:
+        # Needed for mypy to assume self still has the __cm member
+        assert isinstance(self, ContextManagerMixin)
+        if self.__cm is not None:
+            raise RuntimeError(
+                f"this {self.__class__.__qualname__} has already been entered"
+            )
+
+        cm = self.__contextmanager__()
+        if not isinstance(cm, AbstractContextManager):
+            if isgenerator(cm):
+                raise TypeError(
+                    "__contextmanager__() returned a generator object instead of "
+                    "a context manager. Did you forget to add the @contextmanager "
+                    "decorator?"
+                )
+
+            raise TypeError(
+                f"__contextmanager__() did not return a context manager object, "
+                f"but {cm.__class__!r}"
+            )
+
+        if cm is self:
+            raise TypeError(
+                f"{self.__class__.__qualname__}.__contextmanager__() returned "
+                f"self. Did you forget to add the @contextmanager decorator and a "
+                f"'yield' statement?"
+            )
+
+        value = cm.__enter__()
+        self.__cm = cm
+        return value
+
+    @final
+    def __exit__(
+        self: _SupportsCtxMgr[object, _ExitT_co],
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> _ExitT_co:
+        # Needed for mypy to assume self still has the __cm member
+        assert isinstance(self, ContextManagerMixin)
+        if self.__cm is None:
+            raise RuntimeError(
+                f"this {self.__class__.__qualname__} has not been entered yet"
+            )
+
+        # Prevent circular references
+        cm = self.__cm
+        del self.__cm
+
+        return cast(_ExitT_co, cm.__exit__(exc_type, exc_val, exc_tb))
+
+    @abstractmethod
+    def __contextmanager__(self) -> AbstractContextManager[object, bool | None]:
+        """
+        Implement your context manager logic here.
+
+        This method **must** be decorated with
+        :func:`@contextmanager <contextlib.contextmanager>`.
+
+        .. note:: Remember that the ``yield`` will raise any exception raised in the
+            enclosed context block, so use a ``finally:`` block to clean up resources!
+
+        :return: a context manager object
+        """
+
+
+class AsyncContextManagerMixin:
+    """
+    Mixin class providing async context manager functionality via a generator-based
+    implementation.
+
+    This class allows you to implement a context manager via
+    :meth:`__asynccontextmanager__`. The mechanics are meant to mirror those of
+    :func:`@asynccontextmanager <contextlib.asynccontextmanager>`.
+
+    .. note:: Classes using this mix-in are not reentrant as context managers, meaning
+        that once you enter it, you can't re-enter before first exiting it.
+
+    .. seealso:: :doc:`contextmanagers`
+    """
+
+    __cm: AbstractAsyncContextManager[object, bool | None] | None = None
+
+    @final
+    async def __aenter__(self: _SupportsAsyncCtxMgr[_T_co, bool | None]) -> _T_co:
+        # Needed for mypy to assume self still has the __cm member
+        assert isinstance(self, AsyncContextManagerMixin)
+        if self.__cm is not None:
+            raise RuntimeError(
+                f"this {self.__class__.__qualname__} has already been entered"
+            )
+
+        cm = self.__asynccontextmanager__()
+        if not isinstance(cm, AbstractAsyncContextManager):
+            if isasyncgen(cm):
+                raise TypeError(
+                    "__asynccontextmanager__() returned an async generator instead of "
+                    "an async context manager. Did you forget to add the "
+                    "@asynccontextmanager decorator?"
+                )
+            elif iscoroutine(cm):
+                cm.close()
+                raise TypeError(
+                    "__asynccontextmanager__() returned a coroutine object instead of "
+                    "an async context manager. Did you forget to add the "
+                    "@asynccontextmanager decorator and a 'yield' statement?"
+                )
+
+            raise TypeError(
+                f"__asynccontextmanager__() did not return an async context manager, "
+                f"but {cm.__class__!r}"
+            )
+
+        if cm is self:
+            raise TypeError(
+                f"{self.__class__.__qualname__}.__asynccontextmanager__() returned "
+                f"self. Did you forget to add the @asynccontextmanager decorator and a "
+                f"'yield' statement?"
+            )
+
+        value = await cm.__aenter__()
+        self.__cm = cm
+        return value
+
+    @final
+    async def __aexit__(
+        self: _SupportsAsyncCtxMgr[object, _ExitT_co],
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> _ExitT_co:
+        assert isinstance(self, AsyncContextManagerMixin)
+        if self.__cm is None:
+            raise RuntimeError(
+                f"this {self.__class__.__qualname__} has not been entered yet"
+            )
+
+        # Prevent circular references
+        cm = self.__cm
+        del self.__cm
+
+        return cast(_ExitT_co, await cm.__aexit__(exc_type, exc_val, exc_tb))
+
+    @abstractmethod
+    def __asynccontextmanager__(
+        self,
+    ) -> AbstractAsyncContextManager[object, bool | None]:
+        """
+        Implement your async context manager logic here.
+
+        This method **must** be decorated with
+        :func:`@asynccontextmanager <contextlib.asynccontextmanager>`.
+
+        .. note:: Remember that the ``yield`` will raise any exception raised in the
+            enclosed context block, so use a ``finally:`` block to clean up resources!
+
+        :return: an async context manager object
+        """

+ 234 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_eventloop.py

@@ -0,0 +1,234 @@
+from __future__ import annotations
+
+import math
+import sys
+import threading
+from collections.abc import Awaitable, Callable, Generator
+from contextlib import contextmanager
+from contextvars import Token
+from importlib import import_module
+from typing import TYPE_CHECKING, Any, TypeVar
+
+from ._exceptions import NoEventLoopError
+
+if sys.version_info >= (3, 11):
+    from typing import TypeVarTuple, Unpack
+else:
+    from typing_extensions import TypeVarTuple, Unpack
+
+sniffio: Any
+try:
+    import sniffio
+except ModuleNotFoundError:
+    sniffio = None
+
+if TYPE_CHECKING:
+    from ..abc import AsyncBackend
+
+# This must be updated when new backends are introduced
+BACKENDS = "asyncio", "trio"
+
+T_Retval = TypeVar("T_Retval")
+PosArgsT = TypeVarTuple("PosArgsT")
+
+threadlocals = threading.local()
+loaded_backends: dict[str, type[AsyncBackend]] = {}
+
+
+def run(
+    func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+    *args: Unpack[PosArgsT],
+    backend: str = "asyncio",
+    backend_options: dict[str, Any] | None = None,
+) -> T_Retval:
+    """
+    Run the given coroutine function in an asynchronous event loop.
+
+    The current thread must not be already running an event loop.
+
+    :param func: a coroutine function
+    :param args: positional arguments to ``func``
+    :param backend: name of the asynchronous event loop implementation – currently
+        either ``asyncio`` or ``trio``
+    :param backend_options: keyword arguments to call the backend ``run()``
+        implementation with (documented :ref:`here <backend options>`)
+    :return: the return value of the coroutine function
+    :raises RuntimeError: if an asynchronous event loop is already running in this
+        thread
+    :raises LookupError: if the named backend is not found
+
+    """
+    if asynclib_name := current_async_library():
+        raise RuntimeError(f"Already running {asynclib_name} in this thread")
+
+    try:
+        async_backend = get_async_backend(backend)
+    except ImportError as exc:
+        raise LookupError(f"No such backend: {backend}") from exc
+
+    token = None
+    if asynclib_name is None:
+        # Since we're in control of the event loop, we can cache the name of the async
+        # library
+        token = set_current_async_library(backend)
+
+    try:
+        backend_options = backend_options or {}
+        return async_backend.run(func, args, {}, backend_options)
+    finally:
+        reset_current_async_library(token)
+
+
+async def sleep(delay: float) -> None:
+    """
+    Pause the current task for the specified duration.
+
+    :param delay: the duration, in seconds
+
+    """
+    return await get_async_backend().sleep(delay)
+
+
+async def sleep_forever() -> None:
+    """
+    Pause the current task until it's cancelled.
+
+    This is a shortcut for ``sleep(math.inf)``.
+
+    .. versionadded:: 3.1
+
+    """
+    await sleep(math.inf)
+
+
+async def sleep_until(deadline: float) -> None:
+    """
+    Pause the current task until the given time.
+
+    :param deadline: the absolute time to wake up at (according to the internal
+        monotonic clock of the event loop)
+
+    .. versionadded:: 3.1
+
+    """
+    now = current_time()
+    await sleep(max(deadline - now, 0))
+
+
+def current_time() -> float:
+    """
+    Return the current value of the event loop's internal clock.
+
+    :return: the clock value (seconds)
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return get_async_backend().current_time()
+
+
+def get_all_backends() -> tuple[str, ...]:
+    """Return a tuple of the names of all built-in backends."""
+    return BACKENDS
+
+
+def get_available_backends() -> tuple[str, ...]:
+    """
+    Test for the availability of built-in backends.
+
+    :return a tuple of the built-in backend names that were successfully imported
+
+    .. versionadded:: 4.12
+
+    """
+    available_backends: list[str] = []
+    for backend_name in get_all_backends():
+        try:
+            get_async_backend(backend_name)
+        except ImportError:
+            continue
+
+        available_backends.append(backend_name)
+
+    return tuple(available_backends)
+
+
+def get_cancelled_exc_class() -> type[BaseException]:
+    """
+    Return the current async library's cancellation exception class.
+
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return get_async_backend().cancelled_exception_class()
+
+
+#
+# Private API
+#
+
+
+@contextmanager
+def claim_worker_thread(
+    backend_class: type[AsyncBackend], token: object
+) -> Generator[Any, None, None]:
+    from ..lowlevel import EventLoopToken
+
+    threadlocals.current_token = EventLoopToken(backend_class, token)
+    try:
+        yield
+    finally:
+        del threadlocals.current_token
+
+
+def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]:
+    if asynclib_name is None:
+        asynclib_name = current_async_library()
+        if not asynclib_name:
+            raise NoEventLoopError(
+                f"Not currently running on any asynchronous event loop. "
+                f"Available async backends: {', '.join(get_all_backends())}"
+            )
+
+    # We use our own dict instead of sys.modules to get the already imported back-end
+    # class because the appropriate modules in sys.modules could potentially be only
+    # partially initialized
+    try:
+        return loaded_backends[asynclib_name]
+    except KeyError:
+        module = import_module(f"anyio._backends._{asynclib_name}")
+        loaded_backends[asynclib_name] = module.backend_class
+        return module.backend_class
+
+
+def current_async_library() -> str | None:
+    if sniffio is None:
+        # If sniffio is not installed, we assume we're either running asyncio or nothing
+        import asyncio
+
+        try:
+            asyncio.get_running_loop()
+            return "asyncio"
+        except RuntimeError:
+            pass
+    else:
+        try:
+            return sniffio.current_async_library()
+        except sniffio.AsyncLibraryNotFoundError:
+            pass
+
+    return None
+
+
+def set_current_async_library(asynclib_name: str | None) -> Token | None:
+    # no-op if sniffio is not installed
+    if sniffio is None:
+        return None
+
+    return sniffio.current_async_library_cvar.set(asynclib_name)
+
+
+def reset_current_async_library(token: Token | None) -> None:
+    if token is not None:
+        sniffio.current_async_library_cvar.reset(token)

+ 156 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_exceptions.py

@@ -0,0 +1,156 @@
+from __future__ import annotations
+
+import sys
+from collections.abc import Generator
+from textwrap import dedent
+from typing import Any
+
+if sys.version_info < (3, 11):
+    from exceptiongroup import BaseExceptionGroup
+
+
+class BrokenResourceError(Exception):
+    """
+    Raised when trying to use a resource that has been rendered unusable due to external
+    causes (e.g. a send stream whose peer has disconnected).
+    """
+
+
+class BrokenWorkerProcess(Exception):
+    """
+    Raised by :meth:`~anyio.to_process.run_sync` if the worker process terminates abruptly or
+    otherwise misbehaves.
+    """
+
+
+class BrokenWorkerInterpreter(Exception):
+    """
+    Raised by :meth:`~anyio.to_interpreter.run_sync` if an unexpected exception is
+    raised in the subinterpreter.
+    """
+
+    def __init__(self, excinfo: Any):
+        # This was adapted from concurrent.futures.interpreter.ExecutionFailed
+        msg = excinfo.formatted
+        if not msg:
+            if excinfo.type and excinfo.msg:
+                msg = f"{excinfo.type.__name__}: {excinfo.msg}"
+            else:
+                msg = excinfo.type.__name__ or excinfo.msg
+
+        super().__init__(msg)
+        self.excinfo = excinfo
+
+    def __str__(self) -> str:
+        try:
+            formatted = self.excinfo.errdisplay
+        except Exception:
+            return super().__str__()
+        else:
+            return dedent(
+                f"""
+                {super().__str__()}
+
+                Uncaught in the interpreter:
+
+                {formatted}
+                """.strip()
+            )
+
+
+class BusyResourceError(Exception):
+    """
+    Raised when two tasks are trying to read from or write to the same resource
+    concurrently.
+    """
+
+    def __init__(self, action: str):
+        super().__init__(f"Another task is already {action} this resource")
+
+
+class ClosedResourceError(Exception):
+    """Raised when trying to use a resource that has been closed."""
+
+
+class ConnectionFailed(OSError):
+    """
+    Raised when a connection attempt fails.
+
+    .. note:: This class inherits from :exc:`OSError` for backwards compatibility.
+    """
+
+
+def iterate_exceptions(
+    exception: BaseException,
+) -> Generator[BaseException, None, None]:
+    if isinstance(exception, BaseExceptionGroup):
+        for exc in exception.exceptions:
+            yield from iterate_exceptions(exc)
+    else:
+        yield exception
+
+
+class DelimiterNotFound(Exception):
+    """
+    Raised during
+    :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the
+    maximum number of bytes has been read without the delimiter being found.
+    """
+
+    def __init__(self, max_bytes: int) -> None:
+        super().__init__(
+            f"The delimiter was not found among the first {max_bytes} bytes"
+        )
+
+
+class EndOfStream(Exception):
+    """
+    Raised when trying to read from a stream that has been closed from the other end.
+    """
+
+
+class IncompleteRead(Exception):
+    """
+    Raised during
+    :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or
+    :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the
+    connection is closed before the requested amount of bytes has been read.
+    """
+
+    def __init__(self) -> None:
+        super().__init__(
+            "The stream was closed before the read operation could be completed"
+        )
+
+
+class TypedAttributeLookupError(LookupError):
+    """
+    Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute
+    is not found and no default value has been given.
+    """
+
+
+class WouldBlock(Exception):
+    """Raised by ``X_nowait`` functions if ``X()`` would block."""
+
+
+class NoEventLoopError(RuntimeError):
+    """
+    Raised by several functions that require an event loop to be running in the current
+    thread when there is no running event loop.
+
+    This is also raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync`
+    if not calling from an AnyIO worker thread, and no ``token`` was passed.
+    """
+
+
+class RunFinishedError(RuntimeError):
+    """
+    Raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` if the event
+    loop associated with the explicitly passed token has already finished.
+    """
+
+    def __init__(self) -> None:
+        super().__init__(
+            "The event loop associated with the given token has already finished"
+        )

+ 797 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_fileio.py

@@ -0,0 +1,797 @@
+from __future__ import annotations
+
+import os
+import pathlib
+import sys
+from collections.abc import (
+    AsyncIterator,
+    Callable,
+    Iterable,
+    Iterator,
+    Sequence,
+)
+from dataclasses import dataclass
+from functools import partial
+from os import PathLike
+from typing import (
+    IO,
+    TYPE_CHECKING,
+    Any,
+    AnyStr,
+    ClassVar,
+    Final,
+    Generic,
+    overload,
+)
+
+from .. import to_thread
+from ..abc import AsyncResource
+
+if TYPE_CHECKING:
+    from types import ModuleType
+
+    from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
+else:
+    ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object
+
+
+class AsyncFile(AsyncResource, Generic[AnyStr]):
+    """
+    An asynchronous file object.
+
+    This class wraps a standard file object and provides async friendly versions of the
+    following blocking methods (where available on the original file object):
+
+    * read
+    * read1
+    * readline
+    * readlines
+    * readinto
+    * readinto1
+    * write
+    * writelines
+    * truncate
+    * seek
+    * tell
+    * flush
+
+    All other methods are directly passed through.
+
+    This class supports the asynchronous context manager protocol which closes the
+    underlying file at the end of the context block.
+
+    This class also supports asynchronous iteration::
+
+        async with await open_file(...) as f:
+            async for line in f:
+                print(line)
+    """
+
+    def __init__(self, fp: IO[AnyStr]) -> None:
+        self._fp: Any = fp
+
+    def __getattr__(self, name: str) -> object:
+        return getattr(self._fp, name)
+
+    @property
+    def wrapped(self) -> IO[AnyStr]:
+        """The wrapped file object."""
+        return self._fp
+
+    async def __aiter__(self) -> AsyncIterator[AnyStr]:
+        while True:
+            line = await self.readline()
+            if line:
+                yield line
+            else:
+                break
+
+    async def aclose(self) -> None:
+        return await to_thread.run_sync(self._fp.close)
+
+    async def read(self, size: int = -1) -> AnyStr:
+        return await to_thread.run_sync(self._fp.read, size)
+
+    async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes:
+        return await to_thread.run_sync(self._fp.read1, size)
+
+    async def readline(self) -> AnyStr:
+        return await to_thread.run_sync(self._fp.readline)
+
+    async def readlines(self) -> list[AnyStr]:
+        return await to_thread.run_sync(self._fp.readlines)
+
+    async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
+        return await to_thread.run_sync(self._fp.readinto, b)
+
+    async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int:
+        return await to_thread.run_sync(self._fp.readinto1, b)
+
+    @overload
+    async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ...
+
+    @overload
+    async def write(self: AsyncFile[str], b: str) -> int: ...
+
+    async def write(self, b: ReadableBuffer | str) -> int:
+        return await to_thread.run_sync(self._fp.write, b)
+
+    @overload
+    async def writelines(
+        self: AsyncFile[bytes], lines: Iterable[ReadableBuffer]
+    ) -> None: ...
+
+    @overload
+    async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ...
+
+    async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None:
+        return await to_thread.run_sync(self._fp.writelines, lines)
+
+    async def truncate(self, size: int | None = None) -> int:
+        return await to_thread.run_sync(self._fp.truncate, size)
+
+    async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
+        return await to_thread.run_sync(self._fp.seek, offset, whence)
+
+    async def tell(self) -> int:
+        return await to_thread.run_sync(self._fp.tell)
+
+    async def flush(self) -> None:
+        return await to_thread.run_sync(self._fp.flush)
+
+
+@overload
+async def open_file(
+    file: str | PathLike[str] | int,
+    mode: OpenBinaryMode,
+    buffering: int = ...,
+    encoding: str | None = ...,
+    errors: str | None = ...,
+    newline: str | None = ...,
+    closefd: bool = ...,
+    opener: Callable[[str, int], int] | None = ...,
+) -> AsyncFile[bytes]: ...
+
+
+@overload
+async def open_file(
+    file: str | PathLike[str] | int,
+    mode: OpenTextMode = ...,
+    buffering: int = ...,
+    encoding: str | None = ...,
+    errors: str | None = ...,
+    newline: str | None = ...,
+    closefd: bool = ...,
+    opener: Callable[[str, int], int] | None = ...,
+) -> AsyncFile[str]: ...
+
+
+async def open_file(
+    file: str | PathLike[str] | int,
+    mode: str = "r",
+    buffering: int = -1,
+    encoding: str | None = None,
+    errors: str | None = None,
+    newline: str | None = None,
+    closefd: bool = True,
+    opener: Callable[[str, int], int] | None = None,
+) -> AsyncFile[Any]:
+    """
+    Open a file asynchronously.
+
+    The arguments are exactly the same as for the builtin :func:`open`.
+
+    :return: an asynchronous file object
+
+    """
+    fp = await to_thread.run_sync(
+        open, file, mode, buffering, encoding, errors, newline, closefd, opener
+    )
+    return AsyncFile(fp)
+
+
+def wrap_file(file: IO[AnyStr]) -> AsyncFile[AnyStr]:
+    """
+    Wrap an existing file as an asynchronous file.
+
+    :param file: an existing file-like object
+    :return: an asynchronous file object
+
+    """
+    return AsyncFile(file)
+
+
+@dataclass(eq=False)
+class _PathIterator(AsyncIterator["Path"]):
+    iterator: Iterator[PathLike[str]]
+
+    async def __anext__(self) -> Path:
+        nextval = await to_thread.run_sync(
+            next, self.iterator, None, abandon_on_cancel=True
+        )
+        if nextval is None:
+            raise StopAsyncIteration from None
+
+        return Path(nextval)
+
+
+class Path:
+    """
+    An asynchronous version of :class:`pathlib.Path`.
+
+    This class cannot be substituted for :class:`pathlib.Path` or
+    :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike`
+    interface.
+
+    It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for
+    the deprecated :meth:`~pathlib.Path.link_to` method.
+
+    Some methods may be unavailable or have limited functionality, based on the Python
+    version:
+
+    * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later)
+    * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later)
+    * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later)
+    * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later)
+    * :attr:`~pathlib.Path.info` (available on Python 3.14 or later)
+    * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later)
+    * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only
+      available on Python 3.13 or later)
+    * :meth:`~pathlib.Path.move` (available on Python 3.14 or later)
+    * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later)
+    * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available
+      on Python 3.12 or later)
+    * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later)
+
+    Any methods that do disk I/O need to be awaited on. These methods are:
+
+    * :meth:`~pathlib.Path.absolute`
+    * :meth:`~pathlib.Path.chmod`
+    * :meth:`~pathlib.Path.cwd`
+    * :meth:`~pathlib.Path.exists`
+    * :meth:`~pathlib.Path.expanduser`
+    * :meth:`~pathlib.Path.group`
+    * :meth:`~pathlib.Path.hardlink_to`
+    * :meth:`~pathlib.Path.home`
+    * :meth:`~pathlib.Path.is_block_device`
+    * :meth:`~pathlib.Path.is_char_device`
+    * :meth:`~pathlib.Path.is_dir`
+    * :meth:`~pathlib.Path.is_fifo`
+    * :meth:`~pathlib.Path.is_file`
+    * :meth:`~pathlib.Path.is_junction`
+    * :meth:`~pathlib.Path.is_mount`
+    * :meth:`~pathlib.Path.is_socket`
+    * :meth:`~pathlib.Path.is_symlink`
+    * :meth:`~pathlib.Path.lchmod`
+    * :meth:`~pathlib.Path.lstat`
+    * :meth:`~pathlib.Path.mkdir`
+    * :meth:`~pathlib.Path.open`
+    * :meth:`~pathlib.Path.owner`
+    * :meth:`~pathlib.Path.read_bytes`
+    * :meth:`~pathlib.Path.read_text`
+    * :meth:`~pathlib.Path.readlink`
+    * :meth:`~pathlib.Path.rename`
+    * :meth:`~pathlib.Path.replace`
+    * :meth:`~pathlib.Path.resolve`
+    * :meth:`~pathlib.Path.rmdir`
+    * :meth:`~pathlib.Path.samefile`
+    * :meth:`~pathlib.Path.stat`
+    * :meth:`~pathlib.Path.symlink_to`
+    * :meth:`~pathlib.Path.touch`
+    * :meth:`~pathlib.Path.unlink`
+    * :meth:`~pathlib.Path.walk`
+    * :meth:`~pathlib.Path.write_bytes`
+    * :meth:`~pathlib.Path.write_text`
+
+    Additionally, the following methods return an async iterator yielding
+    :class:`~.Path` objects:
+
+    * :meth:`~pathlib.Path.glob`
+    * :meth:`~pathlib.Path.iterdir`
+    * :meth:`~pathlib.Path.rglob`
+    """
+
+    __slots__ = "_path", "__weakref__"
+
+    __weakref__: Any
+
+    def __init__(self, *args: str | PathLike[str]) -> None:
+        self._path: Final[pathlib.Path] = pathlib.Path(*args)
+
+    def __fspath__(self) -> str:
+        return self._path.__fspath__()
+
+    def __str__(self) -> str:
+        return self._path.__str__()
+
+    def __repr__(self) -> str:
+        return f"{self.__class__.__name__}({self.as_posix()!r})"
+
+    def __bytes__(self) -> bytes:
+        return self._path.__bytes__()
+
+    def __hash__(self) -> int:
+        return self._path.__hash__()
+
+    def __eq__(self, other: object) -> bool:
+        target = other._path if isinstance(other, Path) else other
+        return self._path.__eq__(target)
+
+    def __lt__(self, other: pathlib.PurePath | Path) -> bool:
+        target = other._path if isinstance(other, Path) else other
+        return self._path.__lt__(target)
+
+    def __le__(self, other: pathlib.PurePath | Path) -> bool:
+        target = other._path if isinstance(other, Path) else other
+        return self._path.__le__(target)
+
+    def __gt__(self, other: pathlib.PurePath | Path) -> bool:
+        target = other._path if isinstance(other, Path) else other
+        return self._path.__gt__(target)
+
+    def __ge__(self, other: pathlib.PurePath | Path) -> bool:
+        target = other._path if isinstance(other, Path) else other
+        return self._path.__ge__(target)
+
+    def __truediv__(self, other: str | PathLike[str]) -> Path:
+        return Path(self._path / other)
+
+    def __rtruediv__(self, other: str | PathLike[str]) -> Path:
+        return Path(other) / self
+
+    @property
+    def parts(self) -> tuple[str, ...]:
+        return self._path.parts
+
+    @property
+    def drive(self) -> str:
+        return self._path.drive
+
+    @property
+    def root(self) -> str:
+        return self._path.root
+
+    @property
+    def anchor(self) -> str:
+        return self._path.anchor
+
+    @property
+    def parents(self) -> Sequence[Path]:
+        return tuple(Path(p) for p in self._path.parents)
+
+    @property
+    def parent(self) -> Path:
+        return Path(self._path.parent)
+
+    @property
+    def name(self) -> str:
+        return self._path.name
+
+    @property
+    def suffix(self) -> str:
+        return self._path.suffix
+
+    @property
+    def suffixes(self) -> list[str]:
+        return self._path.suffixes
+
+    @property
+    def stem(self) -> str:
+        return self._path.stem
+
+    async def absolute(self) -> Path:
+        path = await to_thread.run_sync(self._path.absolute)
+        return Path(path)
+
+    def as_posix(self) -> str:
+        return self._path.as_posix()
+
+    def as_uri(self) -> str:
+        return self._path.as_uri()
+
+    if sys.version_info >= (3, 13):
+        parser: ClassVar[ModuleType] = pathlib.Path.parser
+
+        @classmethod
+        def from_uri(cls, uri: str) -> Path:
+            return Path(pathlib.Path.from_uri(uri))
+
+        def full_match(
+            self, path_pattern: str, *, case_sensitive: bool | None = None
+        ) -> bool:
+            return self._path.full_match(path_pattern, case_sensitive=case_sensitive)
+
+        def match(
+            self, path_pattern: str, *, case_sensitive: bool | None = None
+        ) -> bool:
+            return self._path.match(path_pattern, case_sensitive=case_sensitive)
+    else:
+
+        def match(self, path_pattern: str) -> bool:
+            return self._path.match(path_pattern)
+
+    if sys.version_info >= (3, 14):
+
+        @property
+        def info(self) -> Any:  # TODO: add return type annotation when Typeshed gets it
+            return self._path.info
+
+        async def copy(
+            self,
+            target: str | os.PathLike[str],
+            *,
+            follow_symlinks: bool = True,
+            preserve_metadata: bool = False,
+        ) -> Path:
+            func = partial(
+                self._path.copy,
+                follow_symlinks=follow_symlinks,
+                preserve_metadata=preserve_metadata,
+            )
+            return Path(await to_thread.run_sync(func, pathlib.Path(target)))
+
+        async def copy_into(
+            self,
+            target_dir: str | os.PathLike[str],
+            *,
+            follow_symlinks: bool = True,
+            preserve_metadata: bool = False,
+        ) -> Path:
+            func = partial(
+                self._path.copy_into,
+                follow_symlinks=follow_symlinks,
+                preserve_metadata=preserve_metadata,
+            )
+            return Path(await to_thread.run_sync(func, pathlib.Path(target_dir)))
+
+        async def move(self, target: str | os.PathLike[str]) -> Path:
+            # Upstream does not handle anyio.Path properly as a PathLike
+            target = pathlib.Path(target)
+            return Path(await to_thread.run_sync(self._path.move, target))
+
+        async def move_into(
+            self,
+            target_dir: str | os.PathLike[str],
+        ) -> Path:
+            return Path(await to_thread.run_sync(self._path.move_into, target_dir))
+
+    def is_relative_to(self, other: str | PathLike[str]) -> bool:
+        try:
+            self.relative_to(other)
+            return True
+        except ValueError:
+            return False
+
+    async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None:
+        func = partial(os.chmod, follow_symlinks=follow_symlinks)
+        return await to_thread.run_sync(func, self._path, mode)
+
+    @classmethod
+    async def cwd(cls) -> Path:
+        path = await to_thread.run_sync(pathlib.Path.cwd)
+        return cls(path)
+
+    async def exists(self) -> bool:
+        return await to_thread.run_sync(self._path.exists, abandon_on_cancel=True)
+
+    async def expanduser(self) -> Path:
+        return Path(
+            await to_thread.run_sync(self._path.expanduser, abandon_on_cancel=True)
+        )
+
+    if sys.version_info < (3, 12):
+        # Python 3.11 and earlier
+        def glob(self, pattern: str) -> AsyncIterator[Path]:
+            gen = self._path.glob(pattern)
+            return _PathIterator(gen)
+    elif (3, 12) <= sys.version_info < (3, 13):
+        # changed in Python 3.12:
+        # - The case_sensitive parameter was added.
+        def glob(
+            self,
+            pattern: str,
+            *,
+            case_sensitive: bool | None = None,
+        ) -> AsyncIterator[Path]:
+            gen = self._path.glob(pattern, case_sensitive=case_sensitive)
+            return _PathIterator(gen)
+    elif sys.version_info >= (3, 13):
+        # Changed in Python 3.13:
+        # - The recurse_symlinks parameter was added.
+        # - The pattern parameter accepts a path-like object.
+        def glob(  # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
+            self,
+            pattern: str | PathLike[str],
+            *,
+            case_sensitive: bool | None = None,
+            recurse_symlinks: bool = False,
+        ) -> AsyncIterator[Path]:
+            gen = self._path.glob(
+                pattern,  # type: ignore[arg-type]
+                case_sensitive=case_sensitive,
+                recurse_symlinks=recurse_symlinks,
+            )
+            return _PathIterator(gen)
+
+    async def group(self) -> str:
+        return await to_thread.run_sync(self._path.group, abandon_on_cancel=True)
+
+    async def hardlink_to(
+        self, target: str | bytes | PathLike[str] | PathLike[bytes]
+    ) -> None:
+        if isinstance(target, Path):
+            target = target._path
+
+        await to_thread.run_sync(os.link, target, self)
+
+    @classmethod
+    async def home(cls) -> Path:
+        home_path = await to_thread.run_sync(pathlib.Path.home)
+        return cls(home_path)
+
+    def is_absolute(self) -> bool:
+        return self._path.is_absolute()
+
+    async def is_block_device(self) -> bool:
+        return await to_thread.run_sync(
+            self._path.is_block_device, abandon_on_cancel=True
+        )
+
+    async def is_char_device(self) -> bool:
+        return await to_thread.run_sync(
+            self._path.is_char_device, abandon_on_cancel=True
+        )
+
+    async def is_dir(self) -> bool:
+        return await to_thread.run_sync(self._path.is_dir, abandon_on_cancel=True)
+
+    async def is_fifo(self) -> bool:
+        return await to_thread.run_sync(self._path.is_fifo, abandon_on_cancel=True)
+
+    async def is_file(self) -> bool:
+        return await to_thread.run_sync(self._path.is_file, abandon_on_cancel=True)
+
+    if sys.version_info >= (3, 12):
+
+        async def is_junction(self) -> bool:
+            return await to_thread.run_sync(self._path.is_junction)
+
+    async def is_mount(self) -> bool:
+        return await to_thread.run_sync(
+            os.path.ismount, self._path, abandon_on_cancel=True
+        )
+
+    def is_reserved(self) -> bool:
+        return self._path.is_reserved()
+
+    async def is_socket(self) -> bool:
+        return await to_thread.run_sync(self._path.is_socket, abandon_on_cancel=True)
+
+    async def is_symlink(self) -> bool:
+        return await to_thread.run_sync(self._path.is_symlink, abandon_on_cancel=True)
+
+    async def iterdir(self) -> AsyncIterator[Path]:
+        gen = (
+            self._path.iterdir()
+            if sys.version_info < (3, 13)
+            else await to_thread.run_sync(self._path.iterdir, abandon_on_cancel=True)
+        )
+        async for path in _PathIterator(gen):
+            yield path
+
+    def joinpath(self, *args: str | PathLike[str]) -> Path:
+        return Path(self._path.joinpath(*args))
+
+    async def lchmod(self, mode: int) -> None:
+        await to_thread.run_sync(self._path.lchmod, mode)
+
+    async def lstat(self) -> os.stat_result:
+        return await to_thread.run_sync(self._path.lstat, abandon_on_cancel=True)
+
+    async def mkdir(
+        self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False
+    ) -> None:
+        await to_thread.run_sync(self._path.mkdir, mode, parents, exist_ok)
+
+    @overload
+    async def open(
+        self,
+        mode: OpenBinaryMode,
+        buffering: int = ...,
+        encoding: str | None = ...,
+        errors: str | None = ...,
+        newline: str | None = ...,
+    ) -> AsyncFile[bytes]: ...
+
+    @overload
+    async def open(
+        self,
+        mode: OpenTextMode = ...,
+        buffering: int = ...,
+        encoding: str | None = ...,
+        errors: str | None = ...,
+        newline: str | None = ...,
+    ) -> AsyncFile[str]: ...
+
+    async def open(
+        self,
+        mode: str = "r",
+        buffering: int = -1,
+        encoding: str | None = None,
+        errors: str | None = None,
+        newline: str | None = None,
+    ) -> AsyncFile[Any]:
+        fp = await to_thread.run_sync(
+            self._path.open, mode, buffering, encoding, errors, newline
+        )
+        return AsyncFile(fp)
+
+    async def owner(self) -> str:
+        return await to_thread.run_sync(self._path.owner, abandon_on_cancel=True)
+
+    async def read_bytes(self) -> bytes:
+        return await to_thread.run_sync(self._path.read_bytes)
+
+    async def read_text(
+        self, encoding: str | None = None, errors: str | None = None
+    ) -> str:
+        return await to_thread.run_sync(self._path.read_text, encoding, errors)
+
+    if sys.version_info >= (3, 12):
+
+        def relative_to(
+            self, *other: str | PathLike[str], walk_up: bool = False
+        ) -> Path:
+            # relative_to() should work with any PathLike but it doesn't
+            others = [pathlib.Path(other) for other in other]
+            return Path(self._path.relative_to(*others, walk_up=walk_up))
+
+    else:
+
+        def relative_to(self, *other: str | PathLike[str]) -> Path:
+            return Path(self._path.relative_to(*other))
+
+    async def readlink(self) -> Path:
+        target = await to_thread.run_sync(os.readlink, self._path)
+        return Path(target)
+
+    async def rename(self, target: str | pathlib.PurePath | Path) -> Path:
+        if isinstance(target, Path):
+            target = target._path
+
+        await to_thread.run_sync(self._path.rename, target)
+        return Path(target)
+
+    async def replace(self, target: str | pathlib.PurePath | Path) -> Path:
+        if isinstance(target, Path):
+            target = target._path
+
+        await to_thread.run_sync(self._path.replace, target)
+        return Path(target)
+
+    async def resolve(self, strict: bool = False) -> Path:
+        func = partial(self._path.resolve, strict=strict)
+        return Path(await to_thread.run_sync(func, abandon_on_cancel=True))
+
+    if sys.version_info < (3, 12):
+        # Pre Python 3.12
+        def rglob(self, pattern: str) -> AsyncIterator[Path]:
+            gen = self._path.rglob(pattern)
+            return _PathIterator(gen)
+    elif (3, 12) <= sys.version_info < (3, 13):
+        # Changed in Python 3.12:
+        # - The case_sensitive parameter was added.
+        def rglob(
+            self, pattern: str, *, case_sensitive: bool | None = None
+        ) -> AsyncIterator[Path]:
+            gen = self._path.rglob(pattern, case_sensitive=case_sensitive)
+            return _PathIterator(gen)
+    elif sys.version_info >= (3, 13):
+        # Changed in Python 3.13:
+        # - The recurse_symlinks parameter was added.
+        # - The pattern parameter accepts a path-like object.
+        def rglob(  # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block
+            self,
+            pattern: str | PathLike[str],
+            *,
+            case_sensitive: bool | None = None,
+            recurse_symlinks: bool = False,
+        ) -> AsyncIterator[Path]:
+            gen = self._path.rglob(
+                pattern,  # type: ignore[arg-type]
+                case_sensitive=case_sensitive,
+                recurse_symlinks=recurse_symlinks,
+            )
+            return _PathIterator(gen)
+
+    async def rmdir(self) -> None:
+        await to_thread.run_sync(self._path.rmdir)
+
+    async def samefile(self, other_path: str | PathLike[str]) -> bool:
+        if isinstance(other_path, Path):
+            other_path = other_path._path
+
+        return await to_thread.run_sync(
+            self._path.samefile, other_path, abandon_on_cancel=True
+        )
+
+    async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result:
+        func = partial(os.stat, follow_symlinks=follow_symlinks)
+        return await to_thread.run_sync(func, self._path, abandon_on_cancel=True)
+
+    async def symlink_to(
+        self,
+        target: str | bytes | PathLike[str] | PathLike[bytes],
+        target_is_directory: bool = False,
+    ) -> None:
+        if isinstance(target, Path):
+            target = target._path
+
+        await to_thread.run_sync(self._path.symlink_to, target, target_is_directory)
+
+    async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
+        await to_thread.run_sync(self._path.touch, mode, exist_ok)
+
+    async def unlink(self, missing_ok: bool = False) -> None:
+        try:
+            await to_thread.run_sync(self._path.unlink)
+        except FileNotFoundError:
+            if not missing_ok:
+                raise
+
+    if sys.version_info >= (3, 12):
+
+        async def walk(
+            self,
+            top_down: bool = True,
+            on_error: Callable[[OSError], object] | None = None,
+            follow_symlinks: bool = False,
+        ) -> AsyncIterator[tuple[Path, list[str], list[str]]]:
+            def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None:
+                try:
+                    return next(gen)
+                except StopIteration:
+                    return None
+
+            gen = self._path.walk(top_down, on_error, follow_symlinks)
+            while True:
+                value = await to_thread.run_sync(get_next_value)
+                if value is None:
+                    return
+
+                root, dirs, paths = value
+                yield Path(root), dirs, paths
+
+    def with_name(self, name: str) -> Path:
+        return Path(self._path.with_name(name))
+
+    def with_stem(self, stem: str) -> Path:
+        return Path(self._path.with_name(stem + self._path.suffix))
+
+    def with_suffix(self, suffix: str) -> Path:
+        return Path(self._path.with_suffix(suffix))
+
+    def with_segments(self, *pathsegments: str | PathLike[str]) -> Path:
+        return Path(*pathsegments)
+
+    async def write_bytes(self, data: bytes) -> int:
+        return await to_thread.run_sync(self._path.write_bytes, data)
+
+    async def write_text(
+        self,
+        data: str,
+        encoding: str | None = None,
+        errors: str | None = None,
+        newline: str | None = None,
+    ) -> int:
+        # Path.write_text() does not support the "newline" parameter before Python 3.10
+        def sync_write_text() -> int:
+            with self._path.open(
+                "w", encoding=encoding, errors=errors, newline=newline
+            ) as fp:
+                return fp.write(data)
+
+        return await to_thread.run_sync(sync_write_text)
+
+
+PathLike.register(Path)

+ 18 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_resources.py

@@ -0,0 +1,18 @@
+from __future__ import annotations
+
+from ..abc import AsyncResource
+from ._tasks import CancelScope
+
+
+async def aclose_forcefully(resource: AsyncResource) -> None:
+    """
+    Close an asynchronous resource in a cancelled scope.
+
+    Doing this closes the resource without waiting on anything.
+
+    :param resource: the resource to close
+
+    """
+    with CancelScope() as scope:
+        scope.cancel()
+        await resource.aclose()

+ 29 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_signals.py

@@ -0,0 +1,29 @@
+from __future__ import annotations
+
+from collections.abc import AsyncIterator
+from contextlib import AbstractContextManager
+from signal import Signals
+
+from ._eventloop import get_async_backend
+
+
+def open_signal_receiver(
+    *signals: Signals,
+) -> AbstractContextManager[AsyncIterator[Signals]]:
+    """
+    Start receiving operating system signals.
+
+    :param signals: signals to receive (e.g. ``signal.SIGINT``)
+    :return: an asynchronous context manager for an asynchronous iterator which yields
+        signal numbers
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    .. warning:: Windows does not support signals natively so it is best to avoid
+        relying on this in cross-platform applications.
+
+    .. warning:: On asyncio, this permanently replaces any previous signal handler for
+        the given signals, as set via :meth:`~asyncio.loop.add_signal_handler`.
+
+    """
+    return get_async_backend().open_signal_receiver(*signals)

+ 1003 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_sockets.py

@@ -0,0 +1,1003 @@
+from __future__ import annotations
+
+import errno
+import os
+import socket
+import ssl
+import stat
+import sys
+from collections.abc import Awaitable
+from dataclasses import dataclass
+from ipaddress import IPv4Address, IPv6Address, ip_address
+from os import PathLike, chmod
+from socket import AddressFamily, SocketKind
+from typing import TYPE_CHECKING, Any, Literal, cast, overload
+
+from .. import ConnectionFailed, to_thread
+from ..abc import (
+    ByteStreamConnectable,
+    ConnectedUDPSocket,
+    ConnectedUNIXDatagramSocket,
+    IPAddressType,
+    IPSockAddrType,
+    SocketListener,
+    SocketStream,
+    UDPSocket,
+    UNIXDatagramSocket,
+    UNIXSocketStream,
+)
+from ..streams.stapled import MultiListener
+from ..streams.tls import TLSConnectable, TLSStream
+from ._eventloop import get_async_backend
+from ._resources import aclose_forcefully
+from ._synchronization import Event
+from ._tasks import create_task_group, move_on_after
+
+if TYPE_CHECKING:
+    from _typeshed import FileDescriptorLike
+else:
+    FileDescriptorLike = object
+
+if sys.version_info < (3, 11):
+    from exceptiongroup import ExceptionGroup
+
+if sys.version_info >= (3, 12):
+    from typing import override
+else:
+    from typing_extensions import override
+
+if sys.version_info < (3, 13):
+    from typing_extensions import deprecated
+else:
+    from warnings import deprecated
+
+IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41)  # https://bugs.python.org/issue29515
+
+AnyIPAddressFamily = Literal[
+    AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6
+]
+IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6]
+
+
+# tls_hostname given
+@overload
+async def connect_tcp(
+    remote_host: IPAddressType,
+    remote_port: int,
+    *,
+    local_host: IPAddressType | None = ...,
+    ssl_context: ssl.SSLContext | None = ...,
+    tls_standard_compatible: bool = ...,
+    tls_hostname: str,
+    happy_eyeballs_delay: float = ...,
+) -> TLSStream: ...
+
+
+# ssl_context given
+@overload
+async def connect_tcp(
+    remote_host: IPAddressType,
+    remote_port: int,
+    *,
+    local_host: IPAddressType | None = ...,
+    ssl_context: ssl.SSLContext,
+    tls_standard_compatible: bool = ...,
+    tls_hostname: str | None = ...,
+    happy_eyeballs_delay: float = ...,
+) -> TLSStream: ...
+
+
+# tls=True
+@overload
+async def connect_tcp(
+    remote_host: IPAddressType,
+    remote_port: int,
+    *,
+    local_host: IPAddressType | None = ...,
+    tls: Literal[True],
+    ssl_context: ssl.SSLContext | None = ...,
+    tls_standard_compatible: bool = ...,
+    tls_hostname: str | None = ...,
+    happy_eyeballs_delay: float = ...,
+) -> TLSStream: ...
+
+
+# tls=False
+@overload
+async def connect_tcp(
+    remote_host: IPAddressType,
+    remote_port: int,
+    *,
+    local_host: IPAddressType | None = ...,
+    tls: Literal[False],
+    ssl_context: ssl.SSLContext | None = ...,
+    tls_standard_compatible: bool = ...,
+    tls_hostname: str | None = ...,
+    happy_eyeballs_delay: float = ...,
+) -> SocketStream: ...
+
+
+# No TLS arguments
+@overload
+async def connect_tcp(
+    remote_host: IPAddressType,
+    remote_port: int,
+    *,
+    local_host: IPAddressType | None = ...,
+    happy_eyeballs_delay: float = ...,
+) -> SocketStream: ...
+
+
+async def connect_tcp(
+    remote_host: IPAddressType,
+    remote_port: int,
+    *,
+    local_host: IPAddressType | None = None,
+    tls: bool = False,
+    ssl_context: ssl.SSLContext | None = None,
+    tls_standard_compatible: bool = True,
+    tls_hostname: str | None = None,
+    happy_eyeballs_delay: float = 0.25,
+) -> SocketStream | TLSStream:
+    """
+    Connect to a host using the TCP protocol.
+
+    This function implements the stateless version of the Happy Eyeballs algorithm (RFC
+    6555). If ``remote_host`` is a host name that resolves to multiple IP addresses,
+    each one is tried until one connection attempt succeeds. If the first attempt does
+    not connected within 250 milliseconds, a second attempt is started using the next
+    address in the list, and so on. On IPv6 enabled systems, an IPv6 address (if
+    available) is tried first.
+
+    When the connection has been established, a TLS handshake will be done if either
+    ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``.
+
+    :param remote_host: the IP address or host name to connect to
+    :param remote_port: port on the target host to connect to
+    :param local_host: the interface address or name to bind the socket to before
+        connecting
+    :param tls: ``True`` to do a TLS handshake with the connected stream and return a
+        :class:`~anyio.streams.tls.TLSStream` instead
+    :param ssl_context: the SSL context object to use (if omitted, a default context is
+        created)
+    :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake
+        before closing the stream and requires that the server does this as well.
+        Otherwise, :exc:`~ssl.SSLEOFError` may be raised during reads from the stream.
+        Some protocols, such as HTTP, require this option to be ``False``.
+        See :meth:`~ssl.SSLContext.wrap_socket` for details.
+    :param tls_hostname: host name to check the server certificate against (defaults to
+        the value of ``remote_host``)
+    :param happy_eyeballs_delay: delay (in seconds) before starting the next connection
+        attempt
+    :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream
+    :raises ConnectionFailed: if the connection fails
+
+    """
+    # Placed here due to https://github.com/python/mypy/issues/7057
+    connected_stream: SocketStream | None = None
+
+    async def try_connect(remote_host: str, event: Event) -> None:
+        nonlocal connected_stream
+        try:
+            stream = await asynclib.connect_tcp(remote_host, remote_port, local_address)
+        except OSError as exc:
+            oserrors.append(exc)
+            return
+        else:
+            if connected_stream is None:
+                connected_stream = stream
+                tg.cancel_scope.cancel()
+            else:
+                await stream.aclose()
+        finally:
+            event.set()
+
+    asynclib = get_async_backend()
+    local_address: IPSockAddrType | None = None
+    family = socket.AF_UNSPEC
+    if local_host:
+        gai_res = await getaddrinfo(str(local_host), None)
+        family, *_, local_address = gai_res[0]
+
+    target_host = str(remote_host)
+    try:
+        addr_obj = ip_address(remote_host)
+    except ValueError:
+        addr_obj = None
+
+    if addr_obj is not None:
+        if isinstance(addr_obj, IPv6Address):
+            target_addrs = [(socket.AF_INET6, addr_obj.compressed)]
+        else:
+            target_addrs = [(socket.AF_INET, addr_obj.compressed)]
+    else:
+        # getaddrinfo() will raise an exception if name resolution fails
+        gai_res = await getaddrinfo(
+            target_host, remote_port, family=family, type=socket.SOCK_STREAM
+        )
+
+        # Organize the list so that the first address is an IPv6 address (if available)
+        # and the second one is an IPv4 addresses. The rest can be in whatever order.
+        v6_found = v4_found = False
+        target_addrs = []
+        for af, *_, sa in gai_res:
+            if af == socket.AF_INET6 and not v6_found:
+                v6_found = True
+                target_addrs.insert(0, (af, sa[0]))
+            elif af == socket.AF_INET and not v4_found and v6_found:
+                v4_found = True
+                target_addrs.insert(1, (af, sa[0]))
+            else:
+                target_addrs.append((af, sa[0]))
+
+    oserrors: list[OSError] = []
+    try:
+        async with create_task_group() as tg:
+            for _af, addr in target_addrs:
+                event = Event()
+                tg.start_soon(try_connect, addr, event)
+                with move_on_after(happy_eyeballs_delay):
+                    await event.wait()
+
+        if connected_stream is None:
+            cause = (
+                oserrors[0]
+                if len(oserrors) == 1
+                else ExceptionGroup("multiple connection attempts failed", oserrors)
+            )
+            raise OSError("All connection attempts failed") from cause
+    finally:
+        oserrors.clear()
+
+    if tls or tls_hostname or ssl_context:
+        try:
+            return await TLSStream.wrap(
+                connected_stream,
+                server_side=False,
+                hostname=tls_hostname or str(remote_host),
+                ssl_context=ssl_context,
+                standard_compatible=tls_standard_compatible,
+            )
+        except BaseException:
+            await aclose_forcefully(connected_stream)
+            raise
+
+    return connected_stream
+
+
+async def connect_unix(path: str | bytes | PathLike[Any]) -> UNIXSocketStream:
+    """
+    Connect to the given UNIX socket.
+
+    Not available on Windows.
+
+    :param path: path to the socket
+    :return: a socket stream object
+    :raises ConnectionFailed: if the connection fails
+
+    """
+    path = os.fspath(path)
+    return await get_async_backend().connect_unix(path)
+
+
+async def create_tcp_listener(
+    *,
+    local_host: IPAddressType | None = None,
+    local_port: int = 0,
+    family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC,
+    backlog: int = 65536,
+    reuse_port: bool = False,
+) -> MultiListener[SocketStream]:
+    """
+    Create a TCP socket listener.
+
+    :param local_port: port number to listen on
+    :param local_host: IP address of the interface to listen on. If omitted, listen on
+        all IPv4 and IPv6 interfaces. To listen on all interfaces on a specific address
+        family, use ``0.0.0.0`` for IPv4 or ``::`` for IPv6.
+    :param family: address family (used if ``local_host`` was omitted)
+    :param backlog: maximum number of queued incoming connections (up to a maximum of
+        2**16, or 65536)
+    :param reuse_port: ``True`` to allow multiple sockets to bind to the same
+        address/port (not supported on Windows)
+    :return: a multi-listener object containing one or more socket listeners
+    :raises OSError: if there's an error creating a socket, or binding to one or more
+        interfaces failed
+
+    """
+    asynclib = get_async_backend()
+    backlog = min(backlog, 65536)
+    local_host = str(local_host) if local_host is not None else None
+
+    def setup_raw_socket(
+        fam: AddressFamily,
+        bind_addr: tuple[str, int] | tuple[str, int, int, int],
+        *,
+        v6only: bool = True,
+    ) -> socket.socket:
+        sock = socket.socket(fam)
+        try:
+            sock.setblocking(False)
+
+            if fam == AddressFamily.AF_INET6:
+                sock.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, v6only)
+
+            # For Windows, enable exclusive address use. For others, enable address
+            # reuse.
+            if sys.platform == "win32":
+                sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1)
+            else:
+                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+            if reuse_port:
+                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+
+            # Workaround for #554
+            if fam == socket.AF_INET6 and "%" in bind_addr[0]:
+                addr, scope_id = bind_addr[0].split("%", 1)
+                bind_addr = (addr, bind_addr[1], 0, int(scope_id))
+
+            sock.bind(bind_addr)
+            sock.listen(backlog)
+        except BaseException:
+            sock.close()
+            raise
+
+        return sock
+
+    # We passing type=0 on non-Windows platforms as a workaround for a uvloop bug
+    # where we don't get the correct scope ID for IPv6 link-local addresses when passing
+    # type=socket.SOCK_STREAM to getaddrinfo():
+    # https://github.com/MagicStack/uvloop/issues/539
+    gai_res = await getaddrinfo(
+        local_host,
+        local_port,
+        family=family,
+        type=socket.SOCK_STREAM if sys.platform == "win32" else 0,
+        flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
+    )
+
+    # The set comprehension is here to work around a glibc bug:
+    # https://sourceware.org/bugzilla/show_bug.cgi?id=14969
+    sockaddrs = sorted({res for res in gai_res if res[1] == SocketKind.SOCK_STREAM})
+
+    # Special case for dual-stack binding on the "any" interface
+    if (
+        local_host is None
+        and family == AddressFamily.AF_UNSPEC
+        and socket.has_dualstack_ipv6()
+        and any(fam == AddressFamily.AF_INET6 for fam, *_ in gai_res)
+    ):
+        raw_socket = setup_raw_socket(
+            AddressFamily.AF_INET6, ("::", local_port), v6only=False
+        )
+        listener = asynclib.create_tcp_listener(raw_socket)
+        return MultiListener([listener])
+
+    errors: list[OSError] = []
+    try:
+        for _ in range(len(sockaddrs)):
+            listeners: list[SocketListener] = []
+            bound_ephemeral_port = local_port
+            try:
+                for fam, *_, sockaddr in sockaddrs:
+                    sockaddr = sockaddr[0], bound_ephemeral_port, *sockaddr[2:]
+                    raw_socket = setup_raw_socket(fam, sockaddr)
+
+                    # Store the assigned port if an ephemeral port was requested, so
+                    # we'll bind to the same port on all interfaces
+                    if local_port == 0 and len(gai_res) > 1:
+                        bound_ephemeral_port = raw_socket.getsockname()[1]
+
+                    listeners.append(asynclib.create_tcp_listener(raw_socket))
+            except BaseException as exc:
+                for listener in listeners:
+                    await listener.aclose()
+
+                # If an ephemeral port was requested but binding the assigned port
+                # failed for another interface, rotate the address list and try again
+                if (
+                    isinstance(exc, OSError)
+                    and exc.errno == errno.EADDRINUSE
+                    and local_port == 0
+                    and bound_ephemeral_port
+                ):
+                    errors.append(exc)
+                    sockaddrs.append(sockaddrs.pop(0))
+                    continue
+
+                raise
+
+            return MultiListener(listeners)
+
+        raise OSError(
+            f"Could not create {len(sockaddrs)} listeners with a consistent port"
+        ) from ExceptionGroup("Several bind attempts failed", errors)
+    finally:
+        del errors  # Prevent reference cycles
+
+
+async def create_unix_listener(
+    path: str | bytes | PathLike[Any],
+    *,
+    mode: int | None = None,
+    backlog: int = 65536,
+) -> SocketListener:
+    """
+    Create a UNIX socket listener.
+
+    Not available on Windows.
+
+    :param path: path of the socket
+    :param mode: permissions to set on the socket
+    :param backlog: maximum number of queued incoming connections (up to a maximum of
+        2**16, or 65536)
+    :return: a listener object
+
+    .. versionchanged:: 3.0
+        If a socket already exists on the file system in the given path, it will be
+        removed first.
+
+    """
+    backlog = min(backlog, 65536)
+    raw_socket = await setup_unix_local_socket(path, mode, socket.SOCK_STREAM)
+    try:
+        raw_socket.listen(backlog)
+        return get_async_backend().create_unix_listener(raw_socket)
+    except BaseException:
+        raw_socket.close()
+        raise
+
+
+async def create_udp_socket(
+    family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC,
+    *,
+    local_host: IPAddressType | None = None,
+    local_port: int = 0,
+    reuse_port: bool = False,
+) -> UDPSocket:
+    """
+    Create a UDP socket.
+
+    If ``port`` has been given, the socket will be bound to this port on the local
+    machine, making this socket suitable for providing UDP based services.
+
+    :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically
+        determined from ``local_host`` if omitted
+    :param local_host: IP address or host name of the local interface to bind to
+    :param local_port: local port to bind to
+    :param reuse_port: ``True`` to allow multiple sockets to bind to the same
+        address/port (not supported on Windows)
+    :return: a UDP socket
+
+    """
+    if family is AddressFamily.AF_UNSPEC and not local_host:
+        raise ValueError('Either "family" or "local_host" must be given')
+
+    if local_host:
+        gai_res = await getaddrinfo(
+            str(local_host),
+            local_port,
+            family=family,
+            type=socket.SOCK_DGRAM,
+            flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
+        )
+        family = cast(AnyIPAddressFamily, gai_res[0][0])
+        local_address = gai_res[0][-1]
+    elif family is AddressFamily.AF_INET6:
+        local_address = ("::", 0)
+    else:
+        local_address = ("0.0.0.0", 0)
+
+    sock = await get_async_backend().create_udp_socket(
+        family, local_address, None, reuse_port
+    )
+    return cast(UDPSocket, sock)
+
+
+async def create_connected_udp_socket(
+    remote_host: IPAddressType,
+    remote_port: int,
+    *,
+    family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC,
+    local_host: IPAddressType | None = None,
+    local_port: int = 0,
+    reuse_port: bool = False,
+) -> ConnectedUDPSocket:
+    """
+    Create a connected UDP socket.
+
+    Connected UDP sockets can only communicate with the specified remote host/port, an
+    any packets sent from other sources are dropped.
+
+    :param remote_host: remote host to set as the default target
+    :param remote_port: port on the remote host to set as the default target
+    :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically
+        determined from ``local_host`` or ``remote_host`` if omitted
+    :param local_host: IP address or host name of the local interface to bind to
+    :param local_port: local port to bind to
+    :param reuse_port: ``True`` to allow multiple sockets to bind to the same
+        address/port (not supported on Windows)
+    :return: a connected UDP socket
+
+    """
+    local_address = None
+    if local_host:
+        gai_res = await getaddrinfo(
+            str(local_host),
+            local_port,
+            family=family,
+            type=socket.SOCK_DGRAM,
+            flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG,
+        )
+        family = cast(AnyIPAddressFamily, gai_res[0][0])
+        local_address = gai_res[0][-1]
+
+    gai_res = await getaddrinfo(
+        str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM
+    )
+    family = cast(AnyIPAddressFamily, gai_res[0][0])
+    remote_address = gai_res[0][-1]
+
+    sock = await get_async_backend().create_udp_socket(
+        family, local_address, remote_address, reuse_port
+    )
+    return cast(ConnectedUDPSocket, sock)
+
+
+async def create_unix_datagram_socket(
+    *,
+    local_path: None | str | bytes | PathLike[Any] = None,
+    local_mode: int | None = None,
+) -> UNIXDatagramSocket:
+    """
+    Create a UNIX datagram socket.
+
+    Not available on Windows.
+
+    If ``local_path`` has been given, the socket will be bound to this path, making this
+    socket suitable for receiving datagrams from other processes. Other processes can
+    send datagrams to this socket only if ``local_path`` is set.
+
+    If a socket already exists on the file system in the ``local_path``, it will be
+    removed first.
+
+    :param local_path: the path on which to bind to
+    :param local_mode: permissions to set on the local socket
+    :return: a UNIX datagram socket
+
+    """
+    raw_socket = await setup_unix_local_socket(
+        local_path, local_mode, socket.SOCK_DGRAM
+    )
+    return await get_async_backend().create_unix_datagram_socket(raw_socket, None)
+
+
+async def create_connected_unix_datagram_socket(
+    remote_path: str | bytes | PathLike[Any],
+    *,
+    local_path: None | str | bytes | PathLike[Any] = None,
+    local_mode: int | None = None,
+) -> ConnectedUNIXDatagramSocket:
+    """
+    Create a connected UNIX datagram socket.
+
+    Connected datagram sockets can only communicate with the specified remote path.
+
+    If ``local_path`` has been given, the socket will be bound to this path, making
+    this socket suitable for receiving datagrams from other processes. Other processes
+    can send datagrams to this socket only if ``local_path`` is set.
+
+    If a socket already exists on the file system in the ``local_path``, it will be
+    removed first.
+
+    :param remote_path: the path to set as the default target
+    :param local_path: the path on which to bind to
+    :param local_mode: permissions to set on the local socket
+    :return: a connected UNIX datagram socket
+
+    """
+    remote_path = os.fspath(remote_path)
+    raw_socket = await setup_unix_local_socket(
+        local_path, local_mode, socket.SOCK_DGRAM
+    )
+    return await get_async_backend().create_unix_datagram_socket(
+        raw_socket, remote_path
+    )
+
+
+async def getaddrinfo(
+    host: bytes | str | None,
+    port: str | int | None,
+    *,
+    family: int | AddressFamily = 0,
+    type: int | SocketKind = 0,
+    proto: int = 0,
+    flags: int = 0,
+) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int]]]:
+    """
+    Look up a numeric IP address given a host name.
+
+    Internationalized domain names are translated according to the (non-transitional)
+    IDNA 2008 standard.
+
+    .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of
+        (host, port), unlike what :func:`socket.getaddrinfo` does.
+
+    :param host: host name
+    :param port: port number
+    :param family: socket family (`'AF_INET``, ...)
+    :param type: socket type (``SOCK_STREAM``, ...)
+    :param proto: protocol number
+    :param flags: flags to pass to upstream ``getaddrinfo()``
+    :return: list of tuples containing (family, type, proto, canonname, sockaddr)
+
+    .. seealso:: :func:`socket.getaddrinfo`
+
+    """
+    # Handle unicode hostnames
+    if isinstance(host, str):
+        try:
+            encoded_host: bytes | None = host.encode("ascii")
+        except UnicodeEncodeError:
+            import idna
+
+            encoded_host = idna.encode(host, uts46=True)
+    else:
+        encoded_host = host
+
+    gai_res = await get_async_backend().getaddrinfo(
+        encoded_host, port, family=family, type=type, proto=proto, flags=flags
+    )
+    return [
+        (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr))
+        for family, type, proto, canonname, sockaddr in gai_res
+        # filter out IPv6 results when IPv6 is disabled
+        if not isinstance(sockaddr[0], int)
+    ]
+
+
+def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[tuple[str, str]]:
+    """
+    Look up the host name of an IP address.
+
+    :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4)
+    :param flags: flags to pass to upstream ``getnameinfo()``
+    :return: a tuple of (host name, service name)
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    .. seealso:: :func:`socket.getnameinfo`
+
+    """
+    return get_async_backend().getnameinfo(sockaddr, flags)
+
+
+@deprecated("This function is deprecated; use `wait_readable` instead")
+def wait_socket_readable(sock: socket.socket) -> Awaitable[None]:
+    """
+    .. deprecated:: 4.7.0
+       Use :func:`wait_readable` instead.
+
+    Wait until the given socket has data to be read.
+
+    .. warning:: Only use this on raw sockets that have not been wrapped by any higher
+        level constructs like socket streams!
+
+    :param sock: a socket object
+    :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the
+        socket to become readable
+    :raises ~anyio.BusyResourceError: if another task is already waiting for the socket
+        to become readable
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return get_async_backend().wait_readable(sock.fileno())
+
+
+@deprecated("This function is deprecated; use `wait_writable` instead")
+def wait_socket_writable(sock: socket.socket) -> Awaitable[None]:
+    """
+    .. deprecated:: 4.7.0
+       Use :func:`wait_writable` instead.
+
+    Wait until the given socket can be written to.
+
+    This does **NOT** work on Windows when using the asyncio backend with a proactor
+    event loop (default on py3.8+).
+
+    .. warning:: Only use this on raw sockets that have not been wrapped by any higher
+        level constructs like socket streams!
+
+    :param sock: a socket object
+    :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the
+        socket to become writable
+    :raises ~anyio.BusyResourceError: if another task is already waiting for the socket
+        to become writable
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return get_async_backend().wait_writable(sock.fileno())
+
+
+def wait_readable(obj: FileDescriptorLike) -> Awaitable[None]:
+    """
+    Wait until the given object has data to be read.
+
+    On Unix systems, ``obj`` must either be an integer file descriptor, or else an
+    object with a ``.fileno()`` method which returns an integer file descriptor. Any
+    kind of file descriptor can be passed, though the exact semantics will depend on
+    your kernel. For example, this probably won't do anything useful for on-disk files.
+
+    On Windows systems, ``obj`` must either be an integer ``SOCKET`` handle, or else an
+    object with a ``.fileno()`` method which returns an integer ``SOCKET`` handle. File
+    descriptors aren't supported, and neither are handles that refer to anything besides
+    a ``SOCKET``.
+
+    On backends where this functionality is not natively provided (asyncio
+    ``ProactorEventLoop`` on Windows), it is provided using a separate selector thread
+    which is set to shut down when the interpreter shuts down.
+
+    .. warning:: Don't use this on raw sockets that have been wrapped by any higher
+        level constructs like socket streams!
+
+    :param obj: an object with a ``.fileno()`` method or an integer handle
+    :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the
+        object to become readable
+    :raises ~anyio.BusyResourceError: if another task is already waiting for the object
+        to become readable
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return get_async_backend().wait_readable(obj)
+
+
+def wait_writable(obj: FileDescriptorLike) -> Awaitable[None]:
+    """
+    Wait until the given object can be written to.
+
+    :param obj: an object with a ``.fileno()`` method or an integer handle
+    :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the
+        object to become writable
+    :raises ~anyio.BusyResourceError: if another task is already waiting for the object
+        to become writable
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    .. seealso:: See the documentation of :func:`wait_readable` for the definition of
+       ``obj`` and notes on backend compatibility.
+
+    .. warning:: Don't use this on raw sockets that have been wrapped by any higher
+        level constructs like socket streams!
+
+    """
+    return get_async_backend().wait_writable(obj)
+
+
+def notify_closing(obj: FileDescriptorLike) -> None:
+    """
+    Call this before closing a file descriptor (on Unix) or socket (on
+    Windows). This will cause any `wait_readable` or `wait_writable`
+    calls on the given object to immediately wake up and raise
+    `~anyio.ClosedResourceError`.
+
+    This doesn't actually close the object – you still have to do that
+    yourself afterwards. Also, you want to be careful to make sure no
+    new tasks start waiting on the object in between when you call this
+    and when it's actually closed. So to close something properly, you
+    usually want to do these steps in order:
+
+    1. Explicitly mark the object as closed, so that any new attempts
+       to use it will abort before they start.
+    2. Call `notify_closing` to wake up any already-existing users.
+    3. Actually close the object.
+
+    It's also possible to do them in a different order if that's more
+    convenient, *but only if* you make sure not to have any checkpoints in
+    between the steps. This way they all happen in a single atomic
+    step, so other tasks won't be able to tell what order they happened
+    in anyway.
+
+    :param obj: an object with a ``.fileno()`` method or an integer handle
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    get_async_backend().notify_closing(obj)
+
+
+#
+# Private API
+#
+
+
+def convert_ipv6_sockaddr(
+    sockaddr: tuple[str, int, int, int] | tuple[str, int],
+) -> tuple[str, int]:
+    """
+    Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format.
+
+    If the scope ID is nonzero, it is added to the address, separated with ``%``.
+    Otherwise the flow id and scope id are simply cut off from the tuple.
+    Any other kinds of socket addresses are returned as-is.
+
+    :param sockaddr: the result of :meth:`~socket.socket.getsockname`
+    :return: the converted socket address
+
+    """
+    # This is more complicated than it should be because of MyPy
+    if isinstance(sockaddr, tuple) and len(sockaddr) == 4:
+        host, port, flowinfo, scope_id = sockaddr
+        if scope_id:
+            # PyPy (as of v7.3.11) leaves the interface name in the result, so
+            # we discard it and only get the scope ID from the end
+            # (https://foss.heptapod.net/pypy/pypy/-/issues/3938)
+            host = host.split("%")[0]
+
+            # Add scope_id to the address
+            return f"{host}%{scope_id}", port
+        else:
+            return host, port
+    else:
+        return sockaddr
+
+
+async def setup_unix_local_socket(
+    path: None | str | bytes | PathLike[Any],
+    mode: int | None,
+    socktype: int,
+) -> socket.socket:
+    """
+    Create a UNIX local socket object, deleting the socket at the given path if it
+    exists.
+
+    Not available on Windows.
+
+    :param path: path of the socket
+    :param mode: permissions to set on the socket
+    :param socktype: socket.SOCK_STREAM or socket.SOCK_DGRAM
+
+    """
+    path_str: str | None
+    if path is not None:
+        path_str = os.fsdecode(path)
+
+        # Linux abstract namespace sockets aren't backed by a concrete file so skip stat call
+        if not path_str.startswith("\0"):
+            # Copied from pathlib...
+            try:
+                stat_result = os.stat(path)
+            except OSError as e:
+                if e.errno not in (
+                    errno.ENOENT,
+                    errno.ENOTDIR,
+                    errno.EBADF,
+                    errno.ELOOP,
+                ):
+                    raise
+            else:
+                if stat.S_ISSOCK(stat_result.st_mode):
+                    os.unlink(path)
+    else:
+        path_str = None
+
+    raw_socket = socket.socket(socket.AF_UNIX, socktype)
+    raw_socket.setblocking(False)
+
+    if path_str is not None:
+        try:
+            await to_thread.run_sync(raw_socket.bind, path_str, abandon_on_cancel=True)
+            if mode is not None:
+                await to_thread.run_sync(chmod, path_str, mode, abandon_on_cancel=True)
+        except BaseException:
+            raw_socket.close()
+            raise
+
+    return raw_socket
+
+
+@dataclass
+class TCPConnectable(ByteStreamConnectable):
+    """
+    Connects to a TCP server at the given host and port.
+
+    :param host: host name or IP address of the server
+    :param port: TCP port number of the server
+    """
+
+    host: str | IPv4Address | IPv6Address
+    port: int
+
+    def __post_init__(self) -> None:
+        if self.port < 1 or self.port > 65535:
+            raise ValueError("TCP port number out of range")
+
+    @override
+    async def connect(self) -> SocketStream:
+        try:
+            return await connect_tcp(self.host, self.port)
+        except OSError as exc:
+            raise ConnectionFailed(
+                f"error connecting to {self.host}:{self.port}: {exc}"
+            ) from exc
+
+
+@dataclass
+class UNIXConnectable(ByteStreamConnectable):
+    """
+    Connects to a UNIX domain socket at the given path.
+
+    :param path: the file system path of the socket
+    """
+
+    path: str | bytes | PathLike[str] | PathLike[bytes]
+
+    @override
+    async def connect(self) -> UNIXSocketStream:
+        try:
+            return await connect_unix(self.path)
+        except OSError as exc:
+            raise ConnectionFailed(f"error connecting to {self.path!r}: {exc}") from exc
+
+
+def as_connectable(
+    remote: ByteStreamConnectable
+    | tuple[str | IPv4Address | IPv6Address, int]
+    | str
+    | bytes
+    | PathLike[str],
+    /,
+    *,
+    tls: bool = False,
+    ssl_context: ssl.SSLContext | None = None,
+    tls_hostname: str | None = None,
+    tls_standard_compatible: bool = True,
+) -> ByteStreamConnectable:
+    """
+    Return a byte stream connectable from the given object.
+
+    If a bytestream connectable is given, it is returned unchanged.
+    If a tuple of (host, port) is given, a TCP connectable is returned.
+    If a string or bytes path is given, a UNIX connectable is returned.
+
+    If ``tls=True``, the connectable will be wrapped in a
+    :class:`~.streams.tls.TLSConnectable`.
+
+    :param remote: a connectable, a tuple of (host, port) or a path to a UNIX socket
+    :param tls: if ``True``, wrap the plaintext connectable in a
+        :class:`~.streams.tls.TLSConnectable`, using the provided TLS settings)
+    :param ssl_context: if ``tls=True``, the SSLContext object to use  (if not provided,
+        a secure default will be created)
+    :param tls_hostname: if ``tls=True``, host name of the server to use for checking
+        the server certificate (defaults to the host portion of the address for TCP
+        connectables)
+    :param tls_standard_compatible: if ``False`` and ``tls=True``, makes the TLS stream
+        skip the closing handshake when closing the connection, so it won't raise an
+        exception if the server does the same
+
+    """
+    connectable: TCPConnectable | UNIXConnectable | TLSConnectable
+    if isinstance(remote, ByteStreamConnectable):
+        return remote
+    elif isinstance(remote, tuple) and len(remote) == 2:
+        connectable = TCPConnectable(*remote)
+    elif isinstance(remote, (str, bytes, PathLike)):
+        connectable = UNIXConnectable(remote)
+    else:
+        raise TypeError(f"cannot convert {remote!r} to a connectable")
+
+    if tls:
+        if not tls_hostname and isinstance(connectable, TCPConnectable):
+            tls_hostname = str(connectable.host)
+
+        connectable = TLSConnectable(
+            connectable,
+            ssl_context=ssl_context,
+            hostname=tls_hostname,
+            standard_compatible=tls_standard_compatible,
+        )
+
+    return connectable

+ 52 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_streams.py

@@ -0,0 +1,52 @@
+from __future__ import annotations
+
+import math
+from typing import TypeVar
+from warnings import warn
+
+from ..streams.memory import (
+    MemoryObjectReceiveStream,
+    MemoryObjectSendStream,
+    _MemoryObjectStreamState,
+)
+
+T_Item = TypeVar("T_Item")
+
+
+class create_memory_object_stream(
+    tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]],
+):
+    """
+    Create a memory object stream.
+
+    The stream's item type can be annotated like
+    :func:`create_memory_object_stream[T_Item]`.
+
+    :param max_buffer_size: number of items held in the buffer until ``send()`` starts
+        blocking
+    :param item_type: old way of marking the streams with the right generic type for
+        static typing (does nothing on AnyIO 4)
+
+        .. deprecated:: 4.0
+          Use ``create_memory_object_stream[YourItemType](...)`` instead.
+    :return: a tuple of (send stream, receive stream)
+
+    """
+
+    def __new__(  # type: ignore[misc]
+        cls, max_buffer_size: float = 0, item_type: object = None
+    ) -> tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]:
+        if max_buffer_size != math.inf and not isinstance(max_buffer_size, int):
+            raise ValueError("max_buffer_size must be either an integer or math.inf")
+        if max_buffer_size < 0:
+            raise ValueError("max_buffer_size cannot be negative")
+        if item_type is not None:
+            warn(
+                "The item_type argument has been deprecated in AnyIO 4.0. "
+                "Use create_memory_object_stream[YourItemType](...) instead.",
+                DeprecationWarning,
+                stacklevel=2,
+            )
+
+        state = _MemoryObjectStreamState[T_Item](max_buffer_size)
+        return (MemoryObjectSendStream(state), MemoryObjectReceiveStream(state))

+ 202 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_subprocesses.py

@@ -0,0 +1,202 @@
+from __future__ import annotations
+
+import sys
+from collections.abc import AsyncIterable, Iterable, Mapping, Sequence
+from io import BytesIO
+from os import PathLike
+from subprocess import PIPE, CalledProcessError, CompletedProcess
+from typing import IO, Any, Union, cast
+
+from ..abc import Process
+from ._eventloop import get_async_backend
+from ._tasks import create_task_group
+
+if sys.version_info >= (3, 10):
+    from typing import TypeAlias
+else:
+    from typing_extensions import TypeAlias
+
+StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"]
+
+
+async def run_process(
+    command: StrOrBytesPath | Sequence[StrOrBytesPath],
+    *,
+    input: bytes | None = None,
+    stdin: int | IO[Any] | None = None,
+    stdout: int | IO[Any] | None = PIPE,
+    stderr: int | IO[Any] | None = PIPE,
+    check: bool = True,
+    cwd: StrOrBytesPath | None = None,
+    env: Mapping[str, str] | None = None,
+    startupinfo: Any = None,
+    creationflags: int = 0,
+    start_new_session: bool = False,
+    pass_fds: Sequence[int] = (),
+    user: str | int | None = None,
+    group: str | int | None = None,
+    extra_groups: Iterable[str | int] | None = None,
+    umask: int = -1,
+) -> CompletedProcess[bytes]:
+    """
+    Run an external command in a subprocess and wait until it completes.
+
+    .. seealso:: :func:`subprocess.run`
+
+    :param command: either a string to pass to the shell, or an iterable of strings
+        containing the executable name or path and its arguments
+    :param input: bytes passed to the standard input of the subprocess
+    :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+        a file-like object, or `None`; ``input`` overrides this
+    :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+        a file-like object, or `None`
+    :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+        :data:`subprocess.STDOUT`, a file-like object, or `None`
+    :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the
+        process terminates with a return code other than 0
+    :param cwd: If not ``None``, change the working directory to this before running the
+        command
+    :param env: if not ``None``, this mapping replaces the inherited environment
+        variables from the parent process
+    :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used
+        to specify process startup parameters (Windows only)
+    :param creationflags: flags that can be used to control the creation of the
+        subprocess (see :class:`subprocess.Popen` for the specifics)
+    :param start_new_session: if ``true`` the setsid() system call will be made in the
+        child process prior to the execution of the subprocess. (POSIX only)
+    :param pass_fds: sequence of file descriptors to keep open between the parent and
+        child processes. (POSIX only)
+    :param user: effective user to run the process as (Python >= 3.9, POSIX only)
+    :param group: effective group to run the process as (Python >= 3.9, POSIX only)
+    :param extra_groups: supplementary groups to set in the subprocess (Python >= 3.9,
+        POSIX only)
+    :param umask: if not negative, this umask is applied in the child process before
+        running the given command (Python >= 3.9, POSIX only)
+    :return: an object representing the completed process
+    :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process
+        exits with a nonzero return code
+
+    """
+
+    async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None:
+        buffer = BytesIO()
+        async for chunk in stream:
+            buffer.write(chunk)
+
+        stream_contents[index] = buffer.getvalue()
+
+    if stdin is not None and input is not None:
+        raise ValueError("only one of stdin and input is allowed")
+
+    async with await open_process(
+        command,
+        stdin=PIPE if input else stdin,
+        stdout=stdout,
+        stderr=stderr,
+        cwd=cwd,
+        env=env,
+        startupinfo=startupinfo,
+        creationflags=creationflags,
+        start_new_session=start_new_session,
+        pass_fds=pass_fds,
+        user=user,
+        group=group,
+        extra_groups=extra_groups,
+        umask=umask,
+    ) as process:
+        stream_contents: list[bytes | None] = [None, None]
+        async with create_task_group() as tg:
+            if process.stdout:
+                tg.start_soon(drain_stream, process.stdout, 0)
+
+            if process.stderr:
+                tg.start_soon(drain_stream, process.stderr, 1)
+
+            if process.stdin and input:
+                await process.stdin.send(input)
+                await process.stdin.aclose()
+
+            await process.wait()
+
+    output, errors = stream_contents
+    if check and process.returncode != 0:
+        raise CalledProcessError(cast(int, process.returncode), command, output, errors)
+
+    return CompletedProcess(command, cast(int, process.returncode), output, errors)
+
+
+async def open_process(
+    command: StrOrBytesPath | Sequence[StrOrBytesPath],
+    *,
+    stdin: int | IO[Any] | None = PIPE,
+    stdout: int | IO[Any] | None = PIPE,
+    stderr: int | IO[Any] | None = PIPE,
+    cwd: StrOrBytesPath | None = None,
+    env: Mapping[str, str] | None = None,
+    startupinfo: Any = None,
+    creationflags: int = 0,
+    start_new_session: bool = False,
+    pass_fds: Sequence[int] = (),
+    user: str | int | None = None,
+    group: str | int | None = None,
+    extra_groups: Iterable[str | int] | None = None,
+    umask: int = -1,
+) -> Process:
+    """
+    Start an external command in a subprocess.
+
+    .. seealso:: :class:`subprocess.Popen`
+
+    :param command: either a string to pass to the shell, or an iterable of strings
+        containing the executable name or path and its arguments
+    :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a
+        file-like object, or ``None``
+    :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+        a file-like object, or ``None``
+    :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`,
+        :data:`subprocess.STDOUT`, a file-like object, or ``None``
+    :param cwd: If not ``None``, the working directory is changed before executing
+    :param env: If env is not ``None``, it must be a mapping that defines the
+        environment variables for the new process
+    :param creationflags: flags that can be used to control the creation of the
+        subprocess (see :class:`subprocess.Popen` for the specifics)
+    :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used
+        to specify process startup parameters (Windows only)
+    :param start_new_session: if ``true`` the setsid() system call will be made in the
+        child process prior to the execution of the subprocess. (POSIX only)
+    :param pass_fds: sequence of file descriptors to keep open between the parent and
+        child processes. (POSIX only)
+    :param user: effective user to run the process as (POSIX only)
+    :param group: effective group to run the process as (POSIX only)
+    :param extra_groups: supplementary groups to set in the subprocess (POSIX only)
+    :param umask: if not negative, this umask is applied in the child process before
+        running the given command (POSIX only)
+    :return: an asynchronous process object
+
+    """
+    kwargs: dict[str, Any] = {}
+    if user is not None:
+        kwargs["user"] = user
+
+    if group is not None:
+        kwargs["group"] = group
+
+    if extra_groups is not None:
+        kwargs["extra_groups"] = group
+
+    if umask >= 0:
+        kwargs["umask"] = umask
+
+    return await get_async_backend().open_process(
+        command,
+        stdin=stdin,
+        stdout=stdout,
+        stderr=stderr,
+        cwd=cwd,
+        env=env,
+        startupinfo=startupinfo,
+        creationflags=creationflags,
+        start_new_session=start_new_session,
+        pass_fds=pass_fds,
+        **kwargs,
+    )

+ 753 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_synchronization.py

@@ -0,0 +1,753 @@
+from __future__ import annotations
+
+import math
+from collections import deque
+from collections.abc import Callable
+from dataclasses import dataclass
+from types import TracebackType
+from typing import TypeVar
+
+from ..lowlevel import checkpoint_if_cancelled
+from ._eventloop import get_async_backend
+from ._exceptions import BusyResourceError, NoEventLoopError
+from ._tasks import CancelScope
+from ._testing import TaskInfo, get_current_task
+
+T = TypeVar("T")
+
+
+@dataclass(frozen=True)
+class EventStatistics:
+    """
+    :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait`
+    """
+
+    tasks_waiting: int
+
+
+@dataclass(frozen=True)
+class CapacityLimiterStatistics:
+    """
+    :ivar int borrowed_tokens: number of tokens currently borrowed by tasks
+    :ivar float total_tokens: total number of available tokens
+    :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from
+        this limiter
+    :ivar int tasks_waiting: number of tasks waiting on
+        :meth:`~.CapacityLimiter.acquire` or
+        :meth:`~.CapacityLimiter.acquire_on_behalf_of`
+    """
+
+    borrowed_tokens: int
+    total_tokens: float
+    borrowers: tuple[object, ...]
+    tasks_waiting: int
+
+
+@dataclass(frozen=True)
+class LockStatistics:
+    """
+    :ivar bool locked: flag indicating if this lock is locked or not
+    :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the
+        lock is not held by any task)
+    :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire`
+    """
+
+    locked: bool
+    owner: TaskInfo | None
+    tasks_waiting: int
+
+
+@dataclass(frozen=True)
+class ConditionStatistics:
+    """
+    :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait`
+    :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying
+        :class:`~.Lock`
+    """
+
+    tasks_waiting: int
+    lock_statistics: LockStatistics
+
+
+@dataclass(frozen=True)
+class SemaphoreStatistics:
+    """
+    :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire`
+
+    """
+
+    tasks_waiting: int
+
+
+class Event:
+    def __new__(cls) -> Event:
+        try:
+            return get_async_backend().create_event()
+        except NoEventLoopError:
+            return EventAdapter()
+
+    def set(self) -> None:
+        """Set the flag, notifying all listeners."""
+        raise NotImplementedError
+
+    def is_set(self) -> bool:
+        """Return ``True`` if the flag is set, ``False`` if not."""
+        raise NotImplementedError
+
+    async def wait(self) -> None:
+        """
+        Wait until the flag has been set.
+
+        If the flag has already been set when this method is called, it returns
+        immediately.
+
+        """
+        raise NotImplementedError
+
+    def statistics(self) -> EventStatistics:
+        """Return statistics about the current state of this event."""
+        raise NotImplementedError
+
+
+class EventAdapter(Event):
+    _internal_event: Event | None = None
+    _is_set: bool = False
+
+    def __new__(cls) -> EventAdapter:
+        return object.__new__(cls)
+
+    @property
+    def _event(self) -> Event:
+        if self._internal_event is None:
+            self._internal_event = get_async_backend().create_event()
+            if self._is_set:
+                self._internal_event.set()
+
+        return self._internal_event
+
+    def set(self) -> None:
+        if self._internal_event is None:
+            self._is_set = True
+        else:
+            self._event.set()
+
+    def is_set(self) -> bool:
+        if self._internal_event is None:
+            return self._is_set
+
+        return self._internal_event.is_set()
+
+    async def wait(self) -> None:
+        await self._event.wait()
+
+    def statistics(self) -> EventStatistics:
+        if self._internal_event is None:
+            return EventStatistics(tasks_waiting=0)
+
+        return self._internal_event.statistics()
+
+
+class Lock:
+    def __new__(cls, *, fast_acquire: bool = False) -> Lock:
+        try:
+            return get_async_backend().create_lock(fast_acquire=fast_acquire)
+        except NoEventLoopError:
+            return LockAdapter(fast_acquire=fast_acquire)
+
+    async def __aenter__(self) -> None:
+        await self.acquire()
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self.release()
+
+    async def acquire(self) -> None:
+        """Acquire the lock."""
+        raise NotImplementedError
+
+    def acquire_nowait(self) -> None:
+        """
+        Acquire the lock, without blocking.
+
+        :raises ~anyio.WouldBlock: if the operation would block
+
+        """
+        raise NotImplementedError
+
+    def release(self) -> None:
+        """Release the lock."""
+        raise NotImplementedError
+
+    def locked(self) -> bool:
+        """Return True if the lock is currently held."""
+        raise NotImplementedError
+
+    def statistics(self) -> LockStatistics:
+        """
+        Return statistics about the current state of this lock.
+
+        .. versionadded:: 3.0
+        """
+        raise NotImplementedError
+
+
+class LockAdapter(Lock):
+    _internal_lock: Lock | None = None
+
+    def __new__(cls, *, fast_acquire: bool = False) -> LockAdapter:
+        return object.__new__(cls)
+
+    def __init__(self, *, fast_acquire: bool = False):
+        self._fast_acquire = fast_acquire
+
+    @property
+    def _lock(self) -> Lock:
+        if self._internal_lock is None:
+            self._internal_lock = get_async_backend().create_lock(
+                fast_acquire=self._fast_acquire
+            )
+
+        return self._internal_lock
+
+    async def __aenter__(self) -> None:
+        await self._lock.acquire()
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        if self._internal_lock is not None:
+            self._internal_lock.release()
+
+    async def acquire(self) -> None:
+        """Acquire the lock."""
+        await self._lock.acquire()
+
+    def acquire_nowait(self) -> None:
+        """
+        Acquire the lock, without blocking.
+
+        :raises ~anyio.WouldBlock: if the operation would block
+
+        """
+        self._lock.acquire_nowait()
+
+    def release(self) -> None:
+        """Release the lock."""
+        self._lock.release()
+
+    def locked(self) -> bool:
+        """Return True if the lock is currently held."""
+        return self._lock.locked()
+
+    def statistics(self) -> LockStatistics:
+        """
+        Return statistics about the current state of this lock.
+
+        .. versionadded:: 3.0
+
+        """
+        if self._internal_lock is None:
+            return LockStatistics(False, None, 0)
+
+        return self._internal_lock.statistics()
+
+
+class Condition:
+    _owner_task: TaskInfo | None = None
+
+    def __init__(self, lock: Lock | None = None):
+        self._lock = lock or Lock()
+        self._waiters: deque[Event] = deque()
+
+    async def __aenter__(self) -> None:
+        await self.acquire()
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self.release()
+
+    def _check_acquired(self) -> None:
+        if self._owner_task != get_current_task():
+            raise RuntimeError("The current task is not holding the underlying lock")
+
+    async def acquire(self) -> None:
+        """Acquire the underlying lock."""
+        await self._lock.acquire()
+        self._owner_task = get_current_task()
+
+    def acquire_nowait(self) -> None:
+        """
+        Acquire the underlying lock, without blocking.
+
+        :raises ~anyio.WouldBlock: if the operation would block
+
+        """
+        self._lock.acquire_nowait()
+        self._owner_task = get_current_task()
+
+    def release(self) -> None:
+        """Release the underlying lock."""
+        self._lock.release()
+
+    def locked(self) -> bool:
+        """Return True if the lock is set."""
+        return self._lock.locked()
+
+    def notify(self, n: int = 1) -> None:
+        """Notify exactly n listeners."""
+        self._check_acquired()
+        for _ in range(n):
+            try:
+                event = self._waiters.popleft()
+            except IndexError:
+                break
+
+            event.set()
+
+    def notify_all(self) -> None:
+        """Notify all the listeners."""
+        self._check_acquired()
+        for event in self._waiters:
+            event.set()
+
+        self._waiters.clear()
+
+    async def wait(self) -> None:
+        """Wait for a notification."""
+        await checkpoint_if_cancelled()
+        self._check_acquired()
+        event = Event()
+        self._waiters.append(event)
+        self.release()
+        try:
+            await event.wait()
+        except BaseException:
+            if not event.is_set():
+                self._waiters.remove(event)
+
+            raise
+        finally:
+            with CancelScope(shield=True):
+                await self.acquire()
+
+    async def wait_for(self, predicate: Callable[[], T]) -> T:
+        """
+        Wait until a predicate becomes true.
+
+        :param predicate: a callable that returns a truthy value when the condition is
+            met
+        :return: the result of the predicate
+
+        .. versionadded:: 4.11.0
+
+        """
+        while not (result := predicate()):
+            await self.wait()
+
+        return result
+
+    def statistics(self) -> ConditionStatistics:
+        """
+        Return statistics about the current state of this condition.
+
+        .. versionadded:: 3.0
+        """
+        return ConditionStatistics(len(self._waiters), self._lock.statistics())
+
+
+class Semaphore:
+    def __new__(
+        cls,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> Semaphore:
+        try:
+            return get_async_backend().create_semaphore(
+                initial_value, max_value=max_value, fast_acquire=fast_acquire
+            )
+        except NoEventLoopError:
+            return SemaphoreAdapter(initial_value, max_value=max_value)
+
+    def __init__(
+        self,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ):
+        if not isinstance(initial_value, int):
+            raise TypeError("initial_value must be an integer")
+        if initial_value < 0:
+            raise ValueError("initial_value must be >= 0")
+        if max_value is not None:
+            if not isinstance(max_value, int):
+                raise TypeError("max_value must be an integer or None")
+            if max_value < initial_value:
+                raise ValueError(
+                    "max_value must be equal to or higher than initial_value"
+                )
+
+        self._fast_acquire = fast_acquire
+
+    async def __aenter__(self) -> Semaphore:
+        await self.acquire()
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self.release()
+
+    async def acquire(self) -> None:
+        """Decrement the semaphore value, blocking if necessary."""
+        raise NotImplementedError
+
+    def acquire_nowait(self) -> None:
+        """
+        Acquire the underlying lock, without blocking.
+
+        :raises ~anyio.WouldBlock: if the operation would block
+
+        """
+        raise NotImplementedError
+
+    def release(self) -> None:
+        """Increment the semaphore value."""
+        raise NotImplementedError
+
+    @property
+    def value(self) -> int:
+        """The current value of the semaphore."""
+        raise NotImplementedError
+
+    @property
+    def max_value(self) -> int | None:
+        """The maximum value of the semaphore."""
+        raise NotImplementedError
+
+    def statistics(self) -> SemaphoreStatistics:
+        """
+        Return statistics about the current state of this semaphore.
+
+        .. versionadded:: 3.0
+        """
+        raise NotImplementedError
+
+
+class SemaphoreAdapter(Semaphore):
+    _internal_semaphore: Semaphore | None = None
+
+    def __new__(
+        cls,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> SemaphoreAdapter:
+        return object.__new__(cls)
+
+    def __init__(
+        self,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> None:
+        super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire)
+        self._initial_value = initial_value
+        self._max_value = max_value
+
+    @property
+    def _semaphore(self) -> Semaphore:
+        if self._internal_semaphore is None:
+            self._internal_semaphore = get_async_backend().create_semaphore(
+                self._initial_value, max_value=self._max_value
+            )
+
+        return self._internal_semaphore
+
+    async def acquire(self) -> None:
+        await self._semaphore.acquire()
+
+    def acquire_nowait(self) -> None:
+        self._semaphore.acquire_nowait()
+
+    def release(self) -> None:
+        self._semaphore.release()
+
+    @property
+    def value(self) -> int:
+        if self._internal_semaphore is None:
+            return self._initial_value
+
+        return self._semaphore.value
+
+    @property
+    def max_value(self) -> int | None:
+        return self._max_value
+
+    def statistics(self) -> SemaphoreStatistics:
+        if self._internal_semaphore is None:
+            return SemaphoreStatistics(tasks_waiting=0)
+
+        return self._semaphore.statistics()
+
+
+class CapacityLimiter:
+    def __new__(cls, total_tokens: float) -> CapacityLimiter:
+        try:
+            return get_async_backend().create_capacity_limiter(total_tokens)
+        except NoEventLoopError:
+            return CapacityLimiterAdapter(total_tokens)
+
+    async def __aenter__(self) -> None:
+        raise NotImplementedError
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        raise NotImplementedError
+
+    @property
+    def total_tokens(self) -> float:
+        """
+        The total number of tokens available for borrowing.
+
+        This is a read-write property. If the total number of tokens is increased, the
+        proportionate number of tasks waiting on this limiter will be granted their
+        tokens.
+
+        .. versionchanged:: 3.0
+            The property is now writable.
+        .. versionchanged:: 4.12
+            The value can now be set to 0.
+
+        """
+        raise NotImplementedError
+
+    @total_tokens.setter
+    def total_tokens(self, value: float) -> None:
+        raise NotImplementedError
+
+    @property
+    def borrowed_tokens(self) -> int:
+        """The number of tokens that have currently been borrowed."""
+        raise NotImplementedError
+
+    @property
+    def available_tokens(self) -> float:
+        """The number of tokens currently available to be borrowed"""
+        raise NotImplementedError
+
+    def acquire_nowait(self) -> None:
+        """
+        Acquire a token for the current task without waiting for one to become
+        available.
+
+        :raises ~anyio.WouldBlock: if there are no tokens available for borrowing
+
+        """
+        raise NotImplementedError
+
+    def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
+        """
+        Acquire a token without waiting for one to become available.
+
+        :param borrower: the entity borrowing a token
+        :raises ~anyio.WouldBlock: if there are no tokens available for borrowing
+
+        """
+        raise NotImplementedError
+
+    async def acquire(self) -> None:
+        """
+        Acquire a token for the current task, waiting if necessary for one to become
+        available.
+
+        """
+        raise NotImplementedError
+
+    async def acquire_on_behalf_of(self, borrower: object) -> None:
+        """
+        Acquire a token, waiting if necessary for one to become available.
+
+        :param borrower: the entity borrowing a token
+
+        """
+        raise NotImplementedError
+
+    def release(self) -> None:
+        """
+        Release the token held by the current task.
+
+        :raises RuntimeError: if the current task has not borrowed a token from this
+            limiter.
+
+        """
+        raise NotImplementedError
+
+    def release_on_behalf_of(self, borrower: object) -> None:
+        """
+        Release the token held by the given borrower.
+
+        :raises RuntimeError: if the borrower has not borrowed a token from this
+            limiter.
+
+        """
+        raise NotImplementedError
+
+    def statistics(self) -> CapacityLimiterStatistics:
+        """
+        Return statistics about the current state of this limiter.
+
+        .. versionadded:: 3.0
+
+        """
+        raise NotImplementedError
+
+
+class CapacityLimiterAdapter(CapacityLimiter):
+    _internal_limiter: CapacityLimiter | None = None
+
+    def __new__(cls, total_tokens: float) -> CapacityLimiterAdapter:
+        return object.__new__(cls)
+
+    def __init__(self, total_tokens: float) -> None:
+        self.total_tokens = total_tokens
+
+    @property
+    def _limiter(self) -> CapacityLimiter:
+        if self._internal_limiter is None:
+            self._internal_limiter = get_async_backend().create_capacity_limiter(
+                self._total_tokens
+            )
+
+        return self._internal_limiter
+
+    async def __aenter__(self) -> None:
+        await self._limiter.__aenter__()
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        return await self._limiter.__aexit__(exc_type, exc_val, exc_tb)
+
+    @property
+    def total_tokens(self) -> float:
+        if self._internal_limiter is None:
+            return self._total_tokens
+
+        return self._internal_limiter.total_tokens
+
+    @total_tokens.setter
+    def total_tokens(self, value: float) -> None:
+        if not isinstance(value, int) and value is not math.inf:
+            raise TypeError("total_tokens must be an int or math.inf")
+        elif value < 1:
+            raise ValueError("total_tokens must be >= 1")
+
+        if self._internal_limiter is None:
+            self._total_tokens = value
+            return
+
+        self._limiter.total_tokens = value
+
+    @property
+    def borrowed_tokens(self) -> int:
+        if self._internal_limiter is None:
+            return 0
+
+        return self._internal_limiter.borrowed_tokens
+
+    @property
+    def available_tokens(self) -> float:
+        if self._internal_limiter is None:
+            return self._total_tokens
+
+        return self._internal_limiter.available_tokens
+
+    def acquire_nowait(self) -> None:
+        self._limiter.acquire_nowait()
+
+    def acquire_on_behalf_of_nowait(self, borrower: object) -> None:
+        self._limiter.acquire_on_behalf_of_nowait(borrower)
+
+    async def acquire(self) -> None:
+        await self._limiter.acquire()
+
+    async def acquire_on_behalf_of(self, borrower: object) -> None:
+        await self._limiter.acquire_on_behalf_of(borrower)
+
+    def release(self) -> None:
+        self._limiter.release()
+
+    def release_on_behalf_of(self, borrower: object) -> None:
+        self._limiter.release_on_behalf_of(borrower)
+
+    def statistics(self) -> CapacityLimiterStatistics:
+        if self._internal_limiter is None:
+            return CapacityLimiterStatistics(
+                borrowed_tokens=0,
+                total_tokens=self.total_tokens,
+                borrowers=(),
+                tasks_waiting=0,
+            )
+
+        return self._internal_limiter.statistics()
+
+
+class ResourceGuard:
+    """
+    A context manager for ensuring that a resource is only used by a single task at a
+    time.
+
+    Entering this context manager while the previous has not exited it yet will trigger
+    :exc:`BusyResourceError`.
+
+    :param action: the action to guard against (visible in the :exc:`BusyResourceError`
+        when triggered, e.g. "Another task is already {action} this resource")
+
+    .. versionadded:: 4.1
+    """
+
+    __slots__ = "action", "_guarded"
+
+    def __init__(self, action: str = "using"):
+        self.action: str = action
+        self._guarded = False
+
+    def __enter__(self) -> None:
+        if self._guarded:
+            raise BusyResourceError(self.action)
+
+        self._guarded = True
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        self._guarded = False

+ 173 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_tasks.py

@@ -0,0 +1,173 @@
+from __future__ import annotations
+
+import math
+from collections.abc import Generator
+from contextlib import contextmanager
+from types import TracebackType
+
+from ..abc._tasks import TaskGroup, TaskStatus
+from ._eventloop import get_async_backend
+
+
+class _IgnoredTaskStatus(TaskStatus[object]):
+    def started(self, value: object = None) -> None:
+        pass
+
+
+TASK_STATUS_IGNORED = _IgnoredTaskStatus()
+
+
+class CancelScope:
+    """
+    Wraps a unit of work that can be made separately cancellable.
+
+    :param deadline: The time (clock value) when this scope is cancelled automatically
+    :param shield: ``True`` to shield the cancel scope from external cancellation
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+    """
+
+    def __new__(
+        cls, *, deadline: float = math.inf, shield: bool = False
+    ) -> CancelScope:
+        return get_async_backend().create_cancel_scope(shield=shield, deadline=deadline)
+
+    def cancel(self, reason: str | None = None) -> None:
+        """
+        Cancel this scope immediately.
+
+        :param reason: a message describing the reason for the cancellation
+
+        """
+        raise NotImplementedError
+
+    @property
+    def deadline(self) -> float:
+        """
+        The time (clock value) when this scope is cancelled automatically.
+
+        Will be ``float('inf')`` if no timeout has been set.
+
+        """
+        raise NotImplementedError
+
+    @deadline.setter
+    def deadline(self, value: float) -> None:
+        raise NotImplementedError
+
+    @property
+    def cancel_called(self) -> bool:
+        """``True`` if :meth:`cancel` has been called."""
+        raise NotImplementedError
+
+    @property
+    def cancelled_caught(self) -> bool:
+        """
+        ``True`` if this scope suppressed a cancellation exception it itself raised.
+
+        This is typically used to check if any work was interrupted, or to see if the
+        scope was cancelled due to its deadline being reached. The value will, however,
+        only be ``True`` if the cancellation was triggered by the scope itself (and not
+        an outer scope).
+
+        """
+        raise NotImplementedError
+
+    @property
+    def shield(self) -> bool:
+        """
+        ``True`` if this scope is shielded from external cancellation.
+
+        While a scope is shielded, it will not receive cancellations from outside.
+
+        """
+        raise NotImplementedError
+
+    @shield.setter
+    def shield(self, value: bool) -> None:
+        raise NotImplementedError
+
+    def __enter__(self) -> CancelScope:
+        raise NotImplementedError
+
+    def __exit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> bool:
+        raise NotImplementedError
+
+
+@contextmanager
+def fail_after(
+    delay: float | None, shield: bool = False
+) -> Generator[CancelScope, None, None]:
+    """
+    Create a context manager which raises a :class:`TimeoutError` if does not finish in
+    time.
+
+    :param delay: maximum allowed time (in seconds) before raising the exception, or
+        ``None`` to disable the timeout
+    :param shield: ``True`` to shield the cancel scope from external cancellation
+    :return: a context manager that yields a cancel scope
+    :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\]
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    current_time = get_async_backend().current_time
+    deadline = (current_time() + delay) if delay is not None else math.inf
+    with get_async_backend().create_cancel_scope(
+        deadline=deadline, shield=shield
+    ) as cancel_scope:
+        yield cancel_scope
+
+    if cancel_scope.cancelled_caught and current_time() >= cancel_scope.deadline:
+        raise TimeoutError
+
+
+def move_on_after(delay: float | None, shield: bool = False) -> CancelScope:
+    """
+    Create a cancel scope with a deadline that expires after the given delay.
+
+    :param delay: maximum allowed time (in seconds) before exiting the context block, or
+        ``None`` to disable the timeout
+    :param shield: ``True`` to shield the cancel scope from external cancellation
+    :return: a cancel scope
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    deadline = (
+        (get_async_backend().current_time() + delay) if delay is not None else math.inf
+    )
+    return get_async_backend().create_cancel_scope(deadline=deadline, shield=shield)
+
+
+def current_effective_deadline() -> float:
+    """
+    Return the nearest deadline among all the cancel scopes effective for the current
+    task.
+
+    :return: a clock value from the event loop's internal clock (or ``float('inf')`` if
+        there is no deadline in effect, or ``float('-inf')`` if the current scope has
+        been cancelled)
+    :rtype: float
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return get_async_backend().current_effective_deadline()
+
+
+def create_task_group() -> TaskGroup:
+    """
+    Create a task group.
+
+    :return: a task group
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return get_async_backend().create_task_group()

+ 616 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_tempfile.py

@@ -0,0 +1,616 @@
+from __future__ import annotations
+
+import os
+import sys
+import tempfile
+from collections.abc import Iterable
+from io import BytesIO, TextIOWrapper
+from types import TracebackType
+from typing import (
+    TYPE_CHECKING,
+    Any,
+    AnyStr,
+    Generic,
+    overload,
+)
+
+from .. import to_thread
+from .._core._fileio import AsyncFile
+from ..lowlevel import checkpoint_if_cancelled
+
+if TYPE_CHECKING:
+    from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer
+
+
+class TemporaryFile(Generic[AnyStr]):
+    """
+    An asynchronous temporary file that is automatically created and cleaned up.
+
+    This class provides an asynchronous context manager interface to a temporary file.
+    The file is created using Python's standard `tempfile.TemporaryFile` function in a
+    background thread, and is wrapped as an asynchronous file using `AsyncFile`.
+
+    :param mode: The mode in which the file is opened. Defaults to "w+b".
+    :param buffering: The buffering policy (-1 means the default buffering).
+    :param encoding: The encoding used to decode or encode the file. Only applicable in
+        text mode.
+    :param newline: Controls how universal newlines mode works (only applicable in text
+        mode).
+    :param suffix: The suffix for the temporary file name.
+    :param prefix: The prefix for the temporary file name.
+    :param dir: The directory in which the temporary file is created.
+    :param errors: The error handling scheme used for encoding/decoding errors.
+    """
+
+    _async_file: AsyncFile[AnyStr]
+
+    @overload
+    def __init__(
+        self: TemporaryFile[bytes],
+        mode: OpenBinaryMode = ...,
+        buffering: int = ...,
+        encoding: str | None = ...,
+        newline: str | None = ...,
+        suffix: str | None = ...,
+        prefix: str | None = ...,
+        dir: str | None = ...,
+        *,
+        errors: str | None = ...,
+    ): ...
+    @overload
+    def __init__(
+        self: TemporaryFile[str],
+        mode: OpenTextMode,
+        buffering: int = ...,
+        encoding: str | None = ...,
+        newline: str | None = ...,
+        suffix: str | None = ...,
+        prefix: str | None = ...,
+        dir: str | None = ...,
+        *,
+        errors: str | None = ...,
+    ): ...
+
+    def __init__(
+        self,
+        mode: OpenTextMode | OpenBinaryMode = "w+b",
+        buffering: int = -1,
+        encoding: str | None = None,
+        newline: str | None = None,
+        suffix: str | None = None,
+        prefix: str | None = None,
+        dir: str | None = None,
+        *,
+        errors: str | None = None,
+    ) -> None:
+        self.mode = mode
+        self.buffering = buffering
+        self.encoding = encoding
+        self.newline = newline
+        self.suffix: str | None = suffix
+        self.prefix: str | None = prefix
+        self.dir: str | None = dir
+        self.errors = errors
+
+    async def __aenter__(self) -> AsyncFile[AnyStr]:
+        fp = await to_thread.run_sync(
+            lambda: tempfile.TemporaryFile(
+                self.mode,
+                self.buffering,
+                self.encoding,
+                self.newline,
+                self.suffix,
+                self.prefix,
+                self.dir,
+                errors=self.errors,
+            )
+        )
+        self._async_file = AsyncFile(fp)
+        return self._async_file
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_value: BaseException | None,
+        traceback: TracebackType | None,
+    ) -> None:
+        await self._async_file.aclose()
+
+
+class NamedTemporaryFile(Generic[AnyStr]):
+    """
+    An asynchronous named temporary file that is automatically created and cleaned up.
+
+    This class provides an asynchronous context manager for a temporary file with a
+    visible name in the file system. It uses Python's standard
+    :func:`~tempfile.NamedTemporaryFile` function and wraps the file object with
+    :class:`AsyncFile` for asynchronous operations.
+
+    :param mode: The mode in which the file is opened. Defaults to "w+b".
+    :param buffering: The buffering policy (-1 means the default buffering).
+    :param encoding: The encoding used to decode or encode the file. Only applicable in
+        text mode.
+    :param newline: Controls how universal newlines mode works (only applicable in text
+        mode).
+    :param suffix: The suffix for the temporary file name.
+    :param prefix: The prefix for the temporary file name.
+    :param dir: The directory in which the temporary file is created.
+    :param delete: Whether to delete the file when it is closed.
+    :param errors: The error handling scheme used for encoding/decoding errors.
+    :param delete_on_close: (Python 3.12+) Whether to delete the file on close.
+    """
+
+    _async_file: AsyncFile[AnyStr]
+
+    @overload
+    def __init__(
+        self: NamedTemporaryFile[bytes],
+        mode: OpenBinaryMode = ...,
+        buffering: int = ...,
+        encoding: str | None = ...,
+        newline: str | None = ...,
+        suffix: str | None = ...,
+        prefix: str | None = ...,
+        dir: str | None = ...,
+        delete: bool = ...,
+        *,
+        errors: str | None = ...,
+        delete_on_close: bool = ...,
+    ): ...
+    @overload
+    def __init__(
+        self: NamedTemporaryFile[str],
+        mode: OpenTextMode,
+        buffering: int = ...,
+        encoding: str | None = ...,
+        newline: str | None = ...,
+        suffix: str | None = ...,
+        prefix: str | None = ...,
+        dir: str | None = ...,
+        delete: bool = ...,
+        *,
+        errors: str | None = ...,
+        delete_on_close: bool = ...,
+    ): ...
+
+    def __init__(
+        self,
+        mode: OpenBinaryMode | OpenTextMode = "w+b",
+        buffering: int = -1,
+        encoding: str | None = None,
+        newline: str | None = None,
+        suffix: str | None = None,
+        prefix: str | None = None,
+        dir: str | None = None,
+        delete: bool = True,
+        *,
+        errors: str | None = None,
+        delete_on_close: bool = True,
+    ) -> None:
+        self._params: dict[str, Any] = {
+            "mode": mode,
+            "buffering": buffering,
+            "encoding": encoding,
+            "newline": newline,
+            "suffix": suffix,
+            "prefix": prefix,
+            "dir": dir,
+            "delete": delete,
+            "errors": errors,
+        }
+        if sys.version_info >= (3, 12):
+            self._params["delete_on_close"] = delete_on_close
+
+    async def __aenter__(self) -> AsyncFile[AnyStr]:
+        fp = await to_thread.run_sync(
+            lambda: tempfile.NamedTemporaryFile(**self._params)
+        )
+        self._async_file = AsyncFile(fp)
+        return self._async_file
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_value: BaseException | None,
+        traceback: TracebackType | None,
+    ) -> None:
+        await self._async_file.aclose()
+
+
+class SpooledTemporaryFile(AsyncFile[AnyStr]):
+    """
+    An asynchronous spooled temporary file that starts in memory and is spooled to disk.
+
+    This class provides an asynchronous interface to a spooled temporary file, much like
+    Python's standard :class:`~tempfile.SpooledTemporaryFile`. It supports asynchronous
+    write operations and provides a method to force a rollover to disk.
+
+    :param max_size: Maximum size in bytes before the file is rolled over to disk.
+    :param mode: The mode in which the file is opened. Defaults to "w+b".
+    :param buffering: The buffering policy (-1 means the default buffering).
+    :param encoding: The encoding used to decode or encode the file (text mode only).
+    :param newline: Controls how universal newlines mode works (text mode only).
+    :param suffix: The suffix for the temporary file name.
+    :param prefix: The prefix for the temporary file name.
+    :param dir: The directory in which the temporary file is created.
+    :param errors: The error handling scheme used for encoding/decoding errors.
+    """
+
+    _rolled: bool = False
+
+    @overload
+    def __init__(
+        self: SpooledTemporaryFile[bytes],
+        max_size: int = ...,
+        mode: OpenBinaryMode = ...,
+        buffering: int = ...,
+        encoding: str | None = ...,
+        newline: str | None = ...,
+        suffix: str | None = ...,
+        prefix: str | None = ...,
+        dir: str | None = ...,
+        *,
+        errors: str | None = ...,
+    ): ...
+    @overload
+    def __init__(
+        self: SpooledTemporaryFile[str],
+        max_size: int = ...,
+        mode: OpenTextMode = ...,
+        buffering: int = ...,
+        encoding: str | None = ...,
+        newline: str | None = ...,
+        suffix: str | None = ...,
+        prefix: str | None = ...,
+        dir: str | None = ...,
+        *,
+        errors: str | None = ...,
+    ): ...
+
+    def __init__(
+        self,
+        max_size: int = 0,
+        mode: OpenBinaryMode | OpenTextMode = "w+b",
+        buffering: int = -1,
+        encoding: str | None = None,
+        newline: str | None = None,
+        suffix: str | None = None,
+        prefix: str | None = None,
+        dir: str | None = None,
+        *,
+        errors: str | None = None,
+    ) -> None:
+        self._tempfile_params: dict[str, Any] = {
+            "mode": mode,
+            "buffering": buffering,
+            "encoding": encoding,
+            "newline": newline,
+            "suffix": suffix,
+            "prefix": prefix,
+            "dir": dir,
+            "errors": errors,
+        }
+        self._max_size = max_size
+        if "b" in mode:
+            super().__init__(BytesIO())  # type: ignore[arg-type]
+        else:
+            super().__init__(
+                TextIOWrapper(  # type: ignore[arg-type]
+                    BytesIO(),
+                    encoding=encoding,
+                    errors=errors,
+                    newline=newline,
+                    write_through=True,
+                )
+            )
+
+    async def aclose(self) -> None:
+        if not self._rolled:
+            self._fp.close()
+            return
+
+        await super().aclose()
+
+    async def _check(self) -> None:
+        if self._rolled or self._fp.tell() <= self._max_size:
+            return
+
+        await self.rollover()
+
+    async def rollover(self) -> None:
+        if self._rolled:
+            return
+
+        self._rolled = True
+        buffer = self._fp
+        buffer.seek(0)
+        self._fp = await to_thread.run_sync(
+            lambda: tempfile.TemporaryFile(**self._tempfile_params)
+        )
+        await self.write(buffer.read())
+        buffer.close()
+
+    @property
+    def closed(self) -> bool:
+        return self._fp.closed
+
+    async def read(self, size: int = -1) -> AnyStr:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            return self._fp.read(size)
+
+        return await super().read(size)  # type: ignore[return-value]
+
+    async def read1(self: SpooledTemporaryFile[bytes], size: int = -1) -> bytes:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            return self._fp.read1(size)
+
+        return await super().read1(size)
+
+    async def readline(self) -> AnyStr:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            return self._fp.readline()
+
+        return await super().readline()  # type: ignore[return-value]
+
+    async def readlines(self) -> list[AnyStr]:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            return self._fp.readlines()
+
+        return await super().readlines()  # type: ignore[return-value]
+
+    async def readinto(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            self._fp.readinto(b)
+
+        return await super().readinto(b)
+
+    async def readinto1(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            self._fp.readinto(b)
+
+        return await super().readinto1(b)
+
+    async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            return self._fp.seek(offset, whence)
+
+        return await super().seek(offset, whence)
+
+    async def tell(self) -> int:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            return self._fp.tell()
+
+        return await super().tell()
+
+    async def truncate(self, size: int | None = None) -> int:
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            return self._fp.truncate(size)
+
+        return await super().truncate(size)
+
+    @overload
+    async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ...
+    @overload
+    async def write(self: SpooledTemporaryFile[str], b: str) -> int: ...
+
+    async def write(self, b: ReadableBuffer | str) -> int:
+        """
+        Asynchronously write data to the spooled temporary file.
+
+        If the file has not yet been rolled over, the data is written synchronously,
+        and a rollover is triggered if the size exceeds the maximum size.
+
+        :param s: The data to write.
+        :return: The number of bytes written.
+        :raises RuntimeError: If the underlying file is not initialized.
+
+        """
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            result = self._fp.write(b)
+            await self._check()
+            return result
+
+        return await super().write(b)  # type: ignore[misc]
+
+    @overload
+    async def writelines(
+        self: SpooledTemporaryFile[bytes], lines: Iterable[ReadableBuffer]
+    ) -> None: ...
+    @overload
+    async def writelines(
+        self: SpooledTemporaryFile[str], lines: Iterable[str]
+    ) -> None: ...
+
+    async def writelines(self, lines: Iterable[str] | Iterable[ReadableBuffer]) -> None:
+        """
+        Asynchronously write a list of lines to the spooled temporary file.
+
+        If the file has not yet been rolled over, the lines are written synchronously,
+        and a rollover is triggered if the size exceeds the maximum size.
+
+        :param lines: An iterable of lines to write.
+        :raises RuntimeError: If the underlying file is not initialized.
+
+        """
+        if not self._rolled:
+            await checkpoint_if_cancelled()
+            result = self._fp.writelines(lines)
+            await self._check()
+            return result
+
+        return await super().writelines(lines)  # type: ignore[misc]
+
+
+class TemporaryDirectory(Generic[AnyStr]):
+    """
+    An asynchronous temporary directory that is created and cleaned up automatically.
+
+    This class provides an asynchronous context manager for creating a temporary
+    directory. It wraps Python's standard :class:`~tempfile.TemporaryDirectory` to
+    perform directory creation and cleanup operations in a background thread.
+
+    :param suffix: Suffix to be added to the temporary directory name.
+    :param prefix: Prefix to be added to the temporary directory name.
+    :param dir: The parent directory where the temporary directory is created.
+    :param ignore_cleanup_errors: Whether to ignore errors during cleanup
+        (Python 3.10+).
+    :param delete: Whether to delete the directory upon closing (Python 3.12+).
+    """
+
+    def __init__(
+        self,
+        suffix: AnyStr | None = None,
+        prefix: AnyStr | None = None,
+        dir: AnyStr | None = None,
+        *,
+        ignore_cleanup_errors: bool = False,
+        delete: bool = True,
+    ) -> None:
+        self.suffix: AnyStr | None = suffix
+        self.prefix: AnyStr | None = prefix
+        self.dir: AnyStr | None = dir
+        self.ignore_cleanup_errors = ignore_cleanup_errors
+        self.delete = delete
+
+        self._tempdir: tempfile.TemporaryDirectory | None = None
+
+    async def __aenter__(self) -> str:
+        params: dict[str, Any] = {
+            "suffix": self.suffix,
+            "prefix": self.prefix,
+            "dir": self.dir,
+        }
+        if sys.version_info >= (3, 10):
+            params["ignore_cleanup_errors"] = self.ignore_cleanup_errors
+
+        if sys.version_info >= (3, 12):
+            params["delete"] = self.delete
+
+        self._tempdir = await to_thread.run_sync(
+            lambda: tempfile.TemporaryDirectory(**params)
+        )
+        return await to_thread.run_sync(self._tempdir.__enter__)
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_value: BaseException | None,
+        traceback: TracebackType | None,
+    ) -> None:
+        if self._tempdir is not None:
+            await to_thread.run_sync(
+                self._tempdir.__exit__, exc_type, exc_value, traceback
+            )
+
+    async def cleanup(self) -> None:
+        if self._tempdir is not None:
+            await to_thread.run_sync(self._tempdir.cleanup)
+
+
+@overload
+async def mkstemp(
+    suffix: str | None = None,
+    prefix: str | None = None,
+    dir: str | None = None,
+    text: bool = False,
+) -> tuple[int, str]: ...
+
+
+@overload
+async def mkstemp(
+    suffix: bytes | None = None,
+    prefix: bytes | None = None,
+    dir: bytes | None = None,
+    text: bool = False,
+) -> tuple[int, bytes]: ...
+
+
+async def mkstemp(
+    suffix: AnyStr | None = None,
+    prefix: AnyStr | None = None,
+    dir: AnyStr | None = None,
+    text: bool = False,
+) -> tuple[int, str | bytes]:
+    """
+    Asynchronously create a temporary file and return an OS-level handle and the file
+    name.
+
+    This function wraps `tempfile.mkstemp` and executes it in a background thread.
+
+    :param suffix: Suffix to be added to the file name.
+    :param prefix: Prefix to be added to the file name.
+    :param dir: Directory in which the temporary file is created.
+    :param text: Whether the file is opened in text mode.
+    :return: A tuple containing the file descriptor and the file name.
+
+    """
+    return await to_thread.run_sync(tempfile.mkstemp, suffix, prefix, dir, text)
+
+
+@overload
+async def mkdtemp(
+    suffix: str | None = None,
+    prefix: str | None = None,
+    dir: str | None = None,
+) -> str: ...
+
+
+@overload
+async def mkdtemp(
+    suffix: bytes | None = None,
+    prefix: bytes | None = None,
+    dir: bytes | None = None,
+) -> bytes: ...
+
+
+async def mkdtemp(
+    suffix: AnyStr | None = None,
+    prefix: AnyStr | None = None,
+    dir: AnyStr | None = None,
+) -> str | bytes:
+    """
+    Asynchronously create a temporary directory and return its path.
+
+    This function wraps `tempfile.mkdtemp` and executes it in a background thread.
+
+    :param suffix: Suffix to be added to the directory name.
+    :param prefix: Prefix to be added to the directory name.
+    :param dir: Parent directory where the temporary directory is created.
+    :return: The path of the created temporary directory.
+
+    """
+    return await to_thread.run_sync(tempfile.mkdtemp, suffix, prefix, dir)
+
+
+async def gettempdir() -> str:
+    """
+    Asynchronously return the name of the directory used for temporary files.
+
+    This function wraps `tempfile.gettempdir` and executes it in a background thread.
+
+    :return: The path of the temporary directory as a string.
+
+    """
+    return await to_thread.run_sync(tempfile.gettempdir)
+
+
+async def gettempdirb() -> bytes:
+    """
+    Asynchronously return the name of the directory used for temporary files in bytes.
+
+    This function wraps `tempfile.gettempdirb` and executes it in a background thread.
+
+    :return: The path of the temporary directory as bytes.
+
+    """
+    return await to_thread.run_sync(tempfile.gettempdirb)

+ 82 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_testing.py

@@ -0,0 +1,82 @@
+from __future__ import annotations
+
+from collections.abc import Awaitable, Generator
+from typing import Any, cast
+
+from ._eventloop import get_async_backend
+
+
+class TaskInfo:
+    """
+    Represents an asynchronous task.
+
+    :ivar int id: the unique identifier of the task
+    :ivar parent_id: the identifier of the parent task, if any
+    :vartype parent_id: Optional[int]
+    :ivar str name: the description of the task (if any)
+    :ivar ~collections.abc.Coroutine coro: the coroutine object of the task
+    """
+
+    __slots__ = "_name", "id", "parent_id", "name", "coro"
+
+    def __init__(
+        self,
+        id: int,
+        parent_id: int | None,
+        name: str | None,
+        coro: Generator[Any, Any, Any] | Awaitable[Any],
+    ):
+        func = get_current_task
+        self._name = f"{func.__module__}.{func.__qualname__}"
+        self.id: int = id
+        self.parent_id: int | None = parent_id
+        self.name: str | None = name
+        self.coro: Generator[Any, Any, Any] | Awaitable[Any] = coro
+
+    def __eq__(self, other: object) -> bool:
+        if isinstance(other, TaskInfo):
+            return self.id == other.id
+
+        return NotImplemented
+
+    def __hash__(self) -> int:
+        return hash(self.id)
+
+    def __repr__(self) -> str:
+        return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})"
+
+    def has_pending_cancellation(self) -> bool:
+        """
+        Return ``True`` if the task has a cancellation pending, ``False`` otherwise.
+
+        """
+        return False
+
+
+def get_current_task() -> TaskInfo:
+    """
+    Return the current task.
+
+    :return: a representation of the current task
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return get_async_backend().get_current_task()
+
+
+def get_running_tasks() -> list[TaskInfo]:
+    """
+    Return a list of running tasks in the current event loop.
+
+    :return: a list of task info objects
+    :raises NoEventLoopError: if no supported asynchronous event loop is running in the
+        current thread
+
+    """
+    return cast("list[TaskInfo]", get_async_backend().get_running_tasks())
+
+
+async def wait_all_tasks_blocked() -> None:
+    """Wait until all other tasks are waiting for something."""
+    await get_async_backend().wait_all_tasks_blocked()

+ 81 - 0
.venv/lib/python3.9/site-packages/anyio/_core/_typedattr.py

@@ -0,0 +1,81 @@
+from __future__ import annotations
+
+from collections.abc import Callable, Mapping
+from typing import Any, TypeVar, final, overload
+
+from ._exceptions import TypedAttributeLookupError
+
+T_Attr = TypeVar("T_Attr")
+T_Default = TypeVar("T_Default")
+undefined = object()
+
+
+def typed_attribute() -> Any:
+    """Return a unique object, used to mark typed attributes."""
+    return object()
+
+
+class TypedAttributeSet:
+    """
+    Superclass for typed attribute collections.
+
+    Checks that every public attribute of every subclass has a type annotation.
+    """
+
+    def __init_subclass__(cls) -> None:
+        annotations: dict[str, Any] = getattr(cls, "__annotations__", {})
+        for attrname in dir(cls):
+            if not attrname.startswith("_") and attrname not in annotations:
+                raise TypeError(
+                    f"Attribute {attrname!r} is missing its type annotation"
+                )
+
+        super().__init_subclass__()
+
+
+class TypedAttributeProvider:
+    """Base class for classes that wish to provide typed extra attributes."""
+
+    @property
+    def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]:
+        """
+        A mapping of the extra attributes to callables that return the corresponding
+        values.
+
+        If the provider wraps another provider, the attributes from that wrapper should
+        also be included in the returned mapping (but the wrapper may override the
+        callables from the wrapped instance).
+
+        """
+        return {}
+
+    @overload
+    def extra(self, attribute: T_Attr) -> T_Attr: ...
+
+    @overload
+    def extra(self, attribute: T_Attr, default: T_Default) -> T_Attr | T_Default: ...
+
+    @final
+    def extra(self, attribute: Any, default: object = undefined) -> object:
+        """
+        extra(attribute, default=undefined)
+
+        Return the value of the given typed extra attribute.
+
+        :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to
+            look for
+        :param default: the value that should be returned if no value is found for the
+            attribute
+        :raises ~anyio.TypedAttributeLookupError: if the search failed and no default
+            value was given
+
+        """
+        try:
+            getter = self.extra_attributes[attribute]
+        except KeyError:
+            if default is undefined:
+                raise TypedAttributeLookupError("Attribute not found") from None
+            else:
+                return default
+
+        return getter()

+ 58 - 0
.venv/lib/python3.9/site-packages/anyio/abc/__init__.py

@@ -0,0 +1,58 @@
+from __future__ import annotations
+
+from ._eventloop import AsyncBackend as AsyncBackend
+from ._resources import AsyncResource as AsyncResource
+from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket
+from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket
+from ._sockets import IPAddressType as IPAddressType
+from ._sockets import IPSockAddrType as IPSockAddrType
+from ._sockets import SocketAttribute as SocketAttribute
+from ._sockets import SocketListener as SocketListener
+from ._sockets import SocketStream as SocketStream
+from ._sockets import UDPPacketType as UDPPacketType
+from ._sockets import UDPSocket as UDPSocket
+from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType
+from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket
+from ._sockets import UNIXSocketStream as UNIXSocketStream
+from ._streams import AnyByteReceiveStream as AnyByteReceiveStream
+from ._streams import AnyByteSendStream as AnyByteSendStream
+from ._streams import AnyByteStream as AnyByteStream
+from ._streams import AnyByteStreamConnectable as AnyByteStreamConnectable
+from ._streams import AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream
+from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream
+from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream
+from ._streams import ByteReceiveStream as ByteReceiveStream
+from ._streams import ByteSendStream as ByteSendStream
+from ._streams import ByteStream as ByteStream
+from ._streams import ByteStreamConnectable as ByteStreamConnectable
+from ._streams import Listener as Listener
+from ._streams import ObjectReceiveStream as ObjectReceiveStream
+from ._streams import ObjectSendStream as ObjectSendStream
+from ._streams import ObjectStream as ObjectStream
+from ._streams import ObjectStreamConnectable as ObjectStreamConnectable
+from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream
+from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream
+from ._streams import UnreliableObjectStream as UnreliableObjectStream
+from ._subprocesses import Process as Process
+from ._tasks import TaskGroup as TaskGroup
+from ._tasks import TaskStatus as TaskStatus
+from ._testing import TestRunner as TestRunner
+
+# Re-exported here, for backwards compatibility
+# isort: off
+from .._core._synchronization import (
+    CapacityLimiter as CapacityLimiter,
+    Condition as Condition,
+    Event as Event,
+    Lock as Lock,
+    Semaphore as Semaphore,
+)
+from .._core._tasks import CancelScope as CancelScope
+from ..from_thread import BlockingPortal as BlockingPortal
+
+# Re-export imports so they look like they live directly in this package
+for __value in list(locals().values()):
+    if getattr(__value, "__module__", "").startswith("anyio.abc."):
+        __value.__module__ = __name__
+
+del __value

+ 414 - 0
.venv/lib/python3.9/site-packages/anyio/abc/_eventloop.py

@@ -0,0 +1,414 @@
+from __future__ import annotations
+
+import math
+import sys
+from abc import ABCMeta, abstractmethod
+from collections.abc import AsyncIterator, Awaitable, Callable, Sequence
+from contextlib import AbstractContextManager
+from os import PathLike
+from signal import Signals
+from socket import AddressFamily, SocketKind, socket
+from typing import (
+    IO,
+    TYPE_CHECKING,
+    Any,
+    TypeVar,
+    Union,
+    overload,
+)
+
+if sys.version_info >= (3, 11):
+    from typing import TypeVarTuple, Unpack
+else:
+    from typing_extensions import TypeVarTuple, Unpack
+
+if sys.version_info >= (3, 10):
+    from typing import TypeAlias
+else:
+    from typing_extensions import TypeAlias
+
+if TYPE_CHECKING:
+    from _typeshed import FileDescriptorLike
+
+    from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore
+    from .._core._tasks import CancelScope
+    from .._core._testing import TaskInfo
+    from ._sockets import (
+        ConnectedUDPSocket,
+        ConnectedUNIXDatagramSocket,
+        IPSockAddrType,
+        SocketListener,
+        SocketStream,
+        UDPSocket,
+        UNIXDatagramSocket,
+        UNIXSocketStream,
+    )
+    from ._subprocesses import Process
+    from ._tasks import TaskGroup
+    from ._testing import TestRunner
+
+T_Retval = TypeVar("T_Retval")
+PosArgsT = TypeVarTuple("PosArgsT")
+StrOrBytesPath: TypeAlias = Union[str, bytes, "PathLike[str]", "PathLike[bytes]"]
+
+
+class AsyncBackend(metaclass=ABCMeta):
+    @classmethod
+    @abstractmethod
+    def run(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+        args: tuple[Unpack[PosArgsT]],
+        kwargs: dict[str, Any],
+        options: dict[str, Any],
+    ) -> T_Retval:
+        """
+        Run the given coroutine function in an asynchronous event loop.
+
+        The current thread must not be already running an event loop.
+
+        :param func: a coroutine function
+        :param args: positional arguments to ``func``
+        :param kwargs: positional arguments to ``func``
+        :param options: keyword arguments to call the backend ``run()`` implementation
+            with
+        :return: the return value of the coroutine function
+        """
+
+    @classmethod
+    @abstractmethod
+    def current_token(cls) -> object:
+        """
+        Return an object that allows other threads to run code inside the event loop.
+
+        :return: a token object, specific to the event loop running in the current
+            thread
+        """
+
+    @classmethod
+    @abstractmethod
+    def current_time(cls) -> float:
+        """
+        Return the current value of the event loop's internal clock.
+
+        :return: the clock value (seconds)
+        """
+
+    @classmethod
+    @abstractmethod
+    def cancelled_exception_class(cls) -> type[BaseException]:
+        """Return the exception class that is raised in a task if it's cancelled."""
+
+    @classmethod
+    @abstractmethod
+    async def checkpoint(cls) -> None:
+        """
+        Check if the task has been cancelled, and allow rescheduling of other tasks.
+
+        This is effectively the same as running :meth:`checkpoint_if_cancelled` and then
+        :meth:`cancel_shielded_checkpoint`.
+        """
+
+    @classmethod
+    async def checkpoint_if_cancelled(cls) -> None:
+        """
+        Check if the current task group has been cancelled.
+
+        This will check if the task has been cancelled, but will not allow other tasks
+        to be scheduled if not.
+
+        """
+        if cls.current_effective_deadline() == -math.inf:
+            await cls.checkpoint()
+
+    @classmethod
+    async def cancel_shielded_checkpoint(cls) -> None:
+        """
+        Allow the rescheduling of other tasks.
+
+        This will give other tasks the opportunity to run, but without checking if the
+        current task group has been cancelled, unlike with :meth:`checkpoint`.
+
+        """
+        with cls.create_cancel_scope(shield=True):
+            await cls.sleep(0)
+
+    @classmethod
+    @abstractmethod
+    async def sleep(cls, delay: float) -> None:
+        """
+        Pause the current task for the specified duration.
+
+        :param delay: the duration, in seconds
+        """
+
+    @classmethod
+    @abstractmethod
+    def create_cancel_scope(
+        cls, *, deadline: float = math.inf, shield: bool = False
+    ) -> CancelScope:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def current_effective_deadline(cls) -> float:
+        """
+        Return the nearest deadline among all the cancel scopes effective for the
+        current task.
+
+        :return:
+            - a clock value from the event loop's internal clock
+            - ``inf`` if there is no deadline in effect
+            - ``-inf`` if the current scope has been cancelled
+        :rtype: float
+        """
+
+    @classmethod
+    @abstractmethod
+    def create_task_group(cls) -> TaskGroup:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_event(cls) -> Event:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_lock(cls, *, fast_acquire: bool) -> Lock:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_semaphore(
+        cls,
+        initial_value: int,
+        *,
+        max_value: int | None = None,
+        fast_acquire: bool = False,
+    ) -> Semaphore:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def run_sync_in_worker_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], T_Retval],
+        args: tuple[Unpack[PosArgsT]],
+        abandon_on_cancel: bool = False,
+        limiter: CapacityLimiter | None = None,
+    ) -> T_Retval:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def check_cancelled(cls) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def run_async_from_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
+        args: tuple[Unpack[PosArgsT]],
+        token: object,
+    ) -> T_Retval:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def run_sync_from_thread(
+        cls,
+        func: Callable[[Unpack[PosArgsT]], T_Retval],
+        args: tuple[Unpack[PosArgsT]],
+        token: object,
+    ) -> T_Retval:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def open_process(
+        cls,
+        command: StrOrBytesPath | Sequence[StrOrBytesPath],
+        *,
+        stdin: int | IO[Any] | None,
+        stdout: int | IO[Any] | None,
+        stderr: int | IO[Any] | None,
+        **kwargs: Any,
+    ) -> Process:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def connect_tcp(
+        cls, host: str, port: int, local_address: IPSockAddrType | None = None
+    ) -> SocketStream:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_tcp_listener(cls, sock: socket) -> SocketListener:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_unix_listener(cls, sock: socket) -> SocketListener:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def create_udp_socket(
+        cls,
+        family: AddressFamily,
+        local_address: IPSockAddrType | None,
+        remote_address: IPSockAddrType | None,
+        reuse_port: bool,
+    ) -> UDPSocket | ConnectedUDPSocket:
+        pass
+
+    @classmethod
+    @overload
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket, remote_path: None
+    ) -> UNIXDatagramSocket: ...
+
+    @classmethod
+    @overload
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket, remote_path: str | bytes
+    ) -> ConnectedUNIXDatagramSocket: ...
+
+    @classmethod
+    @abstractmethod
+    async def create_unix_datagram_socket(
+        cls, raw_socket: socket, remote_path: str | bytes | None
+    ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def getaddrinfo(
+        cls,
+        host: bytes | str | None,
+        port: str | int | None,
+        *,
+        family: int | AddressFamily = 0,
+        type: int | SocketKind = 0,
+        proto: int = 0,
+        flags: int = 0,
+    ) -> Sequence[
+        tuple[
+            AddressFamily,
+            SocketKind,
+            int,
+            str,
+            tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes],
+        ]
+    ]:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def getnameinfo(
+        cls, sockaddr: IPSockAddrType, flags: int = 0
+    ) -> tuple[str, str]:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wait_readable(cls, obj: FileDescriptorLike) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wait_writable(cls, obj: FileDescriptorLike) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def notify_closing(cls, obj: FileDescriptorLike) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wrap_listener_socket(cls, sock: socket) -> SocketListener:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wrap_stream_socket(cls, sock: socket) -> SocketStream:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wrap_unix_stream_socket(cls, sock: socket) -> UNIXSocketStream:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wrap_udp_socket(cls, sock: socket) -> UDPSocket:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wrap_connected_udp_socket(cls, sock: socket) -> ConnectedUDPSocket:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wrap_unix_datagram_socket(cls, sock: socket) -> UNIXDatagramSocket:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wrap_connected_unix_datagram_socket(
+        cls, sock: socket
+    ) -> ConnectedUNIXDatagramSocket:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def current_default_thread_limiter(cls) -> CapacityLimiter:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def open_signal_receiver(
+        cls, *signals: Signals
+    ) -> AbstractContextManager[AsyncIterator[Signals]]:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def get_current_task(cls) -> TaskInfo:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def get_running_tasks(cls) -> Sequence[TaskInfo]:
+        pass
+
+    @classmethod
+    @abstractmethod
+    async def wait_all_tasks_blocked(cls) -> None:
+        pass
+
+    @classmethod
+    @abstractmethod
+    def create_test_runner(cls, options: dict[str, Any]) -> TestRunner:
+        pass

+ 33 - 0
.venv/lib/python3.9/site-packages/anyio/abc/_resources.py

@@ -0,0 +1,33 @@
+from __future__ import annotations
+
+from abc import ABCMeta, abstractmethod
+from types import TracebackType
+from typing import TypeVar
+
+T = TypeVar("T")
+
+
+class AsyncResource(metaclass=ABCMeta):
+    """
+    Abstract base class for all closeable asynchronous resources.
+
+    Works as an asynchronous context manager which returns the instance itself on enter,
+    and calls :meth:`aclose` on exit.
+    """
+
+    __slots__ = ()
+
+    async def __aenter__(self: T) -> T:
+        return self
+
+    async def __aexit__(
+        self,
+        exc_type: type[BaseException] | None,
+        exc_val: BaseException | None,
+        exc_tb: TracebackType | None,
+    ) -> None:
+        await self.aclose()
+
+    @abstractmethod
+    async def aclose(self) -> None:
+        """Close the resource."""

Some files were not shown because too many files changed in this diff