Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/versionhistory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ This library adheres to `Semantic Versioning 2.0 <http://semver.org/>`_.
``Could not create 2 listeners with a consistent port`` when an ephemeral port is
requested and IPv6 is enabled and the dual-stack path is not available or a specific
local host name was given
- Fixed ``AsyncFile`` not shielding against cancellation while closing
(`#1314 <https://github.com/agronholm/anyio/pull/1314>`_)

**4.15.1**

Expand Down
4 changes: 3 additions & 1 deletion src/anyio/_core/_fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from .. import to_thread
from ..abc import AsyncResource
from ._synchronization import CapacityLimiter
from ._tasks import CancelScope

if sys.version_info >= (3, 11):
from typing import Self
Expand Down Expand Up @@ -114,7 +115,8 @@ async def __aiter__(self) -> AsyncIterator[AnyStr]:
break

async def aclose(self) -> None:
return await to_thread.run_sync(self._fp.close, limiter=self._limiter)
with CancelScope(shield=True):
await to_thread.run_sync(self._fp.close, limiter=self._limiter)

async def read(self, size: int = -1) -> AnyStr:
return await to_thread.run_sync(self._fp.read, size, limiter=self._limiter)
Expand Down
17 changes: 16 additions & 1 deletion tests/test_fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@
from _pytest.fixtures import FixtureRequest
from _pytest.tmpdir import TempPathFactory

from anyio import AsyncFile, CapacityLimiter, Path, open_file, wrap_file
from anyio import (
AsyncFile,
CancelScope,
CapacityLimiter,
Path,
open_file,
wrap_file,
)


@pytest.fixture(params=[False, True])
Expand Down Expand Up @@ -86,6 +93,14 @@ async def test_wrap_file(

assert path.read_text() == "dummydata"

async def test_shielded_aclose(self, tmp_path: pathlib.Path) -> None:
async with await open_file(tmp_path / "foo", "wb") as f:
with CancelScope() as scope:
scope.cancel()
await f.aclose()

assert f.closed


class TestPath:
@pytest.fixture
Expand Down