]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-138432: Improved invalid path checking in zoneinfo.reset_tzpath() (GH-13843...
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 11 Sep 2025 07:35:39 +0000 (10:35 +0300)
committerGitHub <noreply@github.com>
Thu, 11 Sep 2025 07:35:39 +0000 (07:35 +0000)
* Improve error messages for path-like relative paths and path-like bytes paths.
* TZPATH is now always a tuple of strings.
(cherry picked from commit 859aecc33b82f45e5b7ae30138d28f2a2f33a575)

Co-authored-by: Stephen Morton <git@tungol.org>
Lib/test/test_zoneinfo/test_zoneinfo.py
Lib/zoneinfo/_tzpath.py
Misc/NEWS.d/next/Library/2025-09-03-15-20-10.gh-issue-138432.RMc7UX.rst [new file with mode: 0644]

index f7bb2aa151c04a3b858bcf73d03637fb5d62d698..b4b2b984b1bf36905d64c2cdf35eb39508e366e8 100644 (file)
@@ -18,6 +18,7 @@ from datetime import date, datetime, time, timedelta, timezone
 from functools import cached_property
 
 from test.support import MISSING_C_DOCSTRINGS, requires_gil_enabled
+from test.support.os_helper import FakePath
 from test.test_zoneinfo import _support as test_support
 from test.test_zoneinfo._support import OS_ENV_LOCK, TZPATH_TEST_LOCK, ZoneInfoTestBase
 from test.support.import_helper import import_module, CleanImport
@@ -1798,6 +1799,7 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase):
             ("/usr/share/zoneinfo", "../relative/path",),
             ("path/to/somewhere", "../relative/path",),
             ("/usr/share/zoneinfo", "path/to/somewhere", "../relative/path",),
+            (FakePath("path/to/somewhere"),)
         ]
         for input_paths in bad_values:
             with self.subTest(input_paths=input_paths):
@@ -1809,6 +1811,9 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase):
             "/etc/zoneinfo:/usr/share/zoneinfo",
             b"/etc/zoneinfo:/usr/share/zoneinfo",
             0,
+            (b"/bytes/path", "/valid/path"),
+            (FakePath(b"/bytes/path"),),
+            (0,),
         ]
 
         for bad_value in bad_values:
@@ -1819,6 +1824,7 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase):
     def test_tzpath_attribute(self):
         tzpath_0 = [f"{DRIVE}/one", f"{DRIVE}/two"]
         tzpath_1 = [f"{DRIVE}/three"]
+        tzpath_pathlike = (FakePath(f"{DRIVE}/usr/share/zoneinfo"),)
 
         with self.tzpath_context(tzpath_0):
             query_0 = self.module.TZPATH
@@ -1826,8 +1832,12 @@ class TzPathTest(TzPathUserMixin, ZoneInfoTestBase):
         with self.tzpath_context(tzpath_1):
             query_1 = self.module.TZPATH
 
+        with self.tzpath_context(tzpath_pathlike):
+            query_pathlike = self.module.TZPATH
+
         self.assertSequenceEqual(tzpath_0, query_0)
         self.assertSequenceEqual(tzpath_1, query_1)
+        self.assertSequenceEqual(tuple([os.fspath(p) for p in tzpath_pathlike]), query_pathlike)
 
 
 class CTzPathTest(TzPathTest):
index 5db17bea045d8c8882601bbeb10fa2d6af850138..d8ccec82059391c4be71cad4bd9b8b566a548cf0 100644 (file)
@@ -13,6 +13,13 @@ def _reset_tzpath(to=None, stacklevel=4):
                 + f"not {type(tzpaths)}: {tzpaths!r}"
             )
 
+        tzpaths = [os.fspath(p) for p in tzpaths]
+        if not all(isinstance(p, str) for p in tzpaths):
+            raise TypeError(
+                "All elements of a tzpath sequence must be strings or "
+                "os.PathLike objects which convert to strings."
+            )
+
         if not all(map(os.path.isabs, tzpaths)):
             raise ValueError(_get_invalid_paths_message(tzpaths))
         base_tzpath = tzpaths
diff --git a/Misc/NEWS.d/next/Library/2025-09-03-15-20-10.gh-issue-138432.RMc7UX.rst b/Misc/NEWS.d/next/Library/2025-09-03-15-20-10.gh-issue-138432.RMc7UX.rst
new file mode 100644 (file)
index 0000000..b48b978
--- /dev/null
@@ -0,0 +1,6 @@
+:meth:`zoneinfo.reset_tzpath` will now convert any :class:`os.PathLike` objects
+it receives into strings before adding them to ``TZPATH``. It will raise
+``TypeError`` if anything other than a string is found after this conversion.
+If given an :class:`os.PathLike` object that represents a relative path, it
+will now raise ``ValueError`` instead of ``TypeError``, and present a more
+informative error message.