From d73c31899e88aa5a1cc28f288cc70a35f2a196c2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 6 Aug 2016 23:22:08 +0300 Subject: [PATCH] Issue #26800: Undocumented support of general bytes-like objects as paths in os functions is now deprecated. --- Doc/whatsnew/3.6.rst | 5 +++++ Lib/test/test_os.py | 9 ++++++++- Lib/test/test_posix.py | 4 +++- Misc/NEWS | 3 +++ Modules/posixmodule.c | 31 +++++++++++++++++++++++++++++-- 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index 7a318e4ca12..7603fa12203 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -638,6 +638,11 @@ Deprecated features and will be removed in 3.8. (Contributed by Serhiy Storchaka in :issue:`21708`.) +* Undocumented support of general :term:`bytes-like objects ` + as paths in :mod:`os` functions is now deprecated. + (Contributed by Serhiy Storchaka in :issue:`25791`.) + + Deprecated Python behavior -------------------------- diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index aa9b5387484..d8920d99c51 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2626,6 +2626,7 @@ class OSErrorTests(unittest.TestCase): else: encoded = os.fsencode(support.TESTFN) self.bytes_filenames.append(encoded) + self.bytes_filenames.append(bytearray(encoded)) self.bytes_filenames.append(memoryview(encoded)) self.filenames = self.bytes_filenames + self.unicode_filenames @@ -2699,8 +2700,14 @@ class OSErrorTests(unittest.TestCase): for filenames, func, *func_args in funcs: for name in filenames: try: - with bytes_filename_warn(False): + if isinstance(name, str): func(name, *func_args) + elif isinstance(name, bytes): + with bytes_filename_warn(False): + func(name, *func_args) + else: + with self.assertWarnsRegex(DeprecationWarning, 'should be'): + func(name, *func_args) except OSError as err: self.assertIs(err.filename, name) else: diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py index 6a1c82917a9..de22513e34e 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -407,8 +407,10 @@ class PosixTester(unittest.TestCase): def test_stat(self): self.assertTrue(posix.stat(support.TESTFN)) self.assertTrue(posix.stat(os.fsencode(support.TESTFN))) - self.assertTrue(posix.stat(bytearray(os.fsencode(support.TESTFN)))) + self.assertWarnsRegex(DeprecationWarning, + 'should be string, bytes or integer, not', + posix.stat, bytearray(os.fsencode(support.TESTFN))) self.assertRaisesRegex(TypeError, 'should be string, bytes or integer, not', posix.stat, None) diff --git a/Misc/NEWS b/Misc/NEWS index 9c60247f302..03a8104a34b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -43,6 +43,9 @@ Core and Builtins Library ------- +- Issue #26800: Undocumented support of general bytes-like objects + as paths in os functions is now deprecated. + - Issue #27661: Added tzinfo keyword argument to datetime.combine. - Issue #27568: Prevent HTTPoxy attack (CVE-2016-1000110). Ignore the diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 6adc7f44dbf..52e465f1ffd 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -891,7 +891,28 @@ path_converter(PyObject *o, void *p) } #endif } + else if (PyBytes_Check(o)) { +#ifdef MS_WINDOWS + if (win32_warn_bytes_api()) { + return 0; + } +#endif + bytes = o; + Py_INCREF(bytes); + } else if (PyObject_CheckBuffer(o)) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "%s%s%s should be %s, not %.200s", + path->function_name ? path->function_name : "", + path->function_name ? ": " : "", + path->argument_name ? path->argument_name : "path", + path->allow_fd && path->nullable ? "string, bytes, integer or None" : + path->allow_fd ? "string, bytes or integer" : + path->nullable ? "string, bytes or None" : + "string or bytes", + Py_TYPE(o)->tp_name)) { + return 0; + } #ifdef MS_WINDOWS if (win32_warn_bytes_api()) { return 0; @@ -946,8 +967,14 @@ path_converter(PyObject *o, void *p) path->length = length; path->object = o; path->fd = -1; - path->cleanup = bytes; - return Py_CLEANUP_SUPPORTED; + if (bytes == o) { + Py_DECREF(bytes); + return 1; + } + else { + path->cleanup = bytes; + return Py_CLEANUP_SUPPORTED; + } } static void