Skip to content

Commit ee50ed3

Browse files
authored
gh-104533: Use @ctypes.util.struct decorator (#154031)
Use also `@ctypes.util.wrap_dll_function()` decorator.
1 parent 84897d2 commit ee50ed3

8 files changed

Lines changed: 84 additions & 45 deletions

File tree

Lib/test/_test_multiprocessing.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,10 @@ def wait_for_handle(handle, timeout):
161161
#
162162

163163
try:
164-
from ctypes import Structure, c_int, c_double, c_longlong
164+
from ctypes.util import struct as ctypes_struct
165+
from ctypes import c_int, c_double, c_longlong
165166
except ImportError:
166-
Structure = object
167+
def ctypes_struct(cls): return cls
167168
c_int = c_double = c_longlong = None
168169

169170

@@ -4390,12 +4391,11 @@ def test_free_from_gc(self):
43904391
#
43914392
#
43924393

4393-
class _Foo(Structure):
4394-
_fields_ = [
4395-
('x', c_int),
4396-
('y', c_double),
4397-
('z', c_longlong,)
4398-
]
4394+
@ctypes_struct
4395+
class _Foo:
4396+
x: c_int
4397+
y: c_double
4398+
z: c_longlong
43994399

44004400
class _TestSharedCTypes(BaseTestCase):
44014401

Lib/test/support/__init__.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,20 +236,41 @@ def _is_gui_available():
236236
# if Python is running as a service (such as the buildbot service),
237237
# gui interaction may be disallowed
238238
import ctypes
239+
import ctypes.util
239240
import ctypes.wintypes
241+
240242
UOI_FLAGS = 1
241243
WSF_VISIBLE = 0x0001
242-
class USEROBJECTFLAGS(ctypes.Structure):
243-
_fields_ = [("fInherit", ctypes.wintypes.BOOL),
244-
("fReserved", ctypes.wintypes.BOOL),
245-
("dwFlags", ctypes.wintypes.DWORD)]
246-
dll = ctypes.windll.user32
247-
h = dll.GetProcessWindowStation()
244+
245+
@ctypes.util.struct
246+
class USEROBJECTFLAGS:
247+
fInherit: ctypes.wintypes.BOOL
248+
fReserved: ctypes.wintypes.BOOL
249+
dwFlags: ctypes.wintypes.DWORD
250+
251+
user32 = ctypes.windll.user32
252+
253+
@ctypes.util.wrap_dll_function(user32)
254+
def GetProcessWindowStation() -> ctypes.wintypes.HANDLE:
255+
...
256+
257+
h = GetProcessWindowStation()
248258
if not h:
249259
raise ctypes.WinError()
260+
261+
@ctypes.util.wrap_dll_function(user32)
262+
def GetUserObjectInformationW(
263+
hObj: ctypes.wintypes.HANDLE,
264+
nIndex: ctypes.c_int,
265+
pvInfo: ctypes.c_void_p,
266+
nLength: ctypes.wintypes.DWORD,
267+
lpnLengthNeeded: ctypes.POINTER(ctypes.wintypes.DWORD),
268+
) -> ctypes.wintypes.BOOL:
269+
...
270+
250271
uof = USEROBJECTFLAGS()
251272
needed = ctypes.wintypes.DWORD()
252-
res = dll.GetUserObjectInformationW(h,
273+
res = GetUserObjectInformationW(h,
253274
UOI_FLAGS,
254275
ctypes.byref(uof),
255276
ctypes.sizeof(uof),

Lib/test/test_buffer.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
try:
3939
import ctypes
40+
import ctypes.util
4041
except ImportError:
4142
ctypes = None
4243

@@ -2849,8 +2850,11 @@ def test_memoryview_cast_1D_ND(self):
28492850

28502851
if ctypes:
28512852
# format: "T{>l:x:>d:y:}"
2852-
class BEPoint(ctypes.BigEndianStructure):
2853-
_fields_ = [("x", ctypes.c_long), ("y", ctypes.c_double)]
2853+
@ctypes.util.struct(endian='big')
2854+
class BEPoint:
2855+
x: ctypes.c_long
2856+
y: ctypes.c_double
2857+
28542858
point = BEPoint(100, 200.1)
28552859
m1 = memoryview(point)
28562860
m2 = m1.cast('B')
@@ -3250,8 +3254,11 @@ def test_memoryview_compare_special_cases(self):
32503254
# Some ctypes format strings are unknown to the struct module.
32513255
if ctypes:
32523256
# format: "T{>l:x:>l:y:}"
3253-
class BEPoint(ctypes.BigEndianStructure):
3254-
_fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)]
3257+
@ctypes.util.struct(endian='big')
3258+
class BEPoint:
3259+
x: ctypes.c_long
3260+
y: ctypes.c_long
3261+
32553262
point = BEPoint(100, 200)
32563263
a = memoryview(point)
32573264
b = memoryview(point)
@@ -3988,8 +3995,11 @@ def test_memoryview_tobytes(self):
39883995
# Unknown formats are handled: tobytes() purely depends on itemsize.
39893996
if ctypes:
39903997
# format: "T{>l:x:>l:y:}"
3991-
class BEPoint(ctypes.BigEndianStructure):
3992-
_fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)]
3998+
@ctypes.util.struct(endian='big')
3999+
class BEPoint:
4000+
x: ctypes.c_long
4001+
y: ctypes.c_long
4002+
39934003
point = BEPoint(100, 200)
39944004
a = memoryview(point)
39954005
self.assertEqual(a.tobytes(), bytes(point))

Lib/test/test_codecs.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,25 @@ def check(input, expect):
3636
self.assertEqual(coder(input), (expect, len(input)))
3737
return check
3838

39-
# On small versions of Windows like Windows IoT or Windows Nano Server not all codepages are present
39+
# On small versions of Windows like Windows IoT or Windows Nano Server,
40+
# not all codepages are present
4041
def is_code_page_present(cp):
41-
from ctypes import POINTER, WINFUNCTYPE, WinDLL, Structure
42+
from ctypes import POINTER, WINFUNCTYPE, WinDLL
43+
from ctypes.util import struct
4244
from ctypes.wintypes import BOOL, BYTE, WCHAR, UINT, DWORD
4345

4446
MAX_LEADBYTES = 12 # 5 ranges, 2 bytes ea., 0 term.
4547
MAX_DEFAULTCHAR = 2 # single or double byte
4648
MAX_PATH = 260
47-
class CPINFOEXW(Structure):
48-
_fields_ = [("MaxCharSize", UINT),
49-
("DefaultChar", BYTE*MAX_DEFAULTCHAR),
50-
("LeadByte", BYTE*MAX_LEADBYTES),
51-
("UnicodeDefaultChar", WCHAR),
52-
("CodePage", UINT),
53-
("CodePageName", WCHAR*MAX_PATH)]
49+
50+
@struct
51+
class CPINFOEXW:
52+
MaxCharSize: UINT
53+
DefaultChar: BYTE * MAX_DEFAULTCHAR
54+
LeadByte: BYTE * MAX_LEADBYTES
55+
UnicodeDefaultChar: WCHAR
56+
CodePage: UINT
57+
CodePageName: WCHAR * MAX_PATH
5458

5559
prototype = WINFUNCTYPE(BOOL, UINT, DWORD, POINTER(CPINFOEXW))
5660
GetCPInfoEx = prototype(("GetCPInfoExW", WinDLL("kernel32")))

Lib/test/test_ctypes/test_refcounts.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ def func(*args):
5454
gc.collect()
5555
self.assertEqual(sys.getrefcount(func), orig_refcount)
5656

57-
class X(ctypes.Structure):
58-
_fields_ = [("a", OtherCallback)]
57+
@ctypes.util.struct
58+
class X:
59+
a: OtherCallback
60+
5961
x = X()
6062
x.a = OtherCallback(func)
6163

Lib/test/test_ctypes/test_unicode.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import ctypes
1+
import ctypes.util
22
import unittest
33
from test.support import import_helper
44
_ctypes_test = import_helper.import_module("_ctypes_test")
@@ -26,8 +26,10 @@ def test_buffers(self):
2626
self.assertEqual(buf[6:5:-1], "")
2727

2828
def test_embedded_null(self):
29-
class TestStruct(ctypes.Structure):
30-
_fields_ = [("unicode", ctypes.c_wchar_p)]
29+
@ctypes.util.struct
30+
class TestStruct:
31+
unicode: ctypes.c_wchar_p
32+
3133
t = TestStruct()
3234
# This would raise a ValueError:
3335
t.unicode = "foo\0bar\0\0"

Lib/test/test_ctypes/test_win32_com_foreign_func.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import ctypes
1+
import ctypes.util
22
import gc
33
import sys
44
import unittest
@@ -20,14 +20,13 @@
2020
E_NOINTERFACE = -2147467262
2121

2222

23-
class GUID(ctypes.Structure):
23+
@ctypes.util.struct
24+
class GUID:
2425
# https://learn.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid
25-
_fields_ = [
26-
("Data1", DWORD),
27-
("Data2", WORD),
28-
("Data3", WORD),
29-
("Data4", BYTE * 8),
30-
]
26+
Data1: DWORD
27+
Data2: WORD
28+
Data3: WORD
29+
Data4: BYTE * 8
3130

3231

3332
def create_proto_com_method(name, index, restype, *argtypes):

Lib/test/test_io/utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88

99

1010
try:
11-
import ctypes
11+
import ctypes.util
1212
except ImportError:
1313
def byteslike(*pos, **kw):
1414
return array.array("b", bytes(*pos, **kw))
1515
else:
16-
class EmptyStruct(ctypes.Structure):
16+
@ctypes.util.struct
17+
class EmptyStruct:
1718
pass
1819

1920
def byteslike(*pos, **kw):

0 commit comments

Comments
 (0)