diff options
Diffstat (limited to 'numpy/core')
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 28 | ||||
-rw-r--r-- | numpy/core/tests/test_deprecations.py | 10 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 50 | ||||
-rw-r--r-- | numpy/core/tests/test_numeric.py | 2 | ||||
-rw-r--r-- | numpy/core/tests/test_regression.py | 11 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 8 |
6 files changed, 83 insertions, 26 deletions
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 7276add75..c69782cb6 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -688,6 +688,12 @@ discover_itemsize(PyObject *s, int nd, int *itemsize, int string_type) return 0; } +typedef enum { + DISCOVERED_OK = 0, + DISCOVERED_RAGGED = 1, + DISCOVERED_OBJECT = 2 +} discovered_t; + /* * Take an arbitrary object and discover how many dimensions it * has, filling in the dimensions as we go. @@ -695,7 +701,7 @@ discover_itemsize(PyObject *s, int nd, int *itemsize, int string_type) static int discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it, int stop_at_string, int stop_at_tuple, - int *out_is_object) + discovered_t *out_is_object) { PyObject *e; npy_intp n, i; @@ -881,7 +887,7 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it, if (PyErr_ExceptionMatches(PyExc_KeyError)) { PyErr_Clear(); *maxndim = 0; - *out_is_object = 1; + *out_is_object = DISCOVERED_OBJECT; return 0; } else { @@ -940,7 +946,7 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it, *maxndim = all_elems_maxndim + 1; if (!all_dimensions_match) { /* typically results in an array containing variable-length lists */ - *out_is_object = 1; + *out_is_object = DISCOVERED_RAGGED; } } @@ -1749,7 +1755,7 @@ PyArray_GetArrayParamsFromObject(PyObject *op, /* 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 check_it, stop_at_string, stop_at_tuple; int type_num, type; /* @@ -1799,7 +1805,7 @@ PyArray_GetArrayParamsFromObject(PyObject *op, ((*out_dtype)->names || (*out_dtype)->subarray)); *out_ndim = NPY_MAXDIMS; - is_object = 0; + discovered_t is_object = DISCOVERED_OK; if (discover_dimensions( op, out_ndim, out_dims, check_it, stop_at_string, stop_at_tuple, &is_object) < 0) { @@ -1816,7 +1822,17 @@ PyArray_GetArrayParamsFromObject(PyObject *op, return 0; } /* If object arrays are forced */ - if (is_object) { + if (is_object != DISCOVERED_OK) { + if (is_object == DISCOVERED_RAGGED && requested_dtype == NULL) { + /* NumPy 1.18, 2019-11-01 */ + if (DEPRECATE("Creating an ndarray with automatic object " + "dtype is deprecated, use dtype=object if you intended " + "it, otherwise specify an exact dtype") < 0) + { + return -1; + } + } + /* either DISCOVERED_OBJECT or there is a requested_dtype */ Py_DECREF(*out_dtype); *out_dtype = PyArray_DescrFromType(NPY_OBJECT); if (*out_dtype == NULL) { diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index 363ff26db..de1d76857 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -568,3 +568,13 @@ class TestNonZero(_DeprecationTestCase): def test_zerod(self): self.assert_deprecated(lambda: np.nonzero(np.array(0))) self.assert_deprecated(lambda: np.nonzero(np.array(1))) + + +class TestRaggedArray(_DeprecationTestCase): + # 2019-11-29 1.18.0 + def test_deprecate_ragged_arrays(self): + # NEP 34 deprecated automatic object dtype when creating ragged + # arrays. Also see the "ragged" tests in `test_multiarray` + arg = [1, [2, 3]] + self.assert_deprecated(np.array, args=(arg,)) + diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 22d550ecc..0235c5063 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -448,7 +448,7 @@ class TestArrayConstruction(object): assert_equal(r, np.ones((2, 6, 6))) d = np.ones((6, )) - r = np.array([[d, d + 1], d + 2]) + r = np.array([[d, d + 1], d + 2], dtype=object) assert_equal(len(r), 2) assert_equal(r[0], [d, d + 1]) assert_equal(r[1], d + 2) @@ -1051,34 +1051,60 @@ 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): + def _ragged_creation(self, seq): + # without dtype=object, the ragged object should raise + with assert_warns(DeprecationWarning): + a = np.array(seq) + b = np.array(seq, dtype=object) + assert_equal(a, b) + return b + + def test_ragged_ndim_object(self): # Lists of mismatching depths are treated as object arrays - a = np.array([[1], 2, 3]) + a = self._ragged_creation([[1], 2, 3]) assert_equal(a.shape, (3,)) assert_equal(a.dtype, object) - a = np.array([1, [2], 3]) + a = self._ragged_creation([1, [2], 3]) assert_equal(a.shape, (3,)) assert_equal(a.dtype, object) - a = np.array([1, 2, [3]]) + a = self._ragged_creation([1, 2, [3]]) assert_equal(a.shape, (3,)) assert_equal(a.dtype, object) - def test_jagged_shape_object(self): + def test_ragged_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]]) + a = self._ragged_creation([[1, 1], [2], [3]]) assert_equal(a.shape, (3,)) assert_equal(a.dtype, object) - a = np.array([[1], [2], [3, 3]]) + a = self._ragged_creation([[1], [2, 2], [3]]) assert_equal(a.shape, (3,)) assert_equal(a.dtype, object) + a = self._ragged_creation([[1], [2], [3, 3]]) + assert a.shape == (3,) + assert a.dtype == object + + def test_array_of_ragged_array(self): + outer = np.array([None, None]) + outer[0] = outer[1] = np.array([1, 2, 3]) + assert np.array(outer).shape == (2,) + assert np.array([outer]).shape == (1, 2) + + outer_ragged = np.array([None, None]) + outer_ragged[0] = np.array([1, 2, 3]) + outer_ragged[1] = np.array([1, 2, 3, 4]) + # should both of these emit deprecation warnings? + assert np.array(outer_ragged).shape == (2,) + assert np.array([outer_ragged]).shape == (1, 2,) + + def test_deep_nonragged_object(self): + # None of these should raise, even though they are missing dtype=object + a = np.array([[[Decimal(1)]]]) + a = np.array([1, Decimal(1)]) + a = np.array([[1], [Decimal(1)]]) class TestStructured(object): def test_subarray_field_access(self): diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index ffebdf648..1f8c7e98d 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -1211,7 +1211,7 @@ class TestNonzero(object): def test_nonzero_invalid_object(self): # gh-9295 - a = np.array([np.array([1, 2]), 3]) + a = np.array([np.array([1, 2]), 3], dtype=object) assert_raises(ValueError, np.nonzero, a) class BoolErrors: diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 3880b1394..f3e170470 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -1367,13 +1367,13 @@ class TestRegression(object): def test_array_from_sequence_scalar_array(self): # Ticket #1078: segfaults when creating an array with a sequence of # 0d arrays. - a = np.array((np.ones(2), np.array(2))) + a = np.array((np.ones(2), np.array(2)), dtype=object) assert_equal(a.shape, (2,)) assert_equal(a.dtype, np.dtype(object)) assert_equal(a[0], np.ones(2)) assert_equal(a[1], np.array(2)) - a = np.array(((1,), np.array(1))) + a = np.array(((1,), np.array(1)), dtype=object) assert_equal(a.shape, (2,)) assert_equal(a.dtype, np.dtype(object)) assert_equal(a[0], (1,)) @@ -1381,7 +1381,7 @@ class TestRegression(object): def test_array_from_sequence_scalar_array2(self): # Ticket #1081: weird array with strange input... - t = np.array([np.array([]), np.array(0, object)]) + t = np.array([np.array([]), np.array(0, object)], dtype=object) assert_equal(t.shape, (2,)) assert_equal(t.dtype, np.dtype(object)) @@ -2290,9 +2290,10 @@ class TestRegression(object): x[0], x[-1] = x[-1], x[0] uf = np.frompyfunc(f, 1, 0) - a = np.array([[1, 2, 3], [4, 5], [6, 7, 8, 9]]) + a = np.array([[1, 2, 3], [4, 5], [6, 7, 8, 9]], dtype=object) assert_equal(uf(a), ()) - assert_array_equal(a, [[3, 2, 1], [5, 4], [9, 7, 8, 6]]) + expected = np.array([[3, 2, 1], [5, 4], [9, 7, 8, 6]], dtype=object) + assert_array_equal(a, expected) @pytest.mark.skipif(not HAS_REFCOUNT, reason="Python lacks refcounts") def test_leak_in_structured_dtype_comparison(self): diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 526925ece..d0173c76d 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -1124,14 +1124,18 @@ class TestUfunc(object): # Twice reproduced also for tuples: np.add.accumulate(arr, out=arr) np.add.accumulate(arr, out=arr) - assert_array_equal(arr, np.array([[1]*i for i in [1, 3, 6, 10]])) + assert_array_equal(arr, + np.array([[1]*i for i in [1, 3, 6, 10]], dtype=object), + ) # And the same if the axis argument is used arr = np.ones((2, 4), dtype=object) arr[0, :] = [[2] for i in range(4)] np.add.accumulate(arr, out=arr, axis=-1) np.add.accumulate(arr, out=arr, axis=-1) - assert_array_equal(arr[0, :], np.array([[2]*i for i in [1, 3, 6, 10]])) + assert_array_equal(arr[0, :], + np.array([[2]*i for i in [1, 3, 6, 10]], dtype=object), + ) def test_object_array_reduceat_inplace(self): # Checks that in-place reduceats work, see also gh-7465 |