diff options
| author | Sebastian Berg <sebastian@sipsolutions.net> | 2021-11-12 15:45:26 -0600 |
|---|---|---|
| committer | Sebastian Berg <sebastian@sipsolutions.net> | 2021-11-12 15:45:26 -0600 |
| commit | f31c4a66ad27b428b6a20f9fa28c1b33854ea949 (patch) | |
| tree | 00fe1a10a557393287d64176c667805ef48dc612 /numpy | |
| parent | 84951a63df4dce887f31969e2a109936b368198a (diff) | |
| download | numpy-f31c4a66ad27b428b6a20f9fa28c1b33854ea949.tar.gz | |
MAINT,BUG: Refactor __array__ and never-copy to move check later
Doing the check before calling `PyArray_FromArrayAttr` means
we look up the attribute twice.
It further fixes two bugs:
1. The reference counting was wrong.
2. In debug mode there was a failure for some deprecation warnings
(probably due to error propagation)
Diffstat (limited to 'numpy')
| -rw-r--r-- | numpy/core/src/multiarray/ctors.c | 61 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/ctors.h | 4 |
2 files changed, 50 insertions, 15 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 7c3ac61c0..3f1d7835e 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -1349,13 +1349,7 @@ _array_from_array_like(PyObject *op, * this should be changed! */ if (!writeable && tmp == Py_NotImplemented) { - PyObject* array_meth = PyArray_LookupSpecial_OnInstance(op, "__array__"); - int has_get = array_meth && PyType_Check(op) && PyObject_HasAttrString(array_meth, "__get__"); - if (array_meth != NULL && !has_get && allow_copy) { - PyErr_SetString(PyExc_ValueError, "Calling __array__ in never copy mode is not allowed."); - return NULL; - } - tmp = PyArray_FromArrayAttr(op, requested_dtype, context); + tmp = PyArray_FromArrayAttr_int(op, requested_dtype, allow_copy); if (tmp == NULL) { return NULL; } @@ -2463,18 +2457,30 @@ PyArray_FromInterface(PyObject *origin) return NULL; } -/*NUMPY_API + +/** + * Check for an __array__ attribute and call it when it exists. + * + * .. warning: + * If returned, `NotImplemented` is borrowed and must not be Decref'd + * + * @param op The Python object to convert to an array. + * @param descr The desired `arr.dtype`, passed into the `__array__` call, + * as information but is not checked/enforced! + * @param never_copy Indicator that a copy is not allowed. + * NOTE: Currently, this means an error is raised instead of calling + * `op.__array__()`. In the future we could call for example call + * `op.__array__(never_copy=True)` instead. + * @returns NotImplemented if `__array__` is not defined or a NumPy array + * (or subclass). On error, return NULL. */ NPY_NO_EXPORT PyObject * -PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) +PyArray_FromArrayAttr_int( + PyObject *op, PyArray_Descr *descr, int never_copy) { PyObject *new; PyObject *array_meth; - if (context != NULL) { - PyErr_SetString(PyExc_RuntimeError, "'context' must be NULL"); - return NULL; - } array_meth = PyArray_LookupSpecial_OnInstance(op, "__array__"); if (array_meth == NULL) { if (PyErr_Occurred()) { @@ -2490,6 +2496,16 @@ PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) } return Py_NotImplemented; } + if (never_copy) { + /* Currently, we must always assume that `__array__` returns a copy */ + PyErr_SetString(PyExc_ValueError, + "Unable to avoid copy while converting from an object " + "implementing the `__array__` protocol. NumPy cannot ensure " + "that no copy will be made."); + Py_DECREF(array_meth); + return NULL; + } + if (PyType_Check(op) && PyObject_HasAttrString(array_meth, "__get__")) { /* * If the input is a class `array_meth` may be a property-like object. @@ -2500,11 +2516,11 @@ PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) Py_DECREF(array_meth); return Py_NotImplemented; } - if (typecode == NULL) { + if (descr == NULL) { new = PyObject_CallFunction(array_meth, NULL); } else { - new = PyObject_CallFunction(array_meth, "O", typecode); + new = PyObject_CallFunction(array_meth, "O", descr); } Py_DECREF(array_meth); if (new == NULL) { @@ -2520,6 +2536,21 @@ PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) return new; } + +/*NUMPY_API + */ +NPY_NO_EXPORT PyObject * +PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) +{ + if (context != NULL) { + PyErr_SetString(PyExc_RuntimeError, "'context' must be NULL"); + return NULL; + } + + return PyArray_FromArrayAttr_int(op, typecode, 0); +} + + /*NUMPY_API * new reference -- accepts NULL for mintype */ diff --git a/numpy/core/src/multiarray/ctors.h b/numpy/core/src/multiarray/ctors.h index cf01a6256..2f9e8547d 100644 --- a/numpy/core/src/multiarray/ctors.h +++ b/numpy/core/src/multiarray/ctors.h @@ -53,6 +53,10 @@ NPY_NO_EXPORT PyObject * PyArray_FromInterface(PyObject *input); NPY_NO_EXPORT PyObject * +PyArray_FromArrayAttr_int( + PyObject *op, PyArray_Descr *descr, int never_copy); + +NPY_NO_EXPORT PyObject * PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context); |
