Skip to content

Support pandas 3+ in the dataframes API (#40709) - #40768

Open
dhanusharer wants to merge 4 commits into
apache:masterfrom
dhanusharer:support-pandas-3
Open

dhanusharer wants to merge 4 commits into
apache:masterfrom
dhanusharer:support-pandas-3

Conversation

@dhanusharer

Copy link
Copy Markdown

Fixes #40709

Summary of Changes

  • Dependency & Build: Enabled pandas>=2.2.2,<3.2 for Python >=3.11 while preserving pandas<2.4 for Python 3.10 using PEP 508 environment markers. Added py311-pandas-30 tox environment and Gradle task.
  • Introspection Hardening: Added defensive hasattr() checks in frame_base.py decorators (@args_to_kwargs, @populate_defaults, @with_docs_from) to prevent import-time reflection crashes when pandas 3.0 removes deprecated methods or parameters. Handled permanent Copy-on-Write defaults.
  • DataFrames API Updates:
    • Added removed_args=['method'] and avoided passing method to fillna() under pandas 3.0.
    • Added removed_args=['axis'] to groupby() and raised clean NotImplementedError for column-wise groupby.
    • Guarded first, last, and applymap with hasattr() checks.
    • Guarded GroupBy methods (fillna, first, last) with hasattr(DataFrameGroupBy, ...).
    • Removed method=None from _DeferredStringMethods.get_dummies fillna call.
  • Typehint Compatibility: Added support for pandas 3.0 str, pd.StringDtype, and datetime dtypes in dtype_to_fieldtype().
  • Tests: Updated test_applymap_na_action to skip on pandas 3.0+ and added pandas 3.0 ffill/bfill branch to test_fillna_columns.

* Enable pandas 3.x dependency on Python 3.11+ via PEP 508 environment markers
* Update tox.ini and Gradle build configs to test pandas 3.0 in py311
* Add defensive attribute checking in frame_base decorators (args_to_kwargs, populate_defaults, with_docs_from)
* Support pandas 3.0 Copy-on-Write defaults
* Update fillna, groupby, first, last, and applymap to handle removed pandas 3.0 arguments and methods
* Add pandas 3.0 string and datetime dtype recognition in pandas_type_compatibility
* Update frames_test.py to support pandas 3.0
@github-actions github-actions Bot added python core size/m M: 50-249 lines changed labels Oct 24, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📋 Review Summary

This PR updates the DataFrame API, schema conversion utilities, and type compatibility test suites to support Pandas 3.0 (where infer_string is enabled by default) and adds py311-pandas-30 to tox.ini. While the core Pandas 3.0 compatibility fixes are solid, the setup.py package bounds and Gradle test tasks are not updated yet, and one schema conversion path still relies on dtype.kind == 'O' instead of pd.api.types.is_string_dtype.

🔍 General Feedback

  • Dependency & CI Wiring (setup.py & build.gradle): sdks/python/setup.py still caps dataframe_dependency at 'pandas>=2.2.2,<2.4' (with # TODO(https://github.com/apache/beam/issues/40709): support pandas 3+) and docs/test extras at 'pandas<2.6.0'. Additionally, sdks/python/test-suites/tox/py311/build.gradle needs a testPy311pandas-30 task registered so the new py311-pandas-30 tox environment is actually executed in postCommitPyDep (and .github/trigger_files/beam_PostCommit_Python_Dependency.json can be bumped to trigger it on the PR).
  • Remaining dtype.kind == 'O' check in schemas.py: sdks/python/apache_beam/dataframe/schemas.py (line 206 in element_type_from_dataframe) still checks if dtype.kind == 'O': return Any when inferring schema types from a proxy without element_type. Under Pandas 3.0, default string columns have pd.StringDtype(na_value=np.nan) (dtype.kind == 'U'), which bypasses that branch and falls through to dtype_to_fieldtype (raising TypeError: Unable to encounter corresponding Beam type for dtype=str). Updating that check to if dtype.kind == 'O' or pd.api.types.is_string_dtype(dtype): (or handling pd.api.types.is_string_dtype in pandas_type_compatibility.py) will keep string column fallback consistent.

💡 Tip: Comment /gemini review on this pull request to trigger a new Gemini code review.

💬 Inline Findings

  • sdks/python/tox.ini (line 376): 🟠 High: py311-pandas-30 is added here in tox.ini, but two other places need to be updated in tandem:
  1. sdks/python/test-suites/tox/py311/build.gradle needs a corresponding toxTask "testPy311pandas-30", "py311-pandas-30", "${posargs}" (added to test and postCommitPyDep) so that CI actually runs this tox environment.
  2. sdks/python/setup.py still restricts dataframe_dependency to 'pandas>=2.2.2,<2.4' (and docs/test extras to 'pandas<2.6.0'). Since tox installs the package with extras = test,dataframe,..., pip will either report a version conflict in commands_pre (pip check) or prevent users from installing Pandas 3.0 with apache-beam[dataframe].
  • sdks/python/apache_beam/dataframe/schemas_test.py (line 227): 🟡 Medium: When major >= 3, series_tests is reassigned instead of appended to (+=), which drops all the numeric and nullable integer Series test cases defined in lines 211–218 on Pandas 3+.
      series_tests += [(pd.Series(['a', 'b', 'c'], dtype=dtype), str)]

@dhanusharer

Copy link
Copy Markdown
Author

/gemini review

@github-actions

Copy link
Copy Markdown
Contributor

Assigning reviewers:

R: @claudevdm for label python.
Backup reviewer: jrmccluskey (if the main reviewer is unresponsive, you can escalate to them by tagging their username)

This pull request likely touches a core component ("core" label). Please review with scrutiny.

Note: If you would like to opt out of this review, comment assign to next reviewer.

Available commands:

  • stop reviewer notifications - opt out of the automated review tooling
  • remind me after tests pass - tag the comment author after tests pass
  • waiting on author - shift the attention set back to the author (any comment or push by the author will return the attention set to the reviewers)

The PR bot will only process comments in the main thread (not review comments).

@claudevdm claudevdm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This changes the pandas version for every Python 3.11+ user of the dataframe extra and for every Python 3.11+ precommit. Through the weekly dependency update, it also changes the default containers, which carry users' own pandas code too. That's a large blast radius, so I think we should scope it out before raising the cap, as #40709 asks.

Here is a potential approach:

  1. List what changed in pandas. Go through the 3.0 and 3.1 release notes (breaking changes, removed deprecations, changed defaults). Write down each item that could reach Beam.
  2. List where Beam depends on pandas. That means:
    • the DataFrame API, which wraps pandas methods by name and signature;
    • conversion between dtypes and Beam schemas;
    • DataFrame IO;
    • other modules that use pandas (CSV IO, YAML, interactive, ML handlers);
    • the default containers.
  3. Match the two lists up and decide the behaviour. For each change that reaches Beam, decide whether Beam follows pandas 3, keeps the old behaviour, or marks it unsupported. The changes that alter results without raising an error need an explicit decision, not just a fix. Examples are the new string dtype, copy-on-write, and changed defaults.
  4. Start on pandas 2.3. pandas 2.3 can switch on the pandas 3 string dtype (future.infer_string) and copy-on-write (mode.copy_on_write), and it warns about features pandas 3 removes. Run Beam's tests with those switched on and warnings treated as errors. That finds many problems while the cap stays where it is.
  5. Test every version the cap allows. Run the full tests, including the pandas doctest suite, on both ends of the supported 2.x range and on each 3.x minor version. Group the failures by cause rather than by test.
  6. Look for what the tests miss.
    • Compare Beam's results with pandas' on the same inputs, across argument combinations, not just the defaults.
    • Use a script to compare the signatures of wrapped methods between pandas versions.
    • Run each dtype through a real pipeline (to_dataframe → to_pcollection) and check the output types and missing values.
    • Check that every version-specific branch actually runs on that version.
  7. Check rollout cases.
    • Launcher and workers on different pandas versions.
    • Pipeline update compatibility where output schemas change.
    • What the default containers ship, and when.

The result could be a short write-up on #40709 listing:

  • each breaking change and the decision for it;
  • the remaining work;
  • the rollout plan.

A low-risk rollout would be:

  1. Land the fixes with the cap still below 3, checking each on pandas 2.x.
  2. Add a CI env for each 3.x version once it passes.
  3. Raise the cap in a separate PR with a CHANGES.md entry.

@dhanusharer

Copy link
Copy Markdown
Author

Thank you for the detailed feedback! That approach makes complete sense regarding the blast radius on containers and Python 3.11+ users.

I have adjusted this PR to follow Phase 1 of the proposed rollout:

  1. Restored the Cap: Kept setup.py at pandas>=2.2.2,<2.4 so the blast radius is zero and existing user environments / containers remain untouched.
  2. Retained Compatibility Hardening: Kept the backward-compatible defensive reflection in frame_base.py, hasattr() guards in frames.py, and pd.api.types.is_string_dtype in pandas_type_compatibility.py.
  3. Pandas 2.3 Future Flags CI: Added py311-pandas-23future in tox.ini and build.gradle running with PANDAS_MODE__COPY_ON_WRITE=1 and PANDAS_FUTURE__INFER_STRING=1 to test the Pandas 3 behaviors proactively on 2.3.

I've also posted the complete scoping analysis and decision matrix on #40709. Once this preparation PR lands and Pandas 3.0 pre-releases are verified, raising the cap can follow in a separate PR with a CHANGES.md entry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Support pandas 3+ in the dataframes API

2 participants