C++ enum to Python namedtuple (cont.)

Here is a way to convert a C++ enum with values to Python.
C++ code:

typedef enum
{
   LADYBUG_RAW_CAM0           = ( 0x1 << 0 ),
   LADYBUG_RAW_CAM1           = ( 0x1 << 1 ),
   LADYBUG_RAW_CAM2           = ( 0x1 << 2 ),
   LADYBUG_RAW_CAM3           = ( 0x1 << 3 ),
   LADYBUG_RAW_CAM4           = ( 0x1 << 4 ),
   LADYBUG_RAW_CAM5           = ( 0x1 << 5 ),
   LADYBUG_ALL_RAW_IMAGES     =  0x0000003F,

   ...

   LADYBUG_PANORAMIC          = ( 0x1 << 12 ),

   LADYBUG_DOME               = ( 0x1 << 13 ),

   LADYBUG_SPHERICAL          = ( 0x1 << 14 ),

   LADYBUG_ALL_CAMERAS_VIEW   = ( 0x1 << 15 ),

   LADYBUG_ALL_OUTPUT_IMAGE   = 0x7FFFFFFF,

} LadybugOutputImage

The Python version:

LadybugOutputImage = dict(
   LADYBUG_RAW_CAM0           = ( 0x1 << 0 ),
   LADYBUG_RAW_CAM1           = ( 0x1 << 1 ),
   LADYBUG_RAW_CAM2           = ( 0x1 << 2 ),
   LADYBUG_RAW_CAM3           = ( 0x1 << 3 ),
   LADYBUG_RAW_CAM4           = ( 0x1 << 4 ),
   LADYBUG_RAW_CAM5           = ( 0x1 << 5 ),
   LADYBUG_ALL_RAW_IMAGES     =  0x0000003F,

   ...

   LADYBUG_PANORAMIC          = ( 0x1 << 12 ),

   LADYBUG_DOME               = ( 0x1 << 13 ),

   LADYBUG_SPHERICAL          = ( 0x1 << 14 ),

   LADYBUG_ALL_CAMERAS_VIEW   = ( 0x1 << 15 ),

   LADYBUG_ALL_OUTPUT_IMAGE   = 0x7FFFFFFF  )
LadybugOutputImage = namedtuple('Enum',
                       LadybugOutputImage.keys() )(**LadybugOutputImage)

Or even better, just get rid of all the packaging and commas on this type if it’s not too long and you have the patience. But you will also have to correct the indenting. Maybe there is a program out there that can do this editing for you.

   LADYBUG_RAW_CAM0           = ( 0x1 << 0 )
   LADYBUG_RAW_CAM1           = ( 0x1 << 1 )
   LADYBUG_RAW_CAM2           = ( 0x1 << 2 )
   LADYBUG_RAW_CAM3           = ( 0x1 << 3 )
   ...
   LADYBUG_ALL_CAMERAS_VIEW   = ( 0x1 << 15 )
   LADYBUG_ALL_OUTPUT_IMAGE   = 0x7FFFFFFF

Python Enum continued

I needed to convert an enum to python so that I could decode some responses from C code. Here is an example of quickly converting a C enum to python.
The C code I am working with has several enum structures, one is a long list of error types:

enum LadybugError
{
   LADYBUG_OK,
   LADYBUG_FAILED,
   LADYBUG_INVALID_ARGUMENT,
   ...
   LADYBUG_INVALID_FRAMERATE,
   LADYBUG_INVALID_OFFSCREEN_BUFFER_SIZE,
   LADYBUG_INVALID_JPEG_IMAGE_STRUCTURE,

   LADYBUG_NUM_LADYBUG_ERRORS,

   LADYBUG_ERROR_FORCE_QUADLET = 0x7FFFFFFF,
}

There are about 70 items in this list.
Here is the conversion using namedtuple:

LadybugError = namedtuple('Enum', '''
   LADYBUG_OK,
   LADYBUG_FAILED,
   LADYBUG_INVALID_ARGUMENT,
   ...
   LADYBUG_INVALID_FRAMERATE,
   LADYBUG_INVALID_OFFSCREEN_BUFFER_SIZE,
   LADYBUG_INVALID_JPEG_IMAGE_STRUCTURE,

   LADYBUG_NUM_LADYBUG_ERRORS''')
LadybugError = LadybugError._make(range(len(LadybugError._fields)))

What is nice about namedtuple is that the keywords can be given as one long string. It parses the string for you by spaces and commas. This saves me the trouble adding quotes around each item, just add quotes around the whole list. I overwrite the original ‘LadybugError’ string with the enumeration because it is no longer needed.
When a program returns an integer representing an error, it can be passed to _fields[] to get the error string.

err = libc.ladybugGetStreamHeader( pContext, streamHeaderInfo, None )
print err, LadybugError._fields[err]

The output from this is:

20 LADYBUG_NOT_INITIALIZED

The value of err is 20 and ‘LADYBUG_NOT_INITIALIZED’ is the 21st item in the LadybugError enumeration.

Because I only need to interpret numerical feedback, I can drop the “_make(range” line and just take advantage of namedtuple’s builtin parsing:

LadybugError = namedtuple('Enum', '''
   LADYBUG_OK,
   LADYBUG_FAILED,
   LADYBUG_INVALID_ARGUMENT,
   ...
   LADYBUG_INVALID_FRAMERATE,
   LADYBUG_INVALID_OFFSCREEN_BUFFER_SIZE,
   LADYBUG_INVALID_JPEG_IMAGE_STRUCTURE,
   LADYBUG_NUM_LADYBUG_ERRORS''')

This helps me easily find out what an error of 12 means:

print error, LadybugError._fields[error]

prints

12 LADYBUG_COULD_NOT_OPEN_FILE

This works smoothly if the enumeration starts with zero. Otherwise, getting the name through _fields[i] will not be correct. Also, remember that exceptions can be added using ._replace(field=new_value). Here’s an example:

LadybugBusSpeed = LadybugBusSpeed._replace(LADYBUG_SPEED_UNKNOWN=-1)
err = -1
print LadybugBusSpeed._fields[LadybugBusSpeed.index(err)]