| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent dac1da2 commit e4ff131
9 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -239,12 +239,16 @@ the :mod:`glob` module.) | |||
| 239 | 239 | .. function:: isabs(path) | |
| 240 | 240 | ||
| 241 | 241 | Return ``True`` if *path* is an absolute pathname. On Unix, that means it | |
| 242 | - begins with a slash, on Windows that it begins with a (back)slash after chopping | ||
| 243 | - off a potential drive letter. | ||
| 242 | + begins with a slash, on Windows that it begins with two (back)slashes, or a | ||
| 243 | + drive letter, colon, and (back)slash together. | ||
| 244 | 244 | ||
| 245 | 245 | .. versionchanged:: 3.6 | |
| 246 | 246 | Accepts a :term:`path-like object`. | |
| 247 | 247 | ||
| 248 | + .. versionchanged:: 3.13 | ||
| 249 | + On Windows, returns ``False`` if the given path starts with exactly one | ||
| 250 | + (back)slash. | ||
| 251 | + | ||
| 248 | 252 | ||
| 249 | 253 | .. function:: isfile(path) | |
| 250 | 254 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -307,6 +307,13 @@ os | |||
| 307 | 307 | :c:func:`!posix_spawn_file_actions_addclosefrom_np`. | |
| 308 | 308 | (Contributed by Jakub Kulik in :gh:`113117`.) | |
| 309 | 309 | ||
| 310 | + os.path | ||
| 311 | + ------- | ||
| 312 | + | ||
| 313 | + * On Windows, :func:`os.path.isabs` no longer considers paths starting with | ||
| 314 | + exactly one (back)slash to be absolute. | ||
| 315 | + (Contributed by Barney Gale and Jon Foster in :gh:`44626`.) | ||
| 316 | + | ||
| 310 | 317 | pathlib | |
| 311 | 318 | ------- | |
| 312 | 319 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -77,29 +77,22 @@ def normcase(s): | |||
| 77 | 77 | return s.replace('/', '\\').lower() | |
| 78 | 78 | ||
| 79 | 79 | ||
| 80 | - # Return whether a path is absolute. | ||
| 81 | - # Trivial in Posix, harder on Windows. | ||
| 82 | - # For Windows it is absolute if it starts with a slash or backslash (current | ||
| 83 | - # volume), or if a pathname after the volume-letter-and-colon or UNC-resource | ||
| 84 | - # starts with a slash or backslash. | ||
| 85 | - | ||
| 86 | 80 | def isabs(s): | |
| 87 | 81 | """Test whether a path is absolute""" | |
| 88 | 82 | s = os.fspath(s) | |
| 89 | 83 | if isinstance(s, bytes): | |
| 90 | 84 | sep = b'\\' | |
| 91 | 85 | altsep = b'/' | |
| 92 | 86 | colon_sep = b':\\' | |
| 87 | + double_sep = b'\\\\' | ||
| 93 | 88 | else: | |
| 94 | 89 | sep = '\\' | |
| 95 | 90 | altsep = '/' | |
| 96 | 91 | colon_sep = ':\\' | |
| 92 | + double_sep = '\\\\' | ||
| 97 | 93 | s = s[:3].replace(altsep, sep) | |
| 98 | 94 | # Absolute: UNC, device, and paths with a drive and root. | |
| 99 | - # LEGACY BUG: isabs("/x") should be false since the path has no drive. | ||
| 100 | - if s.startswith(sep) or s.startswith(colon_sep, 1): | ||
| 101 | - return True | ||
| 102 | - return False | ||
| 95 | + return s.startswith(colon_sep, 1) or s.startswith(double_sep) | ||
| 103 | 96 | ||
| 104 | 97 | ||
| 105 | 98 | # Join two (or more) paths. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,4 @@ | |||
| 1 | 1 | import functools | |
| 2 | - import ntpath | ||
| 3 | 2 | import posixpath | |
| 4 | 3 | from errno import ENOENT, ENOTDIR, EBADF, ELOOP, EINVAL | |
| 5 | 4 | from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO | |
@@ -373,10 +372,7 @@ def parents(self): | |||
| 373 | 372 | def is_absolute(self): | |
| 374 | 373 | """True if the path is absolute (has both a root and, if applicable, | |
| 375 | 374 | a drive).""" | |
| 376 | - if self.pathmod is ntpath: | ||
| 377 | - # ntpath.isabs() is defective - see GH-44626. | ||
| 378 | - return bool(self.drive and self.root) | ||
| 379 | - elif self.pathmod is posixpath: | ||
| 375 | + if self.pathmod is posixpath: | ||
| 380 | 376 | # Optimization: work with raw paths on POSIX. | |
| 381 | 377 | for path in self._raw_paths: | |
| 382 | 378 | if path.startswith('/'): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -227,10 +227,18 @@ def test_split(self): | |||
| 227 | 227 | tester('ntpath.split("//conky/mountpoint/")', ('//conky/mountpoint/', '')) | |
| 228 | 228 | ||
| 229 | 229 | def test_isabs(self): | |
| 230 | + tester('ntpath.isabs("foo\\bar")', 0) | ||
| 231 | + tester('ntpath.isabs("foo/bar")', 0) | ||
| 230 | 232 | tester('ntpath.isabs("c:\\")', 1) | |
| 233 | + tester('ntpath.isabs("c:\\foo\\bar")', 1) | ||
| 234 | + tester('ntpath.isabs("c:/foo/bar")', 1) | ||
| 231 | 235 | tester('ntpath.isabs("\\\\conky\\mountpoint\\")', 1) | |
| 232 | - tester('ntpath.isabs("\\foo")', 1) | ||
| 233 | - tester('ntpath.isabs("\\foo\\bar")', 1) | ||
| 236 | + | ||
| 237 | + # gh-44626: paths with only a drive or root are not absolute. | ||
| 238 | + tester('ntpath.isabs("\\foo\\bar")', 0) | ||
| 239 | + tester('ntpath.isabs("/foo/bar")', 0) | ||
| 240 | + tester('ntpath.isabs("c:foo\\bar")', 0) | ||
| 241 | + tester('ntpath.isabs("c:foo/bar")', 0) | ||
| 234 | 242 | ||
| 235 | 243 | # gh-96290: normal UNC paths and device paths without trailing backslashes | |
| 236 | 244 | tester('ntpath.isabs("\\\\conky\\mountpoint")', 1) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1011,10 +1011,14 @@ def test_is_absolute(self): | |||
| 1011 | 1011 | self.assertTrue(P('c:/a').is_absolute()) | |
| 1012 | 1012 | self.assertTrue(P('c:/a/b/').is_absolute()) | |
| 1013 | 1013 | # UNC paths are absolute by definition. | |
| 1014 | + self.assertTrue(P('//').is_absolute()) | ||
| 1015 | + self.assertTrue(P('//a').is_absolute()) | ||
| 1014 | 1016 | self.assertTrue(P('//a/b').is_absolute()) | |
| 1015 | 1017 | self.assertTrue(P('//a/b/').is_absolute()) | |
| 1016 | 1018 | self.assertTrue(P('//a/b/c').is_absolute()) | |
| 1017 | 1019 | self.assertTrue(P('//a/b/c/d').is_absolute()) | |
| 1020 | + self.assertTrue(P('//?/UNC/').is_absolute()) | ||
| 1021 | + self.assertTrue(P('//?/UNC/spam').is_absolute()) | ||
| 1018 | 1022 | ||
| 1019 | 1023 | def test_join(self): | |
| 1020 | 1024 | P = self.cls | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -459,8 +459,8 @@ def _join(name): | |||
| 459 | 459 | ||
| 460 | 460 | def testParseArgsAbsolutePathsThatCannotBeConverted(self): | |
| 461 | 461 | program = self.program | |
| 462 | - # even on Windows '/...' is considered absolute by os.path.abspath | ||
| 463 | - argv = ['progname', '/foo/bar/baz.py', '/green/red.py'] | ||
| 462 | + drive = os.path.splitdrive(os.getcwd())[0] | ||
| 463 | + argv = ['progname', f'{drive}/foo/bar/baz.py', f'{drive}/green/red.py'] | ||
| 464 | 464 | self._patch_isfile(argv) | |
| 465 | 465 | ||
| 466 | 466 | program.createTests = lambda: None | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -36,6 +36,7 @@ | |||
| 36 | 36 | TEMP_DIR = None | |
| 37 | 37 | DATA_DIR = pathlib.Path(__file__).parent / "data" | |
| 38 | 38 | ZONEINFO_JSON = DATA_DIR / "zoneinfo_data.json" | |
| 39 | + DRIVE = os.path.splitdrive('x:')[0] | ||
| 39 | 40 | ||
| 40 | 41 | # Useful constants | |
| 41 | 42 | ZERO = timedelta(0) | |
@@ -1679,8 +1680,8 @@ def test_env_variable(self): | |||
| 1679 | 1680 | """Tests that the environment variable works with reset_tzpath.""" | |
| 1680 | 1681 | new_paths = [ | |
| 1681 | 1682 | ("", []), | |
| 1682 | - ("/etc/zoneinfo", ["/etc/zoneinfo"]), | ||
| 1683 | - (f"/a/b/c{os.pathsep}/d/e/f", ["/a/b/c", "/d/e/f"]), | ||
| 1683 | + (f"{DRIVE}/etc/zoneinfo", [f"{DRIVE}/etc/zoneinfo"]), | ||
| 1684 | + (f"{DRIVE}/a/b/c{os.pathsep}{DRIVE}/d/e/f", [f"{DRIVE}/a/b/c", f"{DRIVE}/d/e/f"]), | ||
| 1684 | 1685 | ] | |
| 1685 | 1686 | ||
| 1686 | 1687 | for new_path_var, expected_result in new_paths: | |
@@ -1694,22 +1695,22 @@ def test_env_variable_relative_paths(self): | |||
| 1694 | 1695 | test_cases = [ | |
| 1695 | 1696 | [("path/to/somewhere",), ()], | |
| 1696 | 1697 | [ | |
| 1697 | - ("/usr/share/zoneinfo", "path/to/somewhere",), | ||
| 1698 | - ("/usr/share/zoneinfo",), | ||
| 1698 | + (f"{DRIVE}/usr/share/zoneinfo", "path/to/somewhere",), | ||
| 1699 | + (f"{DRIVE}/usr/share/zoneinfo",), | ||
| 1699 | 1700 | ], | |
| 1700 | 1701 | [("../relative/path",), ()], | |
| 1701 | 1702 | [ | |
| 1702 | - ("/usr/share/zoneinfo", "../relative/path",), | ||
| 1703 | - ("/usr/share/zoneinfo",), | ||
| 1703 | + (f"{DRIVE}/usr/share/zoneinfo", "../relative/path",), | ||
| 1704 | + (f"{DRIVE}/usr/share/zoneinfo",), | ||
| 1704 | 1705 | ], | |
| 1705 | 1706 | [("path/to/somewhere", "../relative/path",), ()], | |
| 1706 | 1707 | [ | |
| 1707 | 1708 | ( | |
| 1708 | - "/usr/share/zoneinfo", | ||
| 1709 | + f"{DRIVE}/usr/share/zoneinfo", | ||
| 1709 | 1710 | "path/to/somewhere", | |
| 1710 | 1711 | "../relative/path", | |
| 1711 | 1712 | ), | |
| 1712 | - ("/usr/share/zoneinfo",), | ||
| 1713 | + (f"{DRIVE}/usr/share/zoneinfo",), | ||
| 1713 | 1714 | ], | |
| 1714 | 1715 | ] | |
| 1715 | 1716 | ||
@@ -1727,9 +1728,9 @@ def test_env_variable_relative_paths(self): | |||
| 1727 | 1728 | self.assertSequenceEqual(tzpath, expected_paths) | |
| 1728 | 1729 | ||
| 1729 | 1730 | def test_reset_tzpath_kwarg(self): | |
| 1730 | - self.module.reset_tzpath(to=["/a/b/c"]) | ||
| 1731 | + self.module.reset_tzpath(to=[f"{DRIVE}/a/b/c"]) | ||
| 1731 | 1732 | ||
| 1732 | - self.assertSequenceEqual(self.module.TZPATH, ("/a/b/c",)) | ||
| 1733 | + self.assertSequenceEqual(self.module.TZPATH, (f"{DRIVE}/a/b/c",)) | ||
| 1733 | 1734 | ||
| 1734 | 1735 | def test_reset_tzpath_relative_paths(self): | |
| 1735 | 1736 | bad_values = [ | |
@@ -1758,8 +1759,8 @@ def test_tzpath_type_error(self): | |||
| 1758 | 1759 | self.module.reset_tzpath(bad_value) | |
| 1759 | 1760 | ||
| 1760 | 1761 | def test_tzpath_attribute(self): | |
| 1761 | - tzpath_0 = ["/one", "/two"] | ||
| 1762 | - tzpath_1 = ["/three"] | ||
| 1762 | + tzpath_0 = [f"{DRIVE}/one", f"{DRIVE}/two"] | ||
| 1763 | + tzpath_1 = [f"{DRIVE}/three"] | ||
| 1763 | 1764 | ||
| 1764 | 1765 | with self.tzpath_context(tzpath_0): | |
| 1765 | 1766 | query_0 = self.module.TZPATH | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,5 @@ | |||
| 1 | + Fix :func:`os.path.isabs` incorrectly returning ``True`` when given a path | ||
| 2 | + that starts with exactly one (back)slash on Windows. | ||
| 3 | + | ||
| 4 | + Fix :meth:`pathlib.PureWindowsPath.is_absolute` incorrectly returning | ||
| 5 | + ``False`` for some paths beginning with two (back)slashes. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments