Inscrutable Cythonize error in passing cdef arg as arg to constructor

15 views
Skip to first unread message

Eric Ewanco

unread,
May 20, 2024, 12:14:41 PMMay 20
to cython-users
I have encountered an error neither I nor ChatGPT can adequately explain. I am trying to pass a `cdef` variable or argument (unchanged) through a function into a class instantiation, and it is apparently trying to convert it (unsuccessfully) into a Python object for reasons I don't understand.

Sanitized MRE:
```
cdef class CppWrapper:
    def __cinit__(self, shared_ptr[int] cpp_buffer):
        pass

cdef inline object wrappedObject(shared_ptr[int] cpp_buffer):
    return CppWrapper(cpp_buffer)
```
To me there should be no issues; `wrappedObject` receives an argument of a C++ type, and passes it unchanged to another `cdef` method that receives an argument of the same C++ type, but Cythonize chokes.

This yields the following "Cannot convert 'shared_ptr[int]' to Python object" error (it is pointing to the `cpp_buffer` argument):
```
[CPython38-build] cdef inline object wrappedObject(shared_ptr[int] cpp_buffer):
[CPython38-build]     return CppWrapper(cpp_buffer)
[CPython38-build]                       ^
[CPython38-build] ------------------------------------------------------------
[CPython38-build]
[CPython38-build] src/ar_sensor_matrix_isp_python/ar_sensor_matrix_isp_python.pyx:204:22: Cannot convert 'shared_ptr[int]' to Python object
```
What I cannot understand is that `cpp_buffer` doesn't need to be converted to a Python object, as the class accepts a cdef argument defined in C-style notation. What am I missing?

To rule out the possibility that it's really complaining about the object *returned* by `CppWrapper` and not the *argument*, I tried `cdef shared_ptr[int] _ = CppWrapper(cpp_buffer)`, and I get the same error.

XY PROBLEM (WHAT I AM TRYING TO DO):

I am trying to construct a Cython/Python wrapper around a C++ class instance that points to a C++ allocated buffer, such that Python can access the buffer contents (as an `np.ndarray`) without a copy and such that it will correctly handle reference counts, deallocating the buffer (via C++) when it goes out-of-scope in Python. (The buffer will not be used by C++ after transfer to Python.) Put more simply, I want a buffer that's allocated in C++ and can transparently be used without copy in Python for the remainder of its lifecycle. (Wish me luck.) The function in question (identified here as `wrappedObject`) is passed, in a `def`-defined Cython function, a `cdef`-declared variable initialized with `make_shared[]()`, which represents the source data. In my MRE this might be, for example, represented by `cdef shared_ptr[int] buffer = make_shared[int](42); return wrappedObject(buffer)`.

Thank you for your help.

da-woods

unread,
May 20, 2024, 1:33:17 PMMay 20
to cython...@googlegroups.com
The basic issue is that `__cinit__` is a function that's called from Python so all arguments to it must be convertable too/from Python. Which `shared_ptr[int]` isn't.

What you probably want to do is initialize to a null pointer in C init, and then set up the pointer to the buffer afterwards.
--

---
You received this message because you are subscribed to the Google Groups "cython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cython-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cython-users/92585882-b1d6-48a0-be92-e32a12885d56n%40googlegroups.com.


Reply all
Reply to author
Forward
0 new messages