From f0c3c934e29af387572551d862ba331e1878a289 Mon Sep 17 00:00:00 2001 From: junkmd Date: Fri, 9 Oct 2026 09:14:09 +0900 Subject: [PATCH 1/2] test: Remove temporary skip logic for Python 3.15 in `test_util.py` Remove the temporary logic that skipped tests on Python 3.15. This logic was previously added to avoid `RuntimeError` during import due to `PyCArgObject` layout changes. --- comtypes/test/test_util.py | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/comtypes/test/test_util.py b/comtypes/test/test_util.py index f4746808c..db7348b19 100644 --- a/comtypes/test/test_util.py +++ b/comtypes/test/test_util.py @@ -1,4 +1,3 @@ -import sys import unittest from ctypes import ( POINTER, @@ -14,21 +13,7 @@ sizeof, ) -PY_3_15 = sys.version_info.major == 3 and sys.version_info.minor == 15 - -try: - import comtypes.util -except RuntimeError as e: - SKIP_MSG = ( - "Starting from Python 3.15, PyCArgObject layout is changed. " - "See https://github.com/enthought/comtypes/issues/938." - ) - if PY_3_15: - - def setUpModule(): - raise unittest.SkipTest(SKIP_MSG) - else: - raise e +import comtypes.util from comtypes import GUID, CoCreateInstance, IUnknown, shelllink From ded3f00611cfaf99903e624e4c4ca7c610531238 Mon Sep 17 00:00:00 2001 From: junkmd Date: Fri, 9 Oct 2026 09:14:17 +0900 Subject: [PATCH 2/2] fix: Update `PyCArgObject` layout for Python 3.15. Update `util` to accommodate changes in the internal `PyCArgObject` structure introduced in Python 3.15. The `tag` field was changed from `c_char` to `c_char_p`, and the `size` field was changed from `c_int` to `c_ssize_t`. This change uses a version-based bridge to maintain backward compatibility with older Python versions. --- comtypes/util.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/comtypes/util.py b/comtypes/util.py index bbc27345e..36eb93cae 100644 --- a/comtypes/util.py +++ b/comtypes/util.py @@ -12,6 +12,7 @@ byref, c_byte, c_char, + c_char_p, c_double, c_float, c_int, @@ -19,6 +20,7 @@ c_longdouble, c_longlong, c_short, + c_ssize_t, c_void_p, cast, sizeof, @@ -32,6 +34,13 @@ _T = TypeVar("_T") _CT = TypeVar("_CT", bound="_CData") +if sys.version_info >= (3, 15): + _TAG_TYPE = c_char_p + _SIZE_TYPE = c_ssize_t +else: + _TAG_TYPE = c_char + _SIZE_TYPE = c_int + def _calc_offset(): # Internal helper function that calculates where the object @@ -103,10 +112,10 @@ class value(Union): _fields_ = [ ("PyObject_HEAD", c_byte * object.__basicsize__), ("pffi_type", c_void_p), - ("tag", c_char), + ("tag", _TAG_TYPE), ("value", value), ("obj", c_void_p), - ("size", c_int), + ("size", _SIZE_TYPE), ] _anonymous_ = ["value"]