Code cleanup
This commit is contained in:
parent
2bfb988460
commit
994e83dbeb
46 changed files with 261 additions and 318 deletions
|
|
@ -1,4 +1,5 @@
|
|||
stages:
|
||||
- analysis
|
||||
- build
|
||||
- deploy
|
||||
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
import logging
|
||||
|
||||
from labthings import fields, find_component, schema
|
||||
from labthings import fields, find_component
|
||||
from labthings.views import PropertyView
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import threading
|
||||
import time
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
|
@ -21,6 +18,7 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
|
||||
self.lock = StrictLock(name="Camera", timeout=None)
|
||||
|
||||
self.frames_iterator = None
|
||||
self.frame = None
|
||||
self.last_access = 0
|
||||
self.event = ClientEvent()
|
||||
|
|
@ -34,13 +32,11 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
@abstractmethod
|
||||
def configuration(self):
|
||||
"""The current camera configuration."""
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def state(self):
|
||||
"""The current read-only camera state."""
|
||||
pass
|
||||
|
||||
@property
|
||||
def settings(self):
|
||||
|
|
@ -132,7 +128,6 @@ class BaseCamera(metaclass=ABCMeta):
|
|||
@abstractmethod
|
||||
def frames(self):
|
||||
"""Create generator that returns frames from the camera."""
|
||||
pass
|
||||
|
||||
# WORKER THREAD
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
"""
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import io
|
||||
|
|
@ -11,18 +8,13 @@ import time
|
|||
from datetime import datetime
|
||||
|
||||
# Type hinting
|
||||
from typing import Tuple
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
from openflexure_microscope.camera.base import BaseCamera
|
||||
from openflexure_microscope.captures import CaptureObject
|
||||
|
||||
"""
|
||||
PIL spams the logger with debug-level information. This is a pain when debugging api.app.
|
||||
We override the logging settings in api.app by setting a level for PIL here.
|
||||
"""
|
||||
# PIL spams the logger with debug-level information. This is a pain when debugging api.app.
|
||||
# We override the logging settings in api.app by setting a level for PIL here.
|
||||
|
||||
pil_logger = logging.getLogger("PIL")
|
||||
pil_logger.setLevel(logging.INFO)
|
||||
|
||||
|
|
@ -79,7 +71,6 @@ class MissingCamera(BaseCamera):
|
|||
|
||||
def initialisation(self):
|
||||
"""Run any initialisation code when the frame iterator starts."""
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
"""Close the Raspberry Pi PiCameraStreamer."""
|
||||
|
|
@ -134,7 +125,7 @@ class MissingCamera(BaseCamera):
|
|||
"Cannot update camera config while recording is active."
|
||||
)
|
||||
|
||||
def set_zoom(self, zoom_value: float = 1.0) -> None:
|
||||
def set_zoom(self, *_) -> None:
|
||||
"""
|
||||
Change the camera zoom, handling re-centering and scaling.
|
||||
"""
|
||||
|
|
@ -142,7 +133,7 @@ class MissingCamera(BaseCamera):
|
|||
|
||||
# LAUNCH ACTIONS
|
||||
|
||||
def start_preview(self, fullscreen=True, window=None):
|
||||
def start_preview(self, *_):
|
||||
"""Start the on board GPU camera preview."""
|
||||
logging.warning("GPU preview not implemented in mock camera")
|
||||
|
||||
|
|
@ -150,7 +141,7 @@ class MissingCamera(BaseCamera):
|
|||
"""Stop the on board GPU camera preview."""
|
||||
logging.warning("GPU preview not implemented in mock camera")
|
||||
|
||||
def start_recording(self, output, fmt: str = "h264", quality: int = 15):
|
||||
def start_recording(self, *_):
|
||||
"""Start recording.
|
||||
|
||||
Start a new video recording, writing to a output object.
|
||||
|
|
@ -173,14 +164,7 @@ class MissingCamera(BaseCamera):
|
|||
with self.lock:
|
||||
logging.warning("Recording not implemented in mock camera")
|
||||
|
||||
def capture(
|
||||
self,
|
||||
output,
|
||||
fmt: str = "jpeg",
|
||||
use_video_port: bool = False,
|
||||
resize: Tuple[int, int] = None,
|
||||
bayer: bool = True,
|
||||
):
|
||||
def capture(self, output, *_):
|
||||
"""
|
||||
Capture a still image to a StreamObject.
|
||||
|
||||
|
|
@ -189,10 +173,6 @@ class MissingCamera(BaseCamera):
|
|||
|
||||
Args:
|
||||
output: String or file-like object to write capture data to
|
||||
use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster.
|
||||
fmt (str): Format of the capture.
|
||||
resize ((int, int)): Resize the captured image.
|
||||
bayer (bool): Store raw bayer data in capture
|
||||
"""
|
||||
|
||||
with self.lock:
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ from __future__ import division
|
|||
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
# Type hinting
|
||||
|
|
@ -43,13 +42,8 @@ import picamerax
|
|||
import picamerax.array
|
||||
|
||||
from openflexure_microscope.camera.base import BaseCamera
|
||||
from openflexure_microscope.captures import CaptureObject
|
||||
from openflexure_microscope.paths import settings_file_path
|
||||
from openflexure_microscope.utilities import (
|
||||
json_to_ndarray,
|
||||
ndarray_to_json,
|
||||
serialise_array_b64,
|
||||
)
|
||||
from openflexure_microscope.utilities import json_to_ndarray, ndarray_to_json
|
||||
|
||||
# Richard's fix gain
|
||||
from .set_picamera_gain import set_analog_gain, set_digital_gain
|
||||
|
|
@ -117,6 +111,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
) #: str: Path of .npy lens shading table file
|
||||
|
||||
# Start the stream worker on init
|
||||
self.stream = None
|
||||
self.start_worker()
|
||||
|
||||
@property
|
||||
|
|
@ -131,7 +126,6 @@ class PiCameraStreamer(BaseCamera):
|
|||
|
||||
def initialisation(self):
|
||||
"""Run any initialisation code when the frame iterator starts."""
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
"""Close the Raspberry Pi PiCameraStreamer."""
|
||||
|
|
@ -466,7 +460,7 @@ class PiCameraStreamer(BaseCamera):
|
|||
|
||||
# Reduce the resolution for video streaming
|
||||
try:
|
||||
self.camera._check_recording_stopped()
|
||||
self.camera._check_recording_stopped() # pylint: disable=W0212
|
||||
except picamerax.exc.PiCameraRuntimeError:
|
||||
logging.info(
|
||||
"Error while changing resolution: Recording already running."
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ def read_exif_from_file(filename):
|
|||
head = data[2:6]
|
||||
HEAD_LENGTH = 4
|
||||
exif = None
|
||||
while 1:
|
||||
while len(head) == HEAD_LENGTH:
|
||||
length = struct.unpack(">H", head[2:4])[0]
|
||||
|
||||
if head[:2] == b"\xff\xe1":
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import copy
|
|||
import numbers
|
||||
import struct
|
||||
|
||||
from ._common import *
|
||||
from ._exif import *
|
||||
from ._common import split_into_segments
|
||||
from ._exif import ExifIFD, ImageIFD, TAGS, TYPES
|
||||
|
||||
TIFF_HEADER_LENGTH = 8
|
||||
|
||||
|
|
@ -243,11 +243,11 @@ def _value_to_bytes(raw_value, value_type, offset):
|
|||
elif value_type == TYPES.Ascii:
|
||||
try:
|
||||
new_value = raw_value.encode("latin1") + b"\x00"
|
||||
except:
|
||||
except: # pylint: disable=W0702
|
||||
try:
|
||||
new_value = raw_value + b"\x00"
|
||||
except TypeError:
|
||||
raise ValueError("Got invalid type to convert.")
|
||||
except TypeError as e:
|
||||
raise ValueError("Got invalid type to convert.") from e
|
||||
length = len(new_value)
|
||||
if length > 4:
|
||||
value_str = struct.pack(">I", offset)
|
||||
|
|
@ -262,7 +262,7 @@ def _value_to_bytes(raw_value, value_type, offset):
|
|||
elif isinstance(raw_value[0], tuple):
|
||||
length = len(raw_value)
|
||||
new_value = b""
|
||||
for n, val in enumerate(raw_value):
|
||||
for _, val in enumerate(raw_value):
|
||||
num, den = val
|
||||
new_value += struct.pack(">L", num) + struct.pack(">L", den)
|
||||
value_str = struct.pack(">I", offset)
|
||||
|
|
@ -275,7 +275,7 @@ def _value_to_bytes(raw_value, value_type, offset):
|
|||
elif isinstance(raw_value[0], tuple):
|
||||
length = len(raw_value)
|
||||
new_value = b""
|
||||
for n, val in enumerate(raw_value):
|
||||
for _, val in enumerate(raw_value):
|
||||
num, den = val
|
||||
new_value += struct.pack(">l", num) + struct.pack(">l", den)
|
||||
value_str = struct.pack(">I", offset)
|
||||
|
|
@ -286,13 +286,13 @@ def _value_to_bytes(raw_value, value_type, offset):
|
|||
value_str = struct.pack(">I", offset)
|
||||
try:
|
||||
four_bytes_over = b"" + raw_value
|
||||
except TypeError:
|
||||
raise ValueError("Got invalid type to convert.")
|
||||
except TypeError as e:
|
||||
raise ValueError("Got invalid type to convert.") from e
|
||||
else:
|
||||
try:
|
||||
value_str = raw_value + b"\x00" * (4 - length)
|
||||
except TypeError:
|
||||
raise ValueError("Got invalid type to convert.")
|
||||
except TypeError as e:
|
||||
raise ValueError("Got invalid type to convert.") from e
|
||||
elif value_type == TYPES.SByte: # Signed Byte
|
||||
length = len(raw_value)
|
||||
if length <= 4:
|
||||
|
|
@ -333,7 +333,7 @@ def _dict_to_bytes(ifd_dict, ifd, ifd_offset):
|
|||
entries = b""
|
||||
values = b""
|
||||
|
||||
for n, key in enumerate(sorted(ifd_dict)):
|
||||
for _, key in enumerate(sorted(ifd_dict)):
|
||||
if (ifd == "0th") and (key in (ImageIFD.ExifTag, ImageIFD.GPSTag)):
|
||||
continue
|
||||
elif (ifd == "Exif") and (key == ExifIFD.InteroperabilityTag):
|
||||
|
|
@ -358,11 +358,11 @@ def _dict_to_bytes(ifd_dict, ifd, ifd_offset):
|
|||
length_str, value_str, four_bytes_over = _value_to_bytes(
|
||||
raw_value, value_type, offset
|
||||
)
|
||||
except ValueError:
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
'"dump" got wrong type of exif value.\n'
|
||||
+ "{0} in {1} IFD. Got as {2}.".format(key, ifd, type(ifd_dict[key]))
|
||||
)
|
||||
) from e
|
||||
|
||||
entries += key_str + type_str + length_str + value_str
|
||||
values += four_bytes_over
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import struct
|
|||
import sys
|
||||
|
||||
from . import _webp
|
||||
from ._common import *
|
||||
from ._common import merge_segments, split_into_segments
|
||||
from ._exceptions import InvalidImageDataError
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import struct
|
|||
import sys
|
||||
|
||||
from . import _webp
|
||||
from ._common import *
|
||||
from ._common import get_exif_seg, read_exif_from_file, split_into_segments
|
||||
from ._exceptions import InvalidImageDataError
|
||||
from ._exif import *
|
||||
from ._exif import ExifIFD, ImageIFD, TAGS, TYPES
|
||||
|
||||
LITTLE_ENDIAN = b"\x49\x49"
|
||||
|
||||
|
|
@ -109,6 +109,8 @@ class _ExifReader(object):
|
|||
else:
|
||||
raise InvalidImageDataError("Given file is neither JPEG nor TIFF.")
|
||||
|
||||
self.endian_mark = None
|
||||
|
||||
def get_ifd_dict(self, pointer, ifd_name, read_unknown=False):
|
||||
ifd_dict = {}
|
||||
tag_count = struct.unpack(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import io
|
||||
|
||||
from . import _webp
|
||||
from ._common import *
|
||||
from ._common import get_exif_seg, split_into_segments
|
||||
|
||||
|
||||
def remove(src, new_file=None):
|
||||
|
|
@ -42,7 +42,7 @@ def remove(src, new_file=None):
|
|||
new_data = src_data
|
||||
except Exception as e:
|
||||
print(e)
|
||||
raise ValueError("Error occurred.")
|
||||
raise ValueError("Error occurred.") from e
|
||||
|
||||
if isinstance(new_file, io.BytesIO):
|
||||
new_file.write(new_data)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import io
|
||||
|
||||
from ._common import *
|
||||
from ._common import get_exif_seg, merge_segments, split_into_segments
|
||||
|
||||
|
||||
def transplant(exif_src, image, new_file=None):
|
||||
|
|
|
|||
|
|
@ -204,8 +204,6 @@ def get_exif(data):
|
|||
CHUNK_FOURCC_LENGTH = 4
|
||||
LENGTH_BYTES_LENGTH = 4
|
||||
|
||||
chunks = []
|
||||
exif = b""
|
||||
while pointer < file_size:
|
||||
fourcc = data[pointer : pointer + CHUNK_FOURCC_LENGTH]
|
||||
pointer += CHUNK_FOURCC_LENGTH
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ class UserComment:
|
|||
cls._JIS_PREFIX: cls._JIS,
|
||||
cls._UNICODE_PREFIX: cls._UNICODE,
|
||||
}[prefix]
|
||||
except KeyError:
|
||||
raise ValueError("unable to determine appropriate encoding")
|
||||
except KeyError as e:
|
||||
raise ValueError("unable to determine appropriate encoding") from e
|
||||
return body.decode(encoding, errors="replace")
|
||||
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import logging
|
|||
import time
|
||||
|
||||
import picamerax
|
||||
from picamerax import exc, mmal, mmalobj
|
||||
from picamerax import exc, mmal
|
||||
from picamerax.mmalobj import to_rational
|
||||
|
||||
MMAL_PARAMETER_ANALOG_GAIN = mmal.MMAL_PARAMETER_GROUP_CAMERA + 0x59
|
||||
|
|
@ -21,7 +21,7 @@ def set_gain(camera, gain, value):
|
|||
if gain not in [MMAL_PARAMETER_ANALOG_GAIN, MMAL_PARAMETER_DIGITAL_GAIN]:
|
||||
raise ValueError("The gain parameter was not valid")
|
||||
ret = mmal.mmal_port_parameter_set_rational(
|
||||
camera._camera.control._port, gain, to_rational(value)
|
||||
camera._camera.control._port, gain, to_rational(value) # pylint: disable=W0212
|
||||
)
|
||||
if ret == 4:
|
||||
raise exc.PiCameraMMALError(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import atexit
|
||||
import datetime
|
||||
import glob
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import uuid
|
||||
from collections import OrderedDict
|
||||
|
||||
|
|
@ -37,7 +35,8 @@ def pull_usercomment_dict(filepath):
|
|||
return json.loads(exif_dict["Exif"][piexif.ExifIFD.UserComment].decode())
|
||||
except json.decoder.JSONDecodeError:
|
||||
logging.error(
|
||||
f"Capture {filepath} has old, corrupt, or missing OpenFlexure metadata. Unable to reload to server."
|
||||
"Capture %s has old, corrupt, or missing OpenFlexure metadata. Unable to reload to server.",
|
||||
filepath,
|
||||
)
|
||||
else:
|
||||
return None
|
||||
|
|
@ -56,8 +55,6 @@ def make_file_list(directory, formats):
|
|||
|
||||
|
||||
def build_captures_from_exif(capture_path):
|
||||
global EXIF_FORMATS
|
||||
|
||||
logging.debug("Reloading captures from {}...".format(capture_path))
|
||||
files = make_file_list(capture_path, EXIF_FORMATS)
|
||||
captures = OrderedDict()
|
||||
|
|
@ -97,9 +94,9 @@ def capture_from_exif(path, exif_dict):
|
|||
# Image metadata
|
||||
try:
|
||||
image_metadata = exif_dict.pop("image")
|
||||
except KeyError as e:
|
||||
except KeyError:
|
||||
logging.error(
|
||||
f"Unable to obtain valid 2.0 OpenFlexure metadata from file {path}"
|
||||
"Unable to obtain valid 2.0 OpenFlexure metadata from file %s", path
|
||||
)
|
||||
return None
|
||||
|
||||
|
|
@ -111,7 +108,7 @@ def capture_from_exif(path, exif_dict):
|
|||
capture.annotations = image_metadata.get("annotations")
|
||||
|
||||
# Since we popped the "image" key, we dump whatever is left in _metadata
|
||||
capture._metadata = exif_dict
|
||||
capture.set_metadata(exif_dict)
|
||||
|
||||
return capture
|
||||
|
||||
|
|
@ -133,6 +130,7 @@ class CaptureObject(object):
|
|||
self.datetime = datetime.datetime.now()
|
||||
|
||||
# Create file name. Default to UUID
|
||||
self.format = None
|
||||
self.file = filepath
|
||||
self.split_file_path(self.file)
|
||||
|
||||
|
|
@ -151,15 +149,15 @@ class CaptureObject(object):
|
|||
self.thumb_bytes = None
|
||||
|
||||
def write(self, s):
|
||||
logging.debug(f"Writing to {self}")
|
||||
logging.debug("Writing to %s", self)
|
||||
self.stream.write(s)
|
||||
|
||||
def flush(self):
|
||||
logging.info(f"Writing to disk {self.file}")
|
||||
logging.info("Writing to disk %s", self.file)
|
||||
with open(self.file, "wb") as outfile:
|
||||
outfile.write(self.stream.getbuffer())
|
||||
self.stream.close()
|
||||
logging.info(f"Finished writing to disk {self.file}")
|
||||
logging.info("Finished writing to disk %s", self.file)
|
||||
|
||||
def open(self, mode):
|
||||
return open(self.file, mode)
|
||||
|
|
@ -233,6 +231,15 @@ class CaptureObject(object):
|
|||
self._metadata.update(data)
|
||||
self.save_metadata()
|
||||
|
||||
def set_metadata(self, data: dict) -> None:
|
||||
"""
|
||||
Write root metadata from a passed dictionary into the capture metadata.
|
||||
|
||||
Args:
|
||||
data (dict): Dictionary of metadata to be added
|
||||
"""
|
||||
self._metadata = data
|
||||
|
||||
def put_and_save(
|
||||
self, tags: list = None, annotations: dict = None, metadata: dict = None
|
||||
):
|
||||
|
|
@ -261,22 +268,20 @@ class CaptureObject(object):
|
|||
"""
|
||||
Save metadata to exif, if supported
|
||||
"""
|
||||
global EXIF_FORMATS
|
||||
|
||||
if self.format.upper() in EXIF_FORMATS and self.exists:
|
||||
logging.debug("Writing exif data to capture file")
|
||||
# Extract current Exif data
|
||||
exif_dict = piexif.load(self.file)
|
||||
# Serialize metadata
|
||||
metadata_string = json.dumps(self.metadata, cls=JSONEncoder)
|
||||
logging.debug(f"Saving metadata string to file: {metadata_string}")
|
||||
logging.debug("Saving metadata string to file: %s", metadata_string)
|
||||
# Insert metadata into exif_dict
|
||||
exif_dict["Exif"][piexif.ExifIFD.UserComment] = metadata_string.encode()
|
||||
# Convert new exif dict to exif bytes
|
||||
exif_bytes = piexif.dump(exif_dict)
|
||||
# Insert exif into file
|
||||
piexif.insert(exif_bytes, self.file)
|
||||
logging.info(f"Finished saving metadata to {self.file}")
|
||||
logging.info("Finished saving metadata to %s", self.file)
|
||||
|
||||
@property
|
||||
def metadata(self) -> dict:
|
||||
|
|
@ -344,7 +349,6 @@ class CaptureObject(object):
|
|||
"""
|
||||
Returns a thumbnail of the capture data, for supported image formats.
|
||||
"""
|
||||
global THUMBNAIL_SIZE
|
||||
# If no thumbnail exists, try and make one
|
||||
if not self.thumb_bytes:
|
||||
logging.info("Building thumbnail")
|
||||
|
|
|
|||
|
|
@ -158,7 +158,8 @@ class CaptureManager:
|
|||
|
||||
# Update capture list
|
||||
capture_key = str(output.id)
|
||||
logging.debug(f"Adding image {output} with key {capture_key}")
|
||||
logging.debug("Adding image %s with key %s", output, capture_key)
|
||||
|
||||
self.images[capture_key] = output
|
||||
|
||||
return output
|
||||
|
|
@ -204,7 +205,7 @@ class CaptureManager:
|
|||
|
||||
# Update capture list
|
||||
capture_key = str(output.id)
|
||||
logging.debug(f"Adding video {output} with key {capture_key}")
|
||||
logging.debug("Adding video %s with key %s", output, capture_key)
|
||||
self.videos[capture_key] = output
|
||||
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import shutil
|
|||
from fractions import Fraction
|
||||
from uuid import UUID
|
||||
|
||||
import flask
|
||||
import numpy as np
|
||||
from labthings.json import LabThingsJSONEncoder
|
||||
|
||||
|
|
@ -27,8 +26,8 @@ class OpenflexureSettingsFile:
|
|||
expand (bool): Expand paths to valid auxillary config files.
|
||||
"""
|
||||
|
||||
def __init__(self, path: str, defaults: dict = {}):
|
||||
global DEFAULT_SETTINGS
|
||||
def __init__(self, path: str, defaults: dict = None):
|
||||
defaults = defaults or {}
|
||||
|
||||
# Set arguments
|
||||
self.path = path
|
||||
|
|
@ -84,7 +83,7 @@ class JSONEncoder(LabThingsJSONEncoder):
|
|||
A custom JSON encoder, with type conversions for PiCamera fractions, Numpy integers, and Numpy arrays
|
||||
"""
|
||||
|
||||
def default(self, o, markers=None):
|
||||
def default(self, o):
|
||||
if isinstance(o, UUID):
|
||||
return str(o)
|
||||
# PiCamera fractions
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
from threading import ThreadError
|
||||
|
||||
|
||||
class LockError(ThreadError):
|
||||
ERROR_CODES = {
|
||||
"ACQUIRE_ERROR": "Unable to acquire. Lock in use by another thread.",
|
||||
"IN_USE_ERROR": "Lock in use by another thread.",
|
||||
}
|
||||
|
||||
def __init__(self, code, lock):
|
||||
self.code = code
|
||||
if code in LockError.ERROR_CODES:
|
||||
self.message = LockError.ERROR_CODES[code]
|
||||
else:
|
||||
self.message = "Unknown error."
|
||||
|
||||
self.string = "{}: {}".format(self.code, self.message)
|
||||
print(self.string)
|
||||
|
||||
ThreadError.__init__(self)
|
||||
|
||||
def __str__(self):
|
||||
return self.string
|
||||
|
|
@ -16,14 +16,12 @@ from openflexure_microscope.stage.sanga import SangaDeltaStage, SangaStage
|
|||
|
||||
try:
|
||||
from openflexure_microscope.camera.pi import PiCameraStreamer
|
||||
except Exception as e:
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
logging.error(e)
|
||||
logging.warning("Unable to import PiCameraStreamer")
|
||||
from labthings import CompositeLock
|
||||
|
||||
from openflexure_microscope.camera.mock import MissingCamera
|
||||
from openflexure_microscope.config import user_configuration, user_settings
|
||||
from openflexure_microscope.utilities import Timer, serialise_array_b64
|
||||
|
||||
|
||||
class Microscope:
|
||||
|
|
@ -99,7 +97,7 @@ class Microscope:
|
|||
if camera_type in ("PiCamera", "PiCameraStreamer"):
|
||||
try:
|
||||
self.camera = PiCameraStreamer()
|
||||
except Exception as e:
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
logging.error(e)
|
||||
logging.warning("No compatible camera hardware found.")
|
||||
|
||||
|
|
@ -146,7 +144,7 @@ class Microscope:
|
|||
try:
|
||||
logging.info("Trying SangaStage")
|
||||
self.stage = SangaStage(port=stage_port)
|
||||
except Exception as e:
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
logging.error(e)
|
||||
logging.warning("No compatible Sangaboard hardware found.")
|
||||
elif stage_type in ("SangaDeltaStage"):
|
||||
|
|
@ -154,7 +152,7 @@ class Microscope:
|
|||
logging.info("Trying SangaDeltaStage")
|
||||
self.stage = SangaDeltaStage(port=stage_port)
|
||||
|
||||
except Exception as e:
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
logging.error(e)
|
||||
logging.warning("No compatible Sangaboard hardware found.")
|
||||
else:
|
||||
|
|
@ -334,14 +332,14 @@ class Microscope:
|
|||
|
||||
# Load cached bits of metadata
|
||||
if cache_key:
|
||||
logging.debug(f"Reading cached microscope metadata: {cache_key}")
|
||||
logging.debug("Reading cached microscope metadata: %s", cache_key)
|
||||
metadata = self.metadata_cache.get(cache_key, None)
|
||||
if not metadata:
|
||||
logging.debug(f"Building and caching microscope metadata: {cache_key}")
|
||||
logging.debug("Building and caching microscope metadata: %s", cache_key)
|
||||
metadata = self.force_get_metadata()
|
||||
self.metadata_cache[cache_key] = metadata
|
||||
else:
|
||||
logging.debug(f"Building microscope metadata: {cache_key}")
|
||||
logging.debug("Building microscope metadata: %s", cache_key)
|
||||
metadata = self.force_get_metadata()
|
||||
|
||||
# Keys that should never be cached
|
||||
|
|
@ -367,7 +365,7 @@ class Microscope:
|
|||
metadata: dict = None,
|
||||
cache_key: str = None,
|
||||
):
|
||||
logging.debug(f"Microscope capturing to {filename}")
|
||||
logging.debug("Microscope capturing to %s", filename)
|
||||
if not annotations:
|
||||
annotations = {}
|
||||
if not metadata:
|
||||
|
|
@ -386,8 +384,7 @@ class Microscope:
|
|||
)
|
||||
|
||||
# Capture to output object
|
||||
logging.info(f"Starting microscope capture {output.file}")
|
||||
print(output)
|
||||
logging.info("Starting microscope capture %s", output.file)
|
||||
self.camera.capture(
|
||||
output,
|
||||
use_video_port=use_video_port,
|
||||
|
|
@ -397,6 +394,6 @@ class Microscope:
|
|||
)
|
||||
|
||||
output.put_and_save(tags, annotations, full_metadata)
|
||||
logging.debug(f"Finished capture to {output.file}")
|
||||
logging.debug("Finished capture to %s", output.file)
|
||||
|
||||
return output
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
# UTILITIES
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@ from openflexure_microscope.config import user_settings
|
|||
from openflexure_microscope.rescue.monitor_timeout import launch_timeout_test_process
|
||||
|
||||
|
||||
def check_capture_rebuild(timeout=10):
|
||||
def check_capture_rebuild():
|
||||
logging.info("Loading user settings...")
|
||||
settings = user_settings.load()
|
||||
|
||||
cap_path = str(settings.get("captures", {}).get("paths", {}).get("default"))
|
||||
logging.info(f"Capture path found: {cap_path}")
|
||||
logging.info("Capture path found: %s", cap_path)
|
||||
if not cap_path:
|
||||
logging.error(
|
||||
"No capture path defined in settings. This is unusual for anything other than a first-run. \nFalling back to default path."
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ def trace_config_exceptions():
|
|||
default_config = json.load(DEFAULT_CONFIGURATION_FILE_PATH)
|
||||
if not default_config:
|
||||
error_sources.append("default_config_empty")
|
||||
except Exception as e:
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
logging.error("Error parsing config:")
|
||||
logging.error(e)
|
||||
error_sources.append("default_config_error")
|
||||
|
|
@ -25,7 +25,7 @@ def trace_config_exceptions():
|
|||
default_settings = json.load(SETTINGS_FILE_PATH)
|
||||
if not default_settings:
|
||||
error_sources.append("default_settings_empty")
|
||||
except Exception as e:
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
logging.error("Error parsing settings:")
|
||||
logging.error(e)
|
||||
error_sources.append("default_settings_error")
|
||||
|
|
@ -37,8 +37,8 @@ def main():
|
|||
error_sources = []
|
||||
logging.info("Attempting default settings and config import...")
|
||||
try:
|
||||
from openflexure_microscope import config
|
||||
except Exception as e:
|
||||
from openflexure_microscope import config as _
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
error_sources.append("config_settings_import_error")
|
||||
logging.error("Error importing config:")
|
||||
logging.error(e)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
class ServiceMonitor(object):
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ def launch_timeout_test_process(target, args=(), kwargs=None, timeout=10):
|
|||
# If thread is still active
|
||||
if p.is_alive():
|
||||
logging.error(
|
||||
f"Function {target} reached timeout after {timeout} seconds. Terminating."
|
||||
"Function %s reached timeout after %s seconds. Terminating.",
|
||||
target,
|
||||
timeout,
|
||||
)
|
||||
|
||||
# Terminate
|
||||
|
|
|
|||
|
|
@ -17,36 +17,30 @@ class BaseStage(metaclass=ABCMeta):
|
|||
@abstractmethod
|
||||
def update_settings(self, config: dict):
|
||||
"""Update settings from a config dictionary"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def read_settings(self):
|
||||
"""Return the current settings as a dictionary"""
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def state(self):
|
||||
"""The general state dictionary of the board."""
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def configuration(self):
|
||||
"""The general stage configuration."""
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def n_axes(self):
|
||||
"""The number of axes this stage has."""
|
||||
pass
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def position(self):
|
||||
"""The current position, as a list"""
|
||||
pass
|
||||
|
||||
@property
|
||||
def position_map(self):
|
||||
|
|
@ -56,36 +50,30 @@ class BaseStage(metaclass=ABCMeta):
|
|||
@abstractmethod
|
||||
def backlash(self):
|
||||
"""Get the distance used for backlash compensation."""
|
||||
pass
|
||||
|
||||
@backlash.setter
|
||||
@abstractmethod
|
||||
def backlash(self):
|
||||
"""Set the distance used for backlash compensation."""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def move_rel(self, displacement, backlash=True):
|
||||
def move_rel(self, displacement: list, axis=None, backlash=True):
|
||||
"""Make a relative move, optionally correcting for backlash.
|
||||
displacement: integer or array/list of 3 integers
|
||||
backlash: (default: True) whether to correct for backlash.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def move_abs(self, final, **kwargs):
|
||||
"""Make an absolute move to a position"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def zero_position(self):
|
||||
"""Set the current position to zero"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def close(self):
|
||||
"""Cleanly close communication with the stage"""
|
||||
pass
|
||||
|
||||
def scan_linear(self, rel_positions, backlash=True, return_to_start=True):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from openflexure_microscope.utilities import axes_to_array
|
|||
|
||||
|
||||
class MissingStage(BaseStage):
|
||||
def __init__(self, port=None, **kwargs):
|
||||
def __init__(self, *args, **kwargs): # pylint: disable=unused-argument
|
||||
BaseStage.__init__(self)
|
||||
self._position = [0, 0, 0]
|
||||
self._n_axis = 3
|
||||
|
|
@ -66,11 +66,8 @@ class MissingStage(BaseStage):
|
|||
else:
|
||||
self._backlash = np.array([int(blsh)] * self.n_axes, dtype=np.int)
|
||||
|
||||
def move_rel(
|
||||
self, displacement: list, axis=None, backlash=True, simulate_time: bool = True
|
||||
):
|
||||
if simulate_time:
|
||||
time.sleep(0.5)
|
||||
def move_rel(self, displacement: list, axis=None, backlash=True):
|
||||
time.sleep(0.5)
|
||||
if axis is not None:
|
||||
assert axis in self.axis_names, "axis must be one of {}".format(
|
||||
self.axis_names
|
||||
|
|
@ -83,14 +80,13 @@ class MissingStage(BaseStage):
|
|||
|
||||
self._position = list(np.array(self._position) + np.array(initial_move))
|
||||
logging.debug(np.array(self._position) + np.array(initial_move))
|
||||
logging.debug(f"New position: {self._position}")
|
||||
logging.debug("New position: %s", self._position)
|
||||
|
||||
def move_abs(self, final, simulate_time: bool = True, **kwargs):
|
||||
if simulate_time:
|
||||
time.sleep(0.5)
|
||||
def move_abs(self, final, **kwargs):
|
||||
time.sleep(0.5)
|
||||
|
||||
self._position = list(final)
|
||||
logging.debug(f"New position: {self._position}")
|
||||
logging.debug("New position: %s", self._position)
|
||||
|
||||
def zero_position(self):
|
||||
"""Set the current position to zero"""
|
||||
|
|
|
|||
|
|
@ -29,10 +29,12 @@ class SangaStage(BaseStage):
|
|||
self.board = Sangaboard(port, **kwargs)
|
||||
|
||||
self._backlash = (
|
||||
None
|
||||
) # Initialise backlash storage, used by property setter/getter
|
||||
None # Initialise backlash storage, used by property setter/getter
|
||||
)
|
||||
self.axis_names = ["x", "y", "z"] # Assume all sangaboards are 3 axis
|
||||
|
||||
self._position_on_enter = None
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""The general state dictionary of the board."""
|
||||
|
|
@ -111,7 +113,7 @@ class SangaStage(BaseStage):
|
|||
backlash: (default: True) whether to correct for backlash.
|
||||
"""
|
||||
with self.lock:
|
||||
logging.debug(f"Moving sangaboard by {displacement}")
|
||||
logging.debug("Moving sangaboard by %s", displacement)
|
||||
if not backlash or self.backlash is None:
|
||||
return self.board.move_rel(displacement, axis=axis)
|
||||
if axis is not None:
|
||||
|
|
@ -148,7 +150,7 @@ class SangaStage(BaseStage):
|
|||
"""Make an absolute move to a position
|
||||
"""
|
||||
with self.lock:
|
||||
logging.debug(f"Moving sangaboard to {final}")
|
||||
logging.debug("Moving sangaboard to %s", final)
|
||||
self.board.move_abs(final, **kwargs)
|
||||
|
||||
def zero_position(self):
|
||||
|
|
@ -171,12 +173,12 @@ class SangaStage(BaseStage):
|
|||
self._position_on_enter = self.position
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(self, type_, value, traceback):
|
||||
"""The end of the with statement. Reset position if it went wrong.
|
||||
NB the instrument is closed when the object is deleted, so we don't
|
||||
need to worry about that here.
|
||||
"""
|
||||
if type is not None:
|
||||
if type_ is not None:
|
||||
print(
|
||||
"An exception occurred inside a with block, resetting position \
|
||||
to its value at the start of the with block"
|
||||
|
|
@ -184,7 +186,7 @@ class SangaStage(BaseStage):
|
|||
try:
|
||||
time.sleep(0.5)
|
||||
self.move_abs(self._position_on_enter)
|
||||
except Exception as e:
|
||||
except Exception as e: # pylint: disable=W0703
|
||||
print(
|
||||
"A further exception occurred when resetting position: {}".format(e)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import base64
|
|||
import copy
|
||||
import logging
|
||||
import operator
|
||||
import re
|
||||
import time
|
||||
from collections import abc
|
||||
from contextlib import contextmanager
|
||||
|
|
@ -21,9 +20,9 @@ class Timer(object):
|
|||
def __enter__(self):
|
||||
self.start = time.time()
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
def __exit__(self, type_, value, traceback):
|
||||
self.end = time.time()
|
||||
logging.debug(f"{self.name} time: {self.end - self.start}")
|
||||
logging.debug("%s time: %s", self.name, self.end - self.start)
|
||||
|
||||
|
||||
def deserialise_array_b64(b64_string, dtype, shape):
|
||||
|
|
|
|||
|
|
@ -72,3 +72,7 @@ force_grid_wrap = 0
|
|||
use_parentheses = true
|
||||
ensure_newline_before_comments = true
|
||||
line_length = 88
|
||||
|
||||
[tool.pylint.'MESSAGES CONTROL']
|
||||
disable = "C0330, C0326, W1202, W0511, C, R"
|
||||
max-line-length = 88
|
||||
Loading…
Add table
Add a link
Reference in a new issue