Repository navigation
Fix datetime64 dtype assertion for big-endian platforms - #5833
camdecoster merged 1 commit into
Conversation
The test hardcoded the little-endian dtype literal "<M8[ns]", which fails on big-endian platforms where numpy naturally produces big-endian arrays from this conversion path. Compare against dates_array.dtype directly instead, which is endian-agnostic.
chrikrah
left a comment
There was a problem hiding this comment.
@Vikram12301 the test change at d41d303 is safe to take. #4790 put the "<M8[ns]" literal there to assert a datetime dtype in place of object. dates_array.dtype still pins datetime64[ns]. With the validator patched to return datetime64[us], all four parametrized cases fail on the new line.
non-blocking, and not for this PR: to_typed_array_spec (_plotly_utils/utils.py:84) base64-encodes the array in host order. plotly.js 4.1.1 decodes bdata with new Float64Array(buffer), which is little-endian in every browser I know of. I found no statement that bdata promises little-endian bytes. I have no big-endian host either, so I built the s390x buffer below by hand.
$ .venv/bin/python -m pytest tests/test_plotly_utils/validators/test_pandas_series_input.py -q -p no:randomly # d41d303, numpy 2.5.4, pandas 3.0.6
88 passed
# basevalidators.py patched to v.astype("datetime64[us]") for kind "M", PR test kept:
4 failed, 84 passed # test_data_array_validator_dates_series/_dataframe [Series] and [Index]
$ .venv/bin/python probe5833.py # little-endian host, Python 3.12.6
to_plotly_json y: {'dtype': 'f8', 'bdata': 'AAAAAAAA+D8AAAAAAAAEQAAAAAAAAAxA'}
bytes are host order: True
s390x buffer read as Float64Array on a little-endian browser: [3.13984e-319 5.37543e-321 1.54939e-320]
# not run: anything on a big-endian host
@camdecoster, is a big-endian Python host meant to produce valid bdata? If yes, I will file the byte swap in to_typed_array_spec as its own issue, with this buffer as the repro.
|
Thanks for digging into the On the import base64
import numpy as np
v = np.array([1.1, 2.3, 3.5])
bdata = base64.b64encode(v).decode("ascii")
raw = base64.b64decode(bdata)
as_little = np.frombuffer(raw, dtype="<f8") # what plotly.js's Float64Array reads
as_big = np.frombuffer(raw, dtype=">f8") # what it actually is, on this host
print("bdata:", bdata)
print("decoded little-endian (browser):", as_little)
print("decoded big-endian (actual):", as_big)So yes, |
camdecoster
left a comment
There was a problem hiding this comment.
Thanks for the update. @Vikram12301 could you please file a bug report for the other issue?
Fixes #5832
Summary
The read-side dtype check in two tests hardcodes the little-endian dtype literal
"<M8[ns]". On big-endian platforms (e.g. z/OS/s390x), numpy's datetime64 arrays naturally resolve to big-endian native order, so this assertion fails there even though the validator's behavior is correct.This compares against
dates_array.dtypeinstead, which always reflects the host's native byte order — matching what the validator actually produces on any platform, and consistent with how the other dtype checks in this file already work (e.g.assert res.dtype == numeric_pandas.dtype).Testing
pytest tests/test_plotly_utils/validators/test_pandas_series_input.py: 88 passed (verified on little-endian; this is a no-op there since native order already equals<M8[ns])np.dtype("datetime64[ns]")(unmarked/native) does not equal the literal"<M8[ns]", but always equals another unmarkeddatetime64[ns]dtype — which is why comparing againstdates_array.dtypeis platform-independent while the old literal wasn't. I don't have big-endian hardware on hand to literally reproduce the original failure, but the underlying numpy byte-order mechanism is straightforward and I've reasoned through it directly (details in the linked issue).