Use more docstrings as descriptions

This commit is contained in:
Joel Collins 2019-11-20 12:08:25 +00:00
parent d3f2807bb9
commit 9b387985e3
12 changed files with 88 additions and 59 deletions

View file

@ -1,7 +1,13 @@
import logging import logging
from werkzeug.exceptions import BadRequest from werkzeug.exceptions import BadRequest
from flask import url_for from flask import url_for, Blueprint
def blueprint_for_module(module_name, api_ver=2, suffix=""):
return Blueprint(blueprint_name_for_module(module_name, api_ver=api_ver, suffix=suffix), module_name)
def blueprint_name_for_module(module_name, api_ver=2, suffix=""):
bp_name = module_name.split('.')[-1]
return f"v{api_ver}_{bp_name}_blueprint{suffix}"
class JsonResponse: class JsonResponse:
def __init__(self, request): def __init__(self, request):

View file

@ -1,12 +1,16 @@
"""
Top-level representation of enabled actions
"""
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.utilities import get_docstring from openflexure_microscope.api.utilities import blueprint_for_module
from openflexure_microscope.utilities import get_docstring, description_from_view
from openflexure_microscope.api.views import MicroscopeView from openflexure_microscope.api.views import MicroscopeView
from . import camera, stage, system from . import camera, stage, system
# TODO: Could allowed methods be calculated automatically by looking at what methods exist?
_actions = { _actions = {
"capture": { "capture": {
"rule": "/camera/capture/", "rule": "/camera/capture/",
@ -53,11 +57,12 @@ def actions_representation():
for name, action in enabled_actions().items(): for name, action in enabled_actions().items():
d = { d = {
"links": {"self": url_for(f".{name}")}, "links": {"self": url_for(f".{name}")},
"description": get_docstring(action["view_class"]),
"rule": action["rule"], "rule": action["rule"],
"view_class": str(action["view_class"]), "view_class": str(action["view_class"]),
} }
d.update(description_from_view(action["view_class"]))
actions[name] = d actions[name] = d
return actions return actions
@ -69,7 +74,7 @@ class ActionsAPI(MicroscopeView):
def construct_blueprint(microscope_obj): def construct_blueprint(microscope_obj):
global _actions global _actions
blueprint = Blueprint("v2_actions_blueprint", __name__) blueprint = blueprint_for_module(__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():

View file

@ -9,9 +9,6 @@ from flask import jsonify, request, abort, url_for, redirect, send_file
class CaptureAPI(MicroscopeView): class CaptureAPI(MicroscopeView):
""" """
Create a new image capture. Create a new image capture.
Allowed methods:
POST
""" """
def post(self): def post(self):
""" """
@ -109,9 +106,6 @@ class CaptureAPI(MicroscopeView):
class GPUPreviewStartAPI(MicroscopeView): class GPUPreviewStartAPI(MicroscopeView):
""" """
Start the onboard GPU preview. Start the onboard GPU preview.
Allowed methods:
POST
""" """
def post(self, operation): def post(self, operation):
""" """
@ -157,9 +151,6 @@ class GPUPreviewStartAPI(MicroscopeView):
class GPUPreviewStopAPI(MicroscopeView): class GPUPreviewStopAPI(MicroscopeView):
""" """
Stop the onboard GPU preview. Stop the onboard GPU preview.
Allowed methods:
POST
""" """
def post(self, operation): def post(self, operation):
""" """

View file

@ -10,9 +10,6 @@ import logging
class MoveStageAPI(MicroscopeView): class MoveStageAPI(MicroscopeView):
""" """
Handle stage movements. Handle stage movements.
Allowed methods:
POST
""" """
def post(self): def post(self):
""" """

View file

@ -6,9 +6,6 @@ import subprocess
class ShutdownAPI(MicroscopeView): class ShutdownAPI(MicroscopeView):
""" """
Attempt to shutdown the device Attempt to shutdown the device
Allowed methods:
POST
""" """
def post(self): def post(self):
""" """
@ -25,9 +22,6 @@ class ShutdownAPI(MicroscopeView):
class RebootAPI(MicroscopeView): class RebootAPI(MicroscopeView):
""" """
Attempt to reboot the device Attempt to reboot the device
Allowed methods:
POST
""" """
def post(self): def post(self):
""" """

View file

@ -1,6 +1,11 @@
"""
Top-level representation of all acquired captures
"""
from openflexure_microscope.api.utilities import get_bool, JsonResponse from openflexure_microscope.api.utilities import get_bool, JsonResponse
from openflexure_microscope.api.views import MicroscopeView from openflexure_microscope.api.views import MicroscopeView
from openflexure_microscope.utilities import filter_dict from openflexure_microscope.utilities import filter_dict
from openflexure_microscope.api.utilities import blueprint_for_module
from flask import jsonify, request, abort, url_for, redirect, send_file, Blueprint from flask import jsonify, request, abort, url_for, redirect, send_file, Blueprint
@ -378,7 +383,8 @@ class TagsAPI(MicroscopeView):
def construct_blueprint(microscope_obj): def construct_blueprint(microscope_obj):
blueprint = Blueprint("v2_captures_blueprint", __name__)
blueprint = blueprint_for_module(__name__)
# Tag routes # Tag routes
blueprint.add_url_rule( blueprint.add_url_rule(

View file

@ -1,6 +1,11 @@
"""
Top-level representation of attached and enabled plugins
"""
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 openflexure_microscope.utilities import get_docstring from openflexure_microscope.utilities import get_docstring, description_from_view
from openflexure_microscope.api.utilities import blueprint_for_module
from flask import Blueprint, jsonify, url_for from flask import Blueprint, jsonify, url_for
from openflexure_microscope.api.views import MicroscopeView from openflexure_microscope.api.views import MicroscopeView
@ -9,7 +14,6 @@ import copy
import logging import logging
import warnings import warnings
def plugins_representation(plugin_loader_object: PluginLoader): def plugins_representation(plugin_loader_object: PluginLoader):
""" """
Generate a dictionary representation of all plugins, including Flask route URLs Generate a dictionary representation of all plugins, including Flask route URLs
@ -28,7 +32,7 @@ def plugins_representation(plugin_loader_object: PluginLoader):
"python_name": plugin._name_python_safe, "python_name": plugin._name_python_safe,
"plugin": str(plugin), "plugin": str(plugin),
"views": {}, "views": {},
"form": plugin.form, "gui": plugin.gui,
"description": get_docstring(plugin) "description": get_docstring(plugin)
} }
@ -37,10 +41,11 @@ def plugins_representation(plugin_loader_object: PluginLoader):
uri = url_for(f"v2_plugins_blueprint.{view_id}") uri = url_for(f"v2_plugins_blueprint.{view_id}")
# Make links dictionary if it doesn't yet exist # Make links dictionary if it doesn't yet exist
view_d = { view_d = {
"description": get_docstring(view_data["view"]),
"links": {"self": uri} "links": {"self": uri}
} }
view_d.update(description_from_view(view_data["view"]))
d["views"][view_id] = view_d d["views"][view_id] = view_d
plugins[plugin._name] = d plugins[plugin._name] = d
@ -67,15 +72,13 @@ class PluginFormAPI(MicroscopeView):
def construct_blueprint(microscope_obj): def construct_blueprint(microscope_obj):
blueprint = Blueprint("v2_plugins_blueprint", __name__) blueprint = blueprint_for_module(__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(
"/", view_func=PluginFormAPI.as_view("plugins", microscope=microscope_obj) "/", view_func=PluginFormAPI.as_view("plugins", microscope=microscope_obj)
) )
all_routes = []
# For each plugin attached to the microscope object # For each plugin attached to the microscope object
for plugin in microscope_obj.plugins.active: for plugin in microscope_obj.plugins.active:

View file

@ -2,29 +2,29 @@ from flask import Blueprint, jsonify, url_for
from openflexure_microscope import Microscope from openflexure_microscope import Microscope
from openflexure_microscope.api.views import MicroscopeView from openflexure_microscope.api.views import MicroscopeView
def root_representation(microscope_obj: Microscope): from openflexure_microscope.utilities import get_docstring, bottom_level_name
d = { from openflexure_microscope.api.utilities import blueprint_name_for_module
"settings": { from openflexure_microscope.api.v2.blueprints import settings, status, plugins, captures, actions, stream
"description": "Writeable settings for the microscope, and attached hardware",
"links": {"self": url_for("v2_settings_blueprint.settings")} # List of submodules containing create_blueprint methods using standard blueprint_for_module naming
}, _root_blueprint_modules = [settings, status, plugins, captures, actions, stream]
"status": {
"description": "Read-only status of the microscope, and attached hardware info", def root_representation():
"links": {"self": url_for("v2_status_blueprint.status")} """
}, Generate a dictionar representation of all top-level blueprint rules
"plugins": { """
"description": "Top-level representation of attached and enabled plugins", global _root_blueprint_modules
"links": {"self": url_for("v2_plugins_blueprint.plugins")} d = {}
},
"captures": { for blueprint_module in _root_blueprint_modules:
"description": "Top-level representation of all acquired captures", module_short_name = bottom_level_name(blueprint_module)
"links": {"self": url_for("v2_captures_blueprint.captures")} blueprint_name = blueprint_name_for_module(blueprint_module.__name__)
},
"actions": { d[module_short_name] = {
"description": "Top-level representation of enabled actions", "name": blueprint_module.__name__,
"links": {"self": url_for("v2_actions_blueprint.actions")} "description": get_docstring(blueprint_module),
}, "links": {"self": url_for(f"{blueprint_name}.{module_short_name}")}
} }
return d return d
@ -32,7 +32,7 @@ def root_representation(microscope_obj: Microscope):
class RootAPI(MicroscopeView): class RootAPI(MicroscopeView):
def get(self): def get(self):
return jsonify(root_representation(self.microscope)) return jsonify(root_representation())
def construct_blueprint(microscope_obj): def construct_blueprint(microscope_obj):

View file

@ -1,5 +1,10 @@
"""
Writeable settings for the microscope, and attached hardware
"""
from openflexure_microscope.api.utilities import gen, JsonResponse from openflexure_microscope.api.utilities import gen, JsonResponse
from openflexure_microscope.api.views import MicroscopeView from openflexure_microscope.api.views import MicroscopeView
from openflexure_microscope.api.utilities import blueprint_for_module
from flask import Blueprint, jsonify, request from flask import Blueprint, jsonify, request
import logging import logging
@ -144,7 +149,7 @@ class SettingsAPI(MicroscopeView):
def construct_blueprint(microscope_obj): def construct_blueprint(microscope_obj):
blueprint = Blueprint("v2_settings_blueprint", __name__) blueprint = blueprint_for_module(__name__)
blueprint.add_url_rule( blueprint.add_url_rule(
"/", view_func=SettingsAPI.as_view("settings", microscope=microscope_obj) "/", view_func=SettingsAPI.as_view("settings", microscope=microscope_obj)

View file

@ -1,8 +1,12 @@
"""
Read-only status of the microscope, and attached hardware info
"""
from openflexure_microscope.api.views import MicroscopeView from openflexure_microscope.api.views import MicroscopeView
from openflexure_microscope.api.utilities import blueprint_for_module
from flask import Blueprint, jsonify from flask import Blueprint, jsonify
class StatusAPI(MicroscopeView): class StatusAPI(MicroscopeView):
def get(self): def get(self):
""" """
@ -55,7 +59,7 @@ class StatusAPI(MicroscopeView):
def construct_blueprint(microscope_obj): def construct_blueprint(microscope_obj):
blueprint = Blueprint("v2_status_blueprint", __name__) blueprint = blueprint_for_module(__name__)
blueprint.add_url_rule( blueprint.add_url_rule(
"/", view_func=StatusAPI.as_view("status", microscope=microscope_obj) "/", view_func=StatusAPI.as_view("status", microscope=microscope_obj)

View file

@ -1,5 +1,6 @@
from openflexure_microscope.api.utilities import gen, JsonResponse from openflexure_microscope.api.utilities import gen, JsonResponse
from openflexure_microscope.api.views import MicroscopeView from openflexure_microscope.api.views import MicroscopeView
from openflexure_microscope.api.utilities import blueprint_for_module
from flask import Response, Blueprint, jsonify, request from flask import Response, Blueprint, jsonify, request
@ -43,7 +44,7 @@ class SnapshotAPI(MicroscopeView):
def construct_blueprint(microscope_obj): def construct_blueprint(microscope_obj):
blueprint = Blueprint("v2_stream_blueprint", __name__) blueprint = blueprint_for_module(__name__)
blueprint.add_url_rule( blueprint.add_url_rule(
"/stream", view_func=StreamAPI.as_view("stream", microscope=microscope_obj) "/stream", view_func=StreamAPI.as_view("stream", microscope=microscope_obj)

View file

@ -5,6 +5,23 @@ from collections import abc
from functools import reduce from functools import reduce
from contextlib import contextmanager from contextlib import contextmanager
def bottom_level_name(obj):
return obj.__name__.split('.')[-1]
def description_from_view(view_class):
methods = []
for method_key in ["get", "post", "put", "delete"]:
if hasattr(view_class, method_key):
methods.append(method_key.upper())
brief_description = get_docstring(view_class).partition('\n')[0].strip()
d = {
"methods": methods,
"description": brief_description
}
return d
def get_docstring(obj): def get_docstring(obj):
ds = obj.__doc__ ds = obj.__doc__
if ds: if ds: