Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does ctypes provide anything for enums and flags?

Tags:

python

ctypes

I have an API I'd like to use from python. That API contains flags and enums implemented with #define.

// it's just almost C so don't bother adding the typedef and parenthesis diarrhea here.
routine(API_SOMETHING | API_OTHERTHING)
stuff = getflags()
? stuff & API_SOMETHING

action(API_INTERESTING)
mode = getaction()
? mode == INTERESTING

If ignoring everything else except enums and flags now, my bindings should translate this to:

routine(["something", "otherthing"])
stuff = getflags()
if 'something' in stuff

action('interesting')
mode = getaction()
if mode == 'interesting'

Does ctypes provide mechanisms to do this straight out? If not then just tell about your 'usual' tool for handling flags and enums in python bindings.

like image 390
Cheery Avatar asked Jun 23 '10 10:06

Cheery


People also ask

Why is Ctypes used in Python?

ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.

How does ctype work?

ctypes allows to create C callable function pointers from Python callables. These are sometimes called callback functions. First, you must create a class for the callback function, the class knows the calling convention, the return type, and the number and types of arguments this function will receive.

What does enum do?

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.


2 Answers

I'm a bit disappointed to answer to this question myself. Especially since I found it all from the f* manual.

http://docs.python.org/library/ctypes.html#calling-functions-with-your-own-custom-data-types

To complete my answer, I'll write some code that does wrap an item.

from ctypes import CDLL, c_uint, c_char_p

class Flag(object):
    flags = [(0x1, 'fun'), (0x2, 'toy')]
    @classmethod
    def from_param(cls, data):
        return c_uint(encode_flags(self.flags, data))

libc = CDLL('libc.so.6')
printf = libc.printf
printf.argtypes = [c_char_p, Flag]

printf("hello %d\n", ["fun", "toy"])

encode_flags transforms that nifty list into an integer.

like image 61
Cheery Avatar answered Sep 24 '22 06:09

Cheery


Why don't you use c_uint for the enum parameter and then use a mapping like this (enums are usually unsigned integer values):

in C:

typedef enum {
  MY_VAR      = 1,
  MY_OTHERVAR = 2
} my_enum_t;

and in Python:

class MyEnum():
    __slots__ = ('MY_VAR', 'MY_OTHERVAR')

    MY_VAR = 1
    MY_OTHERVAR = 2


myfunc.argtypes = [c_uint, ...]

You can then pass MyEnum fields to the function.

If you want a string representation for the enumerated values, you can use a dictionary in the MyEnum class.

like image 27
the_void Avatar answered Sep 23 '22 06:09

the_void