I am trying to use a c DLL in cython and during the compilation phase I get a warning from the C compiler :
warning C4133: "=" : incompatible types - from 'foobar *' to 'foobar *'.
My pxd looks like this :
#!/usr/bin/env python3
#cython: language_level=3
cdef extern from "typedef.h"
struct foobar:
long *index
double *my_array
int value
cdef extern from "functions.h"
foobar *get_foobar(char *name);
And my pyx like that :
cimport pxd_file_name
cdef class Handler:
cdef pxd_file_name.foobar *__foobar
def load_foobar(self, char *name):
self.__foobar = pxd_file_name.get_foobar(name) <==
def another_method(self):
pass
I got the warning because of the line marked by an arrow and I don't understand why.
Is there a way to fix this ?
I manage to found my mistake.
Because in my .h file, my struct was declared using typedef, I had to write ctypedef struct foobar instead of struct foobar in my pxd file
Related
In an external library is a macro to a type:
typedef TCHAR MY_TYPE;
#define MY_MACRO_TYPE MY_TYPE;
At any place in the library the macro is used instead of the type.
So how can I provide this macro for cython (cdef extern MY_MACRO_TYPE variable)?
I tried to use it like it is:
cdef extern from "my_lib.h":
ctypedef TCHAR MY_TYPE
cdef MY_MACRO_TYPE MY_TYPE
Which throws the following error:
Error compiling Cython file:
------------------------------------------------------------
...
ctypedef TCHAR MY_TYPE
cdef MY_MACRO_TYPE MY_TYPE
^
------------------------------------------------------------
src/pytypes.pxd:22:9: 'MY_MACRO_TYPE' is not a type identifier
warning: src/pytypes.pxd:22:22: 'MY_TYPE' redeclared
While I wrote this question, I found a possible solution, which may help anyone else.
Cause cython just needs to know the type, you can ignore the macro and use a typedef alias instead.
So it looks like:
cdef extern from "my_lib.h":
ctypedef TCHAR MY_TYPE
ctypedef MY_TYPE MY_MACRO_TYPE
Which works for me, without any errors.
I would like to split a pyx file which contains the declaration and definition of a class hierarchy into a pxd and pyx file for further use in another cython module.
Here is my pxd file (instrument.pxd):
cdef struct s_detector:
int size_x
int size_y
int offset
int board_id_max
ctypedef s_detector Detector
cdef class Instrument:
cdef int nbdet
cdef Detector* detectors
cdef class D11Instrument(Instrument):
pass
and here is my pyx file (instrument.pyx):
from libc.stdlib cimport free, malloc
from instrument cimport Detector, DetectorDescr, PixelInfo
cdef class Instrument:
def __dealloc__(self):
free(self.detectors)
cdef class D11Instrument(Instrument):
def __cinit__(self):
self.nbdet = 3
self.detectors = <Detector*>malloc(self.nbdet*sizeof(Detector))
self.detectors[0] = [256,192,0,6]
self.detectors[1] = [32,256,49152,7]
self.detectors[2] = [32,256,57344,8]
When compiling those files, I get the following kind of errors:
Error compiling Cython file:
------------------------------------------------------------
...
cdef class Instrument:
def __dealloc__(self):
free(self.detectors)
^
------------------------------------------------------------
extensions/instrument.pyx:11:17: Cannot convert Python object to 'void *'
Error compiling Cython file:
------------------------------------------------------------
...
self.detectors = <Detector*>malloc(self.nbdet*sizeof(Detector))
^
------------------------------------------------------------
extensions/instrument.pyx:48:25: Cannot convert 'Detector *' to Python object
Would you know what I am doing wrong with my pxd/pyx files ?
foo.pxd:
cdef class cls: pass
ctypedef int typ
main.pxd:
from foo cimport cls, typ
main.pyx:
import cython
#cython.locals(a='cls')
def f(a): pass
#cython.locals(b='typ') # doesn't compile
def g(b): pass
Cython compiles function f() but not function g(), saying 'Not a type.'
If I remove the quotes from 'typ' then it will compile, but no longer run in the interpreter.
It's important to me that any solution works compiled AND interpreted.
I'm chasing my tail with what I suspect is a simple problem, but I can't seem to find any explanation for the observed behavior. Assume I have a constant in a C header file defined by:
#define FOOBAR 128
typedef uint32_t mytype_t;
I convert this in Cython by putting the following in the .pxd file:
cdef int _FOOBAR "FOOBAR"
ctypedef uint32_t mytype_t
In my .pyx file, I have a declaration:
FOOBAR = _FOOBAR
followed later in a class definition:
cdef class MyClass:
cdef mytype_t myvar
def __init__(self):
try:
self.myvar = FOOBAR
print("GOOD")
except:
print("BAD")
I then try to execute this with a simple program:
try:
foo = MyClass()
except:
print("FAILED TO CREATE CLASS")
Sadly, this errors out, but I don't get an error message - I just get the exception print output:
BAD
Any suggestions on root cause would be greatly appreciated.
I believe I have finally tracked it down. The root cause issue is that FOOBAR in my code was actually set to UINT32MAX. Apparently, Cython/Python interprets that as a -1 and Python then rejects setting a uint32_t variable equal to it. The solution is to define FOOBAR to be 0xffffffff - apparently Python thinks that is a non-negative value and accepts it.
I want to use a library that gives me a dynamic array. The dynamic array struct has a property void* _heap_ptr which gives the start of the array.
After having built the list, I want to access this pointer in cython (to make a copy of the array). But I cannot seem to get the pointer element from the struct.
Here is my pyx:
cimport src.clist as l
def main():
cdef l.ptr_list basic_list
cdef int i = 42
basic_list = l.create_list_size(sizeof(i), 100)
l.list_add_ptr(basic_list, &i)
cdef int* arr;
arr = basic_list._heap_ptr
for i in range(1):
print(arr[i])
This is the error message:
Error compiling Cython file:
------------------------------------------------------------
...
l.list_add_ptr(basic_list, &i)
cdef int* arr;
arr = basic_list._heap_ptr
^
------------------------------------------------------------
src/test.pyx:14:20: Cannot convert Python object to 'int *'
Error compiling Cython file:
------------------------------------------------------------
...
l.list_add_ptr(basic_list, &i)
cdef int* arr;
arr = basic_list._heap_ptr
^
------------------------------------------------------------
src/test.pyx:14:20: Storing unsafe C derivative of temporary Python reference
And my pxd:
cdef extern from "src/list.h":
ctypedef struct _list:
void* _heap_ptr
ctypedef struct ptr_list:
pass
ptr_list create_list_size(size_t size, int length)
list_destroy(ptr_list this_list)
void* list_at_ptr(ptr_list this_list, int index)
list_add_ptr(ptr_list this_list, void* value)
How can I fix my code? Why is this happening? From my investigations that error message pops up if you have forgotten to declare something as C (ie. use malloc not libc.stdlib.malloc, but I cannot see that anything similar is happening here.)
There are two issues in your code.
First: struct ptr_list has no members and thus no member _heap_ptr. It probably should have been
ctypedef struct ptr_list:
void* _heap_ptr
Cython's error message is not really helpful here, but as you said it pops up usually when a C-declaration is forgotten.
Second: you need to cast from void * to int * explicitly:
arr = <int*>basic_list._heap_ptr