Blackened files

This commit is contained in:
Joel Collins 2019-11-06 22:07:16 +00:00
parent be5ddb76ae
commit 4e7606aa0c
24 changed files with 200 additions and 120 deletions

View file

@ -61,9 +61,7 @@ class MyPluginClass(MicroscopePlugin):
for _ in range(n_images): for _ in range(n_images):
# Create a data stream to capture to # Create a data stream to capture to
output = self.microscope.camera.new_image( output = self.microscope.camera.new_image(temporary=False)
temporary=False
)
# Capture a still image from the Pi camera, into the data stream # Capture a still image from the Pi camera, into the data stream
self.microscope.camera.capture(output.file, use_video_port=True) self.microscope.camera.capture(output.file, use_video_port=True)

View file

@ -39,10 +39,8 @@ class SnapshotAPI(MicroscopeView):
# Restart stream worker thread # Restart stream worker thread
self.microscope.camera.start_worker() self.microscope.camera.start_worker()
return Response( return Response(self.microscope.camera.get_frame(), mimetype="image/jpeg")
self.microscope.camera.get_frame(),
mimetype="image/jpeg",
)
class StateAPI(MicroscopeView): class StateAPI(MicroscopeView):
def get(self): def get(self):
@ -240,7 +238,8 @@ def construct_blueprint(microscope_obj):
) )
blueprint.add_url_rule( blueprint.add_url_rule(
"/snapshot", view_func=SnapshotAPI.as_view("snapshot", microscope=microscope_obj) "/snapshot",
view_func=SnapshotAPI.as_view("snapshot", microscope=microscope_obj),
) )
blueprint.add_url_rule( blueprint.add_url_rule(

View file

@ -134,12 +134,8 @@ def construct_blueprint(microscope_obj):
blueprint = Blueprint("task_blueprint", __name__) blueprint = Blueprint("task_blueprint", __name__)
blueprint.add_url_rule( blueprint.add_url_rule("/", view_func=TaskListAPI.as_view("task_list"))
"/", view_func=TaskListAPI.as_view("task_list")
)
blueprint.add_url_rule( blueprint.add_url_rule("/<task_id>/", view_func=TaskAPI.as_view("task"))
"/<task_id>/", view_func=TaskAPI.as_view("task")
)
return blueprint return blueprint

View file

@ -120,15 +120,10 @@ class BaseCamera(metaclass=ABCMeta):
self.stream_timeout = 20 self.stream_timeout = 20
self.stream_timeout_enabled = False self.stream_timeout_enabled = False
self.state = { self.state = {"board": None}
"board": None
}
# TODO: Load/save these to config # TODO: Load/save these to config
self.paths = { self.paths = {"default": BASE_CAPTURE_PATH, "temp": TEMP_CAPTURE_PATH}
"default": BASE_CAPTURE_PATH,
"temp": TEMP_CAPTURE_PATH
}
# Capture data # Capture data
self.images = [] self.images = []
@ -296,7 +291,7 @@ class BaseCamera(metaclass=ABCMeta):
output = CaptureObject(filepath=filepath) output = CaptureObject(filepath=filepath)
# Insert a temporary tag if temporary # Insert a temporary tag if temporary
if temporary: if temporary:
output.put_tags(['temporary']) output.put_tags(["temporary"])
# Update capture list # Update capture list
self.images.append(output) self.images.append(output)
@ -339,7 +334,7 @@ class BaseCamera(metaclass=ABCMeta):
output = CaptureObject(filepath=filepath) output = CaptureObject(filepath=filepath)
# Insert a temporary tag if temporary # Insert a temporary tag if temporary
if temporary: if temporary:
output.put_tags(['temporary']) output.put_tags(["temporary"])
# Update capture list # Update capture list
self.videos.append(output) self.videos.append(output)

View file

@ -27,7 +27,7 @@ def pull_usercomment_dict(filepath):
try: try:
exif_dict = piexif.load(filepath) exif_dict = piexif.load(filepath)
except InvalidImageDataError: except InvalidImageDataError:
logging.error("Invalid data at {}. Skipping.".format(filepath)) logging.warning("Invalid data at {}. Skipping.".format(filepath))
return None return None
if "Exif" in exif_dict and 37510 in exif_dict["Exif"]: if "Exif" in exif_dict and 37510 in exif_dict["Exif"]:
return yaml.load(exif_dict["Exif"][37510].decode()) return yaml.load(exif_dict["Exif"][37510].decode())

View file

@ -16,7 +16,7 @@ import logging
# Type hinting # Type hinting
from typing import Tuple from typing import Tuple
from .base import BaseCamera, CaptureObject from openflexure_microscope.camera.base import BaseCamera
# MAIN CLASS # MAIN CLASS
@ -26,11 +26,9 @@ class MockStreamer(BaseCamera):
BaseCamera.__init__(self) BaseCamera.__init__(self)
# Store state of PiCameraStreamer # Store state of PiCameraStreamer
self.state.update({ self.state.update(
"stream_active": False, {"stream_active": False, "record_active": False, "board": None}
"record_active": False, )
"board": None
})
# Update config properties # Update config properties
self.image_resolution = (1312, 976) self.image_resolution = (1312, 976)
@ -57,7 +55,12 @@ class MockStreamer(BaseCamera):
) )
draw = ImageDraw.Draw(image) draw = ImageDraw.Draw(image)
draw.text((20, 70), "Camera disconnected: {}".format(datetime.now().strftime("%d/%m/%Y, %H:%M:%S"))) draw.text(
(20, 70),
"Camera disconnected: {}".format(
datetime.now().strftime("%d/%m/%Y, %H:%M:%S")
),
)
image.save(self.stream, format="JPEG") image.save(self.stream, format="JPEG")
@ -80,12 +83,14 @@ class MockStreamer(BaseCamera):
conf_dict = BaseCamera.read_config(self) conf_dict = BaseCamera.read_config(self)
# Include device-specific config items # Include device-specific config items
conf_dict.update({ conf_dict.update(
"stream_resolution": self.stream_resolution, {
"image_resolution": self.image_resolution, "stream_resolution": self.stream_resolution,
"numpy_resolution": self.numpy_resolution, "image_resolution": self.image_resolution,
"jpeg_quality": self.jpeg_quality, "numpy_resolution": self.numpy_resolution,
}) "jpeg_quality": self.jpeg_quality,
}
)
return conf_dict return conf_dict
@ -179,7 +184,7 @@ class MockStreamer(BaseCamera):
with self.lock: with self.lock:
if isinstance(output, str): if isinstance(output, str):
output = open(output, 'wb') output = open(output, "wb")
output.write(self.stream.getvalue()) output.write(self.stream.getvalue())

View file

@ -66,12 +66,14 @@ class PiCameraStreamer(BaseCamera):
) #: :py:class:`picamera.PiCamera`: Picamera object ) #: :py:class:`picamera.PiCamera`: Picamera object
# Store state of PiCameraStreamer # Store state of PiCameraStreamer
self.state.update({ self.state.update(
"stream_active": False, {
"record_active": False, "stream_active": False,
"preview_active": False, "record_active": False,
"board": f"picamera_{self.camera.revision}", "preview_active": False,
}) "board": f"picamera_{self.camera.revision}",
}
)
# Reset variable states # Reset variable states
self.set_zoom(1.0) self.set_zoom(1.0)
@ -113,13 +115,15 @@ class PiCameraStreamer(BaseCamera):
conf_dict = BaseCamera.read_config(self) conf_dict = BaseCamera.read_config(self)
# Include device-specific config items # Include device-specific config items
conf_dict.update({ conf_dict.update(
"stream_resolution": self.stream_resolution, {
"image_resolution": self.image_resolution, "stream_resolution": self.stream_resolution,
"numpy_resolution": self.numpy_resolution, "image_resolution": self.image_resolution,
"jpeg_quality": self.jpeg_quality, "numpy_resolution": self.numpy_resolution,
"picamera_settings": {}, "jpeg_quality": self.jpeg_quality,
}) "picamera_settings": {},
}
)
# Include a subset of picamera properties # Include a subset of picamera properties
# TODO: Expand this subset so we have more metadata? # TODO: Expand this subset so we have more metadata?
@ -333,7 +337,7 @@ class PiCameraStreamer(BaseCamera):
return output return output
else: else:
logging.error( logging.warning(
"Cannot start a new recording\ "Cannot start a new recording\
until the current recording has stopped." until the current recording has stopped."
) )

View file

@ -10,5 +10,14 @@ __all__ = [
"ThreadTerminationError", "ThreadTerminationError",
] ]
from .pool import tasks, states, current_task, update_task_progress, cleanup_tasks, remove_task, update_task_data, taskify from .pool import (
tasks,
states,
current_task,
update_task_progress,
cleanup_tasks,
remove_task,
update_task_data,
taskify,
)
from .thread import ThreadTerminationError from .thread import ThreadTerminationError

View file

@ -43,6 +43,7 @@ class TaskMaster:
# Task management # Task management
def tasks(): def tasks():
""" """
Dictionary of tasks in default taskmaster Dictionary of tasks in default taskmaster
@ -62,6 +63,7 @@ def states():
global _default_task_master global _default_task_master
return _default_task_master.states return _default_task_master.states
def cleanup_tasks(): def cleanup_tasks():
global _default_task_master global _default_task_master
return _default_task_master.cleanup() return _default_task_master.cleanup()
@ -74,6 +76,7 @@ def remove_task(task_id: str):
# Operations on the current task # Operations on the current task
def current_task(): def current_task():
current_task_thread = threading.current_thread() current_task_thread = threading.current_thread()
if not isinstance(current_task_thread, TaskThread): if not isinstance(current_task_thread, TaskThread):
@ -97,6 +100,7 @@ def update_task_data(data: dict):
# Main "taskify" functions # Main "taskify" functions
def taskify(f): def taskify(f):
""" """
A decorator that wraps the passed in function A decorator that wraps the passed in function

View file

@ -11,7 +11,12 @@ from openflexure_microscope.api.v1.views import MicroscopeViewPlugin
from openflexure_microscope.api.utilities import JsonResponse from openflexure_microscope.api.utilities import JsonResponse
# Task management # Task management
from openflexure_microscope.common.tasks import current_task, update_task_progress, update_task_data, taskify from openflexure_microscope.common.tasks import (
current_task,
update_task_progress,
update_task_data,
taskify,
)
# Exceptions # Exceptions
from openflexure_microscope.exceptions import TaskDeniedException from openflexure_microscope.exceptions import TaskDeniedException

View file

@ -7,8 +7,9 @@ import pkg_resources
import uuid import uuid
from openflexure_microscope.stage.base import BaseStage from openflexure_microscope.stage.base import BaseStage
from openflexure_microscope.stage.mock import MockStage
from openflexure_microscope.camera.base import BaseCamera from openflexure_microscope.camera.base import BaseCamera
from openflexure_microscope.camera.mock import MockStreamer
from openflexure_microscope.plugins import PluginMount from openflexure_microscope.plugins import PluginMount
from openflexure_microscope.task import TaskOrchestrator from openflexure_microscope.task import TaskOrchestrator
@ -141,6 +142,22 @@ class Microscope:
logging.info("Repopulating PluginMount...") logging.info("Repopulating PluginMount...")
self.attach_plugins(self.plugin_maps) self.attach_plugins(self.plugin_maps)
def has_real_stage(self):
if hasattr(self, "stage") and not isinstance(
self.stage, MockStage
):
return True
else:
return False
def has_real_camera(self):
if hasattr(self, "camera") and not isinstance(
self.camera, MockStreamer
):
return True
else:
return False
# Create unified state # Create unified state
@property @property
def state(self): def state(self):

View file

@ -6,7 +6,7 @@ from openflexure_microscope.devel import (
JsonResponse, JsonResponse,
request, request,
jsonify, jsonify,
taskify taskify,
) )

View file

@ -4,7 +4,7 @@ from openflexure_microscope.devel import (
JsonResponse, JsonResponse,
request, request,
jsonify, jsonify,
taskify taskify,
) )
import logging import logging

View file

@ -4,7 +4,7 @@ from openflexure_microscope.devel import (
request, request,
jsonify, jsonify,
abort, abort,
taskify taskify,
) )
import logging import logging

View file

@ -1,13 +1,13 @@
import time import time
import numpy as np
from typing import Tuple from typing import Tuple
from functools import reduce
import uuid import uuid
import itertools import itertools
import logging import logging
from openflexure_microscope.camera.base import generate_basename from openflexure_microscope.camera.base import generate_basename
from openflexure_microscope.devel import MicroscopePlugin from openflexure_microscope.devel import MicroscopePlugin, update_task_progress, update_task_data
from .api import TileScanAPI from .api import TileScanAPI
@ -53,16 +53,26 @@ class ScanPlugin(MicroscopePlugin):
api_views = {"/tile": TileScanAPI} api_views = {"/tile": TileScanAPI}
def __init__(self):
self.images_to_be_captured: int = 1
update_task_data({"images_to_be_captured": self.images_to_be_captured})
@property
def progress(self):
progress = (self.images_captured_so_far / self.images_to_be_captured) * 100
logging.info(progress)
return progress
def capture( def capture(
self, self,
basename, basename,
scan_id, scan_id,
temporary: bool = False, temporary: bool = False,
use_video_port: bool = False, use_video_port: bool = False,
resize: Tuple[int, int] = None, resize: Tuple[int, int] = None,
bayer: bool = False, bayer: bool = False,
metadata: dict = {}, metadata: dict = {},
tags: list = [], tags: list = [],
): ):
# Construct a tile filename # Construct a tile filename
@ -97,21 +107,26 @@ class ScanPlugin(MicroscopePlugin):
output.put_tags(tags) output.put_tags(tags)
def tile( def tile(
self, self,
basename: str = None, basename: str = None,
temporary: bool = False, temporary: bool = False,
step_size: int = [2000, 1500, 100], step_size: int = [2000, 1500, 100],
grid: list = [3, 3, 5], grid: list = [3, 3, 5],
style="raster", style="raster",
autofocus_dz: int = 50, autofocus_dz: int = 50,
use_video_port: bool = False, use_video_port: bool = False,
resize: Tuple[int, int] = None, resize: Tuple[int, int] = None,
bayer: bool = False, bayer: bool = False,
fast_autofocus=False, fast_autofocus=False,
metadata: dict = {}, metadata: dict = {},
tags: list = [], tags: list = [],
): ):
# Keep task progress
# TODO: Make this line not nasty
self.images_to_be_captured = reduce((lambda x, y: x * y), grid)
self.images_captured_so_far = 0
# Generate a basename if none given # Generate a basename if none given
if not basename: if not basename:
basename = generate_basename() basename = generate_basename()
@ -123,19 +138,24 @@ class ScanPlugin(MicroscopePlugin):
initial_position = self.microscope.stage.position initial_position = self.microscope.stage.position
# Add scan metadata # Add scan metadata
if not "time" in metadata: if "time" not in metadata:
metadata["time"] = generate_basename() metadata["time"] = generate_basename()
# Check if autofocus is enabled # Check if autofocus is enabled
if autofocus_dz and hasattr(self.microscope.plugin, "default_autofocus"): if (
autofocus_dz
and hasattr(self.microscope.plugin, "default_autofocus")
and self.microscope.has_real_stage()
and self.microscope.has_real_camera()
):
autofocus_enabled = True autofocus_enabled = True
else: else:
autofocus_enabled = False autofocus_enabled = False
if fast_autofocus and not hasattr( if fast_autofocus and not hasattr(
self.microscope.plugin.default_autofocus, "monitor_sharpness" self.microscope.plugin.default_autofocus, "monitor_sharpness"
): ):
logging.error( logging.warning(
"Can't use fast autofocus in the scan - the default plugin doesn't support monitor_sharpness; maybe it is too old?" "Can't use fast autofocus in the scan - the default plugin doesn't support monitor_sharpness; maybe it is too old?"
) )
fast_autofocus = False fast_autofocus = False
@ -198,6 +218,9 @@ class ScanPlugin(MicroscopePlugin):
metadata=metadata, metadata=metadata,
tags=tags, tags=tags,
) )
# Update task progress
self.images_captured_so_far += 1
update_task_progress(self.progress)
else: else:
logging.debug("Entering z-stack") logging.debug("Entering z-stack")
self.stack( self.stack(
@ -218,7 +241,7 @@ class ScanPlugin(MicroscopePlugin):
next_z = self.microscope.stage.position[2] next_z = self.microscope.stage.position[2]
if fast_autofocus: if fast_autofocus:
next_z += ( next_z += (
autofocus_dz / 2 autofocus_dz / 2
) # Fast autofocus requires us to start at the top of the range ) # Fast autofocus requires us to start at the top of the range
if grid[2] > 1: if grid[2] > 1:
next_z -= int( next_z -= int(
@ -229,19 +252,19 @@ class ScanPlugin(MicroscopePlugin):
self.microscope.stage.move_abs(initial_position) self.microscope.stage.move_abs(initial_position)
def stack( def stack(
self, self,
basename: str = None, basename: str = None,
temporary: bool = False, temporary: bool = False,
scan_id: str = None, scan_id: str = None,
step_size: int = 100, step_size: int = 100,
steps: int = 5, steps: int = 5,
center: bool = True, center: bool = True,
return_to_start: bool = True, return_to_start: bool = True,
use_video_port: bool = False, use_video_port: bool = False,
resize: Tuple[int, int] = None, resize: Tuple[int, int] = None,
bayer: bool = False, bayer: bool = False,
metadata: dict = {}, metadata: dict = {},
tags: list = [], tags: list = [],
): ):
# Generate a basename if none given # Generate a basename if none given
@ -278,6 +301,9 @@ class ScanPlugin(MicroscopePlugin):
metadata=metadata, metadata=metadata,
tags=tags, tags=tags,
) )
# Update task progress
self.images_captured_so_far += 1
update_task_progress(self.progress)
if i != steps - 1: if i != steps - 1:
logging.debug("Moving z by {}".format(step_size)) logging.debug("Moving z by {}".format(step_size))

View file

@ -87,7 +87,7 @@ def load_plugin_module(plugin_path):
plugin_module = importlib.import_module(plugin_path) plugin_module = importlib.import_module(plugin_path)
plugin_name = name_from_module(plugin_path) plugin_name = name_from_module(plugin_path)
except Exception as e: except Exception as e:
logging.error("Error loading plugin.") logging.warning("Error loading plugin.")
logging.error(e) logging.error(e)
return None, None return None, None
@ -216,7 +216,7 @@ class PluginMount(object):
) )
else: else:
logging.error(f"Error loading plugin {plugin_map}. Moving on.") logging.warning(f"Error loading plugin {plugin_map}. Moving on.")
class MicroscopePlugin: class MicroscopePlugin:

View file

@ -3,7 +3,7 @@ from openflexure_microscope.devel import (
JsonResponse, JsonResponse,
request, request,
jsonify, jsonify,
taskify taskify,
) )
import logging import logging

View file

@ -72,7 +72,7 @@ class ExamplePlugin(MicroscopePlugin):
time.sleep(1) time.sleep(1)
# Update task progress (if running as a task) # Update task progress (if running as a task)
percent_complete = int(((t + 1)/run_time)*100) percent_complete = int(((t + 1) / run_time) * 100)
update_task_progress(percent_complete) update_task_progress(percent_complete)
return vals return vals

View file

@ -1,3 +1,4 @@
import numpy as np
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from openflexure_microscope.common.lock import StrictLock from openflexure_microscope.common.lock import StrictLock

View file

@ -5,6 +5,7 @@ from collections.abc import Iterable
import numpy as np import numpy as np
import time import time
class MockStage(BaseStage): class MockStage(BaseStage):
def __init__(self, port=None, **kwargs): def __init__(self, port=None, **kwargs):
BaseStage.__init__(self) BaseStage.__init__(self)
@ -68,7 +69,9 @@ class MockStage(BaseStage):
else: else:
self._backlash = np.array([int(blsh)] * self.n_axes, dtype=np.int) self._backlash = np.array([int(blsh)] * self.n_axes, dtype=np.int)
def move_rel(self, displacement: list, axis=None, backlash=True, simulate_time: bool=True): def move_rel(
self, displacement: list, axis=None, backlash=True, simulate_time: bool = True
):
if simulate_time: if simulate_time:
time.sleep(1) time.sleep(1)
if axis is not None: if axis is not None:
@ -81,7 +84,7 @@ class MockStage(BaseStage):
self._position = list(np.array(self._position) + np.array(move)) self._position = list(np.array(self._position) + np.array(move))
def move_abs(self, final, simulate_time: bool=True, **kwargs): def move_abs(self, final, simulate_time: bool = True, **kwargs):
if simulate_time: if simulate_time:
time.sleep(1) time.sleep(1)

View file

@ -136,7 +136,7 @@ class Sangaboard(ExtensibleSerialInstrument):
# make sure we close the serial port cleanly (otherwise it hangs open). # make sure we close the serial port cleanly (otherwise it hangs open).
self.close() self.close()
logging.error(e) logging.error(e)
logging.error( logging.warning(
"You may need to update the firmware running on the Sangaboard." "You may need to update the firmware running on the Sangaboard."
) )
raise e raise e
@ -164,12 +164,12 @@ class Sangaboard(ExtensibleSerialInstrument):
r"OpenFlexure Motor Board v(([\d]+)(?:\.([\d]+))+)", self.firmware r"OpenFlexure Motor Board v(([\d]+)(?:\.([\d]+))+)", self.firmware
) )
if not match: if not match:
logging.error( logging.warning(
'Version string "{}" not recognised.'.format(self.firmware) 'Version string "{}" not recognised.'.format(self.firmware)
) )
return False return False
else: else:
logging.error("No firmware version string was returned.") logging.warning("No firmware version string was returned.")
return False return False
# Check for matching/valid version number # Check for matching/valid version number
@ -179,7 +179,7 @@ class Sangaboard(ExtensibleSerialInstrument):
self.firmware_version = match.group(1) self.firmware_version = match.group(1)
if version_tuple not in Sangaboard.valid_firmwares: if version_tuple not in Sangaboard.valid_firmwares:
logging.error( logging.warning(
"This version of the Python module requires firmware v0.5 (with legacy support for v0.4)" "This version of the Python module requires firmware v0.5 (with legacy support for v0.4)"
) )
return False return False

View file

@ -1,5 +1,11 @@
import logging import logging
from openflexure_microscope.common.tasks import tasks, states, taskify, cleanup_tasks, remove_task from openflexure_microscope.common.tasks import (
tasks,
states,
taskify,
cleanup_tasks,
remove_task,
)
class TaskOrchestrator: class TaskOrchestrator:
@ -14,7 +20,9 @@ class TaskOrchestrator:
@property @property
def tasks(self): def tasks(self):
logging.warning("TaskOrchestrator class is deprecated. Please use common.tasks.tasks().values() instead.") logging.warning(
"TaskOrchestrator class is deprecated. Please use common.tasks.tasks().values() instead."
)
return tasks().values() return tasks().values()
@property @property
@ -22,7 +30,9 @@ class TaskOrchestrator:
""" """
Returns a list of dictionary representations of all tasks in the session. Returns a list of dictionary representations of all tasks in the session.
""" """
logging.warning("TaskOrchestrator class is deprecated. Please use common.tasks.tasks() instead.") logging.warning(
"TaskOrchestrator class is deprecated. Please use common.tasks.tasks() instead."
)
return states() return states()
def task_from_id(self, task_id: str): def task_from_id(self, task_id: str):
@ -41,7 +51,9 @@ class TaskOrchestrator:
function (function): The target function to run in the background function (function): The target function to run in the background
args, kwargs: Arguments that will be passed to `function` at runtime. args, kwargs: Arguments that will be passed to `function` at runtime.
""" """
logging.warning("TaskOrchestrator class is deprecated. Please use common.tasks.taskify() instead.") logging.warning(
"TaskOrchestrator class is deprecated. Please use common.tasks.taskify() instead."
)
return taskify(function)(*args, **kwargs) return taskify(function)(*args, **kwargs)
def clean(self): def clean(self):
@ -49,12 +61,16 @@ class TaskOrchestrator:
Remove all inactive tasks from the task array. Remove all inactive tasks from the task array.
This will remove tasks that either finished or never started. This will remove tasks that either finished or never started.
""" """
logging.warning("TaskOrchestrator class is deprecated. Please use common.tasks.cleanup_tasks() instead.") logging.warning(
"TaskOrchestrator class is deprecated. Please use common.tasks.cleanup_tasks() instead."
)
cleanup_tasks() cleanup_tasks()
def delete(self, task_id: str): def delete(self, task_id: str):
""" """
Delete a given task by ID, only if task is not currently running. Delete a given task by ID, only if task is not currently running.
""" """
logging.warning("TaskOrchestrator class is deprecated. Please use common.tasks.remove_task() instead.") logging.warning(
"TaskOrchestrator class is deprecated. Please use common.tasks.remove_task() instead."
)
remove_task(task_id) remove_task(task_id)

View file

@ -30,7 +30,9 @@ class TestCaptureMethods(unittest.TestCase):
# Capture to a context (auto-deletes files when done) # Capture to a context (auto-deletes files when done)
with camera.new_image() as output: with camera.new_image() as output:
camera.capture(output.file, use_video_port=use_video_port, resize=resize) camera.capture(
output.file, use_video_port=use_video_port, resize=resize
)
# Ensure file deletion fails and returns False # Ensure file deletion fails and returns False
self.assertFalse(output.delete_file()) self.assertFalse(output.delete_file())