Skip to content

DEPR: Timestamp.freq #33832

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

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ Deprecations
arguments (:issue:`27573`).

- :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`)
- The :class:`Timestamp` attribute ``freq`` is deprecated and will be removed in a future version; passing ``freq`` to the constructor will raise ``TypeError`` (:issue:`15146`)

.. ---------------------------------------------------------------------------

Expand Down
9 changes: 9 additions & 0 deletions pandas/_libs/tslib.pyx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import warnings

import cython

from cpython.datetime cimport (
Expand Down Expand Up @@ -163,6 +165,13 @@ def ints_to_pydatetime(
elif box == "timestamp":
func_create = create_timestamp_from_ts

if freq is not None:
warnings.warn(
"Passing `freq` to Timestamp is deprecated and will raise "
"TypeError in a future version.",
FutureWarning,
)

if isinstance(freq, str):
freq = to_offset(freq)
elif box == "time":
Expand Down
7 changes: 7 additions & 0 deletions pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,13 @@ class Timestamp(_Timestamp):
if ts.value == NPY_NAT:
return NaT

if freq is not None:
warnings.warn(
"Passing `freq` to Timestamp is deprecated and will raise "
"TypeError in a future version.",
FutureWarning,
)

if freq is None:
# GH 22311: Try to extract the frequency of a given Timestamp input
freq = getattr(ts_input, 'freq', None)
Expand Down
11 changes: 11 additions & 0 deletions pandas/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
from pandas.core import ops
from pandas.core.indexes.api import Index, MultiIndex

silence_freq_deprecation = pytest.mark.filterwarnings(
"ignore:Passing `freq` to Timestamp is deprecated"
)


# ----------------------------------------------------------------
# Configuration / Settings
Expand Down Expand Up @@ -78,6 +82,13 @@ def pytest_runtest_setup(item):
pytest.skip("skipping high memory test since --run-high-memory was not set")


def pytest_collection_modifyitems(config, items):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this show up in a lot of places?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I was putting pytestmark = ... in dozens of files and barely making a dent before putting it here instead

for item in items:
# By adding this marker here, we do not need to silence it throughout
# the tests
item.add_marker(silence_freq_deprecation)


# Hypothesis
hypothesis.settings.register_profile(
"ci",
Expand Down
38 changes: 29 additions & 9 deletions pandas/tests/arithmetic/test_datetime64.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,10 @@ def test_dt64arr_sub_dt64object_array(self, box_with_array, tz_naive_fixture):

warn = PerformanceWarning if box_with_array is not pd.DataFrame else None
with tm.assert_produces_warning(warn):
result = obj - obj.astype(object)
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)
result = obj - obj.astype(object)
tm.assert_equal(result, expected)

def test_dt64arr_naive_sub_dt64ndarray(self, box_with_array):
Expand Down Expand Up @@ -1457,11 +1460,15 @@ def test_dt64arr_add_sub_offset_array(
# GH#10699 array of offsets

tz = tz_naive_fixture
dti = pd.date_range("2017-01-01", periods=2, tz=tz)
dtarr = tm.box_expected(dti, box_with_array)
with warnings.catch_warnings():
warnings.simplefilter("ignore", FutureWarning)
dti = pd.date_range("2017-01-01", periods=2, tz=tz)
dtarr = tm.box_expected(dti, box_with_array)

other = np.array([pd.offsets.MonthEnd(), pd.offsets.Day(n=2)])
expected = DatetimeIndex([op(dti[n], other[n]) for n in range(len(dti))])
with warnings.catch_warnings():
warnings.simplefilter("ignore", FutureWarning)
expected = DatetimeIndex([op(dti[n], other[n]) for n in range(len(dti))])
expected = tm.box_expected(expected, box_with_array)

if box_other:
Expand All @@ -1471,7 +1478,9 @@ def test_dt64arr_add_sub_offset_array(
if box_with_array is pd.DataFrame and not (tz is None and not box_other):
warn = None
with tm.assert_produces_warning(warn):
res = op(dtarr, other)
with warnings.catch_warnings():
warnings.simplefilter("ignore", FutureWarning)
res = op(dtarr, other)

tm.assert_equal(res, expected)

Expand Down Expand Up @@ -2391,10 +2400,15 @@ def test_dti_addsub_offset_arraylike(
xbox = get_upcast_box(box, other)

with tm.assert_produces_warning(PerformanceWarning):
res = op(dti, other)
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)
res = op(dti, other)

expected = DatetimeIndex(
[op(dti[n], other[n]) for n in range(len(dti))], name=names[2], freq="infer"
[op(dti[n], other[n]) for n in range(len(dti))],
name=names[2],
freq="infer",
)
expected = tm.box_expected(expected, xbox)
tm.assert_equal(res, expected)
Expand All @@ -2418,14 +2432,20 @@ def test_dti_addsub_object_arraylike(
warn = None

with tm.assert_produces_warning(warn):
result = dtarr + other
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)
result = dtarr + other
tm.assert_equal(result, expected)

expected = pd.DatetimeIndex(["2016-12-31", "2016-12-29"], tz=tz_naive_fixture)
expected = tm.box_expected(expected, xbox)

with tm.assert_produces_warning(warn):
result = dtarr - other
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)
result = dtarr - other
tm.assert_equal(result, expected)


Expand Down
70 changes: 36 additions & 34 deletions pandas/tests/indexes/datetimes/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,40 +242,42 @@ def test_datetimeindex_accessors(self):

assert dti.is_month_start[0] == 1

tests = [
(Timestamp("2013-06-01", freq="M").is_month_start, 1),
(Timestamp("2013-06-01", freq="BM").is_month_start, 0),
(Timestamp("2013-06-03", freq="M").is_month_start, 0),
(Timestamp("2013-06-03", freq="BM").is_month_start, 1),
(Timestamp("2013-02-28", freq="Q-FEB").is_month_end, 1),
(Timestamp("2013-02-28", freq="Q-FEB").is_quarter_end, 1),
(Timestamp("2013-02-28", freq="Q-FEB").is_year_end, 1),
(Timestamp("2013-03-01", freq="Q-FEB").is_month_start, 1),
(Timestamp("2013-03-01", freq="Q-FEB").is_quarter_start, 1),
(Timestamp("2013-03-01", freq="Q-FEB").is_year_start, 1),
(Timestamp("2013-03-31", freq="QS-FEB").is_month_end, 1),
(Timestamp("2013-03-31", freq="QS-FEB").is_quarter_end, 0),
(Timestamp("2013-03-31", freq="QS-FEB").is_year_end, 0),
(Timestamp("2013-02-01", freq="QS-FEB").is_month_start, 1),
(Timestamp("2013-02-01", freq="QS-FEB").is_quarter_start, 1),
(Timestamp("2013-02-01", freq="QS-FEB").is_year_start, 1),
(Timestamp("2013-06-30", freq="BQ").is_month_end, 0),
(Timestamp("2013-06-30", freq="BQ").is_quarter_end, 0),
(Timestamp("2013-06-30", freq="BQ").is_year_end, 0),
(Timestamp("2013-06-28", freq="BQ").is_month_end, 1),
(Timestamp("2013-06-28", freq="BQ").is_quarter_end, 1),
(Timestamp("2013-06-28", freq="BQ").is_year_end, 0),
(Timestamp("2013-06-30", freq="BQS-APR").is_month_end, 0),
(Timestamp("2013-06-30", freq="BQS-APR").is_quarter_end, 0),
(Timestamp("2013-06-30", freq="BQS-APR").is_year_end, 0),
(Timestamp("2013-06-28", freq="BQS-APR").is_month_end, 1),
(Timestamp("2013-06-28", freq="BQS-APR").is_quarter_end, 1),
(Timestamp("2013-03-29", freq="BQS-APR").is_year_end, 1),
(Timestamp("2013-11-01", freq="AS-NOV").is_year_start, 1),
(Timestamp("2013-10-31", freq="AS-NOV").is_year_end, 1),
(Timestamp("2012-02-01").days_in_month, 29),
(Timestamp("2013-02-01").days_in_month, 28),
]
with tm.assert_produces_warning(FutureWarning):
# passing freq to Timestamp
tests = [
(Timestamp("2013-06-01", freq="M").is_month_start, 1),
(Timestamp("2013-06-01", freq="BM").is_month_start, 0),
(Timestamp("2013-06-03", freq="M").is_month_start, 0),
(Timestamp("2013-06-03", freq="BM").is_month_start, 1),
(Timestamp("2013-02-28", freq="Q-FEB").is_month_end, 1),
(Timestamp("2013-02-28", freq="Q-FEB").is_quarter_end, 1),
(Timestamp("2013-02-28", freq="Q-FEB").is_year_end, 1),
(Timestamp("2013-03-01", freq="Q-FEB").is_month_start, 1),
(Timestamp("2013-03-01", freq="Q-FEB").is_quarter_start, 1),
(Timestamp("2013-03-01", freq="Q-FEB").is_year_start, 1),
(Timestamp("2013-03-31", freq="QS-FEB").is_month_end, 1),
(Timestamp("2013-03-31", freq="QS-FEB").is_quarter_end, 0),
(Timestamp("2013-03-31", freq="QS-FEB").is_year_end, 0),
(Timestamp("2013-02-01", freq="QS-FEB").is_month_start, 1),
(Timestamp("2013-02-01", freq="QS-FEB").is_quarter_start, 1),
(Timestamp("2013-02-01", freq="QS-FEB").is_year_start, 1),
(Timestamp("2013-06-30", freq="BQ").is_month_end, 0),
(Timestamp("2013-06-30", freq="BQ").is_quarter_end, 0),
(Timestamp("2013-06-30", freq="BQ").is_year_end, 0),
(Timestamp("2013-06-28", freq="BQ").is_month_end, 1),
(Timestamp("2013-06-28", freq="BQ").is_quarter_end, 1),
(Timestamp("2013-06-28", freq="BQ").is_year_end, 0),
(Timestamp("2013-06-30", freq="BQS-APR").is_month_end, 0),
(Timestamp("2013-06-30", freq="BQS-APR").is_quarter_end, 0),
(Timestamp("2013-06-30", freq="BQS-APR").is_year_end, 0),
(Timestamp("2013-06-28", freq="BQS-APR").is_month_end, 1),
(Timestamp("2013-06-28", freq="BQS-APR").is_quarter_end, 1),
(Timestamp("2013-03-29", freq="BQS-APR").is_year_end, 1),
(Timestamp("2013-11-01", freq="AS-NOV").is_year_start, 1),
(Timestamp("2013-10-31", freq="AS-NOV").is_year_end, 1),
(Timestamp("2012-02-01").days_in_month, 29),
(Timestamp("2013-02-01").days_in_month, 28),
]

for ts, value in tests:
assert ts == value
Expand Down
9 changes: 7 additions & 2 deletions pandas/tests/indexes/datetimes/test_shift.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
import warnings

import pytest
import pytz
Expand Down Expand Up @@ -149,5 +150,9 @@ def test_shift_bmonth(self):

rng = date_range(START, END, freq=pd.offsets.BMonthEnd())
with tm.assert_produces_warning(pd.errors.PerformanceWarning):
shifted = rng.shift(1, freq=pd.offsets.CDay())
assert shifted[0] == rng[0] + pd.offsets.CDay()
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)

shifted = rng.shift(1, freq=pd.offsets.CDay())
assert shifted[0] == rng[0] + pd.offsets.CDay()
17 changes: 12 additions & 5 deletions pandas/tests/indexes/datetimes/test_to_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,11 @@ def test_to_period_tz(self, tz):

with tm.assert_produces_warning(UserWarning):
# GH#21333 warning that timezone info will be lost
result = ts.to_period()[0]
expected = ts[0].to_period()
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)
result = ts.to_period()[0]
expected = ts[0].to_period()

assert result == expected

Expand All @@ -165,9 +168,13 @@ def test_to_period_tz_utc_offset_consistency(self, tz):
# GH#22905
ts = date_range("1/1/2000", "2/1/2000", tz="Etc/GMT-1")
with tm.assert_produces_warning(UserWarning):
result = ts.to_period()[0]
expected = ts[0].to_period()
assert result == expected
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)
result = ts.to_period()[0]
expected = ts[0].to_period()

assert result == expected

def test_to_period_nofreq(self):
idx = DatetimeIndex(["2000-01-01", "2000-01-02", "2000-01-04"])
Expand Down
13 changes: 11 additions & 2 deletions pandas/tests/indexes/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import math
import operator
import re
import warnings

import numpy as np
import pytest
Expand Down Expand Up @@ -1924,12 +1925,20 @@ def test_outer_join_sort(self):
right_index = tm.makeDateIndex(10)

with tm.assert_produces_warning(RuntimeWarning):
result = left_index.join(right_index, how="outer")
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)

result = left_index.join(right_index, how="outer")

# right_index in this case because DatetimeIndex has join precedence
# over Int64Index
with tm.assert_produces_warning(RuntimeWarning):
expected = right_index.astype(object).union(left_index.astype(object))
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)

expected = right_index.astype(object).union(left_index.astype(object))

tm.assert_index_equal(result, expected)

Expand Down
17 changes: 13 additions & 4 deletions pandas/tests/scalar/timestamp/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pandas.errors import OutOfBoundsDatetime

from pandas import Period, Timedelta, Timestamp, compat
import pandas._testing as tm

from pandas.tseries import offsets

Expand Down Expand Up @@ -187,7 +188,8 @@ def test_constructor_invalid_tz(self):
# GH#5168
# case where user tries to pass tz as an arg, not kwarg, gets
# interpreted as a `freq`
Timestamp("2012-01-01", "US/Pacific")
with tm.assert_produces_warning(FutureWarning):
Timestamp("2012-01-01", "US/Pacific")

def test_constructor_strptime(self):
# GH25016
Expand Down Expand Up @@ -271,7 +273,8 @@ def test_constructor_keyword(self):
def test_constructor_fromordinal(self):
base = datetime(2000, 1, 1)

ts = Timestamp.fromordinal(base.toordinal(), freq="D")
with tm.assert_produces_warning(FutureWarning):
ts = Timestamp.fromordinal(base.toordinal(), freq="D")
assert base == ts
assert ts.freq == "D"
assert base.toordinal() == ts.toordinal()
Expand Down Expand Up @@ -495,15 +498,21 @@ def test_construct_with_different_string_format(self, arg):

def test_construct_timestamp_preserve_original_frequency(self):
# GH 22311
result = Timestamp(Timestamp("2010-08-08", freq="D")).freq
with tm.assert_produces_warning(FutureWarning):
result = Timestamp(Timestamp("2010-08-08", freq="D")).freq
expected = offsets.Day()
assert result == expected

def test_constructor_invalid_frequency(self):
# GH 22311
msg = "Invalid frequency:"
with pytest.raises(ValueError, match=msg):
Timestamp("2012-01-01", freq=[])
with tm.assert_produces_warning(FutureWarning):
Timestamp("2012-01-01", freq=[])

def test_freq_deprecated(self):
with tm.assert_produces_warning(FutureWarning):
Timestamp("2012-01-01", freq="D")

@pytest.mark.parametrize("box", [datetime, Timestamp])
def test_raise_tz_and_tzinfo_in_datetime_input(self, box):
Expand Down
9 changes: 8 additions & 1 deletion pandas/tests/series/test_timeseries.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import warnings

import numpy as np
import pytest

Expand Down Expand Up @@ -115,7 +117,12 @@ def test_asarray_object_dt64(self, tz):

with tm.assert_produces_warning(None):
# Future behavior (for tzaware case) with no warning
result = np.asarray(ser, dtype=object)
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)
# FIXME: this makes the assert_produces_warning(None) toothless

result = np.asarray(ser, dtype=object)

expected = np.array(
[pd.Timestamp("2000-01-01", tz=tz), pd.Timestamp("2000-01-02", tz=tz)]
Expand Down
6 changes: 5 additions & 1 deletion pandas/tseries/offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,11 @@ def apply(self, other):
# shift by n days plus 2 to get past the weekend
days = n + 2

result = other + timedelta(days=7 * weeks + days)
with warnings.catch_warnings():
# Passing freq to Timestamp constructor
warnings.simplefilter("ignore", FutureWarning)
result = other + timedelta(days=7 * weeks + days)

if self.offset:
result = result + self.offset
return result
Expand Down