Skip to content

Commit 91365b0

Browse files
committed
Add a test for the new info, and fix 'name' for nested anonymous structs
1 parent bb41481 commit 91365b0

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed

Lib/test/test_ctypes/test_structunion.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from ctypes import (Structure, Union, POINTER, sizeof, alignment,
55
c_char, c_byte, c_ubyte,
66
c_short, c_ushort, c_int, c_uint,
7-
c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double)
7+
c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double,
8+
c_int8, c_int16, c_int32)
89
from ._support import (_CData, PyCStructType, UnionType,
910
Py_TPFLAGS_DISALLOW_INSTANTIATION,
1011
Py_TPFLAGS_IMMUTABLETYPE)
@@ -175,6 +176,101 @@ class X(self.cls):
175176
# XXX Should we check nested data types also?
176177
# offset is always relative to the class...
177178

179+
def test_field_descriptor_attributes(self):
180+
"""Test information provided by the descriptors"""
181+
class Inner(Structure):
182+
_fields_ = [
183+
("a", c_int16),
184+
("b", c_int8, 1),
185+
("c", c_int8, 2),
186+
]
187+
class X(self.cls):
188+
_fields_ = [
189+
("x", c_int32),
190+
("y", c_int16, 1),
191+
("_", Inner),
192+
]
193+
_anonymous_ = ["_"]
194+
195+
field_names = "xy_abc"
196+
197+
# name
198+
199+
for name in field_names:
200+
with self.subTest(name=name):
201+
self.assertEqual(getattr(X, name).name, name)
202+
203+
# type
204+
205+
expected_types = dict(
206+
x=c_int32,
207+
y=c_int16,
208+
_=Inner,
209+
a=c_int16,
210+
b=c_int8,
211+
c=c_int8,
212+
)
213+
assert set(expected_types) == set(field_names)
214+
for name, tp in expected_types.items():
215+
with self.subTest(name=name):
216+
self.assertEqual(getattr(X, name).type, tp)
217+
self.assertEqual(getattr(X, name).byte_size, sizeof(tp))
218+
219+
# offset, byte_offset
220+
221+
expected_offsets = dict(
222+
x=(0, 0),
223+
y=(0, 4),
224+
_=(0, 6),
225+
a=(0, 6),
226+
b=(2, 8),
227+
c=(2, 8),
228+
)
229+
assert set(expected_offsets) == set(field_names)
230+
for name, (union_offset, struct_offset) in expected_offsets.items():
231+
with self.subTest(name=name):
232+
self.assertEqual(getattr(X, name).offset,
233+
getattr(X, name).byte_offset)
234+
if self.cls == Structure:
235+
self.assertEqual(getattr(X, name).offset, struct_offset)
236+
else:
237+
self.assertEqual(getattr(X, name).offset, union_offset)
238+
239+
# is_bitfield, bit_size, bit_offset
240+
# size
241+
242+
expected_bitfield_info = dict(
243+
# (bit_size, bit_offset)
244+
b=(1, 0),
245+
c=(2, 1),
246+
y=(1, 0),
247+
)
248+
for name in field_names:
249+
with self.subTest(name=name):
250+
if info := expected_bitfield_info.get(name):
251+
self.assertEqual(getattr(X, name).is_bitfield, True)
252+
expected_bit_size, expected_bit_offset = info
253+
self.assertEqual(getattr(X, name).bit_size,
254+
expected_bit_size)
255+
self.assertEqual(getattr(X, name).bit_offset,
256+
expected_bit_offset)
257+
self.assertEqual(getattr(X, name).size,
258+
(expected_bit_size << 16)
259+
| expected_bit_offset)
260+
else:
261+
self.assertEqual(getattr(X, name).is_bitfield, False)
262+
type_size = sizeof(expected_types[name])
263+
self.assertEqual(getattr(X, name).bit_size, type_size * 8)
264+
self.assertEqual(getattr(X, name).bit_offset, 0)
265+
self.assertEqual(getattr(X, name).size, type_size)
266+
267+
# is_anonymous
268+
269+
for name in field_names:
270+
with self.subTest(name=name):
271+
self.assertEqual(getattr(X, name).is_anonymous, (name == '_'))
272+
273+
178274
def test_invalid_field_types(self):
179275
class POINT(self.cls):
180276
pass

Modules/_ctypes/stgdict.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ MakeFields(PyObject *type, CFieldObject *descr,
143143
new_descr->proto = Py_XNewRef(fdescr->proto);
144144
new_descr->getfunc = fdescr->getfunc;
145145
new_descr->setfunc = fdescr->setfunc;
146+
new_descr->name = Py_NewRef(fdescr->name);
146147

147148
Py_DECREF(fdescr);
148149

0 commit comments

Comments
 (0)