Pin kaleido<1.0 in both containers to fix ChromeNotFoundError - #85
Merged
Merged
Conversation
`kaleido` was pip-installed unpinned and resolved to v1.x, which dropped the self-contained chromium and requires a separately provisioned Chrome. The Dockerfiles ran `kaleido.get_chrome_sync()` at build time (as root, into /root/.cache), but GitHub Actions container jobs run with HOME=/github/home, so at test runtime kaleido looked in the wrong place and Plotly static-image export failed with ChromeNotFoundError (BCG_complete_mkts.md, BCG_incomplete_mkts.md, knowing_forecasts_of_others.md) — the same "unpinned dep bumped a major" class as #28. Pin `kaleido<1.0` in both images and drop the now-invalid get_chrome_sync build step (v0 has no such API). kaleido 0.2.x bundles its own chromium (location-independent, so unaffected by the HOME difference) and still exports PNGs on the current plotly — verified plotly 6.7.0 + kaleido 0.2.1 produces a PNG (deprecation warning only, no error). The existing apt chromium runtime libs are retained for the bundled browser. Migrating to kaleido v1 with a system-provisioned Chrome is left as a future follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR stabilizes Plotly static-image export in the quantecon and quantecon-build container images by preventing kaleido from upgrading to v1.x (which requires an externally provisioned Chrome) and by removing the now-invalid build-time Chrome download step.
Changes:
- Pin
kaleido<1.0in both containerenvironment.ymlfiles to keep using kaleido v0.x (bundled chromium). - Remove the
kaleido.get_chrome_sync()build step from both container Dockerfiles. - Document the fix and rationale in
CHANGELOG.mdunder Unreleased → Fixed.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
containers/quantecon/environment.yml |
Pin kaleido<1.0 in pip deps with rationale for CI runtime HOME behavior. |
containers/quantecon/Dockerfile |
Remove build-time kaleido.get_chrome_sync() invocation. |
containers/quantecon-build/environment.yml |
Pin kaleido<1.0 in pip deps with matching rationale. |
containers/quantecon-build/Dockerfile |
Remove build-time kaleido.get_chrome_sync() invocation. |
CHANGELOG.md |
Add Unreleased changelog entry describing the kaleido pin + removed Chrome download step. |
12 tasks
mmcky
added a commit
that referenced
this pull request
Aug 5, 2026
The container smoke tests could not fail. The fixture was inert for three independent reasons, not the one #108 names: 1. `execute_notebooks: "off"` in _config.yml 2. its one code block was a plain ```python fence, not a {code-cell} 3. no jupytext front matter, so the file was never a notebook at all An image whose numpy, matplotlib or kaleido was completely broken therefore still produced a green container test. Fixing only (1) and (2) would still not be enough: myst-nb reports a failed cell as a *warning*, so a raising cell yields a published book and exit 0 unless `-W` or `raise_on_error` is set. The fixture now executes real cells that ASSERT on results — a stack that imports cleanly but computes wrong answers is exactly what a smoke test should catch, and printing alone would not. Coverage: numpy/scipy eigenvalues against an exact closed form, a pandas groupby, a real matplotlib PNG render, and a plotly static export through kaleido. That last one is the #85 path and the reason both images pin kaleido<1.0. test-container.yml now runs both images as real `container:` jobs instead of `docker run`. Not cosmetic: a container job forces HOME=/github/home while docker run leaves HOME=/root, and that is precisely why #85 passed these tests while failing test-containers-lectures.yml, which does use a container job. The job asserts HOME explicitly so a silent revert is caught, and the lean image gains pdflatex coverage it never had. smoke-test.sh --self-test stages a deliberate exception and fails if the build does NOT go red — because the defect being fixed here is silence, and a fixture that cannot fail reads as coverage. It attributes the red on captured stdout rather than reports/*.err.log: verified locally that with raise_on_error myst-nb aborts before Sphinx writes that file, unlike build-fail-guard's path. Verified locally (minus the plotly cell — kaleido is not in my env): the cells genuinely execute, with real values in the built HTML; the book builds clean under -W with zero warnings; a staged raising cell exits 1; the sentinel appears in captured output; and reports/ is indeed absent. The plotly/kaleido cell and the container-job HOME assertion can only be verified in CI — workflow_dispatch on this branch, since workflow_run only fires for workflows already on the default branch. Image size is now read from the manifest, since a container job cannot run docker. That is COMPRESSED layer bytes — a different, smaller number than the old `docker images` figure, so the two series are not comparable. Refs #108 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mmcky
added a commit
that referenced
this pull request
Aug 5, 2026
The container smoke tests could not fail. The fixture was inert for three independent reasons, not the one #108 names: 1. `execute_notebooks: "off"` in _config.yml 2. its one code block was a plain ```python fence, not a {code-cell} 3. no jupytext front matter, so the file was never a notebook at all An image whose numpy, matplotlib or kaleido was completely broken therefore still produced a green container test. Fixing only (1) and (2) would still not be enough: myst-nb reports a failed cell as a *warning*, so a raising cell yields a published book and exit 0 unless `-W` or `raise_on_error` is set. The fixture now executes real cells that ASSERT on results — a stack that imports cleanly but computes wrong answers is exactly what a smoke test should catch, and printing alone would not. Coverage: numpy/scipy eigenvalues against an exact closed form, a pandas groupby, a real matplotlib PNG render, and a plotly static export through kaleido. That last one is the #85 path and the reason both images pin kaleido<1.0. test-container.yml now runs both images as real `container:` jobs instead of `docker run`. Not cosmetic: a container job forces HOME=/github/home while docker run leaves HOME=/root, and that is precisely why #85 passed these tests while failing test-containers-lectures.yml, which does use a container job. The job asserts HOME explicitly so a silent revert is caught, and the lean image gains pdflatex coverage it never had. smoke-test.sh --self-test stages a deliberate exception and fails if the build does NOT go red — because the defect being fixed here is silence, and a fixture that cannot fail reads as coverage. It attributes the red on captured stdout rather than reports/*.err.log: verified locally that with raise_on_error myst-nb aborts before Sphinx writes that file, unlike build-fail-guard's path. Verified locally (minus the plotly cell — kaleido is not in my env): the cells genuinely execute, with real values in the built HTML; the book builds clean under -W with zero warnings; a staged raising cell exits 1; the sentinel appears in captured output; and reports/ is indeed absent. The plotly/kaleido cell and the container-job HOME assertion can only be verified in CI — workflow_dispatch on this branch, since workflow_run only fires for workflows already on the default branch. Image size is now read from the manifest, since a container job cannot run docker. That is COMPRESSED layer bytes — a different, smaller number than the old `docker images` figure, so the two series are not comparable. Refs #108 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mmcky
added a commit
that referenced
this pull request
Aug 5, 2026
* test(containers): make the container fixture able to fail (#108) The container smoke tests could not fail. The fixture was inert for three independent reasons, not the one #108 names: 1. `execute_notebooks: "off"` in _config.yml 2. its one code block was a plain ```python fence, not a {code-cell} 3. no jupytext front matter, so the file was never a notebook at all An image whose numpy, matplotlib or kaleido was completely broken therefore still produced a green container test. Fixing only (1) and (2) would still not be enough: myst-nb reports a failed cell as a *warning*, so a raising cell yields a published book and exit 0 unless `-W` or `raise_on_error` is set. The fixture now executes real cells that ASSERT on results — a stack that imports cleanly but computes wrong answers is exactly what a smoke test should catch, and printing alone would not. Coverage: numpy/scipy eigenvalues against an exact closed form, a pandas groupby, a real matplotlib PNG render, and a plotly static export through kaleido. That last one is the #85 path and the reason both images pin kaleido<1.0. test-container.yml now runs both images as real `container:` jobs instead of `docker run`. Not cosmetic: a container job forces HOME=/github/home while docker run leaves HOME=/root, and that is precisely why #85 passed these tests while failing test-containers-lectures.yml, which does use a container job. The job asserts HOME explicitly so a silent revert is caught, and the lean image gains pdflatex coverage it never had. smoke-test.sh --self-test stages a deliberate exception and fails if the build does NOT go red — because the defect being fixed here is silence, and a fixture that cannot fail reads as coverage. It attributes the red on captured stdout rather than reports/*.err.log: verified locally that with raise_on_error myst-nb aborts before Sphinx writes that file, unlike build-fail-guard's path. Verified locally (minus the plotly cell — kaleido is not in my env): the cells genuinely execute, with real values in the built HTML; the book builds clean under -W with zero warnings; a staged raising cell exits 1; the sentinel appears in captured output; and reports/ is indeed absent. The plotly/kaleido cell and the container-job HOME assertion can only be verified in CI — workflow_dispatch on this branch, since workflow_run only fires for workflows already on the default branch. Image size is now read from the manifest, since a container job cannot run docker. That is COMPRESSED layer bytes — a different, smaller number than the old `docker images` figure, so the two series are not comparable. Refs #108 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * test(containers): address Copilot review on the smoke fixture Three valid points, one of which was my own mess. TESTING.md: my earlier edit replaced a trailing clause and left the sentence it was attached to dangling — an em dash running straight into a capitalised new sentence, then a second em dash. Split into two sentences. run-local-tests.sh: the prereq block ran a bare `python -c`, unlike the three `command -v` checks directly above it. Many macOS setups have only python3, so the script would report a missing science stack when the real problem is no python at all — a misleading diagnostic in the one place whose whole job is diagnosing. Now resolves an interpreter (python3 first) and says which it found. intro.md: the matplotlib cell used np.linspace while importing only matplotlib. It works, because cells share a kernel, but it meant a numpy breakage would surface as a matplotlib-cell failure. Attribution is the point of this PR, so the cell now imports numpy itself. Re-verified locally after the change (minus the plotly cell, kaleido is not in my env): the book still builds clean under -W and the cells still execute, with numpy and matplotlib both reporting real values in the built HTML. Refs #108 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The container tests (
test-containers-lectures.yml) fail at notebook execution withChromeNotFoundErrorfromkaleidoon Plotly static-image export —BCG_complete_mkts.md,BCG_incomplete_mkts.md,knowing_forecasts_of_others.md. This is the same "unpinned dependency bumped a major" class as #28.Root cause
kaleidowas pip-installed unpinned and resolved to v1.x (currently 1.3.0). kaleido v1 dropped the self-contained chromium and requires a separately provisioned Chrome. Both Dockerfiles rankaleido.get_chrome_sync()at build time — but that downloads Chrome under/root/.cache(build runs as root), while GitHub Actions container jobs run withHOME=/github/home, so at test runtime kaleido looks in the wrong place and can't find Chrome.Fix
kaleido<1.0in bothcontainers/quantecon/environment.ymlandcontainers/quantecon-build/environment.yml.kaleido.get_chrome_sync()build step from both Dockerfiles (v0 has no such API; leaving it would fail the build).kaleido 0.2.x bundles its own chromium inside the package (location-independent, so the
HOMEdifference is irrelevant) and still exports images on the current plotly. The existing apt chromium runtime libs (libnss3,libgbm1,libasound2t64, …) are retained for the bundled browser.Verification
Installed
plotly==6.7.0(the version the lean image resolves) +kaleido==0.2.1on Python 3.13 and exported a PNG:Only
DeprecationWarnings are emitted (Plotly notes kaleido v0 support is deprecated) — no error. The full image's plotly 6.3.0 is older and on the same deprecation (warn, not error) path.Caveat / follow-up
This is a pragmatic stopgap consistent with long-standing QuantEcon practice: kaleido v0 is deprecated by Plotly, so a future Plotly release could eventually drop it. Migrating to kaleido v1 with a system-provisioned Chrome (install
google-chrome/chromiumto a fixed path and point kaleido at it via env, independent ofHOME) is the durable path and is left as a follow-up.Notes
ubuntu:24.04base-image "high vulnerability" warning surfaced by the IDE is pre-existing and unrelated to this change.🤖 Generated with Claude Code