-
-
Notifications
You must be signed in to change notification settings - Fork 30.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Annotation-based syntax for ctypes structs #104533
Comments
I would welcome this very much. It would also be very nice if we had annotations for incomplete types if possible. A natural next step would be using generics for pointers. I don't know though whether generics have to stabilize regarding how generic parameters are accessed during runtime (see python/typing#629). If ctypes wouldn't insist on capitalized types, we would get code like this class Incomplete(Struct):
some_data : c_int
children : Pointer['Incomplete'] which looks very clean and natural imho. |
You are welcome to open a separate issue. Your proposal is orthogonal to this one. |
I would like to point out the problems with this approach. The problem is that type checkers interpret the return type of fields solely as As shown below, even if >>> import ctypes
>>>
>>> class Foo(ctypes.Structure):
... pass
...
>>> Foo._fields_ = [('x', ctypes.c_int)]
>>> Foo.x
<Field type=c_long, ofs=0, size=4>
>>> type(Foo.x)
<class '_ctypes.CField'>
>>> foo = Foo()
>>> foo
<__main__.Foo object at 0x0000023CDB80B8C0>
>>> foo.x
0
>>> foo.x = 3
>>> foo.x
3
>>> foo.x = ctypes.c_int(2)
>>> foo.x
2 In order to convey appropriate type information by annotating for fields like below, a special treatment needs to be introduced to type checkers. class Foo(Structure):
x: c_int This effort requires reaching out not only to the
|
I made a dumb wrapper for ctypes to support this sort of thing at DrInfiniteExplorer/dtypes a few years back after I got tired of writing hundreds of definitions with |
I had something similar because I'm too lazy to declare structs and unions using the regular syntax. Instead, I have something like that: @cschema
class MyStruct(cStruct):
i: ctypes.c_int
class a(cStruct):
x: ctypes.c_longlong
y: ctypes.c_longlong which makes it equivalent to class MyInnerStruct(ctypes.Structure):
x: ctypes.c_longlong
y: ctypes.c_longlong
class MyStruct(ctypes.Structure):
_fields_ = [('i', ctypes.c_int), ('a', MyInnerStruct)] With this approach, I can have nested classes and unions. also, I used @cschema
class MyStruct(cStruct):
class _(cStruct, anon=True):
x: ctypes.c_longlong
y: ctypes.c_longlong becomes equivalent to class MyInnerStruct(ctypes.Structure):
x: ctypes.c_longlong
y: ctypes.c_longlong
class MyStruct(ctypes.Structure):
_anonymous_ = ['_']
_fields_ = [('_', MyInnerStruct)] Similarly, I can have something like: class MyStruct(cStruct, pack=32):
pass
class MyUnion(cUnion, pack=32):
pass instead of class MyStruct(ctypes.Structure):
_pack_ = 32
class MyUnion(ctypes.Union):
_pack_ = 32 Note that this last construction is only useful when using nested unions. I've added other features such as: @cschema
class MyClass(cStruct):
field: cArray[ctypes.c_int, 32] to be equivalent to class MyClass(ctypes.Structure):
_fields_ = [('field', ctypes.c_int * 32)] Again, @cschema
class MyClass(cStruct):
field: cPointer[ctypes.c_int] instead of class MyClass(ctypes.Structure):
_fields_ = [('field', ctypes.POINTER(ctypes.c_int))] For type-checkers, I implemented my own mypy plugin since this construction is quite hacky. Note that I needed this If someone is interested, I could try to make this implementation more elegant and perhaps close to how |
Turn this:
Into this:
See discussion on https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579
Working on implementation
The text was updated successfully, but these errors were encountered: