aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-10-28 19:04:04 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-10-28 19:13:08 +0300
commit556acf22e5b9e62e6806d9f84b88885f0028553d (patch)
tree9ff7b45fa733ecbf03b0a418737d64710f089ce8
parent6fa678ce43d0d76bb4fc164199021ae53b097b8f (diff)
downloadydb-556acf22e5b9e62e6806d9f84b88885f0028553d.tar.gz
Intermediate changes
commit_hash:7f456b0de6f7825696f8277ce8c49657004dce2a
-rw-r--r--build/mapping.conf.json6
-rw-r--r--contrib/python/anyio/.dist-info/METADATA6
-rw-r--r--contrib/python/anyio/anyio/_backends/_asyncio.py233
-rw-r--r--contrib/python/anyio/anyio/_backends/_trio.py39
-rw-r--r--contrib/python/anyio/anyio/_core/_fileio.py29
-rw-r--r--contrib/python/anyio/anyio/_core/_signals.py6
-rw-r--r--contrib/python/anyio/anyio/_core/_streams.py4
-rw-r--r--contrib/python/anyio/anyio/_core/_subprocesses.py21
-rw-r--r--contrib/python/anyio/anyio/abc/_eventloop.py8
-rw-r--r--contrib/python/anyio/anyio/abc/_sockets.py8
-rw-r--r--contrib/python/anyio/anyio/from_thread.py16
-rw-r--r--contrib/python/anyio/anyio/pytest_plugin.py51
-rw-r--r--contrib/python/anyio/anyio/streams/tls.py11
-rw-r--r--contrib/python/anyio/ya.make2
14 files changed, 239 insertions, 201 deletions
diff --git a/build/mapping.conf.json b/build/mapping.conf.json
index 2f050bf559..da06c1f807 100644
--- a/build/mapping.conf.json
+++ b/build/mapping.conf.json
@@ -848,8 +848,11 @@
"6990868751": "https://devtools-registry.s3.yandex.net/6990868751",
"6990860705": "https://devtools-registry.s3.yandex.net/6990860705",
"6990881789": "https://devtools-registry.s3.yandex.net/6990881789",
+ "7324461836": "https://devtools-registry.s3.yandex.net/7324461836",
"7193803465": "https://devtools-registry.s3.yandex.net/7193803465",
+ "7324464594": "https://devtools-registry.s3.yandex.net/7324464594",
"7193800506": "https://devtools-registry.s3.yandex.net/7193800506",
+ "7324461714": "https://devtools-registry.s3.yandex.net/7324461714",
"7193813071": "https://devtools-registry.s3.yandex.net/7193813071",
"3167009386": "https://devtools-registry.s3.yandex.net/3167009386",
"3050798466": "https://devtools-registry.s3.yandex.net/3050798466",
@@ -1804,8 +1807,11 @@
"6990868751": "none-none-none-sandbox/backup/3527d100-e2d0-4b0e-bb7a-905010853d98/yfm-docs.tar",
"6990860705": "none-none-none-sandbox/backup/d386643e-58f8-43e1-8760-341d73801df8/yfm-docs.tar",
"6990881789": "none-none-none-sandbox/backup/efc428e5-52a5-4a6f-8f0c-53f1d255efea/yfm-docs.tar",
+ "7324461836": "none-none-none-service_resources/TASKLET_EXECUTABLE/backup/0541e185-8261-4b07-9149-257f03a9c8ae/yfm-docs.tar",
"7193803465": "none-none-none-service_resources/TASKLET_EXECUTABLE/backup/17df2ad2-24bc-49e8-8909-b58685dac393/yfm-docs.tar",
+ "7324464594": "none-none-none-service_resources/TASKLET_EXECUTABLE/backup/32cc8c74-decd-44a8-bc8c-f8f0d7edfffe/yfm-docs.tar",
"7193800506": "none-none-none-service_resources/TASKLET_EXECUTABLE/backup/9be8ed55-d7f8-4029-a7fd-fbfa072b896f/yfm-docs.tar",
+ "7324461714": "none-none-none-service_resources/TASKLET_EXECUTABLE/backup/b3543418-58d4-4e1c-b2be-43b55b035e91/yfm-docs.tar",
"7193813071": "none-none-none-service_resources/TASKLET_EXECUTABLE/backup/b6531a79-b803-4672-a9e9-f9f348009f5f/yfm-docs.tar",
"3167009386": "openjdk 11.0.15 vanilla for darwin",
"3050798466": "openjdk 11.0.15 vanilla for darwin-arm64",
diff --git a/contrib/python/anyio/.dist-info/METADATA b/contrib/python/anyio/.dist-info/METADATA
index 747e994c6b..e28bbd52d0 100644
--- a/contrib/python/anyio/.dist-info/METADATA
+++ b/contrib/python/anyio/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: anyio
-Version: 4.6.0
+Version: 4.6.2
Summary: High level compatibility layer for multiple asynchronous event loop implementations
Author-email: Alex Grönholm <alex.gronholm@nextday.fi>
License: MIT
@@ -15,12 +15,13 @@ Classifier: Framework :: AnyIO
Classifier: Typing :: Typed
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
+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: Programming Language :: Python :: 3.13
-Requires-Python: >=3.9
+Requires-Python: >=3.8
Description-Content-Type: text/x-rst
License-File: LICENSE
Requires-Dist: idna >=2.8
@@ -42,6 +43,7 @@ Requires-Dist: pytest >=7.0 ; extra == 'test'
Requires-Dist: pytest-mock >=3.6.1 ; extra == 'test'
Requires-Dist: trustme ; extra == 'test'
Requires-Dist: uvloop >=0.21.0b1 ; (platform_python_implementation == "CPython" and platform_system != "Windows") and extra == 'test'
+Requires-Dist: truststore >=0.9.1 ; (python_version >= "3.10") and extra == 'test'
Provides-Extra: trio
Requires-Dist: trio >=0.26.1 ; extra == 'trio'
diff --git a/contrib/python/anyio/anyio/_backends/_asyncio.py b/contrib/python/anyio/anyio/_backends/_asyncio.py
index 9342fab818..fa5349a8c2 100644
--- a/contrib/python/anyio/anyio/_backends/_asyncio.py
+++ b/contrib/python/anyio/anyio/_backends/_asyncio.py
@@ -20,18 +20,9 @@ from asyncio import (
)
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 collections.abc import AsyncIterator, Iterable
from concurrent.futures import Future
-from contextlib import AbstractContextManager, suppress
+from contextlib import suppress
from contextvars import Context, copy_context
from dataclasses import dataclass
from functools import partial, wraps
@@ -51,7 +42,15 @@ from types import TracebackType
from typing import (
IO,
Any,
+ AsyncGenerator,
+ Awaitable,
+ Callable,
+ Collection,
+ ContextManager,
+ Coroutine,
Optional,
+ Sequence,
+ Tuple,
TypeVar,
cast,
)
@@ -359,14 +358,6 @@ def _task_started(task: asyncio.Task) -> bool:
#
-def is_anyio_cancellation(exc: CancelledError) -> bool:
- return (
- bool(exc.args)
- and isinstance(exc.args[0], str)
- and exc.args[0].startswith("Cancelled by cancel scope ")
- )
-
-
class CancelScope(BaseCancelScope):
def __new__(
cls, *, deadline: float = math.inf, shield: bool = False
@@ -453,77 +444,35 @@ class CancelScope(BaseCancelScope):
host_task_state.cancel_scope = self._parent_scope
- # Undo all cancellations done by this scope
- if self._cancelling is not None:
- while self._cancel_calls:
- self._cancel_calls -= 1
- if self._host_task.uncancel() <= self._cancelling:
- break
-
- # 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
- not_swallowed_exceptions = 0
- swallow_exception = False
- if exc_val is not None:
- for exc in iterate_exceptions(exc_val):
- if self._cancel_called and isinstance(exc, CancelledError):
- if not (swallow_exception := self._uncancel(exc)):
- not_swallowed_exceptions += 1
- else:
- not_swallowed_exceptions += 1
-
- # Restart the cancellation effort in the closest visible, cancelled parent
- # scope if necessary
+ # Restart the cancellation effort in the closest directly cancelled parent
+ # scope if this one was shielded
self._restart_cancellation_in_parent()
- return swallow_exception and not not_swallowed_exceptions
- @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
+ if self._cancel_called and exc_val is not None:
+ for exc in iterate_exceptions(exc_val):
+ if isinstance(exc, CancelledError):
+ self._cancelled_caught = self._uncancel(exc)
+ if self._cancelled_caught:
+ break
- return False
+ return self._cancelled_caught
- @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
- )
+ return None
def _uncancel(self, cancelled_exc: CancelledError) -> bool:
- if self._host_task is None:
+ if sys.version_info < (3, 9) or self._host_task is None:
self._cancel_calls = 0
return True
- while True:
- if is_anyio_cancellation(cancelled_exc):
- # Only swallow the cancellation exception if it's an AnyIO cancel
- # exception and there are no other cancel scopes down the line pending
- # cancellation
- self._cancelled_caught = (
- self._effectively_cancelled
- and not self._parent_cancellation_is_visible_to_us
- )
- return self._cancelled_caught
-
- # 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
- if isinstance(cancelled_exc.__context__, CancelledError):
- cancelled_exc = cancelled_exc.__context__
- continue
+ # Undo all cancellations done by this scope
+ if self._cancelling is not None:
+ while self._cancel_calls:
+ self._cancel_calls -= 1
+ if self._host_task.uncancel() <= self._cancelling:
+ return True
- return False
+ self._cancel_calls = 0
+ return f"Cancelled by cancel scope {id(self):x}" in cancelled_exc.args
def _timeout(self) -> None:
if self._deadline != math.inf:
@@ -547,17 +496,19 @@ class CancelScope(BaseCancelScope):
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
+ should_retry = True
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(f"Cancelled by cancel scope {id(origin):x}")
- if task is origin._host_task:
- origin._cancel_calls += 1
+ origin._cancel_calls += 1
+ if sys.version_info >= (3, 9):
+ task.cancel(f"Cancelled by cancel scope {id(origin):x}")
+ else:
+ task.cancel()
# Deliver cancellation to child scopes that aren't shielded or running their own
# cancellation callbacks
@@ -595,6 +546,17 @@ class CancelScope(BaseCancelScope):
scope = scope._parent_scope
+ def _parent_cancelled(self) -> bool:
+ # Check whether any parent has been cancelled
+ cancel_scope = self._parent_scope
+ while cancel_scope is not None and not cancel_scope._shield:
+ if cancel_scope._cancel_called:
+ return True
+ else:
+ cancel_scope = cancel_scope._parent_scope
+
+ return False
+
def cancel(self) -> None:
if not self._cancel_called:
if self._timeout_handle:
@@ -701,50 +663,38 @@ class TaskGroup(abc.TaskGroup):
exc_val: BaseException | None,
exc_tb: TracebackType | None,
) -> bool | None:
+ ignore_exception = self.cancel_scope.__exit__(exc_type, exc_val, exc_tb)
if exc_val is not None:
self.cancel_scope.cancel()
if not isinstance(exc_val, CancelledError):
self._exceptions.append(exc_val)
- try:
- if self._tasks:
- with CancelScope() as wait_scope:
- while self._tasks:
- try:
- await asyncio.wait(self._tasks)
- 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
- else:
- # If there are no child tasks to wait on, run at least one checkpoint
- # anyway
- await AsyncIOBackend.cancel_shielded_checkpoint()
+ cancelled_exc_while_waiting_tasks: CancelledError | None = None
+ while self._tasks:
+ try:
+ await asyncio.wait(self._tasks)
+ except CancelledError as exc:
+ # This task was cancelled natively; reraise the CancelledError later
+ # unless this task was already interrupted by another exception
+ self.cancel_scope.cancel()
+ if cancelled_exc_while_waiting_tasks is None:
+ cancelled_exc_while_waiting_tasks = exc
- self._active = False
- if self._exceptions:
- raise BaseExceptionGroup(
- "unhandled errors in a TaskGroup", self._exceptions
- )
- elif exc_val:
- raise exc_val
- except BaseException as exc:
- if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__):
- return True
+ self._active = False
+ if self._exceptions:
+ raise BaseExceptionGroup(
+ "unhandled errors in a TaskGroup", self._exceptions
+ )
- raise
+ # Raise the CancelledError received while waiting for child tasks to exit,
+ # unless the context manager itself was previously exited with another
+ # exception, or if any of the child tasks raised an exception other than
+ # CancelledError
+ if cancelled_exc_while_waiting_tasks:
+ if exc_val is None or ignore_exception:
+ raise cancelled_exc_while_waiting_tasks
- return self.cancel_scope.__exit__(exc_type, exc_val, exc_tb)
+ return ignore_exception
def _spawn(
self,
@@ -780,7 +730,7 @@ class TaskGroup(abc.TaskGroup):
if not isinstance(exc, CancelledError):
self._exceptions.append(exc)
- if not self.cancel_scope._effectively_cancelled:
+ if not self.cancel_scope._parent_cancelled():
self.cancel_scope.cancel()
else:
task_status_future.set_exception(exc)
@@ -856,7 +806,7 @@ class TaskGroup(abc.TaskGroup):
# Threads
#
-_Retval_Queue_Type = tuple[Optional[T_Retval], Optional[BaseException]]
+_Retval_Queue_Type = Tuple[Optional[T_Retval], Optional[BaseException]]
class WorkerThread(Thread):
@@ -1005,7 +955,7 @@ class Process(abc.Process):
_stderr: StreamReaderWrapper | None
async def aclose(self) -> None:
- with CancelScope(shield=True) as scope:
+ with CancelScope(shield=True):
if self._stdin:
await self._stdin.aclose()
if self._stdout:
@@ -1013,14 +963,14 @@ class Process(abc.Process):
if self._stderr:
await self._stderr.aclose()
- scope.shield = False
- try:
- await self.wait()
- except BaseException:
- scope.shield = True
- self.kill()
+ try:
+ await self.wait()
+ except BaseException:
+ self.kill()
+ with CancelScope(shield=True):
await self.wait()
- raise
+
+ raise
async def wait(self) -> int:
return await self._process.wait()
@@ -1731,9 +1681,10 @@ class Lock(BaseLock):
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 = current_task()
+ self._owner_task = task
# Unless on the "fast path", yield control of the event loop so that other
# tasks can run too
@@ -1746,7 +1697,9 @@ class Lock(BaseLock):
return
- task = cast(asyncio.Task, current_task())
+ 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)
@@ -1762,10 +1715,14 @@ class Lock(BaseLock):
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 = current_task()
+ 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:
@@ -2065,7 +2022,9 @@ class AsyncIOTaskInfo(TaskInfo):
if task_state := _task_states.get(task):
if cancel_scope := task_state.cancel_scope:
- return cancel_scope._effectively_cancelled
+ return cancel_scope.cancel_called or (
+ not cancel_scope.shield and cancel_scope._parent_cancelled()
+ )
return False
@@ -2159,7 +2118,7 @@ class TestRunner(abc.TestRunner):
) -> T_Retval:
if not self._runner_task:
self._send_stream, receive_stream = create_memory_object_stream[
- tuple[Awaitable[Any], asyncio.Future]
+ Tuple[Awaitable[Any], asyncio.Future]
](1)
self._runner_task = self.get_loop().create_task(
self._run_tests_and_fixtures(receive_stream)
@@ -2521,7 +2480,7 @@ class AsyncIOBackend(AsyncBackend):
cls, host: str, port: int, local_address: IPSockAddrType | None = None
) -> abc.SocketStream:
transport, protocol = cast(
- tuple[asyncio.Transport, StreamProtocol],
+ Tuple[asyncio.Transport, StreamProtocol],
await get_running_loop().create_connection(
StreamProtocol, host, port, local_addr=local_address
),
@@ -2700,7 +2659,7 @@ class AsyncIOBackend(AsyncBackend):
@classmethod
def open_signal_receiver(
cls, *signals: Signals
- ) -> AbstractContextManager[AsyncIterator[Signals]]:
+ ) -> ContextManager[AsyncIterator[Signals]]:
return _SignalReceiver(signals)
@classmethod
diff --git a/contrib/python/anyio/anyio/_backends/_trio.py b/contrib/python/anyio/anyio/_backends/_trio.py
index de2189ce78..aee974deb6 100644
--- a/contrib/python/anyio/anyio/_backends/_trio.py
+++ b/contrib/python/anyio/anyio/_backends/_trio.py
@@ -7,18 +7,8 @@ import socket
import sys
import types
import weakref
-from collections.abc import (
- AsyncGenerator,
- AsyncIterator,
- Awaitable,
- Callable,
- Collection,
- Coroutine,
- Iterable,
- Sequence,
-)
+from collections.abc import AsyncIterator, Iterable
from concurrent.futures import Future
-from contextlib import AbstractContextManager
from dataclasses import dataclass
from functools import partial
from io import IOBase
@@ -29,8 +19,15 @@ from types import TracebackType
from typing import (
IO,
Any,
+ AsyncGenerator,
+ Awaitable,
+ Callable,
+ Collection,
+ ContextManager,
+ Coroutine,
Generic,
NoReturn,
+ Sequence,
TypeVar,
cast,
overload,
@@ -662,9 +659,19 @@ class Lock(BaseLock):
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:
- await self.__original.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
@@ -673,12 +680,18 @@ class Lock(BaseLock):
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()
@@ -1276,7 +1289,7 @@ class TrioBackend(AsyncBackend):
@classmethod
def open_signal_receiver(
cls, *signals: Signals
- ) -> AbstractContextManager[AsyncIterator[Signals]]:
+ ) -> ContextManager[AsyncIterator[Signals]]:
return _SignalReceiver(signals)
@classmethod
diff --git a/contrib/python/anyio/anyio/_core/_fileio.py b/contrib/python/anyio/anyio/_core/_fileio.py
index 23ccb0d66f..214a90bfd8 100644
--- a/contrib/python/anyio/anyio/_core/_fileio.py
+++ b/contrib/python/anyio/anyio/_core/_fileio.py
@@ -3,7 +3,7 @@ from __future__ import annotations
import os
import pathlib
import sys
-from collections.abc import AsyncIterator, Callable, Iterable, Iterator, Sequence
+from collections.abc import Callable, Iterable, Iterator, Sequence
from dataclasses import dataclass
from functools import partial
from os import PathLike
@@ -12,6 +12,7 @@ from typing import (
TYPE_CHECKING,
Any,
AnyStr,
+ AsyncIterator,
Final,
Generic,
overload,
@@ -217,6 +218,18 @@ class Path:
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.from_uri` (available on Python 3.13 or later)
+ * :meth:`~pathlib.Path.full_match` (available on Python 3.13 or later)
+ * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later)
+ * :meth:`~pathlib.Path.match` (the ``case_sensitive`` paramater is only available on
+ Python 3.13 or later)
+ * :meth:`~pathlib.Path.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`
@@ -232,7 +245,10 @@ class Path:
* :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`
@@ -243,11 +259,14 @@ class Path:
* :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`
@@ -385,9 +404,6 @@ class Path:
except ValueError:
return False
- async def is_junction(self) -> bool:
- return await to_thread.run_sync(self._path.is_junction)
-
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)
@@ -447,6 +463,11 @@ class Path:
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
diff --git a/contrib/python/anyio/anyio/_core/_signals.py b/contrib/python/anyio/anyio/_core/_signals.py
index f3451d302f..115c749bd9 100644
--- a/contrib/python/anyio/anyio/_core/_signals.py
+++ b/contrib/python/anyio/anyio/_core/_signals.py
@@ -1,15 +1,13 @@
from __future__ import annotations
from collections.abc import AsyncIterator
-from contextlib import AbstractContextManager
from signal import Signals
+from typing import ContextManager
from ._eventloop import get_async_backend
-def open_signal_receiver(
- *signals: Signals,
-) -> AbstractContextManager[AsyncIterator[Signals]]:
+def open_signal_receiver(*signals: Signals) -> ContextManager[AsyncIterator[Signals]]:
"""
Start receiving operating system signals.
diff --git a/contrib/python/anyio/anyio/_core/_streams.py b/contrib/python/anyio/anyio/_core/_streams.py
index 6a9814e5a9..aa6b0c222a 100644
--- a/contrib/python/anyio/anyio/_core/_streams.py
+++ b/contrib/python/anyio/anyio/_core/_streams.py
@@ -1,7 +1,7 @@
from __future__ import annotations
import math
-from typing import TypeVar
+from typing import Tuple, TypeVar
from warnings import warn
from ..streams.memory import (
@@ -14,7 +14,7 @@ T_Item = TypeVar("T_Item")
class create_memory_object_stream(
- tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]],
+ Tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]],
):
"""
Create a memory object stream.
diff --git a/contrib/python/anyio/anyio/_core/_subprocesses.py b/contrib/python/anyio/anyio/_core/_subprocesses.py
index 7ba41a5b03..1ac2d549df 100644
--- a/contrib/python/anyio/anyio/_core/_subprocesses.py
+++ b/contrib/python/anyio/anyio/_core/_subprocesses.py
@@ -160,25 +160,38 @@ async def open_process(
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 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 (POSIX only)
+ running the given command (Python >= 3.9; POSIX only)
:return: an asynchronous process object
"""
kwargs: dict[str, Any] = {}
if user is not None:
+ if sys.version_info < (3, 9):
+ raise TypeError("the 'user' argument requires Python 3.9 or later")
+
kwargs["user"] = user
if group is not None:
+ if sys.version_info < (3, 9):
+ raise TypeError("the 'group' argument requires Python 3.9 or later")
+
kwargs["group"] = group
if extra_groups is not None:
+ if sys.version_info < (3, 9):
+ raise TypeError("the 'extra_groups' argument requires Python 3.9 or later")
+
kwargs["extra_groups"] = group
if umask >= 0:
+ if sys.version_info < (3, 9):
+ raise TypeError("the 'umask' argument requires Python 3.9 or later")
+
kwargs["umask"] = umask
return await get_async_backend().open_process(
diff --git a/contrib/python/anyio/anyio/abc/_eventloop.py b/contrib/python/anyio/anyio/abc/_eventloop.py
index 93d0e9d25b..2c73bb9ffb 100644
--- a/contrib/python/anyio/anyio/abc/_eventloop.py
+++ b/contrib/python/anyio/anyio/abc/_eventloop.py
@@ -3,8 +3,7 @@ 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 collections.abc import AsyncIterator, Awaitable
from os import PathLike
from signal import Signals
from socket import AddressFamily, SocketKind, socket
@@ -12,6 +11,9 @@ from typing import (
IO,
TYPE_CHECKING,
Any,
+ Callable,
+ ContextManager,
+ Sequence,
TypeVar,
Union,
overload,
@@ -350,7 +352,7 @@ class AsyncBackend(metaclass=ABCMeta):
@abstractmethod
def open_signal_receiver(
cls, *signals: Signals
- ) -> AbstractContextManager[AsyncIterator[Signals]]:
+ ) -> ContextManager[AsyncIterator[Signals]]:
pass
@classmethod
diff --git a/contrib/python/anyio/anyio/abc/_sockets.py b/contrib/python/anyio/anyio/abc/_sockets.py
index 1c6a450cdc..b321225a7b 100644
--- a/contrib/python/anyio/anyio/abc/_sockets.py
+++ b/contrib/python/anyio/anyio/abc/_sockets.py
@@ -8,7 +8,7 @@ from io import IOBase
from ipaddress import IPv4Address, IPv6Address
from socket import AddressFamily
from types import TracebackType
-from typing import Any, TypeVar, Union
+from typing import Any, Tuple, TypeVar, Union
from .._core._typedattr import (
TypedAttributeProvider,
@@ -19,10 +19,10 @@ from ._streams import ByteStream, Listener, UnreliableObjectStream
from ._tasks import TaskGroup
IPAddressType = Union[str, IPv4Address, IPv6Address]
-IPSockAddrType = tuple[str, int]
+IPSockAddrType = Tuple[str, int]
SockAddrType = Union[IPSockAddrType, str]
-UDPPacketType = tuple[bytes, IPSockAddrType]
-UNIXDatagramPacketType = tuple[bytes, str]
+UDPPacketType = Tuple[bytes, IPSockAddrType]
+UNIXDatagramPacketType = Tuple[bytes, str]
T_Retval = TypeVar("T_Retval")
diff --git a/contrib/python/anyio/anyio/from_thread.py b/contrib/python/anyio/anyio/from_thread.py
index 93a4cfe8e4..b8785845ba 100644
--- a/contrib/python/anyio/anyio/from_thread.py
+++ b/contrib/python/anyio/anyio/from_thread.py
@@ -3,17 +3,15 @@ from __future__ import annotations
import sys
from collections.abc import Awaitable, Callable, Generator
from concurrent.futures import Future
-from contextlib import (
- AbstractAsyncContextManager,
- AbstractContextManager,
- contextmanager,
-)
+from contextlib import AbstractContextManager, contextmanager
from dataclasses import dataclass, field
from inspect import isawaitable
from threading import Lock, Thread, get_ident
from types import TracebackType
from typing import (
Any,
+ AsyncContextManager,
+ ContextManager,
Generic,
TypeVar,
cast,
@@ -89,9 +87,7 @@ class _BlockingAsyncContextManager(Generic[T_co], AbstractContextManager):
type[BaseException] | None, BaseException | None, TracebackType | None
] = (None, None, None)
- def __init__(
- self, async_cm: AbstractAsyncContextManager[T_co], portal: BlockingPortal
- ):
+ def __init__(self, async_cm: AsyncContextManager[T_co], portal: BlockingPortal):
self._async_cm = async_cm
self._portal = portal
@@ -378,8 +374,8 @@ class BlockingPortal:
return f, task_status_future.result()
def wrap_async_context_manager(
- self, cm: AbstractAsyncContextManager[T_co]
- ) -> AbstractContextManager[T_co]:
+ self, cm: AsyncContextManager[T_co]
+ ) -> ContextManager[T_co]:
"""
Wrap an async context manager as a synchronous context manager via this portal.
diff --git a/contrib/python/anyio/anyio/pytest_plugin.py b/contrib/python/anyio/anyio/pytest_plugin.py
index c9fe1bde92..b7d9305614 100644
--- a/contrib/python/anyio/anyio/pytest_plugin.py
+++ b/contrib/python/anyio/anyio/pytest_plugin.py
@@ -1,13 +1,14 @@
from __future__ import annotations
import sys
-from collections.abc import Iterator
+from collections.abc import Generator, Iterator
from contextlib import ExitStack, contextmanager
-from inspect import isasyncgenfunction, iscoroutinefunction
-from typing import Any, cast
+from inspect import isasyncgenfunction, iscoroutinefunction, ismethod
+from typing import Any, Dict, Tuple, cast
import pytest
import sniffio
+from _pytest.fixtures import SubRequest
from _pytest.outcomes import Exit
from ._core._eventloop import get_all_backends, get_async_backend
@@ -27,7 +28,7 @@ def extract_backend_and_options(backend: object) -> tuple[str, dict[str, Any]]:
return backend, {}
elif isinstance(backend, tuple) and len(backend) == 2:
if isinstance(backend[0], str) and isinstance(backend[1], dict):
- return cast(tuple[str, dict[str, Any]], backend)
+ return cast(Tuple[str, Dict[str, Any]], backend)
raise TypeError("anyio_backend must be either a string or tuple of (string, dict)")
@@ -70,28 +71,56 @@ def pytest_configure(config: Any) -> None:
)
-def pytest_fixture_setup(fixturedef: Any, request: Any) -> None:
- def wrapper(*args, anyio_backend, **kwargs): # type: ignore[no-untyped-def]
+@pytest.hookimpl(hookwrapper=True)
+def pytest_fixture_setup(fixturedef: Any, request: Any) -> Generator[Any]:
+ def wrapper(
+ *args: Any, anyio_backend: Any, request: SubRequest, **kwargs: Any
+ ) -> Any:
+ # Rebind any fixture methods to the request instance
+ if (
+ request.instance
+ and ismethod(func)
+ and type(func.__self__) is type(request.instance)
+ ):
+ local_func = func.__func__.__get__(request.instance)
+ else:
+ local_func = func
+
backend_name, backend_options = extract_backend_and_options(anyio_backend)
if has_backend_arg:
kwargs["anyio_backend"] = anyio_backend
+ if has_request_arg:
+ kwargs["request"] = request
+
with get_runner(backend_name, backend_options) as runner:
- if isasyncgenfunction(func):
- yield from runner.run_asyncgen_fixture(func, kwargs)
+ if isasyncgenfunction(local_func):
+ yield from runner.run_asyncgen_fixture(local_func, kwargs)
else:
- yield runner.run_fixture(func, kwargs)
+ yield runner.run_fixture(local_func, kwargs)
# Only apply this to coroutine functions and async generator functions in requests
# that involve the anyio_backend fixture
func = fixturedef.func
if isasyncgenfunction(func) or iscoroutinefunction(func):
if "anyio_backend" in request.fixturenames:
- has_backend_arg = "anyio_backend" in fixturedef.argnames
fixturedef.func = wrapper
- if not has_backend_arg:
+ original_argname = fixturedef.argnames
+
+ if not (has_backend_arg := "anyio_backend" in fixturedef.argnames):
fixturedef.argnames += ("anyio_backend",)
+ if not (has_request_arg := "request" in fixturedef.argnames):
+ fixturedef.argnames += ("request",)
+
+ try:
+ return (yield)
+ finally:
+ fixturedef.func = func
+ fixturedef.argnames = original_argname
+
+ return (yield)
+
@pytest.hookimpl(tryfirst=True)
def pytest_pycollect_makeitem(collector: Any, name: Any, obj: Any) -> None:
diff --git a/contrib/python/anyio/anyio/streams/tls.py b/contrib/python/anyio/anyio/streams/tls.py
index 83240b4d35..d01c8e6f4c 100644
--- a/contrib/python/anyio/anyio/streams/tls.py
+++ b/contrib/python/anyio/anyio/streams/tls.py
@@ -7,7 +7,7 @@ import sys
from collections.abc import Callable, Mapping
from dataclasses import dataclass
from functools import wraps
-from typing import Any, TypeVar
+from typing import Any, Tuple, TypeVar
from .. import (
BrokenResourceError,
@@ -25,8 +25,8 @@ else:
T_Retval = TypeVar("T_Retval")
PosArgsT = TypeVarTuple("PosArgsT")
-_PCTRTT = tuple[tuple[str, str], ...]
-_PCTRTTT = tuple[_PCTRTT, ...]
+_PCTRTT = Tuple[Tuple[str, str], ...]
+_PCTRTTT = Tuple[_PCTRTT, ...]
class TLSAttribute(TypedAttributeSet):
@@ -162,9 +162,8 @@ class TLSStream(ByteStream):
except ssl.SSLError as exc:
self._read_bio.write_eof()
self._write_bio.write_eof()
- if (
- isinstance(exc, ssl.SSLEOFError)
- or "UNEXPECTED_EOF_WHILE_READING" in exc.strerror
+ if isinstance(exc, ssl.SSLEOFError) or (
+ exc.strerror and "UNEXPECTED_EOF_WHILE_READING" in exc.strerror
):
if self.standard_compatible:
raise BrokenResourceError from exc
diff --git a/contrib/python/anyio/ya.make b/contrib/python/anyio/ya.make
index cec445229c..bb56a53ce5 100644
--- a/contrib/python/anyio/ya.make
+++ b/contrib/python/anyio/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(4.6.0)
+VERSION(4.6.2)
LICENSE(MIT)