plot: fail fast with guidance when interactive backend fails to load - #449
yarikoptic-gitmate wants to merge 8 commits into
Conversation
Previously, con-duct only checked that MPLBACKEND named a known interactive backend, not that it actually loaded. A backend that matched by name but failed to import (e.g. TkAgg with a broken/missing tkinter) only surfaced as a raw traceback deep inside plt.subplots(), with no guidance (#447). Move the interactivity check earlier, before any data loading/plot building, and actually try to load the backend module there so a failure is caught with an actionable message pointing at --output or a different MPLBACKEND value, instead of an unguided traceback. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hv454Dwv5QSLfUArTtdYyf
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hv454Dwv5QSLfUArTtdYyf
When the current backend isn't recognized as interactive, name the built-in interactive backends matplotlib knows about (one of which needs a GUI toolkit installed) instead of just pointing at MPLBACKEND in the abstract. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hv454Dwv5QSLfUArTtdYyf
If MPLBACKEND isn't set and the resolved matplotlib backend can't display interactively, try loading each builtin interactive backend ourselves (native GUI toolkits first, then browser/cairo variants matplotlib's own auto-fallback doesn't consider, e.g. webagg) and use the first one that actually works, instead of just reporting the non-interactive backend matplotlib gave up on. When MPLBACKEND is set explicitly, that choice is respected as before: report the failure rather than silently overriding it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hv454Dwv5QSLfUArTtdYyf
backend_registry.load_backend_module() doesn't consistently raise ImportError for a missing dependency -- e.g. webagg raises RuntimeError when tornado is missing. The pinned-backend branch only caught ImportError, so a pinned backend failing this way (e.g. MPLBACKEND=webagg without tornado installed) leaked a raw traceback instead of the intended friendly message. Widen it to Exception, same as the auto-probe helper already does for the same reason. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hv454Dwv5QSLfUArTtdYyf
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #449 +/- ##
=======================================
Coverage 92.02% 92.02%
=======================================
Files 15 15
Lines 1316 1342 +26
Branches 179 182 +3
=======================================
+ Hits 1211 1235 +24
- Misses 70 71 +1
- Partials 35 36 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The oldestdeps CI job (Python 3.10 + matplotlib 3.5, our documented floor per PR #322/issue #320 for Debian Bookworm compat) was failing: tests that decorate a test function with @patch("matplotlib.backends.backend_registry....") have that patch target resolved before the test body runs, so an inline `if not hasattr(...): pytest.skip(...)` inside the function never gets a chance to run on matplotlib < 3.9, which has no backend_registry module at all -- the decorator itself raises first. Add a shared `requires_backend_registry` skipif marker, evaluated at collection time before pytest calls the (patch-wrapped) test function at all, and apply it to every test that patches backend_registry directly. Verified against a real matplotlib 3.5.3 install: previously 5 errors, now those tests skip cleanly and the rest of the suite passes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hv454Dwv5QSLfUArTtdYyf
for more information, see https://pre-commit.ci
|
The Generated by Claude Code |
_INTERACTIVE_BACKEND_PROBE_ORDER's own entries are always builtin interactive backend names, so "candidate not in interactive_backends" can't fire for them in practice, and the loop's broad except Exception already handles a candidate that fails to resolve to a real backend module (load_backend_module on a bad name just raises ModuleNotFoundError, which that clause catches). Dead code identified by codecov's patch coverage flagging it as the one uncovered line/branch in the PR. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Hv454Dwv5QSLfUArTtdYyf
|
Generated by Claude Code |
Previously, con-duct only checked that MPLBACKEND named a known
interactive backend, not that it actually loaded. A backend that
matched by name but failed to import (e.g. TkAgg with a broken/missing
tkinter) only surfaced as a raw traceback deep inside plt.subplots(),
with no guidance (#447).
Move the interactivity check earlier, before any data loading/plot
building, and actually try to load the backend module there so a
failure is caught with an actionable message pointing at --output or
a different MPLBACKEND value, instead of an unguided traceback.
Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01Hv454Dwv5QSLfUArTtdYyf