Skip to content

Commit

Permalink
enforce pdep6
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcoGorelli committed Jun 21, 2024
1 parent c46fb76 commit 45cafc2
Show file tree
Hide file tree
Showing 26 changed files with 359 additions and 625 deletions.
2 changes: 1 addition & 1 deletion doc/source/user_guide/categorical.rst
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ Assigning a ``Categorical`` to parts of a column of other types will use the val
:okwarning:
df = pd.DataFrame({"a": [1, 1, 1, 1, 1], "b": ["a", "a", "a", "a", "a"]})
df.loc[1:2, "a"] = pd.Categorical(["b", "b"], categories=["a", "b"])
df.loc[1:2, "a"] = pd.Categorical([2, 2], categories=[2, 3])
df.loc[2:3, "b"] = pd.Categorical(["b", "b"], categories=["a", "b"])
df
df.dtypes
Expand Down
14 changes: 4 additions & 10 deletions pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
)
from pandas.errors.cow import _chained_assignment_msg
from pandas.util._decorators import doc
from pandas.util._exceptions import find_stack_level

from pandas.core.dtypes.cast import (
can_hold_element,
Expand Down Expand Up @@ -2124,7 +2123,7 @@ def _setitem_single_column(self, loc: int, value, plane_indexer) -> None:
self.obj._mgr.column_setitem(
loc, plane_indexer, value, inplace_only=True
)
except (ValueError, TypeError, LossySetitemError):
except (ValueError, TypeError, LossySetitemError) as exc:
# If we're setting an entire column and we can't do it inplace,
# then we can use value's dtype (or inferred dtype)
# instead of object
Expand All @@ -2140,14 +2139,9 @@ def _setitem_single_column(self, loc: int, value, plane_indexer) -> None:
# - Exclude `object`, as then no upcasting happens.
# - Exclude empty initial object with enlargement,
# as then there's nothing to be inconsistent with.
warnings.warn(
f"Setting an item of incompatible dtype is deprecated "
"and will raise in a future error of pandas. "
f"Value '{value}' has dtype incompatible with {dtype}, "
"please explicitly cast to a compatible dtype first.",
FutureWarning,
stacklevel=find_stack_level(),
)
raise TypeError(
f"Invalid value '{value}' for dtype '{dtype}'"
) from exc
self.obj.isetitem(loc, value)
else:
# set value into the column (first attempting to operate inplace, then
Expand Down
9 changes: 1 addition & 8 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,14 +467,7 @@ def coerce_to_target_dtype(self, other, warn_on_upcast: bool = False) -> Block:
warn_on_upcast = False

if warn_on_upcast:
warnings.warn(
f"Setting an item of incompatible dtype is deprecated "
"and will raise an error in a future version of pandas. "
f"Value '{other}' has dtype incompatible with {self.values.dtype}, "
"please explicitly cast to a compatible dtype first.",
FutureWarning,
stacklevel=find_stack_level(),
)
raise TypeError(f"Invalid value '{other}' for dtype '{self.values.dtype}'")
if self.values.dtype == new_dtype:
raise AssertionError(
f"Did not expect new dtype {new_dtype} to equal self.dtype "
Expand Down
26 changes: 11 additions & 15 deletions pandas/tests/copy_view/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,15 +725,13 @@ def test_column_as_series_set_with_upcast(backend):
with pytest.raises(TypeError, match="Invalid value"):
s[0] = "foo"
expected = Series([1, 2, 3], name="a")
tm.assert_series_equal(s, expected)
tm.assert_frame_equal(df, df_orig)
# ensure cached series on getitem is not the changed series
tm.assert_series_equal(df["a"], df_orig["a"])
else:
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
with pytest.raises(TypeError, match="Invalid value"):
s[0] = "foo"
expected = Series(["foo", 2, 3], dtype=object, name="a")

tm.assert_series_equal(s, expected)
tm.assert_frame_equal(df, df_orig)
# ensure cached series on getitem is not the changed series
tm.assert_series_equal(df["a"], df_orig["a"])


@pytest.mark.parametrize(
Expand Down Expand Up @@ -805,16 +803,14 @@ def test_set_value_copy_only_necessary_column(indexer_func, indexer, val, col):
view = df[:]

if val == "a":
with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype is deprecated"
):
with pytest.raises(TypeError, match="Invalid value"):
indexer_func(df)[indexer] = val
else:
indexer_func(df)[indexer] = val

indexer_func(df)[indexer] = val

assert np.shares_memory(get_array(df, "b"), get_array(view, "b"))
assert not np.shares_memory(get_array(df, "a"), get_array(view, "a"))
tm.assert_frame_equal(view, df_orig)
assert np.shares_memory(get_array(df, "b"), get_array(view, "b"))
assert not np.shares_memory(get_array(df, "a"), get_array(view, "a"))
tm.assert_frame_equal(view, df_orig)


def test_series_midx_slice():
Expand Down
26 changes: 13 additions & 13 deletions pandas/tests/copy_view/test_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -1105,26 +1105,26 @@ def test_putmask_aligns_rhs_no_reference(dtype):
assert np.shares_memory(arr_a, get_array(df, "a"))


@pytest.mark.parametrize(
"val, exp, warn", [(5.5, True, FutureWarning), (5, False, None)]
)
def test_putmask_dont_copy_some_blocks(val, exp, warn):
@pytest.mark.parametrize("val, exp, raises", [(5.5, True, True), (5, False, False)])
def test_putmask_dont_copy_some_blocks(val, exp, raises: bool):
df = DataFrame({"a": [1, 2], "b": 1, "c": 1.5})
view = df[:]
df_orig = df.copy()
indexer = DataFrame(
[[True, False, False], [True, False, False]], columns=list("abc")
)
with tm.assert_produces_warning(warn, match="incompatible dtype"):
if raises:
with pytest.raises(TypeError, match="Invalid value"):
df[indexer] = val
else:
df[indexer] = val

assert not np.shares_memory(get_array(view, "a"), get_array(df, "a"))
# TODO(CoW): Could split blocks to avoid copying the whole block
assert np.shares_memory(get_array(view, "b"), get_array(df, "b")) is exp
assert np.shares_memory(get_array(view, "c"), get_array(df, "c"))
assert df._mgr._has_no_reference(1) is not exp
assert not df._mgr._has_no_reference(2)
tm.assert_frame_equal(view, df_orig)
assert not np.shares_memory(get_array(view, "a"), get_array(df, "a"))
# TODO(CoW): Could split blocks to avoid copying the whole block
assert np.shares_memory(get_array(view, "b"), get_array(df, "b")) is exp
assert np.shares_memory(get_array(view, "c"), get_array(df, "c"))
assert df._mgr._has_no_reference(1) is not exp
assert not df._mgr._has_no_reference(2)
tm.assert_frame_equal(view, df_orig)


@pytest.mark.parametrize("dtype", ["int64", "Int64"])
Expand Down
36 changes: 6 additions & 30 deletions pandas/tests/frame/indexing/test_coercion.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,35 +49,19 @@ def test_loc_setitem_multiindex_columns(self, consolidate):
def test_37477():
# fixed by GH#45121
orig = DataFrame({"A": [1, 2, 3], "B": [3, 4, 5]})
expected = DataFrame({"A": [1, 2, 3], "B": [3, 1.2, 5]})

df = orig.copy()
with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
df.at[1, "B"] = 1.2
tm.assert_frame_equal(df, expected)

df = orig.copy()
with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
df.loc[1, "B"] = 1.2
tm.assert_frame_equal(df, expected)

df = orig.copy()
with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
df.iat[1, 1] = 1.2
tm.assert_frame_equal(df, expected)

df = orig.copy()
with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
df.iloc[1, 1] = 1.2
tm.assert_frame_equal(df, expected)


def test_6942(indexer_al):
Expand Down Expand Up @@ -107,19 +91,11 @@ def test_26395(indexer_al):
expected = DataFrame({"D": [0, 0, 2]}, index=["A", "B", "C"], dtype=np.int64)
tm.assert_frame_equal(df, expected)

with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
indexer_al(df)["C", "D"] = 44.5
expected = DataFrame({"D": [0, 0, 44.5]}, index=["A", "B", "C"], dtype=np.float64)
tm.assert_frame_equal(df, expected)

with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
indexer_al(df)["C", "D"] = "hello"
expected = DataFrame({"D": [0, 0, "hello"]}, index=["A", "B", "C"], dtype=object)
tm.assert_frame_equal(df, expected)


@pytest.mark.xfail(reason="unwanted upcast")
Expand Down
86 changes: 27 additions & 59 deletions pandas/tests/frame/indexing/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
Timestamp,
date_range,
isna,
notna,
to_datetime,
)
import pandas._testing as tm
Expand Down Expand Up @@ -833,13 +832,8 @@ def test_setitem_single_column_mixed_datetime(self):
tm.assert_series_equal(result, expected)

# GH#16674 iNaT is treated as an integer when given by the user
with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
df.loc["b", "timestamp"] = iNaT
assert not isna(df.loc["b", "timestamp"])
assert df["timestamp"].dtype == np.object_
assert df.loc["b", "timestamp"] == iNaT

# allow this syntax (as of GH#3216)
df.loc["c", "timestamp"] = np.nan
Expand All @@ -851,35 +845,11 @@ def test_setitem_single_column_mixed_datetime(self):

def test_setitem_mixed_datetime(self):
# GH 9336
expected = DataFrame(
{
"a": [0, 0, 0, 0, 13, 14],
"b": [
datetime(2012, 1, 1),
1,
"x",
"y",
datetime(2013, 1, 1),
datetime(2014, 1, 1),
],
}
)
df = DataFrame(0, columns=list("ab"), index=range(6))
df["b"] = pd.NaT
df.loc[0, "b"] = datetime(2012, 1, 1)
with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
df.loc[1, "b"] = 1
df.loc[[2, 3], "b"] = "x", "y"
A = np.array(
[
[13, np.datetime64("2013-01-01T00:00:00")],
[14, np.datetime64("2014-01-01T00:00:00")],
]
)
df.loc[[4, 5], ["a", "b"]] = A
tm.assert_frame_equal(df, expected)

def test_setitem_frame_float(self, float_frame):
piece = float_frame.loc[float_frame.index[:2], ["A", "B"]]
Expand Down Expand Up @@ -936,8 +906,12 @@ def test_setitem_frame_upcast(self):
# needs upcasting
df = DataFrame([[1, 2, "foo"], [3, 4, "bar"]], columns=["A", "B", "C"])
df2 = df.copy()
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
with pytest.raises(TypeError, match="Invalid value"):
df2.loc[:, ["A", "B"]] = df.loc[:, ["A", "B"]] + 0.5
# Manually upcast so we can add .5
df = df.astype({"A": "float64", "B": "float64"})
df2 = df2.astype({"A": "float64", "B": "float64"})
df2.loc[:, ["A", "B"]] = df.loc[:, ["A", "B"]] + 0.5
expected = df.reindex(columns=["A", "B"])
expected += 0.5
expected["C"] = df["C"]
Expand Down Expand Up @@ -1366,12 +1340,8 @@ def test_loc_setitem_rhs_frame(self, idxr, val):
# GH#47578
df = DataFrame({"a": [1, 2]})

with tm.assert_produces_warning(
FutureWarning, match="Setting an item of incompatible dtype"
):
with pytest.raises(TypeError, match="Invalid value"):
df.loc[:, idxr] = DataFrame({"a": [val, 11]}, index=[1, 2])
expected = DataFrame({"a": [np.nan, val]})
tm.assert_frame_equal(df, expected)

def test_iloc_setitem_enlarge_no_warning(self):
# GH#47381
Expand Down Expand Up @@ -1579,18 +1549,9 @@ def test_setitem(self):
# With NaN: because uint64 has no NaN element,
# the column should be cast to object.
df2 = df.copy()
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
with pytest.raises(TypeError, match="Invalid value"):
df2.iloc[1, 1] = pd.NaT
df2.iloc[1, 2] = pd.NaT
result = df2["B"]
tm.assert_series_equal(notna(result), Series([True, False, True], name="B"))
tm.assert_series_equal(
df2.dtypes,
Series(
[np.dtype("uint64"), np.dtype("O"), np.dtype("O")],
index=["A", "B", "C"],
),
)


def test_object_casting_indexing_wraps_datetimelike():
Expand Down Expand Up @@ -1926,22 +1887,30 @@ def test_add_new_column_infer_string():
class TestSetitemValidation:
# This is adapted from pandas/tests/arrays/masked/test_indexing.py
# but checks for warnings instead of errors.
def _check_setitem_invalid(self, df, invalid, indexer, warn):
msg = "Setting an item of incompatible dtype is deprecated"
msg = re.escape(msg)

def _check_setitem_invalid(self, df, invalid, indexer):
orig_df = df.copy()

# iloc
with tm.assert_produces_warning(warn, match=msg):
with pytest.raises(TypeError, match="Invalid value"):
df.iloc[indexer, 0] = invalid
df = orig_df.copy()

# loc
with tm.assert_produces_warning(warn, match=msg):
with pytest.raises(TypeError, match="Invalid value"):
df.loc[indexer, "a"] = invalid
df = orig_df.copy()

def _check_setitem_valid(self, df, value, indexer):
orig_df = df.copy()

# iloc
df.iloc[indexer, 0] = value
df = orig_df.copy()

# loc
df.loc[indexer, "a"] = value
df = orig_df.copy()

_invalid_scalars = [
1 + 2j,
"True",
Expand All @@ -1959,20 +1928,19 @@ def _check_setitem_invalid(self, df, invalid, indexer, warn):
@pytest.mark.parametrize("indexer", _indexers)
def test_setitem_validation_scalar_bool(self, invalid, indexer):
df = DataFrame({"a": [True, False, False]}, dtype="bool")
self._check_setitem_invalid(df, invalid, indexer, FutureWarning)
self._check_setitem_invalid(df, invalid, indexer)

@pytest.mark.parametrize("invalid", _invalid_scalars + [True, 1.5, np.float64(1.5)])
@pytest.mark.parametrize("indexer", _indexers)
def test_setitem_validation_scalar_int(self, invalid, any_int_numpy_dtype, indexer):
df = DataFrame({"a": [1, 2, 3]}, dtype=any_int_numpy_dtype)
if isna(invalid) and invalid is not pd.NaT and not np.isnat(invalid):
warn = None
self._check_setitem_valid(df, invalid, indexer)
else:
warn = FutureWarning
self._check_setitem_invalid(df, invalid, indexer, warn)
self._check_setitem_invalid(df, invalid, indexer)

@pytest.mark.parametrize("invalid", _invalid_scalars + [True])
@pytest.mark.parametrize("indexer", _indexers)
def test_setitem_validation_scalar_float(self, invalid, float_numpy_dtype, indexer):
df = DataFrame({"a": [1, 2, None]}, dtype=float_numpy_dtype)
self._check_setitem_invalid(df, invalid, indexer, FutureWarning)
self._check_setitem_invalid(df, invalid, indexer)
Loading

0 comments on commit 45cafc2

Please sign in to comment.