msg = "only compatible with free-threaded CPython"
with self.assertRaisesRegex(ImportError, msg):
_testcapi.pyabiinfo_check(modname, 1, minor, ft_flag, build, 0)
+
+
+class TestModsupport(unittest.TestCase):
+ def test_pyarg_parsearray(self):
+ func = _testcapi.pyarg_parsearray
+ self.assertEqual(func(1, 2), (1, 2, 0))
+ self.assertEqual(func(1, 2, 3), (1, 2, 3))
+ self.assertRaises(TypeError, func, 1)
+ self.assertRaises(TypeError, func, "str", 2)
+
+ def test_funcandkeywords(self):
+ func = _testcapi.pyarg_parsearrayandkeywords
+ self.assertEqual(func(1, 2), (1, 2, 0))
+ self.assertEqual(func(1, 2, 3), (1, 2, 3))
+ self.assertEqual(func(1, b=2), (1, 2, 0))
+ self.assertEqual(func(1, b=2, c=3), (1, 2, 3))
+ self.assertRaises(TypeError, func, 1)
+ self.assertRaises(TypeError, func, "str", 2)
+ self.assertRaises(TypeError, func, 1, z=2)
Py_RETURN_NONE;
}
+static PyObject *
+pyarg_parsearray(PyObject* self, PyObject* const* args, Py_ssize_t nargs)
+{
+ int a, b, c = 0;
+ if (!PyArg_ParseArray(args, nargs, "ii|i", &a, &b, &c)) {
+ return NULL;
+ }
+ return Py_BuildValue("iii", a, b, c);
+}
+
+static PyObject *
+pyarg_parsearrayandkeywords(PyObject* self, PyObject* const* args,
+ Py_ssize_t nargs, PyObject* kwnames)
+{
+ int a, b, c = 0;
+ const char *kwlist[] = {"a", "b", "c", NULL};
+ if (!PyArg_ParseArrayAndKeywords(args, nargs, kwnames,
+ "ii|i", kwlist,
+ &a, &b, &c)) {
+ return NULL;
+ }
+ return Py_BuildValue("iii", a, b, c);
+}
+
static PyMethodDef TestMethods[] = {
{"pyabiinfo_check", pyabiinfo_check, METH_VARARGS},
+ {"pyarg_parsearray", _PyCFunction_CAST(pyarg_parsearray), METH_FASTCALL},
+ {"pyarg_parsearrayandkeywords",
+ _PyCFunction_CAST(pyarg_parsearrayandkeywords),
+ METH_FASTCALL | METH_KEYWORDS},
{NULL},
};
static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **);
static int getbuffer(PyObject *, Py_buffer *, const char**);
-static int vgetargskeywords(PyObject *, PyObject *,
- const char *, const char * const *, va_list *, int);
+static int
+vgetargskeywords(PyObject *args, PyObject *kwargs,
+ const char *format, const char * const *kwlist,
+ va_list *p_va, int flags);
+static int
+vgetargskeywords_impl(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject *kwnames,
+ const char *format, const char * const *kwlist,
+ va_list *p_va, int flags);
static int vgetargskeywordsfast(PyObject *, PyObject *,
struct _PyArg_Parser *, va_list *, int);
static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
return retval;
}
+int
+PyArg_ParseArray(PyObject *const *args, Py_ssize_t nargs, const char *format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ int retval = vgetargs1_impl(NULL, args, nargs, format, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+int
+PyArg_ParseArrayAndKeywords(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwnames,
+ const char *format,
+ const char * const *kwlist, ...)
+{
+ if ((args == NULL && nargs != 0) ||
+ (kwnames != NULL && !PyTuple_Check(kwnames)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ va_list va;
+ va_start(va, kwlist);
+ int retval = vgetargskeywords_impl(args, nargs, NULL, kwnames, format,
+ kwlist, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+
int
PyArg_VaParse(PyObject *args, const char *format, va_list va)
{
static PyObject *
new_kwtuple(const char * const *keywords, int total, int pos);
+static PyObject*
+find_keyword_str(PyObject *kwnames, PyObject *const *kwstack, const char *key)
+{
+ Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames);
+ for (Py_ssize_t i = 0; i < nkwargs; i++) {
+ PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
+ assert(PyUnicode_Check(kwname));
+ if (PyUnicode_EqualToUTF8(kwname, key)) {
+ return Py_NewRef(kwstack[i]);
+ }
+ }
+ return NULL;
+}
+
#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')
static int
-vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
- const char * const *kwlist, va_list *p_va, int flags)
+vgetargskeywords_impl(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject *kwnames,
+ const char *format, const char * const *kwlist,
+ va_list *p_va, int flags)
{
char msgbuf[512];
int levels[32];
int max = INT_MAX;
int i, pos, len;
int skip = 0;
- Py_ssize_t nargs, nkwargs;
+ Py_ssize_t nkwargs;
freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
freelist_t freelist;
+ PyObject * const *kwstack = NULL;
freelist.entries = static_entries;
freelist.first_available = 0;
freelist.entries_malloced = 0;
- assert(args != NULL && PyTuple_Check(args));
+ assert(args != NULL || nargs == 0);
assert(kwargs == NULL || PyDict_Check(kwargs));
+ assert(kwnames == NULL || PyTuple_Check(kwnames));
assert(format != NULL);
assert(kwlist != NULL);
assert(p_va != NULL);
freelist.entries_malloced = 1;
}
- nargs = PyTuple_GET_SIZE(args);
- nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs);
+ if (kwargs != NULL) {
+ nkwargs = PyDict_GET_SIZE(kwargs);
+ }
+ else if (kwnames != NULL) {
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ kwstack = args + nargs;
+ }
+ else {
+ nkwargs = 0;
+ }
if (nargs + nkwargs > len) {
/* Adding "keyword" (when nargs == 0) prevents producing wrong error
messages in some special cases (see bpo-31229). */
if (!skip) {
PyObject *current_arg;
if (i < nargs) {
- current_arg = Py_NewRef(PyTuple_GET_ITEM(args, i));
+ current_arg = Py_NewRef(args[i]);
}
else if (nkwargs && i >= pos) {
- if (PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg) < 0) {
- return cleanreturn(0, &freelist);
+ if (kwargs != NULL) {
+ if (PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg) < 0) {
+ return cleanreturn(0, &freelist);
+ }
+ }
+ else {
+ current_arg = find_keyword_str(kwnames, kwstack, kwlist[i]);
}
if (current_arg) {
--nkwargs;
/* make sure there are no arguments given by name and position */
for (i = pos; i < nargs; i++) {
PyObject *current_arg;
- if (PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg) < 0) {
- return cleanreturn(0, &freelist);
+ if (kwargs != NULL) {
+ if (PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg) < 0) {
+ return cleanreturn(0, &freelist);
+ }
+ }
+ else {
+ current_arg = find_keyword_str(kwnames, kwstack, kwlist[i]);
}
if (current_arg) {
Py_DECREF(current_arg);
}
/* make sure there are no extraneous keyword arguments */
j = 0;
- while (PyDict_Next(kwargs, &j, &key, NULL)) {
+ while (1) {
+ if (kwargs != NULL) {
+ if (!PyDict_Next(kwargs, &j, &key, NULL)) {
+ break;
+ }
+ }
+ else {
+ if (j >= nkwargs) {
+ break;
+ }
+ key = PyTuple_GET_ITEM(kwnames, j);
+ j++;
+ }
+
int match = 0;
if (!PyUnicode_Check(key)) {
PyErr_SetString(PyExc_TypeError,
return cleanreturn(1, &freelist);
}
+static int
+vgetargskeywords(PyObject *argstuple, PyObject *kwargs,
+ const char *format, const char * const *kwlist,
+ va_list *p_va, int flags)
+{
+ PyObject *const *args = _PyTuple_ITEMS(argstuple);
+ Py_ssize_t nargs = PyTuple_GET_SIZE(argstuple);
+ return vgetargskeywords_impl(args, nargs, kwargs, NULL,
+ format, kwlist, p_va, flags);
+}
static int
scan_keywords(const char * const *keywords, int *ptotal, int *pposonly)