Skip to content

DEPR: the method is_anchored() for offsets #56594

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

Merged
merged 7 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 2 additions & 0 deletions doc/source/whatsnew/v2.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ Other Deprecations
- Changed :meth:`Timedelta.resolution_string` to return ``h``, ``min``, ``s``, ``ms``, ``us``, and ``ns`` instead of ``H``, ``T``, ``S``, ``L``, ``U``, and ``N``, for compatibility with respective deprecations in frequency aliases (:issue:`52536`)
- Deprecated :attr:`offsets.Day.delta`, :attr:`offsets.Hour.delta`, :attr:`offsets.Minute.delta`, :attr:`offsets.Second.delta`, :attr:`offsets.Milli.delta`, :attr:`offsets.Micro.delta`, :attr:`offsets.Nano.delta`, use ``pd.Timedelta(obj)`` instead (:issue:`55498`)
- Deprecated :func:`pandas.api.types.is_interval` and :func:`pandas.api.types.is_period`, use ``isinstance(obj, pd.Interval)`` and ``isinstance(obj, pd.Period)`` instead (:issue:`55264`)
- Deprecated :func:`pd.DateOffset().is_anchored()`, use ``DateOffset().n == 1`` instead (:issue:`55388`)
Copy link
Member

Choose a reason for hiding this comment

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

:meth:DateOffset.is_anchored, use ``obj.n == 1` for non-Tick subclasses (for Tick this was always False)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks, I did as you suggested

- Deprecated :func:`pd.core.internals.api.make_block`, use public APIs instead (:issue:`40226`)
- Deprecated :func:`read_gbq` and :meth:`DataFrame.to_gbq`. Use ``pandas_gbq.read_gbq`` and ``pandas_gbq.to_gbq`` instead https://pandas-gbq.readthedocs.io/en/latest/api.html (:issue:`55525`)
- Deprecated :meth:`.DataFrameGroupBy.fillna` and :meth:`.SeriesGroupBy.fillna`; use :meth:`.DataFrameGroupBy.ffill`, :meth:`.DataFrameGroupBy.bfill` for forward and backward filling or :meth:`.DataFrame.fillna` to fill with a single value (or the Series equivalents) (:issue:`55718`)
Expand All @@ -592,6 +593,7 @@ Other Deprecations
- Deprecated :meth:`Series.ravel`, the underlying array is already 1D, so ravel is not necessary (:issue:`52511`)
- Deprecated :meth:`Series.resample` and :meth:`DataFrame.resample` with a :class:`PeriodIndex` (and the 'convention' keyword), convert to :class:`DatetimeIndex` (with ``.to_timestamp()``) before resampling instead (:issue:`53481`)
- Deprecated :meth:`Series.view`, use :meth:`Series.astype` instead to change the dtype (:issue:`20251`)
- Deprecated :meth:`offsets.Tick().is_anchored()`, use ``False`` instead (:issue:`55388`)
Copy link
Member

Choose a reason for hiding this comment

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

no parentheses

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for reviewing this PR. I removed the parentheses

- Deprecated ``core.internals`` members ``Block``, ``ExtensionBlock``, and ``DatetimeTZBlock``, use public APIs instead (:issue:`55139`)
- Deprecated ``year``, ``month``, ``quarter``, ``day``, ``hour``, ``minute``, and ``second`` keywords in the :class:`PeriodIndex` constructor, use :meth:`PeriodIndex.from_fields` instead (:issue:`55960`)
- Deprecated accepting a type as an argument in :meth:`Index.view`, call without any arguments instead (:issue:`55709`)
Expand Down
54 changes: 52 additions & 2 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -756,18 +756,27 @@ cdef class BaseOffset:
raise ValueError(f"{self} is a non-fixed frequency")

def is_anchored(self) -> bool:
# TODO: Does this make sense for the general case? It would help
# if there were a canonical docstring for what is_anchored means.
# GH#55388
"""
Return boolean whether the frequency is a unit frequency (n=1).

.. deprecated:: 2.2.0
The is_anchored is deprecated and will be removed in a future version.
Copy link
Member

Choose a reason for hiding this comment

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

"The is_anchored is deprecated" -> "is_anchored is deprecated"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's done

Do ``DateOffset().n == 1`` instead of ``DateOffset().is_anchored()``.
Copy link
Member

Choose a reason for hiding this comment

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

"Use obj.n == 1"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


Examples
--------
>>> pd.DateOffset().is_anchored()
True
>>> pd.DateOffset(2).is_anchored()
False
"""
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use {type(self).__name__}.n == 1 instead.",
Copy link
Member

Choose a reason for hiding this comment

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

{type(self).name}.n -> obj.n

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

FutureWarning,
stacklevel=find_stack_level(),
)
return self.n == 1

# ------------------------------------------------------------------
Expand Down Expand Up @@ -954,6 +963,27 @@ cdef class Tick(SingleConstructorOffset):
return True

def is_anchored(self) -> bool:
# GH#55388
"""
Return False.

.. deprecated:: 2.2.0
The is_anchored is deprecated and will be removed in a future version.
Do ``False`` instead of ``offsets.Tick().is_anchored()``.

Examples
--------
>>> pd.offsets.Tick().is_anchored()
Copy link
Member

Choose a reason for hiding this comment

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

Tick should never be initialized directly; use a subclass here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you, I will use Hour

False
>>> pd.offsets.Tick(2).is_anchored()
False
"""
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use False instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return False

# This is identical to BaseOffset.__hash__, but has to be redefined here
Expand Down Expand Up @@ -2663,6 +2693,13 @@ cdef class QuarterOffset(SingleConstructorOffset):
return f"{self._prefix}-{month}"

def is_anchored(self) -> bool:
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use {type(self).__name__}.n == 1 "
f" and {type(self).__name__}.startingMonth is not None instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return self.n == 1 and self.startingMonth is not None

def is_on_offset(self, dt: datetime) -> bool:
Expand Down Expand Up @@ -3308,6 +3345,13 @@ cdef class Week(SingleConstructorOffset):
self._cache = state.pop("_cache", {})

def is_anchored(self) -> bool:
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use {type(self).__name__}.n == 1 "
f" and {type(self).__name__}.weekday is not None instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return self.n == 1 and self.weekday is not None

@apply_wraps
Expand Down Expand Up @@ -3597,6 +3641,12 @@ cdef class FY5253Mixin(SingleConstructorOffset):
self.variation = state.pop("variation")

def is_anchored(self) -> bool:
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use {type(self).__name__}.n == 1 instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return (
self.n == 1 and self.startingMonth is not None and self.weekday is not None
)
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/indexes/interval/test_interval_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def test_constructor_timestamp(self, closed, name, freq, periods, tz):
tm.assert_index_equal(result, expected)

# GH 20976: linspace behavior defined from start/end/periods
if not breaks.freq.is_anchored() and tz is None:
if not breaks.freq.n == 1 and tz is None:
# matches expected only for non-anchored offsets and tz naive
Copy link
Member

Choose a reason for hiding this comment

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

comment here refers to anchoring. i suspect the comment (which i suspect i wrote) misunderstood what "is_anchored" really meant

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks, I removed the comment

# (anchored/DST transitions cause unequal spacing in expected)
result = interval_range(
Expand Down
19 changes: 13 additions & 6 deletions pandas/tests/tseries/offsets/test_business_quarter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import pytest

import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
Expand Down Expand Up @@ -54,9 +55,12 @@ def test_repr(self):
assert repr(BQuarterBegin(startingMonth=1)) == expected

def test_is_anchored(self):
assert BQuarterBegin(startingMonth=1).is_anchored()
assert BQuarterBegin().is_anchored()
assert not BQuarterBegin(2, startingMonth=1).is_anchored()
msg = r"BQuarterBegin.is_anchored\(\) is deprecated "

with tm.assert_produces_warning(FutureWarning, match=msg):
assert BQuarterBegin(startingMonth=1).is_anchored()
assert BQuarterBegin().is_anchored()
assert not BQuarterBegin(2, startingMonth=1).is_anchored()

def test_offset_corner_case(self):
# corner
Expand Down Expand Up @@ -177,9 +181,12 @@ def test_repr(self):
assert repr(BQuarterEnd(startingMonth=1)) == expected

def test_is_anchored(self):
assert BQuarterEnd(startingMonth=1).is_anchored()
assert BQuarterEnd().is_anchored()
assert not BQuarterEnd(2, startingMonth=1).is_anchored()
msg = r"BQuarterEnd.is_anchored\(\) is deprecated "

with tm.assert_produces_warning(FutureWarning, match=msg):
assert BQuarterEnd(startingMonth=1).is_anchored()
assert BQuarterEnd().is_anchored()
assert not BQuarterEnd(2, startingMonth=1).is_anchored()

def test_offset_corner_case(self):
# corner
Expand Down
22 changes: 13 additions & 9 deletions pandas/tests/tseries/offsets/test_fiscal.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytest

from pandas import Timestamp
import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
WeekDay,
assert_is_on_offset,
Expand Down Expand Up @@ -295,15 +296,18 @@ def test_apply(self):

class TestFY5253LastOfMonthQuarter:
def test_is_anchored(self):
assert makeFY5253LastOfMonthQuarter(
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
).is_anchored()
assert makeFY5253LastOfMonthQuarter(
weekday=WeekDay.SAT, startingMonth=3, qtr_with_extra_week=4
).is_anchored()
assert not makeFY5253LastOfMonthQuarter(
2, startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
).is_anchored()
msg = r"FY5253Quarter.is_anchored\(\) is deprecated "

with tm.assert_produces_warning(FutureWarning, match=msg):
assert makeFY5253LastOfMonthQuarter(
startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
).is_anchored()
assert makeFY5253LastOfMonthQuarter(
weekday=WeekDay.SAT, startingMonth=3, qtr_with_extra_week=4
).is_anchored()
assert not makeFY5253LastOfMonthQuarter(
2, startingMonth=1, weekday=WeekDay.SAT, qtr_with_extra_week=4
).is_anchored()

def test_equality(self):
assert makeFY5253LastOfMonthQuarter(
Expand Down
7 changes: 5 additions & 2 deletions pandas/tests/tseries/offsets/test_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,11 @@ def test_default_constructor(self, dt):
assert (dt + DateOffset(2)) == datetime(2008, 1, 4)

def test_is_anchored(self):
assert not DateOffset(2).is_anchored()
assert DateOffset(1).is_anchored()
msg = r"DateOffset.is_anchored\(\) is deprecated "

with tm.assert_produces_warning(FutureWarning, match=msg):
assert not DateOffset(2).is_anchored()
assert DateOffset(1).is_anchored()

def test_copy(self):
assert DateOffset(months=2).copy() == DateOffset(months=2)
Expand Down
19 changes: 13 additions & 6 deletions pandas/tests/tseries/offsets/test_quarter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import pytest

import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
assert_is_on_offset,
assert_offset_equal,
Expand Down Expand Up @@ -53,9 +54,12 @@ def test_repr(self):
assert repr(QuarterBegin(startingMonth=1)) == expected

def test_is_anchored(self):
assert QuarterBegin(startingMonth=1).is_anchored()
assert QuarterBegin().is_anchored()
assert not QuarterBegin(2, startingMonth=1).is_anchored()
msg = r"QuarterBegin.is_anchored\(\) is deprecated "

with tm.assert_produces_warning(FutureWarning, match=msg):
assert QuarterBegin(startingMonth=1).is_anchored()
assert QuarterBegin().is_anchored()
assert not QuarterBegin(2, startingMonth=1).is_anchored()

def test_offset_corner_case(self):
# corner
Expand Down Expand Up @@ -161,9 +165,12 @@ def test_repr(self):
assert repr(QuarterEnd(startingMonth=1)) == expected

def test_is_anchored(self):
assert QuarterEnd(startingMonth=1).is_anchored()
assert QuarterEnd().is_anchored()
assert not QuarterEnd(2, startingMonth=1).is_anchored()
msg = r"QuarterEnd.is_anchored\(\) is deprecated "

with tm.assert_produces_warning(FutureWarning, match=msg):
assert QuarterEnd(startingMonth=1).is_anchored()
assert QuarterEnd().is_anchored()
assert not QuarterEnd(2, startingMonth=1).is_anchored()

def test_offset_corner_case(self):
# corner
Expand Down
5 changes: 4 additions & 1 deletion pandas/tests/tseries/offsets/test_ticks.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,10 @@ def test_tick_equalities(cls):

@pytest.mark.parametrize("cls", tick_classes)
def test_tick_offset(cls):
assert not cls().is_anchored()
msg = rf"{cls.__name__}.is_anchored\(\) is deprecated "

with tm.assert_produces_warning(FutureWarning, match=msg):
assert not cls().is_anchored()


@pytest.mark.parametrize("cls", tick_classes)
Expand Down
12 changes: 8 additions & 4 deletions pandas/tests/tseries/offsets/test_week.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
WeekOfMonth,
)

import pandas._testing as tm
from pandas.tests.tseries.offsets.common import (
WeekDay,
assert_is_on_offset,
Expand All @@ -42,10 +43,13 @@ def test_corner(self):
Week(weekday=-1)

def test_is_anchored(self):
assert Week(weekday=0).is_anchored()
assert not Week().is_anchored()
assert not Week(2, weekday=2).is_anchored()
assert not Week(2).is_anchored()
msg = r"Week.is_anchored\(\) is deprecated "

with tm.assert_produces_warning(FutureWarning, match=msg):
assert Week(weekday=0).is_anchored()
assert not Week().is_anchored()
assert not Week(2, weekday=2).is_anchored()
assert not Week(2).is_anchored()

offset_cases = []
# not business week
Expand Down