8000 Merge pull request #12342 from bmakos/fix#10532 · numpy/numpy@50aa813 · GitHub
[go: up one dir, main page]

8000 Skip to content

Commit 50aa813

Browse files
authored
Merge pull request #12342 from bmakos/fix#10532
BUG: Fix for np.dtype(ctypes.Structure) does not respect _pack_ field
2 parents befaf68 + d176283 commit 50aa813

File tree

2 files changed

+46
-7
lines changed

2 files changed

+46
-7
lines changed

numpy/core/_dtype_ctypes.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,38 @@ def _from_ctypes_array(t):
3333

3434

3535
def _from_ctypes_structure(t):
36-
# TODO: gh-10533, gh-10532
37-
fields = []
36+
# TODO: gh-10533
3837
for item in t._fields_:
3938
if len(item) > 2:
4039
raise TypeError(
4140
"ctypes bitfields have no dtype equivalent")
42-
fname, ftyp = item
43-
fields.append((fname, dtype_from_ctypes_type(ftyp)))
4441

45-
# by default, ctypes structs are aligned
46-
return np.dtype(fields, align=True)
42+
if hasattr(t, "_pack_"):
43+
formats = []
44+
offsets = []
45+
names = []
46+
current_offset = 0
47+
for fname, ftyp in t._fields_:
48+
names.append(fname)
49+
formats.append(dtype_from_ctypes_type(ftyp))
50+
# Each type has a default offset, this is platform dependent for some types.
51+
effective_pack = min(t._pack_, ctypes.alignment(ftyp))
52+
current_offset = ((current_offset + effective_pack - 1) // effective_pack) * effective_pack
53+
offsets.append(current_offset)
54+
current_offset += ctypes.sizeof(ftyp)
55+
56+
return np.dtype(dict(
57+
formats=formats,
58+
offsets=offsets,
59+
names=names,
60+
itemsize=ctypes.sizeof(t)))
61+
else:
62+
fields = []
63+
for fname, ftyp in t._fields_:
64+
fields.append((fname, dtype_from_ctypes_type(ftyp)))
65+
66+
# by default, ctypes structs are aligned
67+
return np.dtype(fields, align=True)
4768

4869

4970
def dtype_from_ctypes_type(t):

numpy/core/tests/test_dtype.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,6 @@ class Union(ctypes.Union):
824824
))
825825
self.check(Union, expected)
826826

827-
@pytest.mark.xfail(reason="_pack_ is ignored - see gh-11651")
828827
def test_packed_structure(self):
829828
class PackedStructure(ctypes.Structure):
830829
_pack_ = 1
@@ -838,6 +837,25 @@ class PackedStructure(ctypes.Structure):
838837
])
839838
self.check(PackedStructure, expected)
840839

840+
def test_large_packed_structure(self):
841+
class PackedStructure(ctypes.Structure):
842+
_pack_ = 2
843+
_fields_ = [
844+
('a', ctypes.c_uint8),
845+
('b', ctypes.c_uint16),
846+
('c', ctypes.c_uint8),
847+
('d', ctypes.c_uint16),
848+
('e', ctypes.c_uint32),
849+
('f', ctypes.c_uint32),
850+
('g', ctypes.c_uint8)
851+
]
852+
expected = np.dtype(dict(
853+
formats=[np.uint8, np.uint16, np.uint8, np.uint16, np.uint32, np.uint32, np.uint8 ],
854+
offsets=[0, 2, 4, 6, 8, 12, 16],
855+
names=['a', 'b', 'c', 'd', 'e', 'f', 'g'],
856+
itemsize=18))
857+
self.check(PackedStructure, expected)
858+
841859
@pytest.mark.xfail(sys.byteorder != 'little',
842860
reason="non-native endianness does not work - see gh-10533")
843861
def test_little_endian_structure(self):

0 commit comments

Comments
 (0)
0