Skip to content

Fix datetime64 dtype assertion for big-endian platforms - #5833

Merged
camdecoster merged 1 commit into
plotly:mainfrom
Vikram12301:fix-big-endian-datetime64-dtype-assertion
Oct 22, 2026
Merged

camdecoster merged 1 commit into
plotly:mainfrom
Vikram12301:fix-big-endian-datetime64-dtype-assertion

Conversation

@Vikram12301

Copy link
Copy Markdown
Contributor

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.dtype instead, 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])
  • Verified the failure mode directly: on a big-endian host, np.dtype("datetime64[ns]") (unmarked/native) does not equal the literal "<M8[ns]", but always equals another unmarked datetime64[ns] dtype — which is why comparing against dates_array.dtype is 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).

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.
@camdecoster camdecoster self-assigned this Oct 21, 2026

@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.

@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.

@Vikram12301

Vikram12301 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks for digging into the #4790 history and verifying the datetime64[us] regression case, good to have that confirmed.

On the to_typed_array_spec byte-order question: we actually have a real big-endian host on hand, so I ran this for real instead of simulating it. Confirms your suspicion exactly:

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)
# output, z/OS/s390x, numpy 2.5.3
bdata: P/GZmZmZmZpAAmZmZmZmZkAMAAAAAAAA
decoded little-endian (browser): [-1.54234871e-180  1.90359857e+185  1.54938987e-320]
decoded big-endian (actual):     [1.1 2.3 3.5]

So yes, to_typed_array_spec produces bdata that's unreadable by plotly.js on any real big-endian host, confirmed on s390x. Happy to have this script/output used as the repro if you file it as its own issue.

@camdecoster camdecoster 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.

Thanks for the update. @Vikram12301 could you please file a bug report for the other issue?

@camdecoster camdecoster added the no-changelog A changelog entry is not required for this PR label Oct 22, 2026
@camdecoster
camdecoster merged commit 0de8a38 into plotly:main Oct 22, 2026
31 of 32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog A changelog entry is not required for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

datetime64 dtype test assertion hardcodes little-endian, fails on big-endian platforms

3 participants