1 /* Array Descr Object */
2 
3 #define PY_SSIZE_T_CLEAN
4 #include <Python.h>
5 #include "structmember.h"
6 
7 #define NPY_NO_DEPRECATED_API NPY_API_VERSION
8 #define _MULTIARRAYMODULE
9 #include "numpy/arrayobject.h"
10 #include "numpy/arrayscalars.h"
11 
12 #include "npy_config.h"
13 #include "npy_ctypes.h"
14 #include "npy_pycompat.h"
15 
16 #include "_datetime.h"
17 #include "common.h"
18 #include "templ_common.h" /* for npy_mul_with_overflow_intp */
19 #include "descriptor.h"
20 #include "alloc.h"
21 #include "assert.h"
22 #include "npy_buffer.h"
23 
24 /*
25  * offset:    A starting offset.
26  * alignment: A power-of-two alignment.
27  *
28  * This macro returns the smallest value >= 'offset'
29  * that is divisible by 'alignment'. Because 'alignment'
30  * is a power of two and integers are twos-complement,
31  * it is possible to use some simple bit-fiddling to do this.
32  */
33 #define NPY_NEXT_ALIGNED_OFFSET(offset, alignment) \
34                 (((offset) + (alignment) - 1) & (-(alignment)))
35 
36 #ifndef PyDictProxy_Check
37 #define PyDictProxy_Check(obj) (Py_TYPE(obj) == &PyDictProxy_Type)
38 #endif
39 
40 static PyObject *typeDict = NULL;   /* Must be explicitly loaded */
41 
42 static PyArray_Descr *
43 _try_convert_from_inherit_tuple(PyArray_Descr *type, PyObject *newobj);
44 
45 static PyArray_Descr *
46 _convert_from_any(PyObject *obj, int align);
47 
48 /*
49  * This function creates a dtype object when the object is a ctypes subclass.
50  *
51  * Returns `Py_NotImplemented` if the type is not a ctypes subclass.
52  */
53 static PyArray_Descr *
_try_convert_from_ctypes_type(PyTypeObject * type)54 _try_convert_from_ctypes_type(PyTypeObject *type)
55 {
56     PyObject *_numpy_dtype_ctypes;
57     PyObject *res;
58 
59     if (!npy_ctypes_check(type)) {
60         Py_INCREF(Py_NotImplemented);
61         return (PyArray_Descr *)Py_NotImplemented;
62     }
63 
64     /* Call the python function of the same name. */
65     _numpy_dtype_ctypes = PyImport_ImportModule("numpy.core._dtype_ctypes");
66     if (_numpy_dtype_ctypes == NULL) {
67         return NULL;
68     }
69     res = PyObject_CallMethod(_numpy_dtype_ctypes, "dtype_from_ctypes_type", "O", (PyObject *)type);
70     Py_DECREF(_numpy_dtype_ctypes);
71     if (res == NULL) {
72         return NULL;
73     }
74 
75     /*
76      * sanity check that dtype_from_ctypes_type returned the right type,
77      * since getting it wrong would give segfaults.
78      */
79     if (!PyObject_TypeCheck(res, &PyArrayDescr_Type)) {
80         Py_DECREF(res);
81         PyErr_BadInternalCall();
82         return NULL;
83     }
84 
85     return (PyArray_Descr *)res;
86 }
87 
88 static PyArray_Descr *
89 _convert_from_any(PyObject *obj, int align);
90 
91 /*
92  * This function creates a dtype object when the object has a "dtype" attribute,
93  * and it can be converted to a dtype object.
94  *
95  * Returns `Py_NotImplemented` if this is not possible.
96  * Currently the only failure mode for a NULL return is a RecursionError.
97  */
98 static PyArray_Descr *
_try_convert_from_dtype_attr(PyObject * obj)99 _try_convert_from_dtype_attr(PyObject *obj)
100 {
101     /* For arbitrary objects that have a "dtype" attribute */
102     PyObject *dtypedescr = PyObject_GetAttrString(obj, "dtype");
103     if (dtypedescr == NULL) {
104         /*
105          * This can be reached due to recursion limit being hit while fetching
106          * the attribute (tested for py3.7). This removes the custom message.
107          */
108         goto fail;
109     }
110 
111     if (Py_EnterRecursiveCall(
112             " while trying to convert the given data type from its "
113             "`.dtype` attribute.") != 0) {
114         Py_DECREF(dtypedescr);
115         return NULL;
116     }
117 
118     PyArray_Descr *newdescr = _convert_from_any(dtypedescr, 0);
119     Py_DECREF(dtypedescr);
120     Py_LeaveRecursiveCall();
121     if (newdescr == NULL) {
122         goto fail;
123     }
124 
125     return newdescr;
126 
127   fail:
128     /* Ignore all but recursion errors, to give ctypes a full try. */
129     if (!PyErr_ExceptionMatches(PyExc_RecursionError)) {
130         PyErr_Clear();
131         Py_INCREF(Py_NotImplemented);
132         return (PyArray_Descr *)Py_NotImplemented;
133     }
134     return NULL;
135 }
136 
137 /* Expose to another file with a prefixed name */
138 NPY_NO_EXPORT PyArray_Descr *
_arraydescr_try_convert_from_dtype_attr(PyObject * obj)139 _arraydescr_try_convert_from_dtype_attr(PyObject *obj)
140 {
141     return _try_convert_from_dtype_attr(obj);
142 }
143 
144 /*
145  * Sets the global typeDict object, which is a dictionary mapping
146  * dtype names to numpy scalar types.
147  */
148 NPY_NO_EXPORT PyObject *
array_set_typeDict(PyObject * NPY_UNUSED (ignored),PyObject * args)149 array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args)
150 {
151     PyObject *dict;
152 
153     if (!PyArg_ParseTuple(args, "O:set_typeDict", &dict)) {
154         return NULL;
155     }
156     /* Decrement old reference (if any)*/
157     Py_XDECREF(typeDict);
158     typeDict = dict;
159     /* Create an internal reference to it */
160     Py_INCREF(dict);
161     Py_RETURN_NONE;
162 }
163 
164 #define _chk_byteorder(arg) (arg == '>' || arg == '<' ||        \
165                              arg == '|' || arg == '=')
166 
167 static int
_check_for_commastring(const char * type,Py_ssize_t len)168 _check_for_commastring(const char *type, Py_ssize_t len)
169 {
170     Py_ssize_t i;
171     int sqbracket;
172 
173     /* Check for ints at start of string */
174     if ((type[0] >= '0'
175                 && type[0] <= '9')
176             || ((len > 1)
177                 && _chk_byteorder(type[0])
178                 && (type[1] >= '0'
179                 && type[1] <= '9'))) {
180         return 1;
181     }
182     /* Check for empty tuple */
183     if (((len > 1)
184                 && (type[0] == '('
185                 && type[1] == ')'))
186             || ((len > 3)
187                 && _chk_byteorder(type[0])
188                 && (type[1] == '('
189                 && type[2] == ')'))) {
190         return 1;
191     }
192     /*
193      * Check for presence of commas outside square [] brackets. This
194      * allows commas inside of [], for parameterized dtypes to use.
195      */
196     sqbracket = 0;
197     for (i = 0; i < len; i++) {
198         switch (type[i]) {
199             case ',':
200                 if (sqbracket == 0) {
201                     return 1;
202                 }
203                 break;
204             case '[':
205                 ++sqbracket;
206                 break;
207             case ']':
208                 --sqbracket;
209                 break;
210         }
211     }
212     return 0;
213 }
214 
215 #undef _chk_byteorder
216 
217 static int
is_datetime_typestr(char const * type,Py_ssize_t len)218 is_datetime_typestr(char const *type, Py_ssize_t len)
219 {
220     if (len < 2) {
221         return 0;
222     }
223     if (type[1] == '8' && (type[0] == 'M' || type[0] == 'm')) {
224         return 1;
225     }
226     if (len < 10) {
227         return 0;
228     }
229     if (strncmp(type, "datetime64", 10) == 0) {
230         return 1;
231     }
232     if (len < 11) {
233         return 0;
234     }
235     if (strncmp(type, "timedelta64", 11) == 0) {
236         return 1;
237     }
238     return 0;
239 }
240 
241 static PyArray_Descr *
_convert_from_tuple(PyObject * obj,int align)242 _convert_from_tuple(PyObject *obj, int align)
243 {
244     if (PyTuple_GET_SIZE(obj) != 2) {
245         PyErr_Format(PyExc_TypeError,
246 	        "Tuple must have size 2, but has size %zd",
247 	        PyTuple_GET_SIZE(obj));
248         return NULL;
249     }
250     PyArray_Descr *type = _convert_from_any(PyTuple_GET_ITEM(obj, 0), align);
251     if (type == NULL) {
252         return NULL;
253     }
254     PyObject *val = PyTuple_GET_ITEM(obj,1);
255     /* try to interpret next item as a type */
256     PyArray_Descr *res = _try_convert_from_inherit_tuple(type, val);
257     if ((PyObject *)res != Py_NotImplemented) {
258         Py_DECREF(type);
259         return res;
260     }
261     Py_DECREF(res);
262     /*
263      * We get here if _try_convert_from_inherit_tuple failed without crashing
264      */
265     if (PyDataType_ISUNSIZED(type)) {
266         /* interpret next item as a typesize */
267         int itemsize = PyArray_PyIntAsInt(PyTuple_GET_ITEM(obj,1));
268 
269         if (error_converting(itemsize)) {
270             PyErr_SetString(PyExc_ValueError,
271                     "invalid itemsize in generic type tuple");
272             Py_DECREF(type);
273             return NULL;
274         }
275         PyArray_DESCR_REPLACE(type);
276         if (type == NULL) {
277             return NULL;
278         }
279         if (type->type_num == NPY_UNICODE) {
280             type->elsize = itemsize << 2;
281         }
282         else {
283             type->elsize = itemsize;
284         }
285         return type;
286     }
287     else if (type->metadata && (PyDict_Check(val) || PyDictProxy_Check(val))) {
288         /* Assume it's a metadata dictionary */
289         if (PyDict_Merge(type->metadata, val, 0) == -1) {
290             Py_DECREF(type);
291             return NULL;
292         }
293         return type;
294     }
295     else {
296         /*
297          * interpret next item as shape (if it's a tuple)
298          * and reset the type to NPY_VOID with
299          * a new fields attribute.
300          */
301         PyArray_Dims shape = {NULL, -1};
302         if (!(PyArray_IntpConverter(val, &shape)) || (shape.len > NPY_MAXDIMS)) {
303             PyErr_SetString(PyExc_ValueError,
304                     "invalid shape in fixed-type tuple.");
305             goto fail;
306         }
307         /* if (type, ()) was given it is equivalent to type... */
308         if (shape.len == 0 && PyTuple_Check(val)) {
309             npy_free_cache_dim_obj(shape);
310             return type;
311         }
312         /* (type, 1) use to be equivalent to type, but is deprecated */
313         if (shape.len == 1
314                 && shape.ptr[0] == 1
315                 && PyNumber_Check(val)) {
316             /* 2019-05-20, 1.17 */
317             if (DEPRECATE_FUTUREWARNING(
318                         "Passing (type, 1) or '1type' as a synonym of type is "
319                         "deprecated; in a future version of numpy, it will be "
320                         "understood as (type, (1,)) / '(1,)type'.") < 0) {
321                 goto fail;
322             }
323             npy_free_cache_dim_obj(shape);
324             return type;
325         }
326 
327         /* validate and set shape */
328         for (int i=0; i < shape.len; i++) {
329             if (shape.ptr[i] < 0) {
330                 PyErr_SetString(PyExc_ValueError,
331                                 "invalid shape in fixed-type tuple: "
332                                 "dimension smaller then zero.");
333                 goto fail;
334             }
335             if (shape.ptr[i] > NPY_MAX_INT) {
336                 PyErr_SetString(PyExc_ValueError,
337                                 "invalid shape in fixed-type tuple: "
338                                 "dimension does not fit into a C int.");
339                 goto fail;
340             }
341         }
342         npy_intp items = PyArray_OverflowMultiplyList(shape.ptr, shape.len);
343         int overflowed;
344         int nbytes;
345         if (items < 0 || items > NPY_MAX_INT) {
346             overflowed = 1;
347         }
348         else {
349             overflowed = npy_mul_with_overflow_int(
350                 &nbytes, type->elsize, (int) items);
351         }
352         if (overflowed) {
353             PyErr_SetString(PyExc_ValueError,
354                             "invalid shape in fixed-type tuple: dtype size in "
355                             "bytes must fit into a C int.");
356             goto fail;
357         }
358         PyArray_Descr *newdescr = PyArray_DescrNewFromType(NPY_VOID);
359         if (newdescr == NULL) {
360             goto fail;
361         }
362         newdescr->elsize = nbytes;
363         newdescr->subarray = PyArray_malloc(sizeof(PyArray_ArrayDescr));
364         if (newdescr->subarray == NULL) {
365             Py_DECREF(newdescr);
366             PyErr_NoMemory();
367             goto fail;
368         }
369         newdescr->flags = type->flags;
370         newdescr->alignment = type->alignment;
371         newdescr->subarray->base = type;
372         type = NULL;
373         Py_XDECREF(newdescr->fields);
374         Py_XDECREF(newdescr->names);
375         newdescr->fields = NULL;
376         newdescr->names = NULL;
377 
378         /*
379          * Create a new subarray->shape tuple (it can be an arbitrary
380          * sequence of integer like objects, neither of which is safe.
381          */
382         newdescr->subarray->shape = PyTuple_New(shape.len);
383         if (newdescr->subarray->shape == NULL) {
384             Py_DECREF(newdescr);
385             goto fail;
386         }
387         for (int i=0; i < shape.len; i++) {
388             PyTuple_SET_ITEM(newdescr->subarray->shape, i,
389                              PyLong_FromLong((long)shape.ptr[i]));
390 
391             if (PyTuple_GET_ITEM(newdescr->subarray->shape, i) == NULL) {
392                 Py_DECREF(newdescr);
393                 goto fail;
394             }
395         }
396 
397         npy_free_cache_dim_obj(shape);
398         return newdescr;
399 
400     fail:
401         Py_XDECREF(type);
402         npy_free_cache_dim_obj(shape);
403         return NULL;
404     }
405 }
406 
407 /*
408  * obj is a list.  Each item is a tuple with
409  *
410  * (field-name, data-type (either a list or a string), and an optional
411  * shape parameter).
412  *
413  * field-name can be a string or a 2-tuple
414  * data-type can now be a list, string, or 2-tuple
415  *          (string, metadata dictionary)
416  */
417 static PyArray_Descr *
_convert_from_array_descr(PyObject * obj,int align)418 _convert_from_array_descr(PyObject *obj, int align)
419 {
420     int n = PyList_GET_SIZE(obj);
421     PyObject *nameslist = PyTuple_New(n);
422     if (!nameslist) {
423         return NULL;
424     }
425 
426     /* Types with fields need the Python C API for field access */
427     char dtypeflags = NPY_NEEDS_PYAPI;
428     int maxalign = 0;
429     int totalsize = 0;
430     PyObject *fields = PyDict_New();
431     if (!fields) {
432         return NULL;
433     }
434     for (int i = 0; i < n; i++) {
435         PyObject *item = PyList_GET_ITEM(obj, i);
436         if (!PyTuple_Check(item) || (PyTuple_GET_SIZE(item) < 2)) {
437             PyErr_Format(PyExc_TypeError,
438 			 "Field elements must be 2- or 3-tuples, got '%R'",
439 			 item);
440             goto fail;
441         }
442         PyObject *name = PyTuple_GET_ITEM(item, 0);
443         PyObject *title;
444         if (PyUnicode_Check(name)) {
445             title = NULL;
446         }
447         else if (PyTuple_Check(name)) {
448             if (PyTuple_GET_SIZE(name) != 2) {
449                 PyErr_Format(PyExc_TypeError,
450 				"If a tuple, the first element of a field tuple must have "
451 				"two elements, not %zd",
452 			       	PyTuple_GET_SIZE(name));
453                 goto fail;
454             }
455             title = PyTuple_GET_ITEM(name, 0);
456             name = PyTuple_GET_ITEM(name, 1);
457             if (!PyUnicode_Check(name)) {
458                 PyErr_SetString(PyExc_TypeError, "Field name must be a str");
459                 goto fail;
460             }
461         }
462         else {
463             PyErr_SetString(PyExc_TypeError,
464 			            "First element of field tuple is "
465 			            "neither a tuple nor str");
466             goto fail;
467         }
468 
469         /* Insert name into nameslist */
470         Py_INCREF(name);
471 
472         if (PyUnicode_GetLength(name) == 0) {
473             Py_DECREF(name);
474             if (title == NULL) {
475                 name = PyUnicode_FromFormat("f%d", i);
476                 if (name == NULL) {
477                     goto fail;
478                 }
479             }
480             /* On Py3, allow only non-empty Unicode strings as field names */
481             else if (PyUnicode_Check(title) && PyUnicode_GetLength(title) > 0) {
482                 name = title;
483                 Py_INCREF(name);
484             }
485             else {
486                 PyErr_SetString(PyExc_TypeError, "Field titles must be non-empty strings");
487                 goto fail;
488             }
489         }
490         PyTuple_SET_ITEM(nameslist, i, name);
491 
492         /* Process rest */
493         PyArray_Descr *conv;
494         if (PyTuple_GET_SIZE(item) == 2) {
495             conv = _convert_from_any(PyTuple_GET_ITEM(item, 1), align);
496             if (conv == NULL) {
497                 goto fail;
498             }
499         }
500         else if (PyTuple_GET_SIZE(item) == 3) {
501             PyObject *newobj = PyTuple_GetSlice(item, 1, 3);
502             conv = _convert_from_any(newobj, align);
503             Py_DECREF(newobj);
504             if (conv == NULL) {
505                 goto fail;
506             }
507         }
508         else {
509             PyErr_Format(PyExc_TypeError,
510                     "Field elements must be tuples with at most 3 elements, got '%R'", item);
511             goto fail;
512         }
513         if ((PyDict_GetItemWithError(fields, name) != NULL)
514              || (title
515                  && PyUnicode_Check(title)
516                  && (PyDict_GetItemWithError(fields, title) != NULL))) {
517             PyErr_Format(PyExc_ValueError,
518                     "field %R occurs more than once", name);
519             Py_DECREF(conv);
520             goto fail;
521         }
522         else if (PyErr_Occurred()) {
523             /* Dict lookup crashed */
524             Py_DECREF(conv);
525             goto fail;
526         }
527         dtypeflags |= (conv->flags & NPY_FROM_FIELDS);
528         if (align) {
529             int _align = conv->alignment;
530             if (_align > 1) {
531                 totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, _align);
532             }
533             maxalign = PyArray_MAX(maxalign, _align);
534         }
535         PyObject *tup = PyTuple_New((title == NULL ? 2 : 3));
536         if (tup == NULL) {
537             goto fail;
538         }
539         PyTuple_SET_ITEM(tup, 0, (PyObject *)conv);
540         PyTuple_SET_ITEM(tup, 1, PyLong_FromLong((long) totalsize));
541 
542         /*
543          * Title can be "meta-data".  Only insert it
544          * into the fields dictionary if it is a string
545          * and if it is not the same as the name.
546          */
547         if (title != NULL) {
548             Py_INCREF(title);
549             PyTuple_SET_ITEM(tup, 2, title);
550             if (PyDict_SetItem(fields, name, tup) < 0) {
551                 goto fail;
552             }
553             if (PyUnicode_Check(title)) {
554                 PyObject *existing = PyDict_GetItemWithError(fields, title);
555                 if (existing == NULL && PyErr_Occurred()) {
556                     goto fail;
557                 }
558                 if (existing != NULL) {
559                     PyErr_SetString(PyExc_ValueError,
560                             "title already used as a name or title.");
561                     Py_DECREF(tup);
562                     goto fail;
563                 }
564                 if (PyDict_SetItem(fields, title, tup) < 0) {
565                     goto fail;
566                 }
567             }
568         }
569         else {
570             if (PyDict_SetItem(fields, name, tup) < 0) {
571                 goto fail;
572             }
573         }
574 
575         totalsize += conv->elsize;
576         Py_DECREF(tup);
577     }
578 
579     if (maxalign > 1) {
580         totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign);
581     }
582 
583     PyArray_Descr *new = PyArray_DescrNewFromType(NPY_VOID);
584     if (new == NULL) {
585         Py_XDECREF(fields);
586         Py_XDECREF(nameslist);
587         return NULL;
588     }
589     new->fields = fields;
590     new->names = nameslist;
591     new->elsize = totalsize;
592     new->flags = dtypeflags;
593 
594     /* Structured arrays get a sticky aligned bit */
595     if (align) {
596         new->flags |= NPY_ALIGNED_STRUCT;
597         new->alignment = maxalign;
598     }
599     return new;
600 
601  fail:
602     Py_DECREF(fields);
603     Py_DECREF(nameslist);
604     return NULL;
605 
606 }
607 
608 /*
609  * a list specifying a data-type can just be
610  * a list of formats.  The names for the fields
611  * will default to f0, f1, f2, and so forth.
612  */
613 static PyArray_Descr *
_convert_from_list(PyObject * obj,int align)614 _convert_from_list(PyObject *obj, int align)
615 {
616     int n = PyList_GET_SIZE(obj);
617     /*
618      * Ignore any empty string at end which _internal._commastring
619      * can produce
620      */
621     PyObject *last_item = PyList_GET_ITEM(obj, n-1);
622     if (PyUnicode_Check(last_item)) {
623         Py_ssize_t s = PySequence_Size(last_item);
624         if (s < 0) {
625             return NULL;
626         }
627         if (s == 0) {
628             n = n - 1;
629         }
630     }
631     if (n == 0) {
632         PyErr_SetString(PyExc_ValueError, "Expected at least one field name");
633         return NULL;
634     }
635     PyObject *nameslist = PyTuple_New(n);
636     if (!nameslist) {
637         return NULL;
638     }
639     PyObject *fields = PyDict_New();
640     if (!fields) {
641         Py_DECREF(nameslist);
642         return NULL;
643     }
644 
645     /* Types with fields need the Python C API for field access */
646     char dtypeflags = NPY_NEEDS_PYAPI;
647     int maxalign = 0;
648     int totalsize = 0;
649     for (int i = 0; i < n; i++) {
650         PyArray_Descr *conv = _convert_from_any(
651                 PyList_GET_ITEM(obj, i), align);
652         if (conv == NULL) {
653             goto fail;
654         }
655         dtypeflags |= (conv->flags & NPY_FROM_FIELDS);
656         if (align) {
657             int _align = conv->alignment;
658             if (_align > 1) {
659                 totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, _align);
660             }
661             maxalign = PyArray_MAX(maxalign, _align);
662         }
663         PyObject *size_obj = PyLong_FromLong((long) totalsize);
664         if (!size_obj) {
665             Py_DECREF(conv);
666             goto fail;
667         }
668         PyObject *tup = PyTuple_New(2);
669         if (!tup) {
670             Py_DECREF(size_obj);
671             Py_DECREF(conv);
672             goto fail;
673         }
674         PyTuple_SET_ITEM(tup, 0, (PyObject *)conv);
675         PyTuple_SET_ITEM(tup, 1, size_obj);
676         PyObject *key = PyUnicode_FromFormat("f%d", i);
677         if (!key) {
678             Py_DECREF(tup);
679             goto fail;
680         }
681         /* steals a reference to key */
682         PyTuple_SET_ITEM(nameslist, i, key);
683         int ret = PyDict_SetItem(fields, key, tup);
684         Py_DECREF(tup);
685         if (ret < 0) {
686             goto fail;
687         }
688         totalsize += conv->elsize;
689     }
690     PyArray_Descr *new = PyArray_DescrNewFromType(NPY_VOID);
691     new->fields = fields;
692     new->names = nameslist;
693     new->flags = dtypeflags;
694     if (maxalign > 1) {
695         totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign);
696     }
697     /* Structured arrays get a sticky aligned bit */
698     if (align) {
699         new->flags |= NPY_ALIGNED_STRUCT;
700         new->alignment = maxalign;
701     }
702     new->elsize = totalsize;
703     return new;
704 
705  fail:
706     Py_DECREF(nameslist);
707     Py_DECREF(fields);
708     return NULL;
709 }
710 
711 
712 /*
713  * comma-separated string
714  * this is the format developed by the numarray records module and implemented
715  * by the format parser in that module this is an alternative implementation
716  * found in the _internal.py file patterned after that one -- the approach is
717  * to try to convert to a list (with tuples if any repeat information is
718  * present) and then call the _convert_from_list)
719  *
720  * TODO: Calling Python from C like this in critical-path code is not
721  *       a good idea. This should all be converted to C code.
722  */
723 static PyArray_Descr *
_convert_from_commastring(PyObject * obj,int align)724 _convert_from_commastring(PyObject *obj, int align)
725 {
726     PyObject *listobj;
727     PyArray_Descr *res;
728     PyObject *_numpy_internal;
729     assert(PyUnicode_Check(obj));
730     _numpy_internal = PyImport_ImportModule("numpy.core._internal");
731     if (_numpy_internal == NULL) {
732         return NULL;
733     }
734     listobj = PyObject_CallMethod(_numpy_internal, "_commastring", "O", obj);
735     Py_DECREF(_numpy_internal);
736     if (listobj == NULL) {
737         return NULL;
738     }
739     if (!PyList_Check(listobj) || PyList_GET_SIZE(listobj) < 1) {
740         PyErr_SetString(PyExc_RuntimeError,
741                 "_commastring is not returning a list with len >= 1");
742         Py_DECREF(listobj);
743         return NULL;
744     }
745     if (PyList_GET_SIZE(listobj) == 1) {
746         res = _convert_from_any(PyList_GET_ITEM(listobj, 0), align);
747     }
748     else {
749         res = _convert_from_list(listobj, align);
750     }
751     Py_DECREF(listobj);
752     return res;
753 }
754 
755 static int
_is_tuple_of_integers(PyObject * obj)756 _is_tuple_of_integers(PyObject *obj)
757 {
758     int i;
759 
760     if (!PyTuple_Check(obj)) {
761         return 0;
762     }
763     for (i = 0; i < PyTuple_GET_SIZE(obj); i++) {
764         if (!PyArray_IsIntegerScalar(PyTuple_GET_ITEM(obj, i))) {
765             return 0;
766         }
767     }
768     return 1;
769 }
770 
771 /*
772  * helper function for _try_convert_from_inherit_tuple to disallow dtypes of the form
773  * (old_dtype, new_dtype) where either of the dtypes contains python
774  * objects - these dtypes are not useful and can be a source of segfaults,
775  * when an attempt is made to interpret a python object as a different dtype
776  * or vice versa
777  * an exception is made for dtypes of the form ('O', [('name', 'O')]), which
778  * people have been using to add a field to an object array without fields
779  */
780 static int
_validate_union_object_dtype(PyArray_Descr * new,PyArray_Descr * conv)781 _validate_union_object_dtype(PyArray_Descr *new, PyArray_Descr *conv)
782 {
783     PyObject *name, *tup;
784     PyArray_Descr *dtype;
785 
786     if (!PyDataType_REFCHK(new) && !PyDataType_REFCHK(conv)) {
787         return 0;
788     }
789     if (PyDataType_HASFIELDS(new) || new->kind != 'O') {
790         goto fail;
791     }
792     if (!PyDataType_HASFIELDS(conv) || PyTuple_GET_SIZE(conv->names) != 1) {
793         goto fail;
794     }
795     name = PyTuple_GET_ITEM(conv->names, 0);
796     if (name == NULL) {
797         return -1;
798     }
799     tup = PyDict_GetItemWithError(conv->fields, name);
800     if (tup == NULL) {
801         if (!PyErr_Occurred()) {
802             /* fields was missing the name it claimed to contain */
803             PyErr_BadInternalCall();
804         }
805         return -1;
806     }
807     dtype = (PyArray_Descr *)PyTuple_GET_ITEM(tup, 0);
808     if (dtype == NULL) {
809         return -1;
810     }
811     if (dtype->kind != 'O') {
812         goto fail;
813     }
814     return 0;
815 
816 fail:
817     PyErr_SetString(PyExc_ValueError,
818             "dtypes of the form (old_dtype, new_dtype) containing the object "
819             "dtype are not supported");
820     return -1;
821 }
822 
823 /*
824  * A tuple type would be either (generic typeobject, typesize)
825  * or (fixed-length data-type, shape)
826  *
827  * or (inheriting data-type, new-data-type)
828  * The new data-type must have the same itemsize as the inheriting data-type
829  * unless the latter is 0
830  *
831  * Thus (int32, {'real':(int16,0),'imag',(int16,2)})
832  *
833  * is one way to specify a descriptor that will give
834  * a['real'] and a['imag'] to an int32 array.
835  *
836  * leave type reference alone
837  *
838  * Returns `Py_NotImplemented` if the second tuple item is not
839  * appropriate.
840  */
841 static PyArray_Descr *
_try_convert_from_inherit_tuple(PyArray_Descr * type,PyObject * newobj)842 _try_convert_from_inherit_tuple(PyArray_Descr *type, PyObject *newobj)
843 {
844     if (PyArray_IsScalar(newobj, Integer) || _is_tuple_of_integers(newobj)) {
845         /* It's a subarray or flexible type instead */
846         Py_INCREF(Py_NotImplemented);
847         return (PyArray_Descr *)Py_NotImplemented;
848     }
849     PyArray_Descr *conv = _convert_from_any(newobj, 0);
850     if (conv == NULL) {
851         /* Let someone else try to convert this */
852         PyErr_Clear();
853         Py_INCREF(Py_NotImplemented);
854         return (PyArray_Descr *)Py_NotImplemented;
855     }
856     PyArray_Descr *new = PyArray_DescrNew(type);
857     if (new == NULL) {
858         goto fail;
859     }
860     if (PyDataType_ISUNSIZED(new)) {
861         new->elsize = conv->elsize;
862     }
863     else if (new->elsize != conv->elsize) {
864         PyErr_SetString(PyExc_ValueError,
865                 "mismatch in size of old and new data-descriptor");
866         Py_DECREF(new);
867         goto fail;
868     }
869     else if (_validate_union_object_dtype(new, conv) < 0) {
870         Py_DECREF(new);
871         goto fail;
872     }
873 
874     if (PyDataType_HASFIELDS(conv)) {
875         Py_XDECREF(new->fields);
876         new->fields = conv->fields;
877         Py_XINCREF(new->fields);
878 
879         Py_XDECREF(new->names);
880         new->names = conv->names;
881         Py_XINCREF(new->names);
882     }
883     if (conv->metadata != NULL) {
884         Py_XDECREF(new->metadata);
885         new->metadata = conv->metadata;
886         Py_XINCREF(new->metadata);
887     }
888     /*
889      * Certain flags must be inherited from the fields.  This is needed
890      * only for void dtypes (or subclasses of it such as a record dtype).
891      * For other dtypes, the field part will only be used for direct field
892      * access and thus flag inheritance should not be necessary.
893      * (We only allow object fields if the dtype is object as well.)
894      * This ensures copying over of the NPY_FROM_FIELDS "inherited" flags.
895      */
896     if (new->type_num == NPY_VOID) {
897         new->flags = conv->flags;
898     }
899     Py_DECREF(conv);
900     return new;
901 
902  fail:
903     Py_DECREF(conv);
904     return NULL;
905 }
906 
907 /*
908  * Validates that any field of the structured array 'dtype' which has
909  * the NPY_ITEM_HASOBJECT flag set does not overlap with another field.
910  *
911  * This algorithm is worst case O(n^2). It could be done with a sort
912  * and sweep algorithm, but the structured dtype representation is
913  * rather ugly right now, so writing something better can wait until
914  * that representation is made sane.
915  *
916  * Returns 0 on success, -1 if an exception is raised.
917  */
918 static int
_validate_object_field_overlap(PyArray_Descr * dtype)919 _validate_object_field_overlap(PyArray_Descr *dtype)
920 {
921     PyObject *names, *fields, *key, *tup, *title;
922     Py_ssize_t i, j, names_size;
923     PyArray_Descr *fld_dtype, *fld2_dtype;
924     int fld_offset, fld2_offset;
925 
926     /* Get some properties from the dtype */
927     names = dtype->names;
928     names_size = PyTuple_GET_SIZE(names);
929     fields = dtype->fields;
930 
931     for (i = 0; i < names_size; ++i) {
932         key = PyTuple_GET_ITEM(names, i);
933         if (key == NULL) {
934             return -1;
935         }
936         tup = PyDict_GetItemWithError(fields, key);
937         if (tup == NULL) {
938             if (!PyErr_Occurred()) {
939                 /* fields was missing the name it claimed to contain */
940                 PyErr_BadInternalCall();
941             }
942             return -1;
943         }
944         if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) {
945             return -1;
946         }
947 
948         /* If this field has objects, check for overlaps */
949         if (PyDataType_REFCHK(fld_dtype)) {
950             for (j = 0; j < names_size; ++j) {
951                 if (i != j) {
952                     key = PyTuple_GET_ITEM(names, j);
953                     if (key == NULL) {
954                         return -1;
955                     }
956                     tup = PyDict_GetItemWithError(fields, key);
957                     if (tup == NULL) {
958                         if (!PyErr_Occurred()) {
959                             /* fields was missing the name it claimed to contain */
960                             PyErr_BadInternalCall();
961                         }
962                         return -1;
963                     }
964                     if (!PyArg_ParseTuple(tup, "Oi|O", &fld2_dtype,
965                                                 &fld2_offset, &title)) {
966                         return -1;
967                     }
968                     /* Raise an exception if it overlaps */
969                     if (fld_offset < fld2_offset + fld2_dtype->elsize &&
970                                 fld2_offset < fld_offset + fld_dtype->elsize) {
971                         PyErr_SetString(PyExc_TypeError,
972                                 "Cannot create a NumPy dtype with overlapping "
973                                 "object fields");
974                         return -1;
975                     }
976                 }
977             }
978         }
979     }
980 
981     /* It passed all the overlap tests */
982     return 0;
983 }
984 
985 /*
986  * a dictionary specifying a data-type
987  * must have at least two and up to four
988  * keys These must all be sequences of the same length.
989  *
990  * can also have an additional key called "metadata" which can be any dictionary
991  *
992  * "names" --- field names
993  * "formats" --- the data-type descriptors for the field.
994  *
995  * Optional:
996  *
997  * "offsets" --- integers indicating the offset into the
998  * record of the start of the field.
999  * if not given, then "consecutive offsets"
1000  * will be assumed and placed in the dictionary.
1001  *
1002  * "titles" --- Allows the use of an additional key
1003  * for the fields dictionary.(if these are strings
1004  * or unicode objects) or
1005  * this can also be meta-data to
1006  * be passed around with the field description.
1007  *
1008  * Attribute-lookup-based field names merely has to query the fields
1009  * dictionary of the data-descriptor.  Any result present can be used
1010  * to return the correct field.
1011  *
1012  * So, the notion of what is a name and what is a title is really quite
1013  * arbitrary.
1014  *
1015  * What does distinguish a title, however, is that if it is not None,
1016  * it will be placed at the end of the tuple inserted into the
1017  * fields dictionary.and can therefore be used to carry meta-data around.
1018  *
1019  * If the dictionary does not have "names" and "formats" entries,
1020  * then it will be checked for conformity and used directly.
1021  */
1022 static PyArray_Descr *
_convert_from_field_dict(PyObject * obj,int align)1023 _convert_from_field_dict(PyObject *obj, int align)
1024 {
1025     PyObject *_numpy_internal;
1026     PyArray_Descr *res;
1027 
1028     _numpy_internal = PyImport_ImportModule("numpy.core._internal");
1029     if (_numpy_internal == NULL) {
1030         return NULL;
1031     }
1032     res = (PyArray_Descr *)PyObject_CallMethod(_numpy_internal,
1033             "_usefields", "Oi", obj, align);
1034     Py_DECREF(_numpy_internal);
1035     return res;
1036 }
1037 
1038 /*
1039  * Creates a struct dtype object from a Python dictionary.
1040  */
1041 static PyArray_Descr *
_convert_from_dict(PyObject * obj,int align)1042 _convert_from_dict(PyObject *obj, int align)
1043 {
1044     PyObject *fields = PyDict_New();
1045     if (fields == NULL) {
1046         return (PyArray_Descr *)PyErr_NoMemory();
1047     }
1048     /*
1049      * Use PyMapping_GetItemString to support dictproxy objects as well.
1050      */
1051     PyObject *names = PyMapping_GetItemString(obj, "names");
1052     if (names == NULL) {
1053         Py_DECREF(fields);
1054         /* XXX should check this is a KeyError */
1055         PyErr_Clear();
1056         return _convert_from_field_dict(obj, align);
1057     }
1058     PyObject *descrs = PyMapping_GetItemString(obj, "formats");
1059     if (descrs == NULL) {
1060         Py_DECREF(fields);
1061         /* XXX should check this is a KeyError */
1062         PyErr_Clear();
1063         Py_DECREF(names);
1064         return _convert_from_field_dict(obj, align);
1065     }
1066     int n = PyObject_Length(names);
1067     PyObject *offsets = PyMapping_GetItemString(obj, "offsets");
1068     if (!offsets) {
1069         PyErr_Clear();
1070     }
1071     PyObject *titles = PyMapping_GetItemString(obj, "titles");
1072     if (!titles) {
1073         PyErr_Clear();
1074     }
1075 
1076     if ((n > PyObject_Length(descrs))
1077         || (offsets && (n > PyObject_Length(offsets)))
1078         || (titles && (n > PyObject_Length(titles)))) {
1079         PyErr_SetString(PyExc_ValueError,
1080                 "'names', 'formats', 'offsets', and 'titles' dict "
1081                 "entries must have the same length");
1082         goto fail;
1083     }
1084 
1085     /*
1086      * If a property 'aligned' is in the dict, it overrides the align flag
1087      * to be True if it not already true.
1088      */
1089     PyObject *tmp = PyMapping_GetItemString(obj, "aligned");
1090     if (tmp == NULL) {
1091         PyErr_Clear();
1092     } else {
1093         if (tmp == Py_True) {
1094             align = 1;
1095         }
1096         else if (tmp != Py_False) {
1097             Py_DECREF(tmp);
1098             PyErr_SetString(PyExc_ValueError,
1099                     "NumPy dtype descriptor includes 'aligned' entry, "
1100                     "but its value is neither True nor False");
1101             goto fail;
1102         }
1103         Py_DECREF(tmp);
1104     }
1105 
1106     /* Types with fields need the Python C API for field access */
1107     char dtypeflags = NPY_NEEDS_PYAPI;
1108     int totalsize = 0;
1109     int maxalign = 0;
1110     int has_out_of_order_fields = 0;
1111     for (int i = 0; i < n; i++) {
1112         /* Build item to insert (descr, offset, [title])*/
1113         int len = 2;
1114         PyObject *title = NULL;
1115         PyObject *ind = PyLong_FromLong(i);
1116         if (titles) {
1117             title=PyObject_GetItem(titles, ind);
1118             if (title && title != Py_None) {
1119                 len = 3;
1120             }
1121             else {
1122                 Py_XDECREF(title);
1123             }
1124             PyErr_Clear();
1125         }
1126         PyObject *tup = PyTuple_New(len);
1127         PyObject *descr = PyObject_GetItem(descrs, ind);
1128         if (!descr) {
1129             Py_DECREF(tup);
1130             Py_DECREF(ind);
1131             goto fail;
1132         }
1133         PyArray_Descr *newdescr = _convert_from_any(descr, align);
1134         Py_DECREF(descr);
1135         if (newdescr == NULL) {
1136             Py_DECREF(tup);
1137             Py_DECREF(ind);
1138             goto fail;
1139         }
1140         PyTuple_SET_ITEM(tup, 0, (PyObject *)newdescr);
1141         int _align = 1;
1142         if (align) {
1143             _align = newdescr->alignment;
1144             maxalign = PyArray_MAX(maxalign,_align);
1145         }
1146         if (offsets) {
1147             PyObject *off = PyObject_GetItem(offsets, ind);
1148             if (!off) {
1149                 Py_DECREF(tup);
1150                 Py_DECREF(ind);
1151                 goto fail;
1152             }
1153             long offset = PyArray_PyIntAsInt(off);
1154             if (error_converting(offset)) {
1155                 Py_DECREF(off);
1156                 Py_DECREF(tup);
1157                 Py_DECREF(ind);
1158                 goto fail;
1159             }
1160             Py_DECREF(off);
1161             if (offset < 0) {
1162                 PyErr_Format(PyExc_ValueError, "offset %ld cannot be negative",
1163                              offset);
1164                 Py_DECREF(tup);
1165                 Py_DECREF(ind);
1166                 goto fail;
1167             }
1168 
1169             PyTuple_SET_ITEM(tup, 1, PyLong_FromLong(offset));
1170             /* Flag whether the fields are specified out of order */
1171             if (offset < totalsize) {
1172                 has_out_of_order_fields = 1;
1173             }
1174             /* If align=True, enforce field alignment */
1175             if (align && offset % newdescr->alignment != 0) {
1176                 PyErr_Format(PyExc_ValueError,
1177                         "offset %ld for NumPy dtype with fields is "
1178                         "not divisible by the field alignment %d "
1179                         "with align=True",
1180                         offset, newdescr->alignment);
1181                 Py_DECREF(ind);
1182                 Py_DECREF(tup);
1183                 goto fail;
1184             }
1185             else if (offset + newdescr->elsize > totalsize) {
1186                 totalsize = offset + newdescr->elsize;
1187             }
1188         }
1189         else {
1190             if (align && _align > 1) {
1191                 totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, _align);
1192             }
1193             PyTuple_SET_ITEM(tup, 1, PyLong_FromLong(totalsize));
1194             totalsize += newdescr->elsize;
1195         }
1196         if (len == 3) {
1197             PyTuple_SET_ITEM(tup, 2, title);
1198         }
1199         PyObject *name = PyObject_GetItem(names, ind);
1200         Py_DECREF(ind);
1201         if (!name) {
1202             Py_DECREF(tup);
1203             goto fail;
1204         }
1205         if (!PyUnicode_Check(name)) {
1206             PyErr_SetString(PyExc_ValueError,
1207                     "field names must be strings");
1208             Py_DECREF(tup);
1209             goto fail;
1210         }
1211 
1212         /* Insert into dictionary */
1213         if (PyDict_GetItemWithError(fields, name) != NULL) {
1214             PyErr_SetString(PyExc_ValueError,
1215                     "name already used as a name or title");
1216             Py_DECREF(tup);
1217             goto fail;
1218         }
1219         else if (PyErr_Occurred()) {
1220             /* MemoryError during dict lookup */
1221             Py_DECREF(tup);
1222             goto fail;
1223         }
1224         int ret = PyDict_SetItem(fields, name, tup);
1225         Py_DECREF(name);
1226         if (ret < 0) {
1227             Py_DECREF(tup);
1228             goto fail;
1229         }
1230         if (len == 3) {
1231             if (PyUnicode_Check(title)) {
1232                 if (PyDict_GetItemWithError(fields, title) != NULL) {
1233                     PyErr_SetString(PyExc_ValueError,
1234                             "title already used as a name or title.");
1235                     Py_DECREF(tup);
1236                     goto fail;
1237                 }
1238                 else if (PyErr_Occurred()) {
1239                     /* MemoryError during dict lookup */
1240                     goto fail;
1241                 }
1242                 if (PyDict_SetItem(fields, title, tup) < 0) {
1243                     Py_DECREF(tup);
1244                     goto fail;
1245                 }
1246             }
1247         }
1248         Py_DECREF(tup);
1249         dtypeflags |= (newdescr->flags & NPY_FROM_FIELDS);
1250     }
1251 
1252     PyArray_Descr *new = PyArray_DescrNewFromType(NPY_VOID);
1253     if (new == NULL) {
1254         goto fail;
1255     }
1256     if (maxalign > 1) {
1257         totalsize = NPY_NEXT_ALIGNED_OFFSET(totalsize, maxalign);
1258     }
1259     if (align) {
1260         new->alignment = maxalign;
1261     }
1262     new->elsize = totalsize;
1263     if (!PyTuple_Check(names)) {
1264         Py_SETREF(names, PySequence_Tuple(names));
1265         if (names == NULL) {
1266             Py_DECREF(new);
1267             goto fail;
1268         }
1269     }
1270     new->names = names;
1271     new->fields = fields;
1272     new->flags = dtypeflags;
1273     /* new takes responsibility for DECREFing names, fields */
1274     names = NULL;
1275     fields = NULL;
1276 
1277     /*
1278      * If the fields weren't in order, and there was an OBJECT type,
1279      * need to verify that no OBJECT types overlap with something else.
1280      */
1281     if (has_out_of_order_fields && PyDataType_REFCHK(new)) {
1282         if (_validate_object_field_overlap(new) < 0) {
1283             Py_DECREF(new);
1284             goto fail;
1285         }
1286     }
1287 
1288     /* Structured arrays get a sticky aligned bit */
1289     if (align) {
1290         new->flags |= NPY_ALIGNED_STRUCT;
1291     }
1292 
1293     /* Override the itemsize if provided */
1294     tmp = PyMapping_GetItemString(obj, "itemsize");
1295     if (tmp == NULL) {
1296         PyErr_Clear();
1297     } else {
1298         int itemsize = (int)PyArray_PyIntAsInt(tmp);
1299         Py_DECREF(tmp);
1300         if (error_converting(itemsize)) {
1301             Py_DECREF(new);
1302             goto fail;
1303         }
1304         /* Make sure the itemsize isn't made too small */
1305         if (itemsize < new->elsize) {
1306             PyErr_Format(PyExc_ValueError,
1307                     "NumPy dtype descriptor requires %d bytes, "
1308                     "cannot override to smaller itemsize of %d",
1309                     new->elsize, itemsize);
1310             Py_DECREF(new);
1311             goto fail;
1312         }
1313         /* If align is set, make sure the alignment divides into the size */
1314         if (align && itemsize % new->alignment != 0) {
1315             PyErr_Format(PyExc_ValueError,
1316                     "NumPy dtype descriptor requires alignment of %d bytes, "
1317                     "which is not divisible into the specified itemsize %d",
1318                     new->alignment, itemsize);
1319             Py_DECREF(new);
1320             goto fail;
1321         }
1322         /* Set the itemsize */
1323         new->elsize = itemsize;
1324     }
1325 
1326     /* Add the metadata if provided */
1327     PyObject *metadata = PyMapping_GetItemString(obj, "metadata");
1328 
1329     if (metadata == NULL) {
1330         PyErr_Clear();
1331     }
1332     else if (new->metadata == NULL) {
1333         new->metadata = metadata;
1334     }
1335     else {
1336         int ret = PyDict_Merge(new->metadata, metadata, 0);
1337         Py_DECREF(metadata);
1338         if (ret < 0) {
1339             Py_DECREF(new);
1340             goto fail;
1341         }
1342     }
1343 
1344     Py_XDECREF(fields);
1345     Py_XDECREF(names);
1346     Py_XDECREF(descrs);
1347     Py_XDECREF(offsets);
1348     Py_XDECREF(titles);
1349     return new;
1350 
1351  fail:
1352     Py_XDECREF(fields);
1353     Py_XDECREF(names);
1354     Py_XDECREF(descrs);
1355     Py_XDECREF(offsets);
1356     Py_XDECREF(titles);
1357     return NULL;
1358 }
1359 
1360 
1361 /*NUMPY_API*/
1362 NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrNewFromType(int type_num)1363 PyArray_DescrNewFromType(int type_num)
1364 {
1365     PyArray_Descr *old;
1366     PyArray_Descr *new;
1367 
1368     old = PyArray_DescrFromType(type_num);
1369     new = PyArray_DescrNew(old);
1370     Py_DECREF(old);
1371     return new;
1372 }
1373 
1374 /*NUMPY_API
1375  * Get typenum from an object -- None goes to NULL
1376  */
1377 NPY_NO_EXPORT int
PyArray_DescrConverter2(PyObject * obj,PyArray_Descr ** at)1378 PyArray_DescrConverter2(PyObject *obj, PyArray_Descr **at)
1379 {
1380     if (obj == Py_None) {
1381         *at = NULL;
1382         return NPY_SUCCEED;
1383     }
1384     else {
1385         return PyArray_DescrConverter(obj, at);
1386     }
1387 }
1388 
1389 /**
1390  * Get a dtype instance from a python type
1391  */
1392 static PyArray_Descr *
_convert_from_type(PyObject * obj)1393 _convert_from_type(PyObject *obj) {
1394     PyTypeObject *typ = (PyTypeObject*)obj;
1395 
1396     if (PyType_IsSubtype(typ, &PyGenericArrType_Type)) {
1397         return PyArray_DescrFromTypeObject(obj);
1398     }
1399     else if (typ == &PyLong_Type) {
1400         return PyArray_DescrFromType(NPY_LONG);
1401     }
1402     else if (typ == &PyFloat_Type) {
1403         return PyArray_DescrFromType(NPY_DOUBLE);
1404     }
1405     else if (typ == &PyComplex_Type) {
1406         return PyArray_DescrFromType(NPY_CDOUBLE);
1407     }
1408     else if (typ == &PyBool_Type) {
1409         return PyArray_DescrFromType(NPY_BOOL);
1410     }
1411     else if (typ == &PyBytes_Type) {
1412         /*
1413          * TODO: This should be deprecated, and have special handling for
1414          *       dtype=bytes/"S" in coercion: It should not rely on "S0".
1415          */
1416         return PyArray_DescrFromType(NPY_STRING);
1417     }
1418     else if (typ == &PyUnicode_Type) {
1419         /*
1420          * TODO: This should be deprecated, and have special handling for
1421          *       dtype=str/"U" in coercion: It should not rely on "U0".
1422          */
1423         return PyArray_DescrFromType(NPY_UNICODE);
1424     }
1425     else if (typ == &PyMemoryView_Type) {
1426         return PyArray_DescrFromType(NPY_VOID);
1427     }
1428     else if (typ == &PyBaseObject_Type) {
1429         return PyArray_DescrFromType(NPY_OBJECT);
1430     }
1431     else {
1432         PyArray_Descr *ret = _try_convert_from_dtype_attr(obj);
1433         if ((PyObject *)ret != Py_NotImplemented) {
1434             return ret;
1435         }
1436         Py_DECREF(ret);
1437 
1438         /*
1439          * Note: this comes after _try_convert_from_dtype_attr because the ctypes
1440          * type might override the dtype if numpy does not otherwise
1441          * support it.
1442          */
1443         ret = _try_convert_from_ctypes_type(typ);
1444         if ((PyObject *)ret != Py_NotImplemented) {
1445             return ret;
1446         }
1447         Py_DECREF(ret);
1448 
1449         /*
1450          * All other classes are treated as object. This can be convenient
1451          * to convey an intention of using it for a specific python type
1452          * and possibly allow converting to a new type-specific dtype in the future. It may make sense to
1453          * only allow this only within `dtype=...` keyword argument context
1454          * in the future.
1455          */
1456         return PyArray_DescrFromType(NPY_OBJECT);
1457     }
1458 }
1459 
1460 
1461 static PyArray_Descr *
1462 _convert_from_str(PyObject *obj, int align);
1463 
1464 static PyArray_Descr *
_convert_from_any(PyObject * obj,int align)1465 _convert_from_any(PyObject *obj, int align)
1466 {
1467     /* default */
1468     if (obj == Py_None) {
1469         return PyArray_DescrFromType(NPY_DEFAULT_TYPE);
1470     }
1471     else if (PyArray_DescrCheck(obj)) {
1472         PyArray_Descr *ret = (PyArray_Descr *)obj;
1473         Py_INCREF(ret);
1474         return ret;
1475     }
1476     else if (PyType_Check(obj)) {
1477         return _convert_from_type(obj);
1478     }
1479     /* or a typecode string */
1480     else if (PyBytes_Check(obj)) {
1481         /* Allow bytes format strings: convert to unicode */
1482         PyObject *obj2 = PyUnicode_FromEncodedObject(obj, NULL, NULL);
1483         if (obj2 == NULL) {
1484             /* Convert the exception into a TypeError */
1485             if (PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
1486                 PyErr_SetString(PyExc_TypeError,
1487                         "data type not understood");
1488             }
1489             return NULL;
1490         }
1491         PyArray_Descr *ret = _convert_from_str(obj2, align);
1492         Py_DECREF(obj2);
1493         return ret;
1494     }
1495     else if (PyUnicode_Check(obj)) {
1496         return _convert_from_str(obj, align);
1497     }
1498     else if (PyTuple_Check(obj)) {
1499         /* or a tuple */
1500         if (Py_EnterRecursiveCall(
1501                 " while trying to convert the given data type from"
1502                 " a tuple object" ) != 0) {
1503             return NULL;
1504         }
1505         PyArray_Descr *ret = _convert_from_tuple(obj, align);
1506         Py_LeaveRecursiveCall();
1507         return ret;
1508     }
1509     else if (PyList_Check(obj)) {
1510         /* or a list */
1511         if (Py_EnterRecursiveCall(
1512                 " while trying to convert the given data type from"
1513                 " a list object" ) != 0) {
1514             return NULL;
1515         }
1516         PyArray_Descr *ret = _convert_from_array_descr(obj, align);
1517         Py_LeaveRecursiveCall();
1518         return ret;
1519     }
1520     else if (PyDict_Check(obj) || PyDictProxy_Check(obj)) {
1521         /* or a dictionary */
1522         if (Py_EnterRecursiveCall(
1523                 " while trying to convert the given data type from"
1524                 " a dict object" ) != 0) {
1525             return NULL;
1526         }
1527         PyArray_Descr *ret = _convert_from_dict(obj, align);
1528         Py_LeaveRecursiveCall();
1529         return ret;
1530     }
1531     else if (PyArray_Check(obj)) {
1532         PyErr_SetString(PyExc_TypeError, "Cannot construct a dtype from an array");
1533         return NULL;
1534     }
1535     else {
1536         PyArray_Descr *ret = _try_convert_from_dtype_attr(obj);
1537         if ((PyObject *)ret != Py_NotImplemented) {
1538             return ret;
1539         }
1540         Py_DECREF(ret);
1541         /*
1542          * Note: this comes after _try_convert_from_dtype_attr because the ctypes
1543          * type might override the dtype if numpy does not otherwise
1544          * support it.
1545          */
1546         ret = _try_convert_from_ctypes_type(Py_TYPE(obj));
1547         if ((PyObject *)ret != Py_NotImplemented) {
1548             return ret;
1549         }
1550         Py_DECREF(ret);
1551         PyErr_Format(PyExc_TypeError, "Cannot interpret '%R' as a data type", obj);
1552         return NULL;
1553     }
1554 }
1555 
1556 
1557 /*NUMPY_API
1558  * Get typenum from an object -- None goes to NPY_DEFAULT_TYPE
1559  * This function takes a Python object representing a type and converts it
1560  * to a the correct PyArray_Descr * structure to describe the type.
1561  *
1562  * Many objects can be used to represent a data-type which in NumPy is
1563  * quite a flexible concept.
1564  *
1565  * This is the central code that converts Python objects to
1566  * Type-descriptor objects that are used throughout numpy.
1567  *
1568  * Returns a new reference in *at, but the returned should not be
1569  * modified as it may be one of the canonical immutable objects or
1570  * a reference to the input obj.
1571  */
1572 NPY_NO_EXPORT int
PyArray_DescrConverter(PyObject * obj,PyArray_Descr ** at)1573 PyArray_DescrConverter(PyObject *obj, PyArray_Descr **at)
1574 {
1575     *at = _convert_from_any(obj, 0);
1576     return (*at) ? NPY_SUCCEED : NPY_FAIL;
1577 }
1578 
1579 /** Convert a bytestring specification into a dtype */
1580 static PyArray_Descr *
_convert_from_str(PyObject * obj,int align)1581 _convert_from_str(PyObject *obj, int align)
1582 {
1583     /* Check for a string typecode. */
1584     Py_ssize_t len = 0;
1585     char const *type = PyUnicode_AsUTF8AndSize(obj, &len);
1586     if (type == NULL) {
1587         return NULL;
1588     }
1589 
1590     /* Empty string is invalid */
1591     if (len == 0) {
1592         goto fail;
1593     }
1594 
1595     /* check for commas present or first (or second) element a digit */
1596     if (_check_for_commastring(type, len)) {
1597         return _convert_from_commastring(obj, align);
1598     }
1599 
1600     /* Process the endian character. '|' is replaced by '='*/
1601     char endian = '=';
1602     switch (type[0]) {
1603         case '>':
1604         case '<':
1605         case '=':
1606             endian = type[0];
1607             ++type;
1608             --len;
1609             break;
1610 
1611         case '|':
1612             endian = '=';
1613             ++type;
1614             --len;
1615             break;
1616     }
1617 
1618     /* Just an endian character is invalid */
1619     if (len == 0) {
1620         goto fail;
1621     }
1622 
1623     /* Check for datetime format */
1624     if (is_datetime_typestr(type, len)) {
1625         PyArray_Descr *ret = parse_dtype_from_datetime_typestr(type, len);
1626         if (ret == NULL) {
1627             return NULL;
1628         }
1629         /* ret has byte order '=' at this point */
1630         if (!PyArray_ISNBO(endian)) {
1631             ret->byteorder = endian;
1632         }
1633         return ret;
1634     }
1635 
1636     int check_num = NPY_NOTYPE + 10;
1637     int elsize = 0;
1638     /* A typecode like 'd' */
1639     if (len == 1) {
1640         /* Python byte string characters are unsigned */
1641         check_num = (unsigned char) type[0];
1642     }
1643     /* A kind + size like 'f8' */
1644     else {
1645         char *typeend = NULL;
1646         int kind;
1647 
1648         /* Parse the integer, make sure it's the rest of the string */
1649         elsize = (int)strtol(type + 1, &typeend, 10);
1650         if (typeend - type == len) {
1651 
1652             kind = type[0];
1653             switch (kind) {
1654                 case NPY_STRINGLTR:
1655                 case NPY_STRINGLTR2:
1656                     check_num = NPY_STRING;
1657                     break;
1658 
1659                 /*
1660                  * When specifying length of UNICODE
1661                  * the number of characters is given to match
1662                  * the STRING interface.  Each character can be
1663                  * more than one byte and itemsize must be
1664                  * the number of bytes.
1665                  */
1666                 case NPY_UNICODELTR:
1667                     check_num = NPY_UNICODE;
1668                     elsize <<= 2;
1669                     break;
1670 
1671                 case NPY_VOIDLTR:
1672                     check_num = NPY_VOID;
1673                     break;
1674 
1675                 default:
1676                     if (elsize == 0) {
1677                         check_num = NPY_NOTYPE+10;
1678                     }
1679                     /* Support for generic processing c8, i4, f8, etc...*/
1680                     else {
1681                         check_num = PyArray_TypestrConvert(elsize, kind);
1682                         if (check_num == NPY_NOTYPE) {
1683                             check_num += 10;
1684                         }
1685                         elsize = 0;
1686                     }
1687             }
1688         }
1689     }
1690 
1691     if (PyErr_Occurred()) {
1692         goto fail;
1693     }
1694 
1695     PyArray_Descr *ret;
1696     if ((check_num == NPY_NOTYPE + 10) ||
1697             (ret = PyArray_DescrFromType(check_num)) == NULL) {
1698         PyErr_Clear();
1699         /* Now check to see if the object is registered in typeDict */
1700         if (typeDict == NULL) {
1701             goto fail;
1702         }
1703         PyObject *item = PyDict_GetItemWithError(typeDict, obj);
1704         if (item == NULL) {
1705             if (PyErr_Occurred()) {
1706                 return NULL;
1707             }
1708             goto fail;
1709         }
1710 
1711         /* Check for a deprecated Numeric-style typecode */
1712         /* `Uint` has deliberately weird uppercasing */
1713         char *dep_tps[] = {"Bytes", "Datetime64", "Str", "Uint"};
1714         int ndep_tps = sizeof(dep_tps) / sizeof(dep_tps[0]);
1715         for (int i = 0; i < ndep_tps; ++i) {
1716             char *dep_tp = dep_tps[i];
1717 
1718             if (strncmp(type, dep_tp, strlen(dep_tp)) == 0) {
1719                 /* Deprecated 2020-06-09, NumPy 1.20 */
1720                 if (DEPRECATE("Numeric-style type codes are "
1721                               "deprecated and will result in "
1722                               "an error in the future.") < 0) {
1723                     goto fail;
1724                 }
1725             }
1726         }
1727         /*
1728          * Probably only ever dispatches to `_convert_from_type`, but who
1729          * knows what users are injecting into `np.typeDict`.
1730          */
1731         return _convert_from_any(item, align);
1732     }
1733 
1734     if (PyDataType_ISUNSIZED(ret) && ret->elsize != elsize) {
1735         PyArray_DESCR_REPLACE(ret);
1736         if (ret == NULL) {
1737             return NULL;
1738         }
1739         ret->elsize = elsize;
1740     }
1741     if (endian != '=' && PyArray_ISNBO(endian)) {
1742         endian = '=';
1743     }
1744     if (endian != '=' && ret->byteorder != '|' && ret->byteorder != endian) {
1745         PyArray_DESCR_REPLACE(ret);
1746         if (ret == NULL) {
1747             return NULL;
1748         }
1749         ret->byteorder = endian;
1750     }
1751     return ret;
1752 
1753 fail:
1754     PyErr_Format(PyExc_TypeError, "data type %R not understood", obj);
1755     return NULL;
1756 }
1757 
1758 /** Array Descr Objects for dynamic types **/
1759 
1760 /*
1761  * There are some statically-defined PyArray_Descr objects corresponding
1762  * to the basic built-in types.
1763  * These can and should be DECREF'd and INCREF'd as appropriate, anyway.
1764  * If a mistake is made in reference counting, deallocation on these
1765  * builtins will be attempted leading to problems.
1766  *
1767  * This lets us deal with all PyArray_Descr objects using reference
1768  * counting (regardless of whether they are statically or dynamically
1769  * allocated).
1770  */
1771 
1772 /*NUMPY_API
1773  * base cannot be NULL
1774  */
1775 NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrNew(PyArray_Descr * base)1776 PyArray_DescrNew(PyArray_Descr *base)
1777 {
1778     PyArray_Descr *newdescr = PyObject_New(PyArray_Descr, Py_TYPE(base));
1779 
1780     if (newdescr == NULL) {
1781         return NULL;
1782     }
1783     /* Don't copy PyObject_HEAD part */
1784     memcpy((char *)newdescr + sizeof(PyObject),
1785            (char *)base + sizeof(PyObject),
1786            sizeof(PyArray_Descr) - sizeof(PyObject));
1787 
1788     /*
1789      * The c_metadata has a by-value ownership model, need to clone it
1790      * (basically a deep copy, but the auxdata clone function has some
1791      * flexibility still) so the new PyArray_Descr object owns
1792      * a copy of the data. Having both 'base' and 'newdescr' point to
1793      * the same auxdata pointer would cause a double-free of memory.
1794      */
1795     if (base->c_metadata != NULL) {
1796         newdescr->c_metadata = NPY_AUXDATA_CLONE(base->c_metadata);
1797         if (newdescr->c_metadata == NULL) {
1798             PyErr_NoMemory();
1799             /* TODO: This seems wrong, as the old fields get decref'd? */
1800             Py_DECREF(newdescr);
1801             return NULL;
1802         }
1803     }
1804 
1805     if (newdescr->fields == Py_None) {
1806         newdescr->fields = NULL;
1807     }
1808     Py_XINCREF(newdescr->fields);
1809     Py_XINCREF(newdescr->names);
1810     if (newdescr->subarray) {
1811         newdescr->subarray = PyArray_malloc(sizeof(PyArray_ArrayDescr));
1812         if (newdescr->subarray == NULL) {
1813             Py_DECREF(newdescr);
1814             return (PyArray_Descr *)PyErr_NoMemory();
1815         }
1816         memcpy(newdescr->subarray, base->subarray, sizeof(PyArray_ArrayDescr));
1817         Py_INCREF(newdescr->subarray->shape);
1818         Py_INCREF(newdescr->subarray->base);
1819     }
1820     Py_XINCREF(newdescr->typeobj);
1821     Py_XINCREF(newdescr->metadata);
1822     newdescr->hash = -1;
1823 
1824     return newdescr;
1825 }
1826 
1827 /*
1828  * should never be called for builtin-types unless
1829  * there is a reference-count problem
1830  */
1831 static void
arraydescr_dealloc(PyArray_Descr * self)1832 arraydescr_dealloc(PyArray_Descr *self)
1833 {
1834     if (self->fields == Py_None) {
1835         fprintf(stderr, "*** Reference count error detected: "
1836                 "an attempt was made to deallocate the dtype %d (%c) ***\n",
1837                 self->type_num, self->type);
1838         assert(0);
1839         Py_INCREF(self);
1840         Py_INCREF(self);
1841         return;
1842     }
1843     Py_XDECREF(self->typeobj);
1844     Py_XDECREF(self->names);
1845     Py_XDECREF(self->fields);
1846     if (self->subarray) {
1847         Py_XDECREF(self->subarray->shape);
1848         Py_DECREF(self->subarray->base);
1849         PyArray_free(self->subarray);
1850     }
1851     Py_XDECREF(self->metadata);
1852     NPY_AUXDATA_FREE(self->c_metadata);
1853     self->c_metadata = NULL;
1854     Py_TYPE(self)->tp_free((PyObject *)self);
1855 }
1856 
1857 /*
1858  * we need to be careful about setting attributes because these
1859  * objects are pointed to by arrays that depend on them for interpreting
1860  * data.  Currently no attributes of data-type objects can be set
1861  * directly except names.
1862  */
1863 static PyMemberDef arraydescr_members[] = {
1864     {"type",
1865         T_OBJECT, offsetof(PyArray_Descr, typeobj), READONLY, NULL},
1866     {"kind",
1867         T_CHAR, offsetof(PyArray_Descr, kind), READONLY, NULL},
1868     {"char",
1869         T_CHAR, offsetof(PyArray_Descr, type), READONLY, NULL},
1870     {"num",
1871         T_INT, offsetof(PyArray_Descr, type_num), READONLY, NULL},
1872     {"byteorder",
1873         T_CHAR, offsetof(PyArray_Descr, byteorder), READONLY, NULL},
1874     {"itemsize",
1875         T_INT, offsetof(PyArray_Descr, elsize), READONLY, NULL},
1876     {"alignment",
1877         T_INT, offsetof(PyArray_Descr, alignment), READONLY, NULL},
1878     {"flags",
1879         T_BYTE, offsetof(PyArray_Descr, flags), READONLY, NULL},
1880     {NULL, 0, 0, 0, NULL},
1881 };
1882 
1883 static PyObject *
arraydescr_subdescr_get(PyArray_Descr * self)1884 arraydescr_subdescr_get(PyArray_Descr *self)
1885 {
1886     if (!PyDataType_HASSUBARRAY(self)) {
1887         Py_RETURN_NONE;
1888     }
1889     return Py_BuildValue("OO",
1890             (PyObject *)self->subarray->base, self->subarray->shape);
1891 }
1892 
1893 NPY_NO_EXPORT PyObject *
arraydescr_protocol_typestr_get(PyArray_Descr * self)1894 arraydescr_protocol_typestr_get(PyArray_Descr *self)
1895 {
1896     char basic_ = self->kind;
1897     char endian = self->byteorder;
1898     int size = self->elsize;
1899     PyObject *ret;
1900 
1901     if (endian == '=') {
1902         endian = '<';
1903         if (!PyArray_IsNativeByteOrder(endian)) {
1904             endian = '>';
1905         }
1906     }
1907     if (self->type_num == NPY_UNICODE) {
1908         size >>= 2;
1909     }
1910     if (self->type_num == NPY_OBJECT) {
1911         ret = PyUnicode_FromFormat("%c%c", endian, basic_);
1912     }
1913     else {
1914         ret = PyUnicode_FromFormat("%c%c%d", endian, basic_, size);
1915     }
1916     if (ret == NULL) {
1917         return NULL;
1918     }
1919 
1920     if (PyDataType_ISDATETIME(self)) {
1921         PyArray_DatetimeMetaData *meta;
1922         meta = get_datetime_metadata_from_dtype(self);
1923         if (meta == NULL) {
1924             Py_DECREF(ret);
1925             return NULL;
1926         }
1927         PyObject *umeta = metastr_to_unicode(meta, 0);
1928         if (umeta == NULL) {
1929             Py_DECREF(ret);
1930             return NULL;
1931         }
1932 
1933         Py_SETREF(ret, PyUnicode_Concat(ret, umeta));
1934         Py_DECREF(umeta);
1935     }
1936     return ret;
1937 }
1938 
1939 static PyObject *
arraydescr_name_get(PyArray_Descr * self)1940 arraydescr_name_get(PyArray_Descr *self)
1941 {
1942     /* let python handle this */
1943     PyObject *_numpy_dtype;
1944     PyObject *res;
1945     _numpy_dtype = PyImport_ImportModule("numpy.core._dtype");
1946     if (_numpy_dtype == NULL) {
1947         return NULL;
1948     }
1949     res = PyObject_CallMethod(_numpy_dtype, "_name_get", "O", self);
1950     Py_DECREF(_numpy_dtype);
1951     return res;
1952 }
1953 
1954 static PyObject *
arraydescr_base_get(PyArray_Descr * self)1955 arraydescr_base_get(PyArray_Descr *self)
1956 {
1957     if (!PyDataType_HASSUBARRAY(self)) {
1958         Py_INCREF(self);
1959         return (PyObject *)self;
1960     }
1961     Py_INCREF(self->subarray->base);
1962     return (PyObject *)(self->subarray->base);
1963 }
1964 
1965 static PyObject *
arraydescr_shape_get(PyArray_Descr * self)1966 arraydescr_shape_get(PyArray_Descr *self)
1967 {
1968     if (!PyDataType_HASSUBARRAY(self)) {
1969         return PyTuple_New(0);
1970     }
1971     assert(PyTuple_Check(self->subarray->shape));
1972     Py_INCREF(self->subarray->shape);
1973     return self->subarray->shape;
1974 }
1975 
1976 static PyObject *
arraydescr_ndim_get(PyArray_Descr * self)1977 arraydescr_ndim_get(PyArray_Descr *self)
1978 {
1979     Py_ssize_t ndim;
1980 
1981     if (!PyDataType_HASSUBARRAY(self)) {
1982         return PyLong_FromLong(0);
1983     }
1984 
1985     /*
1986      * PyTuple_Size has built in check
1987      * for tuple argument
1988      */
1989     ndim = PyTuple_Size(self->subarray->shape);
1990     return PyLong_FromLong(ndim);
1991 }
1992 
1993 
1994 NPY_NO_EXPORT PyObject *
arraydescr_protocol_descr_get(PyArray_Descr * self)1995 arraydescr_protocol_descr_get(PyArray_Descr *self)
1996 {
1997     PyObject *dobj, *res;
1998     PyObject *_numpy_internal;
1999 
2000     if (!PyDataType_HASFIELDS(self)) {
2001         /* get default */
2002         dobj = PyTuple_New(2);
2003         if (dobj == NULL) {
2004             return NULL;
2005         }
2006         PyTuple_SET_ITEM(dobj, 0, PyUnicode_FromString(""));
2007         PyTuple_SET_ITEM(dobj, 1, arraydescr_protocol_typestr_get(self));
2008         res = PyList_New(1);
2009         if (res == NULL) {
2010             Py_DECREF(dobj);
2011             return NULL;
2012         }
2013         PyList_SET_ITEM(res, 0, dobj);
2014         return res;
2015     }
2016 
2017     _numpy_internal = PyImport_ImportModule("numpy.core._internal");
2018     if (_numpy_internal == NULL) {
2019         return NULL;
2020     }
2021     res = PyObject_CallMethod(_numpy_internal, "_array_descr", "O", self);
2022     Py_DECREF(_numpy_internal);
2023     return res;
2024 }
2025 
2026 /*
2027  * returns 1 for a builtin type
2028  * and 2 for a user-defined data-type descriptor
2029  * return 0 if neither (i.e. it's a copy of one)
2030  */
2031 static PyObject *
arraydescr_isbuiltin_get(PyArray_Descr * self)2032 arraydescr_isbuiltin_get(PyArray_Descr *self)
2033 {
2034     long val;
2035     val = 0;
2036     if (self->fields == Py_None) {
2037         val = 1;
2038     }
2039     if (PyTypeNum_ISUSERDEF(self->type_num)) {
2040         val = 2;
2041     }
2042     return PyLong_FromLong(val);
2043 }
2044 
2045 static int
_arraydescr_isnative(PyArray_Descr * self)2046 _arraydescr_isnative(PyArray_Descr *self)
2047 {
2048     if (!PyDataType_HASFIELDS(self)) {
2049         return PyArray_ISNBO(self->byteorder);
2050     }
2051     else {
2052         PyObject *key, *value, *title = NULL;
2053         PyArray_Descr *new;
2054         int offset;
2055         Py_ssize_t pos = 0;
2056         while (PyDict_Next(self->fields, &pos, &key, &value)) {
2057             if (NPY_TITLE_KEY(key, value)) {
2058                 continue;
2059             }
2060             if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) {
2061                 return -1;
2062             }
2063             if (!_arraydescr_isnative(new)) {
2064                 return 0;
2065             }
2066         }
2067     }
2068     return 1;
2069 }
2070 
2071 /*
2072  * return Py_True if this data-type descriptor
2073  * has native byteorder if no fields are defined
2074  *
2075  * or if all sub-fields have native-byteorder if
2076  * fields are defined
2077  */
2078 static PyObject *
arraydescr_isnative_get(PyArray_Descr * self)2079 arraydescr_isnative_get(PyArray_Descr *self)
2080 {
2081     PyObject *ret;
2082     int retval;
2083     retval = _arraydescr_isnative(self);
2084     if (retval == -1) {
2085         return NULL;
2086     }
2087     ret = retval ? Py_True : Py_False;
2088     Py_INCREF(ret);
2089     return ret;
2090 }
2091 
2092 static PyObject *
arraydescr_isalignedstruct_get(PyArray_Descr * self)2093 arraydescr_isalignedstruct_get(PyArray_Descr *self)
2094 {
2095     PyObject *ret;
2096     ret = (self->flags&NPY_ALIGNED_STRUCT) ? Py_True : Py_False;
2097     Py_INCREF(ret);
2098     return ret;
2099 }
2100 
2101 static PyObject *
arraydescr_fields_get(PyArray_Descr * self)2102 arraydescr_fields_get(PyArray_Descr *self)
2103 {
2104     if (!PyDataType_HASFIELDS(self)) {
2105         Py_RETURN_NONE;
2106     }
2107     return PyDictProxy_New(self->fields);
2108 }
2109 
2110 static PyObject *
arraydescr_metadata_get(PyArray_Descr * self)2111 arraydescr_metadata_get(PyArray_Descr *self)
2112 {
2113     if (self->metadata == NULL) {
2114         Py_RETURN_NONE;
2115     }
2116     return PyDictProxy_New(self->metadata);
2117 }
2118 
2119 static PyObject *
arraydescr_hasobject_get(PyArray_Descr * self)2120 arraydescr_hasobject_get(PyArray_Descr *self)
2121 {
2122     if (PyDataType_FLAGCHK(self, NPY_ITEM_HASOBJECT)) {
2123         Py_RETURN_TRUE;
2124     }
2125     else {
2126         Py_RETURN_FALSE;
2127     }
2128 }
2129 
2130 static PyObject *
arraydescr_names_get(PyArray_Descr * self)2131 arraydescr_names_get(PyArray_Descr *self)
2132 {
2133     if (!PyDataType_HASFIELDS(self)) {
2134         Py_RETURN_NONE;
2135     }
2136     Py_INCREF(self->names);
2137     return self->names;
2138 }
2139 
2140 static int
arraydescr_names_set(PyArray_Descr * self,PyObject * val)2141 arraydescr_names_set(PyArray_Descr *self, PyObject *val)
2142 {
2143     int N = 0;
2144     int i;
2145     PyObject *new_names;
2146     PyObject *new_fields;
2147 
2148     if (val == NULL) {
2149         PyErr_SetString(PyExc_AttributeError,
2150                 "Cannot delete dtype names attribute");
2151         return -1;
2152     }
2153     if (!PyDataType_HASFIELDS(self)) {
2154         PyErr_SetString(PyExc_ValueError,
2155                 "there are no fields defined");
2156         return -1;
2157     }
2158 
2159     /*
2160      * FIXME
2161      *
2162      * This deprecation has been temporarily removed for the NumPy 1.7
2163      * release. It should be re-added after the 1.7 branch is done,
2164      * and a convenience API to replace the typical use-cases for
2165      * mutable names should be implemented.
2166      *
2167      * if (DEPRECATE("Setting NumPy dtype names is deprecated, the dtype "
2168      *                "will become immutable in a future version") < 0) {
2169      *     return -1;
2170      * }
2171      */
2172 
2173     N = PyTuple_GET_SIZE(self->names);
2174     if (!PySequence_Check(val) || PyObject_Size((PyObject *)val) != N) {
2175         PyErr_Format(PyExc_ValueError,
2176                 "must replace all names at once with a sequence of length %d",
2177                 N);
2178         return -1;
2179     }
2180     /* Make sure all entries are strings */
2181     for (i = 0; i < N; i++) {
2182         PyObject *item;
2183         int valid = 1;
2184         item = PySequence_GetItem(val, i);
2185         valid = PyUnicode_Check(item);
2186         Py_DECREF(item);
2187         if (!valid) {
2188             PyErr_Format(PyExc_ValueError,
2189                     "item #%d of names is of type %s and not string",
2190                     i, Py_TYPE(item)->tp_name);
2191             return -1;
2192         }
2193     }
2194     /* Invalidate cached hash value */
2195     self->hash = -1;
2196     /* Update dictionary keys in fields */
2197     new_names = PySequence_Tuple(val);
2198     if (new_names == NULL) {
2199         return -1;
2200     }
2201     new_fields = PyDict_New();
2202     if (new_fields == NULL) {
2203         Py_DECREF(new_names);
2204         return -1;
2205     }
2206     for (i = 0; i < N; i++) {
2207         PyObject *key;
2208         PyObject *item;
2209         PyObject *new_key;
2210         int ret;
2211         key = PyTuple_GET_ITEM(self->names, i);
2212         /* Borrowed references to item and new_key */
2213         item = PyDict_GetItemWithError(self->fields, key);
2214         if (item == NULL) {
2215             if (!PyErr_Occurred()) {
2216                 /* fields was missing the name it claimed to contain */
2217                 PyErr_BadInternalCall();
2218             }
2219             Py_DECREF(new_names);
2220             Py_DECREF(new_fields);
2221             return -1;
2222         }
2223         new_key = PyTuple_GET_ITEM(new_names, i);
2224         /* Check for duplicates */
2225         ret = PyDict_Contains(new_fields, new_key);
2226         if (ret < 0) {
2227             Py_DECREF(new_names);
2228             Py_DECREF(new_fields);
2229             return -1;
2230         }
2231         else if (ret != 0) {
2232             PyErr_SetString(PyExc_ValueError, "Duplicate field names given.");
2233             Py_DECREF(new_names);
2234             Py_DECREF(new_fields);
2235             return -1;
2236         }
2237         if (PyDict_SetItem(new_fields, new_key, item) < 0) {
2238             Py_DECREF(new_names);
2239             Py_DECREF(new_fields);
2240             return -1;
2241         }
2242     }
2243 
2244     /* Replace names */
2245     Py_DECREF(self->names);
2246     self->names = new_names;
2247 
2248     /* Replace fields */
2249     Py_DECREF(self->fields);
2250     self->fields = new_fields;
2251 
2252     return 0;
2253 }
2254 
2255 static PyGetSetDef arraydescr_getsets[] = {
2256     {"subdtype",
2257         (getter)arraydescr_subdescr_get,
2258         NULL, NULL, NULL},
2259     {"descr",
2260         (getter)arraydescr_protocol_descr_get,
2261         NULL, NULL, NULL},
2262     {"str",
2263         (getter)arraydescr_protocol_typestr_get,
2264         NULL, NULL, NULL},
2265     {"name",
2266         (getter)arraydescr_name_get,
2267         NULL, NULL, NULL},
2268     {"base",
2269         (getter)arraydescr_base_get,
2270         NULL, NULL, NULL},
2271     {"shape",
2272         (getter)arraydescr_shape_get,
2273         NULL, NULL, NULL},
2274     {"ndim",
2275         (getter)arraydescr_ndim_get,
2276         NULL, NULL, NULL},
2277     {"isbuiltin",
2278         (getter)arraydescr_isbuiltin_get,
2279         NULL, NULL, NULL},
2280     {"isnative",
2281         (getter)arraydescr_isnative_get,
2282         NULL, NULL, NULL},
2283     {"isalignedstruct",
2284         (getter)arraydescr_isalignedstruct_get,
2285         NULL, NULL, NULL},
2286     {"fields",
2287         (getter)arraydescr_fields_get,
2288         NULL, NULL, NULL},
2289     {"metadata",
2290         (getter)arraydescr_metadata_get,
2291         NULL, NULL, NULL},
2292     {"names",
2293         (getter)arraydescr_names_get,
2294         (setter)arraydescr_names_set,
2295         NULL, NULL},
2296     {"hasobject",
2297         (getter)arraydescr_hasobject_get,
2298         NULL, NULL, NULL},
2299     {NULL, NULL, NULL, NULL, NULL},
2300 };
2301 
2302 static PyObject *
arraydescr_new(PyTypeObject * subtype,PyObject * args,PyObject * kwds)2303 arraydescr_new(PyTypeObject *subtype,
2304                 PyObject *args, PyObject *kwds)
2305 {
2306     if (subtype != &PyArrayDescr_Type) {
2307         /* The DTypeMeta class should prevent this from happening. */
2308         PyErr_Format(PyExc_SystemError,
2309                 "'%S' must not inherit np.dtype.__new__().", subtype);
2310         return NULL;
2311     }
2312 
2313     PyObject *odescr, *metadata=NULL;
2314     PyArray_Descr *descr, *conv;
2315     npy_bool align = NPY_FALSE;
2316     npy_bool copy = NPY_FALSE;
2317     npy_bool copied = NPY_FALSE;
2318 
2319     static char *kwlist[] = {"dtype", "align", "copy", "metadata", NULL};
2320 
2321     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&O&O!:dtype", kwlist,
2322                 &odescr,
2323                 PyArray_BoolConverter, &align,
2324                 PyArray_BoolConverter, &copy,
2325                 &PyDict_Type, &metadata)) {
2326         return NULL;
2327     }
2328 
2329     conv = _convert_from_any(odescr, align);
2330     if (conv == NULL) {
2331         return NULL;
2332     }
2333 
2334     /* Get a new copy of it unless it's already a copy */
2335     if (copy && conv->fields == Py_None) {
2336         descr = PyArray_DescrNew(conv);
2337         Py_DECREF(conv);
2338         conv = descr;
2339         copied = NPY_TRUE;
2340     }
2341 
2342     if ((metadata != NULL)) {
2343         /*
2344          * We need to be sure to make a new copy of the data-type and any
2345          * underlying dictionary
2346          */
2347         if (!copied) {
2348             copied = NPY_TRUE;
2349             descr = PyArray_DescrNew(conv);
2350             Py_DECREF(conv);
2351             conv = descr;
2352         }
2353         if ((conv->metadata != NULL)) {
2354             /*
2355              * Make a copy of the metadata before merging with the
2356              * input metadata so that this data-type descriptor has
2357              * it's own copy
2358              */
2359             /* Save a reference */
2360             odescr = conv->metadata;
2361             conv->metadata = PyDict_Copy(odescr);
2362             /* Decrement the old reference */
2363             Py_DECREF(odescr);
2364 
2365             /*
2366              * Update conv->metadata with anything new in metadata
2367              * keyword, but do not over-write anything already there
2368              */
2369             if (PyDict_Merge(conv->metadata, metadata, 0) != 0) {
2370                 Py_DECREF(conv);
2371                 return NULL;
2372             }
2373         }
2374         else {
2375             /* Make a copy of the input dictionary */
2376             conv->metadata = PyDict_Copy(metadata);
2377         }
2378     }
2379 
2380     return (PyObject *)conv;
2381 }
2382 
2383 
2384 /*
2385  * Return a tuple of
2386  * (cleaned metadata dictionary, tuple with (str, num))
2387  */
2388 static PyObject *
_get_pickleabletype_from_datetime_metadata(PyArray_Descr * dtype)2389 _get_pickleabletype_from_datetime_metadata(PyArray_Descr *dtype)
2390 {
2391     PyObject *ret, *dt_tuple;
2392     PyArray_DatetimeMetaData *meta;
2393 
2394     /* Create the 2-item tuple to return */
2395     ret = PyTuple_New(2);
2396     if (ret == NULL) {
2397         return NULL;
2398     }
2399 
2400     /* Store the metadata dictionary */
2401     if (dtype->metadata != NULL) {
2402         Py_INCREF(dtype->metadata);
2403         PyTuple_SET_ITEM(ret, 0, dtype->metadata);
2404     } else {
2405         PyTuple_SET_ITEM(ret, 0, PyDict_New());
2406     }
2407 
2408     /* Convert the datetime metadata into a tuple */
2409     meta = get_datetime_metadata_from_dtype(dtype);
2410     if (meta == NULL) {
2411         Py_DECREF(ret);
2412         return NULL;
2413     }
2414     /* Use a 4-tuple that numpy 1.6 knows how to unpickle */
2415     dt_tuple = PyTuple_New(4);
2416     if (dt_tuple == NULL) {
2417         Py_DECREF(ret);
2418         return NULL;
2419     }
2420     PyTuple_SET_ITEM(dt_tuple, 0,
2421             PyBytes_FromString(_datetime_strings[meta->base]));
2422     PyTuple_SET_ITEM(dt_tuple, 1,
2423             PyLong_FromLong(meta->num));
2424     PyTuple_SET_ITEM(dt_tuple, 2,
2425             PyLong_FromLong(1));
2426     PyTuple_SET_ITEM(dt_tuple, 3,
2427             PyLong_FromLong(1));
2428 
2429     PyTuple_SET_ITEM(ret, 1, dt_tuple);
2430 
2431     return ret;
2432 }
2433 
2434 /*
2435  * return a tuple of (callable object, args, state).
2436  *
2437  * TODO: This method needs to change so that unpickling doesn't
2438  *       use __setstate__. This is required for the dtype
2439  *       to be an immutable object.
2440  */
2441 static PyObject *
arraydescr_reduce(PyArray_Descr * self,PyObject * NPY_UNUSED (args))2442 arraydescr_reduce(PyArray_Descr *self, PyObject *NPY_UNUSED(args))
2443 {
2444     /*
2445      * version number of this pickle type. Increment if we need to
2446      * change the format. Be sure to handle the old versions in
2447      * arraydescr_setstate.
2448     */
2449     const int version = 4;
2450     PyObject *ret, *mod, *obj;
2451     PyObject *state;
2452     char endian;
2453     int elsize, alignment;
2454 
2455     ret = PyTuple_New(3);
2456     if (ret == NULL) {
2457         return NULL;
2458     }
2459     mod = PyImport_ImportModule("numpy.core._multiarray_umath");
2460     if (mod == NULL) {
2461         Py_DECREF(ret);
2462         return NULL;
2463     }
2464     obj = PyObject_GetAttrString(mod, "dtype");
2465     Py_DECREF(mod);
2466     if (obj == NULL) {
2467         Py_DECREF(ret);
2468         return NULL;
2469     }
2470     PyTuple_SET_ITEM(ret, 0, obj);
2471     if (PyTypeNum_ISUSERDEF(self->type_num)
2472             || ((self->type_num == NPY_VOID
2473                     && self->typeobj != &PyVoidArrType_Type))) {
2474         obj = (PyObject *)self->typeobj;
2475         Py_INCREF(obj);
2476     }
2477     else {
2478         elsize = self->elsize;
2479         if (self->type_num == NPY_UNICODE) {
2480             elsize >>= 2;
2481         }
2482         obj = PyUnicode_FromFormat("%c%d",self->kind, elsize);
2483     }
2484     PyTuple_SET_ITEM(ret, 1, Py_BuildValue("(NOO)", obj, Py_False, Py_True));
2485 
2486     /*
2487      * Now return the state which is at least byteorder,
2488      * subarray, and fields
2489      */
2490     endian = self->byteorder;
2491     if (endian == '=') {
2492         endian = '<';
2493         if (!PyArray_IsNativeByteOrder(endian)) {
2494             endian = '>';
2495         }
2496     }
2497     if (PyDataType_ISDATETIME(self)) {
2498         PyObject *newobj;
2499         state = PyTuple_New(9);
2500         PyTuple_SET_ITEM(state, 0, PyLong_FromLong(version));
2501         /*
2502          * newobj is a tuple of the Python metadata dictionary
2503          * and tuple of date_time info (str, num)
2504          */
2505         newobj = _get_pickleabletype_from_datetime_metadata(self);
2506         if (newobj == NULL) {
2507             Py_DECREF(state);
2508             Py_DECREF(ret);
2509             return NULL;
2510         }
2511         PyTuple_SET_ITEM(state, 8, newobj);
2512     }
2513     else if (self->metadata) {
2514         state = PyTuple_New(9);
2515         PyTuple_SET_ITEM(state, 0, PyLong_FromLong(version));
2516         Py_INCREF(self->metadata);
2517         PyTuple_SET_ITEM(state, 8, self->metadata);
2518     }
2519     else { /* Use version 3 pickle format */
2520         state = PyTuple_New(8);
2521         PyTuple_SET_ITEM(state, 0, PyLong_FromLong(3));
2522     }
2523 
2524     PyTuple_SET_ITEM(state, 1, PyUnicode_FromFormat("%c", endian));
2525     PyTuple_SET_ITEM(state, 2, arraydescr_subdescr_get(self));
2526     if (PyDataType_HASFIELDS(self)) {
2527         Py_INCREF(self->names);
2528         Py_INCREF(self->fields);
2529         PyTuple_SET_ITEM(state, 3, self->names);
2530         PyTuple_SET_ITEM(state, 4, self->fields);
2531     }
2532     else {
2533         PyTuple_SET_ITEM(state, 3, Py_None);
2534         PyTuple_SET_ITEM(state, 4, Py_None);
2535         Py_INCREF(Py_None);
2536         Py_INCREF(Py_None);
2537     }
2538 
2539     /* for extended types it also includes elsize and alignment */
2540     if (PyTypeNum_ISEXTENDED(self->type_num)) {
2541         elsize = self->elsize;
2542         alignment = self->alignment;
2543     }
2544     else {
2545         elsize = -1;
2546         alignment = -1;
2547     }
2548     PyTuple_SET_ITEM(state, 5, PyLong_FromLong(elsize));
2549     PyTuple_SET_ITEM(state, 6, PyLong_FromLong(alignment));
2550     PyTuple_SET_ITEM(state, 7, PyLong_FromLong(self->flags));
2551 
2552     PyTuple_SET_ITEM(ret, 2, state);
2553     return ret;
2554 }
2555 
2556 /*
2557  * returns NPY_OBJECT_DTYPE_FLAGS if this data-type has an object portion used
2558  * when setting the state because hasobject is not stored.
2559  */
2560 static char
_descr_find_object(PyArray_Descr * self)2561 _descr_find_object(PyArray_Descr *self)
2562 {
2563     if (self->flags
2564             || self->type_num == NPY_OBJECT
2565             || self->kind == 'O') {
2566         return NPY_OBJECT_DTYPE_FLAGS;
2567     }
2568     if (PyDataType_HASFIELDS(self)) {
2569         PyObject *key, *value, *title = NULL;
2570         PyArray_Descr *new;
2571         int offset;
2572         Py_ssize_t pos = 0;
2573 
2574         while (PyDict_Next(self->fields, &pos, &key, &value)) {
2575             if (NPY_TITLE_KEY(key, value)) {
2576                 continue;
2577             }
2578             if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) {
2579                 PyErr_Clear();
2580                 return 0;
2581             }
2582             if (_descr_find_object(new)) {
2583                 new->flags = NPY_OBJECT_DTYPE_FLAGS;
2584                 return NPY_OBJECT_DTYPE_FLAGS;
2585             }
2586         }
2587     }
2588     return 0;
2589 }
2590 
2591 /*
2592  * state is at least byteorder, subarray, and fields but could include elsize
2593  * and alignment for EXTENDED arrays
2594  */
2595 static PyObject *
arraydescr_setstate(PyArray_Descr * self,PyObject * args)2596 arraydescr_setstate(PyArray_Descr *self, PyObject *args)
2597 {
2598     int elsize = -1, alignment = -1;
2599     int version = 4;
2600     char endian;
2601     PyObject *endian_obj;
2602     PyObject *subarray, *fields, *names = NULL, *metadata=NULL;
2603     int incref_names = 1;
2604     int int_dtypeflags = 0;
2605     char dtypeflags;
2606 
2607     if (self->fields == Py_None) {
2608         Py_RETURN_NONE;
2609     }
2610     if (PyTuple_GET_SIZE(args) != 1
2611             || !(PyTuple_Check(PyTuple_GET_ITEM(args, 0)))) {
2612         PyErr_BadInternalCall();
2613         return NULL;
2614     }
2615     switch (PyTuple_GET_SIZE(PyTuple_GET_ITEM(args,0))) {
2616     case 9:
2617         if (!PyArg_ParseTuple(args, "(iOOOOiiiO):__setstate__",
2618                     &version, &endian_obj,
2619                     &subarray, &names, &fields, &elsize,
2620                     &alignment, &int_dtypeflags, &metadata)) {
2621             PyErr_Clear();
2622             return NULL;
2623         }
2624         break;
2625     case 8:
2626         if (!PyArg_ParseTuple(args, "(iOOOOiii):__setstate__",
2627                     &version, &endian_obj,
2628                     &subarray, &names, &fields, &elsize,
2629                     &alignment, &int_dtypeflags)) {
2630             return NULL;
2631         }
2632         break;
2633     case 7:
2634         if (!PyArg_ParseTuple(args, "(iOOOOii):__setstate__",
2635                     &version, &endian_obj,
2636                     &subarray, &names, &fields, &elsize,
2637                     &alignment)) {
2638             return NULL;
2639         }
2640         break;
2641     case 6:
2642         if (!PyArg_ParseTuple(args, "(iOOOii):__setstate__",
2643                     &version,
2644                     &endian_obj, &subarray, &fields,
2645                     &elsize, &alignment)) {
2646             return NULL;
2647         }
2648         break;
2649     case 5:
2650         version = 0;
2651         if (!PyArg_ParseTuple(args, "(OOOii):__setstate__",
2652                     &endian_obj, &subarray, &fields, &elsize,
2653                     &alignment)) {
2654             return NULL;
2655         }
2656         break;
2657     default:
2658         /* raise an error */
2659         if (PyTuple_GET_SIZE(PyTuple_GET_ITEM(args,0)) > 5) {
2660             version = PyLong_AsLong(PyTuple_GET_ITEM(args, 0));
2661         }
2662         else {
2663             version = -1;
2664         }
2665     }
2666 
2667     /*
2668      * If we ever need another pickle format, increment the version
2669      * number. But we should still be able to handle the old versions.
2670      */
2671     if (version < 0 || version > 4) {
2672         PyErr_Format(PyExc_ValueError,
2673                      "can't handle version %d of numpy.dtype pickle",
2674                      version);
2675         return NULL;
2676     }
2677     /* Invalidate cached hash value */
2678     self->hash = -1;
2679 
2680     if (version == 1 || version == 0) {
2681         if (fields != Py_None) {
2682             PyObject *key, *list;
2683             key = PyLong_FromLong(-1);
2684             list = PyDict_GetItemWithError(fields, key);
2685             if (!list) {
2686                 if (!PyErr_Occurred()) {
2687                     /* fields was missing the name it claimed to contain */
2688                     PyErr_BadInternalCall();
2689                 }
2690                 return NULL;
2691             }
2692             Py_INCREF(list);
2693             names = list;
2694             PyDict_DelItem(fields, key);
2695             incref_names = 0;
2696         }
2697         else {
2698             names = Py_None;
2699         }
2700     }
2701 
2702     /* Parse endian */
2703     if (PyUnicode_Check(endian_obj) || PyBytes_Check(endian_obj)) {
2704         PyObject *tmp = NULL;
2705         char *str;
2706         Py_ssize_t len;
2707 
2708         if (PyUnicode_Check(endian_obj)) {
2709             tmp = PyUnicode_AsASCIIString(endian_obj);
2710             if (tmp == NULL) {
2711                 return NULL;
2712             }
2713             endian_obj = tmp;
2714         }
2715 
2716         if (PyBytes_AsStringAndSize(endian_obj, &str, &len) < 0) {
2717             Py_XDECREF(tmp);
2718             return NULL;
2719         }
2720         if (len != 1) {
2721             PyErr_SetString(PyExc_ValueError,
2722                             "endian is not 1-char string in Numpy dtype unpickling");
2723             Py_XDECREF(tmp);
2724             return NULL;
2725         }
2726         endian = str[0];
2727         Py_XDECREF(tmp);
2728     }
2729     else {
2730         PyErr_SetString(PyExc_ValueError,
2731                         "endian is not a string in Numpy dtype unpickling");
2732         return NULL;
2733     }
2734 
2735     if ((fields == Py_None && names != Py_None) ||
2736         (names == Py_None && fields != Py_None)) {
2737         PyErr_Format(PyExc_ValueError,
2738                 "inconsistent fields and names in Numpy dtype unpickling");
2739         return NULL;
2740     }
2741 
2742     if (names != Py_None && !PyTuple_Check(names)) {
2743         PyErr_Format(PyExc_ValueError,
2744                 "non-tuple names in Numpy dtype unpickling");
2745         return NULL;
2746     }
2747 
2748     if (fields != Py_None && !PyDict_Check(fields)) {
2749         PyErr_Format(PyExc_ValueError,
2750                 "non-dict fields in Numpy dtype unpickling");
2751         return NULL;
2752     }
2753 
2754     if (endian != '|' && PyArray_IsNativeByteOrder(endian)) {
2755         endian = '=';
2756     }
2757     self->byteorder = endian;
2758     if (self->subarray) {
2759         Py_XDECREF(self->subarray->base);
2760         Py_XDECREF(self->subarray->shape);
2761         PyArray_free(self->subarray);
2762     }
2763     self->subarray = NULL;
2764 
2765     if (subarray != Py_None) {
2766         PyObject *subarray_shape;
2767 
2768         /*
2769          * Ensure that subarray[0] is an ArrayDescr and
2770          * that subarray_shape obtained from subarray[1] is a tuple of integers.
2771          */
2772         if (!(PyTuple_Check(subarray) &&
2773               PyTuple_Size(subarray) == 2 &&
2774               PyArray_DescrCheck(PyTuple_GET_ITEM(subarray, 0)))) {
2775             PyErr_Format(PyExc_ValueError,
2776                          "incorrect subarray in __setstate__");
2777             return NULL;
2778         }
2779         subarray_shape = PyTuple_GET_ITEM(subarray, 1);
2780         if (PyNumber_Check(subarray_shape)) {
2781             PyObject *tmp;
2782             tmp = PyNumber_Long(subarray_shape);
2783             if (tmp == NULL) {
2784                 return NULL;
2785             }
2786             subarray_shape = Py_BuildValue("(O)", tmp);
2787             Py_DECREF(tmp);
2788             if (subarray_shape == NULL) {
2789                 return NULL;
2790             }
2791         }
2792         else if (_is_tuple_of_integers(subarray_shape)) {
2793             Py_INCREF(subarray_shape);
2794         }
2795         else {
2796             PyErr_Format(PyExc_ValueError,
2797                          "incorrect subarray shape in __setstate__");
2798             return NULL;
2799         }
2800 
2801         self->subarray = PyArray_malloc(sizeof(PyArray_ArrayDescr));
2802         if (!PyDataType_HASSUBARRAY(self)) {
2803             return PyErr_NoMemory();
2804         }
2805         self->subarray->base = (PyArray_Descr *)PyTuple_GET_ITEM(subarray, 0);
2806         Py_INCREF(self->subarray->base);
2807         self->subarray->shape = subarray_shape;
2808     }
2809 
2810     if (fields != Py_None) {
2811         /*
2812          * Ensure names are of appropriate string type
2813          */
2814         Py_ssize_t i;
2815         int names_ok = 1;
2816         PyObject *name;
2817 
2818         for (i = 0; i < PyTuple_GET_SIZE(names); ++i) {
2819             name = PyTuple_GET_ITEM(names, i);
2820             if (!PyUnicode_Check(name)) {
2821                 names_ok = 0;
2822                 break;
2823             }
2824         }
2825 
2826         if (names_ok) {
2827             Py_XDECREF(self->fields);
2828             self->fields = fields;
2829             Py_INCREF(fields);
2830             Py_XDECREF(self->names);
2831             self->names = names;
2832             if (incref_names) {
2833                 Py_INCREF(names);
2834             }
2835         }
2836         else {
2837             /*
2838              * To support pickle.load(f, encoding='bytes') for loading Py2
2839              * generated pickles on Py3, we need to be more lenient and convert
2840              * field names from byte strings to unicode.
2841              */
2842             PyObject *tmp, *new_name, *field;
2843 
2844             tmp = PyDict_New();
2845             if (tmp == NULL) {
2846                 return NULL;
2847             }
2848             Py_XDECREF(self->fields);
2849             self->fields = tmp;
2850 
2851             tmp = PyTuple_New(PyTuple_GET_SIZE(names));
2852             if (tmp == NULL) {
2853                 return NULL;
2854             }
2855             Py_XDECREF(self->names);
2856             self->names = tmp;
2857 
2858             for (i = 0; i < PyTuple_GET_SIZE(names); ++i) {
2859                 name = PyTuple_GET_ITEM(names, i);
2860                 field = PyDict_GetItemWithError(fields, name);
2861                 if (!field) {
2862                     if (!PyErr_Occurred()) {
2863                         /* fields was missing the name it claimed to contain */
2864                         PyErr_BadInternalCall();
2865                     }
2866                     return NULL;
2867                 }
2868 
2869                 if (PyUnicode_Check(name)) {
2870                     new_name = name;
2871                     Py_INCREF(new_name);
2872                 }
2873                 else {
2874                     new_name = PyUnicode_FromEncodedObject(name, "ASCII", "strict");
2875                     if (new_name == NULL) {
2876                         return NULL;
2877                     }
2878                 }
2879 
2880                 PyTuple_SET_ITEM(self->names, i, new_name);
2881                 if (PyDict_SetItem(self->fields, new_name, field) != 0) {
2882                     return NULL;
2883                 }
2884             }
2885         }
2886     }
2887 
2888     if (PyTypeNum_ISEXTENDED(self->type_num)) {
2889         self->elsize = elsize;
2890         self->alignment = alignment;
2891     }
2892 
2893     /*
2894      * We use an integer converted to char for backward compatibility with
2895      * pickled arrays. Pickled arrays created with previous versions encoded
2896      * flags as an int even though it actually was a char in the PyArray_Descr
2897      * structure
2898      */
2899     dtypeflags = int_dtypeflags;
2900     if (dtypeflags != int_dtypeflags) {
2901         PyErr_Format(PyExc_ValueError,
2902                      "incorrect value for flags variable (overflow)");
2903         return NULL;
2904     }
2905     else {
2906         self->flags = dtypeflags;
2907     }
2908 
2909     if (version < 3) {
2910         self->flags = _descr_find_object(self);
2911     }
2912 
2913     /*
2914      * We have a borrowed reference to metadata so no need
2915      * to alter reference count when throwing away Py_None.
2916      */
2917     if (metadata == Py_None) {
2918         metadata = NULL;
2919     }
2920 
2921     if (PyDataType_ISDATETIME(self) && (metadata != NULL)) {
2922         PyObject *old_metadata;
2923         PyArray_DatetimeMetaData temp_dt_data;
2924 
2925         if ((! PyTuple_Check(metadata)) || (PyTuple_Size(metadata) != 2)) {
2926             PyErr_Format(PyExc_ValueError,
2927                     "Invalid datetime dtype (metadata, c_metadata): %R",
2928                     metadata);
2929             return NULL;
2930         }
2931 
2932         if (convert_datetime_metadata_tuple_to_datetime_metadata(
2933                                     PyTuple_GET_ITEM(metadata, 1),
2934                                     &temp_dt_data,
2935                                     NPY_TRUE) < 0) {
2936             return NULL;
2937         }
2938 
2939         old_metadata = self->metadata;
2940         self->metadata = PyTuple_GET_ITEM(metadata, 0);
2941         memcpy((char *) &((PyArray_DatetimeDTypeMetaData *)self->c_metadata)->meta,
2942                (char *) &temp_dt_data,
2943                sizeof(PyArray_DatetimeMetaData));
2944         Py_XINCREF(self->metadata);
2945         Py_XDECREF(old_metadata);
2946     }
2947     else {
2948         PyObject *old_metadata = self->metadata;
2949         self->metadata = metadata;
2950         Py_XINCREF(self->metadata);
2951         Py_XDECREF(old_metadata);
2952     }
2953 
2954     Py_RETURN_NONE;
2955 }
2956 
2957 /*NUMPY_API
2958  *
2959  * Get type-descriptor from an object forcing alignment if possible
2960  * None goes to DEFAULT type.
2961  *
2962  * any object with the .fields attribute and/or .itemsize attribute (if the
2963  *.fields attribute does not give the total size -- i.e. a partial record
2964  * naming).  If itemsize is given it must be >= size computed from fields
2965  *
2966  * The .fields attribute must return a convertible dictionary if present.
2967  * Result inherits from NPY_VOID.
2968 */
2969 NPY_NO_EXPORT int
PyArray_DescrAlignConverter(PyObject * obj,PyArray_Descr ** at)2970 PyArray_DescrAlignConverter(PyObject *obj, PyArray_Descr **at)
2971 {
2972     *at = _convert_from_any(obj, 1);
2973     return (*at) ? NPY_SUCCEED : NPY_FAIL;
2974 }
2975 
2976 /*NUMPY_API
2977  *
2978  * Get type-descriptor from an object forcing alignment if possible
2979  * None goes to NULL.
2980  */
2981 NPY_NO_EXPORT int
PyArray_DescrAlignConverter2(PyObject * obj,PyArray_Descr ** at)2982 PyArray_DescrAlignConverter2(PyObject *obj, PyArray_Descr **at)
2983 {
2984     if (obj == Py_None) {
2985         *at = NULL;
2986         return NPY_SUCCEED;
2987     }
2988     else {
2989         return PyArray_DescrAlignConverter(obj, at);
2990     }
2991 }
2992 
2993 
2994 
2995 /*NUMPY_API
2996  *
2997  * returns a copy of the PyArray_Descr structure with the byteorder
2998  * altered:
2999  * no arguments:  The byteorder is swapped (in all subfields as well)
3000  * single argument:  The byteorder is forced to the given state
3001  * (in all subfields as well)
3002  *
3003  * Valid states:  ('big', '>') or ('little' or '<')
3004  * ('native', or '=')
3005  *
3006  * If a descr structure with | is encountered it's own
3007  * byte-order is not changed but any fields are:
3008  *
3009  *
3010  * Deep bytorder change of a data-type descriptor
3011  * *** Leaves reference count of self unchanged --- does not DECREF self ***
3012  */
3013 NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrNewByteorder(PyArray_Descr * self,char newendian)3014 PyArray_DescrNewByteorder(PyArray_Descr *self, char newendian)
3015 {
3016     PyArray_Descr *new;
3017     char endian;
3018 
3019     new = PyArray_DescrNew(self);
3020     endian = new->byteorder;
3021     if (endian != NPY_IGNORE) {
3022         if (newendian == NPY_SWAP) {
3023             /* swap byteorder */
3024             if (PyArray_ISNBO(endian)) {
3025                 endian = NPY_OPPBYTE;
3026             }
3027             else {
3028                 endian = NPY_NATBYTE;
3029             }
3030             new->byteorder = endian;
3031         }
3032         else if (newendian != NPY_IGNORE) {
3033             new->byteorder = newendian;
3034         }
3035     }
3036     if (PyDataType_HASFIELDS(new)) {
3037         PyObject *newfields;
3038         PyObject *key, *value;
3039         PyObject *newvalue;
3040         PyObject *old;
3041         PyArray_Descr *newdescr;
3042         Py_ssize_t pos = 0;
3043         int len, i;
3044 
3045         newfields = PyDict_New();
3046         /* make new dictionary with replaced PyArray_Descr Objects */
3047         while (PyDict_Next(self->fields, &pos, &key, &value)) {
3048             if (NPY_TITLE_KEY(key, value)) {
3049                 continue;
3050             }
3051             if (!PyUnicode_Check(key) || !PyTuple_Check(value) ||
3052                 ((len=PyTuple_GET_SIZE(value)) < 2)) {
3053                 continue;
3054             }
3055             old = PyTuple_GET_ITEM(value, 0);
3056             if (!PyArray_DescrCheck(old)) {
3057                 continue;
3058             }
3059             newdescr = PyArray_DescrNewByteorder(
3060                     (PyArray_Descr *)old, newendian);
3061             if (newdescr == NULL) {
3062                 Py_DECREF(newfields); Py_DECREF(new);
3063                 return NULL;
3064             }
3065             newvalue = PyTuple_New(len);
3066             PyTuple_SET_ITEM(newvalue, 0, (PyObject *)newdescr);
3067             for (i = 1; i < len; i++) {
3068                 old = PyTuple_GET_ITEM(value, i);
3069                 Py_INCREF(old);
3070                 PyTuple_SET_ITEM(newvalue, i, old);
3071             }
3072             int ret = PyDict_SetItem(newfields, key, newvalue);
3073             Py_DECREF(newvalue);
3074             if (ret < 0) {
3075                 Py_DECREF(newfields);
3076                 Py_DECREF(new);
3077                 return NULL;
3078             }
3079         }
3080         Py_DECREF(new->fields);
3081         new->fields = newfields;
3082     }
3083     if (PyDataType_HASSUBARRAY(new)) {
3084         Py_DECREF(new->subarray->base);
3085         new->subarray->base = PyArray_DescrNewByteorder(
3086                 self->subarray->base, newendian);
3087     }
3088     return new;
3089 }
3090 
3091 
3092 static PyObject *
arraydescr_newbyteorder(PyArray_Descr * self,PyObject * args)3093 arraydescr_newbyteorder(PyArray_Descr *self, PyObject *args)
3094 {
3095     char endian=NPY_SWAP;
3096 
3097     if (!PyArg_ParseTuple(args, "|O&:newbyteorder", PyArray_ByteorderConverter,
3098                 &endian)) {
3099         return NULL;
3100     }
3101     return (PyObject *)PyArray_DescrNewByteorder(self, endian);
3102 }
3103 
3104 static PyMethodDef arraydescr_methods[] = {
3105     /* for pickling */
3106     {"__reduce__",
3107         (PyCFunction)arraydescr_reduce,
3108         METH_VARARGS, NULL},
3109     {"__setstate__",
3110         (PyCFunction)arraydescr_setstate,
3111         METH_VARARGS, NULL},
3112     {"newbyteorder",
3113         (PyCFunction)arraydescr_newbyteorder,
3114         METH_VARARGS, NULL},
3115     {NULL, NULL, 0, NULL}           /* sentinel */
3116 };
3117 
3118 /*
3119  * Checks whether the structured data type in 'dtype'
3120  * has a simple layout, where all the fields are in order,
3121  * and follow each other with no alignment padding.
3122  *
3123  * When this returns true, the dtype can be reconstructed
3124  * from a list of the field names and dtypes with no additional
3125  * dtype parameters.
3126  *
3127  * Returns 1 if it has a simple layout, 0 otherwise.
3128  */
3129 NPY_NO_EXPORT int
is_dtype_struct_simple_unaligned_layout(PyArray_Descr * dtype)3130 is_dtype_struct_simple_unaligned_layout(PyArray_Descr *dtype)
3131 {
3132     PyObject *names, *fields, *key, *tup, *title;
3133     Py_ssize_t i, names_size;
3134     PyArray_Descr *fld_dtype;
3135     int fld_offset;
3136     npy_intp total_offset;
3137 
3138     /* Get some properties from the dtype */
3139     names = dtype->names;
3140     names_size = PyTuple_GET_SIZE(names);
3141     fields = dtype->fields;
3142 
3143     /* Start at offset zero */
3144     total_offset = 0;
3145 
3146     for (i = 0; i < names_size; ++i) {
3147         key = PyTuple_GET_ITEM(names, i);
3148         if (key == NULL) {
3149             return 0;
3150         }
3151         tup = PyDict_GetItem(fields, key);
3152         if (tup == NULL) {
3153             return 0;
3154         }
3155         if (!PyArg_ParseTuple(tup, "Oi|O", &fld_dtype, &fld_offset, &title)) {
3156             PyErr_Clear();
3157             return 0;
3158         }
3159         /* If this field doesn't follow the pattern, not a simple layout */
3160         if (total_offset != fld_offset) {
3161             return 0;
3162         }
3163         /* Get the next offset */
3164         total_offset += fld_dtype->elsize;
3165     }
3166 
3167     /*
3168      * If the itemsize doesn't match the final offset, it's
3169      * not a simple layout.
3170      */
3171     if (total_offset != dtype->elsize) {
3172         return 0;
3173     }
3174 
3175     /* It's a simple layout, since all the above tests passed */
3176     return 1;
3177 }
3178 
3179 /*
3180  * The general dtype repr function.
3181  */
3182 static PyObject *
arraydescr_repr(PyArray_Descr * dtype)3183 arraydescr_repr(PyArray_Descr *dtype)
3184 {
3185     PyObject *_numpy_dtype;
3186     PyObject *res;
3187     _numpy_dtype = PyImport_ImportModule("numpy.core._dtype");
3188     if (_numpy_dtype == NULL) {
3189         return NULL;
3190     }
3191     res = PyObject_CallMethod(_numpy_dtype, "__repr__", "O", dtype);
3192     Py_DECREF(_numpy_dtype);
3193     return res;
3194 }
3195 /*
3196  * The general dtype str function.
3197  */
3198 static PyObject *
arraydescr_str(PyArray_Descr * dtype)3199 arraydescr_str(PyArray_Descr *dtype)
3200 {
3201     PyObject *_numpy_dtype;
3202     PyObject *res;
3203     _numpy_dtype = PyImport_ImportModule("numpy.core._dtype");
3204     if (_numpy_dtype == NULL) {
3205         return NULL;
3206     }
3207     res = PyObject_CallMethod(_numpy_dtype, "__str__", "O", dtype);
3208     Py_DECREF(_numpy_dtype);
3209     return res;
3210 }
3211 
3212 static PyObject *
arraydescr_richcompare(PyArray_Descr * self,PyObject * other,int cmp_op)3213 arraydescr_richcompare(PyArray_Descr *self, PyObject *other, int cmp_op)
3214 {
3215     PyArray_Descr *new = _convert_from_any(other, 0);
3216     if (new == NULL) {
3217         return NULL;
3218     }
3219 
3220     npy_bool ret;
3221     switch (cmp_op) {
3222     case Py_LT:
3223         ret = !PyArray_EquivTypes(self, new) && PyArray_CanCastTo(self, new);
3224         Py_DECREF(new);
3225         return PyBool_FromLong(ret);
3226     case Py_LE:
3227         ret = PyArray_CanCastTo(self, new);
3228         Py_DECREF(new);
3229         return PyBool_FromLong(ret);
3230     case Py_EQ:
3231         ret = PyArray_EquivTypes(self, new);
3232         Py_DECREF(new);
3233         return PyBool_FromLong(ret);
3234     case Py_NE:
3235         ret = !PyArray_EquivTypes(self, new);
3236         Py_DECREF(new);
3237         return PyBool_FromLong(ret);
3238     case Py_GT:
3239         ret = !PyArray_EquivTypes(self, new) && PyArray_CanCastTo(new, self);
3240         Py_DECREF(new);
3241         return PyBool_FromLong(ret);
3242     case Py_GE:
3243         ret = PyArray_CanCastTo(new, self);
3244         Py_DECREF(new);
3245         return PyBool_FromLong(ret);
3246     default:
3247         Py_DECREF(new);
3248         Py_RETURN_NOTIMPLEMENTED;
3249     }
3250 }
3251 
3252 static int
descr_nonzero(PyObject * NPY_UNUSED (self))3253 descr_nonzero(PyObject *NPY_UNUSED(self))
3254 {
3255     /* `bool(np.dtype(...)) == True` for all dtypes. Needed to override default
3256      * nonzero implementation, which checks if `len(object) > 0`. */
3257     return 1;
3258 }
3259 
3260 static PyNumberMethods descr_as_number = {
3261     .nb_bool = (inquiry)descr_nonzero,
3262 };
3263 
3264 /*************************************************************************
3265  ****************   Implement Mapping Protocol ***************************
3266  *************************************************************************/
3267 
3268 static Py_ssize_t
descr_length(PyObject * self0)3269 descr_length(PyObject *self0)
3270 {
3271     PyArray_Descr *self = (PyArray_Descr *)self0;
3272 
3273     if (PyDataType_HASFIELDS(self)) {
3274         return PyTuple_GET_SIZE(self->names);
3275     }
3276     else {
3277         return 0;
3278     }
3279 }
3280 
3281 static PyObject *
descr_repeat(PyObject * self,Py_ssize_t length)3282 descr_repeat(PyObject *self, Py_ssize_t length)
3283 {
3284     PyObject *tup;
3285     PyArray_Descr *new;
3286     if (length < 0) {
3287         return PyErr_Format(PyExc_ValueError,
3288                 "Array length must be >= 0, not %"NPY_INTP_FMT, (npy_intp)length);
3289     }
3290     tup = Py_BuildValue("O" NPY_SSIZE_T_PYFMT, self, length);
3291     if (tup == NULL) {
3292         return NULL;
3293     }
3294     new = _convert_from_any(tup, 0);
3295     Py_DECREF(tup);
3296     return (PyObject *)new;
3297 }
3298 
3299 static int
_check_has_fields(PyArray_Descr * self)3300 _check_has_fields(PyArray_Descr *self)
3301 {
3302     if (!PyDataType_HASFIELDS(self)) {
3303         PyErr_Format(PyExc_KeyError, "There are no fields in dtype %S.", self);
3304         return -1;
3305     }
3306     else {
3307         return 0;
3308     }
3309 }
3310 
3311 static PyObject *
_subscript_by_name(PyArray_Descr * self,PyObject * op)3312 _subscript_by_name(PyArray_Descr *self, PyObject *op)
3313 {
3314     PyObject *obj = PyDict_GetItemWithError(self->fields, op);
3315     if (obj == NULL) {
3316         if (!PyErr_Occurred()) {
3317             PyErr_Format(PyExc_KeyError,
3318                     "Field named %R not found.", op);
3319         }
3320         return NULL;
3321     }
3322     PyObject *descr = PyTuple_GET_ITEM(obj, 0);
3323     Py_INCREF(descr);
3324     return descr;
3325 }
3326 
3327 static PyObject *
_subscript_by_index(PyArray_Descr * self,Py_ssize_t i)3328 _subscript_by_index(PyArray_Descr *self, Py_ssize_t i)
3329 {
3330     PyObject *name = PySequence_GetItem(self->names, i);
3331     PyObject *ret;
3332     if (name == NULL) {
3333         PyErr_Format(PyExc_IndexError,
3334                      "Field index %zd out of range.", i);
3335         return NULL;
3336     }
3337     ret = _subscript_by_name(self, name);
3338     Py_DECREF(name);
3339     return ret;
3340 }
3341 
3342 static npy_bool
_is_list_of_strings(PyObject * obj)3343 _is_list_of_strings(PyObject *obj)
3344 {
3345     int seqlen, i;
3346     if (!PyList_CheckExact(obj)) {
3347         return NPY_FALSE;
3348     }
3349     seqlen = PyList_GET_SIZE(obj);
3350     for (i = 0; i < seqlen; i++) {
3351         PyObject *item = PyList_GET_ITEM(obj, i);
3352         if (!PyUnicode_Check(item)) {
3353             return NPY_FALSE;
3354         }
3355     }
3356 
3357     return NPY_TRUE;
3358 }
3359 
3360 NPY_NO_EXPORT PyArray_Descr *
arraydescr_field_subset_view(PyArray_Descr * self,PyObject * ind)3361 arraydescr_field_subset_view(PyArray_Descr *self, PyObject *ind)
3362 {
3363     int seqlen, i;
3364     PyObject *fields = NULL;
3365     PyObject *names = NULL;
3366     PyArray_Descr *view_dtype;
3367 
3368     seqlen = PySequence_Size(ind);
3369     if (seqlen == -1) {
3370         return NULL;
3371     }
3372 
3373     fields = PyDict_New();
3374     if (fields == NULL) {
3375         goto fail;
3376     }
3377     names = PyTuple_New(seqlen);
3378     if (names == NULL) {
3379         goto fail;
3380     }
3381 
3382     for (i = 0; i < seqlen; i++) {
3383         PyObject *name;
3384         PyObject *tup;
3385 
3386         name = PySequence_GetItem(ind, i);
3387         if (name == NULL) {
3388             goto fail;
3389         }
3390 
3391         /* Let the names tuple steal a reference now, so we don't need to
3392          * decref name if an error occurs further on.
3393          */
3394         PyTuple_SET_ITEM(names, i, name);
3395 
3396         tup = PyDict_GetItemWithError(self->fields, name);
3397         if (tup == NULL) {
3398             if (!PyErr_Occurred()) {
3399                 PyErr_SetObject(PyExc_KeyError, name);
3400             }
3401             goto fail;
3402         }
3403 
3404         /* disallow use of titles as index */
3405         if (PyTuple_Size(tup) == 3) {
3406             PyObject *title = PyTuple_GET_ITEM(tup, 2);
3407             int titlecmp = PyObject_RichCompareBool(title, name, Py_EQ);
3408             if (titlecmp < 0) {
3409                 goto fail;
3410             }
3411             if (titlecmp == 1) {
3412                 /* if title == name, we were given a title, not a field name */
3413                 PyErr_SetString(PyExc_KeyError,
3414                             "cannot use field titles in multi-field index");
3415                 goto fail;
3416             }
3417             if (PyDict_SetItem(fields, title, tup) < 0) {
3418                 goto fail;
3419             }
3420         }
3421         /* disallow duplicate field indices */
3422         if (PyDict_Contains(fields, name)) {
3423             PyObject *msg = NULL;
3424             PyObject *fmt = PyUnicode_FromString(
3425                                    "duplicate field of name {!r}");
3426             if (fmt != NULL) {
3427                 msg = PyObject_CallMethod(fmt, "format", "O", name);
3428                 Py_DECREF(fmt);
3429             }
3430             PyErr_SetObject(PyExc_ValueError, msg);
3431             Py_XDECREF(msg);
3432             goto fail;
3433         }
3434         if (PyDict_SetItem(fields, name, tup) < 0) {
3435             goto fail;
3436         }
3437     }
3438 
3439     view_dtype = PyArray_DescrNewFromType(NPY_VOID);
3440     if (view_dtype == NULL) {
3441         goto fail;
3442     }
3443     view_dtype->elsize = self->elsize;
3444     view_dtype->names = names;
3445     view_dtype->fields = fields;
3446     view_dtype->flags = self->flags;
3447     return view_dtype;
3448 
3449 fail:
3450     Py_XDECREF(fields);
3451     Py_XDECREF(names);
3452     return NULL;
3453 }
3454 
3455 static PyObject *
descr_subscript(PyArray_Descr * self,PyObject * op)3456 descr_subscript(PyArray_Descr *self, PyObject *op)
3457 {
3458     if (_check_has_fields(self) < 0) {
3459         return NULL;
3460     }
3461 
3462     if (PyUnicode_Check(op)) {
3463         return _subscript_by_name(self, op);
3464     }
3465     else if (_is_list_of_strings(op)) {
3466         return (PyObject *)arraydescr_field_subset_view(self, op);
3467     }
3468     else {
3469         Py_ssize_t i = PyArray_PyIntAsIntp(op);
3470         if (error_converting(i)) {
3471             /* if converting to an int gives a type error, adjust the message */
3472             PyObject *err = PyErr_Occurred();
3473             if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) {
3474                 PyErr_SetString(PyExc_TypeError,
3475                         "Field key must be an integer field offset, "
3476                         "single field name, or list of field names.");
3477             }
3478             return NULL;
3479         }
3480         return _subscript_by_index(self, i);
3481     }
3482 }
3483 
3484 static PySequenceMethods descr_as_sequence = {
3485     (lenfunc) descr_length,                  /* sq_length */
3486     (binaryfunc) NULL,                       /* sq_concat */
3487     (ssizeargfunc) descr_repeat,             /* sq_repeat */
3488     (ssizeargfunc) NULL,                     /* sq_item */
3489     (ssizessizeargfunc) NULL,                /* sq_slice */
3490     (ssizeobjargproc) NULL,                  /* sq_ass_item */
3491     (ssizessizeobjargproc) NULL,             /* sq_ass_slice */
3492     (objobjproc) NULL,                       /* sq_contains */
3493     (binaryfunc) NULL,                       /* sq_inplace_concat */
3494     (ssizeargfunc) NULL,                     /* sq_inplace_repeat */
3495 };
3496 
3497 static PyMappingMethods descr_as_mapping = {
3498     descr_length,                                /* mp_length*/
3499     (binaryfunc)descr_subscript,                 /* mp_subscript*/
3500     (objobjargproc)NULL,                         /* mp_ass_subscript*/
3501 };
3502 
3503 /****************** End of Mapping Protocol ******************************/
3504 
3505 
3506 /*
3507  * NOTE: Since this is a MetaClass, the name has Full appended here, the
3508  *       correct name of the type is PyArrayDescr_Type.
3509  */
3510 NPY_NO_EXPORT PyArray_DTypeMeta PyArrayDescr_TypeFull = {
3511     {{
3512         /* NULL represents `type`, this is set to DTypeMeta at import time */
3513         PyVarObject_HEAD_INIT(NULL, 0)
3514         .tp_name = "numpy.dtype",
3515         .tp_basicsize = sizeof(PyArray_Descr),
3516         .tp_dealloc = (destructor)arraydescr_dealloc,
3517         .tp_repr = (reprfunc)arraydescr_repr,
3518         .tp_as_number = &descr_as_number,
3519         .tp_as_sequence = &descr_as_sequence,
3520         .tp_as_mapping = &descr_as_mapping,
3521         .tp_str = (reprfunc)arraydescr_str,
3522         .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
3523         .tp_richcompare = (richcmpfunc)arraydescr_richcompare,
3524         .tp_methods = arraydescr_methods,
3525         .tp_members = arraydescr_members,
3526         .tp_getset = arraydescr_getsets,
3527         .tp_new = arraydescr_new,
3528     },},
3529     .type_num = -1,
3530     .kind = '\0',
3531     .abstract = 1,
3532     .parametric = 0,
3533     .singleton = 0,
3534     .scalar_type = NULL,
3535 };
3536