From 60c6ae72f8a7fb52b87b0c22593e2db2c225292e Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Sun, 1 Mar 2020 17:57:30 +0000 Subject: [PATCH] Handle captures as an OrderedDict. Fixes file deletion --- .../api/default_extensions/zip_builder.py | 3 +-- .../api/v2/views/captures.py | 23 +++++++++------- openflexure_microscope/camera/base.py | 26 +++++++++++-------- openflexure_microscope/camera/capture.py | 6 +++-- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/openflexure_microscope/api/default_extensions/zip_builder.py b/openflexure_microscope/api/default_extensions/zip_builder.py index 3b4840f0..22375a1e 100644 --- a/openflexure_microscope/api/default_extensions/zip_builder.py +++ b/openflexure_microscope/api/default_extensions/zip_builder.py @@ -81,8 +81,7 @@ class ZipManager: # Get array of captures from IDs capture_list = [ - microscope.camera.image_from_id(capture_id) - for capture_id in capture_id_list + microscope.camera.images.get(capture_id) for capture_id in capture_id_list ] # Remove Nones from list (missing/invalid captures) capture_list = [capture for capture in capture_list if capture] diff --git a/openflexure_microscope/api/v2/views/captures.py b/openflexure_microscope/api/v2/views/captures.py index f52a7ed0..27a4a636 100644 --- a/openflexure_microscope/api/v2/views/captures.py +++ b/openflexure_microscope/api/v2/views/captures.py @@ -20,6 +20,7 @@ class InstrumentSchema(Schema): settings = fields.Dict() state = fields.Dict() + class CaptureMetadataImageSchema(Schema): id = fields.UUID() acquisitionDate = fields.String(format="date") @@ -36,6 +37,7 @@ class CaptureMetadataSchema(Schema): image = fields.Nested(CaptureMetadataImageSchema()) instrument = fields.Nested(InstrumentSchema()) + class CaptureSchema(Schema): id = fields.String() file = fields.String( @@ -98,7 +100,7 @@ class CaptureList(View): List all image captures """ microscope = find_component("org.openflexure.microscope") - image_list = microscope.camera.images + image_list = microscope.camera.images.values() return image_list @@ -110,7 +112,7 @@ class CaptureView(View): Description of a single image capture """ microscope = find_component("org.openflexure.microscope") - capture_obj = microscope.camera.image_from_id(id) + capture_obj = microscope.camera.images.get(id) if not capture_obj: return abort(404) # 404 Not Found @@ -122,12 +124,15 @@ class CaptureView(View): Delete a single image capture """ microscope = find_component("org.openflexure.microscope") - capture_obj = microscope.camera.image_from_id(id) + capture_obj = microscope.camera.images.get(id) if not capture_obj: return abort(404) # 404 Not Found + # Delete the capture file capture_obj.delete() + # Delete from capture list + del microscope.camera.images[id] return "", 204 @@ -140,7 +145,7 @@ class CaptureDownload(View): Image data for a single image capture """ microscope = find_component("org.openflexure.microscope") - capture_obj = microscope.camera.image_from_id(id) + capture_obj = microscope.camera.images.get(id) if not capture_obj: return abort(404) # 404 Not Found @@ -175,7 +180,7 @@ class CaptureTags(View): Get tags associated with a single image capture """ microscope = find_component("org.openflexure.microscope") - capture_obj = microscope.camera.image_from_id(id) + capture_obj = microscope.camera.images.get(id) if not capture_obj: return abort(404) # 404 Not Found @@ -187,7 +192,7 @@ class CaptureTags(View): Add tags to a single image capture """ microscope = find_component("org.openflexure.microscope") - capture_obj = microscope.camera.image_from_id(id) + capture_obj = microscope.camera.images.get(id) if not capture_obj: return abort(404) # 404 Not Found @@ -207,7 +212,7 @@ class CaptureTags(View): Delete tags from a single image capture """ microscope = find_component("org.openflexure.microscope") - capture_obj = microscope.camera.image_from_id(id) + capture_obj = microscope.camera.images.get(id) if not capture_obj: return abort(404) # 404 Not Found @@ -230,7 +235,7 @@ class CaptureAnnotations(View): Get annotations associated with a single image capture """ microscope = find_component("org.openflexure.microscope") - capture_obj = microscope.camera.image_from_id(id) + capture_obj = microscope.camera.images.get(id) if not capture_obj: return abort(404) # 404 Not Found @@ -242,7 +247,7 @@ class CaptureAnnotations(View): Update metadata for a single image capture """ microscope = find_component("org.openflexure.microscope") - capture_obj = microscope.camera.image_from_id(id) + capture_obj = microscope.camera.images.get(id) if not capture_obj: return abort(404) # 404 Not Found diff --git a/openflexure_microscope/camera/base.py b/openflexure_microscope/camera/base.py index edd55dca..41b43254 100644 --- a/openflexure_microscope/camera/base.py +++ b/openflexure_microscope/camera/base.py @@ -7,6 +7,7 @@ import datetime import logging from abc import ABCMeta, abstractmethod +from collections import OrderedDict from .capture import CaptureObject, build_captures_from_exif from openflexure_microscope.utilities import entry_by_uuid @@ -113,8 +114,8 @@ class BaseCamera(metaclass=ABCMeta): self.paths = {"default": BASE_CAPTURE_PATH, "temp": TEMP_CAPTURE_PATH} # Capture data - self.images = [] - self.videos = [] + self.images = OrderedDict() + self.videos = OrderedDict() @property @abstractmethod @@ -158,7 +159,7 @@ class BaseCamera(metaclass=ABCMeta): """Close the BaseCamera and all attached StreamObjects.""" logging.info("Closing {}".format(self)) # Close all StreamObjects - for capture_list in [self.images, self.videos]: + for capture_list in [self.images.values(), self.videos.values()]: for stream_object in capture_list: stream_object.close() # Empty temp directory @@ -244,20 +245,22 @@ class BaseCamera(metaclass=ABCMeta): @property def image(self): """Return the latest captured image.""" - return last_entry(self.images) + return last_entry(self.images.values()) @property def video(self): """Return the latest recorded video.""" - return last_entry(self.videos) + return last_entry(self.videos.values()) def image_from_id(self, image_id): """Return an image StreamObject with a matching ID.""" - return entry_by_uuid(image_id, self.images) + logging.warning("image_from_id is deprecated. Access captures as a dictionary.") + return entry_by_uuid(image_id, self.images.values()) def video_from_id(self, video_id): """Return a video StreamObject with a matching ID.""" - return entry_by_uuid(video_id, self.videos) + logging.warning("video_from_id is deprecated. Access captures as a dictionary.") + return entry_by_uuid(video_id, self.videos.values()) # CREATING NEW CAPTURES @@ -282,7 +285,7 @@ class BaseCamera(metaclass=ABCMeta): # Generate file name if not filename: - filename = generate_numbered_basename(self.images) + filename = generate_numbered_basename(self.images.values()) logging.debug(filename) filename = "{}.{}".format(filename, fmt) @@ -300,7 +303,7 @@ class BaseCamera(metaclass=ABCMeta): output.put_tags(["temporary"]) # Update capture list - self.images.append(output) + self.images[output.id] = output return output @@ -322,10 +325,11 @@ class BaseCamera(metaclass=ABCMeta): folder (str): Name of the folder in which to store the capture. fmt (str): Format of the capture. """ + # TODO: Remove the redundancy here # Generate file name if not filename: - filename = generate_numbered_basename(self.videos) + filename = generate_numbered_basename(self.videos.values()) logging.debug(filename) filename = "{}.{}".format(filename, fmt) @@ -343,7 +347,7 @@ class BaseCamera(metaclass=ABCMeta): output.put_tags(["temporary"]) # Update capture list - self.videos.append(output) + self.videos[output.id] = output return output diff --git a/openflexure_microscope/camera/capture.py b/openflexure_microscope/camera/capture.py index 0f190c58..071a52c8 100644 --- a/openflexure_microscope/camera/capture.py +++ b/openflexure_microscope/camera/capture.py @@ -10,6 +10,8 @@ from PIL import Image import dateutil.parser import atexit +from collections import OrderedDict + from openflexure_microscope.camera import piexif from openflexure_microscope.camera.piexif._exceptions import InvalidImageDataError from openflexure_microscope.config import JSONEncoder @@ -58,7 +60,7 @@ def build_captures_from_exif(capture_path): logging.debug("Reloading captures from {}...".format(capture_path)) files = make_file_list(capture_path, EXIF_FORMATS) - captures = [] + captures = OrderedDict() for f in files: logging.debug("Reloading capture {}...".format(f)) @@ -66,7 +68,7 @@ def build_captures_from_exif(capture_path): if exif: capture = capture_from_exif(f, exif) if capture: - captures.append(capture) + captures[capture.id] = capture else: logging.error("Invalid data at {}. Skipping.".format(f))