Skip to content

Commit a81e7b4

Browse files
committed
Merge remote-tracking branch 'upstream/master' into deprecate-nonkeyword-args-clip
2 parents b4dec9e + a246270 commit a81e7b4

38 files changed

+325
-65
lines changed

doc/source/whatsnew/v1.3.0.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,9 @@ Deprecations
648648
- Deprecated setting :attr:`Categorical._codes`, create a new :class:`Categorical` with the desired codes instead (:issue:`40606`)
649649
- Deprecated behavior of :meth:`DatetimeIndex.union` with mixed timezones; in a future version both will be cast to UTC instead of object dtype (:issue:`39328`)
650650
- Deprecated using ``usecols`` with out of bounds indices for ``read_csv`` with ``engine="c"`` (:issue:`25623`)
651-
- Deprecated passing arguments (other than ``"lower"`` and ``"upper"``) as positional in :meth:`DataFrame.clip` and :meth:`Series.clip` (:issue:`41485`)
651+
- Deprecated passing arguments as positional in (:issue:`41485`) :
652+
- :meth:`DataFrame.clip` and :meth:`Series.clip` (other than ``"lower"`` and ``"upper"``)
653+
- :meth:`DataFrame.interpolate` (except for ``"method"``) and :meth:`Series.interpolate`
652654

653655
.. ---------------------------------------------------------------------------
654656

pandas/core/arrays/datetimelike.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,9 @@ def _validate_shift_value(self, fill_value):
599599
"will raise in a future version, pass "
600600
f"{self._scalar_type.__name__} instead.",
601601
FutureWarning,
602-
stacklevel=8,
602+
# There is no way to hard-code the level since this might be
603+
# reached directly or called from the Index or Block method
604+
stacklevel=find_stack_level(),
603605
)
604606
fill_value = new_fill
605607

pandas/core/arrays/datetimes.py

+1
Original file line numberDiff line numberDiff line change
@@ -1175,6 +1175,7 @@ def to_perioddelta(self, freq) -> TimedeltaArray:
11751175
"future version. "
11761176
"Use `dtindex - dtindex.to_period(freq).to_timestamp()` instead",
11771177
FutureWarning,
1178+
# stacklevel chosen to be correct for when called from DatetimeIndex
11781179
stacklevel=3,
11791180
)
11801181
from pandas.core.arrays.timedeltas import TimedeltaArray

pandas/core/frame.py

+24
Original file line numberDiff line numberDiff line change
@@ -1764,6 +1764,7 @@ def to_dict(self, orient: str = "dict", into=dict):
17641764
"will be used in a future version. Use one of the above "
17651765
"to silence this warning.",
17661766
FutureWarning,
1767+
stacklevel=2,
17671768
)
17681769

17691770
if orient.startswith("d"):
@@ -10647,6 +10648,29 @@ def clip(
1064710648
) -> DataFrame | None:
1064810649
return super().clip(lower, upper, axis, inplace, *args, **kwargs)
1064910650

10651+
@deprecate_nonkeyword_arguments(version=None, allowed_args=["self", "method"])
10652+
def interpolate(
10653+
self: DataFrame,
10654+
method: str = "linear",
10655+
axis: Axis = 0,
10656+
limit: int | None = None,
10657+
inplace: bool = False,
10658+
limit_direction: str | None = None,
10659+
limit_area: str | None = None,
10660+
downcast: str | None = None,
10661+
**kwargs,
10662+
) -> DataFrame | None:
10663+
return super().interpolate(
10664+
method,
10665+
axis,
10666+
limit,
10667+
inplace,
10668+
limit_direction,
10669+
limit_area,
10670+
downcast,
10671+
**kwargs,
10672+
)
10673+
1065010674

1065110675
DataFrame._add_numeric_operations()
1065210676

pandas/core/generic.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,19 @@ def _data(self):
481481
@property
482482
def _AXIS_NUMBERS(self) -> dict[str, int]:
483483
""".. deprecated:: 1.1.0"""
484-
warnings.warn("_AXIS_NUMBERS has been deprecated.", FutureWarning, stacklevel=3)
484+
level = self.ndim + 1
485+
warnings.warn(
486+
"_AXIS_NUMBERS has been deprecated.", FutureWarning, stacklevel=level
487+
)
485488
return {"index": 0}
486489

487490
@property
488491
def _AXIS_NAMES(self) -> dict[int, str]:
489492
""".. deprecated:: 1.1.0"""
490-
warnings.warn("_AXIS_NAMES has been deprecated.", FutureWarning, stacklevel=3)
493+
level = self.ndim + 1
494+
warnings.warn(
495+
"_AXIS_NAMES has been deprecated.", FutureWarning, stacklevel=level
496+
)
491497
return {0: "index"}
492498

493499
@final
@@ -6696,7 +6702,6 @@ def replace(
66966702
else:
66976703
return result.__finalize__(self, method="replace")
66986704

6699-
@final
67006705
def interpolate(
67016706
self: FrameOrSeries,
67026707
method: str = "linear",

pandas/core/indexes/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3691,7 +3691,7 @@ def is_int(v):
36913691
"and will raise TypeError in a future version. "
36923692
"Use .loc with labels or .iloc with positions instead.",
36933693
FutureWarning,
3694-
stacklevel=6,
3694+
stacklevel=5,
36953695
)
36963696
indexer = key
36973697
else:

pandas/core/indexes/datetimes.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
cache_readonly,
4141
doc,
4242
)
43+
from pandas.util._exceptions import find_stack_level
4344

4445
from pandas.core.dtypes.common import (
4546
DT64NS_DTYPE,
@@ -660,7 +661,7 @@ def _deprecate_mismatched_indexing(self, key) -> None:
660661
"raise KeyError in a future version. "
661662
"Use a timezone-aware object instead."
662663
)
663-
warnings.warn(msg, FutureWarning, stacklevel=5)
664+
warnings.warn(msg, FutureWarning, stacklevel=find_stack_level())
664665

665666
def get_loc(self, key, method=None, tolerance=None):
666667
"""

pandas/core/reshape/merge.py

+2
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,8 @@ def __init__(
673673
f"in a future version. ({left.columns.nlevels} levels on the left,"
674674
f"{right.columns.nlevels} on the right)"
675675
)
676+
# stacklevel chosen to be correct when this is reached via pd.merge
677+
# (and not DataFrame.join)
676678
warnings.warn(msg, FutureWarning, stacklevel=3)
677679

678680
self._validate_specification()

pandas/core/series.py

+23
Original file line numberDiff line numberDiff line change
@@ -5271,6 +5271,29 @@ def clip(
52715271
) -> Series | None:
52725272
return super().clip(lower, upper, axis, inplace, *args, **kwargs)
52735273

5274+
@deprecate_nonkeyword_arguments(version=None, allowed_args=["self", "method"])
5275+
def interpolate(
5276+
self: Series,
5277+
method: str = "linear",
5278+
axis: Axis = 0,
5279+
limit: int | None = None,
5280+
inplace: bool = False,
5281+
limit_direction: str | None = None,
5282+
limit_area: str | None = None,
5283+
downcast: str | None = None,
5284+
**kwargs,
5285+
) -> Series | None:
5286+
return super().interpolate(
5287+
method,
5288+
axis,
5289+
limit,
5290+
inplace,
5291+
limit_direction,
5292+
limit_area,
5293+
downcast,
5294+
**kwargs,
5295+
)
5296+
52745297
# ----------------------------------------------------------------------
52755298
# Add index
52765299
_AXIS_ORDERS = ["index"]

pandas/tests/arrays/test_datetimelike.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,8 @@ def test_shift_fill_int_deprecated(self):
561561
data = np.arange(10, dtype="i8") * 24 * 3600 * 10 ** 9
562562
arr = self.array_cls(data, freq="D")
563563

564-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
564+
msg = "Passing <class 'int'> to shift"
565+
with tm.assert_produces_warning(FutureWarning, match=msg):
565566
result = arr.shift(1, fill_value=1)
566567

567568
expected = arr.copy()
@@ -783,10 +784,13 @@ def test_to_perioddelta(self, datetime_index, freqstr):
783784
dti = datetime_index
784785
arr = DatetimeArray(dti)
785786

786-
with tm.assert_produces_warning(FutureWarning):
787+
msg = "to_perioddelta is deprecated and will be removed"
788+
with tm.assert_produces_warning(FutureWarning, match=msg):
787789
# Deprecation GH#34853
788790
expected = dti.to_perioddelta(freq=freqstr)
789-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
791+
with tm.assert_produces_warning(
792+
FutureWarning, match=msg, check_stacklevel=False
793+
):
790794
# stacklevel is chosen to be "correct" for DatetimeIndex, not
791795
# DatetimeArray
792796
result = arr.to_perioddelta(freq=freqstr)

pandas/tests/dtypes/cast/test_promote.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -406,11 +406,13 @@ def test_maybe_promote_any_with_datetime64(
406406
exp_val_for_scalar = fill_value
407407

408408
warn = None
409+
msg = "Using a `date` object for fill_value"
409410
if type(fill_value) is datetime.date and dtype.kind == "M":
410411
# Casting date to dt64 is deprecated
411412
warn = FutureWarning
412413

413-
with tm.assert_produces_warning(warn, check_stacklevel=False):
414+
with tm.assert_produces_warning(warn, match=msg, check_stacklevel=False):
415+
# stacklevel is chosen to make sense when called from higher-level functions
414416
_check_promote(dtype, fill_value, expected_dtype, exp_val_for_scalar)
415417

416418

pandas/tests/dtypes/test_missing.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -443,8 +443,10 @@ def test_array_equivalent(dtype_equal):
443443
)
444444
def test_array_equivalent_series(val):
445445
arr = np.array([1, 2])
446+
msg = "elementwise comparison failed"
446447
cm = (
447-
tm.assert_produces_warning(FutureWarning, check_stacklevel=False)
448+
# stacklevel is chosen to make sense when called from .equals
449+
tm.assert_produces_warning(FutureWarning, match=msg, check_stacklevel=False)
448450
if isinstance(val, str)
449451
else nullcontext()
450452
)

pandas/tests/frame/methods/test_diff.py

+9
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,12 @@ def test_diff_readonly(self):
285285
result = df.diff()
286286
expected = DataFrame(np.array(df)).diff()
287287
tm.assert_frame_equal(result, expected)
288+
289+
def test_diff_all_int_dtype(self, any_int_dtype):
290+
# GH 14773
291+
df = DataFrame(range(5))
292+
df = df.astype(any_int_dtype)
293+
result = df.diff()
294+
expected_dtype = "float32" if any_int_dtype in ("int8", "int16") else "float64"
295+
expected = DataFrame([np.nan, 1.0, 1.0, 1.0, 1.0], dtype=expected_dtype)
296+
tm.assert_frame_equal(result, expected)

pandas/tests/frame/methods/test_interpolate.py

+12
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,15 @@ def test_interp_fillna_methods(self, axis, method):
342342
expected = df.fillna(axis=axis, method=method)
343343
result = df.interpolate(method=method, axis=axis)
344344
tm.assert_frame_equal(result, expected)
345+
346+
def test_interpolate_pos_args_deprecation(self):
347+
# https://github.com/pandas-dev/pandas/issues/41485
348+
df = DataFrame({"a": [1, 2, 3]})
349+
msg = (
350+
r"In a future version of pandas all arguments of DataFrame.interpolate "
351+
r"except for the argument 'method' will be keyword-only"
352+
)
353+
with tm.assert_produces_warning(FutureWarning, match=msg):
354+
result = df.interpolate("pad", 0)
355+
expected = DataFrame({"a": [1, 2, 3]})
356+
tm.assert_frame_equal(result, expected)

pandas/tests/frame/methods/test_join.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,11 @@ def test_merge_join_different_levels(self):
345345
# join, see discussion in GH#12219
346346
columns = ["a", "b", ("a", ""), ("c", "c1")]
347347
expected = DataFrame(columns=columns, data=[[1, 11, 0, 44], [0, 22, 1, 33]])
348-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
348+
msg = "merging between different levels is deprecated"
349+
with tm.assert_produces_warning(
350+
FutureWarning, match=msg, check_stacklevel=False
351+
):
352+
# stacklevel is chosen to be correct for pd.merge, not DataFrame.join
349353
result = df1.join(df2, on="a")
350354
tm.assert_frame_equal(result, expected)
351355

pandas/tests/frame/methods/test_quantile.py

+66
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pandas as pd
55
from pandas import (
66
DataFrame,
7+
Index,
78
Series,
89
Timestamp,
910
)
@@ -650,3 +651,68 @@ def test_quantile_ea_scalar(self, index, frame_or_series):
650651
assert result == expected
651652
else:
652653
tm.assert_series_equal(result, expected)
654+
655+
@pytest.mark.parametrize(
656+
"dtype, expected_data, expected_index, axis",
657+
[
658+
["float64", [], [], 1],
659+
["int64", [], [], 1],
660+
["float64", [np.nan, np.nan], ["a", "b"], 0],
661+
["int64", [np.nan, np.nan], ["a", "b"], 0],
662+
],
663+
)
664+
def test_empty_numeric(self, dtype, expected_data, expected_index, axis):
665+
# GH 14564
666+
df = DataFrame(columns=["a", "b"], dtype=dtype)
667+
result = df.quantile(0.5, axis=axis)
668+
expected = Series(
669+
expected_data, name=0.5, index=Index(expected_index), dtype="float64"
670+
)
671+
tm.assert_series_equal(result, expected)
672+
673+
@pytest.mark.parametrize(
674+
"dtype, expected_data, expected_index, axis, expected_dtype",
675+
[
676+
pytest.param(
677+
"datetime64[ns]",
678+
[],
679+
[],
680+
1,
681+
"datetime64[ns]",
682+
marks=pytest.mark.xfail(reason="#GH 41544"),
683+
),
684+
["datetime64[ns]", [pd.NaT, pd.NaT], ["a", "b"], 0, "datetime64[ns]"],
685+
],
686+
)
687+
def test_empty_datelike(
688+
self, dtype, expected_data, expected_index, axis, expected_dtype
689+
):
690+
# GH 14564
691+
df = DataFrame(columns=["a", "b"], dtype=dtype)
692+
result = df.quantile(0.5, axis=axis, numeric_only=False)
693+
expected = Series(
694+
expected_data, name=0.5, index=Index(expected_index), dtype=expected_dtype
695+
)
696+
tm.assert_series_equal(result, expected)
697+
698+
@pytest.mark.parametrize(
699+
"expected_data, expected_index, axis",
700+
[
701+
[[np.nan, np.nan], range(2), 1],
702+
[[], [], 0],
703+
],
704+
)
705+
def test_datelike_numeric_only(self, expected_data, expected_index, axis):
706+
# GH 14564
707+
df = DataFrame(
708+
{
709+
"a": pd.to_datetime(["2010", "2011"]),
710+
"b": [0, 5],
711+
"c": pd.to_datetime(["2011", "2012"]),
712+
}
713+
)
714+
result = df[["a", "c"]].quantile(0.5, axis=axis)
715+
expected = Series(
716+
expected_data, name=0.5, index=Index(expected_index), dtype=np.float64
717+
)
718+
tm.assert_series_equal(result, expected)

pandas/tests/frame/methods/test_reset_index.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ def test_reset_index_with_datetimeindex_cols(self, name):
341341
)
342342
df.index.name = name
343343

344-
with tm.assert_produces_warning(warn, check_stacklevel=False):
344+
with tm.assert_produces_warning(warn):
345345
result = df.reset_index()
346346

347347
item = name if name is not None else "index"

pandas/tests/frame/methods/test_to_dict.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ def test_to_dict_invalid_orient(self):
8181
def test_to_dict_short_orient_warns(self, orient):
8282
# GH#32515
8383
df = DataFrame({"A": [0, 1]})
84-
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
84+
msg = "Using short name for 'orient' is deprecated"
85+
with tm.assert_produces_warning(FutureWarning, match=msg):
8586
df.to_dict(orient=orient)
8687

8788
@pytest.mark.parametrize("mapping", [dict, defaultdict(list), OrderedDict])

pandas/tests/frame/test_constructors.py

+11
Original file line numberDiff line numberDiff line change
@@ -2681,3 +2681,14 @@ def test_from_out_of_bounds_timedelta(self, constructor, cls):
26812681
result = constructor(scalar)
26822682

26832683
assert type(get1(result)) is cls
2684+
2685+
def test_nested_list_columns(self):
2686+
# GH 14467
2687+
result = DataFrame(
2688+
[[1, 2, 3], [4, 5, 6]], columns=[["A", "A", "A"], ["a", "b", "c"]]
2689+
)
2690+
expected = DataFrame(
2691+
[[1, 2, 3], [4, 5, 6]],
2692+
columns=MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("A", "c")]),
2693+
)
2694+
tm.assert_frame_equal(result, expected)

0 commit comments

Comments
 (0)