demo: convert temperature controller to getter/setter style - #411
Conversation
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## refactor #411 +/- ##
=========================================
Coverage 91.25% 91.25%
=========================================
Files 72 72
Lines 2892 2892
=========================================
Hits 2639 2639
Misses 253 253 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/fastcs/demo/temperature_attr.py`:
- Around line 76-77: Update the async close method to reset the controller’s
_connected state to False after awaiting self.connection.close(), so subsequent
connection status checks correctly report the closed state.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a64717b0-dfc5-439f-a5e0-0a883dacae7c
📒 Files selected for processing (2)
src/fastcs/demo/temperature_attr.pytests/demo/test_temperature_attr.py
0f877a4 to
3e774b3
Compare
shihab-dls
left a comment
There was a problem hiding this comment.
Just one comment regarding # type: ignore. This is idiomatic fastcs logic, with good tests, and It does show obscurity with passing setters and getters into an AttributeIORef, which I think is a good starting point. Approving.
Add temperature_attr.py: a small temperature controller with per-attribute IO (a fresh AttributeIO/AttributeIORef pair per attribute) wired directly in __init__ rather than shared class-body declarations, foreshadowing the AttrRW(getter=, setter=) constructor params landing in #392. Baseline against the current callback-IO API. Closes #404
Address CodeRabbit review comment: close() closed the socket but left _connected True, so a subsequent status check would still report connected.
…ape) Rewrites the getter/setter baseline to the intended shape: one generic TemperatureIO drives every attribute, and each TemperatureIORef carries the command-building callables (read_cmd/write_cmd) sourced from a single TemperatureProtocol class - mirroring fastcs-thorlabs-mff's MFFAttributeIO/MFFAttributeIORef/ThorlabsAPTProtocol. This is the honest precursor to #392's AttrRW(getter=, setter=): read_cmd/ write_cmd ARE the getter/setter, promoted onto the constructor when the IO/ref wrapper is deleted, while TemperatureProtocol survives unchanged. Replaces the previous per-attribute AttributeIO subclasses (RampRateIO/PowerIO), which hardcoded commands and foreshadowed nothing. Response parsing (float()) is inline in TemperatureIO.update rather than a response_handler callable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LgnovZ7FWY8YptwqiufTbX
…ttr tests The project type-checks with pyright (standard mode), which does not flag assigning an AsyncMock over a bound method here, and `method-assign` is a mypy error code pyright never emits. pyright src tests is clean without them.
Rather than adding a second temperature module, retarget #404 onto the existing `fastcs.demo.controllers` so there is one temperature demo. `TemperatureProtocol`/`TemperatureRampProtocol` carry one method per wire command, `TemperatureIORef` carries the `read_cmd`/`write_cmd` callables, and a single generic `TemperatureIO` just invokes them - the same shape as `fastcs-thorlabs-mff`, and the honest precursor to `AttrRW(getter=…, setter=…)` in #392. Attributes move from the class body into `__init__`, which is what lets each ramp bake its index into its own protocol instance instead of the IO dispatching on a `name` string plus suffix. Composition, `@scan` and `@command` are unchanged, so this module now covers both the getter/setter rung and the composition rung; the README ladder collapses accordingly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Match the naming of the other demo modules (hello_world.py, temperature_scpi.py, eiger.py), which are named for the device and the style they demonstrate rather than for the framework concept. Updates the importers: `fastcs.demo.__main__`, the test module, the README ladder and the docs nitpick-ignore entry. The launch `type:` in fastcs.yaml is derived from the top-level package, not the submodule, so `fastcs.TemperatureController` and the checked-in schema.json are unaffected (verified by regenerating the schema). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
0ef888d to
e73453b
Compare
Closes #404
Retargets Tutorial 2 (getter/setter) onto the existing temperature controller demo rather than adding a second module: the existing
src/fastcs/demo/controllers.pyis converted to the getter/setter style in place and renamed tosrc/fastcs/demo/temperature_attr.py, matching how the other demo modules are named (device + style, not framework concept). One temperature backend, one temperature module.Current-API baseline in the intended shape:
TemperatureProtocol/TemperatureRampProtocolcarry one method per wire command, each attribute'sTemperatureIORefcarries the command-building callables (read_cmd/write_cmd), and a single genericTemperatureIOjust invokes them — mirroringfastcs-thorlabs-mff(MFFAttributeIO/MFFAttributeIORef/ThorlabsAPTProtocol).read_cmd/write_cmdare the getter/setter this foreshadows: #392 promotes them ontoAttrRW(getter=..., setter=...)and deletes the IO/ref wrapper, while the protocol classes survive unchanged. Response parsing (attr.dtype(...)) is inline inTemperatureIO.update, not aresponse_handlercallable.Attributes move from the class body into
__init__. That is what earns the style: each ramp bakes its index into its own protocol instance, instead of the shared IO dispatching on anamestring plus a suffix. The composition and methods rungs are carried through unchanged — theControllerVectorofTemperatureRampControllers from #409,@scanand@command— so this module now covers both the getter/setter rung and the composition rung (#390), and the README ladder collapses from five modules to four accordingly.Behaviour is preserved: same attribute names and hierarchy, same 0.2 s default poll period, same two scan groups. The launch
type:infastcs.yamlis derived from the top-level package rather than the submodule, sofastcs.TemperatureControllerand the checked-inschema.jsonsurvive the rename unchanged (verified by regenerating the schema).Instructions to reviewer on how to test:
uv run pytest tests/demo/test_temperature_attr.py -vpython -m fastcs.demo run src/fastcs/demo/fastcs.yamlagainst the sim (tickit all src/fastcs/demo/simulation/temp_controller.yaml)Checks for reviewer
literalincludeonly theramp_rate/powerregion instead of the whole module.Notes
refactorafter demo: use ControllerVector for temperature ramp sub-controllers #409/demo: cut-down Eiger REST sim + introspectable controller example #410 merged; theControllerVectorramps and the existingtests/demo/test_controllers.pycases (test_ramps_is_controller_vector,cancel_all,update_voltages) are carried into the rewrite and the renamed test module, alongside the new wire-level protocol tests.uv run --locked tox -e pre-commit,type-checking, both green.ramp_rate), int write+read (end), enum write (Started ramp 0in the sim log,target→ 10.0), read-only reads,update_voltagesandcancel_all.docsenv (no outbound network) or PVA-touching tests (no PVA-capable socket family). Excluding those and Tango (the sandbox cannot start a Tango device server —psutil.NoSuchProcess, reproducible onrefactoritself),pytest src tests --ignore=tests/benchmarkinggives 282 passed. Real CI coversdocs, PVA and Tango.Generated by Claude Code