Skip to content

GH-51548: [Python] Fix silent corruption in non-native-endian dataframe imports - #51557

Open
tam3tamtam wants to merge 1 commit into
apache:mainfrom
tam3tamtam:fix-interchange-endianness
Open

tam3tamtam wants to merge 1 commit into
apache:mainfrom
tam3tamtam:fix-interchange-endianness

Conversation

@tam3tamtam

@tam3tamtam tam3tamtam commented Sep 27, 2026 •

Copy link
Copy Markdown

Rationale for this change

Fixes #51548

The dataframe interchange protocol includes byte order in each dtype description. The PyArrow importer currently wraps these buffers directly, so non-native-endian values can be interpreted incorrectly and silently corrupted.

What changes are included in this PR?

The importer now converts non-native-endian data and string offset buffers to native byte order when needed, using array.array's C-level byteswap().
If that conversion would require a copy and allow_copy=False, it raises a RuntimeError.

Regression tests cover numeric values, string offsets, sentinel nulls, 16-bit
and 64-bit values, and the allow_copy=False and invalid-buffer error paths.

Are these changes tested?

Yes. The focused tests for these changes passed:

python -m pytest pyarrow/tests/interchange/test_conversion.py -k "non_native_endian or unsupported_endianness or misaligned_buffer_size or int8_endianness" -q
9 passed, 1792 deselected

Are there any user-facing changes?

Non-native-endian columns are now imported with their correct values. Importing
them may copy their buffers; with allow_copy=False, conversion raises an error when a copy is required.

This PR contains a "Critical Fix". Non-native-endian values could previously be interpreted with the wrong byte order and silently corrupted during dataframe interchange imports. This change preserves the producer's values.

Was AI used for this PR?

In accordance to the AI generation guidelines, please disclose below whether and how AI was used in this PR.

PR code and description written by:

  • Human
  • AI

Reviewed before submission by:

  • Human
  • AI
  • Not reviewed

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #51548 has been automatically assigned in GitHub to PR creator.

@chrikrah chrikrah left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@tam3tamtam this fixes GH-51548: a pandas frame with >i4 and >f8 columns imports as garbage on the current nightly and as the right values with this branch, and the new tests fail without the fix.

non-blocking: _buffer_with_native_endianness copies the data three times: to_pybytes(), frombytes(), then tobytes(). array.array.frombytes accepts the pa.Buffer directly, and pa.py_buffer accepts the array.array. With both changes only frombytes() copies. A 20M-row >i8 column then imports in 0.121 s, down from 0.424 s, and the test file still passes.

$ python probe_51557.py        # pyarrow 26.0.0.dev350 nightly wheel, pandas 3.2.0.dev0, CPython 3.12; from_dataframe.py and test_conversion.py swapped in
# main e85e181
int32 >                -> [16777216, 33554432, 50331648] int32
float64 >              -> [3.13984e-319, 5.375e-321] double
# this PR at 13c7d89
int32 >                -> [1, 2, 3] int32
float64 >              -> [1.5, 2.5] double

$ python -m pytest -q pyarrow/tests/interchange/test_conversion.py
# main e85e181
1791 passed, 1 skipped
# this PR at 13c7d89
1800 passed, 1 skipped
# PR tests, from_dataframe.py restored to main
8 failed, 1792 passed, 1 skipped
# PR with the two one-line changes below
1800 passed, 1 skipped

$ python perf_51557.py         # np.arange(20_000_000, dtype=">i8"), best of 5
# this PR:                                  0.424s
# raw = pa.foreign_buffer(...) without .to_pybytes(),
# return pa.py_buffer(native_values):       0.121s
# not run: the C++ build and the full pyarrow suite. The nightly wheel matches main for both swapped files.

Would you fold the one-copy variant into this PR, or leave it for a follow-up?

@github-actions github-actions Bot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Oct 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Python] DataFrame interchange silently corrupts non-native-endian columns.

2 participants