From 91a639a094978882caef91915c932fbb2fc347de Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Mon, 22 Feb 2021 22:11:48 +0900 Subject: [PATCH] bpo-36346: Emit DeprecationWarning for PyArg_Parse() with 'u' or 'Z'. (GH-20927) Emit DeprecationWarning when PyArg_Parse*() is called with 'u', 'Z' format. See PEP 623. --- Lib/test/test_getargs2.py | 83 +++++++++++++------ Lib/test/test_unicode.py | 6 +- .../2021-02-22-19-00-00.bpo-36346.uAoni0.rst | 2 + Python/getargs.c | 5 +- 4 files changed, 69 insertions(+), 27 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-02-22-19-00-00.bpo-36346.uAoni0.rst diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index 09560197913..c67e6f51a23 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -4,6 +4,7 @@ import string import sys from test import support from test.support import import_helper +from test.support import warnings_helper # Skip this test if the _testcapi module isn't available. _testcapi = import_helper.import_module('_testcapi') from _testcapi import getargs_keywords, getargs_keyword_only @@ -979,42 +980,66 @@ class String_TestCase(unittest.TestCase): @support.requires_legacy_unicode_capi def test_u(self): from _testcapi import getargs_u - self.assertEqual(getargs_u('abc\xe9'), 'abc\xe9') - self.assertRaises(ValueError, getargs_u, 'nul:\0') - self.assertRaises(TypeError, getargs_u, b'bytes') - self.assertRaises(TypeError, getargs_u, bytearray(b'bytearray')) - self.assertRaises(TypeError, getargs_u, memoryview(b'memoryview')) - self.assertRaises(TypeError, getargs_u, None) + with self.assertWarns(DeprecationWarning): + self.assertEqual(getargs_u('abc\xe9'), 'abc\xe9') + with self.assertWarns(DeprecationWarning): + self.assertRaises(ValueError, getargs_u, 'nul:\0') + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_u, b'bytes') + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_u, bytearray(b'bytearray')) + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_u, memoryview(b'memoryview')) + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_u, None) @support.requires_legacy_unicode_capi def test_u_hash(self): from _testcapi import getargs_u_hash - self.assertEqual(getargs_u_hash('abc\xe9'), 'abc\xe9') - self.assertEqual(getargs_u_hash('nul:\0'), 'nul:\0') - self.assertRaises(TypeError, getargs_u_hash, b'bytes') - self.assertRaises(TypeError, getargs_u_hash, bytearray(b'bytearray')) - self.assertRaises(TypeError, getargs_u_hash, memoryview(b'memoryview')) - self.assertRaises(TypeError, getargs_u_hash, None) + with self.assertWarns(DeprecationWarning): + self.assertEqual(getargs_u_hash('abc\xe9'), 'abc\xe9') + with self.assertWarns(DeprecationWarning): + self.assertEqual(getargs_u_hash('nul:\0'), 'nul:\0') + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_u_hash, b'bytes') + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_u_hash, bytearray(b'bytearray')) + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_u_hash, memoryview(b'memoryview')) + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_u_hash, None) @support.requires_legacy_unicode_capi def test_Z(self): from _testcapi import getargs_Z - self.assertEqual(getargs_Z('abc\xe9'), 'abc\xe9') - self.assertRaises(ValueError, getargs_Z, 'nul:\0') - self.assertRaises(TypeError, getargs_Z, b'bytes') - self.assertRaises(TypeError, getargs_Z, bytearray(b'bytearray')) - self.assertRaises(TypeError, getargs_Z, memoryview(b'memoryview')) - self.assertIsNone(getargs_Z(None)) + with self.assertWarns(DeprecationWarning): + self.assertEqual(getargs_Z('abc\xe9'), 'abc\xe9') + with self.assertWarns(DeprecationWarning): + self.assertRaises(ValueError, getargs_Z, 'nul:\0') + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_Z, b'bytes') + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_Z, bytearray(b'bytearray')) + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_Z, memoryview(b'memoryview')) + with self.assertWarns(DeprecationWarning): + self.assertIsNone(getargs_Z(None)) @support.requires_legacy_unicode_capi def test_Z_hash(self): from _testcapi import getargs_Z_hash - self.assertEqual(getargs_Z_hash('abc\xe9'), 'abc\xe9') - self.assertEqual(getargs_Z_hash('nul:\0'), 'nul:\0') - self.assertRaises(TypeError, getargs_Z_hash, b'bytes') - self.assertRaises(TypeError, getargs_Z_hash, bytearray(b'bytearray')) - self.assertRaises(TypeError, getargs_Z_hash, memoryview(b'memoryview')) - self.assertIsNone(getargs_Z_hash(None)) + with self.assertWarns(DeprecationWarning): + self.assertEqual(getargs_Z_hash('abc\xe9'), 'abc\xe9') + with self.assertWarns(DeprecationWarning): + self.assertEqual(getargs_Z_hash('nul:\0'), 'nul:\0') + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_Z_hash, b'bytes') + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_Z_hash, bytearray(b'bytearray')) + with self.assertWarns(DeprecationWarning): + self.assertRaises(TypeError, getargs_Z_hash, memoryview(b'memoryview')) + with self.assertWarns(DeprecationWarning): + self.assertIsNone(getargs_Z_hash(None)) class Object_TestCase(unittest.TestCase): @@ -1053,6 +1078,8 @@ class Test6012(unittest.TestCase): class SkipitemTest(unittest.TestCase): + # u, and Z raises DeprecationWarning + @warnings_helper.ignore_warnings(category=DeprecationWarning) def test_skipitem(self): """ If this test failed, you probably added a new "format unit" @@ -1221,6 +1248,14 @@ class Test_testcapi(unittest.TestCase): for name in dir(_testcapi) if name.startswith('test_') and name.endswith('_code')) + @warnings_helper.ignore_warnings(category=DeprecationWarning) + def test_u_code(self): + _testcapi.test_u_code() + + @warnings_helper.ignore_warnings(category=DeprecationWarning) + def test_Z_code(self): + _testcapi.test_Z_code() + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index df8f2c92b38..2626be6281c 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -2368,12 +2368,14 @@ class UnicodeTest(string_tests.CommonTest, text = 'a' * length + 'b' # fill wstr internal field - abc = getargs_u(text) + with self.assertWarns(DeprecationWarning): + abc = getargs_u(text) self.assertEqual(abc, text) # resize text: wstr field must be cleared and then recomputed text += 'c' - abcdef = getargs_u(text) + with self.assertWarns(DeprecationWarning): + abcdef = getargs_u(text) self.assertNotEqual(abc, abcdef) self.assertEqual(abcdef, text) diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-02-22-19-00-00.bpo-36346.uAoni0.rst b/Misc/NEWS.d/next/Core and Builtins/2021-02-22-19-00-00.bpo-36346.uAoni0.rst new file mode 100644 index 00000000000..3b3e727b769 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-02-22-19-00-00.bpo-36346.uAoni0.rst @@ -0,0 +1,2 @@ +``PyArg_Parse*()`` functions now emits ``DeprecationWarning`` when ``u`` or +``Z`` format is used. See :pep:`623` for detail. diff --git a/Python/getargs.c b/Python/getargs.c index 8839492e5ef..936eb6a89a3 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1014,7 +1014,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, case 'u': /* raw unicode buffer (Py_UNICODE *) */ case 'Z': /* raw unicode buffer or None */ { - // TODO: Raise DeprecationWarning + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "getargs: The '%c' format is deprecated. Use 'U' instead.", c)) { + return NULL; + } _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);