Skip to content

Commit 3ae33c6

Browse files
mgmarinojreback
andauthored
DEPR: Deprecate week, weekofyear in Series.dt,DatetimeIndex (pandas-dev#33595)
* Deprecate week and weekofyear in Series.dt/DatetimeIndex * Add What's New for deprecations * Ignore week/weekofyear attributes in tests * Remove week/weekofyear attributes from tests * Add isocalendar test to replace removed week/weekofyear tests * Add PR issue number * Import warnings at top of module * Tag deprecation tests with PR * Refactor test to improve readability * Return ndarray from DatetimeArray.week - This is then wrapped by DatetimeIndex.week Co-authored-by: Jeff Reback <[email protected]>
1 parent c29e395 commit 3ae33c6

File tree

10 files changed

+102
-17
lines changed

10 files changed

+102
-17
lines changed

doc/source/whatsnew/v1.1.0.rst

+3
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,9 @@ Deprecations
590590

591591
- :func:`pandas.api.types.is_categorical` is deprecated and will be removed in a future version; use `:func:pandas.api.types.is_categorical_dtype` instead (:issue:`33385`)
592592
- :meth:`Index.get_value` is deprecated and will be removed in a future version (:issue:`19728`)
593+
- :meth:`Series.dt.week` and `Series.dt.weekofyear` are deprecated and will be removed in a future version, use :meth:`Series.dt.isocalendar().week` instead (:issue:`33595`)
594+
- :meth:`DatetimeIndex.week` and `DatetimeIndex.weekofyear` are deprecated and will be removed in a future version, use :meth:`DatetimeIndex.isocalendar().week` instead (:issue:`33595`)
595+
- :meth:`DatetimeArray.week` and `DatetimeArray.weekofyear` are deprecated and will be removed in a future version, use :meth:`DatetimeArray.isocalendar().week` instead (:issue:`33595`)
593596
- :meth:`DateOffset.__call__` is deprecated and will be removed in a future version, use ``offset + other`` instead (:issue:`34171`)
594597
- Indexing an :class:`Index` object with a float key is deprecated, and will
595598
raise an ``IndexError`` in the future. You can manually convert to an integer key

pandas/core/arrays/datetimes.py

+26-8
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,32 @@ def isocalendar(self):
12981298
iso_calendar_df.iloc[self._isnan] = None
12991299
return iso_calendar_df
13001300

1301+
@property
1302+
def weekofyear(self):
1303+
"""
1304+
The week ordinal of the year.
1305+
1306+
.. deprecated:: 1.1.0
1307+
1308+
weekofyear and week have been deprecated.
1309+
Please use DatetimeIndex.isocalendar().week instead.
1310+
"""
1311+
warnings.warn(
1312+
"weekofyear and week have been deprecated, please use "
1313+
"DatetimeIndex.isocalendar().week instead, which returns "
1314+
"a Series. To exactly reproduce the behavior of week and "
1315+
"weekofyear and return an Index, you may call "
1316+
"pd.Int64Index(idx.isocalendar().week)",
1317+
FutureWarning,
1318+
stacklevel=3,
1319+
)
1320+
week_series = self.isocalendar().week
1321+
if week_series.hasnans:
1322+
return week_series.to_numpy(dtype="float64", na_value=np.nan)
1323+
return week_series.to_numpy(dtype="int64")
1324+
1325+
week = weekofyear
1326+
13011327
year = _field_accessor(
13021328
"year",
13031329
"Y",
@@ -1482,14 +1508,6 @@ def isocalendar(self):
14821508
dtype: int64
14831509
""",
14841510
)
1485-
weekofyear = _field_accessor(
1486-
"weekofyear",
1487-
"woy",
1488-
"""
1489-
The week ordinal of the year.
1490-
""",
1491-
)
1492-
week = weekofyear
14931511
_dayofweek_doc = """
14941512
The day of the week with Monday=0, Sunday=6.
14951513

pandas/core/indexes/accessors.py

+25
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
datetimelike delegation
33
"""
44
from typing import TYPE_CHECKING
5+
import warnings
56

67
import numpy as np
78

@@ -250,6 +251,30 @@ def isocalendar(self):
250251
"""
251252
return self._get_values().isocalendar().set_index(self._parent.index)
252253

254+
@property
255+
def weekofyear(self):
256+
"""
257+
The week ordinal of the year.
258+
259+
.. deprecated:: 1.1.0
260+
261+
Series.dt.weekofyear and Series.dt.week have been deprecated.
262+
Please use Series.dt.isocalendar().week instead.
263+
"""
264+
warnings.warn(
265+
"Series.dt.weekofyear and Series.dt.week have been deprecated. "
266+
"Please use Series.dt.isocalendar().week instead.",
267+
FutureWarning,
268+
stacklevel=2,
269+
)
270+
week_series = self.isocalendar().week
271+
week_series.name = self.name
272+
if week_series.hasnans:
273+
return week_series.astype("float64")
274+
return week_series.astype("int64")
275+
276+
week = weekofyear
277+
253278

254279
@delegate_names(
255280
delegate=TimedeltaArray, accessors=TimedeltaArray._datetimelike_ops, typ="property"

pandas/tests/arrays/test_datetimelike.py

+3
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,9 @@ def test_bool_properties(self, datetime_index, propname):
546546

547547
@pytest.mark.parametrize("propname", pd.DatetimeIndex._field_ops)
548548
def test_int_properties(self, datetime_index, propname):
549+
if propname in ["week", "weekofyear"]:
550+
# GH#33595 Deprecate week and weekofyear
551+
return
549552
dti = datetime_index
550553
arr = DatetimeArray(dti)
551554

pandas/tests/groupby/transform/test_transform.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ def test_groupby_transform_with_datetimes(func, values):
10221022
dates = pd.date_range("1/1/2011", periods=10, freq="D")
10231023

10241024
stocks = pd.DataFrame({"price": np.arange(10.0)}, index=dates)
1025-
stocks["week_id"] = pd.to_datetime(stocks.index).week
1025+
stocks["week_id"] = dates.isocalendar().set_index(dates).week
10261026

10271027
result = stocks.groupby(stocks["week_id"])["price"].transform(func)
10281028

pandas/tests/indexes/datetimes/test_misc.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ def test_datetimeindex_accessors(self):
156156
assert dti.dayofyear[0] == 1
157157
assert dti.dayofyear[120] == 121
158158

159-
assert dti.weekofyear[0] == 1
160-
assert dti.weekofyear[120] == 18
159+
assert dti.isocalendar().week[0] == 1
160+
assert dti.isocalendar().week[120] == 18
161161

162162
assert dti.quarter[0] == 1
163163
assert dti.quarter[120] == 2
@@ -192,7 +192,7 @@ def test_datetimeindex_accessors(self):
192192
assert len(dti.microsecond) == 365
193193
assert len(dti.dayofweek) == 365
194194
assert len(dti.dayofyear) == 365
195-
assert len(dti.weekofyear) == 365
195+
assert len(dti.isocalendar()) == 365
196196
assert len(dti.quarter) == 365
197197
assert len(dti.is_month_start) == 365
198198
assert len(dti.is_month_end) == 365
@@ -205,6 +205,9 @@ def test_datetimeindex_accessors(self):
205205

206206
# non boolean accessors -> return Index
207207
for accessor in DatetimeIndex._field_ops:
208+
if accessor in ["week", "weekofyear"]:
209+
# GH#33595 Deprecate week and weekofyear
210+
continue
208211
res = getattr(dti, accessor)
209212
assert len(res) == 365
210213
assert isinstance(res, Index)
@@ -285,7 +288,7 @@ def test_datetimeindex_accessors(self):
285288
dates = ["2013/12/29", "2013/12/30", "2013/12/31"]
286289
dates = DatetimeIndex(dates, tz="Europe/Brussels")
287290
expected = [52, 1, 1]
288-
assert dates.weekofyear.tolist() == expected
291+
assert dates.isocalendar().week.tolist() == expected
289292
assert [d.weekofyear for d in dates] == expected
290293

291294
# GH 12806
@@ -383,6 +386,15 @@ def test_iter_readonly():
383386
list(dti)
384387

385388

389+
def test_week_and_weekofyear_are_deprecated():
390+
# GH#33595 Deprecate week and weekofyear
391+
idx = pd.date_range(start="2019-12-29", freq="D", periods=4)
392+
with tm.assert_produces_warning(FutureWarning):
393+
idx.week
394+
with tm.assert_produces_warning(FutureWarning):
395+
idx.weekofyear
396+
397+
386398
def test_isocalendar_returns_correct_values_close_to_new_year_with_tz():
387399
# GH 6538: Check that DatetimeIndex and its TimeStamp elements
388400
# return the same weekofyear accessor close to new year w/ tz

pandas/tests/indexes/datetimes/test_scalar_compat.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ def test_dti_date_out_of_range(self, data):
4040
[
4141
"dayofweek",
4242
"dayofyear",
43-
"week",
44-
"weekofyear",
4543
"quarter",
4644
"days_in_month",
4745
"is_month_start",
@@ -59,6 +57,12 @@ def test_dti_timestamp_fields(self, field):
5957
result = getattr(Timestamp(idx[-1]), field)
6058
assert result == expected
6159

60+
def test_dti_timestamp_isocalendar_fields(self):
61+
idx = tm.makeDateIndex(100)
62+
expected = tuple(idx.isocalendar().iloc[-1].to_list())
63+
result = idx[-1].isocalendar()
64+
assert result == expected
65+
6266
def test_dti_timestamp_freq_fields(self):
6367
# extra fields from DatetimeIndex like quarter and week
6468
idx = tm.makeDateIndex(100)

pandas/tests/scalar/test_nat.py

+6
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ def test_nat_vector_field_access():
6666
# on NaT/Timestamp for compat with datetime
6767
if field == "weekday":
6868
continue
69+
if field in ["week", "weekofyear"]:
70+
# GH#33595 Deprecate week and weekofyear
71+
continue
6972

7073
result = getattr(idx, field)
7174
expected = Index([getattr(x, field) for x in idx])
@@ -78,6 +81,9 @@ def test_nat_vector_field_access():
7881
# on NaT/Timestamp for compat with datetime
7982
if field == "weekday":
8083
continue
84+
if field in ["week", "weekofyear"]:
85+
# GH#33595 Deprecate week and weekofyear
86+
continue
8187

8288
result = getattr(ser.dt, field)
8389
expected = [getattr(x, field) for x in idx]

pandas/tests/series/test_api.py

+3
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,9 @@ def test_dt_accessor_api_for_categorical(self):
719719
tm.assert_equal(res, exp)
720720

721721
for attr in attr_names:
722+
if attr in ["week", "weekofyear"]:
723+
# GH#33595 Deprecate week and weekofyear
724+
continue
722725
res = getattr(c.dt, attr)
723726
exp = getattr(s.dt, attr)
724727

pandas/tests/series/test_datetime_values.py

+13-2
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ def compare(s, name):
8989
for s in cases:
9090
for prop in ok_for_dt:
9191
# we test freq below
92-
if prop != "freq":
92+
# we ignore week and weekofyear because they are deprecated
93+
if prop not in ["freq", "week", "weekofyear"]:
9394
compare(s, prop)
9495

9596
for prop in ok_for_dt_methods:
@@ -122,7 +123,8 @@ def compare(s, name):
122123
for prop in ok_for_dt:
123124

124125
# we test freq below
125-
if prop != "freq":
126+
# we ignore week and weekofyear because they are deprecated
127+
if prop not in ["freq", "week", "weekofyear"]:
126128
compare(s, prop)
127129

128130
for prop in ok_for_dt_methods:
@@ -687,3 +689,12 @@ def test_isocalendar(self, input_series, expected_output):
687689
expected_output, columns=["year", "week", "day"], dtype="UInt32"
688690
)
689691
tm.assert_frame_equal(result, expected_frame)
692+
693+
694+
def test_week_and_weekofyear_are_deprecated():
695+
# GH#33595 Deprecate week and weekofyear
696+
series = pd.to_datetime(pd.Series(["2020-01-01"]))
697+
with tm.assert_produces_warning(FutureWarning):
698+
series.dt.week
699+
with tm.assert_produces_warning(FutureWarning):
700+
series.dt.weekofyear

0 commit comments

Comments
 (0)