I have the following call to PyArg_ParseTupleAndKeywords
in a C Python extension:
static char *kwlist [] = {
"page_slug", "keys", "facets", "categories", "max_level",
"current_level", "level", "parent_slug", "query",
"include_category", "include_ancestor", NULL
};
int max_level, current_level, level = 0;
PyObject *page_slug, *keys, *facets, *categories,
*parent_slug = PyString_FromString(""), *query = Py_None,
*include_category = Py_True, *include_ancestor = Py_True;
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "OO!O!O!ii|iOOO!O!", kwlist,
&page_slug, &PyList_Type, &keys,
&PyDict_Type, &facets, &PyDict_Type, &categories,
&max_level, ¤t_level, &level, &parent_slug,
&PyBool_Type, &include_category,
&PyBool_Type, &include_ancestor)) {
return NULL;
}
Which should result in a signature like:
func(page_slug, keys, facets, categories, max_level,
current_level, level=0, parent_slug="", query=None,
include_category=True, include_ancestor=True)
However, when the method is called from within Python a TypeError
as follows is raised:
TypeError: argument 10 must be (null), not bool
Could anyone explain why argument 10 is expected to be NULL
when it should, theoretically, accept a PyObject*
? And also, how to correct this?
From Python the function is being called as:
func(page_slug, keys, facets, categories, max_level,
current_level, level=level + 1, parent_slug=slug,
query=query, include_category=include_category,
include_ancestor=include_ancestor)
Where page_slug
, parent_slug
, and query
are unicode objects, keys
is a list, max_level
, current_level
, and level
are ints, and facets
, and categories
are dicts.
Not including the boolean arguments (include_ancestor
and include_category
) works (or rather, the call to PyArg_ParseTupleAndKeywords
works, there's a segmentation fault that currently occurs much later in the C function), but including either of them results in the TypeError
being raised.
Changing the call to PyArg_ParseTupleAndKeyword
to:
PyArg_ParseTupleAndKeywords(
args, kwargs, "OO!O!O!ii|iOOOO", kwlist,
&page_slug, &PyList_Type, &keys,
&PyDict_Type, &facets, &PyDict_Type, &categories,
&max_level, ¤t_level, &level, &parent_slug,
&include_category, &include_ancestor)
(i.e. removing the boolean requirement for include_category
and include_ancestor
) causes a segmentation fault in PyArg_ParseTupleAndKeywords
.
You did not pass query
to PyArg_ParseTupleAndKeywords
after &parent_slug,
Call should be
if (!PyArg_ParseTupleAndKeywords(
args, kwargs, "OO!O!O!ii|iOOO!O!", kwlist,
&page_slug, &PyList_Type, &keys,
&PyDict_Type, &facets, &PyDict_Type, &categories,
&max_level, ¤t_level, &level, &parent_slug,
&query, &PyBool_Type, &include_category,
&PyBool_Type, &include_ancestor)) {
return NULL;
}
Your original call results in mismatched format and object list and hence raises an exception (I think).
Breaking down the format and what is being passed
O &page_slug
O! &PyList_Type, &keys
O! &PyDict_Type, &facets
O! &PyDict_Type, &categories
i &max_level
i| ¤t_level
i &level
O &parent_slug
O ---
O! &PyBool_Type, &include_category
O! &PyBool_Type, &include_ancestor