Skip to content

Commit c79c056

Browse files
jbrockmendelmroeschke
authored andcommitted
DEPR: Enforce datetimelike deprecations (pandas-dev#57999)
* DEPR: Enforce datetimelike deprecations * update message in tests * update overload * mypy fixup * post-merge fixup * update asvs * Update doc/source/whatsnew/v3.0.0.rst --------- Co-authored-by: Matthew Roeschke <[email protected]>
1 parent b750cac commit c79c056

File tree

10 files changed

+44
-55
lines changed

10 files changed

+44
-55
lines changed

asv_bench/benchmarks/categoricals.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def setup(self):
2424
self.codes = np.tile(range(len(self.categories)), N)
2525

2626
self.datetimes = pd.Series(
27-
pd.date_range("1995-01-01 00:00:00", periods=N / 10, freq="s")
27+
pd.date_range("1995-01-01 00:00:00", periods=N // 10, freq="s")
2828
)
2929
self.datetimes_with_nat = self.datetimes.copy()
3030
self.datetimes_with_nat.iloc[-1] = pd.NaT

asv_bench/benchmarks/timeseries.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def setup(self, index_type):
2929
"dst": date_range(
3030
start="10/29/2000 1:00:00", end="10/29/2000 1:59:59", freq="s"
3131
),
32-
"repeated": date_range(start="2000", periods=N / 10, freq="s").repeat(10),
32+
"repeated": date_range(start="2000", periods=N // 10, freq="s").repeat(10),
3333
"tz_aware": date_range(start="2000", periods=N, freq="s", tz="US/Eastern"),
3434
"tz_local": date_range(
3535
start="2000", periods=N, freq="s", tz=dateutil.tz.tzlocal()

doc/source/whatsnew/v3.0.0.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ Removal of prior version deprecations/changes
222222
- All arguments in :meth:`Series.to_dict` are now keyword only (:issue:`56493`)
223223
- Changed the default value of ``observed`` in :meth:`DataFrame.groupby` and :meth:`Series.groupby` to ``True`` (:issue:`51811`)
224224
- Enforce deprecation in :func:`testing.assert_series_equal` and :func:`testing.assert_frame_equal` with object dtype and mismatched null-like values, which are now considered not-equal (:issue:`18463`)
225-
- Enforced deprecation ``all`` and ``any`` reductions with ``datetime64`` and :class:`DatetimeTZDtype` dtypes (:issue:`58029`)
225+
- Enforced deprecation ``all`` and ``any`` reductions with ``datetime64``, :class:`DatetimeTZDtype`, and :class:`PeriodDtype` dtypes (:issue:`58029`)
226+
- Enforced deprecation disallowing ``float`` "periods" in :func:`date_range`, :func:`period_range`, :func:`timedelta_range`, :func:`interval_range`, (:issue:`56036`)
226227
- Enforced deprecation disallowing parsing datetimes with mixed time zones unless user passes ``utc=True`` to :func:`to_datetime` (:issue:`57275`)
227228
- Enforced deprecation in :meth:`Series.value_counts` and :meth:`Index.value_counts` with object dtype performing dtype inference on the ``.index`` of the result (:issue:`56161`)
228229
- Enforced deprecation of :meth:`.DataFrameGroupBy.get_group` and :meth:`.SeriesGroupBy.get_group` allowing the ``name`` argument to be a non-tuple when grouping by a list of length 1 (:issue:`54155`)

pandas/core/arrays/datetimelike.py

+19-24
Original file line numberDiff line numberDiff line change
@@ -1661,20 +1661,24 @@ def _groupby_op(
16611661
dtype = self.dtype
16621662
if dtype.kind == "M":
16631663
# Adding/multiplying datetimes is not valid
1664-
if how in ["any", "all", "sum", "prod", "cumsum", "cumprod", "var", "skew"]:
1664+
if how in ["sum", "prod", "cumsum", "cumprod", "var", "skew"]:
16651665
raise TypeError(f"datetime64 type does not support operation '{how}'")
1666+
if how in ["any", "all"]:
1667+
# GH#34479
1668+
raise TypeError(
1669+
f"'{how}' with datetime64 dtypes is no longer supported. "
1670+
f"Use (obj != pd.Timestamp(0)).{how}() instead."
1671+
)
16661672

16671673
elif isinstance(dtype, PeriodDtype):
16681674
# Adding/multiplying Periods is not valid
16691675
if how in ["sum", "prod", "cumsum", "cumprod", "var", "skew"]:
16701676
raise TypeError(f"Period type does not support {how} operations")
16711677
if how in ["any", "all"]:
16721678
# GH#34479
1673-
warnings.warn(
1674-
f"'{how}' with PeriodDtype is deprecated and will raise in a "
1675-
f"future version. Use (obj != pd.Period(0, freq)).{how}() instead.",
1676-
FutureWarning,
1677-
stacklevel=find_stack_level(),
1679+
raise TypeError(
1680+
f"'{how}' with PeriodDtype is no longer supported. "
1681+
f"Use (obj != pd.Period(0, freq)).{how}() instead."
16781682
)
16791683
else:
16801684
# timedeltas we can add but not multiply
@@ -2424,17 +2428,17 @@ def validate_periods(periods: None) -> None: ...
24242428

24252429

24262430
@overload
2427-
def validate_periods(periods: int | float) -> int: ...
2431+
def validate_periods(periods: int) -> int: ...
24282432

24292433

2430-
def validate_periods(periods: int | float | None) -> int | None:
2434+
def validate_periods(periods: int | None) -> int | None:
24312435
"""
24322436
If a `periods` argument is passed to the Datetime/Timedelta Array/Index
24332437
constructor, cast it to an integer.
24342438
24352439
Parameters
24362440
----------
2437-
periods : None, float, int
2441+
periods : None, int
24382442
24392443
Returns
24402444
-------
@@ -2443,22 +2447,13 @@ def validate_periods(periods: int | float | None) -> int | None:
24432447
Raises
24442448
------
24452449
TypeError
2446-
if periods is None, float, or int
2450+
if periods is not None or int
24472451
"""
2448-
if periods is not None:
2449-
if lib.is_float(periods):
2450-
warnings.warn(
2451-
# GH#56036
2452-
"Non-integer 'periods' in pd.date_range, pd.timedelta_range, "
2453-
"pd.period_range, and pd.interval_range are deprecated and "
2454-
"will raise in a future version.",
2455-
FutureWarning,
2456-
stacklevel=find_stack_level(),
2457-
)
2458-
periods = int(periods)
2459-
elif not lib.is_integer(periods):
2460-
raise TypeError(f"periods must be a number, got {periods}")
2461-
return periods
2452+
if periods is not None and not lib.is_integer(periods):
2453+
raise TypeError(f"periods must be an integer, got {periods}")
2454+
# error: Incompatible return value type (got "int | integer[Any] | None",
2455+
# expected "int | None")
2456+
return periods # type: ignore[return-value]
24622457

24632458

24642459
def _validate_inferred_freq(

pandas/tests/groupby/test_raises.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,8 @@ def test_groupby_raises_datetime(
241241
return
242242

243243
klass, msg = {
244-
"all": (TypeError, "datetime64 type does not support operation 'all'"),
245-
"any": (TypeError, "datetime64 type does not support operation 'any'"),
244+
"all": (TypeError, "'all' with datetime64 dtypes is no longer supported"),
245+
"any": (TypeError, "'any' with datetime64 dtypes is no longer supported"),
246246
"bfill": (None, ""),
247247
"corrwith": (TypeError, "cannot perform __mul__ with this index type"),
248248
"count": (None, ""),

pandas/tests/indexes/datetimes/test_date_range.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,14 @@ def test_date_range_name(self):
135135
assert idx.name == "TEST"
136136

137137
def test_date_range_invalid_periods(self):
138-
msg = "periods must be a number, got foo"
138+
msg = "periods must be an integer, got foo"
139139
with pytest.raises(TypeError, match=msg):
140140
date_range(start="1/1/2000", periods="foo", freq="D")
141141

142142
def test_date_range_fractional_period(self):
143-
msg = "Non-integer 'periods' in pd.date_range, pd.timedelta_range"
144-
with tm.assert_produces_warning(FutureWarning, match=msg):
145-
rng = date_range("1/1/2000", periods=10.5)
146-
exp = date_range("1/1/2000", periods=10)
147-
tm.assert_index_equal(rng, exp)
143+
msg = "periods must be an integer"
144+
with pytest.raises(TypeError, match=msg):
145+
date_range("1/1/2000", periods=10.5)
148146

149147
@pytest.mark.parametrize(
150148
"freq,freq_depr",
@@ -1042,7 +1040,7 @@ def test_constructor(self):
10421040
bdate_range(START, periods=20, freq=BDay())
10431041
bdate_range(end=START, periods=20, freq=BDay())
10441042

1045-
msg = "periods must be a number, got B"
1043+
msg = "periods must be an integer, got B"
10461044
with pytest.raises(TypeError, match=msg):
10471045
date_range("2011-1-1", "2012-1-1", "B")
10481046

@@ -1120,7 +1118,7 @@ def test_constructor(self):
11201118
bdate_range(START, periods=20, freq=CDay())
11211119
bdate_range(end=START, periods=20, freq=CDay())
11221120

1123-
msg = "periods must be a number, got C"
1121+
msg = "periods must be an integer, got C"
11241122
with pytest.raises(TypeError, match=msg):
11251123
date_range("2011-1-1", "2012-1-1", "C")
11261124

pandas/tests/indexes/interval/test_interval_range.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,10 @@ def test_interval_dtype(self, start, end, expected):
236236

237237
def test_interval_range_fractional_period(self):
238238
# float value for periods
239-
expected = interval_range(start=0, periods=10)
240-
msg = "Non-integer 'periods' in pd.date_range, .* pd.interval_range"
241-
with tm.assert_produces_warning(FutureWarning, match=msg):
242-
result = interval_range(start=0, periods=10.5)
243-
tm.assert_index_equal(result, expected)
239+
msg = "periods must be an integer, got 10.5"
240+
ts = Timestamp("2024-03-25")
241+
with pytest.raises(TypeError, match=msg):
242+
interval_range(ts, periods=10.5)
244243

245244
def test_constructor_coverage(self):
246245
# equivalent timestamp-like start/end
@@ -340,7 +339,7 @@ def test_errors(self):
340339
interval_range(start=Timedelta("1 day"), end=Timedelta("10 days"), freq=2)
341340

342341
# invalid periods
343-
msg = "periods must be a number, got foo"
342+
msg = "periods must be an integer, got foo"
344343
with pytest.raises(TypeError, match=msg):
345344
interval_range(start=0, periods="foo")
346345

pandas/tests/indexes/period/test_constructors.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,9 @@ def test_constructor_invalid_quarters(self):
196196
)
197197

198198
def test_period_range_fractional_period(self):
199-
msg = "Non-integer 'periods' in pd.date_range, pd.timedelta_range"
200-
with tm.assert_produces_warning(FutureWarning, match=msg):
201-
result = period_range("2007-01", periods=10.5, freq="M")
202-
exp = period_range("2007-01", periods=10, freq="M")
203-
tm.assert_index_equal(result, exp)
199+
msg = "periods must be an integer, got 10.5"
200+
with pytest.raises(TypeError, match=msg):
201+
period_range("2007-01", periods=10.5, freq="M")
204202

205203
def test_constructor_with_without_freq(self):
206204
# GH53687

pandas/tests/indexes/period/test_period_range.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def test_start_end_non_nat(self):
7070

7171
def test_periods_requires_integer(self):
7272
# invalid periods param
73-
msg = "periods must be a number, got foo"
73+
msg = "periods must be an integer, got foo"
7474
with pytest.raises(TypeError, match=msg):
7575
period_range(start="2017Q1", periods="foo")
7676

pandas/tests/indexes/timedeltas/test_constructors.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,12 @@ def test_constructor_iso(self):
143143
tm.assert_index_equal(result, expected)
144144

145145
def test_timedelta_range_fractional_period(self):
146-
msg = "Non-integer 'periods' in pd.date_range, pd.timedelta_range"
147-
with tm.assert_produces_warning(FutureWarning, match=msg):
148-
rng = timedelta_range("1 days", periods=10.5)
149-
exp = timedelta_range("1 days", periods=10)
150-
tm.assert_index_equal(rng, exp)
146+
msg = "periods must be an integer"
147+
with pytest.raises(TypeError, match=msg):
148+
timedelta_range("1 days", periods=10.5)
151149

152150
def test_constructor_coverage(self):
153-
msg = "periods must be a number, got foo"
151+
msg = "periods must be an integer, got foo"
154152
with pytest.raises(TypeError, match=msg):
155153
timedelta_range(start="1 days", periods="foo", freq="D")
156154

0 commit comments

Comments
 (0)