Skip to content

CLEAN: Enforce pdep6 #59007

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions asv_bench/benchmarks/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,12 +546,9 @@ def time_chained_indexing(self, mode):


class Block:
params = [
(True, "True"),
(np.array(True), "np.array(True)"),
]
params = [True]

def setup(self, true_value, mode):
def setup(self, true_value):
self.df = DataFrame(
False,
columns=np.arange(500).astype(str),
Expand All @@ -560,7 +557,7 @@ def setup(self, true_value, mode):

self.true_value = true_value

def time_test(self, true_value, mode):
def time_test(self, true_value):
start = datetime(2010, 5, 1)
end = datetime(2010, 9, 1)
self.df.loc[start:end, :] = true_value
Expand Down
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 @@ -466,14 +466,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
Loading