diff --git a/pandas/tests/arrays/categorical/test_algos.py b/pandas/tests/arrays/categorical/test_algos.py index da142fa0bd63c..870a0a5db175e 100644 --- a/pandas/tests/arrays/categorical/test_algos.py +++ b/pandas/tests/arrays/categorical/test_algos.py @@ -60,17 +60,21 @@ def test_isin_cats(): @pytest.mark.parametrize( - "to_replace, value, result", - [("b", "c", ["a", "c"]), ("c", "d", ["a", "b"]), ("b", None, ["a", None])], + "to_replace, value, result, expected_error_msg", + [ + ("b", "c", ["a", "c"], "Categorical.categories are different"), + ("c", "d", ["a", "b"], None), + ("b", None, ["a", None], "Categorical.categories length are different"), + ], ) -def test_replace(to_replace, value, result): +def test_replace(to_replace, value, result, expected_error_msg): # GH 26988 cat = pd.Categorical(["a", "b"]) expected = pd.Categorical(result) result = cat.replace(to_replace, value) tm.assert_categorical_equal(result, expected) if to_replace == "b": # the "c" test is supposed to be unchanged - with pytest.raises(AssertionError): + with pytest.raises(AssertionError, match=expected_error_msg): # ensure non-inplace call does not affect original tm.assert_categorical_equal(cat, expected) cat.replace(to_replace, value, inplace=True) @@ -104,13 +108,21 @@ def test_take_positive_no_warning(self): def test_take_bounds(self, allow_fill): # https://github.com/pandas-dev/pandas/issues/20664 cat = pd.Categorical(["a", "b", "a"]) - with pytest.raises(IndexError): + if allow_fill: + msg = "indices are out-of-bounds" + else: + msg = "index 4 is out of bounds for size 3" + with pytest.raises(IndexError, match=msg): cat.take([4, 5], allow_fill=allow_fill) def test_take_empty(self, allow_fill): # https://github.com/pandas-dev/pandas/issues/20664 cat = pd.Categorical([], categories=["a", "b"]) - with pytest.raises(IndexError): + if allow_fill: + msg = "indices are out-of-bounds" + else: + msg = "cannot do a non-empty take from an empty axes" + with pytest.raises(IndexError, match=msg): cat.take([0], allow_fill=allow_fill) def test_positional_take(self, ordered_fixture): diff --git a/pandas/tests/arrays/categorical/test_analytics.py b/pandas/tests/arrays/categorical/test_analytics.py index 637a47eba0597..d2990cbc890a2 100644 --- a/pandas/tests/arrays/categorical/test_analytics.py +++ b/pandas/tests/arrays/categorical/test_analytics.py @@ -271,40 +271,42 @@ def test_map(self): # GH 12766: Return an index not an array tm.assert_index_equal(result, Index(np.array([1] * 5, dtype=np.int64))) - def test_validate_inplace(self): + @pytest.mark.parametrize("value", [1, "True", [1, 2, 3], 5.0]) + def test_validate_inplace_raises(self, value): cat = Categorical(["A", "B", "B", "C", "A"]) - invalid_values = [1, "True", [1, 2, 3], 5.0] - - for value in invalid_values: - with pytest.raises(ValueError): - cat.set_ordered(value=True, inplace=value) + msg = ( + 'For argument "inplace" expected type bool, ' + f"received type {type(value).__name__}" + ) + with pytest.raises(ValueError, match=msg): + cat.set_ordered(value=True, inplace=value) - with pytest.raises(ValueError): - cat.as_ordered(inplace=value) + with pytest.raises(ValueError, match=msg): + cat.as_ordered(inplace=value) - with pytest.raises(ValueError): - cat.as_unordered(inplace=value) + with pytest.raises(ValueError, match=msg): + cat.as_unordered(inplace=value) - with pytest.raises(ValueError): - cat.set_categories(["X", "Y", "Z"], rename=True, inplace=value) + with pytest.raises(ValueError, match=msg): + cat.set_categories(["X", "Y", "Z"], rename=True, inplace=value) - with pytest.raises(ValueError): - cat.rename_categories(["X", "Y", "Z"], inplace=value) + with pytest.raises(ValueError, match=msg): + cat.rename_categories(["X", "Y", "Z"], inplace=value) - with pytest.raises(ValueError): - cat.reorder_categories(["X", "Y", "Z"], ordered=True, inplace=value) + with pytest.raises(ValueError, match=msg): + cat.reorder_categories(["X", "Y", "Z"], ordered=True, inplace=value) - with pytest.raises(ValueError): - cat.add_categories(new_categories=["D", "E", "F"], inplace=value) + with pytest.raises(ValueError, match=msg): + cat.add_categories(new_categories=["D", "E", "F"], inplace=value) - with pytest.raises(ValueError): - cat.remove_categories(removals=["D", "E", "F"], inplace=value) + with pytest.raises(ValueError, match=msg): + cat.remove_categories(removals=["D", "E", "F"], inplace=value) - with pytest.raises(ValueError): - cat.remove_unused_categories(inplace=value) + with pytest.raises(ValueError, match=msg): + cat.remove_unused_categories(inplace=value) - with pytest.raises(ValueError): - cat.sort_values(inplace=value) + with pytest.raises(ValueError, match=msg): + cat.sort_values(inplace=value) def test_isna(self): exp = np.array([False, False, True]) diff --git a/pandas/tests/arrays/categorical/test_api.py b/pandas/tests/arrays/categorical/test_api.py index c80e963d5c409..82f2fe1ab8fb6 100644 --- a/pandas/tests/arrays/categorical/test_api.py +++ b/pandas/tests/arrays/categorical/test_api.py @@ -83,13 +83,15 @@ def test_rename_categories(self): ) tm.assert_index_equal(cat.categories, Index([1, 2, 3])) - # Lengthen - with pytest.raises(ValueError): - cat.rename_categories([1, 2, 3, 4]) - - # Shorten - with pytest.raises(ValueError): - cat.rename_categories([1, 2]) + @pytest.mark.parametrize("new_categories", [[1, 2, 3, 4], [1, 2]]) + def test_rename_categories_wrong_length_raises(self, new_categories): + cat = Categorical(["a", "b", "c", "a"]) + msg = ( + "new categories need to have the same number of items as the" + " old categories!" + ) + with pytest.raises(ValueError, match=msg): + cat.rename_categories(new_categories) def test_rename_categories_series(self): # https://github.com/pandas-dev/pandas/issues/17981 @@ -149,19 +151,19 @@ def test_reorder_categories(self): assert res is None tm.assert_categorical_equal(cat, new) - # not all "old" included in "new" + @pytest.mark.parametrize( + "new_categories", + [ + ["a"], # not all "old" included in "new" + ["a", "b", "d"], # still not all "old" in "new" + ["a", "b", "c", "d"], # all "old" included in "new", but too long + ], + ) + def test_reorder_categories_raises(self, new_categories): cat = Categorical(["a", "b", "c", "a"], ordered=True) - - with pytest.raises(ValueError): - cat.reorder_categories(["a"]) - - # still not all "old" in "new" - with pytest.raises(ValueError): - cat.reorder_categories(["a", "b", "d"]) - - # all "old" included in "new", but too long - with pytest.raises(ValueError): - cat.reorder_categories(["a", "b", "c", "d"]) + msg = "items in new_categories are not the same as in old categories" + with pytest.raises(ValueError, match=msg): + cat.reorder_categories(new_categories) def test_add_categories(self): cat = Categorical(["a", "b", "c", "a"], ordered=True) @@ -184,10 +186,6 @@ def test_add_categories(self): tm.assert_categorical_equal(cat, new) assert res is None - # new is in old categories - with pytest.raises(ValueError): - cat.add_categories(["d"]) - # GH 9927 cat = Categorical(list("abc"), ordered=True) expected = Categorical(list("abc"), categories=list("abcde"), ordered=True) @@ -201,6 +199,13 @@ def test_add_categories(self): res = cat.add_categories(["d", "e"]) tm.assert_categorical_equal(res, expected) + def test_add_categories_existing_raises(self): + # new is in old categories + cat = Categorical(["a", "b", "c", "d"], ordered=True) + msg = re.escape("new categories must not include old categories: {'d'}") + with pytest.raises(ValueError, match=msg): + cat.add_categories(["d"]) + def test_set_categories(self): cat = Categorical(["a", "b", "c", "a"], ordered=True) exp_categories = Index(["c", "b", "a"]) @@ -453,13 +458,13 @@ def test_codes_immutable(self): tm.assert_numpy_array_equal(c.codes, exp) # Assignments to codes should raise - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="cannot set Categorical codes directly"): c.codes = np.array([0, 1, 2, 0, 1], dtype="int8") # changes in the codes array should raise codes = c.codes - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="assignment destination is read-only"): codes[4] = 1 # But even after getting the codes, the original array should still be diff --git a/pandas/tests/arrays/categorical/test_indexing.py b/pandas/tests/arrays/categorical/test_indexing.py index f929eb24c9f19..37dea53f792cb 100644 --- a/pandas/tests/arrays/categorical/test_indexing.py +++ b/pandas/tests/arrays/categorical/test_indexing.py @@ -63,7 +63,8 @@ def test_setitem_different_unordered_raises(self, other): # GH-24142 target = pd.Categorical(["a", "b"], categories=["a", "b"]) mask = np.array([True, False]) - with pytest.raises(ValueError): + msg = "Cannot set a Categorical with another, without identical categories" + with pytest.raises(ValueError, match=msg): target[mask] = other[mask] @pytest.mark.parametrize( @@ -78,8 +79,8 @@ def test_setitem_same_ordered_rasies(self, other): # Gh-24142 target = pd.Categorical(["a", "b"], categories=["a", "b"], ordered=True) mask = np.array([True, False]) - - with pytest.raises(ValueError): + msg = "Cannot set a Categorical with another, without identical categories" + with pytest.raises(ValueError, match=msg): target[mask] = other[mask] @@ -152,13 +153,15 @@ def test_categories_assigments(self): tm.assert_numpy_array_equal(s.__array__(), exp) tm.assert_index_equal(s.categories, Index([1, 2, 3])) - # lengthen - with pytest.raises(ValueError): - s.categories = [1, 2, 3, 4] - - # shorten - with pytest.raises(ValueError): - s.categories = [1, 2] + @pytest.mark.parametrize("new_categories", [[1, 2, 3, 4], [1, 2]]) + def test_categories_assigments_wrong_length_raises(self, new_categories): + cat = Categorical(["a", "b", "c", "a"]) + msg = ( + "new categories need to have the same number of items" + " as the old categories!" + ) + with pytest.raises(ValueError, match=msg): + cat.categories = new_categories # Combinations of sorted/unique: @pytest.mark.parametrize( diff --git a/pandas/tests/arrays/categorical/test_operators.py b/pandas/tests/arrays/categorical/test_operators.py index d62c4f4cf936e..10e33bf70dc66 100644 --- a/pandas/tests/arrays/categorical/test_operators.py +++ b/pandas/tests/arrays/categorical/test_operators.py @@ -73,19 +73,25 @@ def test_comparisons(self): tm.assert_numpy_array_equal(res, exp) # Only categories with same categories can be compared - with pytest.raises(TypeError): + msg = "Categoricals can only be compared if 'categories' are the same" + with pytest.raises(TypeError, match=msg): cat > cat_rev cat_rev_base2 = Categorical(["b", "b", "b"], categories=["c", "b", "a", "d"]) - with pytest.raises(TypeError): + msg = ( + "Categoricals can only be compared if 'categories' are the same. " + "Categories are different lengths" + ) + with pytest.raises(TypeError, match=msg): cat_rev > cat_rev_base2 # Only categories with same ordering information can be compared cat_unorderd = cat.set_ordered(False) assert not (cat > cat).any() - with pytest.raises(TypeError): + msg = "Categoricals can only be compared if 'ordered' is the same" + with pytest.raises(TypeError, match=msg): cat > cat_unorderd # comparison (in both directions) with Series will raise @@ -131,18 +137,6 @@ def test_compare_frame(self): df = DataFrame(cat) - for op in [ - operator.eq, - operator.ne, - operator.ge, - operator.gt, - operator.le, - operator.lt, - ]: - with pytest.raises(ValueError): - # alignment raises unless we transpose - op(cat, df) - result = cat == df.T expected = DataFrame([[True, True, True, True]]) tm.assert_frame_equal(result, expected) @@ -151,6 +145,15 @@ def test_compare_frame(self): expected = DataFrame([[False, True, True, False]]) tm.assert_frame_equal(result, expected) + def test_compare_frame_raises(self, all_compare_operators): + # alignment raises unless we transpose + op = getattr(operator, all_compare_operators) + cat = Categorical(["a", "b", 2, "a"]) + df = DataFrame(cat) + msg = "Unable to coerce to Series, length must be 1: given 4" + with pytest.raises(ValueError, match=msg): + op(cat, df) + def test_datetime_categorical_comparison(self): dt_cat = Categorical(date_range("2014-01-01", periods=3), ordered=True) tm.assert_numpy_array_equal(dt_cat > dt_cat[0], np.array([False, True, True])) @@ -255,7 +258,8 @@ def test_comparisons(self, data, reverse, base): tm.assert_numpy_array_equal(res_rev.values, exp_rev2) # Only categories with same categories can be compared - with pytest.raises(TypeError): + msg = "Categoricals can only be compared if 'categories' are the same" + with pytest.raises(TypeError, match=msg): cat > cat_rev # categorical cannot be compared to Series or numpy array, and also @@ -367,7 +371,9 @@ def test_numeric_like_ops(self): # numpy ops s = Series(Categorical([1, 2, 3, 4])) - with pytest.raises(TypeError): + with pytest.raises( + TypeError, match="Categorical cannot perform the operation sum" + ): np.sum(s) # numeric ops on a Series @@ -384,7 +390,8 @@ def test_numeric_like_ops(self): getattr(s, op)(2) # invalid ufunc - with pytest.raises(TypeError): + msg = "Object with dtype category cannot perform the numpy op log" + with pytest.raises(TypeError, match=msg): np.log(s) def test_contains(self): @@ -394,7 +401,7 @@ def test_contains(self): assert "b" in c assert "z" not in c assert np.nan not in c - with pytest.raises(TypeError): + with pytest.raises(TypeError, match="unhashable type: 'list'"): assert [1] in c # assert codes NOT in index