Skip to content

REF: relocate _freq storage from DTA/TDA arrays to Index (GH#24566)#65322

Merged
mroeschke merged 4 commits intopandas-dev:mainfrom
jbrockmendel:ref-array-no-freq-13
Apr 29, 2026
Merged

REF: relocate _freq storage from DTA/TDA arrays to Index (GH#24566)#65322
mroeschke merged 4 commits intopandas-dev:mainfrom
jbrockmendel:ref-array-no-freq-13

Conversation

@jbrockmendel
Copy link
Copy Markdown
Member

Summary

  • Split PeriodArray.to_timestamp freq inference into PeriodArray._to_timestamp_freq(dta, target_freq, how). Array-level to_timestamp now returns a bare DTA; PeriodIndex.to_timestamp calls the helper and stamps the result.
  • Move freq-stamping out of _generate_range. DatetimeArray._generate_range and TimedeltaArray._generate_range now return bare arrays; the three callers (date_range, timedelta_range, DatetimeIndexOpsMixin.shift) own the freq stamp.
  • Relocate _freq storage from DTA/TDA to DatetimeTimedeltaMixin. Getter, validating setter, and class attribute all live on the Index now. Every former `self._data._freq = X` / `arr._freq = X` write site in `pandas/core/indexes/` is rewritten to stamp `self._freq` on the wrapping Index. `copy()`, `_view()`, `Index.new` (wrap-DTI/TDI case), and `as_unit()` explicitly carry `_freq` forward; `pytables`, `DatetimeIndex.new` fastpath, and `_pin_freq` were updated to match.
  • Pickle compat. `DatetimeIndex/TimedeltaIndex.reduce` now include freq in the dict; `_new_DatetimeIndex` / new `_new_TimedeltaIndex` migrate legacy array-side `_freq` payloads up onto the Index on unpickle.
  • Bycatch: `Grouper._codes_and_uniques` was returning `grouping_vector.result_index._values` (a DTA) for BaseGrouper uniques, which lost freq on the trip through `Index._with_infer`. Returning the full `result_index` (combined with the new Index-preserving branch in `Index.new`) fixes pivot_table silently dropping freq.

Part of GH#24566. Follows up on #65266 / #65276 / #65285.

Test plan

  • `pandas/tests/indexes`, `arrays`, `arithmetic`, `resample`, `reshape`, `tseries`, `tools`, `groupby`, `frame`, `series` — 124K+ tests pass
  • `pandas/tests/io` (ex-SQL/GBQ), `pandas/tests/plotting` — 15K+ tests pass
  • pickle round-trip preserves freq for DatetimeIndex and TimedeltaIndex
  • pre-commit clean; mypy clean on touched files (pre-existing `frame.py:17388` unused-ignore remains)

🤖 Generated with Claude Code

jbrockmendel and others added 3 commits April 21, 2026 15:45
…566)

PeriodArray.to_timestamp now returns a bare DatetimeArray; the freq
inference moves to a new PeriodArray._to_timestamp_freq helper that
PeriodIndex.to_timestamp consumes. Array-level to_timestamp no longer
manages freq, matching the direction of earlier PRs that pulled freq
management off DTA/TDA.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DatetimeArray._generate_range and TimedeltaArray._generate_range now
return bare arrays; the three callers (date_range, timedelta_range,
DatetimeIndexOpsMixin.shift) stamp freq explicitly. Continues moving
freq management off DTA/TDA toward the Index level.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…H#24566)

_freq now lives on the Index. DatetimeTimedeltaMixin owns the class
attribute, property getter, and validating setter; DatetimeIndexOpsMixin
keeps a simpler getter that routes PeriodIndex through self._data.freq
(still dtype-derived on the PeriodArray side).

All former `self._data._freq = X` / `arr._freq = X` write sites across
core/indexes/ now write `self._freq = X` on the wrapping Index. copy(),
_view(), Index.__new__ (wrap-DTI/TDI case), and as_unit() explicitly
carry _freq forward. pytables, DatetimeIndex.__new__ fastpath, and
_pin_freq were updated to match.

Pickle compat: DatetimeIndex/TimedeltaIndex __reduce__ now include freq
in the dict; _new_DatetimeIndex / _new_TimedeltaIndex migrate legacy
array-side _freq payloads up onto the Index on unpickle.

Also fixed Grouper._codes_and_uniques to return the full Index (not
._values) for datetime-like BaseGrouper uniques so freq survives the
trip through Index._with_infer — was causing pivot_table to drop freq.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jbrockmendel jbrockmendel added the Refactor Internal refactoring of code label Apr 21, 2026
@jbrockmendel jbrockmendel added the Refactor Internal refactoring of code label Apr 21, 2026
…566)

When freq was relocated from DatetimeIndexOpsMixin to DatetimeTimedeltaMixin,
the docstring wasn't copied to the override. numpydoc validation flagged
pandas.DatetimeIndex.freq / TimedeltaIndex.freq as missing a docstring,
which the docbuild treats as an error via --warnings-are-errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jbrockmendel jbrockmendel marked this pull request as draft April 21, 2026 23:52
@jbrockmendel jbrockmendel marked this pull request as ready for review April 22, 2026 21:22
@mroeschke mroeschke added this to the 3.1 milestone Apr 29, 2026
@mroeschke mroeschke merged commit 09fc282 into pandas-dev:main Apr 29, 2026
46 checks passed
@mroeschke
Copy link
Copy Markdown
Member

Thanks @jbrockmendel

@jbrockmendel jbrockmendel deleted the ref-array-no-freq-13 branch April 29, 2026 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Refactor Internal refactoring of code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants