0

IMPORTANT UPDATE: reproducible example here

I have code similar to one in documentation, so that the class is created from pointer. It works perfectly, when both class definition and class instance creation are in the same file.

main.pyx:

cdef some_type * ptr_to_wrapped_type = <some_type *>malloc(sizeof(some_type))

#next part from documentation
cdef class WrapperClass:
    """A wrapper class for a C/C++ data structure"""
    cdef my_c_struct *_ptr
    cdef bint ptr_owner

    @staticmethod
    cdef WrapperClass from_ptr(my_c_struct *_ptr, bint owner=False):
        """Factory function to create WrapperClass objects from
        given my_c_struct pointer.
        Setting ``owner`` flag to ``True`` causes
        the extension type to ``free`` the structure pointed to by ``_ptr``
        when the wrapper object is deallocated."""
        # Call to __new__ bypasses __init__ constructor
        cdef WrapperClass wrapper = WrapperClass.__new__(WrapperClass)
        wrapper._ptr = _ptr
        wrapper.ptr_owner = owner
        return wrapper
...

data = WrapperClass.from_ptr(ptr_to_wrapped_type, owner=True)

What I want is to move class definition into separate file and import it in main. This is also described in docs and that's what I have:

wrapper.pxd:

# Example C struct
ctypedef struct my_c_struct:
    int a
    int b

cdef class WrapperClass:
    """A wrapper class for a C/C++ data structure"""
    cdef my_c_struct *_ptr
    cdef bint ptr_owner

wrapper.pyx(class definition from docs):

from libc.stdlib cimport malloc, free

cdef class WrapperClass:
    """A wrapper class for a C/C++ data structure"""
    cdef my_c_struct *_ptr
    cdef bint ptr_owner

    def __cinit__(self):
        self.ptr_owner = False

    def __dealloc__(self):
        # De-allocate if not null and flag is set
        if self._ptr is not NULL and self.ptr_owner is True:
            free(self._ptr)
            self._ptr = NULL

    @staticmethod
    cdef WrapperClass from_ptr(my_c_struct *_ptr, bint owner):
        """Factory function to create WrapperClass objects from
        given my_c_struct pointer.
        Setting ``owner`` flag to ``True`` causes
        the extension type to ``free`` the structure pointed to by ``_ptr``
        when the wrapper object is deallocated."""
        # Call to __new__ bypasses __init__ constructor
        cdef WrapperClass wrapper = WrapperClass.__new__(WrapperClass)
        wrapper._ptr = _ptr
        wrapper.ptr_owner = owner
        return wrapper
...

And finally in main.pyx:

cdef some_type * ptr_to_wrapped_type = <some_type *>malloc(sizeof(some_type))

from wrapper cimport WrapperClass

data = WrapperClass.from_ptr(ptr_to_wrapped_type, owner=True)

Unfortunately, at compilation I get an Error:

data = WrapperClass.from_ptr(ptr_to_wrapped_type, owner=True)
                            ^
------------------------------------------------------------

Cannot convert 'some_type *' to Python object

What is wrong?

7
  • 1
    Did you define a @staticmethod function for your WrapperClass called from_ptr? Commented Jul 24, 2019 at 15:01
  • @CodeSurgeon, Yes. Changes in method are minimal. Literaly I added only one assignment, in doc example terms it looks like wrapper.new_var = _ptr.b and of course I added cdef int * new_var at the beginning of the class Commented Jul 25, 2019 at 8:41
  • @DavidW, as an expert in cython, can you, please point me out the mistake? Commented Jul 25, 2019 at 10:38
  • 2
    In your not working example on github, when you use a .pxd (header) file, all cdef and cpdef functions need to be listed there as well (without the implementation/function body). That way, these functions are accessible when you cimport the class into other .pyx modules. That is why your main.pyx can't find the WrapperClass's from_ptr function. Commented Jul 25, 2019 at 13:11
  • @IvanMishalkin - the comma after my name meant I didn't get notified (might be useful to know this...). CodeSurgeon is right though (and should probably write this up as an answer) Commented Jul 25, 2019 at 13:16

1 Answer 1

1

In your not working example on github, when you use a .pxd (header) file, all cdef and cpdef functions need to be listed there as well (without the implementation/function body). That way, these functions are accessible when you cimport the class into other .pyx modules. That is why your main.pyx can't find the WrapperClass's from_ptr function.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.