# Annotation-based sugar for ctypes

**URL:** <https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579>\
**Category:** Ideas\
**Created:** [May 7, 2023, 1:58pm UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579 "2023-05-07T13:58:51Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![orent](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/orent/32/10796_2.png) [@orent](https://discuss.python.org/u/orent)\
**Post date:** [May 7, 2023, 1:58pm UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/1 "2023-05-07T13:58:51Z")

</div>

Turn this:

```auto
class S(ctypes.Structure):
   _fields_ = [('a', ctypes.c_int), ('b', ctypes.c_char_p)]

```

Into this:

```auto
class S(ctypes.Structure):
    a : ctypes.c_int
    b : ctypes.c_char_p

```

And this:

```auto
libm = ctypes.CDLL('libm.so')
pow = libm.pow
pow.restype = ctypes.c_double
pow.argtypes = (ctypes.c_double, ctypes, c_double)

```

into this:

```auto
libm = ctypes.CDLL('libm.so')

@libm
def pow(a: ctypes.c_double, b:ctypes.c_double) -> c_double:
    pass

```

---

<div class="post-metadata">

**Author:** ![storchaka](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/storchaka/32/217_2.png) [@storchaka](https://discuss.python.org/u/storchaka)\
**Post date:** [May 7, 2023, 2:57pm UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/2 "2023-05-07T14:57:38Z")

</div>

It looks very interesting. I do not see any obvious objections, except possible conflicts with `from __future__ import annotations` and PEP 563. But dataclasses have to deal with it somehow.

Could you please open two separate issues for this? Do you volunteer to implement these features?

---

<div class="post-metadata">

**Author:** ![layday](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/layday/32/2771_2.png) [@layday](https://discuss.python.org/u/layday)\
**Post date:** [May 7, 2023, 3:03pm UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/3 "2023-05-07T15:03:01Z")

</div>

Rubicon does [something similar](https://github.com/beeware/rubicon-objc/blob/main/docs/how-to/type-mapping.rst#type-annotations); it might be instructive to see what their experience has been with runtime annotations as a FFI.

---

<div class="post-metadata">

**Author:** ![orent](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/orent/32/10796_2.png) [@orent](https://discuss.python.org/u/orent)\
**Post date:** [May 7, 2023, 4:20pm UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/4 "2023-05-07T16:20:34Z")

</div>

I have an implementation in Python. It works but breaks a test so I will need a little bit of C.

Is it necessary to support some of the rarer features like bit fields and self-referential structs? They are always available through setting \_\_fields\_\_

Raise exception if both \_\_fields\_\_and annotations set.

May be a good idea to raise exception if decorated function body is not empty?

---

<div class="post-metadata">

**Author:** ![eryksun](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/eryksun/32/697_2.png) [@eryksun](https://discuss.python.org/u/eryksun)\
**Post date:** [May 7, 2023, 6:50pm UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/5 "2023-05-07T18:50:33Z")

</div>

Function prototypes can be instantiated with a `paramflags` tuple, which specifies whether each parameter in `argtypes` is an input parameter (1), output parameter (2), or in-out parameter (3). Optionally, it can also specify a name and default value for each parameter, which allows the function to be called with keyword arguments. For example:

```auto
import ctypes
libm = ctypes.CDLL('libm.so.6')

pow_prototype = ctypes.CFUNCTYPE(
                    ctypes.c_double,
                    ctypes.c_double, ctypes.c_double,
                    use_errno=True)
pow_paramflags = ((1, 'x'), (1, 'y', 2)) # default to returning x**2
pow = pow_prototype(('pow', libm), pow_paramflags)

```

```auto
>>> pow(3)
9.0
>>> pow(3, 3)
27.0
>>> pow(x=3)
9.0
>>> pow(x=3, y=3)
27.0
>>> pow(y=3, x=3)
27.0

```

The parameter names and default values (if any) can be pulled directly from the annotated prototype. If a parameter flag isn’t specified it can be assumed to be handled as an input parameter. An output parameter or in-out parameter could be declared by annotating with a tuple `(type, flag)`.

* * *

A function prototype also has a `_flags_` value in addition to `_argtypes_` and `_restype_`. The supported flag values are

```auto
FUNCFLAG_STDCALL = 0x00 # Windows only
FUNCFLAG_CDECL = 0x01
FUNCFLAG_HRESULT = 0x02 # Windows only
FUNCFLAG_PYTHONAPI = 0x04
FUNCFLAG_USE_ERRNO = 0x08
FUNCFLAG_USE_LASTERROR = 0x10

```

The last two enable the use of `ctypes.get_errno()` and `ctypes.get_last_error()`. Generally scripts rely on the default function prototype of a `CDLL`, `WinDLL`, or `PyDLL` instance to set these flags, or a prototype factory function such as `CFUNCTYPE()`, `WINFUNCTYPE()`, or `PYFUNCTYPE()`. Maybe they could be supported in an annotated prototype as keyword-only parameters such as `_stdcall_`, `_cdecl_`, `_hresult_`, `_pythonapi_`, `_use_errno_`, and `_use_last_error_`. A function pointer also has an `errcheck` attribute, which is a function that gets called just before returning. Maybe this could be supported as an `_errcheck_` keyword-only parameter. If any flag is defined, it will override the `_flags_` of the default prototype of a `CDLL` instance. If a default `_errcheck_` is defined, it will be the initial `errcheck` value of the function pointer.

---

<div class="post-metadata">

**Author:** ![orent](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/orent/32/10796_2.png) [@orent](https://discuss.python.org/u/orent)\
**Post date:** [May 15, 2023, 8:04pm UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/6 "2023-05-15T20:04:18Z")

</div>

Thanks for the suggestions!

I think only things that map naturally to annotations should be specified as annotations. The rest should just be added as arguments to the @library() attribute. No overloading of the function’s keyword-only arguments.

---

<div class="post-metadata">

**Author:** ![sunmy2019](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/sunmy2019/32/11935_2.png) [@sunmy2019](https://discuss.python.org/u/sunmy2019)\
**Post date:** [May 16, 2023, 9:10am UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/7 "2023-05-16T09:10:53Z")

</div>

Can people forbid creating the class in this way?

```py
class S(dataclass):
    # some annotations

```

Will there be a switch?

* * *

I am more in favour of the decorator style

```py
@dataclass
class S:
    # some annotations

```

to

```py
class S(dataclass):
    # some annotations

```

* * *

The point here is:  
Supporting “annotation define” and “\_field\_ define” in similar grammar is weird.

---

<div class="post-metadata">

**Author:** ![vasily-v-ryabov](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/vasily-v-ryabov/32/10074_2.png) [@vasily-v-ryabov](https://discuss.python.org/u/vasily-v-ryabov)\
**Post date:** [May 20, 2023, 7:23am UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/8 "2023-05-20T07:23:54Z")

</div>

The first suggestion about Structure looks somewhat normal to me, though making type hints valuable at runtime seems a little bit non-uniform with all other Python type hints which are not meaningful at runtime. Also there is a need to maintain both syntaxes and make them mutually exclusive, but it’s up to you.

But the second suggestion with decorator is very confusing. Please imagine if you are a newcomer and trying to understand why there is an empty function, maybe I need to remove it. 😉 Static analysis may decide something similar. And what if I add some implementation instead of pass statement? Will it be ignored?

Another argument against the decorator is that a dynamic library is pretty low level object, while a decorator is something at high level: it’s typically a transformation of decorated function, but you suggest something different and strange. I think it’s not worth it.

---

<div class="post-metadata">

**Author:** ![junkmd](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/junkmd/32/8400_2.png) [@junkmd](https://discuss.python.org/u/junkmd)\
**Post date:** [August 13, 2023, 4:03am UTC](https://discuss.python.org/t/annotation-based-sugar-for-ctypes/26579/10 "2023-08-13T04:03:03Z")

</div>

Can I recognize that this discussion has been moved to [Annotation-based syntax for ctypes structs · Issue #104533 · python/cpython · GitHub](https://github.com/python/cpython/issues/104533)?

I have shared my thoughts there.
