Code cleanup

This commit is contained in:
Joel Collins 2020-10-14 14:56:29 +00:00
parent 2bfb988460
commit 994e83dbeb
46 changed files with 261 additions and 318 deletions

View file

@ -21,7 +21,7 @@ import os
from datetime import datetime
import pkg_resources
from flask import Flask, abort, send_file
from flask import abort, send_file
from flask_cors import CORS, cross_origin
from labthings import create_app
from labthings.extensions import find_extensions
@ -34,7 +34,6 @@ from openflexure_microscope.paths import (
OPENFLEXURE_EXTENSIONS_PATH,
OPENFLEXURE_VAR_PATH,
logs_file_path,
settings_file_path,
)
# Handle logging
@ -72,7 +71,7 @@ root_log.addHandler(fh)
access_log.addHandler(afh)
# Log server paths being used
logging.info(f"Running with data path {OPENFLEXURE_VAR_PATH}")
logging.info("Running with data path %s", OPENFLEXURE_VAR_PATH)
logging.info("Creating app")
# Create flask app
@ -103,16 +102,16 @@ for extension in find_extensions(OPENFLEXURE_EXTENSIONS_PATH):
labthing.register_extension(extension)
# Attach captures resources
labthing.add_view(views.CaptureList, f"/captures")
labthing.add_view(views.CaptureList, "/captures")
labthing.add_root_link(views.CaptureList, "captures")
labthing.add_view(views.CaptureView, f"/captures/<id>")
labthing.add_view(views.CaptureDownload, f"/captures/<id>/download/<filename>")
labthing.add_view(views.CaptureTags, f"/captures/<id>/tags")
labthing.add_view(views.CaptureAnnotations, f"/captures/<id>/annotations")
labthing.add_view(views.CaptureView, "/captures/<id>")
labthing.add_view(views.CaptureDownload, "/captures/<id>/download/<filename>")
labthing.add_view(views.CaptureTags, "/captures/<id>/tags")
labthing.add_view(views.CaptureAnnotations, "/captures/<id>/annotations")
# Attach settings and state resources
labthing.add_view(views.SettingsProperty, f"/instrument/settings")
labthing.add_view(views.SettingsProperty, "/instrument/settings")
labthing.add_root_link(views.SettingsProperty, "instrumentSettings")
labthing.add_view(views.NestedSettingsProperty, "/instrument/settings/<path:route>")
labthing.add_view(views.StateProperty, "/instrument/state")
@ -129,8 +128,8 @@ labthing.add_view(views.StageTypeProperty, "/instrument/stage/type")
# Attach streams resources
labthing.add_view(views.MjpegStream, f"/streams/mjpeg")
labthing.add_view(views.SnapshotStream, f"/streams/snapshot")
labthing.add_view(views.MjpegStream, "/streams/mjpeg")
labthing.add_view(views.SnapshotStream, "/streams/snapshot")
# Attach microscope action resources
labthing.add_view(views.actions.ActionsView, "/actions")
@ -170,7 +169,7 @@ def err_log():
@app.route("/api/v1/", defaults={"path": ""})
@app.route("/api/v1/<path:path>")
def api_v1_catch_all(path):
def api_v1_catch_all(path): # pylint: disable=W0613
abort(410, "API v1 is no longer in use. Please upgrade your client.")

View file

@ -8,9 +8,11 @@ def handle_extension_error(extension_name):
"""'gracefully' log an error if an extension fails to load."""
try:
yield
except Exception as e:
except Exception: # pylint: disable=W0703
logging.error(
f"Exception loading builtin extension {extension_name}: \n{traceback.format_exc()}"
"Exception loading builtin extension %s: \n%s",
extension_name,
traceback.format_exc(),
)

View file

@ -6,10 +6,10 @@ from threading import Event, Thread
import numpy as np
from labthings import current_action, fields, find_component
from labthings.extensions import BaseExtension
from labthings.views import ActionView, PropertyView, View
from labthings.views import ActionView, View
from scipy import ndimage
from openflexure_microscope.devel import JsonResponse, abort, request
from openflexure_microscope.devel import abort
from openflexure_microscope.utilities import set_properties
### Autofocus utilities
@ -36,19 +36,15 @@ class JPEGSharpnessMonitor:
return self.background_thread.is_alive()
def should_stop(self):
import time
return time.time() - self.kept_alive > self.timeout
def keep_alive(self):
import time
self.kept_alive = time.time()
def start(self):
"Start monitoring sharpness by looking at JPEG size"
if not self.camera.stream_active:
logging.warn(
logging.warning(
"Autofocus sharpness monitor was started but the camera isn't streaming. Attempting to start the stream..."
)
self.camera.start_stream_recording()
@ -66,7 +62,7 @@ class JPEGSharpnessMonitor:
"Function that runs in a background thread to record sharpness"
logging.debug("Starting sharpness measurement in background thread")
self.keep_alive()
logging.debug(f"_measure_jpegs stop_event: {self.stop_event.is_set()}")
logging.debug("_measure_jpegs stop_event: %s", self.stop_event.is_set())
while not self.stop_event.is_set() and not self.should_stop():
size_now = self.jpeg_size()
time_now = time.time()
@ -107,7 +103,7 @@ class JPEGSharpnessMonitor:
if np.sum(jpeg_times > stage_times[0]) == 0:
raise ValueError(
"No images were captured during the move of the stage. Perhaps the camera is not streaming images?"
)
) from e
else:
raise e
if stop < 1:
@ -119,7 +115,7 @@ class JPEGSharpnessMonitor:
def sharpest_z_on_move(self, index):
"""Return the z position of the sharpest image on a given move"""
jt, jz, js = self.move_data(index)
_, jz, js = self.move_data(index)
if len(js) == 0:
raise ValueError(
"No images were captured during the move of the stage. Perhaps the camera is not streaming images?"
@ -226,7 +222,7 @@ def fast_autofocus(microscope, dz=2000, backlash=None):
"""Perform a down-up-down-up autofocus"""
with monitor_sharpness(
microscope
) as m, microscope.camera.lock, microscope.stage.lock:
) as m, microscope.camera.lock as _, microscope.stage.lock as _:
i, z = m.focus_rel(-dz / 2)
i, z = m.focus_rel(dz)
fz = m.sharpest_z_on_move(i)
@ -278,7 +274,7 @@ def fast_up_down_up_autofocus(
"""
with monitor_sharpness(
microscope
) as m, microscope.camera.lock, microscope.stage.lock:
) as m, microscope.camera.lock as _, microscope.stage.lock as _:
# Ensure the MJPEG stream has started
microscope.camera.start_stream_recording()
@ -291,12 +287,8 @@ def fast_up_down_up_autofocus(
i, z = m.focus_rel(-df)
# now inspect where the sharpest point is, and estimate the sharpness
# (JPEG size) that we should find at the start of the Z stack
logging.debug("Get target_s")
jt, jz, js = m.move_data(i)
_, jz, js = m.move_data(i)
best_z = jz[np.argmax(js)]
target_s = np.interp(
[best_z + target_z], jz[::-1], js[::-1]
) # NB jz is decreasing
# now move to the start of the z stack
logging.debug("Move to the start of the z stack")

View file

@ -1,6 +1,5 @@
import logging
import os
from sys import platform
import psutil
from flask import abort
@ -9,9 +8,7 @@ from labthings.extensions import BaseExtension
from labthings.views import PropertyView, View
from openflexure_microscope.api.utilities.gui import build_gui
from openflexure_microscope.captures.capture import build_captures_from_exif
from openflexure_microscope.captures.capture_manager import BASE_CAPTURE_PATH
from openflexure_microscope.config import OpenflexureSettingsFile
from openflexure_microscope.paths import check_rw, settings_file_path
AS_SETTINGS_PATH = settings_file_path("autostorage_settings.json")
@ -97,10 +94,10 @@ class AutostorageExtension(BaseExtension):
def on_microscope(self, microscope_obj):
"""Function to automatically call when the parent LabThing has a microscope attached."""
logging.debug(f"Autostorage extension found microscope {microscope_obj}")
logging.debug("Autostorage extension found microscope %s", microscope_obj)
if hasattr(microscope_obj, "captures"):
logging.debug(
f"Autostorage extension bound to CaptureManager {self.capture_manager}"
"Autostorage extension bound to CaptureManager %s", self.capture_manager
)
# Store a reference to the CaptureManager
@ -119,7 +116,8 @@ class AutostorageExtension(BaseExtension):
# If preferred path does not exist, or cannot be written to
if not (os.path.isdir(location) and check_rw(location)):
logging.error(
f"Preferred capture path {location} is missing or cannot be written to. Restoring defaults."
"Preferred capture path %s is missing or cannot be written to. Restoring defaults.",
location,
)
# Reset the storage location to default
set_current_location(self.capture_manager, get_default_location())
@ -187,8 +185,6 @@ autostorage_extension_v2 = AutostorageExtension()
class GetLocationsView(PropertyView):
def get(self):
global autostorage_extension_v2
autostorage_extension_v2.check_location()
return autostorage_extension_v2.get_locations()
@ -197,13 +193,10 @@ class PreferredLocationView(PropertyView):
schema = fields.String(required=True, example="Default")
def get(self):
global autostorage_extension_v2
autostorage_extension_v2.check_location()
return autostorage_extension_v2.get_preferred_key()
def post(self, new_path_key):
global autostorage_extension_v2
microscope = find_component("org.openflexure.microscope")
if not microscope:
@ -218,13 +211,11 @@ class PreferredLocationGUIView(View):
args = {"new_path_title": fields.String(required=True)}
def post(self, args):
global autostorage_extension_v2
new_path_title = args.get("new_path_title")
logging.debug(new_path_title)
new_path_key = autostorage_extension_v2.title_to_key(new_path_title)
logging.debug(f"{new_path_key}")
logging.debug(new_path_key)
autostorage_extension_v2.check_location()
autostorage_extension_v2.set_preferred_key(new_path_key)
@ -233,7 +224,6 @@ class PreferredLocationGUIView(View):
def dynamic_form():
global autostorage_extension_v2
autostorage_extension_v2.check_location()
return {
"icon": "sd_storage",

View file

@ -7,7 +7,7 @@ from typing import Tuple
from flask import abort
from labthings import find_component
from labthings.extensions import BaseExtension
from labthings.views import ActionView, View
from labthings.views import ActionView
from .recalibrate_utils import (
auto_expose_and_freeze_settings,
@ -78,17 +78,10 @@ class FlattenLSTView(ActionView):
"No microscope connected. Unable to flatten the lens shading table.",
)
try:
with pause_stream(microscope.camera) as scamera:
flat_lst = flat_lens_shading_table(scamera.camera)
scamera.camera.lens_shading_table = flat_lst
microscope.save_settings()
except:
logging.exception("Error flattening the lens shading table.")
abort(
503,
"Couldn't flatten the lens shading table - do you have the forked PiCamera library installed?",
)
with pause_stream(microscope.camera) as scamera:
flat_lst = flat_lens_shading_table(scamera.camera)
scamera.camera.lens_shading_table = flat_lst
microscope.save_settings()
class DeleteLSTView(ActionView):
@ -101,16 +94,9 @@ class DeleteLSTView(ActionView):
"No microscope connected. Unable to flatten the lens shading table.",
)
try:
with pause_stream(microscope.camera) as scamera:
scamera.camera.lens_shading_table = None
microscope.save_settings()
except:
logging.exception("Error deleting the lens shading table.")
abort(
503,
"Couldn't flatten the lens shading table - do you have the forked PiCamera library installed?",
)
with pause_stream(microscope.camera) as scamera:
scamera.camera.lens_shading_table = None
microscope.save_settings()
lst_extension_v2 = BaseExtension(

View file

@ -24,13 +24,15 @@ def flat_lens_shading_table(camera):
raise ImportError(
"This program requires the forked picamera library with lens shading support"
)
return np.zeros(camera._lens_shading_table_shape(), dtype=np.uint8) + 32
return (
np.zeros(camera._lens_shading_table_shape(), dtype=np.uint8) + 32
) # pylint: disable=W0212
def adjust_exposure_to_setpoint(camera, setpoint):
"""Adjust the camera's exposure time until the maximum pixel value is <setpoint>."""
print("Adjusting shutter speed to hit setpoint {}".format(setpoint), end="")
for i in range(3):
for _ in range(3):
print(".", end="")
camera.shutter_speed = int(
camera.shutter_speed * setpoint / np.max(rgb_image(camera))
@ -50,9 +52,9 @@ def auto_expose_and_freeze_settings(camera):
camera.awb_mode = "auto"
camera.exposure_mode = "auto"
camera.iso = (
0
) # This is important, if it's on a fixed ISO, gain might not set properly.
for i in range(6):
0 # This is important, if it's on a fixed ISO, gain might not set properly.
)
for _ in range(6):
print(".", end="")
time.sleep(0.5)
logging.info("done")
@ -188,10 +190,10 @@ def recalibrate_camera(camera):
if __name__ == "__main__":
with PiCamera() as camera:
camera.start_preview()
with PiCamera() as main_camera:
main_camera.start_preview()
time.sleep(3)
logging.info("Recalibrating...")
recalibrate_camera(camera)
recalibrate_camera(main_camera)
logging.info("Done.")
time.sleep(2)

View file

@ -14,7 +14,7 @@ from labthings import (
update_action_progress,
)
from labthings.extensions import BaseExtension
from labthings.views import ActionView, View
from labthings.views import ActionView
from openflexure_microscope.captures.capture_manager import generate_basename
from openflexure_microscope.devel import abort
@ -74,10 +74,13 @@ class ScanExtension(BaseExtension):
use_video_port: bool = False,
resize: Tuple[int, int] = None,
bayer: bool = False,
metadata: dict = {},
annotations: dict = {},
tags: list = [],
metadata: dict = None,
annotations: dict = None,
tags: list = None,
):
metadata = metadata or {}
annotations = annotations or {}
tags = tags or []
# Construct a tile filename
if namemode == "coordinates":
@ -117,18 +120,22 @@ class ScanExtension(BaseExtension):
basename: str = None,
namemode: str = "coordinates",
temporary: bool = False,
stride_size: int = [2000, 1500, 100],
grid: list = [3, 3, 5],
stride_size: list = (2000, 1500, 100),
grid: list = (3, 3, 5),
style="raster",
autofocus_dz: int = 50,
use_video_port: bool = False,
resize: Tuple[int, int] = None,
bayer: bool = False,
fast_autofocus=False,
metadata: dict = {},
annotations: dict = {},
tags: list = [],
metadata: dict = None,
annotations: dict = None,
tags: list = None,
):
metadata = metadata or {}
annotations = annotations or {}
tags = tags or []
start = time.time()
# Keep task progress
@ -210,7 +217,7 @@ class ScanExtension(BaseExtension):
# If we're not doing a z-stack, just capture
if grid[2] <= 1:
capture(
self.capture(
microscope,
basename,
namemode=namemode,
@ -250,7 +257,7 @@ class ScanExtension(BaseExtension):
microscope.stage.move_abs(initial_position)
end = time.time()
logging.info(f"Scan took {end - start} seconds")
logging.info("Scan took %s seconds", end - start)
def stack(
self,
@ -264,24 +271,27 @@ class ScanExtension(BaseExtension):
use_video_port: bool = False,
resize: Tuple[int, int] = None,
bayer: bool = False,
metadata: dict = {},
annotations: dict = {},
tags: list = [],
metadata: dict = None,
annotations: dict = None,
tags: list = None,
):
metadata = metadata or {}
annotations = annotations or {}
tags = tags or []
# Store initial position
initial_position = microscope.stage.position
logging.debug(f"Starting z-stack from position {microscope.stage.position}")
logging.debug("Starting z-stack from position %s", microscope.stage.position)
with microscope.lock:
# Move to center scan
logging.debug("Moving to z-stack starting position")
microscope.stage.move_rel([0, 0, int((-step_size * steps) / 2)])
logging.debug(f"Starting scan from position {microscope.stage.position}")
logging.debug("Starting scan from position %s", microscope.stage.position)
for i in range(steps):
time.sleep(0.1)
logging.debug(f"Capturing from position {microscope.stage.position}")
logging.debug("Capturing from position %s", microscope.stage.position)
self.capture(
microscope,
basename,

View file

@ -21,7 +21,7 @@ class ZipObjectSchema(Schema):
links = fields.Dict()
@pre_dump
def generate_links(self, data, **kwargs):
def generate_links(self, data, **_):
data.links = {
"download": {
"href": url_for(
@ -34,8 +34,8 @@ class ZipObjectSchema(Schema):
class ZipObjectDescription:
def __init__(self, id, file_pointer, data_size=None):
self.id = id
def __init__(self, id_, file_pointer, data_size=None):
self.id = id_
self.fp = file_pointer
self.data_size = data_size
self.zip_size = os.path.getsize(self.fp.name) * 1e-6
@ -155,7 +155,7 @@ class ZipGetterAPIView(View):
if not session_id in default_zip_manager.session_zips:
return abort(404) # 404 Not Found
logging.info(f"Session ID: {session_id}")
logging.info("Session ID: %s", session_id)
return send_file(
default_zip_manager.zip_fp_from_id(session_id).name,

View file

@ -17,7 +17,7 @@ class SleepFor(ActionView):
def post(self, args):
sleep_time = args.get("time")
logging.info(f"Going to sleep for {sleep_time}...")
logging.info("Going to sleep for %s...", sleep_time)
start = time.time()
time.sleep(sleep_time)
end = time.time()

View file

@ -116,7 +116,6 @@ def create_file(config_path):
def init_default_extensions(extension_dir):
global _DEFAULT_EXTENSION_INIT
os.makedirs(extension_dir, exist_ok=True)
default_ext_path = os.path.join(extension_dir, "defaults.py")

View file

@ -12,9 +12,10 @@ def clean_rule(rule: str):
def build_gui_from_dict(gui_description, extension_object):
# Make a working copy of GUI description
api_gui = copy.deepcopy(gui_description)
logging.debug(extension_object)
logging.debug(extension_object._rules)
# Grab the extensions rules dictionary
# NOTE: The LabThings extension object should probably have a non-private
# way to get the rules dictionary. For now we need to ignore pylint W0212
ext_rules = extension_object._rules # pylint: disable=W0212
# Expand shorthand routes into full relative URLs
if "forms" in gui_description and isinstance(api_gui["forms"], list):
@ -23,12 +24,10 @@ def build_gui_from_dict(gui_description, extension_object):
if "route" in form:
form["route"] = clean_rule(form["route"])
# Match rule in extension object
if "route" in form and form["route"] in extension_object._rules.keys():
form["route"] = extension_object._rules[form["route"]]["urls"][0]
if "route" in form and form["route"] in ext_rules.keys():
form["route"] = ext_rules[form["route"]]["urls"][0]
else:
logging.warn(
"No valid expandable route found for {}".format(form["route"])
)
logging.warning("No valid expandable route found for %s", form["route"])
# Inject extension information
api_gui["id"] = extension_object.name

View file

@ -53,7 +53,6 @@ _actions = {
def enabled_root_actions():
global _actions
return {k: v for k, v in _actions.items() if v["conditions"]}
@ -65,8 +64,6 @@ class ActionsView(View):
This list does not include any actions added by LabThings extensions, only
those part of the default OpenFlexure Microscope API.
"""
global _actions
actions = {}
for name, action in enabled_root_actions().items():
d = {

View file

@ -1,13 +1,11 @@
import io
import logging
from flask import abort, redirect, request, send_file, url_for
from flask import abort, send_file
from labthings import fields, find_component
from labthings.views import ActionView, View
from labthings.views import ActionView
from openflexure_microscope.api.utilities import JsonResponse, get_bool
from openflexure_microscope.api.v2.views.captures import CaptureSchema
from openflexure_microscope.utilities import filter_dict
class CaptureAPI(ActionView):

View file

@ -1,11 +1,9 @@
import logging
from flask import Blueprint, request
from labthings import fields, find_component
from labthings.views import ActionView, View
from labthings.views import ActionView
from openflexure_microscope.api.utilities import JsonResponse
from openflexure_microscope.utilities import axes_to_array, filter_dict
from openflexure_microscope.utilities import axes_to_array
class MoveStageAPI(ActionView):

View file

@ -1,11 +1,10 @@
import os
import subprocess
from sys import platform
from labthings.views import ActionView, View
from labthings.views import ActionView
def is_raspberrypi(raise_on_errors=False):
def is_raspberrypi():
"""
Checks if Raspberry Pi.
"""

View file

@ -45,9 +45,8 @@ class CaptureSchema(Schema):
links = fields.Dict()
# TODO: Automate this somewhat
@pre_dump
def generate_links(self, data, **kwargs):
def generate_links(self, data, **_):
data.links = {
"self": {
"href": url_for(CaptureView.endpoint, id=data.id, _external=True),
@ -97,24 +96,24 @@ class CaptureView(View):
tags = ["captures"]
@marshal_with(CaptureSchema())
def get(self, id):
def get(self, id_):
"""
Description of a single image capture
"""
microscope = find_component("org.openflexure.microscope")
capture_obj = microscope.captures.images.get(id)
capture_obj = microscope.captures.images.get(id_)
if not capture_obj:
return abort(404) # 404 Not Found
return capture_obj
def delete(self, id):
def delete(self, id_):
"""
Delete a single image capture
"""
microscope = find_component("org.openflexure.microscope")
capture_obj = microscope.captures.images.get(id)
capture_obj = microscope.captures.images.get(id_)
if not capture_obj:
return abort(404) # 404 Not Found
@ -122,7 +121,7 @@ class CaptureView(View):
# Delete the capture file
capture_obj.delete()
# Delete from capture list
del microscope.captures.images[id]
del microscope.captures.images[id_]
return "", 204
@ -131,12 +130,12 @@ class CaptureDownload(View):
tags = ["captures"]
responses = {200: {"content_type": "image/jpeg"}}
def get(self, id, filename):
def get(self, id_, filename):
"""
Image data for a single image capture
"""
microscope = find_component("org.openflexure.microscope")
capture_obj = microscope.captures.images.get(id)
capture_obj = microscope.captures.images.get(id_)
if not capture_obj:
return abort(404) # 404 Not Found
@ -148,7 +147,7 @@ class CaptureDownload(View):
return redirect(
url_for(
"DownloadAPI",
id=id,
id=id_,
filename=capture_obj.filename,
thumbnail=thumbnail,
),
@ -167,24 +166,24 @@ class CaptureDownload(View):
class CaptureTags(View):
tags = ["captures"]
def get(self, id):
def get(self, id_):
"""
Get tags associated with a single image capture
"""
microscope = find_component("org.openflexure.microscope")
capture_obj = microscope.captures.images.get(id)
capture_obj = microscope.captures.images.get(id_)
if not capture_obj:
return abort(404) # 404 Not Found
return capture_obj.tags
def put(self, id):
def put(self, id_):
"""
Add tags to a single image capture
"""
microscope = find_component("org.openflexure.microscope")
capture_obj = microscope.captures.images.get(id)
capture_obj = microscope.captures.images.get(id_)
if not capture_obj:
return abort(404) # 404 Not Found
@ -199,12 +198,12 @@ class CaptureTags(View):
return capture_obj.tags
def delete(self, id):
def delete(self, id_):
"""
Delete tags from a single image capture
"""
microscope = find_component("org.openflexure.microscope")
capture_obj = microscope.captures.images.get(id)
capture_obj = microscope.captures.images.get(id_)
if not capture_obj:
return abort(404) # 404 Not Found
@ -223,24 +222,24 @@ class CaptureTags(View):
class CaptureAnnotations(View):
tags = ["captures"]
def get(self, id):
def get(self, id_):
"""
Get annotations associated with a single image capture
"""
microscope = find_component("org.openflexure.microscope")
capture_obj = microscope.captures.images.get(id)
capture_obj = microscope.captures.images.get(id_)
if not capture_obj:
return abort(404) # 404 Not Found
return capture_obj.annotations
def put(self, id):
def put(self, id_):
"""
Update metadata for a single image capture
"""
microscope = find_component("org.openflexure.microscope")
capture_obj = microscope.captures.images.get(id)
capture_obj = microscope.captures.images.get(id_)
if not capture_obj:
return abort(404) # 404 Not Found

View file

@ -1,6 +1,4 @@
import logging
from labthings import fields, find_component, schema
from labthings import fields, find_component
from labthings.views import PropertyView

View file

@ -1,9 +1,8 @@
from flask import Response
from labthings import find_component
from labthings.utilities import create_from_path, get_by_path, set_by_path
from labthings.views import PropertyView, View
from labthings.views import PropertyView
from openflexure_microscope.api.utilities import JsonResponse, gen
from openflexure_microscope.api.utilities import gen
class MjpegStream(PropertyView):