Wör Du Schnaffzig
Wör Du Schnaffzig

Reputation: 1051

Python3, ctypes API and Enum

It seems i cannot instantiate a ctypes.CFUNCTYPE prototype with an Enum return value even when the Enum contains the classmethod from_param. Anybody experienced that? Is there a workaround, maybe? Did i do something wrong?

This works:

import ctypes as ct

@ct.CFUNCTYPE(ct.c_int, ct.c_int)
def pyfunc(a):
    return 100

print(pyfunc(10))

100

This works, too (linux):

import ctypes as ct
import enum


class MyEnum(enum.Enum):
    A = 1
    B = 2

    @classmethod
    def from_param(cls, param):
        return ct.c_int(param)


printf = ct.CDLL("libc.so.6").printf
printf.restype = MyEnum  
printf(b"1")

<MyEnum.A: 1>

printf(b"12")

<MyEnum.B: 2>

This fails:

import ctypes as ct
import enum

class E(enum.Enum):
    A = 10
   
    @classmethod
    def from_param(cls, param):
        return ct.c_int(param)

 @ct.CFUNCTYPE(E, ct.c_int)
 def pyfunc(a):
     return E(10)
Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    @ct.CFUNCTYPE(E, ct.c_int)
TypeError: invalid result type for callback function

Upvotes: 2

Views: 661

Answers (1)

Ethan Furman
Ethan Furman

Reputation: 69051

There are a couple issues here:

  • the return value of pyfunc is going back to a C routine, so must be a standard ctypes type (E is not a ctype type)

  • neither from_param nor _as_parameter_ appear to be called for a return type

To address these problems you must

  • change the E in @ct.CFUNCTYPE to ct.c_int

and one of the following:

  • use IntEnum instead of Enum

or

  • return E(a).value

or

  • add __int__ and __index__ to your enum (which makes it int-like enough for ctypes):
    class E(enum.Enum):
        A = 10
        #
        def __int__(self):
            return self.value
        __index__ = __int__

Upvotes: 1

Related Questions