diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst index b6507eb4d6fa2c..7ab603fd133b86 100644 --- a/Doc/library/pathlib.rst +++ b/Doc/library/pathlib.rst @@ -1052,6 +1052,18 @@ call fails (for example because the path doesn't exist). Added return value, return the new Path instance. +.. method:: Path.absolute() + + Make the path absolute, without normalization or resolving symlinks. + Returns a new path object:: + + >>> p = Path('tests') + >>> p + PosixPath('tests') + >>> p.absolute() + PosixPath('/home/antoine/pathlib/tests') + + .. method:: Path.resolve(strict=False) Make the path absolute, resolving any symlinks. A new path object is @@ -1239,13 +1251,14 @@ Below is a table mapping various :mod:`os` functions to their corresponding Not all pairs of functions/methods below are equivalent. Some of them, despite having some overlapping use-cases, have different semantics. They - include :func:`os.path.abspath` and :meth:`Path.resolve`, + include :func:`os.path.abspath` and :meth:`Path.absolute`, :func:`os.path.relpath` and :meth:`PurePath.relative_to`. ==================================== ============================== :mod:`os` and :mod:`os.path` :mod:`pathlib` ==================================== ============================== -:func:`os.path.abspath` :meth:`Path.resolve` [#]_ +:func:`os.path.abspath` :meth:`Path.absolute` [#]_ +:func:`os.path.realpath` :meth:`Path.resolve` :func:`os.chmod` :meth:`Path.chmod` :func:`os.mkdir` :meth:`Path.mkdir` :func:`os.makedirs` :meth:`Path.mkdir` @@ -1278,5 +1291,5 @@ Below is a table mapping various :mod:`os` functions to their corresponding .. rubric:: Footnotes -.. [#] :func:`os.path.abspath` does not resolve symbolic links while :meth:`Path.resolve` does. +.. [#] :func:`os.path.abspath` normalizes the resulting path, which may change its meaning in the presence of symlinks, while :meth:`Path.absolute` does not. .. [#] :meth:`Path.relative_to` requires ``self`` to be the subpath of the argument, but :func:`os.path.relpath` does not. diff --git a/Lib/pathlib.py b/Lib/pathlib.py index f1a33178e2958b..8caa7c02ee80c4 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -1046,24 +1046,19 @@ def rglob(self, pattern): yield p def absolute(self): - """Return an absolute version of this path. This function works - even if the path doesn't point to anything. + """Return an absolute version of this path by prepending the current + working directory. No normalization or symlink resolution is performed. - No normalization is done, i.e. all '.' and '..' will be kept along. Use resolve() to get the canonical path to a file. """ - # XXX untested yet! if self.is_absolute(): return self - # FIXME this must defer to the specific flavour (and, under Windows, - # use nt._getfullpathname()) return self._from_parts([self._accessor.getcwd()] + self._parts) def resolve(self, strict=False): """ Make the path absolute, resolving all symlinks on the way and also - normalizing it (for example turning slashes into backslashes under - Windows). + normalizing it. """ def check_eloop(e): diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 555c7ee795bd12..d004c38211c48e 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -1456,6 +1456,28 @@ def test_cwd(self): p = self.cls.cwd() self._test_cwd(p) + def test_absolute_common(self): + P = self.cls + + with mock.patch("pathlib._normal_accessor.getcwd") as getcwd: + getcwd.return_value = BASE + + # Simple relative paths. + self.assertEqual(str(P().absolute()), BASE) + self.assertEqual(str(P('.').absolute()), BASE) + self.assertEqual(str(P('a').absolute()), os.path.join(BASE, 'a')) + self.assertEqual(str(P('a', 'b', 'c').absolute()), os.path.join(BASE, 'a', 'b', 'c')) + + # Symlinks should not be resolved. + self.assertEqual(str(P('linkB', 'fileB').absolute()), os.path.join(BASE, 'linkB', 'fileB')) + self.assertEqual(str(P('brokenLink').absolute()), os.path.join(BASE, 'brokenLink')) + self.assertEqual(str(P('brokenLinkLoop').absolute()), os.path.join(BASE, 'brokenLinkLoop')) + + # '..' entries should be preserved and not normalised. + self.assertEqual(str(P('..').absolute()), os.path.join(BASE, '..')) + self.assertEqual(str(P('a', '..').absolute()), os.path.join(BASE, 'a', '..')) + self.assertEqual(str(P('..', 'b').absolute()), os.path.join(BASE, '..', 'b')) + def _test_home(self, p): q = self.cls(os.path.expanduser('~')) self.assertEqual(p, q) @@ -2457,6 +2479,17 @@ def test_glob_empty_pattern(self): class PosixPathTest(_BasePathTest, unittest.TestCase): cls = pathlib.PosixPath + def test_absolute(self): + P = self.cls + self.assertEqual(str(P('/').absolute()), '/') + self.assertEqual(str(P('/a').absolute()), '/a') + self.assertEqual(str(P('/a/b').absolute()), '/a/b') + + # '//'-prefixed absolute path (supported by POSIX). + self.assertEqual(str(P('//').absolute()), '//') + self.assertEqual(str(P('//a').absolute()), '//a') + self.assertEqual(str(P('//a/b').absolute()), '//a/b') + def _check_symlink_loop(self, *args, strict=True): path = self.cls(*args) with self.assertRaises(RuntimeError): @@ -2622,6 +2655,31 @@ def test_handling_bad_descriptor(self): class WindowsPathTest(_BasePathTest, unittest.TestCase): cls = pathlib.WindowsPath + def test_absolute(self): + P = self.cls + + # Simple absolute paths. + self.assertEqual(str(P('c:\\').absolute()), 'c:\\') + self.assertEqual(str(P('c:\\a').absolute()), 'c:\\a') + self.assertEqual(str(P('c:\\a\\b').absolute()), 'c:\\a\\b') + + # UNC absolute paths. + share = '\\\\server\\share\\' + self.assertEqual(str(P(share).absolute()), share) + self.assertEqual(str(P(share + 'a').absolute()), share + 'a') + self.assertEqual(str(P(share + 'a\\b').absolute()), share + 'a\\b') + + # UNC relative paths. + with mock.patch("pathlib._normal_accessor.getcwd") as getcwd: + getcwd.return_value = share + + self.assertEqual(str(P().absolute()), share) + self.assertEqual(str(P('.').absolute()), share) + self.assertEqual(str(P('a').absolute()), os.path.join(share, 'a')) + self.assertEqual(str(P('a', 'b', 'c').absolute()), + os.path.join(share, 'a', 'b', 'c')) + + def test_glob(self): P = self.cls p = P(BASE) diff --git a/Misc/NEWS.d/next/Library/2022-01-05-03-21-21.bpo-29688.W06bSH.rst b/Misc/NEWS.d/next/Library/2022-01-05-03-21-21.bpo-29688.W06bSH.rst new file mode 100644 index 00000000000000..1a202e59b075e7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-05-03-21-21.bpo-29688.W06bSH.rst @@ -0,0 +1 @@ +Document :meth:`pathlib.Path.absolute` (which has always existed). pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy