Wrapping / Casting Cstr dans la classe Cython to Python

Je commence tout juste à me familiariser avec Cython, en essayant d’envelopper des structures d’une bibliothèque C dans des méthodes et des classes Python. Ce que je ne comprends pas vraiment, c’est comment devrait fonctionner le transtypage de structures C (initialisées) vers la classe Python correspondante. Qu’est-ce que j’oublie ici:

Un extrait du fichier d’en-tête C:

struct test_struct { int _something; complex_struct* _another; }; typedef struct test_struct test; test *test_new(void); int some_method(test **n, int irrelevant); 

Extrait correspondant de mon fichier .pxd:

 cdef struct test_struct: pass ctypedef test_struct test test* test_new() int some_method(test **n, int irrelevant) 

Mon .pyx:

 def do_something(int irrelevant): cdef test* t = test_new() ret = some_method(&t, irrelevant) # Here comes the problem... return t cdef class Test: cdef test* _t # cinit here and some methods here. No members except _t 

Tout jusqu’à la déclaration de retour fonctionne bien. J’obtiens une valeur correcte dans ret , etc. Mais la conversion dans l’instruction de retour semble être incorrecte ou il manque plus d’informations. Lors de l’émission de t = do_something(42) Python.

Le segfault lui-même n’est pas du tout utile:

 Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7a9e74b in internal_print () from /usr/lib/libpython2.7.so.1.0 (gdb) bt #0 0x00007ffff7a9e74b in internal_print () from /usr/lib/libpython2.7.so.1.0 #1 0x00007ffff7a81adb in PyFile_WriteObject () from /usr/lib/libpython2.7.so.1.0 #2 0x00007ffff7b19acb in sys_displayhook () from /usr/lib/libpython2.7.so.1.0 #3 0x00007ffff7a64c23 in PyObject_Call () from /usr/lib/libpython2.7.so.1.0 #4 0x00007ffff7af2ff7 in PyEval_CallObjectWithKeywords () from /usr/lib/libpython2.7.so.1.0 #5 0x00007ffff7af6f3b in PyEval_EvalFrameEx () from /usr/lib/libpython2.7.so.1.0 #6 0x00007ffff7af91b0 in PyEval_EvalCodeEx () from /usr/lib/libpython2.7.so.1.0 #7 0x00007ffff7af92b2 in PyEval_EvalCode () from /usr/lib/libpython2.7.so.1.0 #8 0x00007ffff7b11f9f in run_mod () from /usr/lib/libpython2.7.so.1.0 #9 0x00007ffff7b13ec0 in PyRun_InteractiveOneFlags () from /usr/lib/libpython2.7.so.1.0 #10 0x00007ffff7b140ae in PyRun_InteractiveLoopFlags () from /usr/lib/libpython2.7.so.1.0 #11 0x00007ffff7b1470e in PyRun_AnyFileExFlags () from /usr/lib/libpython2.7.so.1.0 #12 0x00007ffff7b24bcf in Py_Main () from /usr/lib/libpython2.7.so.1.0 #13 0x00007ffff746f000 in __libc_start_main () from /usr/lib/libc.so.6 #14 0x000000000040073e in _start () 

Comme vous pouvez le constater, la méthode do_something doit renvoyer un object Python de type Test. Que dois-je append pour que le casting soit un succès? Dois-je mapper manuellement la structure à la classe Python? Y a-t-il de la magie Cython que je peux utiliser?

Vous devez faire de Test un wrapper réel autour du type C. Mais vous ne pouvez pas non plus transmettre un argument C à une fonction Python (telle qu’un constructeur). Vous aurez donc également besoin d’une fonction d’usine. Voici un exemple:

 cdef class Test: cdef test* _t def __cinit__(self): self._t = NULL def _setup(self, test* t): self._t = t return self property something: def __get__(self): return self._t._something def __set__(self, int val): self._t._something = val cdef Test_create(test* t): return Test()._setup(t) 

Puis dans do_something() :

 return Test_create(t)