0

I'm trying to create a bitfield class using ctypes in IronPython 2.7.9. I'm trying the example in this answer. but it is failing with a SystemError: Object reference not set to an instance of an object at the line flags.asbyte = 0xc, when accessing the Union member.

I also tried to point to CPython stdlib as suggested in this message by adding a CPython 2.7.8 path, but this didn't work either.

import sys

sys.path.append("C:/Python27/DLLs")

import ctypes
c_uint8 = ctypes.c_uint8

class Flags_bits(ctypes.LittleEndianStructure):
    _fields_ = [
            ("logout", c_uint8, 1),
            ("userswitch", c_uint8, 1),
            ("suspend", c_uint8, 1),
            ("idle", c_uint8, 1),
        ]

class Flags(ctypes.Union):
    _fields_ = [("b", Flags_bits),
                ("asbyte", c_uint8)]

flags = Flags()
flags.asbyte = 0xc

print(flags.b.idle)
print(flags.b.suspend)
print(flags.b.userswitch)
print(flags.b.logout)

An example of ctypes on IronPython? could be interesting, but the accepted answer doesn't prove an example.

EDIT: I dug a little further and this code (inspired from this unit test) doesn't work:

from ctypes import *

class ANON(Union):
    _fields_ = [("a", c_int),
                ("b", c_int)]

a = ANON()
a.a = 5

While this piece of code (from this unit test) works:

from ctypes import *

class X(Structure):
    _fields_ = [("a", c_longlong, 1),
                ("b", c_longlong, 62),
                ("c", c_longlong, 1)]

x = X()
x.a, x.b, x.c = -1, 7, -1

So it seems an IronPython limitation

Thanks!

Leonardo
  • 1,533
  • 17
  • 28

2 Answers2

1

You should upgrade to the lastest version of IronPython, since 2.7.9 was released last week.

http://ironpython.net/

Anthony
  • 11
  • 1
  • Thanks for the post, but please don't post it as an answer if it's not. Upgrading to IronPython 2.7.9 didn't solve the issue, so your solution wasn't tested. Post it as a comment (a useful one, but not a solution). I edited the question with the new IronPython version. – Leonardo Oct 16 '18 at 15:01
0

This problem was considered a bug on IronPython 2.7.9 ctypes.Union access fails with "SystemError: Object reference not set to an instance of an object.".

For now, I came up with this very ugly solution that works for me:

class __BleCharacteristicFlags(ctypes.LittleEndianStructure):
    """Creates a class to generically represent bitfields.

    Note:
        This ONLY supports ctypes.LittleEndianStructure.
        Unfortunately IronPython 2.7.9 does not supports ctypes.Union. We need this workaround
        code to create an illusion of an union.
    """
    @property
    def as_byte(self):
        """Returns an integer that represents the current set flags
        """
        val = 0
        for i, field in enumerate(self._fields_):
            if getattr(self, field[0]) == 1:
                val += (0x01<<i)
        return val

    @as_byte.setter
    def as_byte(self, hex_val):
        """Writes the flags with a single bitfield.
        """
        for i, field in enumerate(self._fields_):
            if( (hex_val&(0x01<<i)) != 0 ):
                setattr(self, field[0], 1)
            else:
                setattr(self, field[0], 0)

    def __str__(self):
        """Returns a string that represents the current object.
        """
        s = ""
        for i, field in enumerate(self._fields_):
            if getattr(self, field[0]) == 1:
                if s != "":
                    s += ", "
                s += field[0]
        return s

class BleCharacteristicPermissions(__BleCharacteristicFlags):
    """Creates a clas to represent the permissions of a GATT characteristic.

    Note:
        The flags values are:
            Readable = 0x01,
            Writeable = 0x02,
            ReadEncryptionRequired = 0x04,
            WriteEncryptionRequired = 0x08,

    Attributes:
        readable (int): Readable permission flag. If set the characteristic can be read.
        writeable (int): Writeable permission flag. If set the characteristic can be written.
        read_encryption_required (int): Read encryption required permission flag.  If set the
            characteristic can only be read if encryption is enabled.
        write_encryption_required (int): Write encryption required permission flag.  If set the
            characteristic can only be written if encryption is enabled.
        as_byte (int): The flags bit values read as an integer.
    """
    _fields_ = [
            ("readable", ctypes.c_uint8, 1),
            ("writeable", ctypes.c_uint8, 1),
            ("read_encryption_required", ctypes.c_uint8, 1),
            ("write_encryption_required", ctypes.c_uint8, 1),
        ]
Leonardo
  • 1,533
  • 17
  • 28