Index: Python/getargs.c =================================================================== --- Python/getargs.c (revision 80093) +++ Python/getargs.c (working copy) @@ -1522,6 +1522,29 @@ return retval; } +int +PyArg_ValidateKeywordArguments(PyObject *kwargs) +{ + Py_ssize_t pos = 0; + PyObject *key, *value; + if (!PyDict_CheckExact(kwargs)) { + PyErr_BadInternalCall(); + return 0; + } + while (PyDict_Next(kwargs, &pos, &key, &value)) { + if (!(PyString_Check(key) +#ifdef Py_USING_UNICODE + || PyUnicode_Check(key) +#endif + )) { + PyErr_SetString(PyExc_TypeError, + "keyword arguments must be strings"); + return 0; + } + } + return 1; +} + #define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':') static int Index: Include/modsupport.h =================================================================== --- Include/modsupport.h (revision 80093) +++ Include/modsupport.h (working copy) @@ -27,6 +27,7 @@ PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...) Py_FORMAT_PARSETUPLE(PyArg_ParseTuple, 2, 3); PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, const char *, char **, ...); +PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *); PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...); PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...); PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); Index: Objects/dictobject.c =================================================================== --- Objects/dictobject.c (revision 80093) +++ Objects/dictobject.c (working copy) @@ -1413,8 +1413,12 @@ else result = PyDict_MergeFromSeq2(self, arg, 1); } - if (result == 0 && kwds != NULL) - result = PyDict_Merge(self, kwds, 1); + if (result == 0 && kwds != NULL) { + if (PyArg_ValidateKeywordArguments(kwds)) + result = PyDict_Merge(self, kwds, 1); + else + result = -1; + } return result; } Index: Doc/c-api/arg.rst =================================================================== --- Doc/c-api/arg.rst (revision 80093) +++ Doc/c-api/arg.rst (working copy) @@ -353,6 +353,13 @@ va_list rather than a variable number of arguments. +.. cfunction:: int PyArg_ValidateKeywordArguments(PyObject *) + + Ensure that the keys in the keywords argument dictionary are strings. This + is only needed if :cfunc:`PyArg_ParseTupleAndKeywords` is not used, since the + latter already does this check. + + .. cfunction:: int PyArg_Parse(PyObject *args, const char *format, ...) Function used to deconstruct the argument lists of "old-style" functions Index: Lib/test/test_dict.py =================================================================== --- Lib/test/test_dict.py (revision 80093) +++ Lib/test/test_dict.py (working copy) @@ -6,10 +6,18 @@ class DictTest(unittest.TestCase): + + def test_invalid_keyword_arguments(self): + with self.assertRaises(TypeError): + dict(**{1 : 2}) + with self.assertRaises(TypeError): + {}.update(**{1 : 2}) + def test_constructor(self): # calling built-in types without argument must return empty self.assertEqual(dict(), {}) self.assertIsNot(dict(), {}) + self.assertEqual(dict(**{u"x" : 3}), {"x" : 3}) def test_literal_constructor(self): # check literal constructor for different sized dicts