diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index e0fdee33498..824e843914c 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -472,6 +472,13 @@ if 1: d = {f(): f(), f(): f()} self.assertEqual(d, {1: 2, 3: 4}) + def test_compile_filename(self): + for filename in ('file.py', b'file.py', + bytearray(b'file.py'), memoryview(b'file.py')): + code = compile('pass', filename, 'exec') + self.assertEqual(code.co_filename, 'file.py') + self.assertRaises(TypeError, compile, 'pass', list(b'file.py'), 'exec') + @support.cpython_only def test_same_filename_used(self): s = """def f(): pass\ndef g(): pass""" diff --git a/Lib/test/test_parser.py b/Lib/test/test_parser.py index 72692067fe6..1e7d331bc0b 100644 --- a/Lib/test/test_parser.py +++ b/Lib/test/test_parser.py @@ -626,6 +626,22 @@ class CompileTestCase(unittest.TestCase): code2 = parser.compilest(st) self.assertEqual(eval(code2), -3) + def test_compile_filename(self): + st = parser.expr('a + 5') + code = parser.compilest(st) + self.assertEqual(code.co_filename, '') + code = st.compile() + self.assertEqual(code.co_filename, '') + for filename in ('file.py', b'file.py', + bytearray(b'file.py'), memoryview(b'file.py')): + code = parser.compilest(st, filename) + self.assertEqual(code.co_filename, 'file.py') + code = st.compile(filename) + self.assertEqual(code.co_filename, 'file.py') + self.assertRaises(TypeError, parser.compilest, st, list(b'file.py')) + self.assertRaises(TypeError, st.compile, list(b'file.py')) + + class ParserStackLimitTestCase(unittest.TestCase): """try to push the parser to/over its limits. see http://bugs.python.org/issue1881 for a discussion diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index e5e7b83d214..c5d7facfdbd 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -157,6 +157,12 @@ class SymtableTest(unittest.TestCase): self.fail("no SyntaxError for %r" % (brokencode,)) checkfilename("def f(x): foo)(") # parse-time checkfilename("def f(x): global x") # symtable-build-time + symtable.symtable("pass", b"spam", "exec") + with self.assertRaises(TypeError): + symtable.symtable("pass", bytearray(b"spam"), "exec") + symtable.symtable("pass", memoryview(b"spam"), "exec") + with self.assertRaises(TypeError): + symtable.symtable("pass", list(b"spam"), "exec") def test_eval(self): symbols = symtable.symtable("42", "?", "eval") diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py index 1f10095f438..20491cde7a7 100644 --- a/Lib/test/test_zipimport.py +++ b/Lib/test/test_zipimport.py @@ -619,6 +619,19 @@ class UncompressedZipImportTestCase(ImportHooksBaseTestCase): finally: os.remove(filename) + def testBytesPath(self): + filename = support.TESTFN + ".zip" + self.addCleanup(support.unlink, filename) + with ZipFile(filename, "w") as z: + zinfo = ZipInfo(TESTMOD + ".py", time.localtime(NOW)) + zinfo.compress_type = self.compression + z.writestr(zinfo, test_src) + + zipimport.zipimporter(filename) + zipimport.zipimporter(os.fsencode(filename)) + zipimport.zipimporter(bytearray(os.fsencode(filename))) + zipimport.zipimporter(memoryview(os.fsencode(filename))) + @support.requires_zlib class CompressedZipImportTestCase(UncompressedZipImportTestCase): @@ -639,6 +652,8 @@ class BadFileZipImportTestCase(unittest.TestCase): def testBadArgs(self): self.assertRaises(TypeError, zipimport.zipimporter, None) self.assertRaises(TypeError, zipimport.zipimporter, TESTMOD, kwd=None) + self.assertRaises(TypeError, zipimport.zipimporter, + list(os.fsencode(TESTMOD))) def testFilenameTooLong(self): self.assertZipFailure('A' * 33000) diff --git a/Misc/NEWS b/Misc/NEWS index 37e366336e9..6c7555af5b7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,10 @@ What's New in Python 3.6.0 alpha 3 Library ------- +- Issue #26754: Some functions (compile() etc) accepted a filename argument + encoded as an iterable of integers. Now only strings and byte-like objects + are accepted. + - Issue #26536: socket.ioctl now supports SIO_LOOPBACK_FAST_PATH. Patch by Daniel Stokes. @@ -52,6 +56,12 @@ IDLE - Issue #27310: Fix IDLE.app failure to launch on OS X due to vestigial import. +C API +----- + +- Issue #26754: PyUnicode_FSDecoder() accepted a filename argument encoded as + an iterable of integers. Now only strings and byte-like objects are accepted. + Build ----- diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 7de44ce6e7a..db6a51ca22a 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3837,7 +3837,7 @@ PyUnicode_FSDecoder(PyObject* arg, void* addr) output = arg; Py_INCREF(output); } - else { + else if (PyObject_CheckBuffer(arg)) { arg = PyBytes_FromObject(arg); if (!arg) return 0; @@ -3852,6 +3852,12 @@ PyUnicode_FSDecoder(PyObject* arg, void* addr) return 0; } } + else { + PyErr_Format(PyExc_TypeError, + "path should be string or bytes, not %.200s", + Py_TYPE(arg)->tp_name); + return 0; + } if (PyUnicode_READY(output) == -1) { Py_DECREF(output); return 0;