Skip to content

[DEV] address pandas 3.1.0 compatibility issues - #2924

Merged
kandersolar merged 20 commits into
pvlib:mainfrom
echedey-ls:dev/breaking-news-pandas3.1
Oct 28, 2026
Merged

kandersolar merged 20 commits into
pvlib:mainfrom
echedey-ls:dev/breaking-news-pandas3.1

Conversation

@echedey-ls

@echedey-ls echedey-ls commented Oct 25, 2026 •

Copy link
Copy Markdown
Member
  • [ ] Closes #xxxx
  • I am familiar with the contributing guidelines
  • [ ] I attest that all AI-generated material has been vetted for accuracy and is in compliance with the pvlib license 💯 free of shitty autocomplete
  • Tests added
  • [ ] Updates entries in docs/sphinx/source/reference for API changes.
  • Adds description and name entries in the appropriate "what's new" file in docs/sphinx/source/whatsnew for all changes. Includes link to the GitHub Issue with :issue:`num` or this Pull Request with :pull:`num`. Includes contributor name and/or GitHub username (link with :ghuser:`user`).
  • New code is fully documented. Includes numpydoc compliant docstrings, examples, and comments where necessary.
  • Pull request is nearly complete and ready for detailed review.
  • Maintainer: Appropriate GitHub Labels (including remote-data) and Milestone are assigned to the Pull Request and linked Issue.

Opening draft PR as there is work regarding the deprecation warnings that is already fixed and a current regression in pandas 3.1.0 I reported in pandas-dev/pandas#71567. Still missing some work.

I have yet to analyze the impact of these changes with regards to minimum version requirements.

@echedey-ls echedey-ls added this to the v0.16.2 milestone Oct 25, 2026
@echedey-ls echedey-ls added remote-data triggers --remote-data pytests and removed remote-data triggers --remote-data pytests labels Oct 25, 2026
@echedey-ls
echedey-ls marked this pull request as ready for review October 25, 2026 23:18
@echedey-ls

Copy link
Copy Markdown
Member Author

I think this is ready for 'early' review. I'd like to wait on feedback from the pandas community on the issue I opened and is linked in PR body. However, I understand this PR has priority as the other PRs need clean tests to ease reviewing. I don't have a clear suggestion on what to do.

I haven't run tests outside of our current CI/CD setup (e.g., pandas 2).

Pandas4Warning: DatetimeIndex.dayofyear is deprecated and will be
removed in a future version. Use DatetimeIndex.day_of_year instead.
…-> DataFrame constructor instead

Pandas4Warning: Passing a list to DataFrame.from_dict is deprecated. Use
the DataFrame constructor instead.
Pandas4Warning: assert_index_equal will check the 'freq' attribute by
default in a future version; these freqs <Minute> and None do not match.
Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(left, right, **kwargs)
…GH#71567 is resolved)

pvlib/iotools/tmy.py:226: in read_tmy3
    data_ymd.iloc[-1] = data_ymd.iloc[-1].replace(year=coerce_year+1)
    ^^^^^^^^^^^^^^^^^
venv/lib/python3.14/site-packages/pandas/core/indexing.py:1010: in __setitem__
    iloc._setitem_with_indexer(indexer, value, self.name)
venv/lib/python3.14/site-packages/pandas/core/indexing.py:2653: in _setitem_with_indexer
    self._setitem_single_block(indexer, value, name)
venv/lib/python3.14/site-packages/pandas/core/indexing.py:2985: in _setitem_single_block
    self.obj._mgr = self.obj._mgr.setitem(indexer=indexer, value=value)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.14/site-packages/pandas/core/internals/managers.py:625: in setitem
    return self.apply("setitem", indexer=indexer, value=value)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.14/site-packages/pandas/core/internals/managers.py:456: in apply
    applied = getattr(b, f)(**kwargs)
              ^^^^^^^^^^^^^^^^^^^^^^^
… to pd.DatetimeArray

Pandas4Warning: DatetimeIndex.values returning an ndarray that drops
timezone information is deprecated. In a future version, this will
return the underlying DatetimeArray instead. Use
'DatetimeIndex.tz_convert(None).to_numpy()' to get a NumPy array of UTC
values, or 'DatetimeIndex.array' to get the ExtensionArray.
@echedey-ls
echedey-ls force-pushed the dev/breaking-news-pandas3.1 branch from a6df807 to 058848c Compare October 25, 2026 23:34
@echedey-ls echedey-ls changed the title [WIP] [DEV] address pandas 3.1.0 compatibility issues [DEV] address pandas 3.1.0 compatibility issues Oct 25, 2026
@echedey-ls echedey-ls added remote-data triggers --remote-data pytests and removed remote-data triggers --remote-data pytests labels Oct 25, 2026

@kandersolar kandersolar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fantastic, thanks @echedey-ls :) These changes all look good to me (one minor suggestion below).

For the map/transform question: I suggest we go ahead with this PR so that our test runs are clean again. If we eventually get feedback from pandas that we should have done something else, we can just make another change.

I haven't run tests outside of our current CI/CD setup (e.g., pandas 2).

I ran (non-remote-data) tests locally for 058848c with pandas 2.3.1 and everything passed.

Comment thread tests/conftest.py Outdated
@echedey-ls echedey-ls added remote-data triggers --remote-data pytests and removed remote-data triggers --remote-data pytests labels Oct 27, 2026
Comment thread tests/test_conftest.py
check_freq is exclusively supported in assert_index_equal, added in
pandas==3.1.0
Comment thread tests/conftest.py
Comment on lines 51 to 53
else:
kwargs.pop('rtol', None)
kwargs.pop('atol', None)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Btw, our minimum pandas is 1.5.0. This behavior for pandas pre-1.1.0 is completely out of date. We should remove it (in another PR), but I'm also hesitant to open an issue and have bots yap.

…mezone information for DatetimeTZDtype is deprecated.

tests/test_solarposition.py::test_sun_rise_set_transit_geometric

/home/echedey/Documents/10_Programming/pvlib-python/tests/test_solarposition.py:835:
Pandas4Warning: Series.values returning an ndarray that drops timezone
information for DatetimeTZDtype is deprecated. In a future version, this
will return the underlying DatetimeArray instead. Use
'Series.dt.tz_convert(None).to_numpy()' to get a NumPy array of UTC
values, or 'Series.array' to get the ExtensionArray.
  See
https://pandas.pydata.org/docs/dev/whatsnew/v3.1.0.html#whatsnew-310-deprecations-values
for more details.
    expected_sunset =
pd.DatetimeIndex(expected_rise_set_spa.sunset.values,
…et object instead of a string from infer_freq

A future version of pandas will return a BaseOffset object instead of a
string from infer_freq. Use
pd.set_option('future.infer_freq_returns_offset', True) to get the
future behavior, or set to False to keep the old behavior and silence
this warning. To preserve the string representation, use
``infer_freq(...).freqstr``.
@echedey-ls echedey-ls added remote-data triggers --remote-data pytests and removed remote-data triggers --remote-data pytests labels Oct 27, 2026
@echedey-ls

Copy link
Copy Markdown
Member Author

I forgot about two other warnings in the logs. Test output should be as clean as it can get from pandas deprecations.

@kandersolar kandersolar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Three warnings remain in the iotools tests: https://github.com/pvlib/pvlib-python/actions/runs/40597652855/job/122517549082?pr=2924

tests/iotools/test_era5.py::test_get_era5_land
  /home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_era5.py:69: Pandas4Warning: assert_index_equal will check the 'freq' attribute by default in a future version; these freqs None and <Hour> do not match. Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(df.index, expected.index)

tests/iotools/test_nasa_power.py::test_get_nasa_power
  /home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_nasa_power.py:42: Pandas4Warning: assert_index_equal will check the 'freq' attribute by default in a future version; these freqs None and <Hour> do not match. Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(data.index, data_index)

tests/iotools/test_nasa_power.py::test_get_nasa_power_pvlib_params_naming
  /home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_nasa_power.py:57: Pandas4Warning: assert_index_equal will check the 'freq' attribute by default in a future version; these freqs None and <Hour> do not match. Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(data.index, data_index)

Can you fix those in this PR too @echedey-ls? If not, no big deal to leave for another PR and get this one merged now.

Otherwise changes all LGTM!

… default

tests/iotools/test_era5.py::test_get_era5_land

/home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_era5.py:69:
Pandas4Warning: assert_index_equal will check the 'freq' attribute by
default in a future version; these freqs None and <Hour> do not match.
Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(df.index, expected.index)

tests/iotools/test_nasa_power.py::test_get_nasa_power

/home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_nasa_power.py:42:
Pandas4Warning: assert_index_equal will check the 'freq' attribute by
default in a future version; these freqs None and <Hour> do not match.
Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(data.index, data_index)

tests/iotools/test_nasa_power.py::test_get_nasa_power_pvlib_params_naming

/home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_nasa_power.py:57:
Pandas4Warning: assert_index_equal will check the 'freq' attribute by
default in a future version; these freqs None and <Hour> do not match.
Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(data.index, data_index)
@echedey-ls echedey-ls added remote-data triggers --remote-data pytests and removed remote-data triggers --remote-data pytests labels Oct 28, 2026
@kandersolar
kandersolar merged commit 77d8890 into pvlib:main Oct 28, 2026
30 of 32 checks passed
@kandersolar

Copy link
Copy Markdown
Member

Thanks @echedey-ls!

@echedey-ls

Copy link
Copy Markdown
Member Author

I will open a PR in short to appease flake8 :(

echedey-ls added a commit to echedey-ls/pvlib-python that referenced this pull request Oct 28, 2026
kandersolar pushed a commit that referenced this pull request Oct 28, 2026
* Fix deprecated inplace operations

* Fix Pandas4Warning: .dayofyear -> .day_of_year

Pandas4Warning: DatetimeIndex.dayofyear is deprecated and will be
removed in a future version. Use DatetimeIndex.day_of_year instead.

* Fix Pandas4Warning: deprecated passing a list to DataFrame.from_dict -> DataFrame constructor instead

Pandas4Warning: Passing a list to DataFrame.from_dict is deprecated. Use
the DataFrame constructor instead.

* Fix Pandas4Warning: assert_index_equal will check the 'freq' attribute

Pandas4Warning: assert_index_equal will check the 'freq' attribute by
default in a future version; these freqs <Minute> and None do not match.
Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(left, right, **kwargs)

* Fix pandas 3.1.0 unexpected behavior on .map (may defer until pandas GH#71567 is resolved)

pvlib/iotools/tmy.py:226: in read_tmy3
    data_ymd.iloc[-1] = data_ymd.iloc[-1].replace(year=coerce_year+1)
    ^^^^^^^^^^^^^^^^^
venv/lib/python3.14/site-packages/pandas/core/indexing.py:1010: in __setitem__
    iloc._setitem_with_indexer(indexer, value, self.name)
venv/lib/python3.14/site-packages/pandas/core/indexing.py:2653: in _setitem_with_indexer
    self._setitem_single_block(indexer, value, name)
venv/lib/python3.14/site-packages/pandas/core/indexing.py:2985: in _setitem_single_block
    self.obj._mgr = self.obj._mgr.setitem(indexer=indexer, value=value)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.14/site-packages/pandas/core/internals/managers.py:625: in setitem
    return self.apply("setitem", indexer=indexer, value=value)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.14/site-packages/pandas/core/internals/managers.py:456: in apply
    applied = getattr(b, f)(**kwargs)
              ^^^^^^^^^^^^^^^^^^^^^^^

* Fix Pandas4Warning: DatetimeIndex.values will change from UTC ndarray to pd.DatetimeArray

Pandas4Warning: DatetimeIndex.values returning an ndarray that drops
timezone information is deprecated. In a future version, this will
return the underlying DatetimeArray instead. Use
'DatetimeIndex.tz_convert(None).to_numpy()' to get a NumPy array of UTC
values, or 'DatetimeIndex.array' to get the ExtensionArray.

* Fix previous commit - use localize to ignore tz, and not fail when input is tz-naive

* Fix prior Pandas4Warning - we need a writable array, not just a ro view

* Fix error in prior commit due to check_freq nonexistent in pandas<3.1.0

* Fix style issues - flake8

* Fix check_freq not in pandas<3.1.0; iotools

* Fix check_freq not in pandas<3.1.0; iotools (II)

* Review: tidy check_freq logic

* Whatsnew

* Fix _check_pandas_assert_kwargs test (after tidying code)

* Fix index check_freq implementation and tests

check_freq is exclusively supported in assert_index_equal, added in
pandas==3.1.0

* Fix Pandas4Warning - Series.values returning an ndarray that drops timezone information for DatetimeTZDtype is deprecated.

tests/test_solarposition.py::test_sun_rise_set_transit_geometric

/home/echedey/Documents/10_Programming/pvlib-python/tests/test_solarposition.py:835:
Pandas4Warning: Series.values returning an ndarray that drops timezone
information for DatetimeTZDtype is deprecated. In a future version, this
will return the underlying DatetimeArray instead. Use
'Series.dt.tz_convert(None).to_numpy()' to get a NumPy array of UTC
values, or 'Series.array' to get the ExtensionArray.
  See
https://pandas.pydata.org/docs/dev/whatsnew/v3.1.0.html#whatsnew-310-deprecations-values
for more details.
    expected_sunset =
pd.DatetimeIndex(expected_rise_set_spa.sunset.values,

* Fix Pandas4Warning: A future version of pandas will return a BaseOffset object instead of a string from infer_freq

A future version of pandas will return a BaseOffset object instead of a
string from infer_freq. Use
pd.set_option('future.infer_freq_returns_offset', True) to get the
future behavior, or set to False to keep the old behavior and silence
this warning. To preserve the string representation, use
``infer_freq(...).freqstr``.

* Review: Fix Pandas4Warning: assert_index_equal will use check_freq by default

tests/iotools/test_era5.py::test_get_era5_land

/home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_era5.py:69:
Pandas4Warning: assert_index_equal will check the 'freq' attribute by
default in a future version; these freqs None and <Hour> do not match.
Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(df.index, expected.index)

tests/iotools/test_nasa_power.py::test_get_nasa_power

/home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_nasa_power.py:42:
Pandas4Warning: assert_index_equal will check the 'freq' attribute by
default in a future version; these freqs None and <Hour> do not match.
Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(data.index, data_index)

tests/iotools/test_nasa_power.py::test_get_nasa_power_pvlib_params_naming

/home/runner/work/pvlib-python/pvlib-python/tests/iotools/test_nasa_power.py:57:
Pandas4Warning: assert_index_equal will check the 'freq' attribute by
default in a future version; these freqs None and <Hour> do not match.
Pass check_freq=True or check_freq=False to silence this warning
    pd.testing.assert_index_equal(data.index, data_index)

* Appease flake8 warnings from #2924
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependency remote-data triggers --remote-data pytests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants