Uh oh!
There was an error while loading. Please reload this page.
GH-50312: [Python] Fix UUID extension type round-trip to pandas returning bytes - #50325
Conversation
5b15a46 to
386b1b6CompareGiTaDi-CrEaTe
commented
Jul 4, 2026
Hey @parker-cassar, thanks so much for jumping on this so quickly. Just out of curiosity—since this delegates to to_pylist(), do you think this pattern might end up being useful for other Arrow extension types down the way??? |
rok
left a comment
There was a problem hiding this comment.
Thanks for working on this @parker-cassar!
A couple of questions since we're aiming to support Pandas 3.x and Pandas 2.x too for a while.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
ea0d9f2 to
b7f87d1Compareparker-cassar
commented
Jul 8, 2026
Maybe! It works here because the target is object dtype anyway, so building the Python objects is unavoidable. Other extension types could use the same from_arrow + reshape structure, but anything performance-sensitive would want a zero-copy path instead of going through Python objects. |
bc83f11 to
457ff20Compare@rok Applied both of your suggestions. Ready for another look whenever you have time. |
@parker-cassar thank you for your patience :) I've been thinking about this a bit and perhaps we could convert to UUID in c++ and avoid awkward Python compat layer? Pandas had a UUID type proposal that seems stalled but could get completed. See my proposal what this could look like. Let me ask for some feedback from others before you continue. |
rok
commented
Jul 21, 2026
@parker-cassar I think we better implement this in C++ kind of like proposed here. This will likely improve performance and give us a cleaner API/make compat layer with pandas neater. Sorry for not suggesting this sooner. Do you think you can continue in this vein? |
parker-cassar
commented
Jul 23, 2026
Yes I agree and am happy you suggested this (: the Python compat layer approach doesn't really make sense here, especially since a UUID column in pandas isn't exactly a rare case. Doing it natively is cleaner. I'll give it a go and I'll try to have a PR in a few days or less based on your proposal. |
parker-cassar
commented
Jul 27, 2026
@rok Quick update: your proposal is integrated and the full round-trip passes. I'm still working on my last pass and I will have it up in the next day or two. Thanks for the proposal, made it a lot easier. |
457ff20 to
10eab91Compare10eab91 to
b8c8338CompareUh oh!
There was an error while loading. Please reload this page.
rok
left a comment
There was a problem hiding this comment.
I have a potential performance improvement suggestion, but other than that this looks pretty good.
Uh oh!
There was an error while loading. Please reload this page.
eaf0c4b to
2f35759Compare
rok
left a comment
There was a problem hiding this comment.
I think we're almost there - just the matter of ensuring type(uuid_array.to_numpy(zero_copy_only=False)[0]) is bytes, since extension-array NumPy conversion should delegate to its storage type.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
parker-cassar
commented
Aug 10, 2026
@rok The macOS 15-intel check failed in the Install MinIO step (wget couldn't resolve dl.min.io) before anything was built or tested. Are you able to re-run that job? |
AlenkaF
left a comment
There was a problem hiding this comment.
Thank you for working on this @parker-cassar and providing the C++ version of the solution. I think the PR looks good and am happy to see it get merged!
parker-cassar
commented
Aug 18, 2026
rok
left a comment
There was a problem hiding this comment.
Sorry for the wait @parker-cassar and thank you for your flexibility and patience!
I think this is ready and will merge.
After merging your PR, Conbench analyzed the 3 benchmarking runs that have been run so far on merge-commit 892c73d. There were no benchmark performance regressions. 🎉 The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them. |
Rationale for this change
Converting a Table with an
arrow.uuidextension column to pandas currently produces a column ofbytesinstead ofuuid.UUIDobjects. Without a dedicated conversion path,Table.to_pandas()/Array.to_pandas()falls back to the storage type (fixed_size_binary(16)) and materializes raw bytes. Downstream callers (and tests such as those landing via pandas UUID Parquet coverage) expectuuid.UUIDobjects, matching whatto_pylist()/UuidScalar.as_py()already return.Note: the original issue suggested this might be specific to Python 3.14, but the same
bytesresult reproduces on Python 3.10-3.14 with current PyArrow -UuidTypenever had a pandas conversion path.Closes#50312
What changes are included in this PR?
Convert UUID extension arrays to
uuid.UUIDobjects in the C++ pandas conversion path (integrated from @rok's proposal in rok#55), rather than relying on a Pythonto_pandas_dtype()/__from_arrow__compat layer:uuid.UUIDobjects from storage bytes inhelpers.cc(UuidFromBytes) and use that fromarrow_to_pandas.ccto_numpy(zero_copy_only=False)on UUID extension arrays returning storagebytes(extension to NumPy should follow storage type)Are these changes tested?
Yes.
Acceptance criteria:
bytesreturn values touuid.UUIDforto_pandas()Before / after evidence (backend; console):
Also covered by added unit tests in
python/pyarrow/tests/parquet/test_data_types.pyandpython/pyarrow/tests/test_extension_type.py.Are there any user-facing changes?
Yes.
Table.to_pandas()/Array.to_pandas()now returnsuuid.UUIDforarrow.uuidcolumns instead ofbytes.to_numpy(zero_copy_only=False)continues to expose storagebytes.