ctypeslib icon indicating copy to clipboard operation
ctypeslib copied to clipboard

Add __slots__ to structs

Open corby opened this issue 2 years ago • 4 comments

This is an excellent tool and just what I was looking for. Thank you.

In order for the IDEs to recognize the fields as valid inputs we add __slots__ to all of our ctype.Structs. Would it be possible to add a step to each struct def to add the slots?

e.g.:

class struct_c__SA_my_struct_t(Structure):
    pass

class struct_c__SA_my_struct_t._pack_ = 1  # source:True
class struct_c__SA_my_struct_t._fields_ = [
    ('my_var1', ctypes.c_ubyte),
    ('my_var2', ctypes.c_uint16),
]
class struct_c__SA_my_struct_t.__slots__ = ('my_var1','my_var2')

corby avatar Dec 21 '23 17:12 corby

Note that __slots__ must be defined in the actual class body in order to be effective, that's very important. The above post-definition assignment does nothing except set a casual attribute, i.e. won't enable the special slots feature.

Minimal repro:

>>> from ctypes import *
>>>
>>> class TestStruct (Structure): pass
... 
>>> TestStruct.__slots__ = ["a", "b"]
>>> s = TestStruct()
>>> s.c = 1
>>> 
>>> class TestStruct (Structure):
...     __slots__ = ["a", "b"]
... 
>>> s = TestStruct()
>>> s.c = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'TestStruct' object has no attribute 'c'

mara004 avatar Mar 04 '24 18:03 mara004

@corby Shouldn't this be kept open? I don't think ctypeslib provides slots yet? The latest commit on master dates a year back, and searching for __slots__ yields nothing.

mara004 avatar Jul 31 '24 11:07 mara004

Apologies. I thought the point of the note was adding slots to the system would be pointless since it won't enforce frozen attributes.

corby avatar Jul 31 '24 15:07 corby

I thought the point of the note was adding slots to the system would be pointless since it won't enforce frozen attributes.

No: Slots are fine, you just have to get the declaration right. What the above example was supposed to express is that assigning slots to a class after definition (as in your initial post) takes no effect beyond setting a casual attribute, whereas declaring them during class creation[^1] does.

It's quite easy to shoot yourself in the foot with a typo in a struct field name, so it is a good idea to (correctly) set up slots on bindings generation to prevent assignment of non-existent fields.

(Defining slots in the class body is not an issue with forward declarations, because they contain just the field names, no actual references.)

[^1]: e.g. in the class body itself, or in a metaclass

mara004 avatar Jul 31 '24 18:07 mara004