summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2020-01-10 11:51:26 -0600
committerGitHub <noreply@github.com>2020-01-10 11:51:26 -0600
commitc4d5e12879c19c2655b5620fa1c18242b14d5141 (patch)
tree4ebf3d3f002302f87b217035fbaa39dd12ff18e7 /numpy
parent624d34cbda2f8f7614733743f028c0dd6a5c9952 (diff)
parent74df40540001011fc0cad5c2a1a14947cba037f8 (diff)
downloadnumpy-c4d5e12879c19c2655b5620fa1c18242b14d5141.tar.gz
Merge pull request #15300 from eric-wieser/tidy-dtype-ctors-try_convert
MAINT: Refactor dtype conversion functions to be more similar
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/descriptor.c124
-rw-r--r--numpy/core/src/multiarray/descriptor.h4
-rw-r--r--numpy/core/src/multiarray/scalarapi.c15
3 files changed, 76 insertions, 67 deletions
diff --git a/numpy/core/src/multiarray/descriptor.c b/numpy/core/src/multiarray/descriptor.c
index 2ab090e74..efa53696b 100644
--- a/numpy/core/src/multiarray/descriptor.c
+++ b/numpy/core/src/multiarray/descriptor.c
@@ -49,7 +49,7 @@ _report_generic_error(void) {
}
static PyArray_Descr *
-_use_inherit(PyArray_Descr *type, PyObject *newobj, int *errflag);
+_try_convert_from_inherit_tuple(PyArray_Descr *type, PyObject *newobj);
static PyArray_Descr *
_convert_from_any(PyObject *obj, int align);
@@ -65,12 +65,22 @@ _arraydescr_run_converter(PyObject *arg, int align)
return type;
}
+/*
+ * This function creates a dtype object when the object is a ctypes subclass.
+ *
+ * Returns `Py_NotImplemented` if the type is not a ctypes subclass.
+ */
static PyArray_Descr *
-_arraydescr_from_ctypes_type(PyTypeObject *type)
+_try_convert_from_ctypes_type(PyTypeObject *type)
{
PyObject *_numpy_dtype_ctypes;
PyObject *res;
+ if (!npy_ctypes_check(type)) {
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_Descr *)Py_NotImplemented;
+ }
+
/* Call the python function of the same name. */
_numpy_dtype_ctypes = PyImport_ImportModule("numpy.core._dtype_ctypes");
if (_numpy_dtype_ctypes == NULL) {
@@ -95,25 +105,21 @@ _arraydescr_from_ctypes_type(PyTypeObject *type)
return (PyArray_Descr *)res;
}
+static PyArray_Descr *
+_convert_from_any(PyObject *obj, int align);
+
/*
* This function creates a dtype object when the object has a "dtype" attribute,
* and it can be converted to a dtype object.
*
- * Returns a new reference to a dtype object, or NULL
- * if this is not possible.
- * When the return value is true, the dtype attribute should have been used
- * and parsed. Currently the only failure mode for a 1 return is a
- * RecursionError and the descriptor is set to NULL.
- * When the return value is false, no error will be set.
+ * Returns `Py_NotImplemented` if this is not possible.
+ * Currently the only failure mode for a NULL return is a RecursionError.
*/
-int
-_arraydescr_from_dtype_attr(PyObject *obj, PyArray_Descr **newdescr)
+static PyArray_Descr *
+_try_convert_from_dtype_attr(PyObject *obj)
{
- PyObject *dtypedescr;
- int ret;
-
/* For arbitrary objects that have a "dtype" attribute */
- dtypedescr = PyObject_GetAttrString(obj, "dtype");
+ PyObject *dtypedescr = PyObject_GetAttrString(obj, "dtype");
if (dtypedescr == NULL) {
/*
* This can be reached due to recursion limit being hit while fetching
@@ -126,10 +132,11 @@ _arraydescr_from_dtype_attr(PyObject *obj, PyArray_Descr **newdescr)
" while trying to convert the given data type from its "
"`.dtype` attribute.") != 0) {
Py_DECREF(dtypedescr);
- return 1;
+ return NULL;
}
- ret = PyArray_DescrConverter(dtypedescr, newdescr);
+ PyArray_Descr *newdescr;
+ int ret = PyArray_DescrConverter(dtypedescr, &newdescr);
Py_DECREF(dtypedescr);
Py_LeaveRecursiveCall();
@@ -137,15 +144,23 @@ _arraydescr_from_dtype_attr(PyObject *obj, PyArray_Descr **newdescr)
goto fail;
}
- return 1;
+ return newdescr;
fail:
/* Ignore all but recursion errors, to give ctypes a full try. */
if (!PyErr_ExceptionMatches(PyExc_RecursionError)) {
PyErr_Clear();
- return 0;
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_Descr *)Py_NotImplemented;
}
- return 1;
+ return NULL;
+}
+
+/* Expose to another file with a prefixed name */
+NPY_NO_EXPORT PyArray_Descr *
+_arraydescr_try_convert_from_dtype_attr(PyObject *obj)
+{
+ return _try_convert_from_dtype_attr(obj);
}
/*
@@ -257,16 +272,14 @@ _convert_from_tuple(PyObject *obj, int align)
}
PyObject *val = PyTuple_GET_ITEM(obj,1);
/* try to interpret next item as a type */
- int errflag;
- PyArray_Descr *res = _use_inherit(type, val, &errflag);
- if (res || errflag) {
+ PyArray_Descr *res = _try_convert_from_inherit_tuple(type, val);
+ if ((PyObject *)res != Py_NotImplemented) {
Py_DECREF(type);
return res;
}
- PyErr_Clear();
+ Py_DECREF(res);
/*
- * We get here if res was NULL but errflag wasn't set
- * --- i.e. the conversion to a data-descr failed in _use_inherit
+ * We get here if _try_convert_from_inherit_tuple failed without crashing
*/
if (PyDataType_ISUNSIZED(type)) {
/* interpret next item as a typesize */
@@ -757,7 +770,7 @@ _is_tuple_of_integers(PyObject *obj)
}
/*
- * helper function for _use_inherit to disallow dtypes of the form
+ * helper function for _try_convert_from_inherit_tuple to disallow dtypes of the form
* (old_dtype, new_dtype) where either of the dtypes contains python
* objects - these dtypes are not useful and can be a source of segfaults,
* when an attempt is made to interpret a python object as a different dtype
@@ -818,20 +831,24 @@ fail:
* a['real'] and a['imag'] to an int32 array.
*
* leave type reference alone
+ *
+ * Returns `Py_NotImplemented` if the second tuple item is not
+ * appropriate.
*/
static PyArray_Descr *
-_use_inherit(PyArray_Descr *type, PyObject *newobj, int *errflag)
+_try_convert_from_inherit_tuple(PyArray_Descr *type, PyObject *newobj)
{
PyArray_Descr *new;
PyArray_Descr *conv;
- *errflag = 0;
if (PyArray_IsScalar(newobj, Integer)
|| _is_tuple_of_integers(newobj)
|| !PyArray_DescrConverter(newobj, &conv)) {
- return NULL;
+ /* PyArray_DescrConverter may have set an exception, which we ignore */
+ PyErr_Clear();
+ Py_INCREF(Py_NotImplemented);
+ return (PyArray_Descr *)Py_NotImplemented;
}
- *errflag = 1;
new = PyArray_DescrNew(type);
if (new == NULL) {
goto fail;
@@ -866,7 +883,6 @@ _use_inherit(PyArray_Descr *type, PyObject *newobj, int *errflag)
}
new->flags = conv->flags;
Py_DECREF(conv);
- *errflag = 0;
return new;
fail:
@@ -982,7 +998,7 @@ validate_object_field_overlap(PyArray_Descr *dtype)
* then it will be checked for conformity and used directly.
*/
static PyArray_Descr *
-_use_fields_dict(PyObject *obj, int align)
+_convert_from_field_dict(PyObject *obj, int align)
{
PyObject *_numpy_internal;
PyArray_Descr *res;
@@ -1015,7 +1031,7 @@ _convert_from_dict(PyObject *obj, int align)
Py_DECREF(fields);
/* XXX should check this is a KeyError */
PyErr_Clear();
- return _use_fields_dict(obj, align);
+ return _convert_from_field_dict(obj, align);
}
PyObject *descrs = PyMapping_GetItemString(obj, "formats");
if (descrs == NULL) {
@@ -1023,7 +1039,7 @@ _convert_from_dict(PyObject *obj, int align)
/* XXX should check this is a KeyError */
PyErr_Clear();
Py_DECREF(names);
- return _use_fields_dict(obj, align);
+ return _convert_from_field_dict(obj, align);
}
int n = PyObject_Length(names);
PyObject *offsets = PyMapping_GetItemString(obj, "offsets");
@@ -1364,25 +1380,22 @@ _convert_from_type(PyObject *obj) {
return PyArray_DescrFromType(NPY_VOID);
}
else {
- PyArray_Descr *at = NULL;
- if (_arraydescr_from_dtype_attr(obj, &at)) {
- /*
- * Using dtype attribute, *at may be NULL if a
- * RecursionError occurred.
- */
- if (at == NULL) {
- return NULL;
- }
- return at;
+ PyArray_Descr *ret = _try_convert_from_dtype_attr(obj);
+ if ((PyObject *)ret != Py_NotImplemented) {
+ return ret;
}
+ Py_DECREF(ret);
+
/*
- * Note: this comes after _arraydescr_from_dtype_attr because the ctypes
+ * Note: this comes after _try_convert_from_dtype_attr because the ctypes
* type might override the dtype if numpy does not otherwise
* support it.
*/
- if (npy_ctypes_check(typ)) {
- return _arraydescr_from_ctypes_type(typ);
+ ret = _try_convert_from_ctypes_type(typ);
+ if ((PyObject *)ret != Py_NotImplemented) {
+ return ret;
}
+ Py_DECREF(ret);
/* All other classes are treated as object */
return PyArray_DescrFromType(NPY_OBJECT);
@@ -1445,22 +1458,21 @@ _convert_from_any(PyObject *obj, int align)
return NULL;
}
else {
- PyArray_Descr *ret;
- if (_arraydescr_from_dtype_attr(obj, &ret)) {
- /*
- * Using dtype attribute, ret may be NULL if a
- * RecursionError occurred.
- */
+ PyArray_Descr *ret = _try_convert_from_dtype_attr(obj);
+ if ((PyObject *)ret != Py_NotImplemented) {
return ret;
}
+ Py_DECREF(ret);
/*
- * Note: this comes after _arraydescr_from_dtype_attr because the ctypes
+ * Note: this comes after _try_convert_from_dtype_attr because the ctypes
* type might override the dtype if numpy does not otherwise
* support it.
*/
- if (npy_ctypes_check(Py_TYPE(obj))) {
- return _arraydescr_from_ctypes_type(Py_TYPE(obj));
+ ret = _try_convert_from_ctypes_type(Py_TYPE(obj));
+ if ((PyObject *)ret != Py_NotImplemented) {
+ return ret;
}
+ Py_DECREF(ret);
_report_generic_error();
return NULL;
}
diff --git a/numpy/core/src/multiarray/descriptor.h b/numpy/core/src/multiarray/descriptor.h
index fe7dc6f9b..fc9e0895b 100644
--- a/numpy/core/src/multiarray/descriptor.h
+++ b/numpy/core/src/multiarray/descriptor.h
@@ -7,8 +7,8 @@ NPY_NO_EXPORT PyObject *arraydescr_protocol_descr_get(PyArray_Descr *self);
NPY_NO_EXPORT PyObject *
array_set_typeDict(PyObject *NPY_UNUSED(ignored), PyObject *args);
-int
-_arraydescr_from_dtype_attr(PyObject *obj, PyArray_Descr **newdescr);
+NPY_NO_EXPORT PyArray_Descr *
+_arraydescr_try_convert_from_dtype_attr(PyObject *obj);
NPY_NO_EXPORT int
diff --git a/numpy/core/src/multiarray/scalarapi.c b/numpy/core/src/multiarray/scalarapi.c
index 3e5e01e01..3a66df454 100644
--- a/numpy/core/src/multiarray/scalarapi.c
+++ b/numpy/core/src/multiarray/scalarapi.c
@@ -425,14 +425,10 @@ PyArray_ScalarFromObject(PyObject *object)
NPY_NO_EXPORT PyArray_Descr *
PyArray_DescrFromTypeObject(PyObject *type)
{
- int typenum;
- PyArray_Descr *new, *conv = NULL;
-
/* if it's a builtin type, then use the typenumber */
- typenum = _typenum_fromtypeobj(type,1);
+ int typenum = _typenum_fromtypeobj(type,1);
if (typenum != NPY_NOTYPE) {
- new = PyArray_DescrFromType(typenum);
- return new;
+ return PyArray_DescrFromType(typenum);
}
/* Check the generic types */
@@ -470,11 +466,12 @@ PyArray_DescrFromTypeObject(PyObject *type)
/* Do special thing for VOID sub-types */
if (PyType_IsSubtype((PyTypeObject *)type, &PyVoidArrType_Type)) {
- new = PyArray_DescrNewFromType(NPY_VOID);
+ PyArray_Descr *new = PyArray_DescrNewFromType(NPY_VOID);
if (new == NULL) {
return NULL;
}
- if (_arraydescr_from_dtype_attr(type, &conv)) {
+ PyArray_Descr *conv = _arraydescr_try_convert_from_dtype_attr(type);
+ if ((PyObject *)conv != Py_NotImplemented) {
if (conv == NULL) {
Py_DECREF(new);
return NULL;
@@ -486,8 +483,8 @@ PyArray_DescrFromTypeObject(PyObject *type)
new->elsize = conv->elsize;
new->subarray = conv->subarray;
conv->subarray = NULL;
- Py_DECREF(conv);
}
+ Py_DECREF(conv);
Py_XDECREF(new->typeobj);
new->typeobj = (PyTypeObject *)type;
Py_INCREF(type);