getting struct elements in Cython - cython

Amazingly I can't seem to find a single example of getting elements of a struct, by name (both on the web and in the cython examples).
So I'm receiving a pointer to a struct out of a C function, and would want to access those elements one by one and repackage them into a python list/dict.
maybe:
structPointer['propertyName']
or
structPointer.propertyName
I want to get the effect of structName->propertyName.

Your second syntax is the correct one, but you have to have an extern declaration for the struct type:
cdef extern from "someheader.h":
struct properties_t:
int value1
int value2
properties_t* getthem()
cdef void foo():
cdef properties_t* prop
prop = getthem()
i = prop.value1

Related

operator= in Cython cppclass

How can I tell Cython that my C++ class has overloaded operator=? I tried:
cdef extern from "my_source.H":
cdef cppclass MyStatus:
void operator=(const char* status)
cdef public void setStatus(MyStatus& status):
status = "FOO"
but Cython either complains "Assignment to reference status" or (if I make status a non-reference) constructs a python object out of the string "FOO" and then tries to assign the python object to status.
The problem in your code is, that for Cython "FOO" is a Python-object. For expressions like
char *s = "FOO"
Cython is clever enough to understand, what you want and automatically interprets "FOO" as char *.
However, Cython doesn't really "understand"/interpret the signatures of wrapped c++-functions (for that it must be a c++-compiler) and thus cannot know, that you want "FOO" be a char *.
Thus you have to help Cython, for example:
status = <const char *>"FOO"
You also have to work around the problem with reference, for example via:
cdef public void setStatus(MyStatus *status):
status[0] = <const char *>"FOO"
or if you want to have keep the signature of the function intact:
cdef public void setStatus(MyStatus& status):
cdef MyStatus * as_ptr = &status
as_ptr[0] = <const char *>"FOO"
I'm not completely sure the problem with the assigment to reference isn't a bug.
Another observation: the assigment operators aren't part of the "official" wrap of the standard containers, see here or here.

Super constructor in cdef classes

I am working on wrapping a C library using cython. I would like to use a cdef class to wrap a simple struct. The struct does require some parameters to be properly initialized. I put the corresponding code int the __cinit__ method like so:
cdef class Func:
cdef library.Func* func
def __cinit__(self, int value):
library.init_func(&self.func, value)
In python code I can create a function object via f = Func(17). The code then handles the initialization just fine. My question is the following: Say I want to extend the Func class in python (class MyFunc(Func): ...). How do I add a constructor to to MyFunc?
I would like to write a constructor with other parameters which calls
__cinit__(self, int value) with a value derived from constructor parameters. But it does not seem to be possible (likely for good reason) to call __cinit__ from python code.
Is there some way to include constructors in subclasses or should I create a wrapper around the function and delegate methods / properties?

how do I autoconvert a struct* to a dict?

mystruct.pxd
ctypedef struct foo:
pass
ctypedef struct myStruct:
int field1
int field2
foo* field3
mystruct.pyx
class MyStruct:
cdef myStruct* _ptr
def __cinit__(self):
self._ptr = create_myStruct()
def __getattr__(self, key):
if key in self._ptr[0]:
return self._ptr[0][key]
__getattr__ does not compile with cython. Attempting to index non-array type 'myStruct'
Removing the [0] results in a compiler crash.
Attempts to do:
def get_dict(self):
return self._ptr # cannot convert 'myStruct *' to Python object
return self._ptr[0] # cannot convert 'myStruct' to Python object
These structs have many fields that I need to access as properties. Writing basic #property wrappers is adding a lot of clutter to the file so I'd like to be able to use a simple getaddr instead. Any thought?
UPDATE: changed type of field3
It seems the problem is with foo* field3 since foo is a custom struct and not a primitive type (numeric, char*) autoconversion will not work. There does not appear to be a way to fix this directly. I have two workarounds:
Change the type of field3 to unsigned int (or whatever your pointer size is) and cast to foo* when you need to access the sub-structure. This is not a very nice workaround but if your members are really opaque types and not accessible structs, it works just fine.
Write something to explicitly convert to a dict.
This is what I ended up doing. It's another repetition of the field names but it can be easily created with copy-paste-modify
def to_dict(self):
return {'field1':self._ptr.field1,
'field2':self._ptr.field2,
'field3':FooWrapper().from_ptr(self._ptr.field3) # or an int if opaque
}
cdef class FooWrapper:
cdef foo* _ptr
def from_ptr(self, ptr):
assert(ptr is not NULL)
self._ptr = ptr
return self

Auto Conversion of Structs to Dicts in Cython

So, if you've got a header file.
%%file test.h
struct mystruct{
int i;
int j;
};
And then you wrap it in Cython:
cdef extern from "test.h" nogil:
struct mystruct:
int i
int j
And some function that returns back out to Py:
def spit_out_dict():
return mystruct(5,10)
Cython correctly automatically generates a dict wrapper. However, when I wrap the original C header in a namespace, I haven't been able to get get Cython to still generate the dict wrapper correctly, something along these lines:
%%file test2.h
namespace outerspace{
struct mystruct{
int i;
int j;
};
}
And Cython/Python:
cdef extern from "test2.h" namespace "outerspace" nogil:
struct mynewstruct:
int i
int j
def spit_out_dict():
return mynewstruct(5,10)
This won't compile -- lots of namespace complaint errors -- anyone experienced this before?
Your problem is that Cython seems to only expect namespaces to be used with cppclass. For structs, it generates some functions but just copies the full namespaced name in, causing errors:
static PyObject* __pyx_convert__to_py_outerspace::mystruct(struct outerspace::mystruct s);
^
py_bit.cpp: In function ‘PyObject* __pyx_pf_6py_bit_spit_out_dict(PyObject*)’:
py_bit.cpp:721:15: error: ‘__pyx_convert__to_py_outerspace’ has not been declared
where it's trying to create a function called __pyx_convert__to_py_<classname>. (I think this might be worth submitting a bug report for.)
The trick in such circumstances is usually to lie to Cython. I create three files:
// test2.hpp
namespace outerspace{
struct mystruct{
int i;
int j;
};
}
,
// test2_cy.hpp - a wrapper file purely for Cython's benefit
#include "test2.hpp"
using outerpsace::mystruct;
and the cython file
cdef extern from "test2_cy.hpp": # (I didn't test with "nogil", but it's probably fine...)
struct mynewstruct:
int i
int j
def spit_out_dict():
# for some reason using "return mystruct(5,10)" doesn't work, but this does...
cdef mystruct a = mystruct(5,10)
return a
This is a bug in Cython, fixed at https://github.com/cython/cython/commit/fa946e8435a4dcc3497fc7b0f4e87256d40844ba

Cython recursive struct declarations

I'm trying to use a C struct in Cython, that defines a linked list:
typedef struct {
struct query_result* next_result;
char* result;
} query_result;
As you can see I'm using the query_result type inside its own definition.
Using this as is, in Cython gives me compiler errors:
cdef extern from 'c_wrapper.h':
struct query_result:
struct query_result*
char*
Any ideas about how to properly handle this recursive definition in Cython?
You shouldn't use the struct keyword when you are referring to the type:
cdef extern from 'c_wrapper.h':
struct query_result:
query_result* more
char* data