Renamed LabThing plugins to extensions

This commit is contained in:
jtc42 2020-01-05 18:56:46 +00:00
parent d96e188d16
commit 2a245185a6
10 changed files with 89 additions and 89 deletions

View file

@ -11,16 +11,16 @@ from datetime import datetime
from flask_cors import CORS from flask_cors import CORS
from openflexure_microscope.api.utilities import list_routes, init_default_plugins from openflexure_microscope.api.utilities import list_routes, init_default_extensions
from openflexure_microscope.config import ( from openflexure_microscope.config import (
settings_file_path, settings_file_path,
JSONEncoder, JSONEncoder,
USER_PLUGINS_PATH, USER_EXTENSIONS_PATH,
) )
from openflexure_microscope.common.flask_labthings.labthing import LabThing from openflexure_microscope.common.flask_labthings.labthing import LabThing
from openflexure_microscope.common.flask_labthings.plugins import find_plugins from openflexure_microscope.common.flask_labthings.extensions import find_extensions
from openflexure_microscope.api.microscope import default_microscope as api_microscope from openflexure_microscope.api.microscope import default_microscope as api_microscope
@ -73,11 +73,11 @@ labthing.title = f"OpenFlexure Microscope {api_microscope.name}"
# Attach lab devices # Attach lab devices
labthing.register_device(api_microscope, "openflexure_microscope") labthing.register_device(api_microscope, "openflexure_microscope")
# Attach plugins # Attach extensions
if not os.path.isfile(USER_PLUGINS_PATH): if not os.path.isfile(USER_EXTENSIONS_PATH):
init_default_plugins(USER_PLUGINS_PATH) init_default_extensions(USER_EXTENSIONS_PATH)
for plugin in find_plugins(USER_PLUGINS_PATH): for extension in find_extensions(USER_EXTENSIONS_PATH):
labthing.register_plugin(plugin) labthing.register_extension(extension)
# Attach captures resources # Attach captures resources
labthing.add_resource(views.CaptureList, f"/captures") labthing.add_resource(views.CaptureList, f"/captures")

View file

@ -1,5 +1,5 @@
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.plugins import BasePlugin 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.devel import JsonResponse, request, jsonify, taskify, abort from openflexure_microscope.devel import JsonResponse, request, jsonify, taskify, abort
@ -139,7 +139,7 @@ def sharpness_edge(image):
) )
### Autofocus plugin ### Autofocus extension
def measure_sharpness(microscope, metric_fn=sharpness_sum_lap2): def measure_sharpness(microscope, metric_fn=sharpness_sum_lap2):
@ -353,15 +353,15 @@ class FastAutofocusAPI(Resource):
abort(503, "No stage connected. Unable to autofocus.") abort(503, "No stage connected. Unable to autofocus.")
autofocus_plugin_v2 = BasePlugin("autofocus") autofocus_extension_v2 = BaseExtension("autofocus")
autofocus_plugin_v2.add_method(fast_autofocus, "fast_autofocus") autofocus_extension_v2.add_method(fast_autofocus, "fast_autofocus")
autofocus_plugin_v2.add_method(autofocus, "autofocus") autofocus_extension_v2.add_method(autofocus, "autofocus")
autofocus_plugin_v2.add_view(MeasureSharpnessAPI, "/measure_sharpness") autofocus_extension_v2.add_view(MeasureSharpnessAPI, "/measure_sharpness")
autofocus_plugin_v2.add_view(AutofocusAPI, "/autofocus") autofocus_extension_v2.add_view(AutofocusAPI, "/autofocus")
autofocus_plugin_v2.register_action(AutofocusAPI) autofocus_extension_v2.register_action(AutofocusAPI)
autofocus_plugin_v2.add_view(FastAutofocusAPI, "/fast_autofocus") autofocus_extension_v2.add_view(FastAutofocusAPI, "/fast_autofocus")
autofocus_plugin_v2.register_action(FastAutofocusAPI) autofocus_extension_v2.register_action(FastAutofocusAPI)

View file

@ -6,8 +6,8 @@ from typing import Tuple
from functools import reduce from functools import reduce
from openflexure_microscope.camera.base import generate_basename from openflexure_microscope.camera.base import generate_basename
from openflexure_microscope.common.flask_labthings.find import find_device, find_plugin from openflexure_microscope.common.flask_labthings.find import find_device, find_extension
from openflexure_microscope.common.flask_labthings.plugins import BasePlugin from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
from openflexure_microscope.devel import ( from openflexure_microscope.devel import (
JsonResponse, JsonResponse,
@ -169,10 +169,10 @@ def tile(
) )
# Check if autofocus is enabled # Check if autofocus is enabled
autofocus_plugin = find_plugin("autofocus") autofocus_extension = find_extension("autofocus")
if ( if (
autofocus_dz autofocus_dz
and autofocus_plugin and autofocus_extension
and microscope.has_real_stage() and microscope.has_real_stage()
and microscope.has_real_camera() and microscope.has_real_camera()
): ):
@ -211,7 +211,7 @@ def tile(
# Refocus # Refocus
if autofocus_enabled: if autofocus_enabled:
if fast_autofocus: if fast_autofocus:
autofocus_plugin.fast_autofocus( autofocus_extension.fast_autofocus(
dz=autofocus_dz, dz=autofocus_dz,
target_z=-z_stack_dz / 2.0, # Finish below the focus target_z=-z_stack_dz / 2.0, # Finish below the focus
initial_move_up=False, # We're already at the top of the scan initial_move_up=False, # We're already at the top of the scan
@ -219,7 +219,7 @@ def tile(
# TODO: save the focus data for future reference? Use it for diagnostics? # TODO: save the focus data for future reference? Use it for diagnostics?
else: else:
logging.debug("Running autofocus") logging.debug("Running autofocus")
autofocus_plugin.autofocus( autofocus_extension.autofocus(
range(-3 * autofocus_dz, 4 * autofocus_dz, autofocus_dz) range(-3 * autofocus_dz, 4 * autofocus_dz, autofocus_dz)
) )
logging.debug("Finished autofocus") logging.debug("Finished autofocus")
@ -398,7 +398,7 @@ class TileScanAPI(Resource):
return jsonify(task.state), 201 return jsonify(task.state), 201
scan_plugin_v2 = BasePlugin("scan") scan_extension_v2 = BaseExtension("scan")
scan_plugin_v2.add_view(TileScanAPI, "/tile") scan_extension_v2.add_view(TileScanAPI, "/tile")
scan_plugin_v2.register_action(TileScanAPI) scan_extension_v2.register_action(TileScanAPI)

View file

@ -108,22 +108,22 @@ def create_file(config_path):
raise raise
def init_default_plugins(plugin_path): def init_default_extensions(extension_path):
global _DEFAULT_PLUGIN_INIT global _DEFAULT_extension_INIT
os.makedirs(os.path.dirname(plugin_path), exist_ok=True) os.makedirs(os.path.dirname(extension_path), exist_ok=True)
if not os.path.exists(plugin_path): # If user plugins file doesn't exist if not os.path.exists(extension_path): # If user extensions file doesn't exist
logging.warning("No plugin file found at {}. Creating...".format(plugin_path)) logging.warning("No extension file found at {}. Creating...".format(extension_path))
create_file(plugin_path) create_file(extension_path)
logging.info("Populating {}...".format(plugin_path)) logging.info("Populating {}...".format(extension_path))
with open(plugin_path, "w") as outfile: with open(extension_path, "w") as outfile:
outfile.write(_DEFAULT_PLUGIN_INIT) outfile.write(_DEFAULT_extension_INIT)
_DEFAULT_PLUGIN_INIT = """ _DEFAULT_extension_INIT = """
from openflexure_microscope.api.default_plugins.autofocus import autofocus_plugin_v2 from openflexure_microscope.api.default_extensions.autofocus import autofocus_extension_v2
from openflexure_microscope.api.default_plugins.scan import scan_plugin_v2 from openflexure_microscope.api.default_extensions.scan import scan_extension_v2
__plugins__ = [autofocus_plugin_v2, scan_plugin_v2] __extensions__ = [autofocus_extension_v2, scan_extension_v2]
""" """

View file

@ -9,9 +9,9 @@ from openflexure_microscope.common.labthings_core.utilities import get_docstring
from openflexure_microscope.utilities import camel_to_snake, snake_to_spine from openflexure_microscope.utilities import camel_to_snake, snake_to_spine
class BasePlugin: class BaseExtension:
""" """
Parent class for all plugins. Parent class for all extensions.
Handles binding route views and forms. Handles binding route views and forms.
""" """
@ -23,7 +23,7 @@ class BasePlugin:
self._rules = {} # Key: Original rule. Val: View class self._rules = {} # Key: Original rule. Val: View class
self._gui = None self._gui = None
self._cls = str(self) # String description of plugin instance self._cls = str(self) # String description of extension instance
self.actions = [] self.actions = []
self.properties = [] self.properties = []
@ -43,7 +43,7 @@ class BasePlugin:
while cleaned_rule[0] == "/": while cleaned_rule[0] == "/":
cleaned_rule = cleaned_rule[1:] cleaned_rule = cleaned_rule[1:]
# Expand the rule to include plugin name # Expand the rule to include extension name
full_rule = "/{}/{}".format(self._name_uri_safe, cleaned_rule) full_rule = "/{}/{}".format(self._name_uri_safe, cleaned_rule)
view_id = cleaned_rule.replace("/", "_").replace("<", "").replace(">", "") view_id = cleaned_rule.replace("/", "_").replace("<", "").replace(">", "")
@ -119,20 +119,20 @@ class BasePlugin:
setattr(self, method_name, method) setattr(self, method_name, method)
else: else:
logging.warning( logging.warning(
"Unable to bind method to plugin. Method name already exists." "Unable to bind method to extension. Method name already exists."
) )
def find_plugins(plugin_path, module_name="plugins"): def find_extensions(extension_path, module_name="extensions"):
logging.debug(f"Loading plugins from {plugin_path}") logging.debug(f"Loading extensions from {extension_path}")
spec = util.spec_from_file_location(module_name, plugin_path) spec = util.spec_from_file_location(module_name, extension_path)
mod = util.module_from_spec(spec) mod = util.module_from_spec(spec)
sys.modules[spec.name] = mod sys.modules[spec.name] = mod
spec.loader.exec_module(mod) spec.loader.exec_module(mod)
if hasattr(mod, "__plugins__"): if hasattr(mod, "__extensions__"):
return mod.__plugins__ return mod.__extensions__
else: else:
return None return None

View file

@ -15,10 +15,10 @@ def current_labthing():
return app.extensions[EXTENSION_NAME] return app.extensions[EXTENSION_NAME]
def registered_plugins(labthing_instance=None): def registered_extensions(labthing_instance=None):
if not labthing_instance: if not labthing_instance:
labthing_instance = current_labthing() labthing_instance = current_labthing()
return labthing_instance.plugins return labthing_instance.extensions
def registered_devices(labthing_instance=None): def registered_devices(labthing_instance=None):
@ -37,14 +37,14 @@ def find_device(device_name, labthing_instance=None):
return None return None
def find_plugin(plugin_name, labthing_instance=None): def find_extension(extension_name, labthing_instance=None):
if not labthing_instance: if not labthing_instance:
labthing_instance = current_labthing() labthing_instance = current_labthing()
logging.debug("Current labthing:") logging.debug("Current labthing:")
logging.debug(current_labthing()) logging.debug(current_labthing())
if plugin_name in labthing_instance.plugins: if extension_name in labthing_instance.extensions:
return labthing_instance.plugins[plugin_name] return labthing_instance.extensions[extension_name]
else: else:
return None return None

View file

@ -2,8 +2,8 @@ from flask import url_for, jsonify
from apispec import APISpec from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin from apispec.ext.marshmallow import MarshmallowPlugin
from .plugins import BasePlugin from .extensions import BaseExtension
from .views.plugins import PluginListResource from .views.extensions import ExtensionListResource
from .views.tasks import TaskList, TaskResource from .views.tasks import TaskList, TaskResource
from .spec import view2path from .spec import view2path
@ -32,7 +32,7 @@ class LabThing(object):
self.devices = {} self.devices = {}
self.plugins = {} self.extensions = {}
self.resources = [] self.resources = []
self.properties = {} self.properties = {}
@ -121,9 +121,9 @@ class LabThing(object):
self._complete_url("/swagger", ""), "swagger", self.swagger self._complete_url("/swagger", ""), "swagger", self.swagger
) )
# Add plugin overview # Add extension overview
self.add_resource(PluginListResource, "/plugins") self.add_resource(ExtensionListResource, "/extensions")
self.register_property(PluginListResource) self.register_property(ExtensionListResource)
# Add task routes # Add task routes
self.add_resource(TaskList, "/tasks") self.add_resource(TaskList, "/tasks")
self.register_property(TaskList) self.register_property(TaskList)
@ -134,26 +134,26 @@ class LabThing(object):
def register_device(self, device_object, device_name: str): def register_device(self, device_object, device_name: str):
self.devices[device_name] = device_object self.devices[device_name] = device_object
### Plugin stuff ### Extension stuff
def register_plugin(self, plugin_object): def register_extension(self, extension_object):
if isinstance(plugin_object, BasePlugin): if isinstance(extension_object, BaseExtension):
self.plugins[plugin_object.name] = plugin_object self.extensions[extension_object.name] = extension_object
else: else:
raise TypeError("Plugin object must be an instance of BasePlugin") raise TypeError("Extension object must be an instance of BaseExtension")
for plugin_view_id, plugin_view in plugin_object.views.items(): for extension_view_id, extension_view in extension_object.views.items():
# Add route to the plugins blueprint # Add route to the extensions blueprint
self.add_resource( self.add_resource(
plugin_view["view"], extension_view["view"],
"/plugins" + plugin_view["rule"], "/extensions" + extension_view["rule"],
**plugin_view["kwargs"], **extension_view["kwargs"],
) )
for prop in plugin_object.properties: for prop in extension_object.properties:
self.register_property(prop) self.register_property(prop)
for action in plugin_object.actions: for action in extension_object.actions:
self.register_action(action) self.register_action(action)
### Resource stuff ### Resource stuff
@ -327,9 +327,9 @@ class LabThing(object):
"description": get_docstring(self.swagger), "description": get_docstring(self.swagger),
"methods": ["GET"], "methods": ["GET"],
}, },
"plugins": { "extensions": {
"href": self.url_for(PluginListResource, _external=True), "href": self.url_for(ExtensionListResource, _external=True),
**description_from_view(PluginListResource), **description_from_view(ExtensionListResource),
}, },
"tasks": { "tasks": {
"href": self.url_for(TaskList, _external=True), "href": self.url_for(TaskList, _external=True),

View file

@ -1,12 +1,12 @@
""" """
Top-level representation of attached and enabled plugins Top-level representation of attached and enabled Extensions
""" """
from openflexure_microscope.common.labthings_core.utilities import get_docstring from openflexure_microscope.common.labthings_core.utilities import get_docstring
from ..utilities import description_from_view from ..utilities import description_from_view
from openflexure_microscope.common.flask_labthings.resource import Resource from openflexure_microscope.common.flask_labthings.resource import Resource
from openflexure_microscope.common.flask_labthings.find import registered_plugins from openflexure_microscope.common.flask_labthings.find import registered_extensions
from openflexure_microscope.common.flask_labthings.schema import Schema from openflexure_microscope.common.flask_labthings.schema import Schema
from openflexure_microscope.common.flask_labthings.decorators import marshal_with from openflexure_microscope.common.flask_labthings.decorators import marshal_with
from openflexure_microscope.common.flask_labthings import fields from openflexure_microscope.common.flask_labthings import fields
@ -17,7 +17,7 @@ from flask import jsonify, url_for
import logging import logging
class PluginSchema(Schema): class ExtensionSchema(Schema):
name = fields.String(data_key="title") name = fields.String(data_key="title")
_name_python_safe = fields.String(data_key="pythonName") _name_python_safe = fields.String(data_key="pythonName")
_cls = fields.String(data_key="pythonObject") _cls = fields.String(data_key="pythonObject")
@ -44,23 +44,23 @@ class PluginSchema(Schema):
return data return data
class PluginListResource(Resource): class ExtensionListResource(Resource):
""" """
List and basic documentation for all enabled plugins List and basic documentation for all enabled Extensions
""" """
@marshal_with(PluginSchema(many=True)) @marshal_with(ExtensionSchema(many=True))
def get(self): def get(self):
""" """
Return the current plugin forms Return the current Extension forms
.. :quickref: Plugin; Get forms .. :quickref: Extension; Get forms
Returns an array of present plugin forms (describing plugin user interfaces.) Returns an array of present Extension forms (describing Extension user interfaces.)
Please note, this is *not* a list of all enabled plugins, only those with associated Please note, this is *not* a list of all enabled Extensions, only those with associated
user interface forms. user interface forms.
A complete list of enabled plugins can be found in the microscope state. A complete list of enabled Extensions can be found in the microscope state.
""" """
return registered_plugins().values() return registered_extensions().values()

View file

@ -182,7 +182,7 @@ DEFAULT_CONFIG_FILE_PATH = os.path.join(HERE, "microscope_settings.default.json"
USER_CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".openflexure") USER_CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".openflexure")
USER_CONFIG_FILE_PATH = os.path.join(USER_CONFIG_DIR, "microscope_settings.json") USER_CONFIG_FILE_PATH = os.path.join(USER_CONFIG_DIR, "microscope_settings.json")
USER_PLUGINS_PATH = os.path.join(USER_CONFIG_DIR, "microscope_plugins", "__init__.py") USER_EXTENSIONS_PATH = os.path.join(USER_CONFIG_DIR, "microscope_extensions", "__init__.py")
# Load the default config # Load the default config
with open(DEFAULT_CONFIG_FILE_PATH, "r") as default_rc: with open(DEFAULT_CONFIG_FILE_PATH, "r") as default_rc: