diff options
author | Sebastian Berg <sebastian@sipsolutions.net> | 2021-02-16 17:00:08 -0600 |
---|---|---|
committer | Sebastian Berg <sebastian@sipsolutions.net> | 2021-05-12 16:05:03 -0700 |
commit | 1a828f525d2737bfe93e91034603bb2f4f3414db (patch) | |
tree | eeba156a31f5afedde5ed2a7371b22d953c8f5cb | |
parent | 6f5ad737691433b39953663c904e9d330fa38332 (diff) | |
download | numpy-1a828f525d2737bfe93e91034603bb2f4f3414db.tar.gz |
DEP: Ensure the string promotion FutureWarning is raised
Promotion errors are currently ignored and instead we use `object`
as dtype. This means that the FutureWarning is ignored when raised.
It also means that there is no way to opt into "future" behaviour,
although arguably, we may want to force `dtype=object` in any case
if a promotion error occurred (or some signal at least).
Closes gh-18721
Addresses gh-18425 (Does not actually fix it, but chances are we won't)
-rw-r--r-- | doc/release/upcoming_changes/18116.future.rst | 8 | ||||
-rw-r--r-- | numpy/core/src/multiarray/array_coercion.c | 8 | ||||
-rw-r--r-- | numpy/core/tests/test_deprecations.py | 5 | ||||
-rw-r--r-- | numpy/core/tests/test_regression.py | 16 | ||||
-rw-r--r-- | numpy/ma/tests/test_mrecords.py | 2 |
5 files changed, 20 insertions, 19 deletions
diff --git a/doc/release/upcoming_changes/18116.future.rst b/doc/release/upcoming_changes/18116.future.rst index 1341d022f..1eb14d5f7 100644 --- a/doc/release/upcoming_changes/18116.future.rst +++ b/doc/release/upcoming_changes/18116.future.rst @@ -11,9 +11,8 @@ are: a string result. * `numpy.array` and related functions will start returning ``object`` arrays because these functions use ``object`` as a fallback when - no common dtype can be found. (In this case setting the - ``FutureWarning`` to be raised will unfortunately lead to the new - behaviour) + no common dtype can be found. However, it may happen that future + releases of NumPy will generally error in these cases. This will mainly affect code such as:: @@ -24,6 +23,7 @@ and:: np.concatenate((['string'], [0])) in both cases adding ``dtype="U"`` or ``dtype="S"`` will give the -previous (string) result. +previous (string) result, while ``dtype=object`` will ensure an array with +object dtype is returned. Comparisons, universal functions, and casting are not affected by this. diff --git a/numpy/core/src/multiarray/array_coercion.c b/numpy/core/src/multiarray/array_coercion.c index ef99ae479..6b7c3888d 100644 --- a/numpy/core/src/multiarray/array_coercion.c +++ b/numpy/core/src/multiarray/array_coercion.c @@ -622,8 +622,12 @@ handle_promotion(PyArray_Descr **out_descr, PyArray_Descr *descr, } PyArray_Descr *new_descr = PyArray_PromoteTypes(descr, *out_descr); if (NPY_UNLIKELY(new_descr == NULL)) { - if (fixed_DType != NULL) { - /* If a DType is fixed, promotion must not fail. */ + if (fixed_DType != NULL || PyErr_ExceptionMatches(PyExc_FutureWarning)) { + /* + * If a DType is fixed, promotion must not fail. Do not catch + * FutureWarning (raised for string+numeric promotions). We could + * only catch TypeError here or even always raise the error. + */ return -1; } PyErr_Clear(); diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py index ec4112e69..ed1688374 100644 --- a/numpy/core/tests/test_deprecations.py +++ b/numpy/core/tests/test_deprecations.py @@ -1121,10 +1121,7 @@ class TestStringPromotion(_DeprecationTestCase): self.assert_deprecated(lambda: np.concatenate((arr1, arr2), axis=0)) self.assert_deprecated(lambda: np.concatenate((arr1, arr2), axis=None)) - # coercing to an array is similar, but will fall-back to `object` - # (when raising the FutureWarning, this already happens) - self.assert_deprecated(lambda: np.array([arr1[0], arr2[0]]), - exceptions=()) + self.assert_deprecated(lambda: np.array([arr1[0], arr2[0]])) @pytest.mark.parametrize("dtype", "?bhilqpBHILQPefdgFDG") @pytest.mark.parametrize("string_dt", ["S", "U"]) diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index d1af7f1d8..25198bba9 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -503,8 +503,8 @@ class TestRegression: assert_equal(np.arange(4, dtype='<c8').real.max(), 3.0) def test_object_array_from_list(self): - # Ticket #270 - assert_(np.array([1, 'A', None]).shape == (3,)) + # Ticket #270 (gh-868) + assert_(np.array([1, None, 'A']).shape == (3,)) def test_multiple_assign(self): # Ticket #273 @@ -2052,18 +2052,18 @@ class TestRegression: def test_string_truncation(self): # Ticket #1990 - Data can be truncated in creation of an array from a - # mixed sequence of numeric values and strings + # mixed sequence of numeric values and strings (gh-2583) for val in [True, 1234, 123.4, complex(1, 234)]: - for tostr in [asunicode, asbytes]: - b = np.array([val, tostr('xx')]) + for tostr, dtype in [(asunicode, "U"), (asbytes, "S")]: + b = np.array([val, tostr('xx')], dtype=dtype) assert_equal(tostr(b[0]), tostr(val)) - b = np.array([tostr('xx'), val]) + b = np.array([tostr('xx'), val], dtype=dtype) assert_equal(tostr(b[1]), tostr(val)) # test also with longer strings - b = np.array([val, tostr('xxxxxxxxxx')]) + b = np.array([val, tostr('xxxxxxxxxx')], dtype=dtype) assert_equal(tostr(b[0]), tostr(val)) - b = np.array([tostr('xxxxxxxxxx'), val]) + b = np.array([tostr('xxxxxxxxxx'), val], dtype=dtype) assert_equal(tostr(b[1]), tostr(val)) def test_string_truncation_ucs2(self): diff --git a/numpy/ma/tests/test_mrecords.py b/numpy/ma/tests/test_mrecords.py index c2f859273..27df519d2 100644 --- a/numpy/ma/tests/test_mrecords.py +++ b/numpy/ma/tests/test_mrecords.py @@ -405,7 +405,7 @@ class TestMRecordsImport: for (f, l) in zip(('a', 'b', 'c'), (_a, _b, _c)): assert_equal(getattr(mrec, f)._mask, l._mask) # One record only - _x = ma.array([1, 1.1, 'one'], mask=[1, 0, 0],) + _x = ma.array([1, 1.1, 'one'], mask=[1, 0, 0], dtype=object) assert_equal_records(fromarrays(_x, dtype=mrec.dtype), mrec[0]) def test_fromrecords(self): |