Refactored adding views, actions, props and components
This commit is contained in:
parent
7715c19305
commit
a4196b6765
10 changed files with 62 additions and 66 deletions
|
|
@ -69,7 +69,7 @@ app, labthing = create_app(
|
||||||
app.json_encoder = JSONEncoder
|
app.json_encoder = JSONEncoder
|
||||||
|
|
||||||
# Attach lab devices
|
# Attach lab devices
|
||||||
labthing.register_device(api_microscope, "org.openflexure.microscope")
|
labthing.add_component(api_microscope, "org.openflexure.microscope")
|
||||||
|
|
||||||
# Attach extensions
|
# Attach extensions
|
||||||
if not os.path.isfile(USER_EXTENSIONS_PATH):
|
if not os.path.isfile(USER_EXTENSIONS_PATH):
|
||||||
|
|
@ -78,33 +78,27 @@ for extension in find_extensions(USER_EXTENSIONS_PATH):
|
||||||
labthing.register_extension(extension)
|
labthing.register_extension(extension)
|
||||||
|
|
||||||
# Attach captures resources
|
# Attach captures resources
|
||||||
labthing.add_resource(views.CaptureList, f"/captures")
|
labthing.add_view(views.CaptureList, f"/captures")
|
||||||
labthing.register_property(views.CaptureList)
|
labthing.add_view(views.CaptureResource, f"/captures/<id>")
|
||||||
labthing.add_resource(views.CaptureResource, f"/captures/<id>")
|
labthing.add_view(views.CaptureDownload, f"/captures/<id>/download/<filename>")
|
||||||
labthing.add_resource(views.CaptureDownload, f"/captures/<id>/download/<filename>")
|
labthing.add_view(views.CaptureTags, f"/captures/<id>/tags")
|
||||||
labthing.add_resource(views.CaptureTags, f"/captures/<id>/tags")
|
labthing.add_view(views.CaptureMetadata, f"/captures/<id>/metadata")
|
||||||
labthing.add_resource(views.CaptureMetadata, f"/captures/<id>/metadata")
|
|
||||||
|
|
||||||
# Attach settings and status resources
|
# Attach settings and status resources
|
||||||
labthing.add_resource(views.SettingsProperty, f"/settings")
|
labthing.add_view(views.SettingsProperty, f"/settings")
|
||||||
labthing.register_property(views.SettingsProperty)
|
labthing.add_view(views.NestedSettingsProperty, "/settings/<path:route>")
|
||||||
labthing.add_resource(views.NestedSettingsProperty, "/settings/<path:route>")
|
labthing.add_view(views.StatusProperty, "/status")
|
||||||
labthing.add_resource(views.StatusProperty, "/status")
|
labthing.add_view(views.NestedStatusProperty, "/status/<path:route>")
|
||||||
labthing.register_property(views.StatusProperty)
|
|
||||||
labthing.add_resource(views.NestedStatusProperty, "/status/<path:route>")
|
|
||||||
|
|
||||||
# Attach streams resources
|
# Attach streams resources
|
||||||
labthing.add_resource(views.MjpegStream, f"/streams/mjpeg")
|
labthing.add_view(views.MjpegStream, f"/streams/mjpeg")
|
||||||
labthing.register_property(views.MjpegStream)
|
labthing.add_view(views.SnapshotStream, f"/streams/snapshot")
|
||||||
labthing.add_resource(views.SnapshotStream, f"/streams/snapshot")
|
|
||||||
labthing.register_property(views.SnapshotStream)
|
|
||||||
|
|
||||||
# Attach microscope action resources
|
# Attach microscope action resources
|
||||||
for name, action in views.enabled_root_actions().items():
|
for name, action in views.enabled_root_actions().items():
|
||||||
view_class = action["view_class"]
|
view_class = action["view_class"]
|
||||||
rule = action["rule"]
|
rule = action["rule"]
|
||||||
labthing.add_resource(view_class, f"/actions{rule}")
|
labthing.add_view(view_class, f"/actions{rule}")
|
||||||
labthing.register_action(view_class)
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/routes")
|
@app.route("/routes")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
from openflexure_microscope.common.flask_labthings.find import find_device
|
from openflexure_microscope.common.flask_labthings.find import find_device
|
||||||
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
||||||
from openflexure_microscope.common.flask_labthings.resource import Resource
|
from openflexure_microscope.common.flask_labthings.resource import Resource
|
||||||
|
from openflexure_microscope.common.flask_labthings.decorators import (
|
||||||
|
ThingAction,
|
||||||
|
ThingProperty,
|
||||||
|
)
|
||||||
|
|
||||||
from openflexure_microscope.devel import JsonResponse, request, jsonify, taskify, abort
|
from openflexure_microscope.devel import JsonResponse, request, jsonify, taskify, abort
|
||||||
from openflexure_microscope.utilities import set_properties
|
from openflexure_microscope.utilities import set_properties
|
||||||
|
|
@ -298,6 +302,7 @@ class MeasureSharpnessAPI(Resource):
|
||||||
return jsonify({"sharpness": measure_sharpness(microscope)})
|
return jsonify({"sharpness": measure_sharpness(microscope)})
|
||||||
|
|
||||||
|
|
||||||
|
@ThingAction
|
||||||
class AutofocusAPI(Resource):
|
class AutofocusAPI(Resource):
|
||||||
"""
|
"""
|
||||||
Run a standard autofocus
|
Run a standard autofocus
|
||||||
|
|
@ -324,6 +329,7 @@ class AutofocusAPI(Resource):
|
||||||
abort(503, "No stage connected. Unable to autofocus.")
|
abort(503, "No stage connected. Unable to autofocus.")
|
||||||
|
|
||||||
|
|
||||||
|
@ThingAction
|
||||||
class FastAutofocusAPI(Resource):
|
class FastAutofocusAPI(Resource):
|
||||||
"""
|
"""
|
||||||
Run a fast autofocus
|
Run a fast autofocus
|
||||||
|
|
@ -359,9 +365,5 @@ autofocus_extension_v2.add_method(fast_autofocus, "fast_autofocus")
|
||||||
autofocus_extension_v2.add_method(autofocus, "autofocus")
|
autofocus_extension_v2.add_method(autofocus, "autofocus")
|
||||||
|
|
||||||
autofocus_extension_v2.add_view(MeasureSharpnessAPI, "/measure_sharpness")
|
autofocus_extension_v2.add_view(MeasureSharpnessAPI, "/measure_sharpness")
|
||||||
|
|
||||||
autofocus_extension_v2.add_view(AutofocusAPI, "/autofocus")
|
autofocus_extension_v2.add_view(AutofocusAPI, "/autofocus")
|
||||||
autofocus_extension_v2.register_action(AutofocusAPI)
|
|
||||||
|
|
||||||
autofocus_extension_v2.add_view(FastAutofocusAPI, "/fast_autofocus")
|
autofocus_extension_v2.add_view(FastAutofocusAPI, "/fast_autofocus")
|
||||||
autofocus_extension_v2.register_action(FastAutofocusAPI)
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ from openflexure_microscope.common.flask_labthings.find import (
|
||||||
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
||||||
from openflexure_microscope.common.flask_labthings.decorators import (
|
from openflexure_microscope.common.flask_labthings.decorators import (
|
||||||
marshal_task,
|
marshal_task,
|
||||||
marshal_with,
|
|
||||||
use_args,
|
use_args,
|
||||||
|
ThingAction,
|
||||||
)
|
)
|
||||||
from openflexure_microscope.common.flask_labthings import fields
|
from openflexure_microscope.common.flask_labthings import fields
|
||||||
|
|
||||||
|
|
@ -340,6 +340,7 @@ def stack(
|
||||||
### Web views
|
### Web views
|
||||||
|
|
||||||
|
|
||||||
|
@ThingAction
|
||||||
class TileScanAPI(Resource):
|
class TileScanAPI(Resource):
|
||||||
@use_args(
|
@use_args(
|
||||||
{
|
{
|
||||||
|
|
@ -398,4 +399,3 @@ class TileScanAPI(Resource):
|
||||||
scan_extension_v2 = BaseExtension("scan")
|
scan_extension_v2 = BaseExtension("scan")
|
||||||
|
|
||||||
scan_extension_v2.add_view(TileScanAPI, "/tile")
|
scan_extension_v2.add_view(TileScanAPI, "/tile")
|
||||||
scan_extension_v2.register_action(TileScanAPI)
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@ import logging
|
||||||
from openflexure_microscope.common.flask_labthings.find import find_device
|
from openflexure_microscope.common.flask_labthings.find import find_device
|
||||||
from openflexure_microscope.common.flask_labthings.resource import Resource
|
from openflexure_microscope.common.flask_labthings.resource import Resource
|
||||||
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
||||||
|
from openflexure_microscope.common.flask_labthings.decorators import (
|
||||||
|
ThingAction,
|
||||||
|
ThingProperty,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ZipManager:
|
class ZipManager:
|
||||||
|
|
@ -91,6 +95,7 @@ class ZipManager:
|
||||||
default_zip_manager = ZipManager()
|
default_zip_manager = ZipManager()
|
||||||
|
|
||||||
|
|
||||||
|
@ThingAction
|
||||||
class ZipBuilderAPIView(Resource):
|
class ZipBuilderAPIView(Resource):
|
||||||
def post(self):
|
def post(self):
|
||||||
|
|
||||||
|
|
@ -103,6 +108,7 @@ class ZipBuilderAPIView(Resource):
|
||||||
return jsonify(task.state), 201
|
return jsonify(task.state), 201
|
||||||
|
|
||||||
|
|
||||||
|
@ThingProperty
|
||||||
class ZipListAPIView(Resource):
|
class ZipListAPIView(Resource):
|
||||||
def get(self):
|
def get(self):
|
||||||
return jsonify(default_zip_manager.session_zips)
|
return jsonify(default_zip_manager.session_zips)
|
||||||
|
|
@ -146,4 +152,3 @@ zip_extension_v2.add_view(ZipGetterAPIView, "/get/<string:session_id>")
|
||||||
zip_extension_v2.add_view(ZipListAPIView, "/get")
|
zip_extension_v2.add_view(ZipListAPIView, "/get")
|
||||||
|
|
||||||
zip_extension_v2.add_view(ZipBuilderAPIView, "/build")
|
zip_extension_v2.add_view(ZipBuilderAPIView, "/build")
|
||||||
zip_extension_v2.register_action(ZipBuilderAPIView)
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
from openflexure_microscope.common.flask_labthings.resource import Resource
|
from openflexure_microscope.common.flask_labthings.resource import Resource
|
||||||
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
|
||||||
|
from openflexure_microscope.common.flask_labthings.decorators import (
|
||||||
|
ThingAction,
|
||||||
|
ThingProperty,
|
||||||
|
)
|
||||||
|
|
||||||
from openflexure_microscope.api.utilities.gui import expand_routes
|
from openflexure_microscope.api.utilities.gui import expand_routes
|
||||||
|
|
||||||
|
|
@ -72,6 +76,7 @@ static_form = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ThingProperty
|
||||||
class TestAPIView(Resource):
|
class TestAPIView(Resource):
|
||||||
def get(self):
|
def get(self):
|
||||||
global val_int
|
global val_int
|
||||||
|
|
@ -79,6 +84,7 @@ class TestAPIView(Resource):
|
||||||
return jsonify({"val": True})
|
return jsonify({"val": True})
|
||||||
|
|
||||||
|
|
||||||
|
@ThingAction
|
||||||
class TestDoAPIView(Resource):
|
class TestDoAPIView(Resource):
|
||||||
def post(self):
|
def post(self):
|
||||||
global val_int
|
global val_int
|
||||||
|
|
|
||||||
|
|
@ -77,16 +77,20 @@ def ThingAction(viewcls):
|
||||||
update_spec(viewcls, {"_groups": ["actions"]})
|
update_spec(viewcls, {"_groups": ["actions"]})
|
||||||
return viewcls
|
return viewcls
|
||||||
|
|
||||||
|
|
||||||
thing_action = ThingAction
|
thing_action = ThingAction
|
||||||
|
|
||||||
|
|
||||||
def ThingProperty(viewcls):
|
def ThingProperty(viewcls):
|
||||||
# Pass params to call function attribute for external access
|
# Pass params to call function attribute for external access
|
||||||
update_spec(viewcls, {"tags": ["properties"]})
|
update_spec(viewcls, {"tags": ["properties"]})
|
||||||
update_spec(viewcls, {"_groups": ["properties"]})
|
update_spec(viewcls, {"_groups": ["properties"]})
|
||||||
return viewcls
|
return viewcls
|
||||||
|
|
||||||
|
|
||||||
thing_property = ThingProperty
|
thing_property = ThingProperty
|
||||||
|
|
||||||
|
|
||||||
class use_args(object):
|
class use_args(object):
|
||||||
def __init__(self, schema, **kwargs):
|
def __init__(self, schema, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -121,8 +125,10 @@ class Doc(object):
|
||||||
update_spec(f, self.kwargs)
|
update_spec(f, self.kwargs)
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
doc = Doc
|
doc = Doc
|
||||||
|
|
||||||
|
|
||||||
class Tag(object):
|
class Tag(object):
|
||||||
def __init__(self, tags):
|
def __init__(self, tags):
|
||||||
if isinstance(tags, str):
|
if isinstance(tags, str):
|
||||||
|
|
@ -137,8 +143,10 @@ class Tag(object):
|
||||||
update_spec(f, {"tags": self.tags})
|
update_spec(f, {"tags": self.tags})
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
tag = Tag
|
tag = Tag
|
||||||
|
|
||||||
|
|
||||||
class doc_response(object):
|
class doc_response(object):
|
||||||
def __init__(self, code, description=None, **kwargs):
|
def __init__(self, code, description=None, **kwargs):
|
||||||
self.code = code
|
self.code = code
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,11 @@ class LabThing(object):
|
||||||
):
|
):
|
||||||
self.app = app
|
self.app = app
|
||||||
|
|
||||||
self.devices = {}
|
self.components = {}
|
||||||
|
|
||||||
self.extensions = {}
|
self.extensions = {}
|
||||||
|
|
||||||
self.resources = []
|
self.views = []
|
||||||
self.properties = {}
|
self.properties = {}
|
||||||
self.actions = {}
|
self.actions = {}
|
||||||
|
|
||||||
|
|
@ -93,8 +93,8 @@ class LabThing(object):
|
||||||
app.extensions[EXTENSION_NAME] = self
|
app.extensions[EXTENSION_NAME] = self
|
||||||
|
|
||||||
# Add resources, if registered before tying to a Flask app
|
# Add resources, if registered before tying to a Flask app
|
||||||
if len(self.resources) > 0:
|
if len(self.views) > 0:
|
||||||
for resource, urls, endpoint, kwargs in self.resources:
|
for resource, urls, endpoint, kwargs in self.views:
|
||||||
self._register_view(app, resource, *urls, endpoint=endpoint, **kwargs)
|
self._register_view(app, resource, *urls, endpoint=endpoint, **kwargs)
|
||||||
|
|
||||||
# Create base routes
|
# Create base routes
|
||||||
|
|
@ -110,19 +110,15 @@ class LabThing(object):
|
||||||
self.app.register_blueprint(docs_blueprint, url_prefix=self.url_prefix)
|
self.app.register_blueprint(docs_blueprint, url_prefix=self.url_prefix)
|
||||||
|
|
||||||
# Add extension overview
|
# Add extension overview
|
||||||
self.add_resource(
|
self.add_view(ExtensionList, "/extensions", endpoint=EXTENSION_LIST_ENDPOINT)
|
||||||
ExtensionList, "/extensions", endpoint=EXTENSION_LIST_ENDPOINT
|
|
||||||
)
|
|
||||||
self.register_property(ExtensionList)
|
|
||||||
# Add task routes
|
# Add task routes
|
||||||
self.add_resource(TaskList, "/tasks", endpoint=TASK_LIST_ENDPOINT)
|
self.add_view(TaskList, "/tasks", endpoint=TASK_LIST_ENDPOINT)
|
||||||
self.register_property(TaskList)
|
self.add_view(TaskResource, "/tasks/<id>", endpoint=TASK_ENDPOINT)
|
||||||
self.add_resource(TaskResource, "/tasks/<id>", endpoint=TASK_ENDPOINT)
|
|
||||||
|
|
||||||
### Device stuff
|
### Device stuff
|
||||||
|
|
||||||
def register_device(self, device_object, device_name: str):
|
def add_component(self, device_object, device_name: str):
|
||||||
self.devices[device_name] = device_object
|
self.components[device_name] = device_object
|
||||||
|
|
||||||
### Extension stuff
|
### Extension stuff
|
||||||
|
|
||||||
|
|
@ -134,18 +130,12 @@ class LabThing(object):
|
||||||
|
|
||||||
for extension_view_id, extension_view in extension_object.views.items():
|
for extension_view_id, extension_view in extension_object.views.items():
|
||||||
# Add route to the extensions blueprint
|
# Add route to the extensions blueprint
|
||||||
self.add_resource(
|
self.add_view(
|
||||||
extension_view["view"],
|
extension_view["view"],
|
||||||
"/extensions" + extension_view["rule"],
|
"/extensions" + extension_view["rule"],
|
||||||
**extension_view["kwargs"],
|
**extension_view["kwargs"],
|
||||||
)
|
)
|
||||||
|
|
||||||
for prop in extension_object.properties:
|
|
||||||
self.register_property(prop)
|
|
||||||
|
|
||||||
for action in extension_object.actions:
|
|
||||||
self.register_action(action)
|
|
||||||
|
|
||||||
### Resource stuff
|
### Resource stuff
|
||||||
|
|
||||||
def _complete_url(self, url_part, registration_prefix):
|
def _complete_url(self, url_part, registration_prefix):
|
||||||
|
|
@ -158,16 +148,8 @@ class LabThing(object):
|
||||||
parts = [registration_prefix, self.url_prefix, url_part]
|
parts = [registration_prefix, self.url_prefix, url_part]
|
||||||
return "".join([part for part in parts if part])
|
return "".join([part for part in parts if part])
|
||||||
|
|
||||||
def register_property(self, resource):
|
def add_view(self, resource, *urls, endpoint=None, **kwargs):
|
||||||
logging.warning("register_property is deprecated. Use the @ltproperty class decorator instead.")
|
"""Adds a view to the api.
|
||||||
pass
|
|
||||||
|
|
||||||
def register_action(self, resource):
|
|
||||||
logging.warning("register_action is deprecated. Use the @ltaction class decorator instead.")
|
|
||||||
pass
|
|
||||||
|
|
||||||
def add_resource(self, resource, *urls, endpoint=None, **kwargs):
|
|
||||||
"""Adds a resource to the api.
|
|
||||||
:param resource: the class name of your resource
|
:param resource: the class name of your resource
|
||||||
:type resource: :class:`Type[Resource]`
|
:type resource: :class:`Type[Resource]`
|
||||||
:param urls: one or more url routes to match for the resource, standard
|
:param urls: one or more url routes to match for the resource, standard
|
||||||
|
|
@ -197,11 +179,11 @@ class LabThing(object):
|
||||||
if self.app is not None:
|
if self.app is not None:
|
||||||
self._register_view(self.app, resource, *urls, endpoint=endpoint, **kwargs)
|
self._register_view(self.app, resource, *urls, endpoint=endpoint, **kwargs)
|
||||||
|
|
||||||
self.resources.append((resource, urls, endpoint, kwargs))
|
self.views.append((resource, urls, endpoint, kwargs))
|
||||||
|
|
||||||
def resource(self, *urls, **kwargs):
|
def view(self, *urls, **kwargs):
|
||||||
def decorator(cls):
|
def decorator(cls):
|
||||||
self.add_resource(cls, *urls, **kwargs)
|
self.add_view(cls, *urls, **kwargs)
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,12 @@ def update_spec(obj, spec):
|
||||||
rupdate(obj.__apispec__, spec)
|
rupdate(obj.__apispec__, spec)
|
||||||
return obj.__apispec__
|
return obj.__apispec__
|
||||||
|
|
||||||
|
|
||||||
def get_spec(obj):
|
def get_spec(obj):
|
||||||
obj.__apispec__ = obj.__dict__.get("__apispec__", {})
|
obj.__apispec__ = obj.__dict__.get("__apispec__", {})
|
||||||
return obj.__apispec__
|
return obj.__apispec__
|
||||||
|
|
||||||
|
|
||||||
def view2path(rule: str, view: Resource, spec: APISpec):
|
def view2path(rule: str, view: Resource, spec: APISpec):
|
||||||
params = {
|
params = {
|
||||||
"path": rule, # TODO: Validate this slightly (leading / etc)
|
"path": rule, # TODO: Validate this slightly (leading / etc)
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,13 @@
|
||||||
"""
|
"""
|
||||||
Top-level representation of attached and enabled Extensions
|
Top-level representation of attached and enabled Extensions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from openflexure_microscope.common.flask_labthings.utilities import get_docstring
|
|
||||||
from openflexure_microscope.common.flask_labthings.schema import Schema
|
|
||||||
from openflexure_microscope.common.flask_labthings import fields
|
|
||||||
|
|
||||||
from ..resource import Resource
|
from ..resource import Resource
|
||||||
from ..find import registered_extensions
|
from ..find import registered_extensions
|
||||||
from ..schema import ExtensionSchema
|
from ..schema import ExtensionSchema
|
||||||
from ..decorators import marshal_with
|
from ..decorators import marshal_with, ThingProperty
|
||||||
|
|
||||||
|
|
||||||
|
@ThingProperty
|
||||||
class ExtensionList(Resource):
|
class ExtensionList(Resource):
|
||||||
"""
|
"""
|
||||||
List and basic documentation for all enabled Extensions
|
List and basic documentation for all enabled Extensions
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
from flask import abort, url_for
|
from flask import abort, url_for
|
||||||
|
|
||||||
from ..decorators import marshal_with
|
from ..decorators import marshal_with, ThingProperty
|
||||||
from ..resource import Resource
|
from ..resource import Resource
|
||||||
from ..schema import TaskSchema
|
from ..schema import TaskSchema
|
||||||
|
|
||||||
from openflexure_microscope.common.labthings_core import tasks
|
from openflexure_microscope.common.labthings_core import tasks
|
||||||
|
|
||||||
|
|
||||||
|
@ThingProperty
|
||||||
class TaskList(Resource):
|
class TaskList(Resource):
|
||||||
"""
|
"""
|
||||||
List and basic documentation for all session tasks
|
List and basic documentation for all session tasks
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue