bpo-28682: Added support for bytes paths in os.fwalk(). (#489)
This commit is contained in:
parent
8886d5f392
commit
8f6b344d36
|
@ -2840,6 +2840,9 @@ features:
|
||||||
.. versionchanged:: 3.6
|
.. versionchanged:: 3.6
|
||||||
Accepts a :term:`path-like object`.
|
Accepts a :term:`path-like object`.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.7
|
||||||
|
Added support for :class:`bytes` paths.
|
||||||
|
|
||||||
|
|
||||||
Linux extended attributes
|
Linux extended attributes
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -97,6 +97,12 @@ New Modules
|
||||||
Improved Modules
|
Improved Modules
|
||||||
================
|
================
|
||||||
|
|
||||||
|
os
|
||||||
|
--
|
||||||
|
|
||||||
|
Added support for :class:`bytes` paths in :func:`~os.fwalk`.
|
||||||
|
(Contributed by Serhiy Storchaka in :issue:`28682`.)
|
||||||
|
|
||||||
unittest.mock
|
unittest.mock
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
10
Lib/os.py
10
Lib/os.py
|
@ -460,16 +460,19 @@ if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd:
|
||||||
try:
|
try:
|
||||||
if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
|
if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
|
||||||
path.samestat(orig_st, stat(topfd)))):
|
path.samestat(orig_st, stat(topfd)))):
|
||||||
yield from _fwalk(topfd, top, topdown, onerror, follow_symlinks)
|
yield from _fwalk(topfd, top, isinstance(top, bytes),
|
||||||
|
topdown, onerror, follow_symlinks)
|
||||||
finally:
|
finally:
|
||||||
close(topfd)
|
close(topfd)
|
||||||
|
|
||||||
def _fwalk(topfd, toppath, topdown, onerror, follow_symlinks):
|
def _fwalk(topfd, toppath, isbytes, topdown, onerror, follow_symlinks):
|
||||||
# Note: This uses O(depth of the directory tree) file descriptors: if
|
# Note: This uses O(depth of the directory tree) file descriptors: if
|
||||||
# necessary, it can be adapted to only require O(1) FDs, see issue
|
# necessary, it can be adapted to only require O(1) FDs, see issue
|
||||||
# #13734.
|
# #13734.
|
||||||
|
|
||||||
names = listdir(topfd)
|
names = listdir(topfd)
|
||||||
|
if isbytes:
|
||||||
|
names = map(fsencode, names)
|
||||||
dirs, nondirs = [], []
|
dirs, nondirs = [], []
|
||||||
for name in names:
|
for name in names:
|
||||||
try:
|
try:
|
||||||
|
@ -504,7 +507,8 @@ if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd:
|
||||||
try:
|
try:
|
||||||
if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
|
if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
|
||||||
dirpath = path.join(toppath, name)
|
dirpath = path.join(toppath, name)
|
||||||
yield from _fwalk(dirfd, dirpath, topdown, onerror, follow_symlinks)
|
yield from _fwalk(dirfd, dirpath, isbytes,
|
||||||
|
topdown, onerror, follow_symlinks)
|
||||||
finally:
|
finally:
|
||||||
close(dirfd)
|
close(dirfd)
|
||||||
|
|
||||||
|
|
|
@ -1010,9 +1010,12 @@ class FwalkTests(WalkTests):
|
||||||
"""Tests for os.fwalk()."""
|
"""Tests for os.fwalk()."""
|
||||||
|
|
||||||
def walk(self, top, **kwargs):
|
def walk(self, top, **kwargs):
|
||||||
for root, dirs, files, root_fd in os.fwalk(top, **kwargs):
|
for root, dirs, files, root_fd in self.fwalk(top, **kwargs):
|
||||||
yield (root, dirs, files)
|
yield (root, dirs, files)
|
||||||
|
|
||||||
|
def fwalk(self, *args, **kwargs):
|
||||||
|
return os.fwalk(*args, **kwargs)
|
||||||
|
|
||||||
def _compare_to_walk(self, walk_kwargs, fwalk_kwargs):
|
def _compare_to_walk(self, walk_kwargs, fwalk_kwargs):
|
||||||
"""
|
"""
|
||||||
compare with walk() results.
|
compare with walk() results.
|
||||||
|
@ -1027,7 +1030,7 @@ class FwalkTests(WalkTests):
|
||||||
for root, dirs, files in os.walk(**walk_kwargs):
|
for root, dirs, files in os.walk(**walk_kwargs):
|
||||||
expected[root] = (set(dirs), set(files))
|
expected[root] = (set(dirs), set(files))
|
||||||
|
|
||||||
for root, dirs, files, rootfd in os.fwalk(**fwalk_kwargs):
|
for root, dirs, files, rootfd in self.fwalk(**fwalk_kwargs):
|
||||||
self.assertIn(root, expected)
|
self.assertIn(root, expected)
|
||||||
self.assertEqual(expected[root], (set(dirs), set(files)))
|
self.assertEqual(expected[root], (set(dirs), set(files)))
|
||||||
|
|
||||||
|
@ -1049,7 +1052,7 @@ class FwalkTests(WalkTests):
|
||||||
# check returned file descriptors
|
# check returned file descriptors
|
||||||
for topdown, follow_symlinks in itertools.product((True, False), repeat=2):
|
for topdown, follow_symlinks in itertools.product((True, False), repeat=2):
|
||||||
args = support.TESTFN, topdown, None
|
args = support.TESTFN, topdown, None
|
||||||
for root, dirs, files, rootfd in os.fwalk(*args, follow_symlinks=follow_symlinks):
|
for root, dirs, files, rootfd in self.fwalk(*args, follow_symlinks=follow_symlinks):
|
||||||
# check that the FD is valid
|
# check that the FD is valid
|
||||||
os.fstat(rootfd)
|
os.fstat(rootfd)
|
||||||
# redundant check
|
# redundant check
|
||||||
|
@ -1064,7 +1067,7 @@ class FwalkTests(WalkTests):
|
||||||
minfd = os.dup(1)
|
minfd = os.dup(1)
|
||||||
os.close(minfd)
|
os.close(minfd)
|
||||||
for i in range(256):
|
for i in range(256):
|
||||||
for x in os.fwalk(support.TESTFN):
|
for x in self.fwalk(support.TESTFN):
|
||||||
pass
|
pass
|
||||||
newfd = os.dup(1)
|
newfd = os.dup(1)
|
||||||
self.addCleanup(os.close, newfd)
|
self.addCleanup(os.close, newfd)
|
||||||
|
@ -1072,14 +1075,6 @@ class FwalkTests(WalkTests):
|
||||||
|
|
||||||
class BytesWalkTests(WalkTests):
|
class BytesWalkTests(WalkTests):
|
||||||
"""Tests for os.walk() with bytes."""
|
"""Tests for os.walk() with bytes."""
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
self.stack = contextlib.ExitStack()
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
self.stack.close()
|
|
||||||
super().tearDown()
|
|
||||||
|
|
||||||
def walk(self, top, **kwargs):
|
def walk(self, top, **kwargs):
|
||||||
if 'follow_symlinks' in kwargs:
|
if 'follow_symlinks' in kwargs:
|
||||||
kwargs['followlinks'] = kwargs.pop('follow_symlinks')
|
kwargs['followlinks'] = kwargs.pop('follow_symlinks')
|
||||||
|
@ -1091,6 +1086,18 @@ class BytesWalkTests(WalkTests):
|
||||||
bdirs[:] = list(map(os.fsencode, dirs))
|
bdirs[:] = list(map(os.fsencode, dirs))
|
||||||
bfiles[:] = list(map(os.fsencode, files))
|
bfiles[:] = list(map(os.fsencode, files))
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(os, 'fwalk'), "Test needs os.fwalk()")
|
||||||
|
class BytesFwalkTests(FwalkTests):
|
||||||
|
"""Tests for os.walk() with bytes."""
|
||||||
|
def fwalk(self, top='.', *args, **kwargs):
|
||||||
|
for broot, bdirs, bfiles, topfd in os.fwalk(os.fsencode(top), *args, **kwargs):
|
||||||
|
root = os.fsdecode(broot)
|
||||||
|
dirs = list(map(os.fsdecode, bdirs))
|
||||||
|
files = list(map(os.fsdecode, bfiles))
|
||||||
|
yield (root, dirs, files, topfd)
|
||||||
|
bdirs[:] = list(map(os.fsencode, dirs))
|
||||||
|
bfiles[:] = list(map(os.fsencode, files))
|
||||||
|
|
||||||
|
|
||||||
class MakedirTests(unittest.TestCase):
|
class MakedirTests(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -265,6 +265,8 @@ Extension Modules
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- bpo-28682: Added support for bytes paths in os.fwalk().
|
||||||
|
|
||||||
- bpo-29623: Allow use of path-like object as a single argument in
|
- bpo-29623: Allow use of path-like object as a single argument in
|
||||||
ConfigParser.read(). Patch by David Ellis.
|
ConfigParser.read(). Patch by David Ellis.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue