enthought / enthought/comtypes
Support Python 3.15 `PyCArgObject` layout changes in `comtypes.util`
- 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
Assessment
This issue has not been assessed yet.