enthought / enthought/comtypes

Support Python 3.15 `PyCArgObject` layout changes in `comtypes.util`

Open
#938 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
345
Forks
105
PR merge metrics
No merged PRs in 30d

Description

## Summary

[`comtypes.util._calc_offset..PyCArgObject`](https://github.com/enthought/comtypes/blob/8fec0889ce5aa8913f43ed3eb42bf4dd0849b2db/comtypes/util.py#L42) mirrors CPython's internal `_ctypes.PyCArgObject` structure. CPython 3.15 changes the layout of this internal structure, so we needs to update its definition accordingly.

This is similar to the work previously done for Python 3.14 compatibility in https://github.com/enthought/comtypes/pull/839

## Background

The relevant CPython definitions are:

* [Python 3.13 `ctypes.h`](https://github.com/python/cpython/blob/3.13/Modules/_ctypes/ctypes.h#L376-L394)
* [Python 3.14 `ctypes.h`](https://github.com/python/cpython/blob/3.14/Modules/_ctypes/ctypes.h#L481-L502)
* [Python 3.15 `ctypes.h`](https://github.com/python/cpython/blob/3.15/Modules/_ctypes/ctypes.h#L494-L515)

The Python 3.15 change that affects `comtypes` is **NOT** related to [the `_type_` code changes (`F`/`D`/`G` → `Zf`/`Zd`/`Zg`)](https://docs.python.org/3.15/library/ctypes.html#fundamental-data-types) (Related issue: https://github.com/python/cpython/issues/148675).

Instead, the compatibility issue comes from changes in the internal `PyCArgObject` structure itself.

## Required changes

### 1. `tag`

CPython changed:

```c
char tag;
```

to:

```c
const char *tag;
```

Therefore the corresponding field in `comtypes.util._calc_offset..PyCArgObject` should change from:

```py
("tag", c_char)
```

to:

```py
("tag", c_char_p)
```

for Python 3.15+.

### 2. `size`

The structure contains:

```c
Py_ssize_t size; /* for the "V" tag */
```

The current our definition uses `c_int`, but the actual CPython type is `Py_ssize_t`.

Therefore the field should be updated to:

```python
("size", c_ssize_t)
```

for Python 3.15+.

## Proposed implementation

Maintain backward compatibility with a version bridge:

```python
if sys.version_info >= (3, 15):
...
else:
...
```

so that:

* Python 3.13 and 3.14 continue using the existing layout.
* Python 3.15+ uses the updated layout matching CPython.

## Acceptance criteria

* `PyCArgObject` definition matches CPython 3.15.
* Existing Python 3.13 and 3.14 support remains unchanged.
* CI passes on supported Python versions.
* New tests verify the expected field types:

* `tag` → `c_char_p`
* `size` → `c_ssize_t`

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.