Added proper root representation
This commit is contained in:
parent
dac50f1f3a
commit
edecc01ca1
7 changed files with 122 additions and 13 deletions
|
|
@ -144,6 +144,9 @@ app.register_blueprint(task_blueprint, url_prefix=uri("/task", "v1"))
|
||||||
|
|
||||||
### V2
|
### V2
|
||||||
# Root routes
|
# Root routes
|
||||||
|
v2_root_blueprint = v2.blueprints.root.construct_blueprint(api_microscope)
|
||||||
|
app.register_blueprint(v2_root_blueprint, url_prefix=uri("/", "v2"))
|
||||||
|
|
||||||
v2_stream_blueprint = v2.blueprints.stream.construct_blueprint(api_microscope)
|
v2_stream_blueprint = v2.blueprints.stream.construct_blueprint(api_microscope)
|
||||||
app.register_blueprint(v2_stream_blueprint, url_prefix=uri("/", "v2"))
|
app.register_blueprint(v2_stream_blueprint, url_prefix=uri("/", "v2"))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
from . import captures, settings, status, tasks, stream, plugins, actions
|
from . import root, captures, settings, status, tasks, stream, plugins, actions
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
from flask import Blueprint, url_for, jsonify
|
from flask import Blueprint, url_for, jsonify
|
||||||
from sys import platform
|
from sys import platform
|
||||||
|
|
||||||
|
from openflexure_microscope.api.views import MicroscopeView
|
||||||
|
|
||||||
from . import camera, stage, system
|
from . import camera, stage, system
|
||||||
|
|
||||||
_actions = {
|
_actions = {
|
||||||
|
|
@ -64,11 +66,14 @@ def actions_representation():
|
||||||
|
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
class ActionsAPI(MicroscopeView):
|
||||||
|
def get(self):
|
||||||
|
return jsonify(actions_representation())
|
||||||
|
|
||||||
def construct_blueprint(microscope_obj):
|
def construct_blueprint(microscope_obj):
|
||||||
global _actions
|
global _actions
|
||||||
|
|
||||||
blueprint = Blueprint("actions_blueprint", __name__)
|
blueprint = Blueprint("v2_actions_blueprint", __name__)
|
||||||
|
|
||||||
# For each enabled action route defined in our dictionary above
|
# For each enabled action route defined in our dictionary above
|
||||||
for name, action in enabled_actions().items():
|
for name, action in enabled_actions().items():
|
||||||
|
|
@ -78,8 +83,8 @@ def construct_blueprint(microscope_obj):
|
||||||
view_func=action["view_class"].as_view(name, microscope=microscope_obj),
|
view_func=action["view_class"].as_view(name, microscope=microscope_obj),
|
||||||
)
|
)
|
||||||
|
|
||||||
@blueprint.route("/")
|
blueprint.add_url_rule(
|
||||||
def representation():
|
"/", view_func=ActionsAPI.as_view("actions", microscope=microscope_obj)
|
||||||
return jsonify(actions_representation())
|
)
|
||||||
|
|
||||||
return blueprint
|
return blueprint
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ class TagsAPI(MicroscopeView):
|
||||||
|
|
||||||
|
|
||||||
def construct_blueprint(microscope_obj):
|
def construct_blueprint(microscope_obj):
|
||||||
blueprint = Blueprint("captures_blueprint", __name__)
|
blueprint = Blueprint("v2_captures_blueprint", __name__)
|
||||||
|
|
||||||
# Tag routes
|
# Tag routes
|
||||||
blueprint.add_url_rule(
|
blueprint.add_url_rule(
|
||||||
|
|
@ -405,6 +405,6 @@ def construct_blueprint(microscope_obj):
|
||||||
)
|
)
|
||||||
|
|
||||||
blueprint.add_url_rule(
|
blueprint.add_url_rule(
|
||||||
"/", view_func=ListAPI.as_view("capture_list", microscope=microscope_obj)
|
"/", view_func=ListAPI.as_view("captures", microscope=microscope_obj)
|
||||||
)
|
)
|
||||||
return blueprint
|
return blueprint
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from openflexure_microscope.plugins import PluginLoader, MicroscopePlugin
|
from openflexure_microscope.plugins import PluginLoader, MicroscopePlugin
|
||||||
from openflexure_microscope.api.views import MicroscopeViewPlugin
|
from openflexure_microscope.api.views import MicroscopeViewPlugin
|
||||||
|
|
||||||
from flask import Blueprint, jsonify
|
from flask import Blueprint, jsonify, url_for
|
||||||
from openflexure_microscope.api.views import MicroscopeView
|
from openflexure_microscope.api.views import MicroscopeView
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
|
@ -27,6 +27,11 @@ def plugins_representation(plugin_loader_object: PluginLoader):
|
||||||
"routes": plugin["routes"],
|
"routes": plugin["routes"],
|
||||||
"form": plugin["form"],
|
"form": plugin["form"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for route in d["routes"]:
|
||||||
|
route_id = route["id"]
|
||||||
|
uri = url_for(f"v2_plugins_blueprint.{route_id}")
|
||||||
|
route["links"]["self"] = uri
|
||||||
plugins.append(d)
|
plugins.append(d)
|
||||||
|
|
||||||
return plugins
|
return plugins
|
||||||
|
|
@ -51,7 +56,7 @@ class PluginFormAPI(MicroscopeView):
|
||||||
|
|
||||||
def construct_blueprint(microscope_obj):
|
def construct_blueprint(microscope_obj):
|
||||||
|
|
||||||
blueprint = Blueprint("plugins_blueprint", __name__)
|
blueprint = Blueprint("v2_plugins_blueprint", __name__)
|
||||||
|
|
||||||
# Create a base route to return plugin API forms, if any exist
|
# Create a base route to return plugin API forms, if any exist
|
||||||
blueprint.add_url_rule(
|
blueprint.add_url_rule(
|
||||||
|
|
@ -110,7 +115,12 @@ def construct_blueprint(microscope_obj):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add route to the plugin representation dictionary
|
# Add route to the plugin representation dictionary
|
||||||
plugin_representation["routes"].append(full_view_route)
|
route_representation = {
|
||||||
|
"id": plugin_route_id,
|
||||||
|
"route": full_view_route,
|
||||||
|
"links": {},
|
||||||
|
}
|
||||||
|
plugin_representation["routes"].append(route_representation)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
|
|
|
||||||
44
openflexure_microscope/api/v2/blueprints/root.py
Normal file
44
openflexure_microscope/api/v2/blueprints/root.py
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
from flask import Blueprint, jsonify, url_for
|
||||||
|
from openflexure_microscope import Microscope
|
||||||
|
from openflexure_microscope.api.views import MicroscopeView
|
||||||
|
|
||||||
|
def root_representation(microscope_obj: Microscope):
|
||||||
|
d = {
|
||||||
|
"settings": {
|
||||||
|
"description": "Writeable settings for the microscope, and attached hardware",
|
||||||
|
"links": {"self": url_for("v2_settings_blueprint.settings")}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"description": "Read-only status of the microscope, and attached hardware info",
|
||||||
|
"links": {"self": url_for("v2_status_blueprint.status")}
|
||||||
|
},
|
||||||
|
"plugins": {
|
||||||
|
"description": "Top-level representation of attached and enabled plugins",
|
||||||
|
"links": {"self": url_for("v2_plugins_blueprint.plugins")}
|
||||||
|
},
|
||||||
|
"captures": {
|
||||||
|
"description": "Top-level representation of all acquired captures",
|
||||||
|
"links": {"self": url_for("v2_captures_blueprint.captures")}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"description": "Top-level representation of enabled actions",
|
||||||
|
"links": {"self": url_for("v2_actions_blueprint.actions")}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
class RootAPI(MicroscopeView):
|
||||||
|
def get(self):
|
||||||
|
|
||||||
|
return jsonify(root_representation(self.microscope))
|
||||||
|
|
||||||
|
|
||||||
|
def construct_blueprint(microscope_obj):
|
||||||
|
blueprint = Blueprint("root_blueprint", __name__)
|
||||||
|
|
||||||
|
blueprint.add_url_rule(
|
||||||
|
"/", view_func=RootAPI.as_view("root_repr", microscope=microscope_obj)
|
||||||
|
)
|
||||||
|
return blueprint
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import importlib
|
import importlib
|
||||||
|
import copy
|
||||||
import os
|
import os
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from openflexure_microscope.api.views import MicroscopeViewPlugin
|
||||||
|
|
||||||
|
|
||||||
class ConColors:
|
class ConColors:
|
||||||
HEADER = "\033[95m"
|
HEADER = "\033[95m"
|
||||||
|
|
@ -137,6 +140,50 @@ def class_from_map(plugin_map):
|
||||||
return load_plugin_class(*plugin_arr)
|
return load_plugin_class(*plugin_arr)
|
||||||
|
|
||||||
|
|
||||||
|
def expand_views(plugin_object, plugin_name):
|
||||||
|
routes = []
|
||||||
|
|
||||||
|
# If plugin contains valid endpoints
|
||||||
|
if hasattr(plugin_object, "api_views") and isinstance(plugin_object.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_object.api_views.items():
|
||||||
|
|
||||||
|
# Remove all leading slashes from view route
|
||||||
|
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, 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 issubclass(view_class, MicroscopeViewPlugin):
|
||||||
|
|
||||||
|
# Create a Python-safe name for the route
|
||||||
|
plugin_route_id = "plugin{}".format(full_view_route).replace(
|
||||||
|
"/", "_"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add route to the plugin representation dictionary
|
||||||
|
route_representation = {
|
||||||
|
"id": plugin_route_id,
|
||||||
|
"route": full_view_route,
|
||||||
|
"links": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
routes.append(route_representation)
|
||||||
|
|
||||||
|
return routes
|
||||||
|
|
||||||
|
|
||||||
class PluginLoader(object):
|
class PluginLoader(object):
|
||||||
"""
|
"""
|
||||||
A mount-point for all loaded plugins. Attaches to a Microscope object.
|
A mount-point for all loaded plugins. Attaches to a Microscope object.
|
||||||
|
|
@ -174,7 +221,7 @@ class PluginLoader(object):
|
||||||
|
|
||||||
if plugin_class is not None:
|
if plugin_class is not None:
|
||||||
|
|
||||||
pythonsafe_plugin_name = plugin_name.replace("/", "_")
|
plugin_name_python_safe = plugin_name.replace("/", "_")
|
||||||
|
|
||||||
if plugin_class and plugin_name:
|
if plugin_class and plugin_name:
|
||||||
plugin_object = plugin_class()
|
plugin_object = plugin_class()
|
||||||
|
|
@ -194,13 +241,13 @@ class PluginLoader(object):
|
||||||
plugin_object, MicroscopePlugin
|
plugin_object, MicroscopePlugin
|
||||||
): # If plugin_object is an instance of MicroscopePlugin
|
): # If plugin_object is an instance of MicroscopePlugin
|
||||||
# Attach plugin_object to the plugin mount
|
# Attach plugin_object to the plugin mount
|
||||||
setattr(self, pythonsafe_plugin_name, plugin_object)
|
setattr(self, plugin_name_python_safe, plugin_object)
|
||||||
|
|
||||||
# Store the plugin object, and it's properties
|
# Store the plugin object, and it's properties
|
||||||
self._plugins.append(
|
self._plugins.append(
|
||||||
{
|
{
|
||||||
"name": plugin_name,
|
"name": plugin_name,
|
||||||
"python_name": pythonsafe_plugin_name,
|
"python_name": plugin_name_python_safe,
|
||||||
"plugin": plugin_object,
|
"plugin": plugin_object,
|
||||||
"routes": [],
|
"routes": [],
|
||||||
"form": None,
|
"form": None,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue