cpython: b64f83d6ff24 (original) (raw)

Mercurial > cpython

changeset 102920:b64f83d6ff24

Issue #26027, #27524: Add PEP 519/__fspath__() support to os and os.path. Thanks to Jelle Zijlstra for the initial patch against posixmodule.c. [#26027]

Brett Cannon brett@python.org
date Fri, 26 Aug 2016 14:44:48 -0700
parents 685f32972c11
children 95361959d451
files Lib/genericpath.py Lib/ntpath.py Lib/os.py Lib/posixpath.py Lib/test/test_genericpath.py Lib/test/test_ntpath.py Lib/test/test_os.py Lib/test/test_posix.py Lib/test/test_posixpath.py Misc/NEWS Modules/posixmodule.c
diffstat 11 files changed, 428 insertions(+), 56 deletions(-)[+] [-] Lib/genericpath.py 6 Lib/ntpath.py 18 Lib/os.py 4 Lib/posixpath.py 19 Lib/test/test_genericpath.py 64 Lib/test/test_ntpath.py 83 Lib/test/test_os.py 83 Lib/test/test_posix.py 10 Lib/test/test_posixpath.py 80 Misc/NEWS 5 Modules/posixmodule.c 112

line wrap: on

line diff

--- a/Lib/genericpath.py +++ b/Lib/genericpath.py @@ -69,6 +69,12 @@ def getctime(filename): def commonprefix(m): "Given a list of pathnames, returns the longest common leading component" if not m: return ''

--- a/Lib/ntpath.py +++ b/Lib/ntpath.py @@ -46,6 +46,7 @@ def normcase(s): """Normalize case of pathname. Makes all characters lowercase and all slashes into backslashes."""

@@ -66,12 +67,14 @@ def normcase(s): def isabs(s): """Test whether a path is absolute"""

Join two (or more) paths.

def join(path, *paths):

@@ -84,7 +87,7 @@ def join(path, *paths): if not paths: path[:0] + sep #23780: Ensure compatible data type even if p is null. result_drive, result_path = splitdrive(path)

@@ -136,6 +139,7 @@ def splitdrive(p): Paths cannot contain both a drive letter and a UNC path. """

@@ -199,7 +203,7 @@ def split(p): Return tuple (head, tail) where tail is everything after the final slash. Either part may be empty.""" -

@@ -218,6 +222,7 @@ def split(p):

It is always true that root + ext == p.

def splitext(p):

@@ -464,6 +472,7 @@ def expandvars(path): def normpath(path): """Normalize path, eliminating double slashes, etc."""

@@ -518,6 +527,7 @@ try: except ImportError: # not running on Windows - mock up something sensible def abspath(path): """Return the absolute version of a path."""

@@ -531,6 +541,7 @@ else: # use native Windows method on Wi """Return the absolute version of a path.""" if path: # Empty path must return current working directory.

@@ -549,6 +560,7 @@ supports_unicode_filenames = (hasattr(sy def relpath(path, start=None): """Return a relative version of a path"""

@@ -564,6 +576,7 @@ def relpath(path, start=None): if not path: raise ValueError("no path specified")

@@ -607,6 +620,7 @@ def commonpath(paths): if not paths: raise ValueError('commonpath() arg is an empty sequence')

--- a/Lib/os.py +++ b/Lib/os.py @@ -353,7 +353,7 @@ def walk(top, topdown=True, onerror=None dirs.remove('CVS') # don't visit CVS directories """ -

--- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -49,6 +49,7 @@ def _get_sep(path): def normcase(s): """Normalize case of pathname. Has no effect under Posix"""

@@ -60,6 +61,7 @@ def normcase(s): def isabs(s): """Test whether a path is absolute"""

@@ -99,6 +102,7 @@ def join(a, *p): def split(p): """Split a pathname. Returns tuple "(head, tail)" where "tail" is everything after the final slash. Either part may be empty."""

It is always true that root + ext == p.

def splitext(p):

@@ -128,6 +133,7 @@ splitext.doc = genericpath._splitext def splitdrive(p): """Split a pathname into drive and path. On Posix, drive is always empty."""

@@ -318,6 +328,7 @@ def expandvars(path): def normpath(path): """Normalize path, eliminating double slashes, etc."""

@@ -355,6 +366,7 @@ def normpath(path): def abspath(path): """Return an absolute path."""

@@ -370,6 +382,7 @@ def abspath(path): def realpath(filename): """Return the canonical path of the specified filename, eliminating any symbolic links encountered in the path."""

@@ -445,6 +459,8 @@ def relpath(path, start=None): if start is None: start = curdir

try: start_list = [x for x in abspath(start).split(sep) if x] @@ -472,6 +488,7 @@ def commonpath(paths): if not paths: raise ValueError('commonpath() arg is an empty sequence')

--- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -450,16 +450,15 @@ class CommonTest(GenericTest): with self.assertRaisesRegex(TypeError, errmsg): self.pathmodule.join('str', b'bytes') # regression, see #15377

def test_relpath_errors(self): @@ -471,14 +470,59 @@ class CommonTest(GenericTest): self.pathmodule.relpath(b'bytes', 'str') with self.assertRaisesRegex(TypeError, errmsg): self.pathmodule.relpath('str', b'bytes')

+class PathLikeTests(unittest.TestCase): +

+

+

+

+

+

+

+

+

+

+

+ + if name=="main": unittest.main()

--- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -452,5 +452,88 @@ class NtCommonTest(test_genericpath.Comm attributes = ['relpath', 'splitunc'] +class PathLikeTests(unittest.TestCase): +

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+ + if name == "main": unittest.main()

--- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -874,10 +874,12 @@ class WalkTests(unittest.TestCase): self.assertEqual(all[2 + flipped], (self.sub11_path, [], [])) self.assertEqual(all[3 - 2 * flipped], self.sub2_tree)

@@ -886,11 +888,22 @@ class WalkTests(unittest.TestCase): self.assertEqual(len(all), 2) self.assertEqual(all[0],

all[1][-1].sort() self.assertEqual(all[1], self.sub2_tree)

+

+ def test_walk_bottom_up(self): # Walk bottom-up. all = list(self.walk(self.walk_path, topdown=False)) @@ -2807,6 +2820,70 @@ class FDInheritanceTests(unittest.TestCa self.assertEqual(os.get_inheritable(slave_fd), False) +class PathTConverterTests(unittest.TestCase):

+

+

+

+

+

+

+

+

+ + @unittest.skipUnless(hasattr(os, 'get_blocking'), 'needs os.get_blocking() and os.set_blocking()') class BlockingTests(unittest.TestCase):

--- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -397,7 +397,7 @@ class PosixTester(unittest.TestCase): self.assertTrue(posix.stat(fp.fileno())) self.assertRaisesRegex(TypeError,

@@ -409,16 +409,16 @@ class PosixTester(unittest.TestCase): self.assertTrue(posix.stat(os.fsencode(support.TESTFN))) self.assertWarnsRegex(DeprecationWarning,

@unittest.skipUnless(hasattr(posix, 'mkfifo'), "don't have mkfifo()")

--- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -596,5 +596,85 @@ class PosixCommonTest(test_genericpath.C attributes = ['relpath', 'samefile', 'sameopenfile', 'samestat'] +class PathLikeTests(unittest.TestCase): +

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+ + if name=="main": unittest.main()

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -142,7 +142,10 @@ Core and Builtins Library ------- -- Issue 27598: Add Collections to collections.abc. +- Issue #26027, #27524: Add PEP 519/fspath() support to the os and os.path

--- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -834,8 +834,11 @@ static int path_converter(PyObject *o, void *p) { path_t *path = (path_t *)p;

#define FORMAT_EXCEPTION(exc, fmt) [](#l11.15) @@ -850,7 +853,7 @@ path_converter(PyObject *o, void *p) return 1; }

+

+

+

+

#ifdef MS_WINDOWS const wchar_t *wide; wide = PyUnicode_AsUnicodeAndSize(o, &length); if (!wide) {

path->wide = wide; @@ -884,66 +920,71 @@ path_converter(PyObject *o, void *p) path->length = length; path->object = o; path->fd = -1;

#else if (!PyUnicode_FSConverter(o, &bytes)) {

-#endif

+#endif

#ifdef MS_WINDOWS if (win32_warn_bytes_api()) {

#endif bytes = o; Py_INCREF(bytes); }

#ifdef MS_WINDOWS if (win32_warn_bytes_api()) {

#endif bytes = PyBytes_FromObject(o); if (!bytes) {

#endif @@ -959,7 +1000,7 @@ path_converter(PyObject *o, void *p) if ((size_t)length != strlen(narrow)) { FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s"); Py_DECREF(bytes);

} static void @@ -12329,6 +12373,8 @@ error: PyObject * PyOS_FSPath(PyObject *path) {