From 0fecd046cd685f4fa0c6f83c65cf83085b567d6a Mon Sep 17 00:00:00 2001 From: moink Date: Sun, 27 Dec 2020 15:32:49 +0100 Subject: [PATCH 1/6] TST: GH30999 Add match=msg to all pytest.raises in tests/reductions and add error message to nanmedian --- pandas/core/nanops.py | 2 +- pandas/tests/reductions/test_reductions.py | 40 ++++++++++++++----- .../tests/reductions/test_stat_reductions.py | 15 +++++-- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/pandas/core/nanops.py b/pandas/core/nanops.py index 88662a4fabed8..356c54e80f0ca 100644 --- a/pandas/core/nanops.py +++ b/pandas/core/nanops.py @@ -685,7 +685,7 @@ def get_median(x): values = values.astype("f8") except ValueError as err: # e.g. "could not convert string to float: 'a'" - raise TypeError from err + raise TypeError(str(err)) from err if mask is not None: values[mask] = np.nan diff --git a/pandas/tests/reductions/test_reductions.py b/pandas/tests/reductions/test_reductions.py index 8c2297699807d..fb37ad242bbd5 100644 --- a/pandas/tests/reductions/test_reductions.py +++ b/pandas/tests/reductions/test_reductions.py @@ -526,9 +526,17 @@ def test_numpy_minmax_period(self): def test_min_max_categorical(self): ci = pd.CategoricalIndex(list("aabbca"), categories=list("cab"), ordered=False) - with pytest.raises(TypeError): + msg = ( + r"Categorical is not ordered for operation min\n" + r"you can use .as_ordered\(\) to change the Categorical to an ordered one\n" + ) + with pytest.raises(TypeError, match=msg): ci.min() - with pytest.raises(TypeError): + msg = ( + r"Categorical is not ordered for operation max\n" + r"you can use .as_ordered\(\) to change the Categorical to an ordered one\n" + ) + with pytest.raises(TypeError, match=msg): ci.max() ci = pd.CategoricalIndex(list("aabbca"), categories=list("cab"), ordered=True) @@ -880,16 +888,18 @@ def test_all_any_params(self): tm.assert_series_equal(s.all(level=0), Series([False, True, False])) tm.assert_series_equal(s.any(level=0), Series([False, True, True])) - # bool_only is not implemented with level option. - with pytest.raises(NotImplementedError): + msg = "Option bool_only is not implemented with option level" + with pytest.raises(NotImplementedError, match=msg): s.any(bool_only=True, level=0) - with pytest.raises(NotImplementedError): + with pytest.raises(NotImplementedError, match=msg): s.all(bool_only=True, level=0) # bool_only is not implemented alone. - with pytest.raises(NotImplementedError): + msg = "Series.any does not implement numeric_only" + with pytest.raises(NotImplementedError, match=msg): s.any(bool_only=True) - with pytest.raises(NotImplementedError): + msg = "Series.all does not implement numeric_only." + with pytest.raises(NotImplementedError, match=msg): s.all(bool_only=True) def test_all_any_boolean(self): @@ -980,13 +990,21 @@ def test_assert_idxminmax_raises(self, test_input, error_type): """ Cases where ``Series.argmax`` and related should raise an exception """ - with pytest.raises(error_type): + msg = ( + "reduction operation 'argmin' not allowed for this dtype|" + "attempt to get argmin of an empty sequence" + ) + with pytest.raises(error_type, match=msg): test_input.idxmin() - with pytest.raises(error_type): + with pytest.raises(error_type, match=msg): test_input.idxmin(skipna=False) - with pytest.raises(error_type): + msg = ( + "reduction operation 'argmax' not allowed for this dtype|" + "attempt to get argmax of an empty sequence" + ) + with pytest.raises(error_type, match=msg): test_input.idxmax() - with pytest.raises(error_type): + with pytest.raises(error_type, match=msg): test_input.idxmax(skipna=False) def test_idxminmax_with_inf(self): diff --git a/pandas/tests/reductions/test_stat_reductions.py b/pandas/tests/reductions/test_stat_reductions.py index 67e871f8b67c2..d764f0ef9b29a 100644 --- a/pandas/tests/reductions/test_stat_reductions.py +++ b/pandas/tests/reductions/test_stat_reductions.py @@ -98,7 +98,8 @@ def _check_stat_op( # mean, idxmax, idxmin, min, and max are valid for dates if name not in ["max", "min", "mean", "median", "std"]: ds = Series(pd.date_range("1/1/2001", periods=10)) - with pytest.raises(TypeError): + msg = f"'DatetimeArray' does not implement reduction '{name}'" + with pytest.raises(TypeError, match=msg): f(ds) # skipna or no @@ -132,13 +133,21 @@ def _check_stat_op( exp = alternate(s) assert res == exp + # Series.median(Series('abc')) # check on string data + msg = ( + "could not convert string to float|" + r"complex\(\) arg is a malformed string|" + "can't multiply sequence by non-int of type 'str'|" + "Could not convert abc to numeric" + ) if name not in ["sum", "min", "max"]: - with pytest.raises(TypeError): + with pytest.raises(TypeError, match=msg): f(Series(list("abc"))) # Invalid axis. - with pytest.raises(ValueError): + msg = "No axis named 1 for object type Series" + with pytest.raises(ValueError, match=msg): f(string_series_, axis=1) # Unimplemented numeric_only parameter. From f5bebe29a3958ecf310dc6c711cd1740c6f5d7fb Mon Sep 17 00:00:00 2001 From: moink Date: Sun, 27 Dec 2020 18:36:56 +0100 Subject: [PATCH 2/6] TST: GH30999 Be more specific about what error message goes with what method in _check_stat_op --- pandas/tests/reductions/test_stat_reductions.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pandas/tests/reductions/test_stat_reductions.py b/pandas/tests/reductions/test_stat_reductions.py index d764f0ef9b29a..a84a67f21c410 100644 --- a/pandas/tests/reductions/test_stat_reductions.py +++ b/pandas/tests/reductions/test_stat_reductions.py @@ -135,13 +135,15 @@ def _check_stat_op( # Series.median(Series('abc')) # check on string data - msg = ( - "could not convert string to float|" - r"complex\(\) arg is a malformed string|" - "can't multiply sequence by non-int of type 'str'|" - "Could not convert abc to numeric" - ) - if name not in ["sum", "min", "max"]: + + if name == "prod": + with tm.external_error_raised(TypeError): + f(Series(list("abc"))) + elif name not in ["sum", "min", "max"]: + if name == "mean": + msg = "Could not convert abc to numeric" + else: + msg = "could not convert string to float" with pytest.raises(TypeError, match=msg): f(Series(list("abc"))) From 3858d43b329c635246b74b8c89b9c5e6959e2995 Mon Sep 17 00:00:00 2001 From: moink Date: Mon, 28 Dec 2020 10:40:01 +0100 Subject: [PATCH 3/6] TST: GH30999 revert complex logic for setting error message to match based on PR feedback Pass None, which means it matches any message. --- pandas/tests/reductions/test_stat_reductions.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/pandas/tests/reductions/test_stat_reductions.py b/pandas/tests/reductions/test_stat_reductions.py index a84a67f21c410..ab13893901104 100644 --- a/pandas/tests/reductions/test_stat_reductions.py +++ b/pandas/tests/reductions/test_stat_reductions.py @@ -133,18 +133,9 @@ def _check_stat_op( exp = alternate(s) assert res == exp - # Series.median(Series('abc')) # check on string data - - if name == "prod": - with tm.external_error_raised(TypeError): - f(Series(list("abc"))) - elif name not in ["sum", "min", "max"]: - if name == "mean": - msg = "Could not convert abc to numeric" - else: - msg = "could not convert string to float" - with pytest.raises(TypeError, match=msg): + if name not in ["sum", "min", "max"]: + with pytest.raises(TypeError, match=None): f(Series(list("abc"))) # Invalid axis. From bee21902eb7086fbd72b48f166040508f97b9f1f Mon Sep 17 00:00:00 2001 From: moink Date: Wed, 30 Dec 2020 15:01:29 +0100 Subject: [PATCH 4/6] TST: GH30999 change error message returned by Series.any and Series.all when bool_only is passed --- pandas/core/generic.py | 25 ++++++++++++++-------- pandas/tests/reductions/test_reductions.py | 4 ++-- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 4f588075bc830..33d4eeb2c28a4 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -10351,15 +10351,22 @@ def _logical_func( name, func, axis=0, bool_only=bool_only, skipna=skipna, **kwargs ) return res._logical_func(name, func, skipna=skipna, **kwargs) - - return self._reduce( - func, - name=name, - axis=axis, - skipna=skipna, - numeric_only=bool_only, - filter_type="bool", - ) + try: + return self._reduce( + func, + name=name, + axis=axis, + skipna=skipna, + numeric_only=bool_only, + filter_type="bool", + ) + except NotImplementedError as exc: + err_msg = str(exc) + if err_msg.endswith("does not implement numeric_only."): + raise NotImplementedError( + err_msg.replace("numeric_only", "bool_only") + ) from exc + raise def any(self, axis=0, bool_only=None, skipna=True, level=None, **kwargs): return self._logical_func( diff --git a/pandas/tests/reductions/test_reductions.py b/pandas/tests/reductions/test_reductions.py index fb37ad242bbd5..e5443fbd0351b 100644 --- a/pandas/tests/reductions/test_reductions.py +++ b/pandas/tests/reductions/test_reductions.py @@ -895,10 +895,10 @@ def test_all_any_params(self): s.all(bool_only=True, level=0) # bool_only is not implemented alone. - msg = "Series.any does not implement numeric_only" + msg = "Series.any does not implement bool_only" with pytest.raises(NotImplementedError, match=msg): s.any(bool_only=True) - msg = "Series.all does not implement numeric_only." + msg = "Series.all does not implement bool_only." with pytest.raises(NotImplementedError, match=msg): s.all(bool_only=True) From ff21d3b7e8d410a51aa34065b2e1d909b6005241 Mon Sep 17 00:00:00 2001 From: moink Date: Wed, 30 Dec 2020 15:33:59 +0100 Subject: [PATCH 5/6] TST: GH30999 Revert previous commit, add TODO for issue 38810 --- pandas/core/generic.py | 24 ++++++++-------------- pandas/tests/reductions/test_reductions.py | 6 ++++-- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 33d4eeb2c28a4..95bc566060cb6 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -10351,22 +10351,14 @@ def _logical_func( name, func, axis=0, bool_only=bool_only, skipna=skipna, **kwargs ) return res._logical_func(name, func, skipna=skipna, **kwargs) - try: - return self._reduce( - func, - name=name, - axis=axis, - skipna=skipna, - numeric_only=bool_only, - filter_type="bool", - ) - except NotImplementedError as exc: - err_msg = str(exc) - if err_msg.endswith("does not implement numeric_only."): - raise NotImplementedError( - err_msg.replace("numeric_only", "bool_only") - ) from exc - raise + return self._reduce( + func, + name=name, + axis=axis, + skipna=skipna, + numeric_only=bool_only, + filter_type="bool", + ) def any(self, axis=0, bool_only=None, skipna=True, level=None, **kwargs): return self._logical_func( diff --git a/pandas/tests/reductions/test_reductions.py b/pandas/tests/reductions/test_reductions.py index e5443fbd0351b..473e836be8e50 100644 --- a/pandas/tests/reductions/test_reductions.py +++ b/pandas/tests/reductions/test_reductions.py @@ -895,10 +895,12 @@ def test_all_any_params(self): s.all(bool_only=True, level=0) # bool_only is not implemented alone. - msg = "Series.any does not implement bool_only" + # TODO GH38810 change this error message to: + # "Series.any does not implement bool_only" + msg = "Series.any does not implement numeric_only" with pytest.raises(NotImplementedError, match=msg): s.any(bool_only=True) - msg = "Series.all does not implement bool_only." + msg = "Series.all does not implement numeric_only." with pytest.raises(NotImplementedError, match=msg): s.all(bool_only=True) From 35eceb9d5396306be11046c63d21394d15998b23 Mon Sep 17 00:00:00 2001 From: moink Date: Wed, 30 Dec 2020 15:41:08 +0100 Subject: [PATCH 6/6] TST: GH30999 add back random blank line --- pandas/core/generic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 95bc566060cb6..4f588075bc830 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -10351,6 +10351,7 @@ def _logical_func( name, func, axis=0, bool_only=bool_only, skipna=skipna, **kwargs ) return res._logical_func(name, func, skipna=skipna, **kwargs) + return self._reduce( func, name=name,