diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2020-07-28 10:49:18 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-28 10:49:18 -0600 |
commit | 62ca9df412a83d2e641de12e04b776cb3dcdbe66 (patch) | |
tree | dad560c73468f4d0e03187b3661c570a1284931c | |
parent | 4690248dd48e11e57167da20e54dc21a5d853bfa (diff) | |
parent | 592040713bf2100e96f76db143f58477f5c48513 (diff) | |
download | numpy-62ca9df412a83d2e641de12e04b776cb3dcdbe66.tar.gz |
Merge pull request #16941 from seberg/types-are-not-arraylikes
BUG: Allow array-like types to be coerced as object array elements
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 33 | ||||
-rw-r--r-- | numpy/core/tests/test_array_coercion.py | 27 |
2 files changed, 58 insertions, 2 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index cb448756b..dc451685a 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -1748,6 +1748,15 @@ PyArray_FromStructInterface(PyObject *input) } } if (!NpyCapsule_Check(attr)) { + if (PyType_Check(input) && PyObject_HasAttrString(attr, "__get__")) { + /* + * If the input is a class `attr` should be a property-like object. + * This cannot be interpreted as an array, but is a valid. + * (Needed due to the lookup being on the instance rather than type) + */ + Py_DECREF(attr); + return Py_NotImplemented; + } goto fail; } inter = NpyCapsule_AsVoidPtr(attr); @@ -1844,8 +1853,8 @@ PyArray_FromInterface(PyObject *origin) npy_intp dims[NPY_MAXDIMS], strides[NPY_MAXDIMS]; int dataflags = NPY_ARRAY_BEHAVED; - iface = PyArray_LookupSpecial_OnInstance(origin, - "__array_interface__"); + iface = PyArray_LookupSpecial_OnInstance(origin, "__array_interface__"); + if (iface == NULL) { if (PyErr_Occurred()) { PyErr_Clear(); /* TODO[gh-14801]: propagate crashes during attribute access? */ @@ -1853,6 +1862,16 @@ PyArray_FromInterface(PyObject *origin) return Py_NotImplemented; } if (!PyDict_Check(iface)) { + if (PyType_Check(origin) && PyObject_HasAttrString(iface, "__get__")) { + /* + * If the input is a class `iface` should be a property-like object. + * This cannot be interpreted as an array, but is a valid. + * (Needed due to the lookup being on the instance rather than type) + */ + Py_DECREF(iface); + return Py_NotImplemented; + } + Py_DECREF(iface); PyErr_SetString(PyExc_ValueError, "Invalid __array_interface__ value, must be a dict"); @@ -2119,6 +2138,16 @@ PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) } return Py_NotImplemented; } + if (PyType_Check(op) && PyObject_HasAttrString(array_meth, "__get__")) { + /* + * If the input is a class `array_meth` may be a property-like object. + * This cannot be interpreted as an array (called), but is a valid. + * Trying `array_meth.__call__()` on this should not be useful. + * (Needed due to the lookup being on the instance rather than type) + */ + Py_DECREF(array_meth); + return Py_NotImplemented; + } if (typecode == NULL) { new = PyObject_CallFunction(array_meth, NULL); } diff --git a/numpy/core/tests/test_array_coercion.py b/numpy/core/tests/test_array_coercion.py index 07a4c5c22..d18df2e9c 100644 --- a/numpy/core/tests/test_array_coercion.py +++ b/numpy/core/tests/test_array_coercion.py @@ -570,3 +570,30 @@ class TestArrayLikes: with pytest.raises(ValueError): # The error type does not matter much here. np.array([obj]) + + def test_arraylike_classes(self): + # The classes of array-likes should generally be acceptable to be + # stored inside a numpy (object) array. This tests all of the + # special attributes (since all are checked during coercion). + arr = np.array(np.int64) + assert arr[()] is np.int64 + arr = np.array([np.int64]) + assert arr[0] is np.int64 + + # This also works for properties/unbound methods: + class ArrayLike: + @property + def __array_interface__(self): + pass + + @property + def __array_struct__(self): + pass + + def __array__(self): + pass + + arr = np.array(ArrayLike) + assert arr[()] is ArrayLike + arr = np.array([ArrayLike]) + assert arr[0] is ArrayLike |