Loading .gitlab-ci.yml +40 −0 Original line number Diff line number Diff line stages: - analysis - build - deploy Loading @@ -9,6 +10,45 @@ cache: paths: - node_modules/ pylint: stage: analysis image: python:3.7 allow_failure: true before_script: - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python script: # Install server - $HOME/.poetry/bin/poetry install # Run static build script - $HOME/.poetry/bin/poetry run pylint ./openflexure_microscope/ only: - branches - merge_requests - tags - web black: stage: analysis image: python:3.7 allow_failure: true before_script: - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python script: # Install server - $HOME/.poetry/bin/poetry install # Run static build script - $HOME/.poetry/bin/poetry run black --check . only: - branches - merge_requests - tags - web # Electron app build build: Loading openflexure_microscope/api/app.py +11 −12 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -34,7 +34,6 @@ from openflexure_microscope.paths import ( OPENFLEXURE_EXTENSIONS_PATH, OPENFLEXURE_VAR_PATH, logs_file_path, settings_file_path, ) # Handle logging Loading Loading @@ -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 Loading Loading @@ -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") Loading @@ -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") Loading Loading @@ -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.") Loading openflexure_microscope/api/default_extensions/__init__.py +4 −2 Original line number Diff line number Diff line Loading @@ -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(), ) Loading openflexure_microscope/api/default_extensions/autofocus.py +9 −17 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() Loading @@ -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() Loading Loading @@ -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: Loading @@ -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?" Loading Loading @@ -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) Loading Loading @@ -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() Loading @@ -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") Loading openflexure_microscope/api/default_extensions/autostorage.py +5 −15 Original line number Diff line number Diff line import logging import os from sys import platform import psutil from flask import abort Loading @@ -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") Loading Loading @@ -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 Loading @@ -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()) Loading Loading @@ -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() Loading @@ -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: Loading @@ -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) Loading @@ -233,7 +224,6 @@ class PreferredLocationGUIView(View): def dynamic_form(): global autostorage_extension_v2 autostorage_extension_v2.check_location() return { "icon": "sd_storage", Loading Loading
.gitlab-ci.yml +40 −0 Original line number Diff line number Diff line stages: - analysis - build - deploy Loading @@ -9,6 +10,45 @@ cache: paths: - node_modules/ pylint: stage: analysis image: python:3.7 allow_failure: true before_script: - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python script: # Install server - $HOME/.poetry/bin/poetry install # Run static build script - $HOME/.poetry/bin/poetry run pylint ./openflexure_microscope/ only: - branches - merge_requests - tags - web black: stage: analysis image: python:3.7 allow_failure: true before_script: - curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python script: # Install server - $HOME/.poetry/bin/poetry install # Run static build script - $HOME/.poetry/bin/poetry run black --check . only: - branches - merge_requests - tags - web # Electron app build build: Loading
openflexure_microscope/api/app.py +11 −12 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -34,7 +34,6 @@ from openflexure_microscope.paths import ( OPENFLEXURE_EXTENSIONS_PATH, OPENFLEXURE_VAR_PATH, logs_file_path, settings_file_path, ) # Handle logging Loading Loading @@ -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 Loading Loading @@ -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") Loading @@ -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") Loading Loading @@ -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.") Loading
openflexure_microscope/api/default_extensions/__init__.py +4 −2 Original line number Diff line number Diff line Loading @@ -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(), ) Loading
openflexure_microscope/api/default_extensions/autofocus.py +9 −17 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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() Loading @@ -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() Loading Loading @@ -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: Loading @@ -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?" Loading Loading @@ -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) Loading Loading @@ -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() Loading @@ -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") Loading
openflexure_microscope/api/default_extensions/autostorage.py +5 −15 Original line number Diff line number Diff line import logging import os from sys import platform import psutil from flask import abort Loading @@ -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") Loading Loading @@ -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 Loading @@ -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()) Loading Loading @@ -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() Loading @@ -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: Loading @@ -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) Loading @@ -233,7 +224,6 @@ class PreferredLocationGUIView(View): def dynamic_form(): global autostorage_extension_v2 autostorage_extension_v2.check_location() return { "icon": "sd_storage", Loading