Handle captures as an OrderedDict. Fixes file deletion

This commit is contained in:
Joel Collins 2020-03-01 17:57:30 +00:00
parent 7235445cf2
commit 60c6ae72f8
4 changed files with 34 additions and 24 deletions

View file

@ -81,8 +81,7 @@ class ZipManager:
# Get array of captures from IDs # Get array of captures from IDs
capture_list = [ capture_list = [
microscope.camera.image_from_id(capture_id) microscope.camera.images.get(capture_id) for capture_id in capture_id_list
for capture_id in capture_id_list
] ]
# Remove Nones from list (missing/invalid captures) # Remove Nones from list (missing/invalid captures)
capture_list = [capture for capture in capture_list if capture] capture_list = [capture for capture in capture_list if capture]

View file

@ -20,6 +20,7 @@ class InstrumentSchema(Schema):
settings = fields.Dict() settings = fields.Dict()
state = fields.Dict() state = fields.Dict()
class CaptureMetadataImageSchema(Schema): class CaptureMetadataImageSchema(Schema):
id = fields.UUID() id = fields.UUID()
acquisitionDate = fields.String(format="date") acquisitionDate = fields.String(format="date")
@ -36,6 +37,7 @@ class CaptureMetadataSchema(Schema):
image = fields.Nested(CaptureMetadataImageSchema()) image = fields.Nested(CaptureMetadataImageSchema())
instrument = fields.Nested(InstrumentSchema()) instrument = fields.Nested(InstrumentSchema())
class CaptureSchema(Schema): class CaptureSchema(Schema):
id = fields.String() id = fields.String()
file = fields.String( file = fields.String(
@ -98,7 +100,7 @@ class CaptureList(View):
List all image captures List all image captures
""" """
microscope = find_component("org.openflexure.microscope") microscope = find_component("org.openflexure.microscope")
image_list = microscope.camera.images image_list = microscope.camera.images.values()
return image_list return image_list
@ -110,7 +112,7 @@ class CaptureView(View):
Description of a single image capture Description of a single image capture
""" """
microscope = find_component("org.openflexure.microscope") 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: if not capture_obj:
return abort(404) # 404 Not Found return abort(404) # 404 Not Found
@ -122,12 +124,15 @@ class CaptureView(View):
Delete a single image capture Delete a single image capture
""" """
microscope = find_component("org.openflexure.microscope") 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: if not capture_obj:
return abort(404) # 404 Not Found return abort(404) # 404 Not Found
# Delete the capture file
capture_obj.delete() capture_obj.delete()
# Delete from capture list
del microscope.camera.images[id]
return "", 204 return "", 204
@ -140,7 +145,7 @@ class CaptureDownload(View):
Image data for a single image capture Image data for a single image capture
""" """
microscope = find_component("org.openflexure.microscope") 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: if not capture_obj:
return abort(404) # 404 Not Found return abort(404) # 404 Not Found
@ -175,7 +180,7 @@ class CaptureTags(View):
Get tags associated with a single image capture Get tags associated with a single image capture
""" """
microscope = find_component("org.openflexure.microscope") 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: if not capture_obj:
return abort(404) # 404 Not Found return abort(404) # 404 Not Found
@ -187,7 +192,7 @@ class CaptureTags(View):
Add tags to a single image capture Add tags to a single image capture
""" """
microscope = find_component("org.openflexure.microscope") 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: if not capture_obj:
return abort(404) # 404 Not Found return abort(404) # 404 Not Found
@ -207,7 +212,7 @@ class CaptureTags(View):
Delete tags from a single image capture Delete tags from a single image capture
""" """
microscope = find_component("org.openflexure.microscope") 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: if not capture_obj:
return abort(404) # 404 Not Found return abort(404) # 404 Not Found
@ -230,7 +235,7 @@ class CaptureAnnotations(View):
Get annotations associated with a single image capture Get annotations associated with a single image capture
""" """
microscope = find_component("org.openflexure.microscope") 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: if not capture_obj:
return abort(404) # 404 Not Found return abort(404) # 404 Not Found
@ -242,7 +247,7 @@ class CaptureAnnotations(View):
Update metadata for a single image capture Update metadata for a single image capture
""" """
microscope = find_component("org.openflexure.microscope") 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: if not capture_obj:
return abort(404) # 404 Not Found return abort(404) # 404 Not Found

View file

@ -7,6 +7,7 @@ import datetime
import logging import logging
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from collections import OrderedDict
from .capture import CaptureObject, build_captures_from_exif from .capture import CaptureObject, build_captures_from_exif
from openflexure_microscope.utilities import entry_by_uuid 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} self.paths = {"default": BASE_CAPTURE_PATH, "temp": TEMP_CAPTURE_PATH}
# Capture data # Capture data
self.images = [] self.images = OrderedDict()
self.videos = [] self.videos = OrderedDict()
@property @property
@abstractmethod @abstractmethod
@ -158,7 +159,7 @@ class BaseCamera(metaclass=ABCMeta):
"""Close the BaseCamera and all attached StreamObjects.""" """Close the BaseCamera and all attached StreamObjects."""
logging.info("Closing {}".format(self)) logging.info("Closing {}".format(self))
# Close all StreamObjects # 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: for stream_object in capture_list:
stream_object.close() stream_object.close()
# Empty temp directory # Empty temp directory
@ -244,20 +245,22 @@ class BaseCamera(metaclass=ABCMeta):
@property @property
def image(self): def image(self):
"""Return the latest captured image.""" """Return the latest captured image."""
return last_entry(self.images) return last_entry(self.images.values())
@property @property
def video(self): def video(self):
"""Return the latest recorded video.""" """Return the latest recorded video."""
return last_entry(self.videos) return last_entry(self.videos.values())
def image_from_id(self, image_id): def image_from_id(self, image_id):
"""Return an image StreamObject with a matching 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): def video_from_id(self, video_id):
"""Return a video StreamObject with a matching 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 # CREATING NEW CAPTURES
@ -282,7 +285,7 @@ class BaseCamera(metaclass=ABCMeta):
# Generate file name # Generate file name
if not filename: if not filename:
filename = generate_numbered_basename(self.images) filename = generate_numbered_basename(self.images.values())
logging.debug(filename) logging.debug(filename)
filename = "{}.{}".format(filename, fmt) filename = "{}.{}".format(filename, fmt)
@ -300,7 +303,7 @@ class BaseCamera(metaclass=ABCMeta):
output.put_tags(["temporary"]) output.put_tags(["temporary"])
# Update capture list # Update capture list
self.images.append(output) self.images[output.id] = output
return output return output
@ -322,10 +325,11 @@ class BaseCamera(metaclass=ABCMeta):
folder (str): Name of the folder in which to store the capture. folder (str): Name of the folder in which to store the capture.
fmt (str): Format of the capture. fmt (str): Format of the capture.
""" """
# TODO: Remove the redundancy here
# Generate file name # Generate file name
if not filename: if not filename:
filename = generate_numbered_basename(self.videos) filename = generate_numbered_basename(self.videos.values())
logging.debug(filename) logging.debug(filename)
filename = "{}.{}".format(filename, fmt) filename = "{}.{}".format(filename, fmt)
@ -343,7 +347,7 @@ class BaseCamera(metaclass=ABCMeta):
output.put_tags(["temporary"]) output.put_tags(["temporary"])
# Update capture list # Update capture list
self.videos.append(output) self.videos[output.id] = output
return output return output

View file

@ -10,6 +10,8 @@ from PIL import Image
import dateutil.parser import dateutil.parser
import atexit import atexit
from collections import OrderedDict
from openflexure_microscope.camera import piexif from openflexure_microscope.camera import piexif
from openflexure_microscope.camera.piexif._exceptions import InvalidImageDataError from openflexure_microscope.camera.piexif._exceptions import InvalidImageDataError
from openflexure_microscope.config import JSONEncoder 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)) logging.debug("Reloading captures from {}...".format(capture_path))
files = make_file_list(capture_path, EXIF_FORMATS) files = make_file_list(capture_path, EXIF_FORMATS)
captures = [] captures = OrderedDict()
for f in files: for f in files:
logging.debug("Reloading capture {}...".format(f)) logging.debug("Reloading capture {}...".format(f))
@ -66,7 +68,7 @@ def build_captures_from_exif(capture_path):
if exif: if exif:
capture = capture_from_exif(f, exif) capture = capture_from_exif(f, exif)
if capture: if capture:
captures.append(capture) captures[capture.id] = capture
else: else:
logging.error("Invalid data at {}. Skipping.".format(f)) logging.error("Invalid data at {}. Skipping.".format(f))