diff --git a/docs/versionhistory.rst b/docs/versionhistory.rst index c37908a2..9d793eb6 100644 --- a/docs/versionhistory.rst +++ b/docs/versionhistory.rst @@ -3,6 +3,11 @@ Version history This library adheres to `Semantic Versioning 2.0 `_. +**UNRELEASED** + +- Added support for the the ``from_uri()``, ``full_match()``, ``parser`` + methods/properties in ``anyio.Path``, newly added in Python 3.13 + **4.4.0** - Added the ``BlockingPortalProvider`` class to aid with constructing synchronous diff --git a/pyproject.toml b/pyproject.toml index 175e30ae..76aecff5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ test = [ "pytest >= 7.0", "pytest-mock >= 3.6.1", "trustme", - "uvloop >= 0.17; platform_python_implementation == 'CPython' and platform_system != 'Windows'", + "uvloop >= 0.17; platform_python_implementation == 'CPython' and platform_system != 'Windows' and python_version < '3.13'", ] doc = [ "packaging", @@ -87,7 +87,7 @@ extend-select = [ "required-imports" = ["from __future__ import annotations"] [tool.mypy] -python_version = "3.12" +python_version = "3.13" strict = true ignore_missing_imports = true disallow_any_generics = false 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/*")