8000 Merge pull request #11652 from eric-wieser/ctypes-dtype-coercion-fix · numpy/numpy@066298b · GitHub
[go: up one dir, main page]

Skip to content

Commit 066298b

Browse files
authored
Merge pull request #11652 from eric-wieser/ctypes-dtype-coercion-fix
BUG: Ensure singleton dimensions are not dropped when converting ctype arrays to dtypes
2 parents e14db2f + 78b85e0 commit 066298b

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

numpy/core/src/multiarray/descriptor.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ _arraydescr_fromctypes(PyObject *obj)
8383
/* derived type */
8484
PyObject *newtup;
8585
PyArray_Descr *derived;
86-
newtup = Py_BuildValue("NN", newdescr, length);
86+
newtup = Py_BuildValue("N(N)", newdescr, length);
8787
ret = PyArray_DescrConverter(newtup, &derived);
8888
Py_DECREF(newtup);
8989
if (ret == NPY_SUCCEED) {

numpy/core/tests/test_dtype.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55
import operator
66
import pytest
7+
import ctypes
78

89
import numpy as np
910
from numpy.core._rational_tests import rational
@@ -728,3 +729,74 @@ def test_dtypes_are_true():
728729
def test_invalid_dtype_string():
729730
# test for gh-10440
730731
assert_raises(TypeError, np.dtype, 'f8,i8,[f8,i8]')
732+
733+
734+
class TestFromCTypes(object):
735+
736+
@staticmethod
737+
def check(ctype, dtype):
738+
dtype = np.dtype(dtype)
739+
assert_equal(np.dtype(ctype), dtype)
740+
assert_equal(np.dtype(ctype()), dtype)
741+
742+
def test_array(self):
743+
c8 = ctypes.c_uint8
744+
self.check( 3 * c8, (np.uint8, (3,)))
745+
self.check( 1 * c8, (np.uint8, (1,)))
746+
self.check( 0 * c8, (np.uint8, (0,)))
747+
self.check(1 * (3 * c8), ((np.uint8, (3,)), (1,)))
748+
self.check(3 * (1 * c8), ((np.uint8, (1,)), (3,)))
749+
750+
def test_padded_structure(self):
751+
class PaddedStruct(ctypes.Structure):
752+
_fields_ = [
753+
('a', ctypes.c_uint8),
754+
('b', ctypes.c_uint16)
755+
]
756+
expected = np.dtype([
757+
('a', np.uint8),
758+
('b', np.uint16)
759+
], align=True)
760+
self.check(PaddedStruct, expected)
761+
762+
@pytest.mark.xfail(reason="_pack_ is ignored - see gh-11651")
763+
def test_packed_structure(self):
764+
class PackedStructure(ctypes.Structure):
765+
_pack_ = 1
766+
_fields_ = [
767+
('a', ctypes.c_uint8),
768+
('b', ctypes.c_uint16)
769+
]
770+
expected = np.dtype([
771+
('a', np.uint8),
772+
('b', np.uint16)
773+
])
774+
self.check(PackedStructure, expected)
775+
776+
@pytest.mark.xfail(sys.byteorder != 'little',
777+
reason="non-native endianness does not work - see gh-10533")
778+
def test_little_endian_structure(self):
779+
class PaddedStruct(ctypes.LittleEndianStructure):
780+
_fields_ = [
781+
('a', ctypes.c_uint8),
782+
('b', ctypes.c_uint16)
783+
]
784+
expected = np.dtype([
785+
('a', '<B'),
786+
('b', '<H')
787+
], align=True)
788+
self.check(PaddedStruct, expected)
789+
790+
@pytest.mark.xfail(sys.byteorder != 'big',
791+
reason="non-native endianness does not work - see gh-10533")
792+
def test_big_endian_structure(self):
793+
class PaddedStruct(ctypes.BigEndianStructure):
794+
_fields_ = [
795+
('a', ctypes.c_uint8),
796+
('b', ctypes.c_uint16)
797+
]
798+
expected = np.dtype([
799+
('a', '>B'),
800+
('b', '>H')
801+
], align=True)
802+
self.check(PaddedStruct, expected)

0 commit comments

Comments
 (0)
0