Visitar URL original
fix(eload): cache mode only after the driver confirms set_mode by MaxFreedomPollard · Pull Request #485 · nominal-io/instro · GitHub
Skip to content

fix(eload): cache mode only after the driver confirms set_mode - #485

Merged
hoehner merged 1 commit into
nominal-io:mainfrom
MaxFreedomPollard:issue-417-eload-set-mode-cache
Sep 7, 2026
Merged

hoehner merged 1 commit into
nominal-io:mainfrom
MaxFreedomPollard:issue-417-eload-set-mode-cache

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown
Contributor

Summary

InstroELoad.set_mode() assigned self._mode = mode before it entered self._resource_lock and called self._driver.set_mode(...) (instro/eload/eload.py:224 on main). If the driver raised, for example a model that answers CP with NotImplementedError, the exception propagated but the cached mode was already updated to a mode the instrument was never put into. The next set_level() or set_range() then sailed past the "Mode must be set" guard and handed that wrong mode to the driver, so the load was driven in CP units while it was still in whatever mode it was actually in.

open() already resets self._mode = None when _apply_load_config() fails, so the config-driven path was covered. Direct set_mode() calls had no recovery, and the stale value persisted silently.

The fix moves the assignment inside the lock, after self._driver.set_mode(...) returns. InstroDMM already does it this way: every one of its setters calls the driver first and only then updates self._measurement_config (instro/dmm/dmm.py:292-365). ELoad was the outlier.

Fixes #417

Type of change

  • Bug fix (fix)
  • New feature (feat)
  • Breaking change (feat! / fix!)
  • Refactor (refactor)
  • Documentation (docs)
  • Chore / tooling (chore)

Verification

The new test fails on main and passes with the fix. Checking out just the unmodified module under the new test:

$ git checkout origin/main -- instro/eload/eload.py
$ uv run --frozen pytest -q tests/eload/test_eload_drivers.py::test_nominal_eload_set_mode_leaves_mode_unset_when_driver_raises
E       Failed: DID NOT RAISE ValueError
1 failed in 0.40s

With the fix in place:

$ uv run --frozen pytest -q tests/eload/test_eload_drivers.py::test_nominal_eload_set_mode_leaves_mode_unset_when_driver_raises
1 passed in 0.26s
$ uv run --frozen pytest -q tests/eload
56 passed, 2 deselected in 0.51s
$ uv run --frozen pytest -q
2235 passed, 2 skipped, 490 deselected, 1 xfailed in 17.99s
$ uv run --frozen ruff format --check
305 files already formatted
$ uv run --frozen ruff check
All checks passed!
$ uv run --frozen mypy
Success: no issues found in 85 source files

main at b8f262a gives 2234 passed on the same suite, so the only difference is the added test. The change is pure Python and touches no Rust, so I ran the Python half of just check and just test rather than the full native build. No hardware was used; the test drives a MagicMock(spec=ELoadDriverBase) the same way the surrounding InstroELoad tests do.

Tests

  • Unit tests added or updated
  • Existing tests cover this change
  • No tests, explain why:

Checklist

  • PR title follows Conventional Commits (e.g. feat(driver): add support for Keysight E36300)
  • I have read CONTRIBUTING.md
  • Documentation updated if user-facing behavior changed
  • Code follows the style/conventions of the surrounding code

Notes for reviewers

No docs change: docs/guides/instrumentation/eload.mdx already says the mode must be set before level or range, and this only makes the code hold to that when the driver rejects the mode.

I left the self._mode = None rollback in open() alone. It still earns its place, because _apply_load_config() can fail at set_range or set_level after set_mode legitimately succeeded, and the cache has to be cleared for that case too.

Scoped to #417 only. #416, the atomicity of _apply_load_config across separately locked setters, is untouched here: the assignment now sits inside _resource_lock, which is where #416 would want it, so that work can build on this rather than undo it.

InstroELoad.set_mode assigned self._mode before entering _resource_lock
and calling self._driver.set_mode (instro/eload/eload.py:224). When the
driver raised, for example a model that does not support CP, the cached
mode was left pointing at a mode the instrument was never put into, and
the next set_level/set_range passed it straight to the driver instead of
hitting the "Mode must be set" guard.

open() already rolls the cache back for the _apply_load_config path, so
only direct set_mode calls were exposed.

Move the assignment inside the lock, after the driver call returns. That
matches InstroDMM, which updates _measurement_config only after its
driver call succeeds.
@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR corrects ELoad mode caching so the in-memory mode changes only after the driver successfully applies it.

  • Moves the _mode assignment into the resource lock after driver.set_mode() returns.
  • Adds a regression test confirming that a rejected initial mode does not permit a subsequent level command.

Confidence Score: 5/5

The PR appears safe to merge and directly fixes the stale-mode state without introducing an actionable regression.

The cached mode is now updated only after successful driver confirmation, and the added test exercises the reported failure path; no blocking or independently actionable quality issues remain.

Important Files Changed

Filename Overview
instro/eload/eload.py Defers cached mode assignment until the locked driver operation succeeds, preventing rejected modes from becoming active application state.
tests/eload/test_eload_drivers.py Adds focused regression coverage for a failed mode selection followed by a guarded level command.

Reviews (1): Last reviewed commit: "fix(eload): cache mode only after the dr..." | Re-trigger Greptile

@hoehner
hoehner self-requested a review September 7, 2026 20:43

@hoehner hoehner left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix, approving after tests run!

@hoehner
hoehner enabled auto-merge (squash) September 7, 2026 20:45
@hoehner
hoehner merged commit 9ccbf0a into nominal-io:main Sep 7, 2026
23 checks passed
@nombotv2 nombotv2 Bot mentioned this pull request Sep 7, 2026
@hoehner

hoehner commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Thank you @MaxFreedomPollard !

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.

InstroELoad.set_mode writes self._mode before the driver confirms the command

2 participants