Class docstrings
This commit is contained in:
parent
11a1fd7f85
commit
a30b726b91
16 changed files with 118 additions and 10 deletions
|
|
@ -130,7 +130,6 @@ ignore = [
|
||||||
"D400", # A stricter version of #415 that doesn't allow !
|
"D400", # A stricter version of #415 that doesn't allow !
|
||||||
# The checkers below should be turned on as they complain about missing docstrings.
|
# The checkers below should be turned on as they complain about missing docstrings.
|
||||||
"D102",
|
"D102",
|
||||||
"D101",
|
|
||||||
"D103",
|
"D103",
|
||||||
"D104",
|
"D104",
|
||||||
"D105",
|
"D105",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ import requests
|
||||||
|
|
||||||
|
|
||||||
class Zenodo:
|
class Zenodo:
|
||||||
|
"""A class that packages data for Zenodo."""
|
||||||
|
|
||||||
def __init__(self, api_token, use_sandbox=True):
|
def __init__(self, api_token, use_sandbox=True):
|
||||||
self._api_token = api_token
|
self._api_token = api_token
|
||||||
self._use_sandbox = use_sandbox
|
self._use_sandbox = use_sandbox
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ IMAGE_REGEX = re.compile(r"-?[0-9]+_-?[0-9]+\.jpe?g$")
|
||||||
|
|
||||||
|
|
||||||
class NotEnoughFreeSpaceError(IOError):
|
class NotEnoughFreeSpaceError(IOError):
|
||||||
pass
|
"""An exception raised if there is not enough free space on disk to scan."""
|
||||||
|
|
||||||
|
|
||||||
class ScanInfo(BaseModel):
|
class ScanInfo(BaseModel):
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,12 @@ AutofocusDep = lt.deps.direct_thing_client_dependency(AutofocusThing, "/autofocu
|
||||||
|
|
||||||
|
|
||||||
class RecentringThing(lt.Thing):
|
class RecentringThing(lt.Thing):
|
||||||
|
"""A Thing for recentring the stage by monitoring parasitic z motion of the stage.
|
||||||
|
|
||||||
|
As the stage moves over a sphere-cap there is parasitic motion in z during xy
|
||||||
|
movement. The highest z position is the centre of motion.
|
||||||
|
"""
|
||||||
|
|
||||||
@lt.thing_action
|
@lt.thing_action
|
||||||
def recentre(
|
def recentre(
|
||||||
self,
|
self,
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,13 @@ def _get_capture_index_by_id(captures: list[CaptureInfo], buffer_id: int) -> int
|
||||||
|
|
||||||
|
|
||||||
class SharpnessDataArrays(BaseModel):
|
class SharpnessDataArrays(BaseModel):
|
||||||
|
"""A BaseModel with the position and sharpness data from JPEGSharpnessMonitor.
|
||||||
|
|
||||||
|
Each JPEG Size (representing a sharpness metric) has an associated timestamp,
|
||||||
|
as does each stage position. The stage positions need to be interpolated so
|
||||||
|
they correspond with the image timestamps.
|
||||||
|
"""
|
||||||
|
|
||||||
jpeg_times: NDArray
|
jpeg_times: NDArray
|
||||||
jpeg_sizes: NDArray
|
jpeg_sizes: NDArray
|
||||||
stage_times: NDArray
|
stage_times: NDArray
|
||||||
|
|
@ -182,6 +189,21 @@ class SharpnessDataArrays(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class JPEGSharpnessMonitor:
|
class JPEGSharpnessMonitor:
|
||||||
|
"""A class with direct access to the CameraThing for monitoring the MJPEG stream.
|
||||||
|
|
||||||
|
The autofocus algorithm uses sharpness calculated from the file size of the
|
||||||
|
images in the MJPEG stream. This class monitors both the stage position and the
|
||||||
|
jpeg sharpness over time.
|
||||||
|
|
||||||
|
The ``run`` context manager is used to start monitoring the camera stream. Position
|
||||||
|
monitoring happens during ``focus_rel``. Raw data can be retrieved with
|
||||||
|
``data_dict`` and data with interpolate ``z`` positions can be retrieved with
|
||||||
|
move_data.
|
||||||
|
|
||||||
|
A new JPEGSharpnessMonitor instance is created each time an action with the
|
||||||
|
SharpnessMonitorDep as an argument is called.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, stage: Stage, camera: Camera, portal: lt.deps.BlockingPortal):
|
def __init__(self, stage: Stage, camera: Camera, portal: lt.deps.BlockingPortal):
|
||||||
self.camera = camera
|
self.camera = camera
|
||||||
self.stage = stage
|
self.stage = stage
|
||||||
|
|
@ -564,7 +586,7 @@ class AutofocusThing(lt.Thing):
|
||||||
) -> tuple[bool, list[CaptureInfo], Optional[int]]:
|
) -> tuple[bool, list[CaptureInfo], Optional[int]]:
|
||||||
"""Capture a series of images checking that sharpest image central.
|
"""Capture a series of images checking that sharpest image central.
|
||||||
|
|
||||||
The images are seperated in z offset by stack_parameters.stack_dz, as they
|
The images are separated in z offset by stack_parameters.stack_dz, as they
|
||||||
are captured the last stack_parameters.min_images_to_test images are checked
|
are captured the last stack_parameters.min_images_to_test images are checked
|
||||||
to see if the sharpest image is central enough in the stack. If it is the stack
|
to see if the sharpest image is central enough in the stack. If it is the stack
|
||||||
completes.
|
completes.
|
||||||
|
|
@ -577,7 +599,7 @@ class AutofocusThing(lt.Thing):
|
||||||
|
|
||||||
* the stack result (True for successful stack, False for failed stack),
|
* the stack result (True for successful stack, False for failed stack),
|
||||||
* a list of CaptureInfo objects,
|
* a list of CaptureInfo objects,
|
||||||
* the buffer_id of the shapest image (or None if the stack failed)
|
* the buffer_id of the sharpest image (or None if the stack failed).
|
||||||
"""
|
"""
|
||||||
# Move down by the height of the z stack, plus an overshoot
|
# Move down by the height of the z stack, plus an overshoot
|
||||||
# Better to start too low and take too many images than too high and need to refocus
|
# Better to start too low and take too many images than too high and need to refocus
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,24 @@ from .camera import CameraDependency as CamDep
|
||||||
|
|
||||||
|
|
||||||
class ChannelDistributions(BaseModel):
|
class ChannelDistributions(BaseModel):
|
||||||
|
"""A BaseModel for storing the channel distribution of a background image."""
|
||||||
|
|
||||||
means: list[float]
|
means: list[float]
|
||||||
|
"""The mean of each channel in the colourspace."""
|
||||||
standard_deviations: list[float]
|
standard_deviations: list[float]
|
||||||
|
"""The standard deviation of each channel in the colourspace."""
|
||||||
colorspace: str = "LUV"
|
colorspace: str = "LUV"
|
||||||
|
"""The colourspace used."""
|
||||||
|
|
||||||
|
|
||||||
class BackgroundDetectThing(lt.Thing):
|
class BackgroundDetectThing(lt.Thing):
|
||||||
|
"""Thing for setting a background image and detecting sample in the field of view.
|
||||||
|
|
||||||
|
This uses an LUV colour space checking only the mean and standard deviation of the
|
||||||
|
UV channels. Over time different, selectable, background detection methods will be
|
||||||
|
added.
|
||||||
|
"""
|
||||||
|
|
||||||
# Requires a getter and a setter to support being a BaseModel but being
|
# Requires a getter and a setter to support being a BaseModel but being
|
||||||
# saved to file as a dict
|
# saved to file as a dict
|
||||||
_background_distributions: Optional[ChannelDistributions] = None
|
_background_distributions: Optional[ChannelDistributions] = None
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ from labthings_fastapi.types.numpy import NDArray
|
||||||
|
|
||||||
|
|
||||||
class JPEGBlob(lt.blob.Blob):
|
class JPEGBlob(lt.blob.Blob):
|
||||||
|
"""A class representing a JPEG image as a LabThings FastAPI Blob."""
|
||||||
|
|
||||||
media_type: str = "image/jpeg"
|
media_type: str = "image/jpeg"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,14 @@ XYCoordinateType = Tuple[float, float]
|
||||||
|
|
||||||
|
|
||||||
class HardwareInterfaceModel(BaseModel):
|
class HardwareInterfaceModel(BaseModel):
|
||||||
|
"""A pydantic base model for a stage and camera interface.
|
||||||
|
|
||||||
|
This class provides access to both the stage and the camera, but
|
||||||
|
it is confusing both because it is a BaseModel of callables rather
|
||||||
|
than a class with methods, and because it uses names from the underlying
|
||||||
|
Thing actions, but performs different actions.
|
||||||
|
"""
|
||||||
|
|
||||||
move: Callable[[NDArray], None]
|
move: Callable[[NDArray], None]
|
||||||
get_position: Callable[[], NDArray]
|
get_position: Callable[[], NDArray]
|
||||||
grab_image: Callable[[], NDArray]
|
grab_image: Callable[[], NDArray]
|
||||||
|
|
@ -123,6 +131,14 @@ HardwareInterfaceDep = Annotated[
|
||||||
|
|
||||||
|
|
||||||
class MoveHistory(NamedTuple):
|
class MoveHistory(NamedTuple):
|
||||||
|
"""A named tuple containing the position over time for a single move.
|
||||||
|
|
||||||
|
This a named tuple with elements:
|
||||||
|
|
||||||
|
* ``times``
|
||||||
|
* ``stage_positions``
|
||||||
|
"""
|
||||||
|
|
||||||
times: List[float]
|
times: List[float]
|
||||||
stage_positions: List[CoordinateType]
|
stage_positions: List[CoordinateType]
|
||||||
|
|
||||||
|
|
@ -163,6 +179,13 @@ class LoggingMoveWrapper:
|
||||||
|
|
||||||
|
|
||||||
class CSMUncalibratedError(HTTPException):
|
class CSMUncalibratedError(HTTPException):
|
||||||
|
"""An HTTP Exception raised if camera stage mapping data is needed but unavailable.
|
||||||
|
|
||||||
|
Camera Stage Mapping data is needed to convert from distances specified in fractions
|
||||||
|
of the feild of view to distances in motor steps. This is used when clicking on the
|
||||||
|
live preview to move, or when performing a scan.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
HTTPException.__init__(
|
HTTPException.__init__(
|
||||||
self,
|
self,
|
||||||
|
|
@ -186,9 +209,8 @@ class CameraStageMapper(lt.Thing):
|
||||||
direction: Tuple[float, float, float],
|
direction: Tuple[float, float, float],
|
||||||
) -> DenumpifyingDict:
|
) -> DenumpifyingDict:
|
||||||
"""Move a microscope's stage in 1D, and figure out the relationship with the camera."""
|
"""Move a microscope's stage in 1D, and figure out the relationship with the camera."""
|
||||||
move = LoggingMoveWrapper(
|
# log positions and times for stage calibration
|
||||||
hw.move
|
move = LoggingMoveWrapper(hw.move)
|
||||||
) # log positions and times for stage calibration
|
|
||||||
tracker = Tracker(hw.grab_image, hw.get_position, settle=hw.settle)
|
tracker = Tracker(hw.grab_image, hw.get_position, settle=hw.settle)
|
||||||
direction_array: np.ndarray = np.array(direction)
|
direction_array: np.ndarray = np.array(direction)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,12 @@ def nested_dict_get(data: dict, key: Sequence[str], create=False) -> Any:
|
||||||
|
|
||||||
|
|
||||||
class SettingsManager(lt.Thing):
|
class SettingsManager(lt.Thing):
|
||||||
|
"""Provides functionality to other Things about the current server state.
|
||||||
|
|
||||||
|
The SettingsManager is used to get information the microscope ID, the hostname
|
||||||
|
and the state of other Things.
|
||||||
|
"""
|
||||||
|
|
||||||
external_metadata = lt.ThingSetting(
|
external_metadata = lt.ThingSetting(
|
||||||
initial_value={},
|
initial_value={},
|
||||||
model=Mapping,
|
model=Mapping,
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,13 @@ def _scan_running(method):
|
||||||
|
|
||||||
|
|
||||||
class SmartScanThing(lt.Thing):
|
class SmartScanThing(lt.Thing):
|
||||||
|
"""A Thing for scanning samples and interacting with past scans.
|
||||||
|
|
||||||
|
SmartScanThing exposes all functionality for automatically scanning samples,
|
||||||
|
previewing live stitching, retrieving data from past scans, and for deleting
|
||||||
|
past scans.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, scans_folder):
|
def __init__(self, scans_folder):
|
||||||
self._scan_dir_manager = scan_directories.ScanDirectoryManager(scans_folder)
|
self._scan_dir_manager = scan_directories.ScanDirectoryManager(scans_folder)
|
||||||
self._preview_stitch_popen = None
|
self._preview_stitch_popen = None
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class CommandOutput(BaseModel):
|
class CommandOutput(BaseModel):
|
||||||
|
"""A pydantic model passing the STDOUT and STDERR from a subprocess over HTTP."""
|
||||||
|
|
||||||
output: str
|
output: str
|
||||||
error: str
|
error: str
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,13 @@ answers to functions.
|
||||||
|
|
||||||
|
|
||||||
class MockAutoFocusThing:
|
class MockAutoFocusThing:
|
||||||
|
"""A mock autofocus Thing that imports no code from AutofocusThing.
|
||||||
|
|
||||||
|
The class needs functionality added to it over time as more complex
|
||||||
|
mocking is needed. It imports no code from AutofocusThing so that coverage
|
||||||
|
is not artificially inflated.
|
||||||
|
"""
|
||||||
|
|
||||||
# Counter for checking functions were called
|
# Counter for checking functions were called
|
||||||
mock_call_count = {"looping_autofocus": 0}
|
mock_call_count = {"looping_autofocus": 0}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,14 @@ answers to functions.
|
||||||
from openflexure_microscope_server.things.background_detect import ChannelDistributions
|
from openflexure_microscope_server.things.background_detect import ChannelDistributions
|
||||||
|
|
||||||
|
|
||||||
class MockBackgoundDetectThing:
|
class MockBackgroundDetectThing:
|
||||||
|
"""A mock background detect Thing that imports no code from BackgroundDetectThing.
|
||||||
|
|
||||||
|
The class needs functionality added to it over time as more complex
|
||||||
|
mocking is needed. It imports no code from BackgroundDetectThing so that coverage
|
||||||
|
is not artificially inflated.
|
||||||
|
"""
|
||||||
|
|
||||||
background_distributions = ChannelDistributions(
|
background_distributions = ChannelDistributions(
|
||||||
means=[128.0, 128.0, 128.0],
|
means=[128.0, 128.0, 128.0],
|
||||||
standard_deviations=[3.0, 3.0, 3.0],
|
standard_deviations=[3.0, 3.0, 3.0],
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,11 @@ answers to functions.
|
||||||
|
|
||||||
|
|
||||||
class MockCSMThing:
|
class MockCSMThing:
|
||||||
|
"""A mock CSM Thing that imports no code from CameraStageMapper.
|
||||||
|
|
||||||
|
The class needs functionality added to it over time as more complex
|
||||||
|
mocking is needed. It imports no code from CameraStageMapper so that coverage
|
||||||
|
is not artificially inflated.
|
||||||
|
"""
|
||||||
|
|
||||||
image_resolution = (123, 456)
|
image_resolution = (123, 456)
|
||||||
|
|
|
||||||
|
|
@ -9,4 +9,11 @@ answers to functions.
|
||||||
|
|
||||||
|
|
||||||
class MockStageThing:
|
class MockStageThing:
|
||||||
|
"""A mock Thing for a stage that imports no code from BaseStage.
|
||||||
|
|
||||||
|
The class needs functionality added to it over time as more complex
|
||||||
|
mocking is needed. It imports no code from BaseStage so that coverage
|
||||||
|
is not artificially inflated.
|
||||||
|
"""
|
||||||
|
|
||||||
position = (111, 222, 333)
|
position = (111, 222, 333)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ from openflexure_microscope_server.things.smart_scan import (
|
||||||
from .mock_things.mock_csm import MockCSMThing
|
from .mock_things.mock_csm import MockCSMThing
|
||||||
from .mock_things.mock_autofocus import MockAutoFocusThing
|
from .mock_things.mock_autofocus import MockAutoFocusThing
|
||||||
from .mock_things.mock_stage import MockStageThing
|
from .mock_things.mock_stage import MockStageThing
|
||||||
from .mock_things.mock_background_detect import MockBackgoundDetectThing
|
from .mock_things.mock_background_detect import MockBackgroundDetectThing
|
||||||
|
|
||||||
# A global logger to pass in as an Invocation Logger
|
# A global logger to pass in as an Invocation Logger
|
||||||
LOGGER = logging.getLogger("mock-invocation_logger")
|
LOGGER = logging.getLogger("mock-invocation_logger")
|
||||||
|
|
@ -172,7 +172,7 @@ def _run_only_outer_scan(adjust_inital_state: Optional[Callable] = None):
|
||||||
cam_mock = 4 # not called
|
cam_mock = 4 # not called
|
||||||
meta_mock = 5 # not called
|
meta_mock = 5 # not called
|
||||||
csm_mock = MockCSMThing()
|
csm_mock = MockCSMThing()
|
||||||
bkgrnd_det_mock = MockBackgoundDetectThing()
|
bkgrnd_det_mock = MockBackgroundDetectThing()
|
||||||
|
|
||||||
class MockedSmartScanThing(SmartScanThing):
|
class MockedSmartScanThing(SmartScanThing):
|
||||||
"""Mocked version of SmartScanThing with a patched _run_scan method."""
|
"""Mocked version of SmartScanThing with a patched _run_scan method."""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue