From e6cb9f6b35f2961f5c2aea778eef5b945747e76d Mon Sep 17 00:00:00 2001 From: Joel Collins Date: Mon, 29 Jun 2020 15:24:59 +0100 Subject: [PATCH] Initial 0.7.0 conversion --- .../api/default_extensions/autofocus.py | 22 +++--- .../api/default_extensions/autostorage.py | 7 +- .../api/default_extensions/scan.py | 38 +++++----- .../api/default_extensions/zip_builder.py | 12 +-- .../api/v2/views/actions/__init__.py | 1 - .../api/v2/views/actions/camera.py | 76 +++++++++---------- .../api/v2/views/actions/stage.py | 20 +++-- .../api/v2/views/actions/system.py | 8 +- .../api/v2/views/captures.py | 33 ++++---- .../api/v2/views/instrument.py | 24 +++--- .../api/v2/views/streams.py | 18 +++-- 11 files changed, 129 insertions(+), 130 deletions(-) diff --git a/openflexure_microscope/api/default_extensions/autofocus.py b/openflexure_microscope/api/default_extensions/autofocus.py index d61f72df..8ce2575a 100644 --- a/openflexure_microscope/api/default_extensions/autofocus.py +++ b/openflexure_microscope/api/default_extensions/autofocus.py @@ -1,7 +1,7 @@ from labthings.server.find import find_component from labthings.server.extensions import BaseExtension from labthings.server.view import View, ActionView, PropertyView -from labthings.server.decorators import ThingAction, ThingProperty +from labthings.server import fields from openflexure_microscope.devel import JsonResponse, request, abort from openflexure_microscope.utilities import set_properties @@ -336,7 +336,9 @@ class AutofocusAPI(ActionView): """ Run a standard autofocus """ - def post(self): + args = {"dz": fields.List(fields.Int())} + + def post(self, args): payload = JsonResponse(request) microscope = find_component("org.openflexure.microscope") @@ -344,7 +346,7 @@ class AutofocusAPI(ActionView): abort(503, "No microscope connected. Unable to autofocus.") # Figure out the range of z values to use - dz = payload.param("dz", default=np.linspace(-300, 300, 7), convert=np.array) + dz = np.array(args.get("dz", np.linspace(-300, 300, 7))) if microscope.has_real_stage(): logging.debug("Running autofocus...") @@ -360,18 +362,20 @@ class FastAutofocusAPI(ActionView): """ Run a fast autofocus """ - def post(self): - payload = JsonResponse(request) + args = { + "dz": fields.Int(default=2000), + "backlash": fields.Int(default=25, minimum=0) + } + + def post(self, args): microscope = find_component("org.openflexure.microscope") if not microscope: abort(503, "No microscope connected. Unable to autofocus.") # Figure out the parameters to use - dz = payload.param("dz", default=2000, convert=int) - backlash = payload.param("backlash", default=25, convert=int) - if backlash < 0: - backlash = 0 + dz = args.get("dz") + backlash = args.get("backlash") if microscope.has_real_stage(): logging.debug("Running autofocus...") diff --git a/openflexure_microscope/api/default_extensions/autostorage.py b/openflexure_microscope/api/default_extensions/autostorage.py index da282827..5f0640c0 100644 --- a/openflexure_microscope/api/default_extensions/autostorage.py +++ b/openflexure_microscope/api/default_extensions/autostorage.py @@ -1,6 +1,5 @@ from labthings.server.extensions import BaseExtension from labthings.server.view import View, PropertyView -from labthings.server.decorators import ThingProperty, PropertySchema, use_args from labthings.server import fields from labthings.server.find import find_component @@ -198,8 +197,9 @@ class GetLocationsView(PropertyView): return autostorage_extension_v2.get_locations() -@PropertySchema(fields.String(required=True, example="Default")) class PreferredLocationView(PropertyView): + schema = fields.String(required=True, example="Default") + def get(self): global autostorage_extension_v2 @@ -219,7 +219,8 @@ class PreferredLocationView(PropertyView): class PreferredLocationGUIView(View): - @use_args({"new_path_title": fields.String(required=True)}) + args = {"new_path_title": fields.String(required=True)} + def post(self, args): global autostorage_extension_v2 diff --git a/openflexure_microscope/api/default_extensions/scan.py b/openflexure_microscope/api/default_extensions/scan.py index 65db21b9..c58d282f 100644 --- a/openflexure_microscope/api/default_extensions/scan.py +++ b/openflexure_microscope/api/default_extensions/scan.py @@ -8,7 +8,6 @@ from functools import reduce from openflexure_microscope.captures.capture_manager import generate_basename from labthings.server.find import find_component, find_extension from labthings.server.extensions import BaseExtension -from labthings.server.decorators import use_args from labthings.server import fields from openflexure_microscope.devel import abort, update_task_progress @@ -91,7 +90,7 @@ class ScanExtension(BaseExtension): def __init__(self): self._images_to_be_captured: int = 1 self._images_captured_so_far: int = 0 - return BaseExtension.__init__(self, "org.openflexure.scan", version="2.0.0") + BaseExtension.__init__(self, "org.openflexure.scan", version="2.0.0") def progress(self): progress = (self._images_captured_so_far / self._images_to_be_captured) * 100 @@ -289,24 +288,23 @@ class ScanExtension(BaseExtension): scan_extension_v2 = ScanExtension() class TileScanAPI(ActionView): - @use_args( - { - "filename": fields.String(missing=None, example=None), - "temporary": fields.Boolean(missing=False), - "stride_size": fields.List( - fields.Integer, missing=[2000, 1500, 100], example=[2000, 1500, 100] - ), - "grid": fields.List(fields.Integer, missing=[3, 3, 3], example=[3, 3, 3]), - "style": fields.String(missing="raster"), - "autofocus_dz": fields.Integer(missing=50), - "fast_autofocus": fields.Boolean(missing=False), - "use_video_port": fields.Boolean(missing=False), - "bayer": fields.Boolean(missing=False), - "annotations": fields.Dict(missing={}, example={"Foo": "Bar"}), - "tags": fields.List(fields.String, missing=[]), - "resize": fields.Dict(missing=None), # TODO: Validate keys - } - ) + args = { + "filename": fields.String(missing=None, example=None), + "temporary": fields.Boolean(missing=False), + "stride_size": fields.List( + fields.Integer, missing=[2000, 1500, 100], example=[2000, 1500, 100] + ), + "grid": fields.List(fields.Integer, missing=[3, 3, 3], example=[3, 3, 3]), + "style": fields.String(missing="raster"), + "autofocus_dz": fields.Integer(missing=50), + "fast_autofocus": fields.Boolean(missing=False), + "use_video_port": fields.Boolean(missing=False), + "bayer": fields.Boolean(missing=False), + "annotations": fields.Dict(missing={}, example={"Foo": "Bar"}), + "tags": fields.List(fields.String, missing=[]), + "resize": fields.Dict(missing=None), # TODO: Validate keys + } + def post(self, args): microscope = find_component("org.openflexure.microscope") diff --git a/openflexure_microscope/api/default_extensions/zip_builder.py b/openflexure_microscope/api/default_extensions/zip_builder.py index e168e42f..d012741c 100644 --- a/openflexure_microscope/api/default_extensions/zip_builder.py +++ b/openflexure_microscope/api/default_extensions/zip_builder.py @@ -14,16 +14,10 @@ import logging from labthings.server.find import find_component from labthings.server.view import View, ActionView, PropertyView -from labthings.server.schema import Schema +from labthings.server.schema import Schema, pre_dump from labthings.server import fields from labthings.server.extensions import BaseExtension from labthings.server.utilities import description_from_view -from labthings.server.decorators import ( - ThingAction, - ThingProperty, - marshal_with, - pre_dump, -) class ZipObjectSchema(Schema): @@ -140,7 +134,6 @@ default_zip_manager = ZipManager() class ZipBuilderAPIView(ActionView): def post(self): - ids = list(JsonResponse(request).json) microscope = find_component("org.openflexure.microscope") @@ -151,7 +144,8 @@ class ZipBuilderAPIView(ActionView): class ZipListAPIView(PropertyView): - @marshal_with(ZipObjectSchema(many=True)) + schema = ZipObjectSchema(many=True) + def get(self): return default_zip_manager.session_zips.values() diff --git a/openflexure_microscope/api/v2/views/actions/__init__.py b/openflexure_microscope/api/v2/views/actions/__init__.py index e06454c5..9c7ad8b3 100644 --- a/openflexure_microscope/api/v2/views/actions/__init__.py +++ b/openflexure_microscope/api/v2/views/actions/__init__.py @@ -58,7 +58,6 @@ def enabled_root_actions(): return {k: v for k, v in _actions.items() if v["conditions"]} -# @Tag("actions") class ActionsView(View): def get(self): """ diff --git a/openflexure_microscope/api/v2/views/actions/camera.py b/openflexure_microscope/api/v2/views/actions/camera.py index 59872992..176112cc 100644 --- a/openflexure_microscope/api/v2/views/actions/camera.py +++ b/openflexure_microscope/api/v2/views/actions/camera.py @@ -1,19 +1,11 @@ from openflexure_microscope.api.utilities import get_bool, JsonResponse from labthings.server.view import View, ActionView from labthings.server.find import find_component -from labthings.server.decorators import ( - use_args, - marshal_with, - doc, - tag, - ThingAction, - doc_response, -) from labthings.server import fields from openflexure_microscope.utilities import filter_dict -from openflexure_microscope.api.v2.views.captures import capture_schema +from openflexure_microscope.api.v2.views.captures import CaptureSchema import logging import io @@ -25,24 +17,23 @@ class CaptureAPI(ActionView): Create a new image capture. """ - @use_args( - { - "filename": fields.String(example="MyFileName"), - "temporary": fields.Boolean( - missing=False, description="Delete capture on shutdown" - ), - "use_video_port": fields.Boolean(missing=False), - "bayer": fields.Boolean( - missing=False, description="Store raw bayer data in file" - ), - "annotations": fields.Dict(missing={}, example={"Client": "SwaggerUI"}), - "tags": fields.List(fields.String, missing=[], example=["docs"]), - "resize": fields.Dict( - missing=None, example={"width": 640, "height": 480} - ), # TODO: Validate keys - } - ) - @marshal_with(capture_schema) + args = { + "filename": fields.String(example="MyFileName"), + "temporary": fields.Boolean( + missing=False, description="Delete capture on shutdown" + ), + "use_video_port": fields.Boolean(missing=False), + "bayer": fields.Boolean( + missing=False, description="Store raw bayer data in file" + ), + "annotations": fields.Dict(missing={}, example={"Client": "SwaggerUI"}), + "tags": fields.List(fields.String, missing=[], example=["docs"]), + "resize": fields.Dict( + missing=None, example={"width": 640, "height": 480} + ), # TODO: Validate keys + } + schema = CaptureSchema() + def post(self, args): """ Create a new capture @@ -78,18 +69,22 @@ class RAMCaptureAPI(ActionView): Take a non-persistant image capture. """ - @use_args( - { - "use_video_port": fields.Boolean(missing=True), - "bayer": fields.Boolean( - missing=False, description="Return with raw bayer data" - ), - "resize": fields.Dict( - missing=None, example={"width": 640, "height": 480} - ), # TODO: Validate keys + args = { + "use_video_port": fields.Boolean(missing=True), + "bayer": fields.Boolean( + missing=False, description="Return with raw bayer data" + ), + "resize": fields.Dict( + missing=None, example={"width": 640, "height": 480} + ), # TODO: Validate keys + } + + responses = { + 200: { + "content_type": "image/jpeg" } - ) - @doc_response(200, mimetype="image/jpeg") + } + def post(self, args): """ Take a non-persistant image capture. @@ -128,9 +123,8 @@ class GPUPreviewStartAPI(ActionView): in the format ``[x, y, width, height]``. """ - @use_args( - {"window": fields.List(fields.Integer, missing=[], example=[0, 0, 640, 480])} - ) + args = {"window": fields.List(fields.Integer, missing=[], example=[0, 0, 640, 480])} + def post(self, args): """ Start the onboard GPU preview. diff --git a/openflexure_microscope/api/v2/views/actions/stage.py b/openflexure_microscope/api/v2/views/actions/stage.py index 0b9d1372..334de1b8 100644 --- a/openflexure_microscope/api/v2/views/actions/stage.py +++ b/openflexure_microscope/api/v2/views/actions/stage.py @@ -1,7 +1,6 @@ from openflexure_microscope.api.utilities import JsonResponse from labthings.server.view import View, ActionView from labthings.server.find import find_component -from labthings.server.decorators import use_args, marshal_with, doc, ThingAction from labthings.server import fields from openflexure_microscope.utilities import axes_to_array, filter_dict @@ -12,16 +11,15 @@ import logging class MoveStageAPI(ActionView): - @use_args( - { - "absolute": fields.Boolean( - default=False, example=False, description="Move to an absolute position" - ), - "x": fields.Int(default=0, example=100), - "y": fields.Int(default=0, example=100), - "z": fields.Int(default=0, example=20), - } - ) + args = { + "absolute": fields.Boolean( + default=False, example=False, description="Move to an absolute position" + ), + "x": fields.Int(default=0, example=100), + "y": fields.Int(default=0, example=100), + "z": fields.Int(default=0, example=20), + } + def post(self, args): """ Move the microscope stage in x, y, z diff --git a/openflexure_microscope/api/v2/views/actions/system.py b/openflexure_microscope/api/v2/views/actions/system.py index d8756891..8677478d 100644 --- a/openflexure_microscope/api/v2/views/actions/system.py +++ b/openflexure_microscope/api/v2/views/actions/system.py @@ -3,8 +3,6 @@ import subprocess import os from sys import platform -from labthings.server.decorators import ThingAction, doc_response - def is_raspberrypi(raise_on_errors=False): """ @@ -19,7 +17,6 @@ class ShutdownAPI(ActionView): Attempt to shutdown the device """ - @doc_response(201) def post(self): """ Attempt to shutdown the device @@ -31,7 +28,7 @@ class ShutdownAPI(ActionView): ) out, err = p.communicate() - return {"out": out, "err": err}, 201 + return {"out": out, "err": err} class RebootAPI(ActionView): @@ -39,7 +36,6 @@ class RebootAPI(ActionView): Attempt to reboot the device """ - @doc_response(201) def post(self): """ Attempt to reboot the device @@ -51,4 +47,4 @@ class RebootAPI(ActionView): ) out, err = p.communicate() - return {"out": out, "err": err}, 201 + return {"out": out, "err": err} diff --git a/openflexure_microscope/api/v2/views/captures.py b/openflexure_microscope/api/v2/views/captures.py index b4b00e04..09f3ae4f 100644 --- a/openflexure_microscope/api/v2/views/captures.py +++ b/openflexure_microscope/api/v2/views/captures.py @@ -7,7 +7,6 @@ from labthings.server.schema import Schema from labthings.server import fields from labthings.server.view import View, PropertyView from labthings.server.utilities import description_from_view -from labthings.server.decorators import marshal_with, doc_response, Tag, ThingProperty from labthings.server.find import find_component @@ -84,16 +83,10 @@ class CaptureSchema(Schema): return data -capture_schema = CaptureSchema() -capture_list_schema = CaptureSchema(many=True) - - -from pprint import pprint - - -@Tag("captures") class CaptureList(PropertyView): - @marshal_with(CaptureSchema(many=True)) + tags = ["captures"] + schema = CaptureSchema(many=True) + def get(self): """ List all image captures @@ -103,9 +96,10 @@ class CaptureList(PropertyView): return image_list -@Tag("captures") class CaptureView(View): - @marshal_with(CaptureSchema()) + tags = ["captures"] + schema = CaptureSchema() + def get(self, id): """ Description of a single image capture @@ -136,9 +130,14 @@ class CaptureView(View): return "", 204 -@Tag("captures") class CaptureDownload(View): - @doc_response(200, mimetype="image/jpeg") + tags = ["captures"] + responses = { + 200: { + "content_type": "image/jpeg" + } + } + def get(self, id, filename): """ Image data for a single image capture @@ -172,8 +171,9 @@ class CaptureDownload(View): return send_file(img, mimetype="image/jpeg") -@Tag("captures") class CaptureTags(View): + tags = ["captures"] + def get(self, id): """ Get tags associated with a single image capture @@ -227,8 +227,9 @@ class CaptureTags(View): return capture_obj.tags -@Tag("captures") class CaptureAnnotations(View): + tags = ["captures"] + def get(self, id): """ Get annotations associated with a single image capture diff --git a/openflexure_microscope/api/v2/views/instrument.py b/openflexure_microscope/api/v2/views/instrument.py index 3a51633e..e7198373 100644 --- a/openflexure_microscope/api/v2/views/instrument.py +++ b/openflexure_microscope/api/v2/views/instrument.py @@ -5,8 +5,6 @@ from labthings.core.utilities import get_by_path, set_by_path, create_from_path from labthings.server.find import find_component from labthings.server.view import View, PropertyView -from labthings.server.decorators import ThingProperty, Tag, doc_response - from flask import request, abort import logging @@ -35,9 +33,12 @@ class SettingsProperty(PropertyView): return self.get() -@Tag("properties") class NestedSettingsProperty(View): - @doc_response(404, description="Settings key cannot be found") + tags = ["properties"] + responses = { + 404: {"description": "Settings key cannot be found"} + } + def get(self, route): """ Show a nested section of the current microscope settings @@ -52,7 +53,6 @@ class NestedSettingsProperty(View): return value - @doc_response(404, description="Settings key cannot be found") def put(self, route): """ Update a nested section of the current microscope settings @@ -79,9 +79,12 @@ class StateProperty(PropertyView): return microscope.state -@Tag("properties") class NestedStateProperty(View): - @doc_response(404, description="Status key cannot be found") + tags = ["properties"] + responses = { + 404: {"description": "Status key cannot be found"} + } + def get(self, route): """ Show a nested section of the current microscope state @@ -106,9 +109,12 @@ class ConfigurationProperty(PropertyView): return microscope.configuration -@Tag("properties") class NestedConfigurationProperty(View): - @doc_response(404, description="Configuration key cannot be found") + tags = ["properties"] + responses = { + 404: {"description": "Status key cannot be found"} + } + def get(self, route): """ Show a nested section of the current microscope state diff --git a/openflexure_microscope/api/v2/views/streams.py b/openflexure_microscope/api/v2/views/streams.py index f8b8cbe7..02eddc2e 100644 --- a/openflexure_microscope/api/v2/views/streams.py +++ b/openflexure_microscope/api/v2/views/streams.py @@ -4,17 +4,19 @@ from labthings.core.utilities import get_by_path, set_by_path, create_from_path from labthings.server.find import find_component from labthings.server.view import View, PropertyView -from labthings.server.decorators import doc_response, ThingProperty - -from flask import Response +from labthings.server.responses import Response class MjpegStream(PropertyView): """ Real-time MJPEG stream from the microscope camera """ + responses = { + 200: { + "content_type": "multipart/x-mixed-replace" + } + } - @doc_response(200, mimetype="multipart/x-mixed-replace") def get(self): """ MJPEG stream from the microscope camera. @@ -42,7 +44,13 @@ class SnapshotStream(PropertyView): Single JPEG snapshot from the camera stream """ - @doc_response(200, description="Snapshot taken", mimetype="image/jpeg") + responses = { + 200: { + "content_type": "image/jpeg", + "description": "Snapshot taken" + } + } + def get(self): """ Single snapshot from the camera stream