2

I am using a Python C Api to fill the list containing the PyObject* elements and transfer it to the function in Python. Everything went very smoothly but there is one issue - transfered list in Python is containing odd <NULL> entries. List is containing "wanted" objects as well so it looks like it's almost-working.

This is the list preview:

[<NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <NULL>, <dbg.TBack object at 0x19675870>, <interface.Grid object at 0x196758B0>, <interface.Grid object at 0x196758F0>, <interface.slp object at 0x196757D0>]

Code I am using for filling the list in Python C API.

PyObject* list = PyList_New(objectsList.size());
PyObject* handle;

for (auto child : objectsList) {
    if (!child) {
        continue;
    }

    handle = child->GetHandle(); // handle = PyObject*
    if (!handle) {
        continue;
    }

    PyList_Append(list, handle);
}

return list; // push

I have tried adding if(!handle) checks but it doesn't seem to have any result in practise.

Question: How can I get rid of the <NULL> entries in my list?

Lucas
  • 3,517
  • 13
  • 46
  • 75

2 Answers2

2

Try this solution

if (handle == Py_None) {
    continue;
}   

Or

int PyObject_Not(PyObject *o)

Returns 0 if the object o is considered to be true, and 1 otherwise. This is equivalent to the Python expression not o. On failure, return -1.

Otherwise, maybe you could check handle's string representation. According to the documentation, you might be able to use some combination of

int       PyObject_Compare(PyObject *o1, PyObject *o2)
PyObject* PyObject_Repr   (PyObject *o)

I'm thinking something like

PyObject* null_str   = Py_BuildValue("null_str", "<NULL>");
PyObject* handle_str = PyObject_Repr(handle);
if (!PyObject_Compare(null_str, handle_str)) {
    continue;
}
maddouri
  • 3,737
  • 5
  • 29
  • 51
1

The issue is in how you allocate the list. From the documentation for PyList_New(Py_ssize_t len):

Note: If len is greater than zero, the returned list object’s items are set to NULL. Thus you cannot use abstract API functions such as PySequence_SetItem() or expose the object to Python code before setting all items to a real object with PyList_SetItem().

I.e. it's making a list of "len" null pointers, rather than making an empty list with preallocated space.

The solution is either:

  1. make an empty list (pass len 0) and keep the rest of your code the same (using PyList_Append), or
  2. allocate the list with a size, and use PyList_SetItem instead of append. It you use this approach be aware that PyList_setItem steals a reference (so you'll have to incref handle), and that the length of the list you want only includes those objects with getHandle()!=NULL.
DavidW
  • 29,336
  • 6
  • 55
  • 86