Uniformize capability mixins: single *Capability convention, single module, single base#114
Merged
Merged
Conversation
Problem: The DAQ family named its interface-segregated capability mixins with a *Device suffix (AnalogInputDevice, TriggerableDevice, ...), while the same objects are features a device *has*, not devices themselves. This collided conceptually with instantiable hardware drivers, which are also named *Device (LabjackDevice, SR830Device), making it unclear from a name whether a class is a mixin or a real device. Solution: Rename all nine DAQ mixins to the *Capability suffix, reserving *Device for instantiable hardware drivers. Public methods and behavior are unchanged; only the mixin class names change. AnalogInputDevice -> AnalogInputCapability AnalogOutputDevice -> AnalogOutputCapability AnalogIODevice -> AnalogIOCapability AnalogInputStreamDevice -> AnalogInputStreamCapability DigitalInputDevice -> DigitalInputCapability DigitalOutputDevice -> DigitalOutputCapability DigitalIODevice -> DigitalIOCapability PhaseLockedDetectionDevice -> PhaseLockedDetectionCapability TriggerableDevice -> TriggerCapability Updates the LabjackDevice and SR830Device base-class lists and imports, the daq package exports, and the SR830 tests. Documents the rename in CHANGELOG (Unreleased, marked Breaking) and the *Capability/*Device rule in CLAUDE.md and the skill doc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem: After the DAQ rename, two families still used their own conventions for capability mixins: laser sources used a *Control suffix (OnOffControl, PowerControl, ...) and power meters used adjective forms (WavelengthCalibratable, AutoScalable, ScaleAdjustable). This left three naming styles for the same concept -- a feature a device may have -- and made it inconsistent which classes are mixins versus instantiable devices. Solution: Rename these mixins to the same *Capability suffix adopted for DAQ, completing the uniform rule: *Capability for mixins, *Device for instantiable hardware. Public methods and behavior are unchanged. Laser sources (sources/capabilities.py): OnOffControl -> OnOffCapability ShutterControl -> ShutterCapability PowerControl -> PowerCapability InterlockControl -> InterlockCapability AutostartControl -> AutostartCapability WavelengthControl -> WavelengthCapability DispersionControl -> DispersionCapability Power meters (powermeters/capabilities.py): WavelengthCalibratable -> WavelengthCalibrationCapability AutoScalable -> AutoScaleCapability ScaleAdjustable -> ScaleCapability Updates the CoboltDevice, MillenniaEv25Device, MatisseDevice, VerdiGDevice, FieldMasterDevice, and IntegraDevice base-class lists and imports, the sources/powermeters package exports, the source/powermeter tests, and the physicaldevice.py doc comment. Documents the rename in CHANGELOG (Unreleased, folded into the Breaking capability-rename entry) and CLAUDE.md / the skill doc, and aligns the HOPS and Millennia manuals. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…y base Problem: Capability mixins were spread across three modules with two independent Capability base classes: sources/capabilities.py and powermeters/capabilities.py each defined their own Capability(ABC), while the DAQ mixins in daq/daqdevice.py inherited bare ABC with no shared base at all. Capability introspection (capabilities() / hasCapability()) was duplicated verbatim on LaserSourceDevice and PowerMeterDevice, each bound to its family's local Capability, and DAQ devices had no introspection. Solution: Move every capability mixin into a single top-level module, hardwarelibrary/capabilities.py, all subclassing one Capability base. The DAQ enums (InputSource, TriggerSource, SampleClock, DAQNotification) move with their mixins. Hoist capabilities() / hasCapability() onto PhysicalDevice, bound to the single Capability, so every device -- DAQ included -- gets capability introspection, and the duplicated methods are removed (LaserSourceDevice becomes a pure marker; PowerMeterDevice keeps only its power hooks). The per-family capabilities.py / daqdevice.py files are deleted. All internal imports point at hardwarelibrary.capabilities; the family package __init__s still re-export their own mixins, so existing consumers such as `from hardwarelibrary.daq import AnalogIOCapability` keep working. Docs updated: capabilities are documented once on the Core page; the per-family automodule sections and their file-path references are removed. Full suite: 470 passed, 247 skipped, no regressions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem: DAQNotification (willAcquire/didAcquire) sat as a free-floating module-level enum in capabilities.py, unattached to the capability that posts it. Solution: Nest it as AnalogInputStreamCapability.Notification, inside the acquisition capability it belongs to, so the notification is discoverable from the capability that raises it. Co-Authored-By: Claude Opus 4.8 (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.
Summary
Uniformizes the library's capability system across all three families (DAQ, laser sources, power meters), which previously used three different naming conventions and two independent
Capabilitybase classes.The end-state rule:
*Capability= a feature a device may have (a mixin);*Device= instantiable hardware.Three focused commits:
*Device→*Capability—AnalogInputDevice→AnalogInputCapability,TriggerableDevice→TriggerCapability, etc.*Deviceno longer doubles as both a mixin suffix and a hardware-driver suffix.*Control) and power-meter (*able) mixins →*Capability—OnOffControl→OnOffCapability,WavelengthCalibratable→WavelengthCalibrationCapability, etc.hardwarelibrary/capabilities.pyand subclasses a singleCapability(ABC). The DAQ enums (InputSource,TriggerSource,SampleClock,DAQNotification) move with their mixins.capabilities()/hasCapability()are hoisted ontoPhysicalDevice, so every device — including DAQ drivers — gets capability introspection, and the duplicated copies onLaserSourceDevice/PowerMeterDeviceare removed.Breaking changes
Public methods and runtime behavior are unchanged; only class names, the module layout, and where introspection lives change. Downstream code must update mixin names and imports. The family package
__init__s still re-export their own mixins, sofrom hardwarelibrary.daq import AnalogIOCapability(and equivalents) keep working. SeeCHANGELOG.md[Unreleased]for the full old → new table.Removed
hardwarelibrary/sources/capabilities.pyhardwarelibrary/powermeters/capabilities.pyhardwarelibrary/daq/daqdevice.pyDocs
CLAUDE.md, the pyhardwarelibrary skill, and the HOPS/Millennia manuals reflect the new names.automodulesections removed.[1.3.1],[1.4.0]) left intact as the accurate record of prior names.Testing
Full suite: 470 passed, 247 skipped, 0 failures — identical to the pre-change baseline (skips are all hardware-absent).
🤖 Generated with Claude Code