]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-104533: Use `@ctypes.util.struct` decorator (#154031)
authorVictor Stinner <vstinner@python.org>
Sun, 19 Jul 2026 12:08:56 +0000 (14:08 +0200)
committerGitHub <noreply@github.com>
Sun, 19 Jul 2026 12:08:56 +0000 (12:08 +0000)
Use also `@ctypes.util.wrap_dll_function()` decorator.

Lib/test/_test_multiprocessing.py
Lib/test/support/__init__.py
Lib/test/test_buffer.py
Lib/test/test_codecs.py
Lib/test/test_ctypes/test_refcounts.py
Lib/test/test_ctypes/test_unicode.py
Lib/test/test_ctypes/test_win32_com_foreign_func.py
Lib/test/test_io/utils.py

index 115a187a8a858824a500b2c614a3e79fee734e23..8f665b3a98a0371cc9cf1752151a12dce2794b9e 100644 (file)
@@ -161,9 +161,10 @@ PRELOAD = ['__main__', 'test.test_multiprocessing_forkserver']
 #
 
 try:
-    from ctypes import Structure, c_int, c_double, c_longlong
+    from ctypes.util import struct as ctypes_struct
+    from ctypes import c_int, c_double, c_longlong
 except ImportError:
-    Structure = object
+    def ctypes_struct(cls): return cls
     c_int = c_double = c_longlong = None
 
 
@@ -4390,12 +4391,11 @@ class _TestHeap(BaseTestCase):
 #
 #
 
-class _Foo(Structure):
-    _fields_ = [
-        ('x', c_int),
-        ('y', c_double),
-        ('z', c_longlong,)
-        ]
+@ctypes_struct
+class _Foo:
+    x: c_int
+    y: c_double
+    z: c_longlong
 
 class _TestSharedCTypes(BaseTestCase):
 
index d17d9a2ecf8d9b08cb7660864a4cca891a184da6..e5bc2fd9b3d0954e5fa1cb4c458ac8f1daddaea5 100644 (file)
@@ -236,20 +236,41 @@ def _is_gui_available():
         # if Python is running as a service (such as the buildbot service),
         # gui interaction may be disallowed
         import ctypes
+        import ctypes.util
         import ctypes.wintypes
+
         UOI_FLAGS = 1
         WSF_VISIBLE = 0x0001
-        class USEROBJECTFLAGS(ctypes.Structure):
-            _fields_ = [("fInherit", ctypes.wintypes.BOOL),
-                        ("fReserved", ctypes.wintypes.BOOL),
-                        ("dwFlags", ctypes.wintypes.DWORD)]
-        dll = ctypes.windll.user32
-        h = dll.GetProcessWindowStation()
+
+        @ctypes.util.struct
+        class USEROBJECTFLAGS:
+            fInherit: ctypes.wintypes.BOOL
+            fReserved: ctypes.wintypes.BOOL
+            dwFlags: ctypes.wintypes.DWORD
+
+        user32 = ctypes.windll.user32
+
+        @ctypes.util.wrap_dll_function(user32)
+        def GetProcessWindowStation() -> ctypes.wintypes.HANDLE:
+            ...
+
+        h = GetProcessWindowStation()
         if not h:
             raise ctypes.WinError()
+
+        @ctypes.util.wrap_dll_function(user32)
+        def GetUserObjectInformationW(
+            hObj: ctypes.wintypes.HANDLE,
+            nIndex: ctypes.c_int,
+            pvInfo: ctypes.c_void_p,
+            nLength: ctypes.wintypes.DWORD,
+            lpnLengthNeeded: ctypes.POINTER(ctypes.wintypes.DWORD),
+        ) -> ctypes.wintypes.BOOL:
+            ...
+
         uof = USEROBJECTFLAGS()
         needed = ctypes.wintypes.DWORD()
-        res = dll.GetUserObjectInformationW(h,
+        res = GetUserObjectInformationW(h,
             UOI_FLAGS,
             ctypes.byref(uof),
             ctypes.sizeof(uof),
index 3213a4751273431392c0a95ab12b068238828923..453dafe2709eb2fd356a855cc378c032058fea97 100644 (file)
@@ -37,6 +37,7 @@ except ImportError:
 
 try:
     import ctypes
+    import ctypes.util
 except ImportError:
     ctypes = None
 
@@ -2849,8 +2850,11 @@ class TestBufferProtocol(unittest.TestCase):
 
         if ctypes:
             # format: "T{>l:x:>d:y:}"
-            class BEPoint(ctypes.BigEndianStructure):
-                _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_double)]
+            @ctypes.util.struct(endian='big')
+            class BEPoint:
+                x: ctypes.c_long
+                y: ctypes.c_double
+
             point = BEPoint(100, 200.1)
             m1 = memoryview(point)
             m2 = m1.cast('B')
@@ -3250,8 +3254,11 @@ class TestBufferProtocol(unittest.TestCase):
         # Some ctypes format strings are unknown to the struct module.
         if ctypes:
             # format: "T{>l:x:>l:y:}"
-            class BEPoint(ctypes.BigEndianStructure):
-                _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)]
+            @ctypes.util.struct(endian='big')
+            class BEPoint:
+                x: ctypes.c_long
+                y: ctypes.c_long
+
             point = BEPoint(100, 200)
             a = memoryview(point)
             b = memoryview(point)
@@ -3988,8 +3995,11 @@ class TestBufferProtocol(unittest.TestCase):
         # Unknown formats are handled: tobytes() purely depends on itemsize.
         if ctypes:
             # format: "T{>l:x:>l:y:}"
-            class BEPoint(ctypes.BigEndianStructure):
-                _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)]
+            @ctypes.util.struct(endian='big')
+            class BEPoint:
+                x: ctypes.c_long
+                y: ctypes.c_long
+
             point = BEPoint(100, 200)
             a = memoryview(point)
             self.assertEqual(a.tobytes(), bytes(point))
index c18b203f42f59f3a44164a1dc1b8a9028cc16f15..31704955df3e14e822be2d94c255b4575ed13c64 100644 (file)
@@ -36,21 +36,25 @@ def coding_checker(self, coder):
         self.assertEqual(coder(input), (expect, len(input)))
     return check
 
-# On small versions of Windows like Windows IoT or Windows Nano Server not all codepages are present
+# On small versions of Windows like Windows IoT or Windows Nano Server,
+# not all codepages are present
 def is_code_page_present(cp):
-    from ctypes import POINTER, WINFUNCTYPE, WinDLL, Structure
+    from ctypes import POINTER, WINFUNCTYPE, WinDLL
+    from ctypes.util import struct
     from ctypes.wintypes import BOOL, BYTE, WCHAR, UINT, DWORD
 
     MAX_LEADBYTES = 12  # 5 ranges, 2 bytes ea., 0 term.
     MAX_DEFAULTCHAR = 2 # single or double byte
     MAX_PATH = 260
-    class CPINFOEXW(Structure):
-        _fields_ = [("MaxCharSize", UINT),
-                    ("DefaultChar", BYTE*MAX_DEFAULTCHAR),
-                    ("LeadByte", BYTE*MAX_LEADBYTES),
-                    ("UnicodeDefaultChar", WCHAR),
-                    ("CodePage", UINT),
-                    ("CodePageName", WCHAR*MAX_PATH)]
+
+    @struct
+    class CPINFOEXW:
+        MaxCharSize: UINT
+        DefaultChar: BYTE * MAX_DEFAULTCHAR
+        LeadByte: BYTE * MAX_LEADBYTES
+        UnicodeDefaultChar: WCHAR
+        CodePage: UINT
+        CodePageName: WCHAR * MAX_PATH
 
     prototype = WINFUNCTYPE(BOOL, UINT, DWORD, POINTER(CPINFOEXW))
     GetCPInfoEx = prototype(("GetCPInfoExW", WinDLL("kernel32")))
index d79937277e7df696503bb591de9a94454e2a8ca2..5191862658c56719b58a72490d5b1b4a689c6f0e 100644 (file)
@@ -54,8 +54,10 @@ class RefcountTestCase(unittest.TestCase):
         gc.collect()
         self.assertEqual(sys.getrefcount(func), orig_refcount)
 
-        class X(ctypes.Structure):
-            _fields_ = [("a", OtherCallback)]
+        @ctypes.util.struct
+        class X:
+            a: OtherCallback
+
         x = X()
         x.a = OtherCallback(func)
 
index d9e17371d1357246edd735a39ae2dc5cfe760b72..8e91f8f2c566803f92472237e6e58873d6e4a9f5 100644 (file)
@@ -1,4 +1,4 @@
-import ctypes
+import ctypes.util
 import unittest
 from test.support import import_helper
 _ctypes_test = import_helper.import_module("_ctypes_test")
@@ -26,8 +26,10 @@ class UnicodeTestCase(unittest.TestCase):
         self.assertEqual(buf[6:5:-1], "")
 
     def test_embedded_null(self):
-        class TestStruct(ctypes.Structure):
-            _fields_ = [("unicode", ctypes.c_wchar_p)]
+        @ctypes.util.struct
+        class TestStruct:
+            unicode: ctypes.c_wchar_p
+
         t = TestStruct()
         # This would raise a ValueError:
         t.unicode = "foo\0bar\0\0"
index 7e54f8f6c31d33f9aa6288775498440cff3b8c01..c797ab98cf1e424cdcd758c9d6332d48474b0532 100644 (file)
@@ -1,4 +1,4 @@
-import ctypes
+import ctypes.util
 import gc
 import sys
 import unittest
@@ -20,14 +20,13 @@ TRUE = 1
 E_NOINTERFACE = -2147467262
 
 
-class GUID(ctypes.Structure):
+@ctypes.util.struct
+class GUID:
     # https://learn.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid
-    _fields_ = [
-        ("Data1", DWORD),
-        ("Data2", WORD),
-        ("Data3", WORD),
-        ("Data4", BYTE * 8),
-    ]
+    Data1: DWORD
+    Data2: WORD
+    Data3: WORD
+    Data4: BYTE * 8
 
 
 def create_proto_com_method(name, index, restype, *argtypes):
index 3b1faec2140fbc63519b5389852e49ba92f0c39e..dde49337a24f0b9d97ab2f65aee026cd75206277 100644 (file)
@@ -8,12 +8,13 @@ import _pyio as pyio # Python implementation of io
 
 
 try:
-    import ctypes
+    import ctypes.util
 except ImportError:
     def byteslike(*pos, **kw):
         return array.array("b", bytes(*pos, **kw))
 else:
-    class EmptyStruct(ctypes.Structure):
+    @ctypes.util.struct
+    class EmptyStruct:
         pass
 
     def byteslike(*pos, **kw):