title: Cython: Cannot Convert pointer to Python Object after module split
body: <p><strong>The Problem:</strong></p>
  
  <pre><code>Error compiling Cython file:
  ------------------------------------------------------------
  ...
  cpdef Py_GetRemoteDevice(PyChannel Chan):
      ret_val = mod_one.PyRemoteDevice()
      cdef core.RemoteDevice  * tmp
      with nogil:
          tmp = core.GetRemoteDevice(Chan.__instance)
      ret_val.__set_ptr(tmp)
                          ^
  ------------------------------------------------------------
  
  core/mod_two.pyx:11589:25: Cannot convert 'RemoteDevice *' to Python object
  </code></pre>
  
  <p><strong>The Background:</strong>
  I have a fairly large C library I'm wrapping with Cython. Initially I 
  had everything in two files, core.pyx and core.pxd. However, the more
  of the library that was wrapped the larger the core.c file generated.
  2.5 million lines and counting. The compile time and memory usage became
  cumbersome.</p>
  
  <p>I decided to split things into multiple .pyx files. That's when things that used
  to work stopped working.</p>
  
  <p><strong>Disclaimer:</strong>
  Please keep in mind that I've greatly simplified things for this question.
  The wrapped library is somewhat large and proprietary.</p>
  
  <p><strong>The Details:</strong><br>
  <em>core.pxd</em> - contains all the necessary components from the C library<br>
  I'm wrapping. Also a simple Void * wrapper class declaration.</p>
  
  <pre><code>cdef class Void:
      cdef void *__void
      cdef __set_ptr(self, void *ptr)
  
  cdef extern from "core.h":
      ctypedef unsigned char U8
      ctypedef unsigned int U32
  
      void OS_MemSet(U8 *dest, U8 byte, U32 len) nogil
  
  cdef extern from "mod_one.h":
      cdef struct _RemoteDevice
      ctypedef _RemoteDevice RemoteDevice
  
  cdef extern from "mod_two.h":
      cdef struct _Channel
      ctypedef _Channel Channel
  </code></pre>
  
  <p><em>core.pyx</em> - not a whole lot is needed here, really it's just the 
  implementation of the Void * wrapper.</p>
  
  <pre><code>cdef class Void:
      cdef __set_ptr(self, void *ptr):
          self.__void = ptr
  </code></pre>
  
  <p><em>mod_one.pxd</em> - declares the wrapper class for the RemoteDevice C struct</p>
  
  <pre><code>cimport core
  
  cdef class PyRemoteDevice:
      cdef core.RemoteDevice *__instance
      cdef __set_ptr(self, core.RemoteDevice *ptr)
  </code></pre>
  
  <p><em>mod_one.pyx</em> - defines the RemoteDevice wrapper class. Note the 
  __set_ptr function, which is cdef'd and takes a RemoteDevice *</p>
  
  <pre><code>from cpython.mem cimport PyMem_Malloc, PyMem_Free
  import core
  cimport core
  
  cdef class PyRemoteDevice:
      def __cinit__(self):
          self.__instance = &lt;core.RemoteDevice *&gt;PyMem_Malloc(sizeof(core.RemoteDevice))
  
      def __init__(self):
          core.OS_MemSet(&lt;core.U8 *&gt;self.__instance, &lt;core.U8&gt;0, sizeof(core.RemoteDevice))
  
      cdef __set_ptr(self, core.RemoteDevice *ptr):
          self.__instance = ptr
  
      def __dealloc__(self):
          if self.__instance is not NULL:
              PyMem_Free(self.__instance)
              self.__instance = NULL
  </code></pre>
  
  <p><em>mod_two.pxd</em> - declares the Channel wrapper class, which I'm only showing
  here because it's used in the function that is causing me problems.</p>
  
  <pre><code>cimport core
  cimport mod_one
  
  cdef class PyChannel:
      cdef core.Channel *__instance
      cdef __set_ptr(self, core.Channel *ptr)
  </code></pre>
  
  <p><em>mod_two.pyx</em> - defines the Channel wrapper class, and declares the
  Py_GetRemoteDevice function, which wraps the GetRemoteDevice function 
  from the C library.</p>
  
  <pre><code>from cpython.mem cimport PyMem_Malloc, PyMem_Free import core cimport core import mod_one cimport mod_one
  
  cdef class PyChannel:
      def __cinit__(self):
          self.__instance = &lt;core.Channel *&gt;PyMem_Malloc(sizeof(core.Channel))
  
      def __init__(self):
          core.OS_MemSet(&lt;core.U8 *&gt;self.__instance, &lt;core.U8&gt;0, sizeof(core.Channel))
  
      cdef __set_ptr(self, core.Channel *ptr):
          self.__instance = ptr
  
      def __dealloc__(self):
          if self.__instance is not NULL:
              PyMem_Free(self.__instance)
              self.__instance = NULL
  
  cpdef Py_GetRemoteDevice(PyChannel Chan):
      ret_val = mod_one.PyRemoteDevice()
      cdef core.RemoteDevice  * tmp
      with nogil:
          tmp = core.GetRemoteDevice(Chan.__instance)
      ret_val.__set_ptr(tmp)
      return ret_val
  </code></pre>
  
  <p>The problem I'm getting is that when Cythonizing mod_two, I get the 
  following error:</p>
  
  <pre><code>Error compiling Cython file:
  ------------------------------------------------------------
  ...
  cpdef Py_GetRemoteDevice(PyChannel Chan):
      ret_val = mod_one.PyRemoteDevice()
      cdef core.RemoteDevice  * tmp
      with nogil:
          tmp = core.GetRemoteDevice(Chan.__instance)
      ret_val.__set_ptr(tmp)
                          ^
  ------------------------------------------------------------
  
  core/mod_two.pyx:11589:25: Cannot convert 'RemoteDevice *' to Python object
  </code></pre>
  
  <p>I'm a bit confused, because this used to work when I had everything in one
  module. One difference I can see is that all my wrapper classes were wholly defined
  in core.pyx because I wasn't needing to share them between modules. Now
  I need to share them, so I've split them into .pyx and .pxd files.</p>
  
  <p>Can anyone point me in the right direction? I've scoured the Cython docs and Google
  but so far I haven't found anything that answers my question.</p>
  
  <p>Thanks, and please let me know if any additional information is needed!</p>