diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -568,6 +568,10 @@ Porting Python code with sys.platform.startswith('linux'), or directly sys.platform == 'linux' if you don't need to support older Python versions. +* Issue #xxx: The Windows bytes API has been deprecated in the :mod:`os` + module. Use Unicode filenames instead of bytes filenames to not depend on the + ANSI code page anymore and to support any filename. + Porting C code -------------- diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py --- a/Lib/test/test_genericpath.py +++ b/Lib/test/test_genericpath.py @@ -2,11 +2,12 @@ Tests common to genericpath, macpath, ntpath and posixpath """ +import genericpath +import os +import sys import unittest +import warnings from test import support -import os -import genericpath -import sys def safe_rmdir(dirname): @@ -258,7 +259,9 @@ class CommonTest(GenericTest): def test_abspath(self): self.assertIn("foo", self.pathmodule.abspath("foo")) - self.assertIn(b"foo", self.pathmodule.abspath(b"foo")) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + self.assertIn(b"foo", self.pathmodule.abspath(b"foo")) # Abspath returns bytes when the arg is bytes for path in (b'', b'foo', b'f\xf2\xf2', b'/foo', b'C:\\'): @@ -266,7 +269,9 @@ class CommonTest(GenericTest): def test_realpath(self): self.assertIn("foo", self.pathmodule.realpath("foo")) - self.assertIn(b"foo", self.pathmodule.realpath(b"foo")) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + self.assertIn(b"foo", self.pathmodule.realpath(b"foo")) def test_normpath_issue5827(self): # Make sure normpath preserves unicode @@ -296,8 +301,10 @@ class CommonTest(GenericTest): "Mac OS X denies the creation of a directory with an invalid utf8 name") def test_nonascii_abspath(self): # Test non-ASCII, non-UTF8 bytes in the path. - with support.temp_cwd(b'\xe7w\xf0'): - self.test_abspath() + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + with support.temp_cwd(b'\xe7w\xf0'): + self.test_abspath() def test_main(): diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py --- a/Lib/test/test_ntpath.py +++ b/Lib/test/test_ntpath.py @@ -1,10 +1,11 @@ import ntpath import os import sys +import unittest +import warnings from test.support import TestFailed from test import support, test_genericpath from tempfile import TemporaryFile -import unittest def tester(fn, wantResult): @@ -21,7 +22,9 @@ def tester(fn, wantResult): fn = fn.replace('["', '[b"') fn = fn.replace(", '", ", b'") fn = fn.replace(', "', ', b"') - gotResult = eval(fn) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + gotResult = eval(fn) if isinstance(wantResult, str): wantResult = wantResult.encode('ascii') elif isinstance(wantResult, tuple): diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -213,7 +213,9 @@ class StatAttributeTests(unittest.TestCa fname = self.fname.encode(sys.getfilesystemencoding()) except UnicodeEncodeError: self.skipTest("cannot encode %a for the filesystem" % self.fname) - self.check_stat_attributes(fname) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + self.check_stat_attributes(fname) def test_statvfs_attributes(self): if not hasattr(os, "statvfs"): @@ -838,7 +840,9 @@ class LinkTests(unittest.TestCase): with open(file1, "w") as f1: f1.write("test") - os.link(file1, file2) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + os.link(file1, file2) with open(file1, "r") as f1, open(file2, "r") as f2: self.assertTrue(os.path.sameopenfile(f1.fileno(), f2.fileno())) @@ -1160,8 +1164,10 @@ class Win32SymlinkTests(unittest.TestCas self.assertNotEqual(os.lstat(link), os.stat(link)) bytes_link = os.fsencode(link) - self.assertEqual(os.stat(bytes_link), os.stat(target)) - self.assertNotEqual(os.lstat(bytes_link), os.stat(bytes_link)) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + self.assertEqual(os.stat(bytes_link), os.stat(target)) + self.assertNotEqual(os.lstat(bytes_link), os.stat(bytes_link)) def test_12084(self): level1 = os.path.abspath(support.TESTFN) @@ -1619,6 +1625,30 @@ class ExtendedAttributeTests(unittest.Te self._check_xattrs(getxattr, setxattr, removexattr, listxattr) +@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") +class Win32DeprecatedBytesAPI(unittest.TestCase): + def test_bla(self): + import nt + filename = os.fsencode(support.TESTFN) + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.assertRaises(DeprecationWarning, os.rename, filename, filename) + self.assertRaises(DeprecationWarning, os.stat, filename) + self.assertRaises(DeprecationWarning, os.lstat, filename) + self.assertRaises(DeprecationWarning, os.link, filename, filename) + self.assertRaises(DeprecationWarning, os.symlink, filename, filename) + self.assertRaises(DeprecationWarning, os.chdir, filename) + self.assertRaises(DeprecationWarning, os.rmdir, filename) + self.assertRaises(DeprecationWarning, os.unlink, filename) + self.assertRaises(DeprecationWarning, os.access, filename, os.R_OK) + self.assertRaises(DeprecationWarning, os.chmod, filename, 0o777) + self.assertRaises(DeprecationWarning, os.listdir, filename) + self.assertRaises(DeprecationWarning, os.mkdir, filename) + self.assertRaises(DeprecationWarning, os.utime, filename) + self.assertRaises(DeprecationWarning, nt._isdir, filename) + self.assertRaises(DeprecationWarning, nt._getfullpathname, filename) + + @support.reap_threads def test_main(): support.run_unittest( @@ -1643,6 +1673,7 @@ def test_main(): TestSendfile, ProgramPriorityTests, ExtendedAttributeTests, + Win32DeprecatedBytesAPI, ) if __name__ == "__main__": diff --git a/Lib/test/test_pep277.py b/Lib/test/test_pep277.py --- a/Lib/test/test_pep277.py +++ b/Lib/test/test_pep277.py @@ -1,6 +1,9 @@ # Test the Unicode versions of normal file functions # open, os.open, os.stat. os.listdir, os.rename, os.remove, os.mkdir, os.chdir, os.rmdir -import sys, os, unittest +import os +import sys +import unittest +import warnings from unicodedata import normalize from test import support @@ -155,7 +158,9 @@ class UnicodeFileTests(unittest.TestCase @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') def test_listdir(self): sf0 = set(self.files) - f1 = os.listdir(support.TESTFN.encode(sys.getfilesystemencoding())) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + f1 = os.listdir(support.TESTFN.encode(sys.getfilesystemencoding())) f2 = os.listdir(support.TESTFN) sf2 = set(os.path.join(support.TESTFN, f) for f in f2) self.assertEqual(sf0, sf2, "%a != %a" % (sf0, sf2)) diff --git a/Lib/test/test_posixpath.py b/Lib/test/test_posixpath.py --- a/Lib/test/test_posixpath.py +++ b/Lib/test/test_posixpath.py @@ -1,11 +1,11 @@ +import os +import posixpath +import sys import unittest +import warnings +from posixpath import realpath, abspath, dirname, basename from test import support, test_genericpath -import posixpath -import os -import sys -from posixpath import realpath, abspath, dirname, basename - try: import posix except ImportError: @@ -231,7 +231,9 @@ class PosixPathTest(unittest.TestCase): def test_ismount(self): self.assertIs(posixpath.ismount("/"), True) - self.assertIs(posixpath.ismount(b"/"), True) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + self.assertIs(posixpath.ismount(b"/"), True) def test_ismount_non_existent(self): # Non-existent mountpoint. diff --git a/Lib/test/test_unicode_file.py b/Lib/test/test_unicode_file.py --- a/Lib/test/test_unicode_file.py +++ b/Lib/test/test_unicode_file.py @@ -82,7 +82,7 @@ class TestUnicodeFiles(unittest.TestCase self.assertFalse(os.path.exists(filename2 + '.new')) def _do_directory(self, make_name, chdir_name): - cwd = os.getcwdb() + cwd = os.getcwd() if os.path.isdir(make_name): rmtree(make_name) os.mkdir(make_name) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -725,22 +725,6 @@ win32_error_object(char* function, PyObj return PyErr_SetFromWindowsErr(errno); } -static int -convert_to_unicode(PyObject **param) -{ - if (PyUnicode_CheckExact(*param)) - Py_INCREF(*param); - else if (PyUnicode_Check(*param)) - /* For a Unicode subtype that's not a Unicode object, - return a true Unicode object with the same data. */ - *param = PyUnicode_Copy(*param); - else - *param = PyUnicode_FromEncodedObject(*param, - Py_FileSystemDefaultEncoding, - "strict"); - return (*param) != NULL; -} - #endif /* MS_WINDOWS */ #if defined(PYOS_OS2) @@ -889,13 +873,24 @@ posix_2str(PyObject *args, } #ifdef MS_WINDOWS +int +win32_warn_bytes_api() +{ + return PyErr_WarnEx(PyExc_DeprecationWarning, + "The Windows bytes API has been deprecated, " + "use Unicode filenames instead", + 1); +} +#endif + +#ifdef MS_WINDOWS static PyObject* win32_1str(PyObject* args, char* func, char* format, BOOL (__stdcall *funcA)(LPCSTR), char* wformat, BOOL (__stdcall *funcW)(LPWSTR)) { PyObject *uni; - char *ansi; + const char *ansi; BOOL result; if (PyArg_ParseTuple(args, wformat, &uni)) @@ -915,6 +910,8 @@ win32_1str(PyObject* args, char* func, if (!PyArg_ParseTuple(args, format, &ansi)) return NULL; + if (win32_warn_bytes_api()) + return NULL; Py_BEGIN_ALLOW_THREADS result = funcA(ansi); Py_END_ALLOW_THREADS @@ -1848,6 +1845,9 @@ posix_do_stat(PyObject *self, PyObject * /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); + + if (win32_warn_bytes_api()) + return NULL; #endif if (!PyArg_ParseTuple(args, format, @@ -1885,8 +1885,7 @@ existence, or the inclusive-OR of R_OK, static PyObject * posix_access(PyObject *self, PyObject *args) { - PyObject *opath; - char *path; + const char *path; int mode; #ifdef MS_WINDOWS @@ -1904,14 +1903,13 @@ posix_access(PyObject *self, PyObject *a /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); - if (!PyArg_ParseTuple(args, "O&i:access", - PyUnicode_FSConverter, &opath, &mode)) - return NULL; - path = PyBytes_AsString(opath); + if (!PyArg_ParseTuple(args, "yi:access", &path, &mode)) + return NULL; + if (win32_warn_bytes_api()) + return NULL; Py_BEGIN_ALLOW_THREADS attr = GetFileAttributesA(path); Py_END_ALLOW_THREADS - Py_DECREF(opath); finish: if (attr == 0xFFFFFFFF) /* File does not exist, or cannot read attributes */ @@ -1923,6 +1921,7 @@ finish: || !(attr & FILE_ATTRIBUTE_READONLY) || (attr & FILE_ATTRIBUTE_DIRECTORY)); #else + PyObject *opath; int res; if (!PyArg_ParseTuple(args, "O&i:access", PyUnicode_FSConverter, &opath, &mode)) @@ -2042,7 +2041,7 @@ static PyObject * posix_chmod(PyObject *self, PyObject *args) { PyObject *opath = NULL; - char *path = NULL; + const char *path = NULL; int i; int res; #ifdef MS_WINDOWS @@ -2073,10 +2072,10 @@ posix_chmod(PyObject *self, PyObject *ar are also valid. */ PyErr_Clear(); - if (!PyArg_ParseTuple(args, "O&i:chmod", PyUnicode_FSConverter, - &opath, &i)) - return NULL; - path = PyBytes_AsString(opath); + if (!PyArg_ParseTuple(args, "yi:chmod", &path, &i)) + return NULL; + if (win32_warn_bytes_api()) + return NULL; Py_BEGIN_ALLOW_THREADS attr = GetFileAttributesA(path); if (attr != 0xFFFFFFFF) { @@ -2091,10 +2090,8 @@ posix_chmod(PyObject *self, PyObject *ar Py_END_ALLOW_THREADS if (!res) { win32_error("chmod", path); - Py_DECREF(opath); - return NULL; - } - Py_DECREF(opath); + return NULL; + } Py_INCREF(Py_None); return Py_None; #else /* MS_WINDOWS */ @@ -2450,7 +2447,6 @@ Create a hard link to a file."); static PyObject * win32_link(PyObject *self, PyObject *args) { - PyObject *osrc, *odst; char *src, *dst; BOOL rslt; PyObject *usrc, *udst; @@ -2478,19 +2474,16 @@ win32_link(PyObject *self, PyObject *arg /* Narrow strings also valid. */ PyErr_Clear(); - if (!PyArg_ParseTuple(args, "O&O&:link", PyUnicode_FSConverter, &osrc, - PyUnicode_FSConverter, &odst)) - return NULL; - - src = PyBytes_AsString(osrc); - dst = PyBytes_AsString(odst); + if (!PyArg_ParseTuple(args, "yy:link", &src, &dst)) + return NULL; + + if (win32_warn_bytes_api()) + return NULL; Py_BEGIN_ALLOW_THREADS rslt = CreateHardLinkA(dst, src, NULL); Py_END_ALLOW_THREADS - Py_DECREF(osrc); - Py_DECREF(odst); if (rslt == 0) return win32_error("link", NULL); @@ -2519,7 +2512,8 @@ posix_listdir(PyObject *self, PyObject * HANDLE hFindFile; BOOL result; WIN32_FIND_DATA FileData; - PyObject *opath; + const char *path; + Py_ssize_t pathlen; char namebuf[MAX_PATH+5]; /* Overallocate for \\*.*\0 */ char *bufptr = namebuf; Py_ssize_t len = sizeof(namebuf)-5; /* only claim to have space for MAX_PATH */ @@ -2613,17 +2607,16 @@ posix_listdir(PyObject *self, PyObject * are also valid. */ PyErr_Clear(); - if (!PyArg_ParseTuple(args, "O&:listdir", - PyUnicode_FSConverter, &opath)) - return NULL; - if (PyBytes_GET_SIZE(opath)+1 > MAX_PATH) { + if (!PyArg_ParseTuple(args, "y#:listdir", &path, &pathlen)) + return NULL; + if (win32_warn_bytes_api()) + return NULL; + if (pathlen+1 > MAX_PATH) { PyErr_SetString(PyExc_ValueError, "path too long"); - Py_DECREF(opath); - return NULL; - } - strcpy(namebuf, PyBytes_AsString(opath)); - len = PyObject_Size(opath); - Py_DECREF(opath); + return NULL; + } + strcpy(namebuf, path); + len = pathlen; if (len > 0) { char ch = namebuf[len-1]; if (ch != SEP && ch != ALTSEP && ch != ':') @@ -2915,11 +2908,9 @@ posix_fdlistdir(PyObject *self, PyObject static PyObject * posix__getfullpathname(PyObject *self, PyObject *args) { - PyObject *opath; - char *path; + const char *path; char outbuf[MAX_PATH*2]; char *temp; -#ifdef MS_WINDOWS PyObject *po; if (PyArg_ParseTuple(args, "U|:_getfullpathname", &po)) @@ -2953,19 +2944,17 @@ posix__getfullpathname(PyObject *self, P /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); -#endif - - if (!PyArg_ParseTuple (args, "O&:_getfullpathname", - PyUnicode_FSConverter, &opath)) - return NULL; - path = PyBytes_AsString(opath); + + if (!PyArg_ParseTuple (args, "y:_getfullpathname", + &path)) + return NULL; + if (win32_warn_bytes_api()) + return NULL; if (!GetFullPathName(path, Py_ARRAY_LENGTH(outbuf), outbuf, &temp)) { win32_error("GetFullPathName", path); - Py_DECREF(opath); - return NULL; - } - Py_DECREF(opath); + return NULL; + } if (PyUnicode_Check(PyTuple_GetItem(args, 0))) { return PyUnicode_Decode(outbuf, strlen(outbuf), Py_FileSystemDefaultEncoding, NULL); @@ -3069,8 +3058,7 @@ PyDoc_STRVAR(posix__isdir__doc__, static PyObject * posix__isdir(PyObject *self, PyObject *args) { - PyObject *opath; - char *path; + const char *path; PyObject *po; DWORD attributes; @@ -3088,11 +3076,10 @@ posix__isdir(PyObject *self, PyObject *a are also valid. */ PyErr_Clear(); - if (!PyArg_ParseTuple(args, "O&:_isdir", - PyUnicode_FSConverter, &opath)) - return NULL; - - path = PyBytes_AsString(opath); + if (!PyArg_ParseTuple(args, "y:_isdir", &path)) + return NULL; + if (win32_warn_bytes_api()) + return NULL; attributes = GetFileAttributesA(path); if (attributes == INVALID_FILE_ATTRIBUTES) Py_RETURN_FALSE; @@ -3113,8 +3100,7 @@ static PyObject * posix_mkdir(PyObject *self, PyObject *args) { int res; - PyObject *opath; - char *path; + const char *path; int mode = 0777; #ifdef MS_WINDOWS @@ -3136,22 +3122,21 @@ posix_mkdir(PyObject *self, PyObject *ar /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); - if (!PyArg_ParseTuple(args, "O&|i:mkdir", - PyUnicode_FSConverter, &opath, &mode)) - return NULL; - path = PyBytes_AsString(opath); + if (!PyArg_ParseTuple(args, "y|i:mkdir", &path, &mode)) + return NULL; + if (win32_warn_bytes_api()) + return NULL; Py_BEGIN_ALLOW_THREADS res = CreateDirectoryA(path, NULL); Py_END_ALLOW_THREADS if (!res) { win32_error("mkdir", path); - Py_DECREF(opath); - return NULL; - } - Py_DECREF(opath); + return NULL; + } Py_INCREF(Py_None); return Py_None; #else + PyObject *opath; if (!PyArg_ParseTuple(args, "O&|i:mkdir", PyUnicode_FSConverter, &opath, &mode)) @@ -3267,34 +3252,34 @@ posix_rename(PyObject *self, PyObject *a #ifdef MS_WINDOWS PyObject *o1, *o2; wchar_t *w1, *w2; - char *p1, *p2; + const char *p1, *p2; BOOL result; - if (!PyArg_ParseTuple(args, "OO:rename", &o1, &o2)) - goto error; - if (!convert_to_unicode(&o1)) - goto error; - if (!convert_to_unicode(&o2)) { - Py_DECREF(o1); - goto error; - } - w1 = PyUnicode_AsUnicode(o1); - if (w1 == NULL) - goto error; - w2 = PyUnicode_AsUnicode(o2); - if (w2 == NULL) - goto error; - Py_BEGIN_ALLOW_THREADS - result = MoveFileW(w1, w2); - Py_END_ALLOW_THREADS - Py_DECREF(o1); - Py_DECREF(o2); - if (!result) - return win32_error("rename", NULL); - Py_INCREF(Py_None); - return Py_None; -error: + if (PyArg_ParseTuple(args, "UU:rename", &o1, &o2)) { + w1 = PyUnicode_AsUnicode(o1); + if (w1 == NULL) { + Py_DECREF(o1); + Py_DECREF(o2); + return NULL; + } + w2 = PyUnicode_AsUnicode(o2); + if (w2 == NULL) { + Py_DECREF(o1); + Py_DECREF(o2); + return NULL; + } + Py_BEGIN_ALLOW_THREADS + result = MoveFileW(w1, w2); + Py_END_ALLOW_THREADS + if (!result) + return win32_error("rename", NULL); + Py_INCREF(Py_None); + return Py_None; + } PyErr_Clear(); - if (!PyArg_ParseTuple(args, "ss:rename", &p1, &p2)) + + if (!PyArg_ParseTuple(args, "yy:rename", &p1, &p2)) + return NULL; + if (win32_warn_bytes_api()) return NULL; Py_BEGIN_ALLOW_THREADS result = MoveFileA(p1, p2); @@ -3546,8 +3531,7 @@ posix_utime(PyObject *self, PyObject *ar PyObject *arg = Py_None; PyObject *obwpath; wchar_t *wpath = NULL; - PyObject *oapath; - char *apath; + const char *apath; HANDLE hFile; time_t atimesec, mtimesec; long ausec, musec; @@ -3571,11 +3555,11 @@ posix_utime(PyObject *self, PyObject *ar are also valid. */ PyErr_Clear(); - if (!PyArg_ParseTuple(args, "O&|O:utime", - PyUnicode_FSConverter, &oapath, &arg)) + if (!PyArg_ParseTuple(args, "y|O:utime", &apath, &arg)) return NULL; - - apath = PyBytes_AsString(oapath); + if (win32_warn_bytes_api()) + return NULL; + Py_BEGIN_ALLOW_THREADS hFile = CreateFileA(apath, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, @@ -3583,10 +3567,8 @@ posix_utime(PyObject *self, PyObject *ar Py_END_ALLOW_THREADS if (hFile == INVALID_HANDLE_VALUE) { win32_error("utime", apath); - Py_DECREF(oapath); return NULL; } - Py_DECREF(oapath); } if (arg == Py_None) { @@ -6512,10 +6494,28 @@ a directory.\n\ This function requires Windows 6.0 or greater, and raises a\n\ NotImplementedError otherwise."); +static PyObject* +win32_encode_filename(PyObject *obj) +{ + PyObject *bytes; + if (PyUnicode_Check(obj)) { + if (PyUnicode_READY(obj)) + return NULL; + Py_INCREF(obj); + return obj; + } + if (win32_warn_bytes_api()) + return NULL; + if (!PyUnicode_FSConverter(obj, &bytes)) + return NULL; + return bytes; +} + static PyObject * win_symlink(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = {"src", "dest", "target_is_directory", NULL}; + PyObject *osrc, *odest; PyObject *src, *dest; wchar_t *wsrc, *wdest; int target_is_directory = 0; @@ -6528,26 +6528,35 @@ win_symlink(PyObject *self, PyObject *ar return PyErr_Format(PyExc_NotImplementedError, "CreateSymbolicLinkW not found"); } - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:symlink", - kwlist, &src, &dest, &target_is_directory)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "OO|i:symlink", kwlist, + &osrc, &odest, &target_is_directory)) + return NULL; + + src = win32_encode_filename(osrc); + if (!src) + return NULL; + dest = win32_encode_filename(odest); + if (!dest) { + Py_DECREF(src); + return NULL; + } if (win32_can_symlink == 0) return PyErr_Format(PyExc_OSError, "symbolic link privilege not held"); - if (!convert_to_unicode(&src)) - return NULL; - if (!convert_to_unicode(&dest)) { + wsrc = PyUnicode_AsUnicode(src); + if (wsrc == NULL) { Py_DECREF(src); - return NULL; - } - - wsrc = PyUnicode_AsUnicode(src); - if (wsrc == NULL) - goto error; + Py_DECREF(dest); + return NULL; + } wdest = PyUnicode_AsUnicode(dest); - if (wsrc == NULL) - goto error; + if (wsrc == NULL) { + Py_DECREF(src); + Py_DECREF(dest); + return NULL; + } /* if src is a directory, ensure target_is_directory==1 */ if( @@ -6570,11 +6579,6 @@ win_symlink(PyObject *self, PyObject *ar Py_INCREF(Py_None); return Py_None; - -error: - Py_DECREF(src); - Py_DECREF(dest); - return NULL; } #endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */ @@ -6785,6 +6789,8 @@ posix_open(PyObject *self, PyObject *arg /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); + if (win32_warn_bytes_api()) + return NULL; #endif if (!PyArg_ParseTuple(args, "O&i|i:open",