diff -r fadc4b53b840 Lib/test/test_capi.py --- a/Lib/test/test_capi.py Mon Jan 25 23:00:21 2016 -0800 +++ b/Lib/test/test_capi.py Tue Jan 26 15:27:52 2016 +0200 @@ -488,10 +488,10 @@ class SkipitemTest(unittest.TestCase): _testcapi.parse_tuple_and_keywords(tuple_1, dict_b, format.encode("ascii"), keywords) when_not_skipped = False - except TypeError as e: - s = "argument 1 must be impossible, not int" + except SystemError as e: + s = "argument 1 (impossible)" when_not_skipped = (str(e) == s) - except RuntimeError as e: + except (TypeError, RuntimeError): when_not_skipped = False # test the format unit when skipped diff -r fadc4b53b840 Lib/test/test_getargs2.py --- a/Lib/test/test_getargs2.py Mon Jan 25 23:00:21 2016 -0800 +++ b/Lib/test/test_getargs2.py Tue Jan 26 15:27:52 2016 +0200 @@ -610,6 +610,82 @@ class Unicode_TestCase(unittest.TestCase self.assertRaises(TypeError, getargs_Z_hash, memoryview(b'memoryview')) self.assertIsNone(getargs_Z_hash(None)) + def test_et(self): + from _testcapi import getargs_et + self.assertEqual(getargs_et('abc\xe9'), b'abc\xc3\xa9') + self.assertEqual(getargs_et('abc\xe9', 'latin1'), b'abc\xe9') + self.assertRaises(UnicodeEncodeError, getargs_et, 'abc\xe9', 'ascii') + self.assertRaises(LookupError, getargs_et, 'abc\xe9', 'spam') + self.assertEqual(getargs_et(b'bytes', 'latin1'), b'bytes') + self.assertEqual(getargs_et(bytearray(b'bytearray'), 'latin1'), b'bytearray') + self.assertRaises(TypeError, getargs_et, memoryview(b'memoryview'), 'latin1') + self.assertRaises(TypeError, getargs_et, None, 'latin1') + self.assertRaises(TypeError, getargs_et, 'nul:\0', 'latin1') + self.assertRaises(TypeError, getargs_et, b'nul:\0', 'latin1') + self.assertRaises(TypeError, getargs_et, bytearray(b'nul:\0'), 'latin1') + + def test_es(self): + from _testcapi import getargs_es + self.assertEqual(getargs_es('abc\xe9'), b'abc\xc3\xa9') + self.assertEqual(getargs_es('abc\xe9', 'latin1'), b'abc\xe9') + self.assertRaises(UnicodeEncodeError, getargs_es, 'abc\xe9', 'ascii') + self.assertRaises(LookupError, getargs_es, 'abc\xe9', 'spam') + self.assertRaises(TypeError, getargs_es, b'bytes', 'latin1') + self.assertRaises(TypeError, getargs_es, bytearray(b'bytearray'), 'latin1') + self.assertRaises(TypeError, getargs_es, memoryview(b'memoryview'), 'latin1') + self.assertRaises(TypeError, getargs_es, None, 'latin1') + self.assertRaises(TypeError, getargs_es, 'nul:\0', 'latin1') + + def test_es_hash(self): + from _testcapi import getargs_es_hash + self.assertEqual(getargs_es_hash('abc\xe9'), b'abc\xc3\xa9') + self.assertEqual(getargs_es_hash('abc\xe9', 'latin1'), b'abc\xe9') + self.assertRaises(UnicodeEncodeError, getargs_es_hash, 'abc\xe9', 'ascii') + self.assertRaises(LookupError, getargs_es_hash, 'abc\xe9', 'spam') + self.assertRaises(TypeError, getargs_es_hash, b'bytes', 'latin1') + self.assertRaises(TypeError, getargs_es_hash, bytearray(b'bytearray'), 'latin1') + self.assertRaises(TypeError, getargs_es_hash, memoryview(b'memoryview'), 'latin1') + self.assertRaises(TypeError, getargs_es_hash, None, 'latin1') + self.assertEqual(getargs_es_hash('nul:\0', 'latin1'), b'nul:\0') + + buf = bytearray(b'x'*8) + self.assertEqual(getargs_es_hash('abc\xe9', 'latin1', buf), b'abc\xe9') + self.assertEqual(buf, bytearray(b'abc\xe9\x00xxx')) + buf = bytearray(b'x'*5) + self.assertEqual(getargs_es_hash('abc\xe9', 'latin1', buf), b'abc\xe9') + self.assertEqual(buf, bytearray(b'abc\xe9\x00')) + buf = bytearray(b'x'*4) + self.assertRaises(ValueError, getargs_es_hash, 'abc\xe9', 'latin1', buf) + self.assertEqual(buf, bytearray(b'x'*4)) + buf = bytearray() + self.assertRaises(ValueError, getargs_es_hash, 'abc\xe9', 'latin1', buf) + + def test_et_hash(self): + from _testcapi import getargs_et_hash + self.assertEqual(getargs_et_hash('abc\xe9'), b'abc\xc3\xa9') + self.assertEqual(getargs_et_hash('abc\xe9', 'latin1'), b'abc\xe9') + self.assertRaises(UnicodeEncodeError, getargs_et_hash, 'abc\xe9', 'ascii') + self.assertRaises(LookupError, getargs_et_hash, 'abc\xe9', 'spam') + self.assertEqual(getargs_et_hash(b'bytes', 'latin1'), b'bytes') + self.assertEqual(getargs_et_hash(bytearray(b'bytearray'), 'latin1'), b'bytearray') + self.assertRaises(TypeError, getargs_et_hash, memoryview(b'memoryview'), 'latin1') + self.assertRaises(TypeError, getargs_et_hash, None, 'latin1') + self.assertEqual(getargs_et_hash('nul:\0', 'latin1'), b'nul:\0') + self.assertEqual(getargs_et_hash(b'nul:\0', 'latin1'), b'nul:\0') + self.assertEqual(getargs_et_hash(bytearray(b'nul:\0'), 'latin1'), b'nul:\0') + + buf = bytearray(b'x'*8) + self.assertEqual(getargs_et_hash('abc\xe9', 'latin1', buf), b'abc\xe9') + self.assertEqual(buf, bytearray(b'abc\xe9\x00xxx')) + buf = bytearray(b'x'*5) + self.assertEqual(getargs_et_hash('abc\xe9', 'latin1', buf), b'abc\xe9') + self.assertEqual(buf, bytearray(b'abc\xe9\x00')) + buf = bytearray(b'x'*4) + self.assertRaises(ValueError, getargs_et_hash, 'abc\xe9', 'latin1', buf) + self.assertEqual(buf, bytearray(b'x'*4)) + buf = bytearray() + self.assertRaises(ValueError, getargs_et_hash, 'abc\xe9', 'latin1', buf) + if __name__ == "__main__": unittest.main() diff -r fadc4b53b840 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Mon Jan 25 23:00:21 2016 -0800 +++ b/Modules/_testcapimodule.c Tue Jan 26 15:27:52 2016 +0200 @@ -1243,6 +1243,84 @@ getargs_Z_hash(PyObject *self, PyObject Py_RETURN_NONE; } +static PyObject * +getargs_es(PyObject *self, PyObject *args) +{ + PyObject *arg, *result; + const char *encoding = NULL; + char *str; + + if (!PyArg_ParseTuple(args, "O|s", &arg, &encoding)) + return NULL; + if (!PyArg_Parse(arg, "es", encoding, &str)) + return NULL; + result = PyBytes_FromString(str); + PyMem_Free(str); + return result; +} + +static PyObject * +getargs_et(PyObject *self, PyObject *args) +{ + PyObject *arg, *result; + const char *encoding = NULL; + char *str; + + if (!PyArg_ParseTuple(args, "O|s", &arg, &encoding)) + return NULL; + if (!PyArg_Parse(arg, "et", encoding, &str)) + return NULL; + result = PyBytes_FromString(str); + PyMem_Free(str); + return result; +} + +static PyObject * +getargs_es_hash(PyObject *self, PyObject *args) +{ + PyObject *arg, *result; + const char *encoding = NULL; + PyByteArrayObject *buffer = NULL; + char *str = NULL; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "O|sY", &arg, &encoding, &buffer)) + return NULL; + if (buffer != NULL) { + str = PyByteArray_AS_STRING(buffer); + size = PyByteArray_GET_SIZE(buffer); + } + if (!PyArg_Parse(arg, "es#", encoding, &str, &size)) + return NULL; + result = PyBytes_FromStringAndSize(str, size); + if (buffer == NULL) + PyMem_Free(str); + return result; +} + +static PyObject * +getargs_et_hash(PyObject *self, PyObject *args) +{ + PyObject *arg, *result; + const char *encoding = NULL; + PyByteArrayObject *buffer = NULL; + char *str = NULL; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "O|sY", &arg, &encoding, &buffer)) + return NULL; + if (buffer != NULL) { + str = PyByteArray_AS_STRING(buffer); + size = PyByteArray_GET_SIZE(buffer); + } + if (!PyArg_Parse(arg, "et#", encoding, &str, &size)) + return NULL; + result = PyBytes_FromStringAndSize(str, size); + if (buffer == NULL) + PyMem_Free(str); + return result; +} + /* Test the s and z codes for PyArg_ParseTuple. */ static PyObject * @@ -3604,6 +3682,10 @@ static PyMethodDef TestMethods[] = { {"getargs_Z", getargs_Z, METH_VARARGS}, {"getargs_Z_hash", getargs_Z_hash, METH_VARARGS}, {"getargs_w_star", getargs_w_star, METH_VARARGS}, + {"getargs_es", getargs_es, METH_VARARGS}, + {"getargs_et", getargs_et, METH_VARARGS}, + {"getargs_es_hash", getargs_es_hash, METH_VARARGS}, + {"getargs_et_hash", getargs_et_hash, METH_VARARGS}, {"codec_incrementalencoder", (PyCFunction)codec_incrementalencoder, METH_VARARGS}, {"codec_incrementaldecoder", diff -r fadc4b53b840 Python/getargs.c --- a/Python/getargs.c Mon Jan 25 23:00:21 2016 -0800 +++ b/Python/getargs.c Tue Jan 26 15:27:52 2016 +0200 @@ -342,7 +342,7 @@ vgetargs1(PyObject *args, const char *fo flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { - seterror(i+1, msg, levels, fname, msg); + seterror(i+1, msg, levels, fname, message); return cleanreturn(0, &freelist); } } @@ -394,7 +394,12 @@ seterror(Py_ssize_t iarg, const char *ms PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg); message = buf; } - PyErr_SetString(PyExc_TypeError, message); + if (msg[0] == '(') { + PyErr_SetString(PyExc_SystemError, message); + } + else { + PyErr_SetString(PyExc_TypeError, message); + } } @@ -535,9 +540,17 @@ converterr(const char *expected, PyObjec { assert(expected != NULL); assert(arg != NULL); - PyOS_snprintf(msgbuf, bufsize, - "must be %.50s, not %.50s", expected, - arg == Py_None ? "None" : arg->ob_type->tp_name); + if (expected[0] == '(') { + PyOS_snprintf(msgbuf, bufsize, + "%.100s", expected); + strncpy(msgbuf, expected, bufsize); + msgbuf[bufsize-1] = '\0'; + } + else { + PyOS_snprintf(msgbuf, bufsize, + "must be %.50s, not %.50s", expected, + arg == Py_None ? "None" : arg->ob_type->tp_name); + } return msgbuf; } @@ -741,7 +754,7 @@ convertsimple(PyObject *arg, const char if (PyLong_Check(arg)) ival = PyLong_AsUnsignedLongMask(arg); else - return converterr("integer", arg, msgbuf, bufsize); + return converterr("int", arg, msgbuf, bufsize); *p = ival; break; } @@ -766,7 +779,7 @@ convertsimple(PyObject *arg, const char if (PyLong_Check(arg)) ival = PyLong_AsUnsignedLongLongMask(arg); else - return converterr("integer", arg, msgbuf, bufsize); + return converterr("int", arg, msgbuf, bufsize); *p = ival; break; } @@ -1123,9 +1136,11 @@ convertsimple(PyObject *arg, const char } else { if (size + 1 > BUFFER_LEN) { Py_DECREF(s); - return converterr( - "(buffer overflow)", - arg, msgbuf, bufsize); + PyErr_Format(PyExc_ValueError, + "encoded string too long " + "(%zd, maximum length %zd)", + size, (Py_ssize_t)(BUFFER_LEN-1)); + RETURN_ERR_OCCURRED; } } memcpy(*buffer, ptr, size+1); @@ -1147,7 +1162,7 @@ convertsimple(PyObject *arg, const char if ((Py_ssize_t)strlen(ptr) != size) { Py_DECREF(s); return converterr( - "encoded string without NULL bytes", + "encoded string without null bytes", arg, msgbuf, bufsize); } *buffer = PyMem_NEW(char, size + 1); @@ -1237,7 +1252,7 @@ convertsimple(PyObject *arg, const char if (*format != '*') return converterr( - "invalid use of 'w' format character", + "(invalid use of 'w' format character)", arg, msgbuf, bufsize); format++; @@ -1261,7 +1276,7 @@ convertsimple(PyObject *arg, const char } default: - return converterr("impossible", arg, msgbuf, bufsize); + return converterr("(impossible)", arg, msgbuf, bufsize); }