Skip to content

fix: lazy visualizer so client construction never warns (#151); remove root clutter - #157

Merged
karlwaldman merged 2 commits into
mainfrom
fix/151-lazy-matplotlib
Oct 14, 2026
Merged

karlwaldman merged 2 commits into
mainfrom
fix/151-lazy-matplotlib

Conversation

@karlwaldman

Copy link
Copy Markdown
Member

Closes #151.

Problem

python -W error -c "import oilpriceapi; oilpriceapi.OilPriceAPI(api_key='x')" on main 5d9aa37 without matplotlib -> ImportWarning: matplotlib is required for visualization (raised as error). Cause: OilPriceAPI.__init__ builds PriceVisualizer eagerly and its __init__ warns.

Change

  • client.viz is a property: builds PriceVisualizer on first access, returns None when matplotlib is missing (same contract the examples use: if not client.viz).
  • PriceVisualizer.__init__ no longer warns; plotting methods already raise ImportError.
  • Removed test_debug_params.py (ad-hoc live-call debug script outside testpaths) and WEBSITE_FIXES_DEPLOYED.md (2025-11 website deploy note). No references to either in the repo.

Verification (local, Python venv)

  • Red: 3 of 4 new tests failed on main; acceptance command raised.
  • Green without matplotlib: acceptance command exit 0; CI test set 2023 passed, 35 skipped, coverage 80.10%.
  • Green with matplotlib: client.viz is a PriceVisualizer; matplotlib not imported at construction; unit + new tests 1903 passed.

Expected effect: SDK users who run with warnings-as-errors (pytest filterwarnings=error, -W error) can construct a client; construction no longer pays the matplotlib import cost.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QQ7W3CkRKEnBpU5KRQUfUu

…151)

OilPriceAPI.__init__ built PriceVisualizer eagerly, which imported
matplotlib when present and emitted ImportWarning when absent, so
`python -W error` could not construct a client. `viz` is now a property
that builds on first access and returns None without matplotlib
(unchanged contract for `if not client.viz`). Plotting methods still raise
ImportError with guidance.

Also removes root clutter: test_debug_params.py (an ad-hoc live-call
debug script, not a test; pytest testpaths is tests/) and
WEBSITE_FIXES_DEPLOYED.md (a 2025-11 website deploy note).

Closes #151

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQ7W3CkRKEnBpU5KRQUfUu
@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7ff9588f-add7-437c-ad5e-3a107d4da3cd
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@karlwaldman karlwaldman added the risk:elevated Elevated: auto-merges after an adversarial review APPROVE label Oct 14, 2026
@karlwaldman

Copy link
Copy Markdown
Member Author

Adversarial review: BLOCK (head c4192a9)

Blocking: this PR makes the no-matplotlib failure unexplained. I tested in a fresh venv with the SDK installed and matplotlib not installed:

PR head: client.viz -> None
         client.viz.plot_price_series("WTI_USD")
         AttributeError: 'NoneType' object has no attribute 'plot_price_series'
main:    client.viz.plot_price_series("WTI_USD")
         ImportError: matplotlib required for visualization

On main, client.viz was always a PriceVisualizer, because importing visualization.py never fails. Its methods raise ImportError with install guidance. The new property returns None when HAS_MATPLOTLIB is false, so a user following any client.viz.plot_* example gets a bare AttributeError. The new comment in visualization.py says plotting methods give install guidance, but this PR makes them unreachable through client.viz.

Suggested fix (keeps #151's goal): in the viz property, build and cache PriceVisualizer(self) lazily without the HAS_MATPLOTLIB check. Construction still imports nothing and warns nothing. The PriceVisualizer.__init__ warning is already removed, and calls still raise the ImportError with guidance. Then flip test_viz_is_none_without_matplotlib_and_object_with_it to assert an ImportError on a plot call without matplotlib.

Confirmed working:

  • The 4 new tests pass. Construction under -W error is clean, and matplotlib is not imported at construction.
  • Unit suite: 2023 passed, 35 skipped, coverage 80.1%.
  • Locally, tests/integration/test_demo_contract.py failed with a live 429 on /v1/demo/prices, which is unrelated. CI "Live API tests" is green.
  • Removing WEBSITE_FIXES_DEPLOYED.md and test_debug_params.py breaks no references.

…otlib (#151)

Adversarial review of #157 found client.viz returned None when matplotlib
was missing, so client.viz.plot_* failed with a bare AttributeError. The
viz property now always builds a cached PriceVisualizer lazily (no import,
no warning at construction), and each plotting method raises ImportError:
"matplotlib is required for visualization. Install it with:
pip install 'oilpriceapi[viz]'". Adds the viz extra to pyproject.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQ7W3CkRKEnBpU5KRQUfUu
@karlwaldman

Copy link
Copy Markdown
Member Author

Addressed the BLOCK on c4192a9 (new head 2a7596e)

The review found that without matplotlib, client.viz returned None. As a result, client.viz.plot_price_series("WTI_USD") failed with AttributeError: 'NoneType' object has no attribute 'plot_price_series'. On main the same call raised an ImportError with guidance.

Changes

  • client.viz always builds and caches a PriceVisualizer on first access, with no HAS_MATPLOTLIB check. This follows the review's suggested fix. Construction still imports nothing optional and emits no warning.
  • All 4 plotting methods now raise ImportError: matplotlib is required for visualization. Install it with: pip install 'oilpriceapi[viz]'.
  • Added a viz extra (matplotlib, numpy, pandas) to pyproject.toml, so the message names an extra that installs.
  • examples/visualization_demo.py checks HAS_MATPLOTLIB instead of if not client.viz, which was always truthy.
  • I replaced test_viz_is_none_without_matplotlib_and_object_with_it as the review asked. It became a parametrized test of all 4 plot methods in a fresh -W error interpreter with matplotlib blocked, plus a test that construction is warning-free without matplotlib.

Evidence

  • Red before the fix: 4 failed, 5 passed. Each failure was OTHER:AttributeError:'NoneType' object has no attribute 'plot_*'.
  • Green after the fix: 9/9 in a venv with matplotlib and 9/9 in a fresh venv without it.
  • python -W error -c "import oilpriceapi; oilpriceapi.OilPriceAPI(api_key='x')" exits 0 both with and without matplotlib.
  • In the venv without matplotlib, client.viz.plot_price_series('WTI_USD') raises ImportError: matplotlib is required for visualization. Install it with: pip install 'oilpriceapi[viz]'.
  • I ran the CI unit command (pytest tests/ --ignore=tests/integration --ignore=tests/contract -m 'not slow'). With matplotlib: 2053 passed, coverage 83.31%. Without matplotlib: 2028 passed, 14 skipped, coverage 80.93%.
  • ruff check oilpriceapi/ and mypy oilpriceapi/ --ignore-missing-imports are clean.

@karlwaldman

Copy link
Copy Markdown
Member Author

Adversarial review: APPROVE (head 2a7596e)

I re-reviewed head 2a7596e544e845dba481721bc6c45bdb262dc588 in a fresh worktree. The head is unchanged from the one named in the request. The BLOCK on c4192a9 is fixed, and I could not refute the change.

Prior BLOCK point (client.viz returning None without matplotlib): fixed.
I installed the package into a fresh venv (Python 3.14) with pip install . and no matplotlib, numpy, pandas, plotly, or seaborn. I then ran the check with python -I -W error:

  • import oilpriceapi, plus pkgutil.walk_packages over all 57 modules, imports cleanly. The one exception is oilpriceapi.cli, which exits with "install oilpriceapi[cli]". That behavior predates this PR, and the PR does not touch the cli.
  • After importing every module, sys.modules contains none of matplotlib, numpy, pandas, plotly, or seaborn.
  • client.viz returns a PriceVisualizer, and the instance is cached (c.viz is c.viz).
  • All 4 public plot methods raise ImportError: matplotlib is required for visualization. Install it with: pip install 'oilpriceapi[viz]'. The methods are plot_price_series, plot_spread, create_sparkline, and create_small_multiples.

With the extra installed: In a second fresh venv I ran pip install '.[viz]', which installed matplotlib 3.11.2, numpy 2.5.4, and pandas 3.0.6. Client construction under -W error does not load matplotlib. The first client.viz access loads it. With historical.get stubbed, plot_price_series, plot_spread, and create_sparkline each return a matplotlib.figure.Figure.

Wheel metadata (oilpriceapi-1.17.0-py3-none-any.whl):

Provides-Extra: viz
Requires-Dist: matplotlib>=3.5.0; extra == "viz"
Requires-Dist: numpy>=1.20.0; extra == "viz"
Requires-Dist: pandas>=1.5.0; extra == "viz"

The base Requires-Dist entries are still httpx, pydantic, python-dateutil, and typing-extensions, so no viz dependency leaks into the base install. Neither deleted root file (WEBSITE_FIXES_DEPLOYED.md, test_debug_params.py) is in the wheel, and nothing else references them.

Tests and lint (Python 3.12 venv with all extras):

  • CI unit command pytest tests/ --ignore=tests/integration --ignore=tests/contract -m 'not slow': 2053 passed, coverage 83.33%.
  • tests/test_lazy_visualization.py: 9/9 passed.
  • ruff check oilpriceapi/ is clean. mypy oilpriceapi/ --ignore-missing-imports is clean (57 files).
  • CI: Test (Python 3.8 through 3.12) and Live API tests all pass. CodeRabbit passes. The merge state is CLEAN.

Non-blocking:

  • create_small_multiples crashes when all commodities fit in one row (n <= cols, which includes the default cols=3). The error is AttributeError: 'numpy.ndarray' object has no attribute 'spines'. main (5d9aa37) fails the same way, so this PR did not introduce it. Filed as create_small_multiples crashes when commodities fit in one row (n <= cols) #158.
  • The all extra still does not include viz. That matches main, which had no matplotlib extra at all. Leaving it out keeps [all] light.

@karlwaldman
karlwaldman merged commit 1e881a1 into main Oct 14, 2026
7 checks passed
@karlwaldman
karlwaldman deleted the fix/151-lazy-matplotlib branch October 14, 2026 22:40
karlwaldman added a commit that referenced this pull request Oct 17, 2026
* chore(deps): bump actions/download-artifact from 8.0.1 to 8.0.2

Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 8.0.1 to 8.0.2.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](actions/download-artifact@3e5f45b...9000827)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: lazy visualizer so client construction never warns (#151); remove root clutter (#157)

* fix: build the visualizer lazily so client construction never warns (#151)

OilPriceAPI.__init__ built PriceVisualizer eagerly, which imported
matplotlib when present and emitted ImportWarning when absent, so
`python -W error` could not construct a client. `viz` is now a property
that builds on first access and returns None without matplotlib
(unchanged contract for `if not client.viz`). Plotting methods still raise
ImportError with guidance.

Also removes root clutter: test_debug_params.py (an ad-hoc live-call
debug script, not a test; pytest testpaths is tests/) and
WEBSITE_FIXES_DEPLOYED.md (a 2025-11 website deploy note).

Closes #151

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQ7W3CkRKEnBpU5KRQUfUu

* fix: client.viz raises ImportError naming the viz extra without matplotlib (#151)

Adversarial review of #157 found client.viz returned None when matplotlib
was missing, so client.viz.plot_* failed with a bare AttributeError. The
viz property now always builds a cached PriceVisualizer lazily (no import,
no warning at construction), and each plotting method raises ImportError:
"matplotlib is required for visualization. Install it with:
pip install 'oilpriceapi[viz]'". Adds the viz extra to pyproject.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQ7W3CkRKEnBpU5KRQUfUu

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* test: verify the updated artifact action pin

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: karlwaldman <karl.waldman@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:elevated Elevated: auto-merges after an adversarial review APPROVE

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P3][bug] Constructing OilPriceAPI emits ImportWarning when matplotlib is not installed

1 participant