Skip to content

docling-rs: add build-docling-rs.yml for riscv64 wheels - #4276

Draft
luhenry wants to merge 15 commits into
mainfrom
docling-rs
Draft

luhenry wants to merge 15 commits into
mainfrom
docling-rs

Conversation

@luhenry

@luhenry luhenry commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Compiles docling.rs's Rust document-conversion engine into a PyO3 abi3 extension (docling_rs._native). Upstream publishes no riscv64 wheel.

Mirrors upstream's pypi-publish.yml.

Differs from upstream

  • Built with ort-load-dynamic, like upstream's s390x wheel - pyke ships no riscv64 ONNX Runtime.
  • ML stages need a user-supplied libonnxruntime.so (ORT_DYLIB_PATH); declarative formats and the PDF text layer don't.
  • No cargo vendor step - the riscv64 container fetches crates directly.
  • Repo-root LICENSE staged beside pyproject.toml - upstream's wheels ship none.

Matrix: one cp39-abi3 wheel, built on cp312 and tested on cp312/cp313/cp314; no cp314t, as upstream ships abi3 only.

Testing

  • Adds the bindings' declarative pytest tests/ suite from upstream's README, with repo fixtures staged; upstream CI only imports the module.

License: OK

First riscv64 CI run pending.

Builds the cp39-abi3 wheel from a maturin sdist of the v2.62.0 tag, with
ort-load-dynamic (the feature upstream uses for its s390x wheel, since pyke
ships no ONNX Runtime for that target either), and runs the bindings'
declarative pytest suite against it on cp312/cp313/cp314.
luhenry added a commit that referenced this pull request Nov 2, 2026
ort-load-dynamic (CIBW_CONFIG_SETTINGS above) makes the PDF layout/
tables/OCR pipeline dlopen ONNX Runtime at runtime instead of linking
it in, matching upstream's own s390x wheel (no riscv64 pyke/ort
binary). With nothing on the dlopen path, all 8 PDF tests fail:
"ONNX Runtime library unavailable ... set ORT_DYLIB_PATH to a
libonnxruntime (1.17 or newer) built for this platform". This
registry already publishes onnxruntime for cp312/cp313/cp314 riscv64
(the exact interpreters this port tests), so install it as a test
dependency and point ORT_DYLIB_PATH at its bundled .so instead of
leaving the ML pipeline untested.
cibuildwheel evaluates CIBW_TEST_ENVIRONMENT when it creates the test
virtualenv, before CIBW_TEST_REQUIRES is installed, so importing
onnxruntime there failed with ModuleNotFoundError. Compute the path in
CIBW_TEST_COMMAND instead, once onnxruntime is installed.
In run 42497562052, the manylinux build job failed after ~1.5h with
"Failed: DID NOT RAISE KeyboardInterrupt" in
test_ctrl_c_interrupts_native_chunking (234 passed, this was the only
failure). The test fires one SIGINT 0.5s after starting to chunk a
3000-paragraph document and expects KeyboardInterrupt within 5s, but
PyChunkStream::__next__ only calls check_signals() when its 100ms poll of
the chunk channel times out with nothing queued, and the whole chunk
(~60s on this host, per the log timestamps) ran without that gap ever
appearing, so the one-shot signal was never observed.

Patch the test to re-issue the SIGINT every 0.2s until the call is
interrupted, matching the same disposition already used for kuzu's
test_connection_interrupt (patches/kuzu/0.11.3/0002-*), and drop the fixed
5s completion budget that assumed a one-shot signal lands immediately.
Wire the patch into build-docling-rs.yml: CIBW_TEST_SOURCES copies the
tests from the top-level checkout, not the sdist unpacked for the build,
so the patch applies to that checkout.
_publish-wheel.yml now requires a matrix input (main's "publish:
Validate effective wheel targets"), but this PR branch forked before
that landed and docling-rs has never been merged to main, so
build-docling-rs.yml never picked up the matching one-line update every
already-published package's workflow got. The merge ref combines the
new required-input _publish-wheel.yml with this branch's old
build-docling-rs.yml, so any run has failed startup with "Input matrix is
required, but not provided".

Pass it the same way the mass-update commit did for every other
package's publish job.
…n leak

Run 42731217360's manylinux build job failed with cibuildwheel exit code
130 (SIGINT) during pytest's own session teardown (gc.collect() in
_ensure_unconfigure), right after test_ctrl_c_interrupts_native_chunking
-- the last item in the file -- leaving it uncounted in "16 passed, 4
skipped" instead of passing.

The 2026-11-09 fix for this test's single missed SIGINT re-issues it
every 0.2s from a background thread until the call is interrupted, but
that thread checks `stop` and calls raise_signal() as two separate,
unsynchronized steps. It can commit to one more raise_signal() in the
instant before the main thread observes `stop` and returns from
timer.join(); that extra SIGINT is still pending delivery to the main
thread at that point and, with no later test in the file to catch it,
surfaced as an unhandled KeyboardInterrupt during session teardown
instead.

time.sleep() is itself interruptible, so give the pending signal a
bounded 0.2s window to land and absorb it right there in the test's own
finally block, instead of leaving it for whatever the session runs next.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant