Skip to content

Commit 957fc3c

Browse files
authored
BUG/DEPR: loc.__setitem__ incorrectly accepting positional slices (#31840)
1 parent aa27b9a commit 957fc3c

File tree

15 files changed

+108
-58
lines changed

15 files changed

+108
-58
lines changed

doc/source/whatsnew/v1.1.0.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ Deprecations
172172
~~~~~~~~~~~~
173173
- Lookups on a :class:`Series` with a single-item list containing a slice (e.g. ``ser[[slice(0, 4)]]``) are deprecated, will raise in a future version. Either convert the list to tuple, or pass the slice directly instead (:issue:`31333`)
174174
- :meth:`DataFrame.mean` and :meth:`DataFrame.median` with ``numeric_only=None`` will include datetime64 and datetime64tz columns in a future version (:issue:`29941`)
175-
-
175+
- Setting values with ``.loc`` using a positional slice is deprecated and will raise in a future version. Use ``.loc`` with labels or ``.iloc`` with positions instead (:issue:`31840`)
176176
-
177177

178178
.. ---------------------------------------------------------------------------

pandas/core/indexes/base.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3137,8 +3137,18 @@ def is_int(v):
31373137
pass
31383138

31393139
if com.is_null_slice(key):
3140+
# It doesn't matter if we are positional or label based
31403141
indexer = key
31413142
elif is_positional:
3143+
if kind == "loc":
3144+
# GH#16121, GH#24612, GH#31810
3145+
warnings.warn(
3146+
"Slicing a positional slice with .loc is not supported, "
3147+
"and will raise TypeError in a future version. "
3148+
"Use .loc with labels or .iloc with positions instead.",
3149+
FutureWarning,
3150+
stacklevel=6,
3151+
)
31423152
indexer = key
31433153
else:
31443154
indexer = self.slice_indexer(start, stop, step, kind=kind)

pandas/tests/frame/conftest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ def float_frame_with_na():
4040
"""
4141
df = DataFrame(tm.getSeriesData())
4242
# set some NAs
43-
df.loc[5:10] = np.nan
44-
df.loc[15:20, -2:] = np.nan
43+
df.iloc[5:10] = np.nan
44+
df.iloc[15:20, -2:] = np.nan
4545
return df
4646

4747

@@ -74,8 +74,8 @@ def bool_frame_with_na():
7474
df = DataFrame(tm.getSeriesData()) > 0
7575
df = df.astype(object)
7676
# set some NAs
77-
df.loc[5:10] = np.nan
78-
df.loc[15:20, -2:] = np.nan
77+
df.iloc[5:10] = np.nan
78+
df.iloc[15:20, -2:] = np.nan
7979
return df
8080

8181

pandas/tests/frame/indexing/test_indexing.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,7 @@ def test_setitem_frame_mixed(self, float_string_frame):
12091209
piece = DataFrame(
12101210
[[1.0, 2.0], [3.0, 4.0]], index=f.index[0:2], columns=["A", "B"]
12111211
)
1212-
key = (slice(None, 2), ["A", "B"])
1212+
key = (f.index[slice(None, 2)], ["A", "B"])
12131213
f.loc[key] = piece
12141214
tm.assert_almost_equal(f.loc[f.index[0:2], ["A", "B"]].values, piece.values)
12151215

@@ -1220,7 +1220,7 @@ def test_setitem_frame_mixed(self, float_string_frame):
12201220
index=list(f.index[0:2]) + ["foo", "bar"],
12211221
columns=["A", "B"],
12221222
)
1223-
key = (slice(None, 2), ["A", "B"])
1223+
key = (f.index[slice(None, 2)], ["A", "B"])
12241224
f.loc[key] = piece
12251225
tm.assert_almost_equal(
12261226
f.loc[f.index[0:2:], ["A", "B"]].values, piece.values[0:2]
@@ -1230,15 +1230,15 @@ def test_setitem_frame_mixed(self, float_string_frame):
12301230
f = float_string_frame.copy()
12311231
piece = f.loc[f.index[:2], ["A"]]
12321232
piece.index = f.index[-2:]
1233-
key = (slice(-2, None), ["A", "B"])
1233+
key = (f.index[slice(-2, None)], ["A", "B"])
12341234
f.loc[key] = piece
12351235
piece["B"] = np.nan
12361236
tm.assert_almost_equal(f.loc[f.index[-2:], ["A", "B"]].values, piece.values)
12371237

12381238
# ndarray
12391239
f = float_string_frame.copy()
12401240
piece = float_string_frame.loc[f.index[:2], ["A", "B"]]
1241-
key = (slice(-2, None), ["A", "B"])
1241+
key = (f.index[slice(-2, None)], ["A", "B"])
12421242
f.loc[key] = piece.values
12431243
tm.assert_almost_equal(f.loc[f.index[-2:], ["A", "B"]].values, piece.values)
12441244

@@ -1873,7 +1873,7 @@ def test_setitem_datetimelike_with_inference(self):
18731873
df = DataFrame(index=date_range("20130101", periods=4))
18741874
df["A"] = np.array([1 * one_hour] * 4, dtype="m8[ns]")
18751875
df.loc[:, "B"] = np.array([2 * one_hour] * 4, dtype="m8[ns]")
1876-
df.loc[:3, "C"] = np.array([3 * one_hour] * 3, dtype="m8[ns]")
1876+
df.loc[df.index[:3], "C"] = np.array([3 * one_hour] * 3, dtype="m8[ns]")
18771877
df.loc[:, "D"] = np.array([4 * one_hour] * 4, dtype="m8[ns]")
18781878
df.loc[df.index[:3], "E"] = np.array([5 * one_hour] * 3, dtype="m8[ns]")
18791879
df["F"] = np.timedelta64("NaT")

pandas/tests/frame/methods/test_asof.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class TestFrameAsof:
3131
def test_basic(self, date_range_frame):
3232
df = date_range_frame
3333
N = 50
34-
df.loc[15:30, "A"] = np.nan
34+
df.loc[df.index[15:30], "A"] = np.nan
3535
dates = date_range("1/1/1990", periods=N * 3, freq="25s")
3636

3737
result = df.asof(dates)
@@ -51,7 +51,7 @@ def test_basic(self, date_range_frame):
5151
def test_subset(self, date_range_frame):
5252
N = 10
5353
df = date_range_frame.iloc[:N].copy()
54-
df.loc[4:8, "A"] = np.nan
54+
df.loc[df.index[4:8], "A"] = np.nan
5555
dates = date_range("1/1/1990", periods=N * 3, freq="25s")
5656

5757
# with a subset of A should be the same
@@ -159,7 +159,7 @@ def test_is_copy(self, date_range_frame):
159159
# doesn't track the parent dataframe / doesn't give SettingWithCopy warnings
160160
df = date_range_frame
161161
N = 50
162-
df.loc[15:30, "A"] = np.nan
162+
df.loc[df.index[15:30], "A"] = np.nan
163163
dates = date_range("1/1/1990", periods=N * 3, freq="25s")
164164

165165
result = df.asof(dates)

pandas/tests/frame/test_analytics.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -913,8 +913,8 @@ def test_sum_bools(self):
913913

914914
def test_idxmin(self, float_frame, int_frame):
915915
frame = float_frame
916-
frame.loc[5:10] = np.nan
917-
frame.loc[15:20, -2:] = np.nan
916+
frame.iloc[5:10] = np.nan
917+
frame.iloc[15:20, -2:] = np.nan
918918
for skipna in [True, False]:
919919
for axis in [0, 1]:
920920
for df in [frame, int_frame]:
@@ -928,8 +928,8 @@ def test_idxmin(self, float_frame, int_frame):
928928

929929
def test_idxmax(self, float_frame, int_frame):
930930
frame = float_frame
931-
frame.loc[5:10] = np.nan
932-
frame.loc[15:20, -2:] = np.nan
931+
frame.iloc[5:10] = np.nan
932+
frame.iloc[15:20, -2:] = np.nan
933933
for skipna in [True, False]:
934934
for axis in [0, 1]:
935935
for df in [frame, int_frame]:

pandas/tests/frame/test_apply.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def test_apply_yield_list(self, float_frame):
339339
tm.assert_frame_equal(result, float_frame)
340340

341341
def test_apply_reduce_Series(self, float_frame):
342-
float_frame.loc[::2, "A"] = np.nan
342+
float_frame["A"].iloc[::2] = np.nan
343343
expected = float_frame.mean(1)
344344
result = float_frame.apply(np.mean, axis=1)
345345
tm.assert_series_equal(result, expected)

pandas/tests/frame/test_block_internals.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ def test_convert_objects(self, float_string_frame):
478478
length = len(float_string_frame)
479479
float_string_frame["J"] = "1."
480480
float_string_frame["K"] = "1"
481-
float_string_frame.loc[0:5, ["J", "K"]] = "garbled"
481+
float_string_frame.loc[float_string_frame.index[0:5], ["J", "K"]] = "garbled"
482482
converted = float_string_frame._convert(datetime=True, numeric=True)
483483
assert converted["H"].dtype == "float64"
484484
assert converted["I"].dtype == "int64"

pandas/tests/frame/test_cumulative.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ def test_cumsum_corner(self):
2323
result = dm.cumsum() # noqa
2424

2525
def test_cumsum(self, datetime_frame):
26-
datetime_frame.loc[5:10, 0] = np.nan
27-
datetime_frame.loc[10:15, 1] = np.nan
28-
datetime_frame.loc[15:, 2] = np.nan
26+
datetime_frame.iloc[5:10, 0] = np.nan
27+
datetime_frame.iloc[10:15, 1] = np.nan
28+
datetime_frame.iloc[15:, 2] = np.nan
2929

3030
# axis = 0
3131
cumsum = datetime_frame.cumsum()
@@ -46,9 +46,9 @@ def test_cumsum(self, datetime_frame):
4646
assert np.shape(cumsum_xs) == np.shape(datetime_frame)
4747

4848
def test_cumprod(self, datetime_frame):
49-
datetime_frame.loc[5:10, 0] = np.nan
50-
datetime_frame.loc[10:15, 1] = np.nan
51-
datetime_frame.loc[15:, 2] = np.nan
49+
datetime_frame.iloc[5:10, 0] = np.nan
50+
datetime_frame.iloc[10:15, 1] = np.nan
51+
datetime_frame.iloc[15:, 2] = np.nan
5252

5353
# axis = 0
5454
cumprod = datetime_frame.cumprod()
@@ -80,9 +80,9 @@ def test_cumprod(self, datetime_frame):
8080
strict=False,
8181
)
8282
def test_cummin(self, datetime_frame):
83-
datetime_frame.loc[5:10, 0] = np.nan
84-
datetime_frame.loc[10:15, 1] = np.nan
85-
datetime_frame.loc[15:, 2] = np.nan
83+
datetime_frame.iloc[5:10, 0] = np.nan
84+
datetime_frame.iloc[10:15, 1] = np.nan
85+
datetime_frame.iloc[15:, 2] = np.nan
8686

8787
# axis = 0
8888
cummin = datetime_frame.cummin()
@@ -108,9 +108,9 @@ def test_cummin(self, datetime_frame):
108108
strict=False,
109109
)
110110
def test_cummax(self, datetime_frame):
111-
datetime_frame.loc[5:10, 0] = np.nan
112-
datetime_frame.loc[10:15, 1] = np.nan
113-
datetime_frame.loc[15:, 2] = np.nan
111+
datetime_frame.iloc[5:10, 0] = np.nan
112+
datetime_frame.iloc[10:15, 1] = np.nan
113+
datetime_frame.iloc[15:, 2] = np.nan
114114

115115
# axis = 0
116116
cummax = datetime_frame.cummax()

pandas/tests/frame/test_to_csv.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ def create_cols(name):
761761
)
762762

763763
# add in some nans
764-
df_float.loc[30:50, 1:3] = np.nan
764+
df_float.iloc[30:50, 1:3] = np.nan
765765

766766
# ## this is a bug in read_csv right now ####
767767
# df_dt.loc[30:50,1:3] = np.nan

0 commit comments

Comments
 (0)