diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2019-12-02 15:48:59 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-02 15:48:59 -0800 |
commit | dc94b2f0f8618f11c045f361859b8c0a3314a40b (patch) | |
tree | f2ac891a472c1d652dc84b66ea976b7ef0c39fc2 /numpy | |
parent | 03d489735e863e27f3e6ce39b8a85eca440c0231 (diff) | |
parent | 4af600d10b3edac291e5a2072b3d909e7a3568ae (diff) | |
download | numpy-dc94b2f0f8618f11c045f361859b8c0a3314a40b.tar.gz |
Merge pull request #15027 from charris/revert-71fc59d
REV: "ENH: Improved performance of PyArray_FromAny for sequences of a…"
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 184 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 23 |
2 files changed, 62 insertions, 145 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 64933ae1b..7276add75 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -453,10 +453,6 @@ copy_and_swap(void *dst, void *src, int itemsize, npy_intp numitems, } } -NPY_NO_EXPORT PyObject * -_array_from_array_like(PyObject *op, PyArray_Descr *requested_dtype, - npy_bool writeable, PyObject *context); - /* * adapted from Numarray, * a: destination array @@ -477,6 +473,11 @@ setArrayFromSequence(PyArrayObject *a, PyObject *s, if (dst == NULL) dst = a; + /* + * This code is to ensure that the sequence access below will + * return a lower-dimensional sequence. + */ + /* INCREF on entry DECREF on exit */ Py_INCREF(s); @@ -502,11 +503,6 @@ setArrayFromSequence(PyArrayObject *a, PyObject *s, return 0; } - /* - * This code is to ensure that the sequence access below will - * return a lower-dimensional sequence. - */ - if (dim > PyArray_NDIM(a)) { PyErr_Format(PyExc_ValueError, "setArrayFromSequence: sequence/array dimensions mismatch."); @@ -517,27 +513,6 @@ setArrayFromSequence(PyArrayObject *a, PyObject *s, if (slen < 0) { goto fail; } - if (slen > 0) { - /* gh-13659: try __array__ before using s as a sequence */ - PyObject *tmp = _array_from_array_like(s, /*dtype*/NULL, /*writeable*/0, - /*context*/NULL); - if (tmp == NULL) { - goto fail; - } - else if (tmp == Py_NotImplemented) { - Py_DECREF(tmp); - } - else { - int r = PyArray_CopyInto(dst, (PyArrayObject *)tmp); - Py_DECREF(tmp); - if (r < 0) { - goto fail; - } - Py_DECREF(s); - return 0; - } - } - /* * Either the dimensions match, or the sequence has length 1 and can * be broadcast to the destination. @@ -1603,90 +1578,6 @@ fail: } - -/* - * Attempts to extract an array from an array-like object. - * - * array-like is defined as either - * - * * an object implementing the PEP 3118 buffer interface; - * * an object with __array_struct__ or __array_interface__ attributes; - * * an object with an __array__ function. - * - * Returns Py_NotImplemented if a given object is not array-like; - * PyArrayObject* in case of success and NULL in case of failure. - */ -NPY_NO_EXPORT PyObject * -_array_from_array_like(PyObject *op, PyArray_Descr *requested_dtype, - npy_bool writeable, PyObject *context) { - PyObject* tmp; - - /* If op supports the PEP 3118 buffer interface */ - if (!PyBytes_Check(op) && !PyUnicode_Check(op)) { - PyObject *memoryview = PyMemoryView_FromObject(op); - if (memoryview == NULL) { - PyErr_Clear(); - } - else { - tmp = _array_from_buffer_3118(memoryview); - Py_DECREF(memoryview); - if (tmp == NULL) { - return NULL; - } - - if (writeable - && PyArray_FailUnlessWriteable((PyArrayObject *) tmp, "PEP 3118 buffer") < 0) { - Py_DECREF(tmp); - return NULL; - } - - return tmp; - } - } - - /* If op supports the __array_struct__ or __array_interface__ interface */ - tmp = PyArray_FromStructInterface(op); - if (tmp == NULL) { - return NULL; - } - if (tmp == Py_NotImplemented) { - tmp = PyArray_FromInterface(op); - if (tmp == NULL) { - return NULL; - } - } - - /* - * If op supplies the __array__ function. - * The documentation says this should produce a copy, so - * we skip this method if writeable is true, because the intent - * of writeable is to modify the operand. - * XXX: If the implementation is wrong, and/or if actual - * usage requires this behave differently, - * this should be changed! - */ - if (!writeable && tmp == Py_NotImplemented) { - tmp = PyArray_FromArrayAttr(op, requested_dtype, context); - if (tmp == NULL) { - return NULL; - } - } - - if (tmp != Py_NotImplemented) { - if (writeable - && PyArray_FailUnlessWriteable((PyArrayObject *) tmp, - "array interface object") < 0) { - Py_DECREF(tmp); - return NULL; - } - return tmp; - } - - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - - /*NUMPY_API * Retrieves the array parameters for viewing/converting an arbitrary * PyObject* to a NumPy array. This allows the "innate type and shape" @@ -1794,20 +1685,69 @@ PyArray_GetArrayParamsFromObject(PyObject *op, return 0; } - /* If op is an array-like */ - tmp = _array_from_array_like(op, requested_dtype, writeable, context); + /* If op supports the PEP 3118 buffer interface */ + if (!PyBytes_Check(op) && !PyUnicode_Check(op)) { + + PyObject *memoryview = PyMemoryView_FromObject(op); + if (memoryview == NULL) { + PyErr_Clear(); + } + else { + PyObject *arr = _array_from_buffer_3118(memoryview); + Py_DECREF(memoryview); + if (arr == NULL) { + return -1; + } + if (writeable + && PyArray_FailUnlessWriteable((PyArrayObject *)arr, "PEP 3118 buffer") < 0) { + Py_DECREF(arr); + return -1; + } + *out_arr = (PyArrayObject *)arr; + return 0; + } + } + + /* If op supports the __array_struct__ or __array_interface__ interface */ + tmp = PyArray_FromStructInterface(op); if (tmp == NULL) { return -1; } - else if (tmp != Py_NotImplemented) { - *out_arr = (PyArrayObject*) tmp; - return 0; + if (tmp == Py_NotImplemented) { + tmp = PyArray_FromInterface(op); + if (tmp == NULL) { + return -1; + } } - else { - Py_DECREF(Py_NotImplemented); + if (tmp != Py_NotImplemented) { + if (writeable + && PyArray_FailUnlessWriteable((PyArrayObject *)tmp, + "array interface object") < 0) { + Py_DECREF(tmp); + return -1; + } + *out_arr = (PyArrayObject *)tmp; + return (*out_arr) == NULL ? -1 : 0; + } + + /* + * If op supplies the __array__ function. + * The documentation says this should produce a copy, so + * we skip this method if writeable is true, because the intent + * of writeable is to modify the operand. + * XXX: If the implementation is wrong, and/or if actual + * usage requires this behave differently, + * this should be changed! + */ + if (!writeable) { + tmp = PyArray_FromArrayAttr(op, requested_dtype, context); + if (tmp != Py_NotImplemented) { + *out_arr = (PyArrayObject *)tmp; + return (*out_arr) == NULL ? -1 : 0; + } } - /* Try to treat op as a list of lists or array-like objects. */ + /* Try to treat op as a list of lists */ if (!writeable && PySequence_Check(op)) { int check_it, stop_at_string, stop_at_tuple, is_object; int type_num, type; diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 218106a63..22d550ecc 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -970,29 +970,6 @@ class TestCreation(object): assert_equal(np.array([long(4), 2**80, long(4)]).dtype, object) assert_equal(np.array([2**80, long(4)]).dtype, object) - def test_sequence_of_array_like(self): - class ArrayLike: - def __init__(self): - self.__array_interface__ = { - "shape": (42,), - "typestr": "<i1", - "data": bytes(42) - } - - # Make sure __array_*__ is used instead of Sequence methods. - def __iter__(self): - raise AssertionError("__iter__ was called") - - def __getitem__(self, idx): - raise AssertionError("__getitem__ was called") - - def __len__(self): - return 42 - - assert_equal( - np.array([ArrayLike()]), - np.zeros((1, 42), dtype=np.byte)) - def test_non_sequence_sequence(self): """Should not segfault. |