Question

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, &current_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?

Edit:

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, &current_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.

Was it helpful?

Solution

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, &current_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|  &current_level
i   &level
O   &parent_slug
O   ---
O!  &PyBool_Type, &include_category
O!  &PyBool_Type, &include_ancestor
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top