From 8a4d651610abb71da66cef58f350788eab6b0bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= Date: Tue, 28 May 2024 01:00:49 +0300 Subject: [PATCH 1/3] Added missing Path properties from Python 3.13 Fixes #737. --- src/anyio/_core/_fileio.py | 24 ++++++++++++++++++++++-- tests/test_fileio.py | 18 ++++++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/anyio/_core/_fileio.py b/src/anyio/_core/_fileio.py index df2057fe..8053dce5 100644 --- a/src/anyio/_core/_fileio.py +++ b/src/anyio/_core/_fileio.py @@ -358,8 +358,28 @@ def as_posix(self) -> str: def as_uri(self) -> str: return self._path.as_uri() - def match(self, path_pattern: str) -> bool: - return self._path.match(path_pattern) + if sys.version_info >= (3, 13): + parser = pathlib.Path.parser # type: ignore[attr-defined] + + @classmethod + def from_uri(cls, uri: str) -> Path: + return Path(pathlib.Path.from_uri(uri)) # type: ignore[attr-defined] + + def full_match( + self, path_pattern: str, *, case_sensitive: bool | None = None + ) -> bool: + return self._path.full_match( # type: ignore[attr-defined] + 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) def is_relative_to(self, other: str | PathLike[str]) -> bool: try: diff --git a/tests/test_fileio.py b/tests/test_fileio.py index bcd7fe1d..ff9178e0 100644 --- a/tests/test_fileio.py +++ b/tests/test_fileio.py @@ -186,6 +186,15 @@ def test_as_uri(self) -> None: else: assert Path("/foo/bar").as_uri() == "file:///foo/bar" + @pytest.mark.skipif( + sys.version_info < (3, 13), + reason="Path.from_uri() is only available on Python 3.13+", + ) + def test_from_uri(self) -> None: + path = Path.from_uri("file:///foo/bar") + assert isinstance(path, Path) + assert path.as_uri() == "file:///foo/bar" + async def test_cwd(self) -> None: result = await Path.cwd() assert isinstance(result, Path) @@ -269,6 +278,7 @@ async def test_is_mount(self) -> None: assert not await Path("/gfobj4ewiotj").is_mount() assert await Path("/").is_mount() + @pytest.mark.filterwarnings("ignore::DeprecationWarning") def test_is_reserved(self) -> None: expected_result = platform.system() == "Windows" assert Path("nul").is_reserved() == expected_result @@ -339,6 +349,14 @@ def test_joinpath(self) -> None: path = Path("/foo").joinpath("bar") assert path == Path("/foo/bar") + @pytest.mark.skipif( + sys.version_info < (3, 13), + reason="Path.full_match() is only available on Python 3.13+", + ) + def test_fullmatch(self) -> None: + assert Path("/foo/bar").full_match("/foo/*") + assert not Path("/foo/bar").full_match("/baz/*") + def test_match(self) -> None: assert Path("/foo/bar").match("/foo/*") assert not Path("/foo/bar").match("/baz/*")