Add return typehints to magic methods

This commit is contained in:
Julian Stirling 2025-08-27 14:04:25 +01:00
parent 4c46330959
commit 2ce49088e7
17 changed files with 41 additions and 34 deletions

View file

@ -134,7 +134,6 @@ ignore = [
"D203", # incompatible with D204 "D203", # incompatible with D204
"D213", # incompatible with D212 "D213", # incompatible with D212
"D400", # A stricter version of #415 that doesn't allow ! "D400", # A stricter version of #415 that doesn't allow !
"ANN204", # Requrite type hints for
"ANN401", # Disalows Any, Any is needed at times, Once MyPy is running Any will be "ANN401", # Disalows Any, Any is needed at times, Once MyPy is running Any will be
# handled appropriately # handled appropriately
] ]

View file

@ -55,7 +55,7 @@ class BackgroundDetectAlgorithm:
settings_data_model: BaseModel = BaseModel settings_data_model: BaseModel = BaseModel
"""The data model of algorithm settings. This must be set by child classes""" """The data model of algorithm settings. This must be set by child classes"""
def __init__(self): def __init__(self) -> None:
"""Initialise the algorithm settings.""" """Initialise the algorithm settings."""
try: try:
self._settings: BaseModel = self.settings_data_model() self._settings: BaseModel = self.settings_data_model()

View file

@ -120,7 +120,7 @@ class OFMLogFileFormatter(logging.Formatter):
class OFMHandler(logging.Handler): class OFMHandler(logging.Handler):
"""A logging.Handler that stores the most recent logs for access by the server.""" """A logging.Handler that stores the most recent logs for access by the server."""
def __init__(self, level: int = logging.INFO, max_logs: int = 250): def __init__(self, level: int = logging.INFO, max_logs: int = 250) -> None:
"""Initialise the handler with a set logging level and message buffer size. """Initialise the handler with a set logging level and message buffer size.
:param level: The level of logs captured. As standard logs of INFO and above :param level: The level of logs captured. As standard logs of INFO and above

View file

@ -167,7 +167,7 @@ class ScanDirectoryManager:
_base_scan_dir: str _base_scan_dir: str
def __init__(self, base_scan_dir: str): def __init__(self, base_scan_dir: str) -> None:
"""Initialise the scan directory manager. """Initialise the scan directory manager.
:param base_scan_dir: Path of the directory that holds all scans. :param base_scan_dir: Path of the directory that holds all scans.
@ -374,7 +374,7 @@ class ScanDirectory:
_name: str _name: str
_base_scan_dir: str _base_scan_dir: str
def __init__(self, name: str, base_scan_dir: str): def __init__(self, name: str, base_scan_dir: str) -> None:
"""Initialise the scan directory. """Initialise the scan directory.
:param name: the name of the scan (the scan directory basename). :param name: the name of the scan (the scan directory basename).

View file

@ -80,7 +80,7 @@ class ScanPlanner:
def __init__( def __init__(
self, initial_position: XYPos, planner_settings: Optional[dict] = None self, initial_position: XYPos, planner_settings: Optional[dict] = None
): ) -> None:
"""Set up lists for the path planning, and scan history.""" """Set up lists for the path planning, and scan history."""
self._initial_position = enforce_xy_tuple(initial_position) self._initial_position = enforce_xy_tuple(initial_position)
self._parse(planner_settings) self._parse(planner_settings)

View file

@ -59,7 +59,9 @@ class BaseStitcher:
complete. complete.
""" """
def __init__(self, images_dir: str, *, overlap: float, correlation_resize: float): def __init__(
self, images_dir: str, *, overlap: float, correlation_resize: float
) -> None:
"""Initialise a stitcher. """Initialise a stitcher.
All args except images_dir are positional only. All args except images_dir are positional only.
@ -128,7 +130,9 @@ class PreviewStitcher(BaseStitcher):
one preview must finish before another can be started. one preview must finish before another can be started.
""" """
def __init__(self, images_dir: str, *, overlap: float, correlation_resize: float): def __init__(
self, images_dir: str, *, overlap: float, correlation_resize: float
) -> None:
"""Initialise a preview stitcher. """Initialise a preview stitcher.
All args except images_dir are positional only. All args except images_dir are positional only.
@ -192,7 +196,7 @@ class FinalStitcher(BaseStitcher):
correlation_resize: Optional[float] = None, correlation_resize: Optional[float] = None,
stitch_tiff: bool = False, stitch_tiff: bool = False,
scan_data_dict: Optional[dict[str, Any]] = None, scan_data_dict: Optional[dict[str, Any]] = None,
): ) -> None:
"""Initialise a final stitcher, this has more args than the base class. """Initialise a final stitcher, this has more args than the base class.
All args except images_dir are positional only. All args except images_dir are positional only.

View file

@ -215,7 +215,9 @@ class JPEGSharpnessMonitor:
SharpnessMonitorDep as an argument is called. SharpnessMonitorDep as an argument is called.
""" """
def __init__(self, stage: Stage, camera: RawCamera, portal: lt.deps.BlockingPortal): def __init__(
self, stage: Stage, camera: RawCamera, portal: lt.deps.BlockingPortal
) -> None:
"""Initialise a new JPEGSharpnessMonitor. The args are injected automatically. """Initialise a new JPEGSharpnessMonitor. The args are injected automatically.
:param stage: A direct_thing_client dependency for the the microscope stage. :param stage: A direct_thing_client dependency for the the microscope stage.

View file

@ -69,7 +69,7 @@ class CameraMemoryBuffer:
_storage: dict[int, tuple[Any, Optional[dict]]] _storage: dict[int, tuple[Any, Optional[dict]]]
def __init__(self): def __init__(self) -> None:
"""Create the buffer instance.""" """Create the buffer instance."""
# This dictionary is the main store for data. Dictionaries are ordered since # This dictionary is the main store for data. Dictionaries are ordered since
# Python 3.6, so the order in the dictionary is the capture order # Python 3.6, so the order in the dictionary is the capture order
@ -170,7 +170,7 @@ class BaseCamera(lt.Thing):
lores_mjpeg_stream = lt.outputs.MJPEGStreamDescriptor() lores_mjpeg_stream = lt.outputs.MJPEGStreamDescriptor()
_memory_buffer = CameraMemoryBuffer() _memory_buffer = CameraMemoryBuffer()
def __init__(self): def __init__(self) -> None:
"""Initialise the base camera, this creates the background detectors. """Initialise the base camera, this creates the background detectors.
This must be run by all child camera classes. This must be run by all child camera classes.

View file

@ -25,7 +25,7 @@ from . import BaseCamera
class OpenCVCamera(BaseCamera): class OpenCVCamera(BaseCamera):
"""A Thing that provides and interface to an OpenCV Camera.""" """A Thing that provides and interface to an OpenCV Camera."""
def __init__(self, camera_index: int = 0): def __init__(self, camera_index: int = 0) -> None:
"""Iniatilise the thing storing the index of the camera to use. """Iniatilise the thing storing the index of the camera to use.
:param camera_index: The index of the camera to use for the microscope. :param camera_index: The index of the camera to use for the microscope.
@ -35,7 +35,7 @@ class OpenCVCamera(BaseCamera):
self._capture_thread: Optional[Thread] = None self._capture_thread: Optional[Thread] = None
self._capture_enabled = False self._capture_enabled = False
def __enter__(self): def __enter__(self) -> None:
"""Start the capture thread when the Thing context manager is opened.""" """Start the capture thread when the Thing context manager is opened."""
self.cap = cv2.VideoCapture(self.camera_index) self.cap = cv2.VideoCapture(self.camera_index)
self._capture_enabled = True self._capture_enabled = True
@ -48,7 +48,7 @@ class OpenCVCamera(BaseCamera):
_exc_type: type[BaseException], _exc_type: type[BaseException],
_exc_value: Optional[BaseException], _exc_value: Optional[BaseException],
_traceback: Optional[TracebackType], _traceback: Optional[TracebackType],
): ) -> None:
"""Release the camera when the Thing context manager is closed. """Release the camera when the Thing context manager is closed.
Before releasing the camera the capture thread is closed. Before releasing the camera the capture thread is closed.

View file

@ -53,7 +53,9 @@ class MissingCalibrationError(RuntimeError):
class PicameraStreamOutput(Output): class PicameraStreamOutput(Output):
"""An Output class that sends frames to a stream.""" """An Output class that sends frames to a stream."""
def __init__(self, stream: lt.outputs.MJPEGStream, portal: lt.deps.BlockingPortal): def __init__(
self, stream: lt.outputs.MJPEGStream, portal: lt.deps.BlockingPortal
) -> None:
"""Create an output that puts frames in an MJPEGStream. """Create an output that puts frames in an MJPEGStream.
We need to pass the stream object, and also the blocking portal, because We need to pass the stream object, and also the blocking portal, because
@ -126,7 +128,7 @@ class StreamingPiCamera2(BaseCamera):
generalisation. generalisation.
""" """
def __init__(self, camera_num: int = 0): def __init__(self, camera_num: int = 0) -> None:
"""Initialise the camera with the given camera number. """Initialise the camera with the given camera number.
This makes no connection to the camera (except to get the default tuning file). This makes no connection to the camera (except to get the default tuning file).
@ -384,7 +386,7 @@ class StreamingPiCamera2(BaseCamera):
) )
self._picamera_lock = RLock() self._picamera_lock = RLock()
def __enter__(self): def __enter__(self) -> None:
"""Start streaming when the Thing context manager is opened. """Start streaming when the Thing context manager is opened.
This opens the picamera connection, initialises the camera, sets the This opens the picamera connection, initialises the camera, sets the
@ -430,7 +432,7 @@ class StreamingPiCamera2(BaseCamera):
_exc_type: type[BaseException], _exc_type: type[BaseException],
_exc_value: Optional[BaseException], _exc_value: Optional[BaseException],
_traceback: Optional[TracebackType], _traceback: Optional[TracebackType],
): ) -> None:
"""Close the picamera connection when the Thing context manager is closed.""" """Close the picamera connection when the Thing context manager is closed."""
self.stop_streaming() self.stop_streaming()
with self._streaming_picamera() as cam: with self._streaming_picamera() as cam:

View file

@ -54,7 +54,7 @@ class SimulatedCamera(BaseCamera):
glyph_shape: tuple[int, int, int] = (91, 91, 3), glyph_shape: tuple[int, int, int] = (91, 91, 3),
canvas_shape: tuple[int, int, int] = (3000, 4000, 3), canvas_shape: tuple[int, int, int] = (3000, 4000, 3),
frame_interval: float = 0.1, frame_interval: float = 0.1,
): ) -> None:
"""Initialise the simulated with settings for how images are generated. """Initialise the simulated with settings for how images are generated.
:param shape: The shape (size) of the generated image. :param shape: The shape (size) of the generated image.
@ -208,7 +208,7 @@ class SimulatedCamera(BaseCamera):
pos = {"x": 0, "y": 0, "z": 0} pos = {"x": 0, "y": 0, "z": 0}
return self.generate_image((pos["y"], pos["x"], pos["z"])) return self.generate_image((pos["y"], pos["x"], pos["z"]))
def __enter__(self): def __enter__(self) -> None:
"""Start the capture thread when the Thing context manager is opened.""" """Start the capture thread when the Thing context manager is opened."""
self.start_streaming() self.start_streaming()
return self return self
@ -218,7 +218,7 @@ class SimulatedCamera(BaseCamera):
_exc_type: type[BaseException], _exc_type: type[BaseException],
_exc_value: Optional[BaseException], _exc_value: Optional[BaseException],
_traceback: Optional[TracebackType], _traceback: Optional[TracebackType],
): ) -> None:
"""Close the capture thread when the Thing context manager is closed.""" """Close the capture thread when the Thing context manager is closed."""
if self.stream_active: if self.stream_active:
self._capture_enabled = False self._capture_enabled = False

View file

@ -62,7 +62,7 @@ class RecordedMove:
for calibrating the stage as it allows measuring how long moves take. for calibrating the stage as it allows measuring how long moves take.
""" """
def __init__(self, stage: Stage): def __init__(self, stage: Stage) -> None:
"""Set the stage client used for for movement. """Set the stage client used for for movement.
:param stage: the stage client to be used. ``stage.move_to_xyz_position`` will :param stage: the stage client to be used. ``stage.move_to_xyz_position`` will
@ -72,7 +72,7 @@ class RecordedMove:
self._current_position: Optional[CoordinateType] = None self._current_position: Optional[CoordinateType] = None
self._history: List[Tuple[float, Optional[CoordinateType]]] = [] self._history: List[Tuple[float, Optional[CoordinateType]]] = []
def __call__(self, new_position: CoordinateType): def __call__(self, new_position: CoordinateType) -> None:
"""Move to a new position, and record it.""" """Move to a new position, and record it."""
self._history.append((time.time(), self._current_position)) self._history.append((time.time(), self._current_position))
self._stage.move_to_xyz_position(xyz_pos=new_position) self._stage.move_to_xyz_position(xyz_pos=new_position)
@ -99,7 +99,7 @@ class CSMUncalibratedError(HTTPException):
live preview to move, or when performing a scan. live preview to move, or when performing a scan.
""" """
def __init__(self): def __init__(self) -> None:
"""Customise the default error code and message of HTTPException.""" """Customise the default error code and message of HTTPException."""
HTTPException.__init__( HTTPException.__init__(
self, self,

View file

@ -85,7 +85,7 @@ class SmartScanThing(lt.Thing):
past scans. past scans.
""" """
def __init__(self, scans_folder: str): def __init__(self, scans_folder: str) -> None:
"""Initialise a SmartScanThing saving to and loading from the input directory. """Initialise a SmartScanThing saving to and loading from the input directory.
:param scans_folder: This is the path to the directory where all scans will be :param scans_folder: This is the path to the directory where all scans will be

View file

@ -45,7 +45,7 @@ class BaseStage(lt.Thing):
_axis_names = ("x", "y", "z") _axis_names = ("x", "y", "z")
def __init__(self): def __init__(self) -> None:
"""Initialise the stage. """Initialise the stage.
:raises RedefinedBaseMovementError: if ``move_relative`` and/or :raises RedefinedBaseMovementError: if ``move_relative`` and/or

View file

@ -19,7 +19,7 @@ class DummyStage(BaseStage):
hardware attached. hardware attached.
""" """
def __init__(self, step_time: float = 0.001, **kwargs: Any): def __init__(self, step_time: float = 0.001, **kwargs: Any) -> None:
"""Initialise the Dummy stage, setting the step_time to adjust the speed. """Initialise the Dummy stage, setting the step_time to adjust the speed.
:param step_time: The time in seconds per "motor" step. The default of 0.001 :param step_time: The time in seconds per "motor" step. The default of 0.001
@ -31,7 +31,7 @@ class DummyStage(BaseStage):
self.step_time = step_time self.step_time = step_time
self.instantaneous_position = self._hardware_position self.instantaneous_position = self._hardware_position
def __enter__(self): def __enter__(self) -> None:
"""Register the stage position when the Thing context manager is opened.""" """Register the stage position when the Thing context manager is opened."""
self.instantaneous_position = self._hardware_position self.instantaneous_position = self._hardware_position
@ -40,7 +40,7 @@ class DummyStage(BaseStage):
_exc_type: type[BaseException], _exc_type: type[BaseException],
_exc_value: Optional[BaseException], _exc_value: Optional[BaseException],
_traceback: Optional[TracebackType], _traceback: Optional[TracebackType],
): ) -> None:
"""Nothing to do when the Thing context manager is closed.""" """Nothing to do when the Thing context manager is closed."""
axis_inverted = lt.ThingSetting( axis_inverted = lt.ThingSetting(

View file

@ -25,7 +25,7 @@ class SangaboardThing(BaseStage):
functionality is accessed by directly querying the serial interface. functionality is accessed by directly querying the serial interface.
""" """
def __init__(self, port: str = None, **kwargs: Any): def __init__(self, port: str = None, **kwargs: Any) -> None:
"""Initialise SangaboardThing. """Initialise SangaboardThing.
Initialise the "Thing", but do not initialise an underlying Initialise the "Thing", but do not initialise an underlying
@ -42,7 +42,7 @@ class SangaboardThing(BaseStage):
self.sangaboard_kwargs["port"] = port self.sangaboard_kwargs["port"] = port
super().__init__(**kwargs) super().__init__(**kwargs)
def __enter__(self): def __enter__(self) -> None:
"""Connect to the sangaboard when the Thing context manager is opened.""" """Connect to the sangaboard when the Thing context manager is opened."""
self._sangaboard = sangaboard.Sangaboard(**self.sangaboard_kwargs) self._sangaboard = sangaboard.Sangaboard(**self.sangaboard_kwargs)
self._sangaboard_lock = threading.RLock() self._sangaboard_lock = threading.RLock()
@ -59,7 +59,7 @@ class SangaboardThing(BaseStage):
_exc_type: type[BaseException], _exc_type: type[BaseException],
_exc_value: Optional[BaseException], _exc_value: Optional[BaseException],
_traceback: Optional[TracebackType], _traceback: Optional[TracebackType],
): ) -> None:
"""Close the sangaboard connection when the Thing context manager is closed.""" """Close the sangaboard connection when the Thing context manager is closed."""
with self.sangaboard() as sb: with self.sangaboard() as sb:
sb.close() sb.close()

View file

@ -78,7 +78,7 @@ class ErrorCapturingThread(Thread):
kwargs: Optional[dict[str, Any]] = None, kwargs: Optional[dict[str, Any]] = None,
*, *,
daemon: Optional[bool] = None, daemon: Optional[bool] = None,
): ) -> None:
"""Initialise with the same arguments as Thread.""" """Initialise with the same arguments as Thread."""
# As all inputs are keywords we need to set the default values for args and kwargs: # As all inputs are keywords we need to set the default values for args and kwargs:
if args is None: if args is None: