Went on a PEP-8 rampage

This commit is contained in:
Joel Collins 2019-01-31 17:20:46 +00:00
parent f99ad30fb6
commit 0948c9308a
36 changed files with 186 additions and 218 deletions

View file

@ -1,31 +1,16 @@
#!/usr/bin/env python
"""
TODO: Implement API route to cleanly shut down server
TODO: Implement plugin API routes somehow
"""
import numpy as np
from importlib import import_module
import time
import datetime
import os
from flask import (
Flask, render_template, Response, url_for,
redirect, request, jsonify, send_file, abort,
make_response)
from flask.views import MethodView
from werkzeug.exceptions import default_exceptions
from serial import SerialException
Flask, render_template)
from flask_cors import CORS
from openflexure_microscope.api.utilities import list_routes
from openflexure_microscope.api.exceptions import JSONExceptionHandler
from openflexure_microscope import Microscope
from openflexure_microscope.exceptions import LockError
from openflexure_microscope.camera.pi import StreamingCamera
from openflexure_microscope.stage.openflexure import Stage

View file

@ -2,6 +2,7 @@ from flask import jsonify
from werkzeug.exceptions import default_exceptions
from werkzeug.exceptions import HTTPException
class JSONExceptionHandler(object):
def __init__(self, app=None):
@ -24,7 +25,6 @@ class JSONExceptionHandler(object):
}
return jsonify(response)
def init_app(self, app):
self.app = app
self.register(HTTPException)

View file

@ -1,8 +1,8 @@
import pprint
import logging
import copy
from werkzeug.exceptions import BadRequest
class JsonPayload:
def __init__(self, request):
"""
@ -60,8 +60,7 @@ def gen(camera):
def get_bool(get_arg):
"""Convert GET request argument string to a Python bool"""
if (
get_arg == 'true' or
if (get_arg == 'true' or
get_arg == 'True' or
get_arg == '1'):
return True

View file

@ -197,4 +197,4 @@ def construct_blueprint(microscope_obj):
view_func=ConfigAPI.as_view('config', microscope=microscope_obj)
)
return(blueprint)
return blueprint

View file

@ -2,9 +2,7 @@ from openflexure_microscope.api.utilities import gen, get_bool, JsonPayload
from openflexure_microscope.api.v1.views import MicroscopeView
from openflexure_microscope.utilities import filter_dict
from flask import Response, Blueprint, jsonify, request, abort, url_for, redirect, send_file
import logging
from flask import Response, jsonify, request, abort, url_for, redirect, send_file
class ListAPI(MicroscopeView):
@ -368,7 +366,7 @@ class MetadataAPI(MicroscopeView):
# If no filename is specified, redirect to the capture's currently set filename
if not filename:
return redirect(url_for('capture_download', capture_id=capture_id, filename=capture_obj.metadataname, as_attachment=as_attachment), code=307)
return redirect(url_for('capture_download', capture_id=capture_id, filename=capture_obj.metadataname), code=307)
# Download the metadata using the requested filename
data = capture_obj.yaml
@ -377,6 +375,7 @@ class MetadataAPI(MicroscopeView):
data,
mimetype="text/yaml")
class TagsAPI(MicroscopeView):
def get(self, capture_id):
"""
@ -402,7 +401,7 @@ class TagsAPI(MicroscopeView):
if not capture_obj or not capture_obj.state['available']:
return abort(404) # 404 Not Found
metadata_tags = filter_dict(capture_obj.state, ('metadata', 'tags'))
metadata_tags = filter_dict(capture_obj.state, ['metadata', 'tags'])
return jsonify(metadata_tags)
@ -440,7 +439,7 @@ class TagsAPI(MicroscopeView):
for tag in data_dict:
capture_obj.put_tag(str(tag))
metadata_tags = filter_dict(capture_obj.state, ('metadata', 'tags'))
metadata_tags = filter_dict(capture_obj.state, ['metadata', 'tags'])
return jsonify(metadata_tags)
@ -477,6 +476,6 @@ class TagsAPI(MicroscopeView):
for tag in data_dict:
capture_obj.delete_tag(str(tag))
metadata_tags = filter_dict(capture_obj.state, ('metadata', 'tags'))
metadata_tags = filter_dict(capture_obj.state, ['metadata', 'tags'])
return jsonify(metadata_tags)

View file

@ -1,9 +1,7 @@
from openflexure_microscope.api.v1.views import MicroscopeView
from openflexure_microscope.api.utilities import JsonPayload
from flask import Response, Blueprint, jsonify, request, abort, url_for, redirect, send_file
import logging
from flask import jsonify, request
class ZoomAPI(MicroscopeView):

View file

@ -1,8 +1,6 @@
from openflexure_microscope.api.v1.views import MicroscopeView
from flask import Response, Blueprint, jsonify, request, abort, url_for, redirect, send_file
import logging
from flask import jsonify
class GPUPreviewAPI(MicroscopeView):

View file

@ -1,11 +1,12 @@
from openflexure_microscope.api.v1.views import MicroscopeViewPlugin
from flask import Response, Blueprint, jsonify
from flask import Blueprint
import logging, warnings
import logging
import warnings
def construct_blueprint(microscope_obj, plugin_paths=[], include_default=True):
def construct_blueprint(microscope_obj):
blueprint = Blueprint('plugin_blueprint', __name__)
@ -56,4 +57,4 @@ def construct_blueprint(microscope_obj, plugin_paths=[], include_default=True):
"No valid 'api_views' dictionary found in {}".format(plugin_obj)
)
return(blueprint)
return blueprint

View file

@ -2,7 +2,7 @@ from openflexure_microscope.api.utilities import gen, JsonPayload
from openflexure_microscope.api.v1.views import MicroscopeView
from openflexure_microscope.utilities import axes_to_array, filter_dict
from flask import Response, Blueprint, jsonify, request
from flask import Blueprint, jsonify, request
import logging
@ -42,7 +42,7 @@ class PositionAPI(MicroscopeView):
}
"""
out = filter_dict(self.microscope.state, ('stage', 'position'))
out = filter_dict(self.microscope.state, ['stage', 'position'])
return jsonify(out)
def post(self):
@ -85,7 +85,7 @@ class PositionAPI(MicroscopeView):
with self.microscope.stage.lock:
self.microscope.stage.move_rel(position)
out = filter_dict(self.microscope.state, ('stage', 'position'))
out = filter_dict(self.microscope.state, ['stage', 'position'])
return jsonify(out)
@ -99,4 +99,4 @@ def construct_blueprint(microscope_obj):
view_func=PositionAPI.as_view('position', microscope=microscope_obj)
)
return(blueprint)
return blueprint

View file

@ -1,6 +1,7 @@
from openflexure_microscope.api.v1.views import MicroscopeView
from flask import jsonify, abort, Blueprint
class TaskListAPI(MicroscopeView):
def get(self):
@ -65,6 +66,7 @@ class TaskListAPI(MicroscopeView):
return jsonify(data)
class TaskAPI(MicroscopeView):
def get(self, task_id):
@ -135,6 +137,7 @@ class TaskAPI(MicroscopeView):
return jsonify(data)
def construct_blueprint(microscope_obj):
blueprint = Blueprint('task_blueprint', __name__)
@ -149,4 +152,4 @@ def construct_blueprint(microscope_obj):
view_func=TaskAPI.as_view('task', microscope=microscope_obj)
)
return(blueprint)
return blueprint

View file

@ -1,9 +1,7 @@
# -*- coding: utf-8 -*-
import time
import io
import os
import threading
from PIL import Image
import datetime
import yaml
import logging
@ -35,6 +33,18 @@ def generate_basename():
return datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
def generate_numbered_basename(obj_list: list) -> str:
initial_basename = generate_basename()
basename = initial_basename
# Handle clashing
iterator = 1
while basename in [obj.basename for obj in obj_list]:
basename = initial_basename + "_{}".format(iterator)
iterator += 1
return basename
class CameraEvent(object):
"""
A frame-signaller object used by any instances or subclasses of BaseCamera.
@ -79,18 +89,6 @@ class CameraEvent(object):
self.events[get_ident()][0].clear()
def generate_basename(obj_list: list) -> str:
initial_basename = generate_basename()
basename = initial_basename
# Handle clashing
iterator = 1
while basename in [obj.basename for obj in obj_list]:
basename = initial_basename + "_{}".format(iterator)
iterator += 1
return basename
class BaseCamera(object):
"""
Base implementation of StreamingCamera.
@ -217,13 +215,13 @@ class BaseCamera(object):
"""Return the latest recorded video."""
return last_entry(self.videos)
def image_from_id(self, id):
def image_from_id(self, image_id):
"""Return an image StreamObject with a matching ID."""
return entry_by_id(id, self.images)
return entry_by_id(image_id, self.images)
def video_from_id(self, id):
def video_from_id(self, video_id):
"""Return a video StreamObject with a matching ID."""
return entry_by_id(id, self.videos)
return entry_by_id(video_id, self.videos)
# MANAGE CAPTURE DATABASE
@ -280,22 +278,21 @@ class BaseCamera(object):
write_to_file: bool = False,
temporary: bool = True,
filename: str = None,
fmt: str='jpeg',
shunt_others: bool=True):
fmt: str = 'jpeg'):
"""
Create a new image capture object. Adds to the image list, and shunt all others.
Args:
write_to_file (bool): Should the StreamObject write to a file, or an in-memory byte stream.
keep_on_disk (bool): Should the data be deleted after session ends. Creating the capture with a content manager sets this to true.
temporary (bool): Should the data be deleted after session ends. Creating the capture with a content manager sets this to true.
filename (str): Name of the stored file. Defaults to timestamp.
fmt (str): Format of the capture.
"""
# Generate file name
if not filename:
filename = generate_basename(self.images)
filename = generate_numbered_basename(self.images)
logging.debug(filename)
# Create capture object
@ -320,8 +317,7 @@ class BaseCamera(object):
write_to_file: bool = True,
temporary: bool = False,
filename: str = None,
fmt: str='h264',
shunt_others: bool=True):
fmt: str = 'h264'):
"""
Create a new video capture object. Adds to the image list, and shunt all others.
@ -335,7 +331,7 @@ class BaseCamera(object):
# Generate file name
if not filename:
filename = generate_basename(self.videos)
filename = generate_numbered_basename(self.videos)
logging.debug(filename)
# Create capture object

View file

@ -15,6 +15,7 @@ thumbnail_size = (60, 60)
BASE_CAPTURE_PATH = os.path.join(os.path.expanduser('~'), 'micrographs')
TEMP_CAPTURE_PATH = os.path.join(BASE_CAPTURE_PATH, 'tmp')
def clear_tmp():
global TEMP_CAPTURE_PATH
@ -24,6 +25,7 @@ def clear_tmp():
os.remove(f)
logging.debug("Removed {}".format(f))
def capture_from_dict(capture_dict):
capture = CaptureObject(create_metadata_file=False) # Create a placeholder capture
@ -48,6 +50,7 @@ class CaptureObject(object):
Note: Captures cannot be stored in a lower-level directory than BASE_CAPTURE_PATH.
"""
def __init__(
self,
write_to_file: bool = False,
@ -102,7 +105,9 @@ class CaptureObject(object):
def __enter__(self):
"""Create StreamObject in context, to auto-clean disk data."""
logging.debug("Entering context for {}. Stored files will be cleaned up automatically regardless of location.".format(self.id))
logging.debug(
"Entering context for {}. Stored files will be cleaned up automatically regardless of location.".format(
self.id))
self.temporary = True # Flag file to be removed on close.
self.context_manager = True # Used in metadata
@ -170,7 +175,8 @@ class CaptureObject(object):
def split_file_path(self, filepath):
"""Takes a full file path, and splits it into separated class properties."""
self.filefolder, self.filename = os.path.split(filepath) # Split the full file path into a folder and a filename
self.filefolder, self.filename = os.path.split(
filepath) # Split the full file path into a folder and a filename
self.basename = os.path.splitext(self.filename)[0] # Split the filename out from it's file extension
self.metadataname = "{}.yaml".format(self.basename)
@ -234,18 +240,10 @@ class CaptureObject(object):
@property
def metadata(self) -> dict:
# Create basic metadata dictionary
d = {
'id': self.id,
'filename': self.filename,
'path': self.file,
'time': self.timestring,
'format': self.format,
'tags': self.tags
}
d = {'id': self.id, 'filename': self.filename, 'path': self.file, 'time': self.timestring,
'format': self.format, 'tags': self.tags, 'custom': self._metadata}
# Add custom metadata to dictionary
d['custom'] = self._metadata
return d
@property
@ -261,14 +259,10 @@ class CaptureObject(object):
"""Return dictionary of StreamObject properties."""
# Create basic state dictionary
d = {
'locked': self.locked,
'temporary': self.temporary,
}
d = {'locked': self.locked, 'temporary': self.temporary, 'metadata': self.metadata,
'metadata_path': self.metadata_file}
# Add metadata to state
d['metadata'] = self.metadata
d['metadata_path'] = self.metadata_file
# Check bytestream
if self.stream_exists:
@ -404,4 +398,5 @@ class CaptureObject(object):
if self.temporary:
self.delete()
atexit.register(clear_tmp)

View file

@ -36,7 +36,6 @@ def to_map(data, func):
Args:
data: Input iterable data
func: Function to apply to all non-iterable values
excluded_keys: Any dictionary keys to exclude from the returned data
"""
# If the object is a dictionary
if isinstance(data, abc.Mapping):
@ -58,7 +57,6 @@ def json_map(data, clean_keys=True):
Args:
data: Input dictionary
clean_keys: Modify any keys unsuitable for JSON return
"""
# Do not overwrite original data dictionary

View file

@ -1,8 +1,10 @@
from threading import ThreadError
class TaskDeniedException(Exception):
pass
class LockError(ThreadError):
ERROR_CODES = {
'ACQUIRE_ERROR': "Unable to acquire. Lock in use by another thread.",

View file

@ -3,7 +3,6 @@
Defines a microscope object, binding a camera and stage with basic functionality.
"""
import logging
import os
import numpy as np
import uuid

View file

@ -3,15 +3,15 @@ import numpy as np
from openflexure_microscope.api.v1.views import MicroscopeViewPlugin
from openflexure_microscope.api.utilities import JsonPayload
from flask import request, Response, escape, jsonify
from flask import request, jsonify
import logging
class MeasureSharpnessAPI(MicroscopeViewPlugin):
def post(self):
payload = JsonPayload(request)
return jsonify({'sharpness': self.plugin.measure_sharpness()})
class AutofocusAPI(MicroscopeViewPlugin):
def post(self):
payload = JsonPayload(request)

View file

@ -1,11 +1,13 @@
import numpy as np
from scipy import ndimage
def decimate_to(shape, image):
"""Decimate an image to reduce its size if it's too big."""
decimation = np.max(np.ceil(np.array(image.shape, dtype=np.float)[:len(shape)]/np.array(shape)))
return image[::int(decimation), ::int(decimation), ...]
def sharpness_sum_lap2(rgb_image):
"""Return an image sharpness metric: sum(laplacian(image)**")"""
# image_bw=np.mean(decimate_to((1000,1000), rgb_image),2)
@ -13,6 +15,7 @@ def sharpness_sum_lap2(rgb_image):
image_lap = ndimage.filters.laplace(image_bw)
return np.mean(image_lap.astype(np.float)**4)
def sharpness_edge(image):
"""Return a sharpness metric optimised for vertical lines"""
gray = np.mean(image.astype(float), 2)

View file

@ -34,7 +34,7 @@ class AutofocusPlugin(MicroscopePlugin):
positions = []
camera.annotate_text = ""
for i in stage.scan_z(dz, return_to_start=False):
for _ in stage.scan_z(dz, return_to_start=False):
positions.append(stage.position[2])
time.sleep(settle)
sharpnesses.append(self.measure_sharpness(metric_fn))

View file

@ -1,28 +1,26 @@
import time
import numpy as np
from openflexure_microscope.plugins import MicroscopePlugin
from openflexure_microscope.utilities import set_properties
from openflexure_microscope.api.v1.views import MicroscopeViewPlugin
from openflexure_microscope.api.utilities import JsonPayload
from flask import request, Response, escape, jsonify
from flask import request, jsonify
import logging
from .recalibrate_utils import recalibrate_camera
class RecalibrateAPIView(MicroscopeViewPlugin):
def post(self):
payload = JsonPayload(request)
# Figure out the range of z values to use
# TODO: Figure out the range of z values to use
print("Starting microscope recalibration...")
task = self.microscope.task.start(self.plugin.recalibrate)
# return a handle on the autofocus task
# Return a handle on the autofocus task
return jsonify(task.state, 202)
class Plugin(MicroscopePlugin):
"""
A set of default plugins
@ -56,5 +54,3 @@ class Plugin(MicroscopePlugin):
if streaming:
logging.info("Restarting stream after recalibration")
scamera.start_stream_recording()

View file

@ -3,12 +3,14 @@ from picamera import PiCamera
from picamera.array import PiRGBArray, PiBayerArray
import time
def rgb_image(camera, resize=None, **kwargs):
"""Capture an image and return an RGB numpy array"""
with PiRGBArray(camera, size=resize) as output:
camera.capture(output, format='rgb', resize=resize, **kwargs)
return output.array
def flat_lens_shading_table(camera):
"""Return a flat (i.e. unity gain) lens shading table.
@ -20,6 +22,7 @@ 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
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="")
@ -29,6 +32,7 @@ def adjust_exposure_to_setpoint(camera, setpoint):
time.sleep(1)
print("done")
def auto_expose_and_freeze_settings(camera):
"""Freeze the settings after auto-exposing to white illumination"""
print("Allowing the camera to auto-expose")
@ -62,6 +66,7 @@ def channels_from_bayer_array(bayer_array):
return channels
def lst_from_channels(channels):
"""Given the 4 Bayer colour channels from a white image, generate a LST."""
full_resolution = np.array(channels.shape[1:]) * 2 # channels have been binned
@ -85,7 +90,11 @@ def lst_from_channels(channels):
padded_image_channel = np.pad(image_channel,
[(0, lw*32 - iw), (0, lh*32 - ih)],
mode="edge") # Pad image to the right and bottom
print("Channel shape: {}x{}, shading table shape: {}x{}, after padding {}".format(iw,ih,lw*32,lh*32,padded_image_channel.shape))
print("Channel shape: {}x{}, shading table shape: {}x{}, after padding {}".format(iw,
ih,
lw*32,
lh*32,
padded_image_channel.shape))
# Next, fill the shading table (except edge pixels). Please excuse the
# for loop - I know it's not fast but this code needn't be!
box = 3 # We average together a square of this side length for each pixel.
@ -113,6 +122,7 @@ def lst_from_channels(channels):
lens_shading_table = gains.astype(np.uint8)
return lens_shading_table[::-1, :, :].copy()
def recalibrate_camera(camera):
"""Reset the lens shading table and exposure settings.
@ -124,7 +134,7 @@ def recalibrate_camera(camera):
``StreamingCamera``.
"""
camera.lens_shading_table = flat_lens_shading_table(camera)
discarded = rgb_image(camera) # for some reason the camera won't work unless I do this!
_ = rgb_image(camera) # for some reason the camera won't work unless I do this!
with PiBayerArray(camera) as a:
camera.capture(a, format="jpeg", bayer=True)
@ -132,18 +142,19 @@ def recalibrate_camera(camera):
# Now we need to calculate a lens shading table that would make this flat.
# raw_image is a 3D array, with full resolution and 3 colour channels. No
# demosaicing has been done, so 2/3 of the values are zero (3/4 for R and B
# channels, 1/2 for green because there's twize as many green pixels).
# de-mosaicing has been done, so 2/3 of the values are zero (3/4 for R and B
# channels, 1/2 for green because there's twice as many green pixels).
channels = channels_from_bayer_array(raw_image)
lens_shading_table = lst_from_channels(channels)
camera.lens_shading_table = lens_shading_table
test = rgb_image(camera)
_ = rgb_image(camera)
# Fix the AWB gains so the image is neutral
channel_means = np.mean(np.mean(rgb_image(camera), axis=0, dtype=np.float), axis=0)
old_gains = camera.awb_gains
camera.awb_gains = (channel_means[1]/channel_means[0] * old_gains[0], channel_means[1]/channel_means[2]*old_gains[1])
camera.awb_gains = (channel_means[1]/channel_means[0] * old_gains[0],
channel_means[1]/channel_means[2]*old_gains[1])
time.sleep(1)
# Ensure the background is bright but not saturated
adjust_exposure_to_setpoint(camera, 230)
@ -157,4 +168,3 @@ if __name__ == "__main__":
recalibrate_camera(camera)
print("Done.")
time.sleep(2)

View file

@ -4,8 +4,6 @@ from openflexure_microscope.exceptions import TaskDeniedException
from flask import request, Response, escape, jsonify, abort
import logging
class IdentifyAPI(MicroscopeViewPlugin):
"""
@ -53,6 +51,7 @@ class HelloWorldAPI(MicroscopeViewPlugin):
return Response(self.microscope.plugin_string)
class LongRunningAPI(MicroscopeViewPlugin):
"""
An example API plugin that uses a long-running plugin method.
@ -75,6 +74,7 @@ class LongRunningAPI(MicroscopeViewPlugin):
except TaskDeniedException:
return abort(409)
class SomeExceptionAPI(MicroscopeViewPlugin):
"""
An example API plugin that uses a long-running but broken plugin method.

View file

@ -4,7 +4,7 @@ import inspect
import logging
class bcolors:
class ConColors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
@ -23,7 +23,7 @@ def module_from_file(plugin_path):
# Check if the path is to a file
if not os.path.isfile(plugin_path):
logging.warning(bcolors.FAIL + "No valid plugin found at {}.".format(plugin_path) + bcolors.ENDC)
logging.warning(ConColors.FAIL + "No valid plugin found at {}.".format(plugin_path) + ConColors.ENDC)
return None, None, None
else:
@ -63,6 +63,7 @@ def check_module(module_path):
# If all checks pass, return True
return True
def name_from_module(plugin_path):
path_array = plugin_path.split('.')
@ -100,7 +101,7 @@ def load_plugin_class(plugin_path, plugin_class_name):
try:
plugin_class = getattr(plugin_module, plugin_class_name)
except AttributeError:
logging.warning(bcolors.FAIL + "Class {} does not exist in plugin {}. Skipping.".format(plugin_class_name, plugin_path) + bcolors.ENDC)
logging.warning(ConColors.FAIL + "Class {} does not exist in plugin {}. Skipping.".format(plugin_class_name, plugin_path) + ConColors.ENDC)
return None, None
else:
return plugin_class, plugin_name
@ -112,7 +113,7 @@ def class_from_map(plugin_map):
plugin_arr = plugin_map.split(':')
if not len(plugin_arr) == 2:
logging.warning(bcolors.WARNING + "Malformed plugin map {}. Skipping.".format(plugin_map) + bcolors.ENDC)
logging.warning(ConColors.WARNING + "Malformed plugin map {}. Skipping.".format(plugin_map) + ConColors.ENDC)
return None, None
else:
return load_plugin_class(*plugin_arr)
@ -155,7 +156,7 @@ class PluginMount(object):
plugin_object = plugin_class()
if hasattr(self, plugin_name): # If a plugin with the same name is already attached.
logging.warning(bcolors.WARNING + "A plugin named {} has already been loaded. Skipping {}.".format(plugin_name, plugin_map) + bcolors.ENDC)
logging.warning(ConColors.WARNING + "A plugin named {} has already been loaded. Skipping {}.".format(plugin_name, plugin_map) + ConColors.ENDC)
elif isinstance(plugin_object, MicroscopePlugin): # If plugin_object is an instance of MicroscopePlugin
# Attach plugin_object to the plugin mount
@ -165,10 +166,10 @@ class PluginMount(object):
# Grant plugin access to the hardware
plugin_object.microscope = self.parent
logging.info(bcolors.OKGREEN + "Plugin {} loaded as {}.".format(plugin_map, plugin_name) + bcolors.ENDC)
logging.info(ConColors.OKGREEN + "Plugin {} loaded as {}.".format(plugin_map, plugin_name) + ConColors.ENDC)
class MicroscopePlugin():
class MicroscopePlugin:
"""
Parent class for all microscope plugins.

View file

@ -10,4 +10,4 @@ class Plugin(MicroscopePlugin):
"""
Tests for access to Microscope.camera, and Microscope.stage
"""
return (self.microscope.camera, self.microscope.stage)
return self.microscope.camera, self.microscope.stage

View file

@ -5,6 +5,7 @@ from openflexure_microscope.lock import StrictLock
import logging
# TODO: Implement lock on movement
class Stage(OpenFlexureStage):
def __init__(self, *args, **kwargs):
@ -16,7 +17,7 @@ class Stage(OpenFlexureStage):
try:
OpenFlexureStage.__init__(self, *args, **kwargs)
except SerialException as e:
except SerialException:
logging.error("No stage found. Aborting stage.")
logging.warning("Stage lock can be acquired, but any stage methods will fail and raise exceptions.")

View file

@ -1,14 +1,13 @@
from threading import Thread
from functools import wraps
import datetime
import logging
import traceback
import time
import uuid
from openflexure_microscope.exceptions import TaskDeniedException
from openflexure_microscope.utilities import entry_by_id
class TaskOrchestrator:
"""
Class responsible for spawning threaded tasks, and storing their returns.

View file

@ -1,9 +1,9 @@
import copy
import operator
from fractions import Fraction
from functools import reduce
from contextlib import contextmanager
@contextmanager
def set_properties(obj, **kwargs):
"""A context manager to set, then reset, certain properties of an object.
@ -25,7 +25,8 @@ def set_properties(obj, **kwargs):
for k, v in saved_properties.items():
setattr(obj, k, v)
def axes_to_array(coordinate_dictionary, axis_keys=['x', 'y', 'z'], base_array=None):
def axes_to_array(coordinate_dictionary, axis_keys=('x', 'y', 'z'), base_array=None):
"""Takes key-value pairs of a JSON value, and maps onto an array"""
# If no base array is given
if not base_array:
@ -42,6 +43,7 @@ def axes_to_array(coordinate_dictionary, axis_keys=['x', 'y', 'z'], base_array=N
return base_array
def filter_dict(dictionary: dict, keys: list):
# Get value by recursively applying getitem
val = reduce(operator.getitem, keys, dictionary)
@ -51,10 +53,11 @@ def filter_dict(dictionary: dict, keys: list):
return out
def entry_by_id(id: str, object_list: list):
def entry_by_id(entry_id: str, object_list: list):
"""Return an object from a list, if <object>.id matches id argument."""
found = None
for o in object_list:
if o.id == id:
if o.id == entry_id:
found = o
return found

View file

@ -3,6 +3,7 @@ from PIL import Image
from io import BytesIO
import numpy as np
class APIconnection:
def __init__(self, host="localhost", port=5000, api_ver="v1"):
self.base = self.build_base(host=host, port=port, api_ver=api_ver)

View file

@ -1,19 +1,11 @@
#!/usr/bin/env python
from api_client import APIconnection
import os
import io
import sys
import time
import numpy as np
import uuid
from PIL import Image
import unittest
from pprint import pprint
import logging, sys
import logging
import sys
logging.basicConfig(stream=sys.stderr, level=logging.INFO)
@ -66,6 +58,7 @@ class TestCapture(unittest.TestCase):
self.assertTrue(capture_array.shape == (resolution[1], resolution[0], 3))
class TestStage(unittest.TestCase):
def test_stage_config(self):
@ -114,6 +107,7 @@ class TestStage(unittest.TestCase):
self.assertTrue(np.array_equal(diff, move))
if __name__ == '__main__':
suites = [

View file

@ -3,17 +3,15 @@ from openflexure_microscope.camera.pi import StreamingCamera, CaptureObject
import os
import io
import sys
import time
import numpy as np
import uuid
from PIL import Image
import unittest
from pprint import pprint
import logging, sys
import logging
import sys
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)

View file

@ -46,4 +46,3 @@ if __name__ == '__main__':
alltests = unittest.TestSuite(suites)
result = unittest.TextTestRunner(verbosity=2).run(alltests)

View file

@ -1,21 +1,13 @@
#!/usr/bin/env python
from openflexure_microscope.camera.pi import StreamingCamera
from openflexure_stage import OpenFlexureStage
from openflexure_microscope import Microscope
import os
import io
import sys
import time
import numpy as np
import uuid
from PIL import Image
import unittest
from pprint import pprint
import logging, sys
import logging
import sys
logging.basicConfig(stream=sys.stderr, level=logging.INFO)

View file

@ -4,9 +4,7 @@ from openflexure_microscope.camera.pi import StreamingCamera
from openflexure_microscope import config
import numpy as np
import sys
import time
import matplotlib.pyplot as plt
import os
import logging, sys