Skip to content

Conversation

AdvancedImagingUTSW
Copy link
Collaborator

This pull request refactors the base classes for several device types (camera, DAQ, filter wheel, and galvo) in the navigate model to use Python's abc module, making them proper abstract base classes. This enforces a consistent interface for all subclasses and clarifies which methods must be implemented by hardware-specific implementations. Additionally, some type annotations and docstrings have been improved, and redundant or duplicated code has been removed from subclasses.

Abstract base class refactoring and interface enforcement:

  • Converted CameraBase, DAQBase, FilterWheelBase, and GalvoBase to inherit from ABC and use @abstractmethod for key interface methods, ensuring that hardware-specific subclasses implement required methods. [1] [2] [3] [4] [5] [6] [7] [8]

  • Added or updated abstract methods in base classes:

    • CameraBase: get_new_frame, initialize_image_series, close_image_series, set_line_interval, set_exposure_time, set_trigger_mode, and calculate_light_sheet_exposure_time now marked as abstract. [1] [2] [3]
    • DAQBase: stop_acquisition, prepare_acquisition, run_acquisition, and wait_acquisition_done now marked as abstract.
    • FilterWheelBase: set_filter now marked as abstract.
    • GalvoBase: turn_off now marked as abstract.

Code cleanup and improvements:

  • Improved type annotations and docstrings for constructors and methods in all affected base classes, clarifying expected input and output types. [1] [2] [3] [4] [5] [6]
  • Removed redundant load_images implementation from SyntheticCamera, as this logic is now handled in the abstract base class.
  • Minor import cleanups and formatting improvements in updated files. [1] [2]

These changes help ensure that all device subclasses provide the necessary functionality, make the codebase more robust and maintainable, and reduce code duplication.

Updated DAQBase, FilterWheelBase, and GalvoBase to inherit from abc.ABC and define required abstract methods. Enforces implementation of key interface methods in subclasses and clarifies the intended usage of these base classes as abstract interfaces for hardware device control.
Updated LaserBase, RemoteFocusBase, and ShutterBase to inherit from ABC and define key interface methods as abstractmethods. Removed unused initialize_laser method from LaserBase and SyntheticLaser.
StageBase now inherits from ABC and defines abstract methods for position reporting, absolute movement, axis movement, and stopping. Type hints and docstrings were added.
Implemented additional methods for synthetic device classes: camera (light sheet exposure calculation), galvo (turn_off), laser (set_power, turn_on, turn_off), stage (stop), and zoom (set_zoom). Added type annotations and abstract base class usage to ZoomBase and updated related zoom device classes.
Updated all device-related test files to use synthetic device classes instead of base classes for cameras, DAQs, filter wheels, galvos, lasers, remote focus, shutters, and zoom devices. Added a stub 'stop' method to MCLStage.
Copy link

codecov bot commented Sep 29, 2025

Codecov Report

❌ Patch coverage is 64.39024% with 146 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.58%. Comparing base (a857470) to head (581421b).
⚠️ Report is 28 commits behind head on develop.

Files with missing lines Patch % Lines
src/navigate/model/devices/camera/photometrics.py 0.00% 29 Missing ⚠️
src/navigate/model/devices/camera/ximea.py 0.00% 20 Missing ⚠️
src/navigate/model/devices/camera/hamamatsu.py 0.00% 19 Missing ⚠️
src/navigate/model/devices/galvo/asi.py 0.00% 8 Missing ⚠️
src/navigate/model/devices/laser/asi.py 0.00% 8 Missing ⚠️
src/navigate/model/devices/camera/base.py 82.50% 7 Missing ⚠️
src/navigate/model/devices/filter_wheel/ludl.py 0.00% 7 Missing ⚠️
src/navigate/model/devices/filter_wheel/ni.py 0.00% 7 Missing ⚠️
src/navigate/model/devices/daq/base.py 71.42% 6 Missing ⚠️
src/navigate/model/devices/stage/base.py 79.16% 5 Missing ⚠️
... and 15 more
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1140      +/-   ##
===========================================
+ Coverage    53.53%   53.58%   +0.05%     
===========================================
  Files          194      194              
  Lines        22374    22460      +86     
===========================================
+ Hits         11978    12036      +58     
- Misses       10396    10424      +28     
Flag Coverage Δ
unittests 53.58% <64.39%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AdvancedImagingUTSW
Copy link
Collaborator Author

@annie-xd-wang - I managed to spend a little time trying to wrap this up. Could you please double-check that I have 1) identified all of the proper interface methods and 2) that every established device has these methods implemented (either by calling the super() method, or just being a pass statement if not critical).

@AdvancedImagingUTSW AdvancedImagingUTSW linked an issue Sep 29, 2025 that may be closed by this pull request
@AdvancedImagingUTSW AdvancedImagingUTSW marked this pull request as ready for review September 29, 2025 12:06
@Copilot Copilot AI review requested due to automatic review settings September 29, 2025 12:06
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This pull request refactors the base classes for several device types to use Python's abc module, making them proper abstract base classes. This ensures consistent interfaces across hardware implementations and eliminates code duplication.

Key Changes:

  • Converted CameraBase, DAQBase, FilterWheelBase, GalvoBase, ShutterBase, StageBase, RemoteFocusBase, LaserBase, and ZoomBase to abstract base classes with @abstractmethod decorators
  • Updated all test files to use synthetic implementations instead of base classes (which can no longer be instantiated)
  • Moved common functionality like load_images from synthetic camera to base camera class

Reviewed Changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/navigate/model/devices/*/base.py Added ABC inheritance and abstract method decorators to enforce interface contracts
src/navigate/model/devices/*/synthetic.py Implemented required abstract methods in synthetic device classes
test/model/devices/*/test_*.py Updated tests to use concrete synthetic implementations instead of abstract base classes
docs/source/index.rst Updated documentation with new badges and improved formatting
docs/source/03_contributing/01_contributing_guidelines/01_contributing_guidelines.rst Enhanced contributing guidelines with better structure and hardware abstraction documentation

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +209 to 218

# Test minimum boundary
move_dict[f"{axis}_abs"] = axis_min - 1.5
abs_dict[axis] = axis_min - 1.5
assert stage.verify_abs_position(move_dict) == abs_dict

# Test maximum boundary
move_dict[f"{axis}_abs"] = axis_max + 1.5
abs_dict[axis] = axis_max + 1.5
assert stage.verify_abs_position(move_dict) == abs_dict
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

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

[nitpick] The added comments improve readability, but the test logic appears to expect that positions outside the limits are accepted when stage_limits is False. Consider adding assertions that verify the stage_limits flag is indeed False before these boundary tests to make the test intent clearer.

Copilot uses AI. Check for mistakes.

laser = SyntheticLaser(microscope_name, None, model.configuration, 0)

funcs = ["set_power", "turn_on", "turn_off", "close", "initialize_laser"]
funcs = ["set_power", "turn_on", "turn_off", "close"]
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

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

The removal of 'initialize_laser' from the function list suggests this method was removed from the base class. Ensure this change aligns with the abstract base class refactoring and that initialization logic is properly handled elsewhere.

Copilot uses AI. Check for mistakes.

Comment on lines 256 to 257
# TODO: self.num_of_frame is not defined in the base class
if idx >= self.num_of_frame:
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

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

This TODO comment indicates a potential issue where self.num_of_frame may not be properly defined in the base class. This should be resolved rather than left as a TODO, especially since the attribute is initialized in the __init__ method at line 166.

Copilot uses AI. Check for mistakes.


def turn_off(self) -> None:
"""Turn off the laser"""

Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

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

[nitpick] There's an unnecessary blank line between the docstring and the pass statement. Remove the blank line for consistent formatting.

Suggested change

Copilot uses AI. Check for mistakes.

@AdvancedImagingUTSW AdvancedImagingUTSW merged commit cae1fbe into develop Oct 3, 2025
1 of 2 checks passed
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.

Update Developer Documentation

2 participants