From 8a4d651610abb71da66cef58f350788eab6b0bd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alex=20Gr=C3=B6nholm?= <alex.gronholm@nextday.fi>
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/*")

