Repository navigation
Install Pyraview 0.4.2 from its pre-built release wheels, never from source - #330
Conversation
Pyraview is not on PyPI, and its sdist needs CMake and a C++ compiler. Its GitHub release carries a wheel per platform and CPython version with the compiled library inside, so: - pyproject.toml: new `pyraview` extra, `pyraview==0.4.2` by name (not folded into `gui`, so `pip install .[gui]` needs no extra flag). - install/pyraview-wheels.html: committed find-links flat index, one link per release wheel with its #sha256 fragment; the sdist is left out. install/pyraview-constraints.txt: the same hashes as a constraints file, which is how uv is made to verify them (uv ignores find-links hash fragments; pip checks them). tools/make_pyraview_index.py regenerates both from a release tag via the GitHub API, or --check compares. - ndi_install.py: drop the Pyraview clone and its from-source pip build; the editable install now takes the `pyraview` extra with --find-links install/pyraview-wheels.html --only-binary pyraview. - CI: install-without-git becomes a matrix (Linux x86_64/aarch64, Windows, macOS arm64, macos-15-intel, x86_64 CPython under Rosetta) that hides git, CMake and the compilers, installs .[tutorials,pyraview] from the raw-URL index with --only-binary pyraview and the hashed constraints, and proves with tools/check_pyraview_wheel.py that the installed WHEEL tags are exactly a release wheel's. Negative checks: no find-links fails without compiling, and a corrupted hash is refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0121enpth5oMvjLdL1tP6uAG
cryptography 49 dropped its universal2 macOS wheels, so on an Intel Mac 50.0.2 resolved to the sdist and uv tried a Rust + C build. The new macos-intel and macos-rosetta-x86_64 CI legs, which hide the compilers, caught it. Cap it below 49 on x86_64 macOS only; 48.0.1 is the last release with a wheel there. Every other platform keeps the latest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0121enpth5oMvjLdL1tP6uAG
|
I checked the diff. On the Python side nothing needs porting. That entry is - matlab_last_sync_hash: "63043f393"
+ matlab_last_sync_hash: "49a875c94"(or I haven't put this in this PR because it's unrelated to installing Pyraview. Your call: it can go in a separate one-line PR, or I can add it here if you'd rather. The Intel-macOS legs failed for a reason this PR did surface: cryptography ≥49 has no x86_64 macOS wheel, so it was being compiled with Rust. Fixed in 47b6c91, which caps it below 49 on Intel Macs only. Generated by Claude Code |
|
Installed wheel per leg (CI run on 47b6c91, from each job's
On every leg, with git, CMake and the C/C++ compilers hidden:
On the Linux x86_64 leg:
Every check on 47b6c91 is green except Generated by Claude Code |
Summary
Pyraview isn't on PyPI, and building its sdist needs CMake and a C++ compiler. The v0.4.2 GitHub release ships a wheel for each platform and CPython version, with the compiled library bundled inside. After this PR, NDI-python and the uv-based installer get pyraview only from those wheels. If no wheel fits, the install fails; it never compiles.
pyproject.toml: new extrapyraview = ["pyraview==0.4.2"]. It's declared by name with an exact pin, not a git URL or sdist URL. It's not ingui, sopip install ".[gui]"still works without a find-links flag. The installer will requestndi[gui,napari,pyraview].install/pyraview-wheels.html: a committed flat index (--find-links) with all 54 v0.4.2 wheels. Each link is the release download URL plus a#sha256=fragment. The sdist is not listed.install/pyraview-constraints.txt:pyraview==0.4.2with one--hashper wheel. These are the same hashes as the index; this file is what makes uv check them (see below).tools/make_pyraview_index.py <tag>: regenerates both files from the GitHub API, using each release asset'sdigest.--checkrebuilds them in memory and fails if the committed files differ.--release-jsonreads a saved API response.ndi_install.py: removed the Pyraview entry fromDEPENDENCIESand the clone +pip install <checkout>build (pip_install_dependency). The existing editable install now requests thepyraviewextra with--find-links install/pyraview-wheels.html --only-binary pyraview. Its other behaviour is unchanged.tools/check_pyraview_wheel.py: the CI proof. It imports pyraview and asserts that_lib_pathis the library bundled inside the package. It also asserts that.dist-info/WHEELhasRoot-Is-Purelib: falseand that its tag set is exactly the tag set of one wheel in the committed index. A wheel built locally from the sdist would carrylinux_x86_64rather thanmanylinux_*, a different macOS target, and so on. It then prints that release wheel's filename and sha256.Which find-links mechanism, and why: (b), the committed index
I picked (b) over GitHub's undocumented
releases/expanded_assets/<tag>page because it pins hashes and doesn't depend on a page GitHub might change. I tested how uv and pip each read it, locally with uv 0.11.32 against a real downloaded 0.4.2 wheel:install/pyraview-wheels.htmltext/plain)--find-linksdirectory … Not a directory"). uv takes only a directory or a URL.So each tool uses the form it can read:
-f https://raw.githubusercontent.com/Waltham-Data-Science/NDI-python/<ref>/install/pyraview-wheels.html. CI uses this commit's SHA; the installer will usemainor a tag.ndi_install.py, README): the local path in the checkout.What is hash-verified, and what is not
I checked each of these locally by corrupting hashes, and CI checks the uv case on every leg:
pip install … --find-links install/pyraview-wheels.html(ndi_install.py)#sha256fragment on every link: "Expected sha256 000… Got 2a55…"uv pip install -f <raw URL>alone#sha256fragments; a corrupted fragment still installs, with or without--verify-hashesuv pip install -f <raw URL> -c install/pyraview-constraints.txtuv tool install … -c constraints/--with-requirements/UV_REQUIRE_HASHES=1uv tool installchecks no pyraview hash in any of those forms. A corrupted constraints file still installed.For the double-click installer (next PR): as of uv 0.11.32,
uv tool installcan't enforce these hashes. The installer can create its environment withuv venv+uv pip install -c install/pyraview-constraints.txt(hash-enforced). Or it can acceptuv tool install, which still never compiles (--no-build-package pyraview) but trusts TLS to GitHub for the wheel's contents.--checkin CI proves the committed hashes are GitHub's own asset digests.The constraints file also protects against a squatter publishing
pyraviewon PyPI: uv would reject any file whose hash isn't listed. The pip path checks link fragments only for links that come from our index.No source builds: belt and braces
--only-binary pyraviewforpipanduv pip(uv piphas no--no-build-package), and--no-build-package pyraviewforuv tool install.cmake,cc,c++,gcc,g++,clang,clang++,clandgit. On Linux and macOS they are shadowed by scripts that always fail. On Windows, PATH dirs containing them are dropped, since native lookup ignores shell shadows. The step checks they're really unusable before going on.CI proof
The
install-without-gitjob from #328 is now a matrix, rather than a second job. Each leg runs with git and the compilers hidden and uses Python 3.12:ubuntu-latest(x86_64),ubuntu-24.04-arm(aarch64),windows-latest,macos-latest(arm64),macos-15-intel, and Rosetta:macos-latestwithcpython-3.12-macos-x86_64installed by uv, which assertsplatform.machine() == "x86_64"and tags containingmacosx_andx86_64.Each leg runs:
.[pyraview]without-fmust fail and must not build anything..[tutorials,pyraview]with the raw-URL index, the constraints file and--only-binary pyraview.python -c "import pyraview, os; print(pyraview.__file__, pyraview._lib_path)", thencheck_pyraview_wheel.py..htmlfile.ndi check/ NDIcalc steps.The Linux x86_64 leg also runs
uv tool install … --no-build-package pyraview(the installer's command form) andmake_pyraview_index.py --checkagainst the GitHub API.The Linux x86_64 leg keeps the check name "Install without git", so a required-check rule naming it still matches.
timeout-minutes: 45bounds a hung run. Note that it doesn't bound time spent queued for a runner label: ifmacos-15-intelis ever retired, drop that leg.The existing
test,windows-smokeandced-integrationjobs runndi_install.py, so they now take the pip + local-index path on Linux 3.10–3.12, Windows 3.10/3.12 and Linux 3.14. Before this PR they compiled Pyraview from a clone.Installed wheel per leg: see the comment below; I'll post it from the CI logs once the run finishes.
Local verification (sandbox)
tests/test_pyraview_wheel_index.py,test_ndi_install_exit_codes.pyandtest_ndi_install_timeouts.py; the full suite needs the archive-URL dependencies, which this sandbox can't fetch, so CI runs it.cp312 manylinux x86_64, sha2562a550481…= GitHub's digest): uv selected the right wheel from the index; pip installed it andcheck_pyraview_wheel.pypassed. I also ran the hash experiments in the table above.Tests
tests/test_pyraview_wheel_index.pychecks offline:pyraviewisn't inguiand isn't a URL;ndi_install.pyno longer clones Pyraview and passes--find-links+--only-binary pyraview.The two
ndi_installtests that covered the removedpip_install_dependencyand its 1800 s literal timeout were updated to match.No bridge YAML changes: no MATLAB interface changed.
🤖 Generated with Claude Code
https://claude.ai/code/session_0121enpth5oMvjLdL1tP6uAG
Generated by Claude Code