Apply suggestions from code review of branch camera_modes

Co-authored-by: Joe Knapper <joe.knapper@glasgow.ac.uk>
This commit is contained in:
Julian Stirling 2026-06-05 15:53:04 +00:00
parent bc7204f554
commit 071d62e8a0
11 changed files with 28 additions and 28 deletions

View file

@ -68,9 +68,9 @@ class OFMThing(lt.Thing):
"""Create a ``RelativeDataPath`` object with this Thing set as the saving Thing. """Create a ``RelativeDataPath`` object with this Thing set as the saving Thing.
:param path: The relative path within the data directory of this Thing's data :param path: The relative path within the data directory of this Thing's data
dir that the data shudl be saved. dir that the data should be saved to.
:param absolute: Set to True if the current path is absolute. A relative path :param absolute: Set to True if the current path is absolute. A relative path
will be returned. An validation error will be raised if the absolute path will be returned. A validation error will be raised if the absolute path
is not within the data directory. is not within the data directory.
:return: A ``RelativeDataPath`` object with the saving Thing already set. :return: A ``RelativeDataPath`` object with the saving Thing already set.

View file

@ -230,8 +230,10 @@ class BaseCamera(OFMThing, ABC):
# would be ideal. # would be ideal.
self._default_background_detector = "bg_channel_deviations_luv" self._default_background_detector = "bg_channel_deviations_luv"
self._background_detector_name: Optional[str] = None self._background_detector_name: Optional[str] = None
self._framerate_monitor_running = False
if "default" and "full_resolution" not in self.streaming_modes: required_modes = ("default", "full_resolution")
if not all(mode in self.streaming_modes for mode in required_modes):
raise KeyError( raise KeyError(
f"Camera {type(self).__name__} doesn't define both a 'default' and a " f"Camera {type(self).__name__} doesn't define both a 'default' and a "
"'full_resolution' streaming mode." "'full_resolution' streaming mode."
@ -559,7 +561,7 @@ class BaseCamera(OFMThing, ABC):
def capture_downsampled_array(self) -> NDArray: def capture_downsampled_array(self) -> NDArray:
"""Acquire one image from the camera, downsample, and return as an array. """Acquire one image from the camera, downsample, and return as an array.
* The array is downsamples by the thing property `downsampled_array_factor`. * The array is downsampled by the thing property `downsampled_array_factor`.
* The default capture array arguments are used. * The default capture array arguments are used.
This method provides the interface expected by the camera_stage_mapping. This method provides the interface expected by the camera_stage_mapping.
@ -718,7 +720,7 @@ class BaseCamera(OFMThing, ABC):
"""Capture a PIL image from the camera. """Capture a PIL image from the camera.
This unlike the ``grab_*`` methods this may pause the stream or temporarily This unlike the ``grab_*`` methods this may pause the stream or temporarily
switch streaming mode to capute the image if required by the mode. switch streaming mode to capture the image if required by the mode.
""" """
@lt.action @lt.action

View file

@ -149,7 +149,7 @@ class OpenCVCamera(BaseCamera):
raise NotImplementedError( raise NotImplementedError(
"OpenCV camera camera doesn't support raw capture." "OpenCV camera camera doesn't support raw capture."
) )
# Warn if the capture mode is incorrect, but don't read the cooerced value as # Warn if the capture mode is incorrect, but don't read the coerced value as
# this camera only supports one mode. # this camera only supports one mode.
self._validate_capture_mode(capture_mode) self._validate_capture_mode(capture_mode)
ret, frame = self.cap.read() ret, frame = self.cap.read()
@ -159,7 +159,7 @@ class OpenCVCamera(BaseCamera):
def _capture_image(self, capture_mode: str = "standard") -> Image.Image: def _capture_image(self, capture_mode: str = "standard") -> Image.Image:
"""Acquire one image from the camera and return as a PIL image.""" """Acquire one image from the camera and return as a PIL image."""
# Warn if the capture mode is incorrect, but don't read the cooerced value as # Warn if the capture mode is incorrect, but don't read the coerced value as
# this camera only supports one mode. # this camera only supports one mode.
self._validate_capture_mode(capture_mode) self._validate_capture_mode(capture_mode)
return Image.fromarray(self.capture_as_array()) return Image.fromarray(self.capture_as_array())

View file

@ -536,8 +536,8 @@ class StreamingPiCamera2(BaseCamera, ABC):
If the camera is already in the correct mode, the stream isn't paused and If the camera is already in the correct mode, the stream isn't paused and
this is the same as using ``self._streaming_picamera()``. this is the same as using ``self._streaming_picamera()``.
Otherwise, pause stream, and switch switch mode. Mode is reset and stream Otherwise, pause stream, and switch mode. Mode is reset and stream
restarts stream after the context manager closes. restarts after the context manager closes.
""" """
required_streaming_mode = capture_mode_info.streaming_mode required_streaming_mode = capture_mode_info.streaming_mode
if ( if (
@ -568,7 +568,7 @@ class StreamingPiCamera2(BaseCamera, ABC):
"""Acquire one image from the camera and return it as a PIL Image. """Acquire one image from the camera and return it as a PIL Image.
:param capture_mode: The capture mode to use. See the description field of each :param capture_mode: The capture mode to use. See the description field of each
mode for more detail in ``capture_modes`` for more detail. mode in ``capture_modes`` for more detail.
:raises TimeoutError: if this time is exceeded during capture. :raises TimeoutError: if this time is exceeded during capture.
""" """
@ -594,13 +594,13 @@ class StreamingPiCamera2(BaseCamera, ABC):
:param capture_mode: (Optional) The name of the capture mode as defined by the :param capture_mode: (Optional) The name of the capture mode as defined by the
camera. camera.
:param raw: Whether to capture RAW data. Capturing RAW data may infore some :param raw: Whether to capture RAW data. Capturing RAW data may ignore some
of the camera mode settings. of the camera mode settings.
:raises TimeoutError: if this time is exceeded during capture. :raises TimeoutError: if this time is exceeded during capture.
""" """
if raw: if raw:
# Raw cannot used _capture_image. # Raw cannot use _capture_image.
capture_mode = self._validate_capture_mode(capture_mode) capture_mode = self._validate_capture_mode(capture_mode)
capture_mode_info = self.capture_modes[capture_mode] capture_mode_info = self.capture_modes[capture_mode]

View file

@ -496,10 +496,8 @@ class SimulatedCamera(BaseCamera):
Setting this to True will result in an error. Setting this to True will result in an error.
""" """
if raw is True: if raw is True:
raise NotImplementedError( raise NotImplementedError("Simulation camera doesn't support raw capture.")
"Simulation camera camera doesn't support raw capture." # Warn if the capture mode is incorrect, but don't read the coerced value as
)
# Warn if the capture mode is incorrect, but don't read the cooerced value as
# this camera only supports one mode. # this camera only supports one mode.
self._validate_capture_mode(capture_mode) self._validate_capture_mode(capture_mode)
return np.array(self.generate_frame()) return np.array(self.generate_frame())
@ -509,7 +507,7 @@ class SimulatedCamera(BaseCamera):
It is used for capture to memory. It is used for capture to memory.
""" """
# Warn if the capture mode is incorrect, but don't read the cooerced value as # Warn if the capture mode is incorrect, but don't read the coerced value as
# this camera only supports one mode. # this camera only supports one mode.
self._validate_capture_mode(capture_mode) self._validate_capture_mode(capture_mode)
return self.generate_frame() return self.generate_frame()

View file

@ -129,7 +129,7 @@ class ScanWorkflow(Generic[SettingModelType], lt.Thing):
"""Return the save resolution as determined by a test image.""" """Return the save resolution as determined by a test image."""
# Capture an example image. # Capture an example image.
image = self._cam._capture_image(capture_mode=self.capture_mode) image = self._cam._capture_image(capture_mode=self.capture_mode)
# Check side to create a unit faction for downsampling. # Check size to create a unit faction for downsampling.
return image.size return image.size
def pre_scan_routine(self, settings: SettingModelType) -> None: def pre_scan_routine(self, settings: SettingModelType) -> None:

View file

@ -52,9 +52,9 @@ def test_format(picamera_client):
image_format="png", image_format="png",
retain_image=True, retain_image=True,
) )
jpeg_capture = Image.open(blob.open()) png_capture = Image.open(blob.open())
jpeg_capture.verify() png_capture.verify()
assert jpeg_capture.format == "PNG" assert png_capture.format == "PNG"
def test_standard_capture_size(picamera_client): def test_standard_capture_size(picamera_client):

View file

@ -53,7 +53,7 @@ def test_grab_jpeg(simulation_test_env):
def test_capture_and_metadata(simulation_test_env, image_format, caplog): def test_capture_and_metadata(simulation_test_env, image_format, caplog):
"""Capture an image and check a attributes. """Capture an image and check a attributes.
- Check that the position is encoded into the image metadata. - Check that the position is encoded into the image metadata
- Check the dimensions - Check the dimensions
- Check the format - Check the format
""" """

View file

@ -86,7 +86,7 @@ class MemorySaveTestCase:
SAVE_TEST_CASES = [ SAVE_TEST_CASES = [
# Default test case is a jpeg, ckec it works with all extensions. # Default test case is a jpeg, check it works with all extensions.
MemorySaveTestCase("foobar.jpeg"), MemorySaveTestCase("foobar.jpeg"),
MemorySaveTestCase("foobar.jpg"), MemorySaveTestCase("foobar.jpg"),
MemorySaveTestCase("foobar.JPEG"), MemorySaveTestCase("foobar.JPEG"),
@ -103,7 +103,7 @@ SAVE_TEST_CASES = [
@pytest.mark.parametrize("test_case", SAVE_TEST_CASES) @pytest.mark.parametrize("test_case", SAVE_TEST_CASES)
def test_save_from_memory(test_case, test_env, mocker): def test_save_from_memory(test_case, test_env, mocker):
"""Check the correct timage is retrieved and saved with correct settings.""" """Check the correct image is retrieved and saved with correct settings."""
camera = test_env.get_thing_by_type(SimulatedCamera) camera = test_env.get_thing_by_type(SimulatedCamera)
camera._memory_buffer = mocker.Mock() camera._memory_buffer = mocker.Mock()
camera._add_metadata_to_capture = mocker.Mock() camera._add_metadata_to_capture = mocker.Mock()

View file

@ -90,7 +90,7 @@ def test_get_two_images():
) )
returned_image1, _, _ = mem_buf.get_image(buffer_id1) returned_image1, _, _ = mem_buf.get_image(buffer_id1)
returned_image2, _, _ = mem_buf.get_image(buffer_id2) returned_image2, _, _ = mem_buf.get_image(buffer_id2)
# It they the same images # Assert they are the same images
assert misc_image1 is returned_image1 assert misc_image1 is returned_image1
assert misc_image2 is returned_image2 assert misc_image2 is returned_image2
# They are removed from memory # They are removed from memory
@ -134,7 +134,7 @@ def test_buffer_size_changing():
with pytest.raises(NoImageInMemoryError): with pytest.raises(NoImageInMemoryError):
mem_buf.get_image(buffer_id2) mem_buf.get_image(buffer_id2)
returned_image3, _, _ = mem_buf.get_image(buffer_id3) returned_image3, _, _ = mem_buf.get_image(buffer_id3)
# Image 3 the expected image # Image 3 is the expected image
assert misc_image3 is returned_image3 assert misc_image3 is returned_image3
@ -226,7 +226,7 @@ def test_get_metadata_too():
def test_mode_is_returned(): def test_mode_is_returned():
"""Capture 10 images with metadata and check metadata is returned as expected.""" """Check that the correct mode name is returned with the image from the buffer."""
mem_buf = CameraMemoryBuffer() mem_buf = CameraMemoryBuffer()
misc_image = random_image() misc_image = random_image()
buffer_id = mem_buf.add_image(misc_image, random_metadata(), "standard") buffer_id = mem_buf.add_image(misc_image, random_metadata(), "standard")

View file

@ -92,7 +92,7 @@ def test_saving_thing_propagates_on_join():
path2 = path.join("bar") path2 = path.join("bar")
assert not path2.save_location_set assert not path2.save_location_set
# Set thing and check joiend path is as expected # Set thing and check joined path is as expected
path2.set_saving_thing(thing) path2.set_saving_thing(thing)
assert path2.save_location_set assert path2.save_location_set
assert path2.abs_data_path == os.path.join("data", "thing", "foo", "bar") assert path2.abs_data_path == os.path.join("data", "thing", "foo", "bar")