Error when splitting pyx file into pxd and pyx file - cython

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 ?

Related

Not possible to initialize C++ vector from pointer

I'd like to initialize a C++ STL vector by using the
template<class InputIt>
std::vector(InputIt first, InputIt last);
constructor in Cython. Here's a simple example:
from libcpp.vector cimport vector
import numpy as np
cimport numpy as cnp
cnp.import_array()
def foo(double[::1] a):
cdef vector[double] vec = vector[double](&a[0], &a[0] + a.size)
# do something with vec..
However, this yields the error message
from libcpp.vector cimport vector
def foo(double[::1] a):
cdef vector[double] vec = vector[double](&a[0], &a[0] + a.size)
^
------------------------------------------------------------
.ipython/cython/_cython_magic_c522d88d9553084771dd501620335f85a93b04ae.pyx:5:52: Cannot convert 'double *' to Python object
Error compiling Cython file:
------------------------------------------------------------
...
from libcpp.vector cimport vector
def foo(double[::1] a):
cdef vector[double] vec = vector[double](&a[0], &a[0] + a.size)
^
------------------------------------------------------------
.ipython/cython/_cython_magic_c522d88d9553084771dd501620335f85a93b04ae.pyx:5:45: Cannot assign type 'double *' to 'size_type
Any idea what I am doing wrong?
As mentioned in the comments, your desired constructor is not available inside Cython. AFAIK, Cython doesn't support templated constructors yet. As a workaround, you could use .assign(), i.e.:
from libcpp.vector cimport vector
def foo(double[::1] a):
cdef vector[double] vec
vec.assign(&a[0], &a[0] + <size_t>a.size)
# do something with vec..

Cython compilation warning incompatible types

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

can I use a typedef in #cython.locals

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.

How to iterate over objects contained in some other structure and call their methods (make them known to Cython)?

Methods go unrecognized when I iterate over objects of the same type (or of derived class) and call the same method within a loop.
This happens when I iterate over objects stored in a data structure (in this case, collections.OrderedDict) within a class I've defined. I've made the methods available to Cython in a pxd file.
This happens whether or not MyClass is a base class or derived class.
I'm using unittest to test my code.
I'm wondering if Cython doesn't support this or if some information about an object is missing when it's a Cython extension.
myclass.pxd
cdef class MyClass():
cdef public object _dict
cdef void add_obj(self, name, obj)
cdef void m(self)
cdef void _m(self)
myclass.pyx
from collections import OrderedDict
cdef class MyClass():
def __cinit__(self):
self._dict = OrderedDict()
cdef void add_obj(self, name, obj):
self._dict[name] = obj
cdef void m(self):
# user defines this in derived class
pass
cdef void _m(self):
cdef int i = 0
print('running user defined method')
self.m()
print(self._dict.keys())
print('adding objects')
for key, obj in self._dict.items():
# ERROR
print('obj')
print(obj)
obj.m()
i += 1
print('added an object')
print(i)
test.pyx
from mypkg.core.myclass cimport MyClass
import unittest
cdef class ChildClass(MyClass):
cdef void m(self):
self.add_obj('a', MyClass())
self.add_obj('b', MyClass())
self.add_obj('c', MyClass())
cdef class ParentClass(MyClass):
cdef void m(self):
self.add_obj('a', ChildClass())
self.add_obj('b', ChildClass())
self.add_obj('c', ChildClass())
cdef ParentClass H = ParentClass()
class SetupTree(unittest.TestCase):
def setUp(self):
H._m()
def test_tree(self):
print(H._dict)
print(len(H._dict))
Output
running user defined method
odict_keys(['a', 'b', 'c'])
adding objects
obj
<mypkg.test.test_system2.ChildClass object at 0x7f86ff915b38>
AttributeError: 'mypkg.test.test_system2.ChildClass' object has no attribute 'm'
Exception ignored in: 'mypkg.core.group.MyClass._m'
AttributeError: 'mypkg.test.test_system2.ChildClass' object has no attribute 'm'
OrderedDict([('a', <mypkg.test.test_system2.ChildClass object at 0x7f86ff915b38>), ('b', <mypkg.test.test_system2.ChildClass object at 0x7f86ff915d30>), ('c', <mypkg.test.test_system2.ChildClass object at 0x7f86ff915c88>)])
3
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
cdef methods can only be called if they can be found at compile time - they can't be looked up as Python attributes at runtime. You've done nothing in _m to tell Cython that obj is a MyClass, so it does not know of the existence of the cdef method.
You have two options:
Change the cdef m(...) to def (or cpdef) so it can be found by Python at runtime.
Tell Cython that obj is an instance of MyClass:
cdef MyClass obj # you'll receive an TypeError exception if you ever
# attempt to assign something that isn't a MyClass to obj
for key, obj in self._dict.items():
obj.m() # now works!

Cython - Wrapping pointer to structure from C to python

I have a C function which take pointer to struct and i want to use it in python by C-Extensions by Cython way but when i want to pass pointer to struct from python give me an error: "Cannot convert Python object to 'Foo *'"
In the below example i make object to call the C function but what passed to C function is NULL pointer.
My Trial:
hello.h
#include <stdio.h>
typedef struct
{
int x;
} Foo;
int hello(Foo* what);
hello.c
#include "hello.h"
int hello(Foo* what)
{
printf("Hello Wrapper\n");
printf("what: %p\n", what);
what->x = 5;
return what->x;
}
phello.pxd
cdef extern from "hello.h":
ctypedef struct Foo:
int x
cdef int hello(Foo* what)
phello.pyx
cimport phello
cdef class Foo_c:
cdef phello.Foo* s
def hello_fn(self):
return phello.hello(self.s)
setup.py
from distutils.core import setup, Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext': build_ext},
ext_modules=[ Extension("hellomodule",
sources=["phello.pyx", "hello.c"],
) ]
test.py
import hellomodule
print "Hello test.py"
tobject = hellomodule.Foo_c()
print "Object:", tobject
tobject.hello_fn()
So i want create "Foo" struct in "test.py" and pass it to "hello_fn()" function to call the C function "hello()" after passing this struct, so i can read or write on this structure from both sides python & C.
Can Anyone help me in this, please?
Your code does not allocate memory for phello.Foo. Allocation can be done in __cinit__ with calloc (or malloc) and deallocation in __dealloc__ with free.
cimport phello
from libc.stdlib cimport calloc, free
cdef class Foo_c:
cdef phello.Foo* s
def __cinit__(self, int n):
self.s = <phello.Foo *>calloc(1, sizeof(phello.Foo))
def __dealloc__(self):
free(<void *>self.s)
def __init__(self, int n):
self.s.x = n