From e55c097a324395ae2e4b46f6c47455d79ab59bd3 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Fri, 14 Jun 2019 17:18:13 +0100 Subject: [PATCH 01/15] Added API route for returning API schemas --- .../api/v1/blueprints/plugins.py | 54 ++++++++++++++++--- openflexure_microscope/api/v1/views.py | 1 + openflexure_microscope/plugins/loader.py | 3 +- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/openflexure_microscope/api/v1/blueprints/plugins.py b/openflexure_microscope/api/v1/blueprints/plugins.py index 9aca0f80..9cc98587 100644 --- a/openflexure_microscope/api/v1/blueprints/plugins.py +++ b/openflexure_microscope/api/v1/blueprints/plugins.py @@ -1,15 +1,33 @@ from openflexure_microscope.api.v1.views import MicroscopeViewPlugin -from flask import Blueprint +from flask import Blueprint, jsonify +from openflexure_microscope.api.v1.views import MicroscopeView import logging import warnings +class PluginSchemaAPI(MicroscopeView): + def get(self): + """ + Return the current plugin schemas + + .. :quickref: Plugin; Get schemas + + """ + out = self.microscope.plugin.schemas + return jsonify(out) + def construct_blueprint(microscope_obj): blueprint = Blueprint('plugin_blueprint', __name__) + # Create a base route to return plugin API schemas, if any exist + blueprint.add_url_rule( + '/', + view_func=PluginSchemaAPI.as_view('plugin_api_schema', microscope=microscope_obj) + ) + all_routes = [] # For each plugin attached to the microscope object @@ -18,27 +36,37 @@ def construct_blueprint(microscope_obj): # If plugin contains valid endpoints 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 = {} + # For each defined endpoint for view_route, view_class in plugin_obj.api_views.items(): # Remove all leading slashes from view route - while view_route[0] == '/': - view_route = view_route[1:] + cleaned_route = view_route + while cleaned_route[0] == '/': + cleaned_route = cleaned_route[1:] # Construct a full view route from the plugin name - full_view_route = "/{}/{}".format(plugin_name, view_route) + full_view_route = "/{}/{}".format(plugin_name, cleaned_route) logging.debug(full_view_route) + # Record how the view_route got expanded + 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): # 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('/', '_') + # Add route to the plugins blueprint blueprint.add_url_rule( full_view_route, view_func=view_class.as_view( - 'plugin_{}'.format(full_view_route).replace('/', '_'), + plugin_route_id, microscope=microscope_obj, plugin=plugin_obj ) @@ -52,9 +80,23 @@ def construct_blueprint(microscope_obj): ) ) + # If plugin includes an API schema + if hasattr(plugin_obj, 'api_schema') and isinstance(plugin_obj.api_schema, dict): + schema = plugin_obj.api_schema + # TODO: Validate schema? + schema['id'] = plugin_name + if 'forms' in schema and isinstance(schema['forms'], list): + for form in schema['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'])) + + # Store the complete schema in Microscope().plugin.schema + microscope_obj.plugin.schemas.append(schema) + else: warnings.warn( "No valid 'api_views' dictionary found in {}".format(plugin_obj) ) - return blueprint diff --git a/openflexure_microscope/api/v1/views.py b/openflexure_microscope/api/v1/views.py index 3c32ad44..10c88888 100644 --- a/openflexure_microscope/api/v1/views.py +++ b/openflexure_microscope/api/v1/views.py @@ -22,5 +22,6 @@ class MicroscopeViewPlugin(MicroscopeView): def __init__(self, microscope, plugin=None, **kwargs): self.plugin = plugin + self.route = None MicroscopeView.__init__(self, microscope=microscope, **kwargs) diff --git a/openflexure_microscope/plugins/loader.py b/openflexure_microscope/plugins/loader.py index 35bb00f9..74b40a70 100644 --- a/openflexure_microscope/plugins/loader.py +++ b/openflexure_microscope/plugins/loader.py @@ -126,7 +126,8 @@ class PluginMount(object): """ def __init__(self, parent): self.parent = parent - self.plugins = [] + self.plugins = [] # List of plugin objects + self.schemas = [] # List of plugin schemas logging.info("Creating plugin mount") @property From 616ed455f54ddea778e5009aeddfd35a86bb9c59 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Fri, 14 Jun 2019 17:18:54 +0100 Subject: [PATCH 02/15] Removed redundant payload --- .../plugins/default/camera_calibration/plugin.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openflexure_microscope/plugins/default/camera_calibration/plugin.py b/openflexure_microscope/plugins/default/camera_calibration/plugin.py index ccd0cd2c..87a03a1a 100644 --- a/openflexure_microscope/plugins/default/camera_calibration/plugin.py +++ b/openflexure_microscope/plugins/default/camera_calibration/plugin.py @@ -26,8 +26,6 @@ API_SCHEMA = { class RecalibrateAPIView(MicroscopeViewPlugin): def post(self): - payload = JsonPayload(request) - logging.info("Starting microscope recalibration...") task = self.microscope.task.start(self.plugin.recalibrate) From 8742c4d43c733b3aa040fc32218c23401eee59d0 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Fri, 14 Jun 2019 17:51:26 +0100 Subject: [PATCH 03/15] Added extra content to test schema --- .../plugins/default/camera_calibration/plugin.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/openflexure_microscope/plugins/default/camera_calibration/plugin.py b/openflexure_microscope/plugins/default/camera_calibration/plugin.py index 87a03a1a..07dee05d 100644 --- a/openflexure_microscope/plugins/default/camera_calibration/plugin.py +++ b/openflexure_microscope/plugins/default/camera_calibration/plugin.py @@ -17,8 +17,19 @@ API_SCHEMA = { { 'fieldType': "htmlBlock", 'name': "heading", - 'content': "This is different form in a plugin!" - } + 'content': "This plugin was generated from JSON!

In fact, I'm typing this HTML block into my Python plugin right now." + }, + { + 'fieldType': "radioList", + 'name': "coolness", + 'label': "How cool is that!?", + 'options': ["Very", "Very very", "I'm losing my mind"] + }, + { + 'fieldType': "htmlBlock", + 'name': "subheading", + 'content': "I should apologise to the auto-calibrate plugin though. I'm using that as a test-bed..." + }, ] } ] From a8d03689e63b6ea45e058d55d171ad57facfd9fe Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Fri, 14 Jun 2019 17:52:18 +0100 Subject: [PATCH 04/15] Removed redundant route attribute --- openflexure_microscope/api/v1/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openflexure_microscope/api/v1/views.py b/openflexure_microscope/api/v1/views.py index 10c88888..3c32ad44 100644 --- a/openflexure_microscope/api/v1/views.py +++ b/openflexure_microscope/api/v1/views.py @@ -22,6 +22,5 @@ class MicroscopeViewPlugin(MicroscopeView): def __init__(self, microscope, plugin=None, **kwargs): self.plugin = plugin - self.route = None MicroscopeView.__init__(self, microscope=microscope, **kwargs) From 4ca93ba62914874e1755abab510b515f9913ac75 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Fri, 14 Jun 2019 17:55:08 +0100 Subject: [PATCH 05/15] Added extra notes --- openflexure_microscope/api/v1/blueprints/plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openflexure_microscope/api/v1/blueprints/plugins.py b/openflexure_microscope/api/v1/blueprints/plugins.py index 9cc98587..9c32dacd 100644 --- a/openflexure_microscope/api/v1/blueprints/plugins.py +++ b/openflexure_microscope/api/v1/blueprints/plugins.py @@ -83,7 +83,7 @@ def construct_blueprint(microscope_obj): # If plugin includes an API schema if hasattr(plugin_obj, 'api_schema') and isinstance(plugin_obj.api_schema, dict): schema = plugin_obj.api_schema - # TODO: Validate schema? + # TODO: Validate schema? We need to make sure no single plugin can break all plugins. schema['id'] = plugin_name if 'forms' in schema and isinstance(schema['forms'], list): for form in schema['forms']: From 5837d78a215aeb5151deed8f91b4c3e90e26332a Mon Sep 17 00:00:00 2001 From: jtc42 Date: Sun, 16 Jun 2019 13:06:28 +0100 Subject: [PATCH 06/15] Add missing itertools import --- openflexure_microscope/plugins/default/scan/plugin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openflexure_microscope/plugins/default/scan/plugin.py b/openflexure_microscope/plugins/default/scan/plugin.py index 06bb87a7..dbf37b0c 100644 --- a/openflexure_microscope/plugins/default/scan/plugin.py +++ b/openflexure_microscope/plugins/default/scan/plugin.py @@ -2,6 +2,7 @@ import time import numpy as np from typing import Tuple import uuid +import itertools import logging from openflexure_microscope.camera.base import generate_basename From e52871e21bf73c411eafd86b66d034be47ac299a Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Mon, 17 Jun 2019 13:54:32 +0100 Subject: [PATCH 07/15] Fixed default backlash --- openflexure_microscope/plugins/default/autofocus/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openflexure_microscope/plugins/default/autofocus/api.py b/openflexure_microscope/plugins/default/autofocus/api.py index 9670540f..a737e7fb 100644 --- a/openflexure_microscope/plugins/default/autofocus/api.py +++ b/openflexure_microscope/plugins/default/autofocus/api.py @@ -32,9 +32,9 @@ class FastAutofocusAPI(MicroscopeViewPlugin): # Figure out the parameters to use dz = payload.param("dz", default=2000, convert=int) - backlash = payload.param("backlash", default=None, convert=int) + backlash = payload.param("backlash", default=0, convert=int) if backlash < 0: - backlash = None + backlash = 0 logging.info("Running autofocus...") task = self.microscope.task.start(self.plugin.fast_autofocus, dz, backlash=backlash) From 456ca7d13d946573268073cffec46f6ecfad9e9c Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Mon, 17 Jun 2019 13:55:05 +0100 Subject: [PATCH 08/15] Added example schema --- .../plugins/default/autofocus/plugin.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openflexure_microscope/plugins/default/autofocus/plugin.py b/openflexure_microscope/plugins/default/autofocus/plugin.py index 302fe9a0..450f67e0 100644 --- a/openflexure_microscope/plugins/default/autofocus/plugin.py +++ b/openflexure_microscope/plugins/default/autofocus/plugin.py @@ -9,6 +9,22 @@ from openflexure_microscope.utilities import set_properties from .focus_utils import sharpness_sum_lap2, JPEGSharpnessMonitor from .api import MeasureSharpnessAPI, AutofocusAPI, FastAutofocusAPI +API_SCHEMA = { + 'icon': 'center_focus_strong', + 'requireConnection': True, + 'forms': [ + { + 'route': '/fast_autofocus', + 'schema': [ + { + 'fieldType': "htmlBlock", + 'name': "heading", + 'content': "This plugin was generated from JSON" + }, + ] + } + ] +} class AutofocusPlugin(MicroscopePlugin): """ @@ -21,6 +37,8 @@ class AutofocusPlugin(MicroscopePlugin): '/fast_autofocus': FastAutofocusAPI, } + api_schema = API_SCHEMA + ### SLOW AUTOFOCUS def autofocus(self, dz, settle=0.5, metric_fn=sharpness_sum_lap2): From 9911b33621b4e4f8755bcfa6b2f7e26d4f40e65e Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Mon, 17 Jun 2019 13:55:14 +0100 Subject: [PATCH 09/15] Removed test schema --- .../default/camera_calibration/plugin.py | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/openflexure_microscope/plugins/default/camera_calibration/plugin.py b/openflexure_microscope/plugins/default/camera_calibration/plugin.py index 07dee05d..9096a91e 100644 --- a/openflexure_microscope/plugins/default/camera_calibration/plugin.py +++ b/openflexure_microscope/plugins/default/camera_calibration/plugin.py @@ -7,33 +7,6 @@ import logging from .recalibrate_utils import recalibrate_camera, auto_expose_and_freeze_settings -API_SCHEMA = { - 'icon': 'lifesaver', - 'requireConnection': True, - 'forms': [ - { - 'route': '/recalibrate', - 'schema': [ - { - 'fieldType': "htmlBlock", - 'name': "heading", - 'content': "This plugin was generated from JSON!

In fact, I'm typing this HTML block into my Python plugin right now." - }, - { - 'fieldType': "radioList", - 'name': "coolness", - 'label': "How cool is that!?", - 'options': ["Very", "Very very", "I'm losing my mind"] - }, - { - 'fieldType': "htmlBlock", - 'name': "subheading", - 'content': "I should apologise to the auto-calibrate plugin though. I'm using that as a test-bed..." - }, - ] - } - ] -} class RecalibrateAPIView(MicroscopeViewPlugin): def post(self): @@ -53,8 +26,6 @@ class Plugin(MicroscopePlugin): '/recalibrate': RecalibrateAPIView, } - api_schema = API_SCHEMA - def recalibrate(self): """Reset the camera's settings. From 8a5c749d479cb86bd2c360c820ac7656f593364e Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Mon, 17 Jun 2019 17:35:20 +0100 Subject: [PATCH 10/15] Added specific API schema example plugin --- openflexure_microscope/api/utilities.py | 2 +- .../plugins/default/autofocus/plugin.py | 2 + .../plugins/testing/__init__.py | 1 - .../plugins/testing/plugin.py | 13 ---- .../testing/schema_example/__init__.py | 2 + .../plugins/testing/schema_example/api.py | 40 ++++++++++++ .../plugins/testing/schema_example/plugin.py | 60 ++++++++++++++++++ .../testing/schema_example/schema.json | 61 +++++++++++++++++++ 8 files changed, 166 insertions(+), 15 deletions(-) delete mode 100644 openflexure_microscope/plugins/testing/plugin.py create mode 100644 openflexure_microscope/plugins/testing/schema_example/__init__.py create mode 100644 openflexure_microscope/plugins/testing/schema_example/api.py create mode 100644 openflexure_microscope/plugins/testing/schema_example/plugin.py create mode 100644 openflexure_microscope/plugins/testing/schema_example/schema.json diff --git a/openflexure_microscope/api/utilities.py b/openflexure_microscope/api/utilities.py index b3f919e0..cdeca9d0 100644 --- a/openflexure_microscope/api/utilities.py +++ b/openflexure_microscope/api/utilities.py @@ -44,7 +44,7 @@ class JsonPayload: else: val = default - if convert: + if convert and (val is not None): val = convert(val) return val diff --git a/openflexure_microscope/plugins/default/autofocus/plugin.py b/openflexure_microscope/plugins/default/autofocus/plugin.py index 450f67e0..c9b44780 100644 --- a/openflexure_microscope/plugins/default/autofocus/plugin.py +++ b/openflexure_microscope/plugins/default/autofocus/plugin.py @@ -15,6 +15,8 @@ API_SCHEMA = { 'forms': [ { 'route': '/fast_autofocus', + 'isTask': True, + 'submitLabel': "Run autofocus", 'schema': [ { 'fieldType': "htmlBlock", diff --git a/openflexure_microscope/plugins/testing/__init__.py b/openflexure_microscope/plugins/testing/__init__.py index f42b093e..e69de29b 100644 --- a/openflexure_microscope/plugins/testing/__init__.py +++ b/openflexure_microscope/plugins/testing/__init__.py @@ -1 +0,0 @@ -from .plugin import Plugin \ No newline at end of file diff --git a/openflexure_microscope/plugins/testing/plugin.py b/openflexure_microscope/plugins/testing/plugin.py deleted file mode 100644 index 719eb62b..00000000 --- a/openflexure_microscope/plugins/testing/plugin.py +++ /dev/null @@ -1,13 +0,0 @@ -from openflexure_microscope.plugins import MicroscopePlugin - - -class Plugin(MicroscopePlugin): - """ - A set of default plugins - """ - - def identify(self): - """ - Tests for access to Microscope.camera, and Microscope.stage - """ - return self.microscope.camera, self.microscope.stage diff --git a/openflexure_microscope/plugins/testing/schema_example/__init__.py b/openflexure_microscope/plugins/testing/schema_example/__init__.py new file mode 100644 index 00000000..3e9a8c4d --- /dev/null +++ b/openflexure_microscope/plugins/testing/schema_example/__init__.py @@ -0,0 +1,2 @@ +from .plugin import ExamplePlugin +from . import api \ No newline at end of file diff --git a/openflexure_microscope/plugins/testing/schema_example/api.py b/openflexure_microscope/plugins/testing/schema_example/api.py new file mode 100644 index 00000000..6c518043 --- /dev/null +++ b/openflexure_microscope/plugins/testing/schema_example/api.py @@ -0,0 +1,40 @@ +from openflexure_microscope.api.utilities import JsonPayload +from openflexure_microscope.api.v1.views import MicroscopeViewPlugin +from openflexure_microscope.exceptions import TaskDeniedException + +from flask import request, Response, escape, jsonify + +class DoAPI(MicroscopeViewPlugin): + """ + A simple example API plugin + """ + + def get(self): + return jsonify(self.plugin.get_values_dict()) + + def post(self): + # Get payload JSON + payload = JsonPayload(request) + + # Extract a values from the JSON payload. + val_int = payload.param('val_int', default=None, convert=int) + val_str = payload.param('val_str', default=None, convert=str) + val_radio = payload.param('val_radio', default=None) + val_check = payload.param('val_check', default=None) + val_select = payload.param('val_select', default=None) + val_disposable = payload.param('val_disposable', default=None) + + self.plugin.set_values( + val_int, + val_str, + val_radio, + val_check, + val_select, + val_disposable + ) + + print(self.plugin.get_values_dict()) + + return jsonify({ + 'response': 'completed' + }) \ No newline at end of file diff --git a/openflexure_microscope/plugins/testing/schema_example/plugin.py b/openflexure_microscope/plugins/testing/schema_example/plugin.py new file mode 100644 index 00000000..e3d2b936 --- /dev/null +++ b/openflexure_microscope/plugins/testing/schema_example/plugin.py @@ -0,0 +1,60 @@ +import random +import time +import os +import json +from openflexure_microscope.plugins import MicroscopePlugin + +from .api import DoAPI + +HERE = os.path.dirname(os.path.realpath(__file__)) +SCHEMA_PATH = os.path.join(HERE, "schema.json") + +class ExamplePlugin(MicroscopePlugin): + """ + An example plugin using a comprehensive schema + """ + global SCHEMA_PATH + + with open(SCHEMA_PATH, 'r') as sc: + api_schema = json.load(sc) + + api_views = { + '/do': DoAPI, + } + + def __init__(self): + self.val_int = 10 + self.val_str = "Hello" + self.val_radio = "First" + self.val_check = ["Foo", "Bar"] + self.val_select = "Most" + self.val_unused = "I'm an unused string, here to confuse the form parsing" + + def set_values(self, val_int, val_str, val_radio, val_check, val_select, val_disposable): + """ + Demonstrate a plugin with schema + """ + if val_int: + self.val_int = int(val_int) + if val_str: + self.val_str = str(val_str) + if val_radio: + self.val_radio = val_radio + if val_check is not None: + print(val_check) + self.val_check = val_check if (type(val_check) is list) else [val_check] + if val_select: + self.val_select = val_select + + if val_disposable: + print("DISPOSABLE VALUE: {}".format(val_disposable)) + + def get_values_dict(self): + return { + 'val_int': self.val_int, + 'val_str': self.val_str, + 'val_radio': self.val_radio, + 'val_check': self.val_check, + 'val_select': self.val_select, + 'val_unused': self.val_unused + } \ No newline at end of file diff --git a/openflexure_microscope/plugins/testing/schema_example/schema.json b/openflexure_microscope/plugins/testing/schema_example/schema.json new file mode 100644 index 00000000..a26bd8c0 --- /dev/null +++ b/openflexure_microscope/plugins/testing/schema_example/schema.json @@ -0,0 +1,61 @@ +{ + "id": "test-plugin", + "forms": [ + { + "route": "/do", + "submitLabel": "Do things", + "selfUpdate": true, + "schema": [ + { + "fieldType": "htmlBlock", + "name": "heading", + "content": "This is a plugin!" + }, + [ + { + "fieldType": "numberInput", + "placeholder": "Some integer", + "name": "val_int", + "label": "Number value", + "minValue": 0 + }, + { + "fieldType": "textInput", + "placeholder": "Some string", + "label": "String value", + "name": "val_str" + } + ], + [ + { + "fieldType": "radioList", + "name": "val_radio", + "label": "Radio value", + "options": ["First", "Second", "Third"] + }, + { + "fieldType": "checkList", + "name": "val_check", + "label": "Checklist values", + "options": ["Foo", "Bar", "Baz"] + } + ], + + { + "fieldType": "selectList", + "name": "val_select", + "multi": false, + "label": "Some selection", + "options": ["Most", "Average", "Least"] + }, + + { + "fieldType": "textInput", + "placeholder": "Some string", + "label": "Non-persistent string", + "name": "val_disposable" + } + ] + } + ] +} \ No newline at end of file From 54dcee00837366311deb3163bde920ecf180054e Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Tue, 18 Jun 2019 13:53:38 +0100 Subject: [PATCH 11/15] Tweaked example schema --- .../testing/schema_example/schema.json | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/openflexure_microscope/plugins/testing/schema_example/schema.json b/openflexure_microscope/plugins/testing/schema_example/schema.json index a26bd8c0..34d67fd1 100644 --- a/openflexure_microscope/plugins/testing/schema_example/schema.json +++ b/openflexure_microscope/plugins/testing/schema_example/schema.json @@ -2,15 +2,13 @@ "id": "test-plugin", "forms": [ { + "name": "Simple request", + "isCollapsible": false, + "isTask": false, + "selfUpdate": true, "route": "/do", "submitLabel": "Do things", - "selfUpdate": true, "schema": [ - { - "fieldType": "htmlBlock", - "name": "heading", - "content": "This is a plugin!" - }, [ { "fieldType": "numberInput", @@ -40,7 +38,11 @@ "options": ["Foo", "Bar", "Baz"] } ], - + { + "fieldType": "htmlBlock", + "name": "html_block", + "content": "This is a block of HTML in a plugin!
I can do paragraph breaks and stuff." + }, { "fieldType": "selectList", "name": "val_select", @@ -56,6 +58,30 @@ "name": "val_disposable" } ] + }, + { + "name": "Different form", + "isTask": false, + "selfUpdate": true, + "route": "/do", + "submitLabel": "Do different things", + "schema": [ + [ + { + "fieldType": "numberInput", + "placeholder": "Some integer", + "name": "val_int", + "label": "Number value", + "minValue": 0 + }, + { + "fieldType": "textInput", + "placeholder": "Some string", + "label": "String value", + "name": "val_str" + } + ] + ] } ] } \ No newline at end of file From e91e58daa3fb7d80c9683fc10d966430ca63cf0f Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Tue, 18 Jun 2019 15:56:02 +0100 Subject: [PATCH 12/15] Added a long running task to schema example --- .../plugins/testing/schema_example/api.py | 26 ++++++++++++++++++- .../plugins/testing/schema_example/plugin.py | 16 ++++++++++-- .../testing/schema_example/schema.json | 24 ++++++----------- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/openflexure_microscope/plugins/testing/schema_example/api.py b/openflexure_microscope/plugins/testing/schema_example/api.py index 6c518043..67f92b62 100644 --- a/openflexure_microscope/plugins/testing/schema_example/api.py +++ b/openflexure_microscope/plugins/testing/schema_example/api.py @@ -3,6 +3,7 @@ from openflexure_microscope.api.v1.views import MicroscopeViewPlugin from openflexure_microscope.exceptions import TaskDeniedException from flask import request, Response, escape, jsonify +import logging class DoAPI(MicroscopeViewPlugin): """ @@ -37,4 +38,27 @@ class DoAPI(MicroscopeViewPlugin): return jsonify({ 'response': 'completed' - }) \ No newline at end of file + }) + +class TaskAPI(MicroscopeViewPlugin): + """ + A task example API plugin + """ + + def get(self): + return jsonify({ + 'run_time': self.plugin.run_time + }) + + def post(self): + # Get payload JSON + payload = JsonPayload(request) + + # Extract a values from the JSON payload. + val_int = payload.param('run_time', default=5, convert=int) + + logging.info("Running task...") + task = self.microscope.task.start(self.plugin.generate_random_numbers_for_a_while, val_int) + + # return a handle on the autofocus task + return jsonify(task.state), 202 \ No newline at end of file diff --git a/openflexure_microscope/plugins/testing/schema_example/plugin.py b/openflexure_microscope/plugins/testing/schema_example/plugin.py index e3d2b936..da2264c9 100644 --- a/openflexure_microscope/plugins/testing/schema_example/plugin.py +++ b/openflexure_microscope/plugins/testing/schema_example/plugin.py @@ -4,7 +4,7 @@ import os import json from openflexure_microscope.plugins import MicroscopePlugin -from .api import DoAPI +from .api import DoAPI, TaskAPI HERE = os.path.dirname(os.path.realpath(__file__)) SCHEMA_PATH = os.path.join(HERE, "schema.json") @@ -20,6 +20,7 @@ class ExamplePlugin(MicroscopePlugin): api_views = { '/do': DoAPI, + '/task': TaskAPI } def __init__(self): @@ -30,6 +31,8 @@ class ExamplePlugin(MicroscopePlugin): self.val_select = "Most" self.val_unused = "I'm an unused string, here to confuse the form parsing" + self.run_time = 5 + def set_values(self, val_int, val_str, val_radio, val_check, val_select, val_disposable): """ Demonstrate a plugin with schema @@ -57,4 +60,13 @@ class ExamplePlugin(MicroscopePlugin): 'val_check': self.val_check, 'val_select': self.val_select, 'val_unused': self.val_unused - } \ No newline at end of file + } + + def generate_random_numbers_for_a_while(self, run_time: int): + self.run_time = run_time + vals = [] + for _ in range(run_time): + vals.append(random.random()) + time.sleep(1) + + return vals \ No newline at end of file diff --git a/openflexure_microscope/plugins/testing/schema_example/schema.json b/openflexure_microscope/plugins/testing/schema_example/schema.json index 34d67fd1..1628740f 100644 --- a/openflexure_microscope/plugins/testing/schema_example/schema.json +++ b/openflexure_microscope/plugins/testing/schema_example/schema.json @@ -60,27 +60,19 @@ ] }, { - "name": "Different form", - "isTask": false, + "name": "Task form", + "isTask": true, "selfUpdate": true, - "route": "/do", - "submitLabel": "Do different things", + "route": "/task", + "submitLabel": "Start task", "schema": [ - [ { "fieldType": "numberInput", - "placeholder": "Some integer", - "name": "val_int", - "label": "Number value", - "minValue": 0 - }, - { - "fieldType": "textInput", - "placeholder": "Some string", - "label": "String value", - "name": "val_str" + "placeholder": "", + "name": "run_time", + "label": "Run time (seconds)", + "minValue": 1 } - ] ] } ] From 085daa5ba6e1c0696ea594ecd986f43ffceadea0 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Tue, 18 Jun 2019 17:03:17 +0100 Subject: [PATCH 13/15] Removed redundant test schema --- .../plugins/default/autofocus/plugin.py | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/openflexure_microscope/plugins/default/autofocus/plugin.py b/openflexure_microscope/plugins/default/autofocus/plugin.py index c9b44780..302fe9a0 100644 --- a/openflexure_microscope/plugins/default/autofocus/plugin.py +++ b/openflexure_microscope/plugins/default/autofocus/plugin.py @@ -9,24 +9,6 @@ from openflexure_microscope.utilities import set_properties from .focus_utils import sharpness_sum_lap2, JPEGSharpnessMonitor from .api import MeasureSharpnessAPI, AutofocusAPI, FastAutofocusAPI -API_SCHEMA = { - 'icon': 'center_focus_strong', - 'requireConnection': True, - 'forms': [ - { - 'route': '/fast_autofocus', - 'isTask': True, - 'submitLabel': "Run autofocus", - 'schema': [ - { - 'fieldType': "htmlBlock", - 'name': "heading", - 'content': "This plugin was generated from JSON" - }, - ] - } - ] -} class AutofocusPlugin(MicroscopePlugin): """ @@ -39,8 +21,6 @@ class AutofocusPlugin(MicroscopePlugin): '/fast_autofocus': FastAutofocusAPI, } - api_schema = API_SCHEMA - ### SLOW AUTOFOCUS def autofocus(self, dz, settle=0.5, metric_fn=sharpness_sum_lap2): From 7aed8d0585598c4d90df2cb6896aefa34710a001 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Tue, 18 Jun 2019 17:03:22 +0100 Subject: [PATCH 14/15] Added a custom icon --- .../plugins/testing/schema_example/schema.json | 1 + 1 file changed, 1 insertion(+) diff --git a/openflexure_microscope/plugins/testing/schema_example/schema.json b/openflexure_microscope/plugins/testing/schema_example/schema.json index 1628740f..4aee4dcd 100644 --- a/openflexure_microscope/plugins/testing/schema_example/schema.json +++ b/openflexure_microscope/plugins/testing/schema_example/schema.json @@ -1,5 +1,6 @@ { "id": "test-plugin", + "icon": "pets", "forms": [ { "name": "Simple request", From 6608f4dcd3f8241931eabbc13f211a525f44bc21 Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Fri, 21 Jun 2019 13:15:33 +0100 Subject: [PATCH 15/15] Iterated to beta 2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 44c01cfd..f861631b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.masonry.api" [tool.poetry] name = "openflexure_microscope" -version = "1.1.0-beta.1" +version = "1.1.0-beta.2" description = "Python module, and Flask-based web API, to run the OpenFlexure Microscope." authors = [