Repository navigation
Rename Command attributes around four conceptual operations - #86
Merged
Merged
Conversation
dccote
marked this pull request as draft
May 19, 2026 19:50
Every Command (TextCommand, MultilineTextCommand, DataCommand) carries
the same four conceptual operations:
requestEncoder encode an outgoing request payload (device -> wire)
requestDecoder decode an incoming request payload (wire -> mock)
replyEncoder encode an outgoing reply payload (mock -> wire)
replyDecoder decode an incoming reply payload (wire -> device)
Before this commit, those operations were named ad-hoc per subclass --
TextCommand used text_format/matchPattern/replyPattern/responseTemplate
while DataCommand used sendFormat+sendFields+sendDefaults / requestFormat+
requestFields+prefix / unpackingMask+replyDataLength / responseFormat+
responseFields. Twenty-two attribute slots describing four conceptual
roles, no two sharing a name across subclasses.
This commit gives every Command subclass the same four attribute names
for the same four operations. For TextCommand they hold strings (format
strings for encoders, regexes for decoders). For DataCommand they hold
small frozen dataclasses (DataEncoder bundles struct format + fields +
defaults; DataDecoder bundles struct format + fields + length + prefix).
Deleted attributes:
- alternatePattern: TextCommand + MultilineTextCommand kwarg that was
plumbed through readMatchingGroups but never actually set by any
Command in the codebase. Fold into replyDecoder regex if needed.
- replyHexRegex: DataCommand kwarg whose only code path raised
NotImplementedError. Dead.
Migration of every Command in the codebase to the new constructor:
- SutterDevice (4 commands): each DataCommand now wraps the struct
format + fields + defaults inside DataEncoder/DataDecoder. The MOVE
command goes from 7 keyword args + a prefix=b'M' to one tidy
requestEncoder/requestDecoder/replyDecoder triple.
- IntellidriveDevice (3 text commands), IntegraDevice (5 text/multiline
commands), EchoDevice (3 mixed commands), CoboltDevice (11 text
commands): same pattern, attribute names renamed.
- testCommandRecognition.py (38 tests), testTableDrivenDebugPort.py
(3 fixtures + 12 tests), testCommunicationPorts.py (5 tests): all
rewritten to use the new constructor signatures.
Internal property renames:
- TextCommand.effectiveMatchPattern -> effectiveDecoder
- TextCommand._autoMatchPattern (was a property) -> _autoMatchPattern()
(now a method, since it's called rather than read)
These are private/dunder-ish; the only tests that referenced them were
updated.
Verified:
- 261 passed, 203 skipped, 0 failures on the full test suite. The
skipped tests are all hardware-gated (no spectrometer / no Sutter /
no LabJack attached) and were also skipping before this commit.
Closes the first item of the redesign discussed in PR #85's review:
"TextCommand and DataCommand don't share a shape". The remaining items
(separate Command schema from per-call instance, unify error model,
mock hook contract) are left for follow-up work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
First step of the redesign discussed during review of PR #85.
What changes
Every `Command` subclass — `TextCommand`, `MultilineTextCommand`, `DataCommand` — now carries the same four attribute names for the same four conceptual operations:
Two new frozen dataclasses (`DataEncoder`, `DataDecoder`) collapse the 12 previous attribute slots on `DataCommand` (`sendFormat`/`sendFields`/`sendDefaults`/`requestFormat`/`requestFields`/`prefix`/`responseFormat`/`responseFields`/`unpackingMask`/`replyDataLength`/`replyHexRegex`/`_prefix`) into 4 grouped slots.
Deleted attributes
Migration scope
All five device families' `commands = {...}` dicts migrated:
Test fixtures in `testCommandRecognition.py` (38 tests), `testTableDrivenDebugPort.py` (3 fixtures + 12 tests), and `testCommunicationPorts.py` (5 tests) all rewritten for the new constructor signatures.
Before / after — SutterDevice MOVE
```python
Before
"MOVE": DataCommand(name="MOVE", prefix=b'M',
sendFormat='<clllc',
sendFields=('header', 'x', 'y', 'z', 'terminator'),
sendDefaults={'header': b'M', 'terminator': b'\r'},
requestFormat='<xlllx', requestFields=('x', 'y', 'z'),
replyDataLength=1, unpackingMask='<c'),
After
"MOVE": DataCommand(name="MOVE",
requestEncoder=DataEncoder('<clllc',
('header', 'x', 'y', 'z', 'terminator'),
{'header': b'M', 'terminator': b'\r'}),
requestDecoder=DataDecoder('<xlllx', ('x', 'y', 'z'), prefix=b'M'),
replyDecoder=DataDecoder('<c', length=1),
),
```
Internal renames
Both are private-ish; the only tests that touched them were updated.
Test plan
What this PR does not address (intentional, deferred)
From the review of PR #85, the redesign concerns were:
Relationship to PR #85
`unify-sendcommand` (PR #85) is unaffected by this PR — they touch different concerns. After this PR merges, PR #85 will need a rebase that picks up the new attribute names.
🤖 Generated with Claude Code