File handler as an argument for a function in cython - cython

What should be the variable type of a _io.TextIOWrapper object as argument for a function in Cython?
e.g.
f = open("myfile.txt","r")
cpdef int myFunction(f):
...
return 0
Something like this?:
cpdef int myFunction(FILE* f):
...
return 0
Thank you.

Related

UnboundLocalError: local variable 'animal_signals' referenced before assignment

I have a some Cython code where if a variable equals a value from a list then values from another list are copied into a testing array.
double [:] signals
cdef int total_days=signals.shape[0]
cdef size_t epoch=0
cdef int total_animals
cdef int n
cdef double[:] animal_signals
for animal in range(total_animals):
individual_animal = uniq_instr[animal]
for element in range(total_days):
if list(animal_ids[n]) == individual_animal:
animal_signals.append(signals[n])
I am getting an error:
UnboundLocalError: local variable 'animal_signals' referenced before assignment
I have thought having the line
cdef double[:] animal_signals
would have meant the array was assigned.
Update
As suggested I have also tried declaring the array animal_signals (and removing the append):
cdef int total_days=signals.shape[0]
cdef size_t epoch=0
cdef int total_animals
cdef int n
cdef int count=0
for animal in range(total_animals):
count=0
individual_animal = uniq_instr[animal]
for element in range(total_days):
if list(animal_ids[element]) == individual_animal:
cdef double[:] animal_signals[count] = signals[n]
count=count+1
however when I compile the code I get the error:
Error compiling Cython file:
------------------------------------------------------------
...
for element in range(total_days):
if list(animal_ids[element]) == individual_animal:
cdef double[:] animal_signals[count] = signals[n]
^
------------------------------------------------------------
project/temps.pyx:288:21: cdef statement not allowed here
Where am I going wrong?
Indeed, your line cdef double[:] animal_signals
declares animal_signals as a variable, but you never assign anything to it before using it (in Python assignement is done with the = operator).
In Cython, using the slice ([:]) notation when defining a variable is usually done to get the memory view of an other object (see the reference documentation).
For example :
some_1d_numpy_array = np.zeros((10,10)).reshape(-1)
cdef double[:] animal_signals = some_1d_numpy_array
If you want to create a C array, you have to allocate the memory for it (here for a size of number entries containing double) :
cdef double *my_array = <double *> malloc(number * sizeof(double))
Also, regarding to your original code, note that in both case you won't be able to use the append method on this object because it will not be a Python list, you will have to access its member by their indexes.

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.

"Storing unsafe C derivative of temporary Python reference" when trying to access struct pointer

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

Cython, using function pointer inside class

I am trying to use a pointer inside a cython class.
the outside_class ctypedef works like a charm but i am unable to get the inside_class to work. a "ctypedef statement not allowed here" error is thrown and i don't understand what is wrong.
Why should this work
the outside_class typdef works so i assumed it should also work inside. I was unable to get it to work so i tried to find some more information on it, unfortunately all information is about the outside_class example so i do not know whether the other is allowed or even possible. to me it seems the only difference is the self argument.
Why do i want this to work
This class is going to contain 35+ functions with the same arguments, when used only a part of those functions is called in a specific order. When initializing i want to create an array with all functions in the correct order. Of course a different way of doing so is also welcome.
updated code sample 14-02
test A & B work but C & D do not, error message is given below.
My code:
ctypedef int (*outside_class)()
ctypedef int (*inside_class)(Preprocess)
cdef int outside_foo():
return 12
cdef int outside_bar(Preprocess self):
return 20
cdef class Preprocess:
cdef int inside_foo(self):
return 18
cdef int inside_bar(self):
return 14
cdef int inside_sek(self):
return 16
def __init__(self):
cdef outside_class test_A
test_A = &outside_foo
print( test_A() )
cdef inside_class test_B
test_B = &outside_bar
print( test_B(self) )
cdef inside_class test_C
test_C = &self.inside_foo
#print( test_C(self) )
print( "no error, yet.." )
cdef inside_class test_D
test_D = &self.inside_foo
print( test_D(self) )
error
/home/boss/.pyxbld/temp.linux-x86_64-2.7/pyrex/aa/preprocessing/preprocessing.c: In function ‘__pyx_pf_7aa_13preprocessing_13preprocessing_10Preprocess___init__’:
/home/boss/.pyxbld/temp.linux-x86_64-2.7/pyrex/aa/preprocessing/preprocessing.c:938:18: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
__pyx_v_test_C = (&((struct __pyx_vtabstruct_7aa_13preprocessing_13preprocessing_Preprocess *)__pyx_v_se
^
/home/boss/.pyxbld/temp.linux-x86_64-2.7/pyrex/aa/preprocessing/preprocessing.c:955:18: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
__pyx_v_test_D = (&((struct __pyx_vtabstruct_7aa_13preprocessing_13preprocessing_Preprocess *)__pyx_v_se
^
12
20
no error, yet..
Segmentation fault (core dumped)
cython raises the error as soon as it sees the cdeftype within the class definition. It hasn't even looked at, or run, the &self.inside_foo assignment:
0000:~/mypy/cython3$ cython stack42214943.pyx -a
Error compiling Cython file:
------------------------------------------------------------
...
cdef int outside_foo():
return 12
cdef class Preprocess:
ctypedef int (*inside_class)(Preprocess)
^
------------------------------------------------------------
stack42214943.pyx:8:4: ctypedef statement not allowed here
If I try cdef int(*)(Preprocess) inside_test, I get a Syntax error in C variable declaration. Again before the self line.
(edit)
With the following code I can create and run both a python list of 3 functions and a C array of the same.
def __init__(self):
cdef outside_class test_A
test_A = &outside_foo
print( test_A() )
cdef inside_class test_B
test_B = &outside_bar
print( test_B(self) )
print(self.inside_foo())
cpdef evalc(self):
# cdef int (*inside_array[3]) (Preprocess)
cdef inside_class inside_array[3]
inside_array[0] = self.inside_foo
inside_array[1] = self.inside_bar
inside_array[2] = self.inside_sek
print('eval inside_array')
for fn in inside_array:
print(fn(self))
def evals(self):
alist = [self.inside_foo, self.inside_bar, self.inside_sek]
alist = [fn(self) for fn in alist]
print(alist)
self.evalc()
In an Ipython session I can compile and import this, and run it with:
In [3]: p=stack42214943.Preprocess()
12
20
18
In [4]: p.evals()
[18, 14, 16]
eval inside_array
18
14
16
In [5]: p.evalc()
eval inside_array
18
14
16
I haven't figured out how to define and access inside_array outside of the evalc function. But maybe I don't need to. And instead of printing, that function could return the 3 values as some sort of int array or list.

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