import contextlib
+class BadStr(str):
+ def __eq__(self, other):
+ return True
+ def __hash__(self):
+ # Guaranteed different hash
+ return str.__hash__(self) ^ 3
+
+ def __eq__(self, other):
+ return False
+ def __hash__(self):
+ return str.__hash__(self)
+
+
class FunctionCalls(unittest.TestCase):
def test_kwargs_order(self):
self.assertRaisesRegex(TypeError, msg,
print, 0, sep=1, end=2, file=3, flush=4, foo=5)
+ def test_varargs18_kw(self):
+ # _PyArg_UnpackKeywordsWithVararg()
+ msg = r"invalid keyword argument for print\(\)$"
+ with self.assertRaisesRegex(TypeError, msg):
+ print(0, 1, **{BadStr('foo'): ','})
+
+ def test_varargs19_kw(self):
+ # _PyArg_UnpackKeywords()
+ msg = r"invalid keyword argument for round\(\)$"
+ with self.assertRaisesRegex(TypeError, msg):
+ round(1.75, **{BadStr('foo'): 1})
+
def test_oldargs0_1(self):
msg = r"keys\(\) takes no arguments \(1 given\)"
self.assertRaisesRegex(TypeError, msg, {}.keys, 0)
"'\udc80' is an invalid keyword argument for this function"):
getargs_keyword_only(1, 2, **{'\uDC80': 10})
+ def test_weird_str_subclass(self):
+ class BadStr(str):
+ def __eq__(self, other):
+ return True
+ def __hash__(self):
+ # Guaranteed different hash
+ return str.__hash__(self) ^ 3
+ with self.assertRaisesRegex(TypeError,
+ "invalid keyword argument for this function"):
+ getargs_keyword_only(1, 2, **{BadStr("keyword_only"): 3})
+ with self.assertRaisesRegex(TypeError,
+ "invalid keyword argument for this function"):
+ getargs_keyword_only(1, 2, **{BadStr("monster"): 666})
+
+ def test_weird_str_subclass2(self):
+ class BadStr(str):
+ def __eq__(self, other):
+ return False
+ def __hash__(self):
+ return str.__hash__(self)
+ with self.assertRaisesRegex(TypeError,
+ "invalid keyword argument for this function"):
+ getargs_keyword_only(1, 2, **{BadStr("keyword_only"): 3})
+ with self.assertRaisesRegex(TypeError,
+ "invalid keyword argument for this function"):
+ getargs_keyword_only(1, 2, **{BadStr("monster"): 666})
+
class PositionalOnlyAndKeywords_TestCase(unittest.TestCase):
from _testcapi import getargs_positional_only_and_keywords as getargs
return retval;
}
+static void
+error_unexpected_keyword_arg(PyObject *kwargs, PyObject *kwnames, PyObject *kwtuple, const char *fname)
+{
+ /* make sure there are no extraneous keyword arguments */
+ Py_ssize_t j = 0;
+ while (1) {
+ PyObject *keyword;
+ if (kwargs != NULL) {
+ if (!PyDict_Next(kwargs, &j, &keyword, NULL))
+ break;
+ }
+ else {
+ if (j >= PyTuple_GET_SIZE(kwnames))
+ break;
+ keyword = PyTuple_GET_ITEM(kwnames, j);
+ j++;
+ }
+ if (!PyUnicode_Check(keyword)) {
+ PyErr_SetString(PyExc_TypeError,
+ "keywords must be strings");
+ return;
+ }
+
+ int match = PySequence_Contains(kwtuple, keyword);
+ if (match <= 0) {
+ if (!match) {
+ PyErr_Format(PyExc_TypeError,
+ "'%S' is an invalid keyword "
+ "argument for %.200s%s",
+ keyword,
+ (fname == NULL) ? "this function" : fname,
+ (fname == NULL) ? "" : "()");
+ }
+ return;
+ }
+ }
+ /* Something wrong happened. There are extraneous keyword arguments,
+ * but we don't know what. And we don't bother. */
+ PyErr_Format(PyExc_TypeError,
+ "invalid keyword argument for %.200s%s",
+ (fname == NULL) ? "this function" : fname,
+ (fname == NULL) ? "" : "()");
+}
+
int
PyArg_ValidateKeywordArguments(PyObject *kwargs)
{
return cleanreturn(0, &freelist);
}
}
+ /* Something wrong happened. There are extraneous keyword arguments,
+ * but we don't know what. And we don't bother. */
+ PyErr_Format(PyExc_TypeError,
+ "invalid keyword argument for %.200s%s",
+ (fname == NULL) ? "this function" : fname,
+ (fname == NULL) ? "" : "()");
+ return cleanreturn(0, &freelist);
}
return cleanreturn(1, &freelist);
assert(IS_END_OF_FORMAT(*format) || (*format == '|') || (*format == '$'));
if (nkwargs > 0) {
- Py_ssize_t j;
/* make sure there are no arguments given by name and position */
for (i = pos; i < nargs; i++) {
keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
return cleanreturn(0, &freelist);
}
}
- /* make sure there are no extraneous keyword arguments */
- j = 0;
- while (1) {
- int match;
- if (kwargs != NULL) {
- if (!PyDict_Next(kwargs, &j, &keyword, NULL))
- break;
- }
- else {
- if (j >= PyTuple_GET_SIZE(kwnames))
- break;
- keyword = PyTuple_GET_ITEM(kwnames, j);
- j++;
- }
- match = PySequence_Contains(kwtuple, keyword);
- if (match <= 0) {
- if (!match) {
- PyErr_Format(PyExc_TypeError,
- "'%S' is an invalid keyword "
- "argument for %.200s%s",
- keyword,
- (parser->fname == NULL) ? "this function" : parser->fname,
- (parser->fname == NULL) ? "" : "()");
- }
- return cleanreturn(0, &freelist);
- }
- }
+ error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname);
+ return cleanreturn(0, &freelist);
}
return cleanreturn(1, &freelist);
}
if (nkwargs > 0) {
- Py_ssize_t j;
/* make sure there are no arguments given by name and position */
for (i = posonly; i < nargs; i++) {
keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
return NULL;
}
}
- /* make sure there are no extraneous keyword arguments */
- j = 0;
- while (1) {
- int match;
- if (kwargs != NULL) {
- if (!PyDict_Next(kwargs, &j, &keyword, NULL))
- break;
- }
- else {
- if (j >= PyTuple_GET_SIZE(kwnames))
- break;
- keyword = PyTuple_GET_ITEM(kwnames, j);
- j++;
- }
- match = PySequence_Contains(kwtuple, keyword);
- if (match <= 0) {
- if (!match) {
- PyErr_Format(PyExc_TypeError,
- "'%S' is an invalid keyword "
- "argument for %.200s%s",
- keyword,
- (parser->fname == NULL) ? "this function" : parser->fname,
- (parser->fname == NULL) ? "" : "()");
- }
- return NULL;
- }
- }
+ error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname);
+ return NULL;
}
return buf;