summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2019-12-02 15:48:59 -0800
committerGitHub <noreply@github.com>2019-12-02 15:48:59 -0800
commitdc94b2f0f8618f11c045f361859b8c0a3314a40b (patch)
treef2ac891a472c1d652dc84b66ea976b7ef0c39fc2 /numpy
parent03d489735e863e27f3e6ce39b8a85eca440c0231 (diff)
parent4af600d10b3edac291e5a2072b3d909e7a3568ae (diff)
downloadnumpy-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.c184
-rw-r--r--numpy/core/tests/test_multiarray.py23
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.