user3674296
user3674296

Reputation: 69

Cython: Cannot convert Python object to struct

Warning: I am pretty newbie with Cython. :D I have the following pieces of code:

my_structs.h:

typedef struct Dataset{
    int lines;
    char **tid;
}Dataset;

myiolib.pyx:

from libc.stdlib cimport malloc
from libc.string cimport strcpy
from cpython.string cimport PyString_AsString

cdef extern from "my_structs.h":
    cdef struct Dataset:
        int lines
        char **tid


cdef Dataset readDataset(TID_name):
    cdef:
        int i, line_count=0
        Dataset instance

    with open(TID_name, 'rU') as file_iter:
        for line in file_iter:
            line_count=line_count+1

    instance.tid = <char **>malloc(line_count * sizeof(char *))

    i = 0
    with open(TID_name, 'rU') as file_iter:
        for line in file_iter:
            instance.tid[i] = <char *>malloc((len(line)+1) * sizeof(char ))
            strcpy(instance.tid[i], PyString_AsString(line.strip()))
            i += 1

    instance.lines = line_count
    return instance

mytest.pyx:

import myiolib

cdef extern from "my_structs.h":
    cdef struct Dataset:
        int lines
        char **tid


def test():
    cdef Dataset D
    D = myiolib.readDataset("test.dat")

    # Do something...
    # Free memory (?!)

test.py:

import mytest

mytest.test()

When I type: cython -a mytest.pyx it says: "Cannot convert Python object to 'Dataset' ", pointing at D = myiolib.readDataset("test.dat"). Why? I don't understand... What am I doing wrong?

Upvotes: 1

Views: 2791

Answers (1)

Veedrac
Veedrac

Reputation: 60147

First, I think your minimal example is pretty bad. You don't include a setup.py or any other way of running the code.

As such, here's a proper minimal example:

test_python.py

import pyximport
pyximport.install(setup_args={'include_dirs': "."})

import my_test

my_test.test()

my_test.pyx

import my_library

cdef extern from "my_type.h":
    cdef struct MyType:
        int x

def test():
    cdef MyType my_instance
    my_object = my_library.my_function()

my_library.pyx

cdef extern from "my_type.h":
    cdef struct MyType:
        int x

cdef MyType my_function():
    return MyType()

my_type.h

typedef struct MyType {
    int my_attribute;
} MyType;

This errors with:

AttributeError: 'module' object has no attribute 'my_function'

This is because cdef is being used, so import will not allow access to the function. You've used cdef too, so I'm surprised this isn't happening with you. Maybe compiling with setup.py doesn't require this; it wouldn't surprise me. Even then, though, you're using import where you should be using cimport.

Add a my_library.pxd:

cdef extern from "my_type.h":
    cdef struct MyType:
        int x

cdef MyType my_function()

optionally remove cdef extern from the pyx file and change

import my_library

to

cimport my_library

and it works.

If these tips don't fix it for you, please give me an example I can run.

Upvotes: 1

Related Questions