Skip to content

Commit

Permalink
Merge branch 'master' into 3-14
Browse files Browse the repository at this point in the history
  • Loading branch information
agronholm authored Jan 2, 2025
2 parents 897570f + 9a792f3 commit e645f02
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 24 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test-downstream.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
with:
python-version: "${{ matrix.python-version }}"
- name: Setup uv
uses: astral-sh/setup-uv@v3
uses: astral-sh/setup-uv@v5
with:
version: "0.4.15"
enable-cache: true
Expand All @@ -96,7 +96,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.12"]
python-version: ["3.9", "3.13"]
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -106,7 +106,7 @@ jobs:
with:
python-version: ${{ inputs.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@v4
uses: astral-sh/setup-uv@v5
with:
version: "0.5.4"
enable-cache: true
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.1
rev: v0.8.4
hooks:
- id: ruff
args: [--fix, --show-fixes]
- id: ruff-format

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
rev: v1.14.0
hooks:
- id: mypy
additional_dependencies:
Expand Down
6 changes: 6 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.

- Added support for the ``copy()``, ``copy_into()``, ``move()`` and ``move_into()``
methods in ``anyio.Path``, available in Python 3.14
- Configure ``SO_RCVBUF``, ``SO_SNDBUF`` and ``TCP_NODELAY`` on the selector
thread waker socket pair. This should improve the performance of ``wait_readable()``
and ``wait_writable()`` when using the ``ProactorEventLoop``
(`#836 <https://github.com/agronholm/anyio/pull/836>`_; PR by @graingert)
- Fixed ``AssertionError`` when using ``nest-asyncio``
(`#840 <https://github.com/agronholm/anyio/issues/840>`_)

**4.7.0**

Expand Down
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,9 @@ extend-select = [
[tool.mypy]
python_version = "3.13"
strict = true
ignore_missing_imports = true
disallow_any_generics = false
warn_return_any = false
disallow_untyped_decorators = false
disallow_subclassing_any = false
show_error_codes = true

[tool.pytest.ini_options]
addopts = "-rsfE --tb=short --strict-config --strict-markers -p anyio -p no:asyncio -p no:trio"
Expand Down
32 changes: 17 additions & 15 deletions src/anyio/_backends/_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,40 +677,42 @@ def __init__(self, parent_id: int | None, cancel_scope: CancelScope | None):
self.cancel_scope = cancel_scope


class TaskStateStore(MutableMapping["Awaitable[Any] | asyncio.Task", TaskState]):
class TaskStateStore(
MutableMapping["Coroutine[Any, Any, Any] | asyncio.Task", TaskState]
):
def __init__(self) -> None:
self._task_states = WeakKeyDictionary[asyncio.Task, TaskState]()
self._preliminary_task_states: dict[Awaitable[Any], TaskState] = {}
self._preliminary_task_states: dict[Coroutine[Any, Any, Any], TaskState] = {}

def __getitem__(self, key: Awaitable[Any] | asyncio.Task, /) -> TaskState:
assert isinstance(key, asyncio.Task)
def __getitem__(self, key: Coroutine[Any, Any, Any] | asyncio.Task, /) -> TaskState:
task = cast(asyncio.Task, key)
try:
return self._task_states[key]
return self._task_states[task]
except KeyError:
if coro := key.get_coro():
if coro := task.get_coro():
if state := self._preliminary_task_states.get(coro):
return state

raise KeyError(key)

def __setitem__(
self, key: asyncio.Task | Awaitable[Any], value: TaskState, /
self, key: asyncio.Task | Coroutine[Any, Any, Any], value: TaskState, /
) -> None:
if isinstance(key, asyncio.Task):
self._task_states[key] = value
else:
if isinstance(key, Coroutine):
self._preliminary_task_states[key] = value

def __delitem__(self, key: asyncio.Task | Awaitable[Any], /) -> None:
if isinstance(key, asyncio.Task):
del self._task_states[key]
else:
self._task_states[key] = value

def __delitem__(self, key: asyncio.Task | Coroutine[Any, Any, Any], /) -> None:
if isinstance(key, Coroutine):
del self._preliminary_task_states[key]
else:
del self._task_states[key]

def __len__(self) -> int:
return len(self._task_states) + len(self._preliminary_task_states)

def __iter__(self) -> Iterator[Awaitable[Any] | asyncio.Task]:
def __iter__(self) -> Iterator[Coroutine[Any, Any, Any] | asyncio.Task]:
yield from self._task_states
yield from self._preliminary_task_states

Expand Down
17 changes: 17 additions & 0 deletions src/anyio/_core/_asyncio_selector_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@ def __init__(self) -> None:
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

Expand Down
14 changes: 13 additions & 1 deletion tests/test_taskgroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

import pytest
from exceptiongroup import catch
from pytest import FixtureRequest
from pytest import FixtureRequest, MonkeyPatch
from pytest_mock import MockerFixture

import anyio
from anyio import (
Expand Down Expand Up @@ -1805,3 +1806,14 @@ async def sync_coro() -> None:
async with create_task_group() as tg:
tg.start_soon(sync_coro)
tg.cancel_scope.cancel()


@pytest.mark.parametrize("anyio_backend", ["asyncio"])
async def test_patched_asyncio_task(monkeypatch: MonkeyPatch) -> None:
monkeypatch.setattr(
asyncio,
"Task",
asyncio.tasks._PyTask, # type: ignore[attr-defined]
)
async with create_task_group() as tg:
tg.start_soon(sleep, 0)

0 comments on commit e645f02

Please sign in to comment.