Merge remote-tracking branch 'origin/master' into labthings-070

This commit is contained in:
Joel Collins 2020-07-03 18:13:20 +01:00
commit ab3c4b3745
7 changed files with 140 additions and 111 deletions

View file

@ -6,8 +6,7 @@ import logging
import pkg_resources
import uuid
from typing import Tuple
import gevent
from expiringdict import ExpiringDict
from openflexure_microscope.captures import CaptureManager
@ -61,6 +60,10 @@ class Microscope:
# Apply settings loaded from file
self.update_settings(self.settings_file.load())
# Data cache
self.configuration_cache = ExpiringDict(max_len=100, max_age_seconds=3600)
self.metadata_cache = ExpiringDict(max_len=100, max_age_seconds=3600)
def __enter__(self):
"""Create microscope on context enter."""
return self
@ -237,8 +240,7 @@ class Microscope:
# Save config to file
self.settings_file.save(current_config, backup=True)
@property
def configuration(self):
def force_get_configuration(self):
with self.lock:
initial_configuration = self.configuration_file.load()
@ -262,37 +264,62 @@ class Microscope:
initial_configuration.update(current_configuration)
return initial_configuration
def get_configuration(self, cache_key=None):
if cache_key:
cached_config = self.configuration_cache.get(cache_key, None)
if cached_config:
return cached_config
else:
full_config = self.force_get_configuration()
self.configuration_cache[cache_key] = full_config
return full_config
return self.force_get_configuration()
@property
def metadata(self):
def configuration(self):
return self.get_configuration()
def force_get_metadata(self):
"""
Microscope system metadata, to be applied to basically all captures
Read cachable bits of microscope metadata.
Currently ID, settings, and configuration can be cached
"""
with Timer("Reading settings:"):
settings = self.read_settings(full=False)
with Timer("Reading state:"):
state = self.state
with Timer("Reading configuration:"):
configuration = self.configuration
system_metadata = {
"id": self.id,
"settings": settings,
"state": state,
"configuration": configuration,
"settings": self.read_settings(full=False),
"configuration": self.get_configuration(),
}
return system_metadata
def add_metadata_to_capture(self, output, metadata, annotations, tags):
logging.debug(f"Waiting for {output.file}")
# Wait for the file to be written to disk
with Timer("Waiting for file:"):
output.file_ready.wait()
def get_metadata(self, cache_key=None):
"""
Read microscope metadata, with partial caching
"""
metadata = {}
# Load cached bits of metadata
if cache_key:
logging.debug(f"Reading cached microscope metadata: {cache_key}")
metadata = self.metadata_cache.get(cache_key, None)
if not metadata:
logging.debug(f"Building and caching microscope metadata: {cache_key}")
metadata = self.force_get_metadata()
self.metadata_cache[cache_key] = metadata
else:
logging.debug(f"Building microscope metadata: {cache_key}")
metadata = self.force_get_metadata()
with Timer("Building metadata"):
full_metadata = {"instrument": self.metadata, **metadata}
with Timer("Writing metadata to file"):
output.put_and_save(tags, annotations, full_metadata)
logging.info(f"Finished injecting EXIF data into {output.file}")
# Keys that should never be cached
metadata.update({
"state": self.state,
})
return metadata
@property
def metadata(self):
return self.get_metadata()
def capture(
self,
@ -306,6 +333,7 @@ class Microscope:
annotations: dict = None,
tags: list = None,
metadata: dict = None,
cache_key: str = None
):
logging.debug(f"Microscope capturing to {filename}")
if not annotations:
@ -315,6 +343,10 @@ class Microscope:
if not tags:
tags = []
# Read metadata for capture
full_metadata = {"instrument": self.get_metadata(cache_key), **metadata}
# Do capture
with self.camera.lock:
# Create output object
output = self.captures.new_image(
@ -322,7 +354,7 @@ class Microscope:
)
# Capture to output object
logging.info("Starting microscope capture...")
logging.info(f"Starting microscope capture {filename}")
self.camera.capture(
output,
use_video_port=use_video_port,
@ -331,11 +363,7 @@ class Microscope:
fmt=fmt,
)
# Gether metadata from hardware in a greenlet
#gevent.get_hub().threadpool.spawn(self.add_metadata_to_capture, output, metadata, annotations, tags)
gevent.spawn(self.add_metadata_to_capture, output, metadata, annotations, tags)
#self.add_metadata_to_capture(output, metadata, annotations, tags)
logging.info(f"Finished capture to {output.file}")
output.put_and_save(tags, annotations, full_metadata)
logging.debug(f"Finished capture to {output.file}")
return output