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 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 (
settings_file_path,
JSONEncoder,
USER_PLUGINS_PATH,
USER_EXTENSIONS_PATH,
)
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
@ -73,11 +73,11 @@ labthing.title = f"OpenFlexure Microscope {api_microscope.name}"
# Attach lab devices
labthing.register_device(api_microscope, "openflexure_microscope")
# Attach plugins
if not os.path.isfile(USER_PLUGINS_PATH):
init_default_plugins(USER_PLUGINS_PATH)
for plugin in find_plugins(USER_PLUGINS_PATH):
labthing.register_plugin(plugin)
# Attach extensions
if not os.path.isfile(USER_EXTENSIONS_PATH):
init_default_extensions(USER_EXTENSIONS_PATH)
for extension in find_extensions(USER_EXTENSIONS_PATH):
labthing.register_extension(extension)
# Attach captures resources
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.plugins import BasePlugin
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
from openflexure_microscope.common.flask_labthings.resource import Resource
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):
@ -353,15 +353,15 @@ class FastAutofocusAPI(Resource):
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_plugin_v2.add_method(autofocus, "autofocus")
autofocus_extension_v2.add_method(fast_autofocus, "fast_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_plugin_v2.register_action(AutofocusAPI)
autofocus_extension_v2.add_view(AutofocusAPI, "/autofocus")
autofocus_extension_v2.register_action(AutofocusAPI)
autofocus_plugin_v2.add_view(FastAutofocusAPI, "/fast_autofocus")
autofocus_plugin_v2.register_action(FastAutofocusAPI)
autofocus_extension_v2.add_view(FastAutofocusAPI, "/fast_autofocus")
autofocus_extension_v2.register_action(FastAutofocusAPI)

View file

@ -6,8 +6,8 @@ from typing import Tuple
from functools import reduce
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.plugins import BasePlugin
from openflexure_microscope.common.flask_labthings.find import find_device, find_extension
from openflexure_microscope.common.flask_labthings.extensions import BaseExtension
from openflexure_microscope.devel import (
JsonResponse,
@ -169,10 +169,10 @@ def tile(
)
# Check if autofocus is enabled
autofocus_plugin = find_plugin("autofocus")
autofocus_extension = find_extension("autofocus")
if (
autofocus_dz
and autofocus_plugin
and autofocus_extension
and microscope.has_real_stage()
and microscope.has_real_camera()
):
@ -211,7 +211,7 @@ def tile(
# Refocus
if autofocus_enabled:
if fast_autofocus:
autofocus_plugin.fast_autofocus(
autofocus_extension.fast_autofocus(
dz=autofocus_dz,
target_z=-z_stack_dz / 2.0, # Finish below the focus
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?
else:
logging.debug("Running autofocus")
autofocus_plugin.autofocus(
autofocus_extension.autofocus(
range(-3 * autofocus_dz, 4 * autofocus_dz, autofocus_dz)
)
logging.debug("Finished autofocus")
@ -398,7 +398,7 @@ class TileScanAPI(Resource):
return jsonify(task.state), 201
scan_plugin_v2 = BasePlugin("scan")
scan_extension_v2 = BaseExtension("scan")
scan_plugin_v2.add_view(TileScanAPI, "/tile")
scan_plugin_v2.register_action(TileScanAPI)
scan_extension_v2.add_view(TileScanAPI, "/tile")
scan_extension_v2.register_action(TileScanAPI)

View file

@ -108,22 +108,22 @@ def create_file(config_path):
raise
def init_default_plugins(plugin_path):
global _DEFAULT_PLUGIN_INIT
os.makedirs(os.path.dirname(plugin_path), exist_ok=True)
def init_default_extensions(extension_path):
global _DEFAULT_extension_INIT
os.makedirs(os.path.dirname(extension_path), exist_ok=True)
if not os.path.exists(plugin_path): # If user plugins file doesn't exist
logging.warning("No plugin file found at {}. Creating...".format(plugin_path))
create_file(plugin_path)
if not os.path.exists(extension_path): # If user extensions file doesn't exist
logging.warning("No extension file found at {}. Creating...".format(extension_path))
create_file(extension_path)
logging.info("Populating {}...".format(plugin_path))
with open(plugin_path, "w") as outfile:
outfile.write(_DEFAULT_PLUGIN_INIT)
logging.info("Populating {}...".format(extension_path))
with open(extension_path, "w") as outfile:
outfile.write(_DEFAULT_extension_INIT)
_DEFAULT_PLUGIN_INIT = """
from openflexure_microscope.api.default_plugins.autofocus import autofocus_plugin_v2
from openflexure_microscope.api.default_plugins.scan import scan_plugin_v2
_DEFAULT_extension_INIT = """
from openflexure_microscope.api.default_extensions.autofocus import autofocus_extension_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
class BasePlugin:
class BaseExtension:
"""
Parent class for all plugins.
Parent class for all extensions.
Handles binding route views and forms.
"""
@ -23,7 +23,7 @@ class BasePlugin:
self._rules = {} # Key: Original rule. Val: View class
self._gui = None
self._cls = str(self) # String description of plugin instance
self._cls = str(self) # String description of extension instance
self.actions = []
self.properties = []
@ -43,7 +43,7 @@ class BasePlugin:
while cleaned_rule[0] == "/":
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)
view_id = cleaned_rule.replace("/", "_").replace("<", "").replace(">", "")
@ -119,20 +119,20 @@ class BasePlugin:
setattr(self, method_name, method)
else:
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"):
logging.debug(f"Loading plugins from {plugin_path}")
def find_extensions(extension_path, module_name="extensions"):
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)
sys.modules[spec.name] = mod
spec.loader.exec_module(mod)
if hasattr(mod, "__plugins__"):
return mod.__plugins__
if hasattr(mod, "__extensions__"):
return mod.__extensions__
else:
return None

View file

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

View file

@ -2,8 +2,8 @@ from flask import url_for, jsonify
from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin
from .plugins import BasePlugin
from .views.plugins import PluginListResource
from .extensions import BaseExtension
from .views.extensions import ExtensionListResource
from .views.tasks import TaskList, TaskResource
from .spec import view2path
@ -32,7 +32,7 @@ class LabThing(object):
self.devices = {}
self.plugins = {}
self.extensions = {}
self.resources = []
self.properties = {}
@ -121,9 +121,9 @@ class LabThing(object):
self._complete_url("/swagger", ""), "swagger", self.swagger
)
# Add plugin overview
self.add_resource(PluginListResource, "/plugins")
self.register_property(PluginListResource)
# Add extension overview
self.add_resource(ExtensionListResource, "/extensions")
self.register_property(ExtensionListResource)
# Add task routes
self.add_resource(TaskList, "/tasks")
self.register_property(TaskList)
@ -134,26 +134,26 @@ class LabThing(object):
def register_device(self, device_object, device_name: str):
self.devices[device_name] = device_object
### Plugin stuff
### Extension stuff
def register_plugin(self, plugin_object):
if isinstance(plugin_object, BasePlugin):
self.plugins[plugin_object.name] = plugin_object
def register_extension(self, extension_object):
if isinstance(extension_object, BaseExtension):
self.extensions[extension_object.name] = extension_object
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():
# Add route to the plugins blueprint
for extension_view_id, extension_view in extension_object.views.items():
# Add route to the extensions blueprint
self.add_resource(
plugin_view["view"],
"/plugins" + plugin_view["rule"],
**plugin_view["kwargs"],
extension_view["view"],
"/extensions" + extension_view["rule"],
**extension_view["kwargs"],
)
for prop in plugin_object.properties:
for prop in extension_object.properties:
self.register_property(prop)
for action in plugin_object.actions:
for action in extension_object.actions:
self.register_action(action)
### Resource stuff
@ -327,9 +327,9 @@ class LabThing(object):
"description": get_docstring(self.swagger),
"methods": ["GET"],
},
"plugins": {
"href": self.url_for(PluginListResource, _external=True),
**description_from_view(PluginListResource),
"extensions": {
"href": self.url_for(ExtensionListResource, _external=True),
**description_from_view(ExtensionListResource),
},
"tasks": {
"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 ..utilities import description_from_view
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.decorators import marshal_with
from openflexure_microscope.common.flask_labthings import fields
@ -17,7 +17,7 @@ from flask import jsonify, url_for
import logging
class PluginSchema(Schema):
class ExtensionSchema(Schema):
name = fields.String(data_key="title")
_name_python_safe = fields.String(data_key="pythonName")
_cls = fields.String(data_key="pythonObject")
@ -44,23 +44,23 @@ class PluginSchema(Schema):
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):
"""
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.)
Please note, this is *not* a list of all enabled plugins, only those with associated
Returns an array of present Extension forms (describing Extension user interfaces.)
Please note, this is *not* a list of all enabled Extensions, only those with associated
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_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
with open(DEFAULT_CONFIG_FILE_PATH, "r") as default_rc: