summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2018-07-22 19:50:21 -0500
committerGitHub <noreply@github.com>2018-07-22 19:50:21 -0500
commit083aedba2f49e1b490d3e122f5927f0718cf202c (patch)
tree4168bd704df270ac788fcdd990be527f882685bc /numpy
parentbc021e4ae3232875fbbd13cdc74348f9893ed641 (diff)
parent9841981c3533d36582c2bd4d1fe24208de99f82f (diff)
downloadnumpy-083aedba2f49e1b490d3e122f5927f0718cf202c.tar.gz
Merge pull request #11601 from eric-wieser/list-ctor
BUG: Make np.array([[1], 2]) and np.array([1, [2]]) behave in the same way
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/ctors.c65
-rw-r--r--numpy/core/tests/test_multiarray.py31
2 files changed, 64 insertions, 32 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 7367902cc..938850997 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -666,7 +666,6 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it,
int *out_is_object)
{
PyObject *e;
- int r;
npy_intp n, i;
Py_buffer buffer_view;
PyObject * seq;
@@ -846,46 +845,48 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it,
return 0;
}
else {
- npy_intp dtmp[NPY_MAXDIMS];
- int j, maxndim_m1 = *maxndim - 1;
- e = PySequence_Fast_GET_ITEM(seq, 0);
-
- r = discover_dimensions(e, &maxndim_m1, d + 1, check_it,
- stop_at_string, stop_at_tuple,
- out_is_object);
- if (r < 0) {
+ int all_elems_maxndim = *maxndim - 1;
+ npy_intp *all_elems_d = d + 1;
+ int all_dimensions_match = 1;
+
+ /* Get the dimensions of the first item as a baseline */
+ PyObject *first = PySequence_Fast_GET_ITEM(seq, 0);
+ if (discover_dimensions(
+ first, &all_elems_maxndim, all_elems_d, check_it,
+ stop_at_string, stop_at_tuple, out_is_object) < 0) {
Py_DECREF(seq);
- return r;
+ return -1;
}
- /* For the dimension truncation check below */
- *maxndim = maxndim_m1 + 1;
+ /* Compare the dimensions of all the remaining items */
for (i = 1; i < n; ++i) {
- e = PySequence_Fast_GET_ITEM(seq, i);
- /* Get the dimensions of the first item */
- r = discover_dimensions(e, &maxndim_m1, dtmp, check_it,
- stop_at_string, stop_at_tuple,
- out_is_object);
- if (r < 0) {
+ int j;
+ int elem_maxndim = *maxndim - 1;
+ npy_intp elem_d[NPY_MAXDIMS];
+
+ PyObject *elem = PySequence_Fast_GET_ITEM(seq, i);
+ if (discover_dimensions(
+ elem, &elem_maxndim, elem_d, check_it,
+ stop_at_string, stop_at_tuple, out_is_object) < 0) {
Py_DECREF(seq);
- return r;
+ return -1;
}
- /* Reduce max_ndim_m1 to just items which match */
- for (j = 0; j < maxndim_m1; ++j) {
- if (dtmp[j] != d[j+1]) {
- maxndim_m1 = j;
+ /* Find the number of left-dimensions which match, j */
+ for (j = 0; j < elem_maxndim && j < all_elems_maxndim; ++j) {
+ if (elem_d[j] != all_elems_d[j]) {
break;
}
}
+ if (j != elem_maxndim || j != all_elems_maxndim) {
+ all_dimensions_match = 0;
+ }
+ all_elems_maxndim = j;
}
- /*
- * If the dimensions are truncated, need to produce
- * an object array.
- */
- if (maxndim_m1 + 1 < *maxndim) {
+ *maxndim = all_elems_maxndim + 1;
+ if (!all_dimensions_match) {
+ /* typically results in an array containing variable-length lists */
*out_is_object = 1;
- *maxndim = maxndim_m1 + 1;
}
}
@@ -1704,9 +1705,9 @@ PyArray_GetArrayParamsFromObject(PyObject *op,
*out_ndim = NPY_MAXDIMS;
is_object = 0;
- if (discover_dimensions(op, out_ndim, out_dims, check_it,
- stop_at_string, stop_at_tuple,
- &is_object) < 0) {
+ if (discover_dimensions(
+ op, out_ndim, out_dims, check_it,
+ stop_at_string, stop_at_tuple, &is_object) < 0) {
Py_DECREF(*out_dtype);
if (PyErr_Occurred()) {
return -1;
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index e85a73154..3812a20d8 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -688,6 +688,9 @@ class TestScalarIndexing(object):
class TestCreation(object):
+ """
+ Test the np.array constructor
+ """
def test_from_attribute(self):
class x(object):
def __array__(self, dtype=None):
@@ -903,6 +906,34 @@ class TestCreation(object):
assert_raises(ValueError, np.ndarray, buffer=buf, strides=(0,),
shape=(max_bytes//itemsize + 1,), dtype=dtype)
+ def test_jagged_ndim_object(self):
+ # Lists of mismatching depths are treated as object arrays
+ a = np.array([[1], 2, 3])
+ assert_equal(a.shape, (3,))
+ assert_equal(a.dtype, object)
+
+ a = np.array([1, [2], 3])
+ assert_equal(a.shape, (3,))
+ assert_equal(a.dtype, object)
+
+ a = np.array([1, 2, [3]])
+ assert_equal(a.shape, (3,))
+ assert_equal(a.dtype, object)
+
+ def test_jagged_shape_object(self):
+ # The jagged dimension of a list is turned into an object array
+ a = np.array([[1, 1], [2], [3]])
+ assert_equal(a.shape, (3,))
+ assert_equal(a.dtype, object)
+
+ a = np.array([[1], [2, 2], [3]])
+ assert_equal(a.shape, (3,))
+ assert_equal(a.dtype, object)
+
+ a = np.array([[1], [2], [3, 3]])
+ assert_equal(a.shape, (3,))
+ assert_equal(a.dtype, object)
+
class TestStructured(object):
def test_subarray_field_access(self):