Cython unsigned char uuid_t[16] representaion

风格不统一 提交于 2020-07-31 05:59:06

问题


I have structure declarations in my code:

cdef extern from "uuid/uuid.h":
    ctypedef unsigned char uuid_t[16]


cdef extern from "fr_common.h":
    ctypedef uuid_t fr_id_t

    ctypedef struct fr_event_t:
       fr_id_t id
       size_t action
       fr_id_t object_id
       long long ts

Here I have cython class where I need to pass fr_id_t id value from fr_event_t structure.

cdef class Event:
    cdef:
        bytes _id
        int _action
        bytes object_id
        int _ts

    def __cinit__(self, fr_id_t id, int action, fr_id_t object_id, int ts):
        self._id = id
        self._action = action
        self._object_id = object_id
        self._ts = ts
    
    @staticmethod
    cdef Event from_c(fr_event_t fr_event):
        return Event(
            fr_id_t=fr_event.id,
            action=fr_event.action,
            object_id=fr_event.object_id,
            ts=fr_event.ts,

How I can represent fr_id_t type passing it in the function somehow else? Its representation is unsigned char uuid_t[16] that stores bytes. Passing fr_id_t is not working and cython compiler gives me assertion error while compiling my .pyx file into .so.

AssertionError: (<FileSourceDescriptor:/home/dmitriyravdel/teyefr/teye-fr/python/teyefr/_teyefr.pyx>, 356, 24): (__pyx_v_id == ((unsigned char *)NULL)) && PyErr_Occurred()

回答1:


The error message is a bug in Cython an makes it pretty hard to diagnose. However, what you're trying to do doesn't make a lot of sense to me.

__init__ and __cinit__ are fundamentally Python methods and their arguments must be Python objects

All constructor arguments will be passed as Python objects. This implies that non-convertible C types such as pointers or C++ objects cannot be passed into the constructor from Cython code. If this is needed, use a factory function instead that handles the object initialisation. It often helps to directly call __new__() in this function to bypass the call to the __init__() constructor.

What will happen (if your code worked) is that first fr_event.id will be converted to a Python object to be passed to __cinit__ then it'll be converted back to a fr_id_t, then it'll be converted to a bytes where you store it. This is not what you want! It looks like one of these conversions has confused Cython.

What you actually want to do is to create a genuinely empty Event in from_c:

@staticmethod
cdef from_c(fr_event_t event):
    cdef Event e = Event.__new__()  # This only works if __cinit__ is removed or takes no arguments
    e._id = event.id
    # etc
    return e

You also cannot have fr_id_t arguments to __cinit__ since these are what triggers the issue. I'd suggest that it isn't meaningful to construct Event objects from Python (only Cython) so that you probably shouldn't have a __cinit__ at all. Another alternative would be to have a __cinit__ that takes the Python equivalent types bytes and int:

cdef class Event:
    cdef bytes _id
    def __cinit__(self, bytes id):
        self._id = id

    @staticmethod
    cdef from_c(fr_event_t event):
        return Event(event.id)

(I've cut this example down further for the sake of simplicity)



来源:https://stackoverflow.com/questions/63036383/cython-unsigned-char-uuid-t16-representaion

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!