Repository navigation
Draft
Conversation
This was referenced Nov 10, 2026
… fly() and ensure_stopped() StandardMovable and StandardFlyable take one `logic` property instead of movable_logic and flyable_logic (ADR 0021). FlyableLogic's hooks become a prepare_to_fly() generator, a fly() generator that yields KICKED_OFF, and an abstract ensure_stopped() (ADR 0022). Standard devices raise TransitionError for a verb in the wrong state and StoppedError when stop() or a new set() ends a move, prepare or fly early, and unstage() cancels whatever is running before it stops the hardware. The motor, pmac, panda and sim motor ports move onto it. The old detector keeps running on it unchanged. Assisted-by: Claude Opus 5.5
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.
Second of six stacked draft PRs that together land the detector rewrite. It reworks the Movable, Flyable and status machinery the detector rewrite is built on, and rewrites no detector. Next: #22
What changes
StandardMovableandStandardFlyableare rebuilt around onelogicproperty and a state machine (ADR 0021, ADR 0022):logicinstead ofmovable_logicandflyable_logic.Logicis the shared base ofMovableLogicandFlyableLogic.FlyableLogic.prepare_to_fly()andfly()are async generators.prepare_to_flyyields the context thenWatcherUpdates for progress;flyyieldsKICKED_OFFonce flying then progress. Everything a scan starts lives inside the generator, so cancelling it stops it.MovableLogic.stop()becomes the abstractensure_stopped(), which waits until the hardware has stopped.unstage()cancels a runningprepare()or fly, then always calls it.prepare(),kickoff()andcomplete()must come in that order, elseTransitionError. Staging an already-staged Standard device raises.StoppedErrorreplaces the bare "was stopped"RuntimeError.Motor,SimMotor, the PMAC trajectory and the PandA fly logic are ported.SimMotorbecomes aStandardFlyable.WatchableAsyncStatuscloses the generator it drives as soon as it is cancelled or fails.add_children_as_readables()registers children in the order they were declared.watch_readback(),cancel_and_wait(), and fixes for cancellations swallowed on Python 3.11.The full list of breaking changes, additions and fixes is in the CHANGELOG diff.
Breaking changes
Out-of-tree code that subclasses
StandardMovable,StandardFlyable,MovableLogicorFlyableLogicmust change: renamemovable_logic/flyable_logictologic; replaceon_prepare/on_kickoff/on_complete/on_stage/on_unstage/stopwithprepare_to_fly/fly/ensure_ready/ensure_stopped, each of which raisesTypeErrornaming its replacement if still defined. Plans that fly a stockbp.flymust now stage and prepare the flyer first.ophyd_asyncnow needstyping-extensions>=4.14. Every item is listed under "Breaking changes" in the CHANGELOG.Points to question
MovableLogic.calculate_timeoutdefaults toNone, so a move has no timeout unless the logic overrides it. This is unchanged from main, where the docs wrongly said the default wasDEFAULT_TIMEOUT.logicis now caught both ways: pyright reportsreportAbstractUsageat instantiation, and instantiating it raisesTypeError: Can't instantiate abstract class ... with abstract method logic. On main only pyright caught it.How to review
Start with ADR 0021 and ADR 0022, which state the decisions, then
core/_standard_base.py(the state machine),core/_flyable.py,core/_movable.pyandcore/_status.py. The motor, PMAC, PandA and sim ports are mechanical once the core is understood. The behaviour is tested through the public interface: one happy path per device, with small unhappy-path tests for ordering and failure.Position in the stack
Previous: https://github.com/coretl/ophyd-async/pull/26. Next: #22
AI Disclaimer
The code and this description were generated with AI and reviewed/tweaked by the author.