[3.6] bpo-30879: os.listdir() and os.scandir() now emit bytes names when (GH-2634) (#2656)

called with bytes-like argument..
(cherry picked from commit 1180e5a518)
This commit is contained in:
Serhiy Storchaka 2017-07-11 07:16:11 +03:00 committed by GitHub
parent fe6e686c27
commit ecfe4f678b
4 changed files with 35 additions and 6 deletions

View file

@ -3402,6 +3402,22 @@ class TestScandir(unittest.TestCase):
self.assertEqual(entry.path, self.assertEqual(entry.path,
os.fsencode(os.path.join(self.path, 'file.txt'))) os.fsencode(os.path.join(self.path, 'file.txt')))
def test_bytes_like(self):
self.create_file("file.txt")
for cls in bytearray, memoryview:
path_bytes = cls(os.fsencode(self.path))
with self.assertWarns(DeprecationWarning):
entries = list(os.scandir(path_bytes))
self.assertEqual(len(entries), 1, entries)
entry = entries[0]
self.assertEqual(entry.name, b'file.txt')
self.assertEqual(entry.path,
os.fsencode(os.path.join(self.path, 'file.txt')))
self.assertIs(type(entry.name), bytes)
self.assertIs(type(entry.path), bytes)
def test_empty_path(self): def test_empty_path(self):
self.assertRaises(FileNotFoundError, os.scandir, '') self.assertRaises(FileNotFoundError, os.scandir, '')

View file

@ -581,17 +581,25 @@ class PosixTester(unittest.TestCase):
self.assertRaises(OSError, posix.chdir, support.TESTFN) self.assertRaises(OSError, posix.chdir, support.TESTFN)
def test_listdir(self): def test_listdir(self):
self.assertTrue(support.TESTFN in posix.listdir(os.curdir)) self.assertIn(support.TESTFN, posix.listdir(os.curdir))
def test_listdir_default(self): def test_listdir_default(self):
# When listdir is called without argument, # When listdir is called without argument,
# it's the same as listdir(os.curdir). # it's the same as listdir(os.curdir).
self.assertTrue(support.TESTFN in posix.listdir()) self.assertIn(support.TESTFN, posix.listdir())
def test_listdir_bytes(self): def test_listdir_bytes(self):
# When listdir is called with a bytes object, # When listdir is called with a bytes object,
# the returned strings are of type bytes. # the returned strings are of type bytes.
self.assertTrue(os.fsencode(support.TESTFN) in posix.listdir(b'.')) self.assertIn(os.fsencode(support.TESTFN), posix.listdir(b'.'))
def test_listdir_bytes_like(self):
for cls in bytearray, memoryview:
with self.assertWarns(DeprecationWarning):
names = posix.listdir(cls(b'.'))
self.assertIn(os.fsencode(support.TESTFN), names)
for name in names:
self.assertIs(type(name), bytes)
@unittest.skipUnless(posix.listdir in os.supports_fd, @unittest.skipUnless(posix.listdir in os.supports_fd,
"test needs fd support for posix.listdir()") "test needs fd support for posix.listdir()")

View file

@ -18,6 +18,9 @@ Core and Builtins
Library Library
------- -------
- bpo-30879: os.listdir() and os.scandir() now emit bytes names when called
with bytes-like argument.
- bpo-30746: Prohibited the '=' character in environment variable names in - bpo-30746: Prohibited the '=' character in environment variable names in
``os.putenv()`` and ``os.spawn*()``. ``os.putenv()`` and ``os.spawn*()``.

View file

@ -949,6 +949,8 @@ path_converter(PyObject *o, void *p)
Py_INCREF(bytes); Py_INCREF(bytes);
} }
else if (is_buffer) { else if (is_buffer) {
/* XXX Replace PyObject_CheckBuffer with PyBytes_Check in other code
after removing suport of non-bytes buffer objects. */
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"%s%s%s should be %s, not %.200s", "%s%s%s should be %s, not %.200s",
path->function_name ? path->function_name : "", path->function_name ? path->function_name : "",
@ -3511,8 +3513,8 @@ _posix_listdir(path_t *path, PyObject *list)
const char *name; const char *name;
if (path->narrow) { if (path->narrow) {
name = path->narrow; name = path->narrow;
/* only return bytes if they specified a bytes object */ /* only return bytes if they specified a bytes-like object */
return_str = !(PyBytes_Check(path->object)); return_str = !PyObject_CheckBuffer(path->object);
} }
else { else {
name = "."; name = ".";
@ -11708,7 +11710,7 @@ DirEntry_from_posix_info(path_t *path, const char *name, Py_ssize_t name_len,
if (!joined_path) if (!joined_path)
goto error; goto error;
if (!path->narrow || !PyBytes_Check(path->object)) { if (!path->narrow || !PyObject_CheckBuffer(path->object)) {
entry->name = PyUnicode_DecodeFSDefaultAndSize(name, name_len); entry->name = PyUnicode_DecodeFSDefaultAndSize(name, name_len);
entry->path = PyUnicode_DecodeFSDefault(joined_path); entry->path = PyUnicode_DecodeFSDefault(joined_path);
} }