10
10
#include "numpy/arrayscalars.h"
11
11
12
12
#include "npy_config.h"
13
-
13
+ #include "npy_ctypes.h"
14
14
#include "npy_pycompat.h"
15
15
16
16
#include "_datetime.h"
@@ -54,79 +54,46 @@ Borrowed_PyMapping_GetItemString(PyObject *o, char *key)
54
54
return ret ;
55
55
}
56
56
57
- /*
58
- * Creates a dtype object from ctypes inputs.
59
- *
60
- * Returns a new reference to a dtype object, or NULL
61
- * if this is not possible. When it returns NULL, it does
62
- * not set a Python exception.
63
- */
64
57
static PyArray_Descr *
65
- _arraydescr_fromctypes ( PyObject * obj )
58
+ _arraydescr_from_ctypes_type ( PyTypeObject * type )
66
59
{
67
- PyObject * dtypedescr ;
68
- PyArray_Descr * newdescr ;
69
- int ret ;
60
+ PyObject * _numpy_dtype_ctypes ;
61
+ PyObject * res ;
70
62
71
- /* Understand basic ctypes */
72
- dtypedescr = PyObject_GetAttrString (obj , "_type_" );
73
- PyErr_Clear ();
74
- if (dtypedescr ) {
75
- ret = PyArray_DescrConverter (dtypedescr , & newdescr );
76
- Py_DECREF (dtypedescr );
77
- if (ret == NPY_SUCCEED ) {
78
- PyObject * length ;
79
- /* Check for ctypes arrays */
80
- length = PyObject_GetAttrString (obj , "_length_" );
81
- PyErr_Clear ();
82
- if (length ) {
83
- /* derived type */
84
- PyObject * newtup ;
85
- PyArray_Descr * derived ;
86
- newtup = Py_BuildValue ("N(N)" , newdescr , length );
87
- ret = PyArray_DescrConverter (newtup , & derived );
88
- Py_DECREF (newtup );
89
- if (ret == NPY_SUCCEED ) {
90
- return derived ;
91
- }
92
- PyErr_Clear ();
93
- return NULL ;
94
- }
95
- return newdescr ;
96
- }
97
- PyErr_Clear ();
63
+ /* Call the python function of the same name. */
64
+ _numpy_dtype_ctypes = PyImport_ImportModule ("numpy.core._dtype_ctypes" );
65
+ if (_numpy_dtype_ctypes == NULL ) {
98
66
return NULL ;
99
67
}
100
- /* Understand ctypes structures --
101
- bit-fields are not supported
102
- automatically aligns */
103
- dtypedescr = PyObject_GetAttrString (obj , "_fields_" );
104
- PyErr_Clear ();
105
- if (dtypedescr ) {
106
- ret = PyArray_DescrAlignConverter (dtypedescr , & newdescr );
107
- Py_DECREF (dtypedescr );
108
- if (ret == NPY_SUCCEED ) {
109
- return newdescr ;
110
- }
111
- PyErr_Clear ();
68
+ res = PyObject_CallMethod (_numpy_dtype_ctypes , "dtype_from_ctypes_type" , "O" , (PyObject * )type );
69
+ Py_DECREF (_numpy_dtype_ctypes );
70
+ if (res == NULL ) {
71
+ return NULL ;
112
72
}
113
73
114
- return NULL ;
74
+ /*
75
+ * sanity check that dtype_from_ctypes_type returned the right type,
76
+ * since getting it wrong would give segfaults.
77
+ */
78
+ if (!PyObject_TypeCheck (res , & PyArrayDescr_Type )) {
79
+ Py_DECREF (res );
80
+ PyErr_BadInternalCall ();
81
+ return NULL ;
82
+ }
83
+
84
+ return (PyArray_Descr * )res ;
115
85
}
116
86
117
87
/*
118
- * This function creates a dtype object when:
119
- * - The object has a "dtype" attribute, and it can be converted
120
- * to a dtype object.
121
- * - The object is a ctypes type object, including array
122
- * and structure types.
88
+ * This function creates a dtype object when the object has a "dtype" attribute,
89
+ * and it can be converted to a dtype object.
123
90
*
124
91
* Returns a new reference to a dtype object, or NULL
125
92
* if this is not possible. When it returns NULL, it does
126
93
* not set a Python exception.
127
94
*/
128
95
NPY_NO_EXPORT PyArray_Descr *
129
- _arraydescr_fromobj (PyObject * obj )
96
+ _arraydescr_from_dtype_attr (PyObject * obj )
130
97
{
131
98
PyObject * dtypedescr ;
132
99
PyArray_Descr * newdescr = NULL ;
@@ -135,15 +102,18 @@ _arraydescr_fromobj(PyObject *obj)
135
102
/* For arbitrary objects that have a "dtype" attribute */
136
103
dtypedescr = PyObject_GetAttrString (obj , "dtype" );
137
104
PyErr_Clear ();
138
- if (dtypedescr != NULL ) {
139
- ret = PyArray_DescrConverter (dtypedescr , & newdescr );
140
- Py_DECREF (dtypedescr );
141
- if (ret == NPY_SUCCEED ) {
142
- return newdescr ;
143
- }
105
+ if (dtypedescr == NULL ) {
106
+ return NULL ;
107
+ }
108
+
109
+ ret = PyArray_DescrConverter (dtypedescr , & newdescr );
110
+ Py_DECREF (dtypedescr );
111
+ if (ret != NPY_SUCCEED ) {
144
112
PyErr_Clear ();
113
+ return NULL ;
145
114
}
146
- return _arraydescr_fromctypes (obj );
115
+
116
+ return newdescr ;
147
117
}
148
118
149
119
/*
@@ -1423,10 +1393,20 @@ PyArray_DescrConverter(PyObject *obj, PyArray_Descr **at)
1423
1393
check_num = NPY_VOID ;
1424
1394
}
1425
1395
else {
1426
- * at = _arraydescr_fromobj (obj );
1396
+ * at = _arraydescr_from_dtype_attr (obj );
1427
1397
if (* at ) {
1428
1398
return NPY_SUCCEED ;
1429
1399
}
1400
+
1401
+ /*
1402
+ * Note: this comes after _arraydescr_from_dtype_attr because the ctypes
1403
+ * type might override the dtype if numpy does not otherwise
1404
+ * support it.
1405
+ */
1406
+ if (npy_ctypes_check ((PyTypeObject * )obj )) {
1407
+ * at = _arraydescr_from_ctypes_type ((PyTypeObject * )obj );
1408
+ return * at ? NPY_SUCCEED : NPY_FAIL ;
1409
+ }
1430
1410
}
1431
1411
goto finish ;
1432
1412
}
@@ -1596,13 +1576,23 @@ PyArray_DescrConverter(PyObject *obj, PyArray_Descr **at)
1596
1576
goto fail ;
1597
1577
}
1598
1578
else {
1599
- * at = _arraydescr_fromobj (obj );
1579
+ * at = _arraydescr_from_dtype_attr (obj );
1600
1580
if (* at ) {
1601
1581
return NPY_SUCCEED ;
1602
1582
}
1603
1583
if (PyErr_Occurred ()) {
1604
1584
return NPY_FAIL ;
1605
1585
}
1586
+
1587
+ /*
1588
+ * Note: this comes after _arraydescr_from_dtype_attr because the ctypes
1589
+ * type might override the dtype if numpy does not otherwise
1590
+ * support it.
1591
+ */
1592
+ if (npy_ctypes_check (Py_TYPE (obj ))) {
1593
+ * at = _arraydescr_from_ctypes_type (Py_TYPE (obj ));
1594
+ return * at ? NPY_SUCCEED : NPY_FAIL ;
1595
+ }
1606
1596
goto fail ;
1607
1597
}
1608
1598
if (PyErr_Occurred ()) {
0 commit comments