Blackened everything

This commit is contained in:
Joel Collins 2019-09-15 14:17:52 +01:00
parent e213647217
commit 5966ce29be
57 changed files with 1938 additions and 1414 deletions

View file

@ -1,3 +1,3 @@
__all__ = ['utilities']
__all__ = ["utilities"]
from . import utilities

View file

@ -6,8 +6,7 @@ import logging
import sys
import os
from flask import (
Flask, jsonify, send_file)
from flask import Flask, jsonify, send_file
from serial import SerialException
from datetime import datetime
@ -39,7 +38,7 @@ from openflexure_microscope.stage.mock import MockStage
# Handle logging
is_gunicorn = "gunicorn" in os.environ.get("SERVER_SOFTWARE", "")
DEFAULT_LOGFILE = os.path.join(USER_CONFIG_DIR, 'openflexure_microscope.log')
DEFAULT_LOGFILE = os.path.join(USER_CONFIG_DIR, "openflexure_microscope.log")
if (__name__ == "__main__") or (not is_gunicorn):
# If imported, but not by gunicorn
@ -48,18 +47,15 @@ if (__name__ == "__main__") or (not is_gunicorn):
else:
# Direct standard Python logging to file and console
root = logging.getLogger()
error_formatter = logging.Formatter("[%(asctime)s] [%(threadName)s] [%(levelname)s] %(message)s")
rotating_logfile = logging.handlers.RotatingFileHandler(
DEFAULT_LOGFILE,
maxBytes=1000000,
backupCount=7
error_formatter = logging.Formatter(
"[%(asctime)s] [%(threadName)s] [%(levelname)s] %(message)s"
)
error_handlers = [
rotating_logfile,
logging.StreamHandler()
]
rotating_logfile = logging.handlers.RotatingFileHandler(
DEFAULT_LOGFILE, maxBytes=1000000, backupCount=7
)
error_handlers = [rotating_logfile, logging.StreamHandler()]
for handler in error_handlers:
handler.setFormatter(error_formatter)
@ -88,7 +84,7 @@ def uri(suffix, api_version, base=None):
app = Flask(__name__)
app.url_map.strict_slashes = False
CORS(app, resources=r'/api/*')
CORS(app, resources=r"/api/*")
# Make errors more API friendly
handler = JSONExceptionHandler(app)
@ -121,10 +117,7 @@ def attach_microscope():
# Attach devices to microscope
logging.debug("Attaching devices to microscope...")
api_microscope.attach(
api_camera,
api_stage
)
api_microscope.attach(api_camera, api_stage)
# Restore loaded capture array to camera object
logging.debug("Restoring captures...")
@ -140,26 +133,26 @@ def attach_microscope():
# Base routes
base_blueprint = blueprints.base.construct_blueprint(api_microscope)
app.register_blueprint(base_blueprint, url_prefix=uri('', 'v1'))
app.register_blueprint(base_blueprint, url_prefix=uri("", "v1"))
# Stage routes
stage_blueprint = blueprints.stage.construct_blueprint(api_microscope)
app.register_blueprint(stage_blueprint, url_prefix=uri('/stage', 'v1'))
app.register_blueprint(stage_blueprint, url_prefix=uri("/stage", "v1"))
# Camera routes
camera_blueprint = blueprints.camera.construct_blueprint(api_microscope)
app.register_blueprint(camera_blueprint, url_prefix=uri('/camera', 'v1'))
app.register_blueprint(camera_blueprint, url_prefix=uri("/camera", "v1"))
# Plugin routes
plugin_blueprint = blueprints.plugins.construct_blueprint(api_microscope)
app.register_blueprint(plugin_blueprint, url_prefix=uri('/plugin', 'v1'))
app.register_blueprint(plugin_blueprint, url_prefix=uri("/plugin", "v1"))
# Task routes
task_blueprint = blueprints.task.construct_blueprint(api_microscope)
app.register_blueprint(task_blueprint, url_prefix=uri('/task', 'v1'))
app.register_blueprint(task_blueprint, url_prefix=uri("/task", "v1"))
@app.route('/routes')
@app.route("/routes")
def routes():
"""
List of all connected API routes
@ -173,7 +166,7 @@ def routes():
return jsonify(list_routes(app))
@app.route('/log')
@app.route("/log")
def err_log():
"""
Most recent 1mb of log output
@ -186,9 +179,9 @@ def err_log():
"""
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
return send_file(
DEFAULT_LOGFILE,
as_attachment=True,
attachment_filename='openflexure_microscope_{}.log'.format(timestamp)
DEFAULT_LOGFILE,
as_attachment=True,
attachment_filename="openflexure_microscope_{}.log".format(timestamp),
)
@ -219,4 +212,4 @@ def cleanup():
atexit.register(cleanup)
if __name__ == "__main__":
app.run(host='0.0.0.0', port="5000", threaded=True, debug=True, use_reloader=False)
app.run(host="0.0.0.0", port="5000", threaded=True, debug=True, use_reloader=False)

View file

@ -17,17 +17,14 @@ class JSONExceptionHandler(object):
def std_handler(self, error):
if isinstance(error, HTTPException):
message = error.description
elif hasattr(error, 'message'):
elif hasattr(error, "message"):
message = error.message
else:
message = str(error)
status_code = error.code if isinstance(error, HTTPException) else 500
response = {
'status_code': status_code,
'message': escape(message)
}
response = {"status_code": status_code, "message": escape(message)}
return jsonify(response), status_code
def init_app(self, app):

View file

@ -10,7 +10,9 @@ class JsonResponse:
"""
# Try to load as json
try:
self.json = request.get_json() #: dict: Dictionary representation of request JSON
self.json = (
request.get_json()
) #: dict: Dictionary representation of request JSON
# If malformed JSON is passed, make an empty dictionary
except BadRequest as e:
logging.error(e)
@ -55,15 +57,12 @@ def gen(camera):
# the obtained frame is a jpeg
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
yield (b"--frame\r\n" b"Content-Type: image/jpeg\r\n\r\n" + frame + b"\r\n")
def get_bool(get_arg):
"""Convert GET request argument string to a Python bool"""
if (get_arg == 'true' or
get_arg == 'True' or
get_arg == '1'):
if get_arg == "true" or get_arg == "True" or get_arg == "1":
return True
else:
return False
@ -80,10 +79,7 @@ def list_routes(app):
endpoint = rule.endpoint
methods = list(rule.methods)
url = url_for(rule.endpoint, **options)
line = {
'endpoint': endpoint,
'methods': methods
}
line = {"endpoint": endpoint, "methods": methods}
output[url] = line
return output
return output

View file

@ -6,7 +6,6 @@ import logging
class StreamAPI(MicroscopeView):
def get(self):
"""
Real-time MJPEG stream from the microscope camera
@ -22,11 +21,11 @@ class StreamAPI(MicroscopeView):
return Response(
gen(self.microscope.camera),
mimetype='multipart/x-mixed-replace; boundary=frame')
mimetype="multipart/x-mixed-replace; boundary=frame",
)
class StateAPI(MicroscopeView):
def get(self):
"""
JSON representation of the microscope object.
@ -77,7 +76,6 @@ class StateAPI(MicroscopeView):
class ConfigAPI(MicroscopeView):
def get(self):
"""
JSON representation of the microscope config.
@ -216,21 +214,18 @@ class ConfigAPI(MicroscopeView):
def construct_blueprint(microscope_obj):
blueprint = Blueprint('base_blueprint', __name__)
blueprint = Blueprint("base_blueprint", __name__)
blueprint.add_url_rule(
'/stream',
view_func=StreamAPI.as_view('stream', microscope=microscope_obj)
"/stream", view_func=StreamAPI.as_view("stream", microscope=microscope_obj)
)
blueprint.add_url_rule(
'/state',
view_func=StateAPI.as_view('state', microscope=microscope_obj)
"/state", view_func=StateAPI.as_view("state", microscope=microscope_obj)
)
blueprint.add_url_rule(
'/config',
view_func=ConfigAPI.as_view('config', microscope=microscope_obj)
"/config", view_func=ConfigAPI.as_view("config", microscope=microscope_obj)
)
return blueprint

View file

@ -7,51 +7,70 @@ from . import capture, record, preview, function
def construct_blueprint(microscope_obj):
blueprint = Blueprint('camera_blueprint', __name__)
blueprint = Blueprint("camera_blueprint", __name__)
# Metadata routes
blueprint.add_url_rule(
'/capture/<capture_id>/metadata/<filename>',
view_func=capture.MetadataAPI.as_view('metadata_download', microscope=microscope_obj))
"/capture/<capture_id>/metadata/<filename>",
view_func=capture.MetadataAPI.as_view(
"metadata_download", microscope=microscope_obj
),
)
blueprint.add_url_rule(
'/capture/<capture_id>/metadata',
view_func=capture.MetadataRedirectAPI.as_view('metadata_download_redirect', microscope=microscope_obj))
"/capture/<capture_id>/metadata",
view_func=capture.MetadataRedirectAPI.as_view(
"metadata_download_redirect", microscope=microscope_obj
),
)
# Tag routes
blueprint.add_url_rule(
'/capture/<capture_id>/tags',
view_func=capture.TagsAPI.as_view('capture_tags', microscope=microscope_obj))
"/capture/<capture_id>/tags",
view_func=capture.TagsAPI.as_view("capture_tags", microscope=microscope_obj),
)
# Capture routes
blueprint.add_url_rule(
'/capture/<capture_id>/download/<filename>',
view_func=capture.DownloadAPI.as_view('capture_download', microscope=microscope_obj))
"/capture/<capture_id>/download/<filename>",
view_func=capture.DownloadAPI.as_view(
"capture_download", microscope=microscope_obj
),
)
blueprint.add_url_rule(
'/capture/<capture_id>/download',
view_func=capture.DownloadRedirectAPI.as_view('capture_download_redirect', microscope=microscope_obj))
"/capture/<capture_id>/download",
view_func=capture.DownloadRedirectAPI.as_view(
"capture_download_redirect", microscope=microscope_obj
),
)
blueprint.add_url_rule(
'/capture/<capture_id>/',
view_func=capture.CaptureAPI.as_view('capture', microscope=microscope_obj))
"/capture/<capture_id>/",
view_func=capture.CaptureAPI.as_view("capture", microscope=microscope_obj),
)
blueprint.add_url_rule(
'/capture/',
view_func=capture.ListAPI.as_view('capture_list', microscope=microscope_obj))
"/capture/",
view_func=capture.ListAPI.as_view("capture_list", microscope=microscope_obj),
)
# Preview routes
blueprint.add_url_rule(
'/preview/<string:operation>',
view_func=preview.GPUPreviewAPI.as_view('gpu_preview', microscope=microscope_obj))
"/preview/<string:operation>",
view_func=preview.GPUPreviewAPI.as_view(
"gpu_preview", microscope=microscope_obj
),
)
# Function routes
blueprint.add_url_rule(
'/overlay',
view_func=function.OverlayAPI.as_view('overlay', microscope=microscope_obj))
"/overlay",
view_func=function.OverlayAPI.as_view("overlay", microscope=microscope_obj),
)
blueprint.add_url_rule(
'/zoom',
view_func=function.ZoomAPI.as_view('zoom', microscope=microscope_obj))
"/zoom", view_func=function.ZoomAPI.as_view("zoom", microscope=microscope_obj)
)
return(blueprint)
return blueprint

View file

@ -6,7 +6,6 @@ from flask import Response, jsonify, request, abort, url_for, redirect, send_fil
class ListAPI(MicroscopeView):
def get(self):
"""
Get list of image captures.
@ -30,12 +29,16 @@ class ListAPI(MicroscopeView):
:status 200: capture found
:status 404: no capture found with that id
"""
include_unavailable = get_bool(request.args.get('include_unavailable'))
include_unavailable = get_bool(request.args.get("include_unavailable"))
if include_unavailable:
captures = [image.state for image in self.microscope.camera.images]
else:
captures = [image.state for image in self.microscope.camera.images if image.state['available']]
captures = [
image.state
for image in self.microscope.camera.images
if image.state["available"]
]
return jsonify(captures)
@ -100,38 +103,40 @@ class ListAPI(MicroscopeView):
"""
payload = JsonResponse(request)
filename = payload.param('filename')
temporary = payload.param('temporary', default=False, convert=bool)
use_video_port = payload.param('use_video_port', default=False, convert=bool)
bayer = payload.param('bayer', default=True, convert=bool)
metadata = payload.param('metadata', default={}, convert=dict)
tags = payload.param('tags', default=[], convert=list)
filename = payload.param("filename")
temporary = payload.param("temporary", default=False, convert=bool)
use_video_port = payload.param("use_video_port", default=False, convert=bool)
bayer = payload.param("bayer", default=True, convert=bool)
metadata = payload.param("metadata", default={}, convert=dict)
tags = payload.param("tags", default=[], convert=list)
resize = payload.param('size', default=None)
resize = payload.param("size", default=None)
if resize:
if ('width' in resize) and ('height' in resize):
resize = (int(resize['width']), int(resize['height'])) # Convert dict to tuple
if ("width" in resize) and ("height" in resize):
resize = (
int(resize["width"]),
int(resize["height"]),
) # Convert dict to tuple
else:
abort(404)
# Explicitally acquire lock (prevents empty files being created if lock is unavailable)
with self.microscope.camera.lock:
output = self.microscope.camera.new_image(
write_to_file=True,
temporary=temporary,
filename=filename)
write_to_file=True, temporary=temporary, filename=filename
)
self.microscope.camera.capture(
output,
use_video_port=use_video_port,
resize=resize,
bayer=bayer)
output, use_video_port=use_video_port, resize=resize, bayer=bayer
)
metadata.update({
'position': self.microscope.state['stage']['position'],
'microscope_id': self.microscope.id,
'microscope_name': self.microscope.name
})
metadata.update(
{
"position": self.microscope.state["stage"]["position"],
"microscope_id": self.microscope.id,
"microscope_name": self.microscope.name,
}
)
output.put_metadata(metadata)
output.put_tags(tags)
@ -140,7 +145,6 @@ class ListAPI(MicroscopeView):
class CaptureAPI(MicroscopeView):
def get(self, capture_id):
"""
Get JSON representation of a capture
@ -200,14 +204,15 @@ class CaptureAPI(MicroscopeView):
# Add API routes to returned state
uri_dict = {
'uri': {'state': '{}'.format(url_for('.capture', capture_id=capture_obj.id))}
"uri": {
"state": "{}".format(url_for(".capture", capture_id=capture_obj.id))
}
}
# If available, also add download link
if capture_metadata['available']:
uri_dict['uri']['download'] = '{}download/{}'.format(
url_for('.capture', capture_id=capture_obj.id),
capture_obj.filename
if capture_metadata["available"]:
uri_dict["uri"]["download"] = "{}download/{}".format(
url_for(".capture", capture_id=capture_obj.id), capture_obj.filename
)
capture_metadata.update(uri_dict)
@ -257,7 +262,7 @@ class CaptureAPI(MicroscopeView):
if not capture_obj:
return abort(404) # 404 Not Found
data_dict = JsonResponse(request).json
capture_obj.put_metadata(data_dict)
@ -299,17 +304,20 @@ class DownloadRedirectAPI(MicroscopeView):
"""
capture_obj = self.microscope.camera.image_from_id(capture_id)
if not capture_obj or not capture_obj.state['available']:
if not capture_obj or not capture_obj.state["available"]:
return abort(404) # 404 Not Found
thumbnail = get_bool(request.args.get('thumbnail'))
thumbnail = get_bool(request.args.get("thumbnail"))
return redirect(url_for(
'.capture_download',
capture_id=capture_id,
filename=capture_obj.filename,
thumbnail=thumbnail
), code=307)
return redirect(
url_for(
".capture_download",
capture_id=capture_id,
filename=capture_obj.filename,
thumbnail=thumbnail,
),
code=307,
)
class DownloadAPI(MicroscopeView):
@ -317,19 +325,22 @@ class DownloadAPI(MicroscopeView):
capture_obj = self.microscope.camera.image_from_id(capture_id)
if not capture_obj or not capture_obj.state['available']:
if not capture_obj or not capture_obj.state["available"]:
return abort(404) # 404 Not Found
thumbnail = get_bool(request.args.get('thumbnail'))
thumbnail = get_bool(request.args.get("thumbnail"))
# 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.filename,
thumbnail=thumbnail
), code=307)
return redirect(
url_for(
"capture_download",
capture_id=capture_id,
filename=capture_obj.filename,
thumbnail=thumbnail,
),
code=307,
)
# Download the image data using the requested filename
if thumbnail:
@ -337,9 +348,7 @@ class DownloadAPI(MicroscopeView):
else:
img = capture_obj.data
return send_file(
img,
mimetype='image/jpeg')
return send_file(img, mimetype="image/jpeg")
class MetadataRedirectAPI(MicroscopeView):
@ -374,14 +383,17 @@ class MetadataRedirectAPI(MicroscopeView):
"""
capture_obj = self.microscope.camera.image_from_id(capture_id)
if not capture_obj or not capture_obj.state['available']:
if not capture_obj or not capture_obj.state["available"]:
return abort(404) # 404 Not Found
return redirect(url_for(
'.metadata_download',
capture_id=capture_id,
filename=capture_obj.metadataname
), code=307)
return redirect(
url_for(
".metadata_download",
capture_id=capture_id,
filename=capture_obj.metadataname,
),
code=307,
)
class MetadataAPI(MicroscopeView):
@ -389,23 +401,24 @@ class MetadataAPI(MicroscopeView):
capture_obj = self.microscope.camera.image_from_id(capture_id)
if not capture_obj or not capture_obj.state['available']:
if not capture_obj or not capture_obj.state["available"]:
return abort(404) # 404 Not Found
# 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
), 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
return Response(
data,
mimetype="text/yaml")
return Response(data, mimetype="text/yaml")
class TagsAPI(MicroscopeView):
@ -430,13 +443,13 @@ class TagsAPI(MicroscopeView):
"""
capture_obj = self.microscope.camera.image_from_id(capture_id)
if not capture_obj or not capture_obj.state['available']:
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)
def put(self, capture_id):
"""
Add tags to the capture
@ -460,9 +473,9 @@ class TagsAPI(MicroscopeView):
capture_obj = self.microscope.camera.image_from_id(capture_id)
if not capture_obj or not capture_obj.state['available']:
if not capture_obj or not capture_obj.state["available"]:
return abort(404) # 404 Not Found
data_dict = JsonResponse(request).json
if type(data_dict) != list:
@ -470,7 +483,7 @@ class TagsAPI(MicroscopeView):
capture_obj.put_tags(data_dict)
metadata_tags = filter_dict(capture_obj.state, ['metadata', 'tags'])
metadata_tags = filter_dict(capture_obj.state, ["metadata", "tags"])
return jsonify(metadata_tags)
@ -507,6 +520,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

@ -5,7 +5,6 @@ from flask import jsonify, request
class ZoomAPI(MicroscopeView):
def get(self):
"""
Get the current zoom value
@ -17,9 +16,9 @@ class ZoomAPI(MicroscopeView):
:<header Content-Type: application/json
:status 200: preview started/stopped
"""
zoom_value = self.microscope.camera.state['zoom_value']
zoom_value = self.microscope.camera.state["zoom_value"]
return jsonify({'zoom_value': zoom_value})
return jsonify({"zoom_value": zoom_value})
def post(self):
"""
@ -44,7 +43,7 @@ class ZoomAPI(MicroscopeView):
:status 200: preview started/stopped
"""
payload = JsonResponse(request)
zoom_value = payload.param('zoom_value', default=1.0, convert=float)
zoom_value = payload.param("zoom_value", default=1.0, convert=float)
self.microscope.camera.set_zoom(zoom_value)
@ -52,7 +51,6 @@ class ZoomAPI(MicroscopeView):
class OverlayAPI(MicroscopeView):
def get(self):
"""
Get overlay text
@ -67,7 +65,7 @@ class OverlayAPI(MicroscopeView):
text = self.microscope.camera.camera.annotate_text
size = self.microscope.camera.camera.annotate_text_size
return jsonify({'text': text, 'size': size})
return jsonify({"text": text, "size": size})
def post(self):
"""
@ -94,10 +92,10 @@ class OverlayAPI(MicroscopeView):
"""
payload = JsonResponse(request)
text = payload.param('text', default="", convert=str)
size = payload.param('size', default=50, convert=int)
text = payload.param("text", default="", convert=str)
size = payload.param("size", default=50, convert=int)
self.microscope.camera.camera.annotate_text = text
self.microscope.camera.camera.annotate_text_size = size
return jsonify({'text': text, 'size': size})
return jsonify({"text": text, "size": size})

View file

@ -6,7 +6,6 @@ import logging
class GPUPreviewAPI(MicroscopeView):
def post(self, operation):
"""
Start or stop the onboard GPU preview.
@ -39,7 +38,7 @@ class GPUPreviewAPI(MicroscopeView):
if operation == "start":
payload = JsonResponse(request)
window = payload.param('window', default=[])
window = payload.param("window", default=[])
logging.debug(window)
if len(window) != 4:

View file

@ -6,6 +6,7 @@ from openflexure_microscope.api.v1.views import MicroscopeView
import logging
import warnings
class PluginFormAPI(MicroscopeView):
def get(self):
"""
@ -26,12 +27,12 @@ class PluginFormAPI(MicroscopeView):
def construct_blueprint(microscope_obj):
blueprint = Blueprint('plugin_blueprint', __name__)
blueprint = Blueprint("plugin_blueprint", __name__)
# Create a base route to return plugin API forms, if any exist
blueprint.add_url_rule(
'/',
view_func=PluginFormAPI.as_view('plugin_api_form', microscope=microscope_obj)
"/",
view_func=PluginFormAPI.as_view("plugin_api_form", microscope=microscope_obj),
)
all_routes = []
@ -40,7 +41,7 @@ def construct_blueprint(microscope_obj):
for plugin_name, plugin_obj in microscope_obj.plugin.plugins:
# If plugin contains valid endpoints
if hasattr(plugin_obj, 'api_views') and isinstance(plugin_obj.api_views, dict):
if hasattr(plugin_obj, "api_views") and isinstance(plugin_obj.api_views, dict):
# We'll keep a record of how each route was expanded
expanded_routes = {}
@ -50,7 +51,7 @@ def construct_blueprint(microscope_obj):
# Remove all leading slashes from view route
cleaned_route = view_route
while cleaned_route[0] == '/':
while cleaned_route[0] == "/":
cleaned_route = cleaned_route[1:]
# Construct a full view route from the plugin name
@ -61,12 +62,16 @@ def construct_blueprint(microscope_obj):
expanded_routes[view_route] = full_view_route
# Check if endpoint name clashes
if full_view_route not in all_routes and issubclass(view_class, MicroscopeViewPlugin):
if full_view_route not in all_routes and issubclass(
view_class, MicroscopeViewPlugin
):
# Add route to main route dictionary
all_routes.append(full_view_route)
# Create a Python-safe name for the route
plugin_route_id = 'plugin{}'.format(full_view_route).replace('/', '_')
plugin_route_id = "plugin{}".format(full_view_route).replace(
"/", "_"
)
# Add route to the plugins blueprint
blueprint.add_url_rule(
@ -74,30 +79,37 @@ def construct_blueprint(microscope_obj):
view_func=view_class.as_view(
plugin_route_id,
microscope=microscope_obj,
plugin=plugin_obj
)
plugin=plugin_obj,
),
)
else:
warnings.warn(
"An endpoint /{} has already been loaded. Skipping {}.".format(
full_view_route,
view_class
full_view_route, view_class
)
)
# If plugin includes an API form
if hasattr(plugin_obj, 'api_form') and isinstance(plugin_obj.api_form, dict):
if hasattr(plugin_obj, "api_form") and isinstance(
plugin_obj.api_form, dict
):
api_form_info = plugin_obj.api_form
# TODO: Validate form? We need to make sure no single plugin can break all plugins.
api_form_info['id'] = plugin_name
if 'forms' in api_form_info and isinstance(api_form_info['forms'], list):
for form in api_form_info['forms']:
if 'route' in form and form['route'] in expanded_routes.keys():
form['route'] = expanded_routes[form['route']]
api_form_info["id"] = plugin_name
if "forms" in api_form_info and isinstance(
api_form_info["forms"], list
):
for form in api_form_info["forms"]:
if "route" in form and form["route"] in expanded_routes.keys():
form["route"] = expanded_routes[form["route"]]
else:
logging.warn("No valid expandable route found for {}".format(form['route']))
logging.warn(
"No valid expandable route found for {}".format(
form["route"]
)
)
# Store the complete form in Microscope().plugin.form
microscope_obj.plugin.forms.append(api_form_info)
print(microscope_obj.plugin.forms)

View file

@ -8,7 +8,6 @@ import logging
class PositionAPI(MicroscopeView):
def get(self):
"""
Return current x, y and z positions of the stage.
@ -42,7 +41,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):
@ -67,15 +66,19 @@ class PositionAPI(MicroscopeView):
position = [0, 0, 0]
# Handle absolute positioning (calculate a relative move from current position and target)
if (payload.param('absolute') is True) and (self.microscope.stage): # Only if stage exists
target_position = axes_to_array(payload.json, ['x', 'y', 'z'])
if (payload.param("absolute") is True) and (
self.microscope.stage
): # Only if stage exists
target_position = axes_to_array(payload.json, ["x", "y", "z"])
logging.debug("TARGET: {}".format(target_position))
position = [target_position[i] - self.microscope.stage.position[i] for i in range(3)]
position = [
target_position[i] - self.microscope.stage.position[i] for i in range(3)
]
logging.debug("DELTA: {}".format(position))
else:
# Get coordinates from payload
position = axes_to_array(payload.json, ['x', 'y', 'z'], [0, 0, 0])
position = axes_to_array(payload.json, ["x", "y", "z"], [0, 0, 0])
logging.debug(position)
@ -85,18 +88,18 @@ 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)
def construct_blueprint(microscope_obj):
blueprint = Blueprint('stage_blueprint', __name__)
blueprint = Blueprint("stage_blueprint", __name__)
blueprint.add_url_rule(
'/position',
view_func=PositionAPI.as_view('position', microscope=microscope_obj)
"/position",
view_func=PositionAPI.as_view("position", microscope=microscope_obj),
)
return blueprint

View file

@ -3,7 +3,6 @@ from flask import jsonify, abort, Blueprint
class TaskListAPI(MicroscopeView):
def get(self):
"""
Get list of long-running tasks.
@ -66,7 +65,6 @@ class TaskListAPI(MicroscopeView):
class TaskAPI(MicroscopeView):
def get(self, task_id):
"""
Get JSON representation of a task
@ -123,14 +121,11 @@ class TaskAPI(MicroscopeView):
success = self.microscope.task.delete(task_id)
if success:
data = {
'status': 'success',
'message': 'task successfully deleted'
}
data = {"status": "success", "message": "task successfully deleted"}
else:
data = {
'status': 'fail',
'message': 'task could not be deleted, as it is currently running or does not exist'
"status": "fail",
"message": "task could not be deleted, as it is currently running or does not exist",
}
return jsonify(data)
@ -138,16 +133,14 @@ class TaskAPI(MicroscopeView):
def construct_blueprint(microscope_obj):
blueprint = Blueprint('task_blueprint', __name__)
blueprint = Blueprint("task_blueprint", __name__)
blueprint.add_url_rule(
'/',
view_func=TaskListAPI.as_view('task_list', microscope=microscope_obj)
"/", view_func=TaskListAPI.as_view("task_list", microscope=microscope_obj)
)
blueprint.add_url_rule(
'/<task_id>/',
view_func=TaskAPI.as_view('task', microscope=microscope_obj)
"/<task_id>/", view_func=TaskAPI.as_view("task", microscope=microscope_obj)
)
return blueprint

View file

@ -6,6 +6,7 @@ class MicroscopeView(MethodView):
Create a generic MethodView with a globally available
microscope object passed as an argument.
"""
def __init__(self, microscope, **kwargs):
self.microscope = microscope
@ -19,6 +20,7 @@ class MicroscopeViewPlugin(MicroscopeView):
microscope object passed as an argument, and a plugin
reference stored in 'self'. Initially None.
"""
def __init__(self, microscope, plugin=None, **kwargs):
self.plugin = plugin