Loading openflexure_microscope/api/app.py +5 −1 Original line number Diff line number Diff line Loading @@ -168,4 +168,8 @@ def cleanup(): atexit.register(cleanup) if __name__ == "__main__": app.run(host="0.0.0.0", port="5000", threaded=True, debug=True, use_reloader=False) # app.run(host="0.0.0.0", port="5000", threaded=True, debug=True, use_reloader=False) #from pprint import pprint #pprint(labthing.spec.to_dict()) with open('spec.yaml', 'w') as f: f.write(labthing.spec.to_yaml()) No newline at end of file openflexure_microscope/api/v2/views/actions/camera.py +2 −2 Original line number Diff line number Diff line from openflexure_microscope.api.utilities import get_bool, JsonResponse from openflexure_microscope.common.flask_labthings.resource import Resource from openflexure_microscope.common.flask_labthings.find import find_device from openflexure_microscope.common.flask_labthings.decorators import use_args, marshal_with from openflexure_microscope.common.flask_labthings.decorators import use_args, marshal_with, doc from openflexure_microscope.common.flask_labthings import fields from openflexure_microscope.utilities import filter_dict Loading @@ -10,7 +10,7 @@ from openflexure_microscope.api.v2.views.captures import capture_schema import logging from flask import jsonify, request, abort, url_for, redirect, send_file @doc(tags=["actions"]) class CaptureAPI(Resource): """ Create a new image capture. Loading openflexure_microscope/common/flask_labthings/decorators.py +23 −9 Original line number Diff line number Diff line Loading @@ -32,6 +32,10 @@ class marshal_with(object): self.schema = schema def __call__(self, f): # Pass params to call function attribute for external access f.__apispec__ = f.__dict__.get('__apispec__', {}) f.__apispec__["_schema"] = self.schema # Wrapper function @wraps(f) def wrapper(*args, **kwargs): resp = f(*args, **kwargs) Loading @@ -46,27 +50,37 @@ class marshal_with(object): class use_args(object): def __init__(self, argmap, **kwargs): def __init__(self, schema, **kwargs): """ Equivalent to webargs.flask_parser.use_args """ self.argmap = argmap self.wrapper = flaskparser.use_args(argmap, **kwargs) self.schema = schema self.wrapper = flaskparser.use_args(schema, **kwargs) def __call__(self, f): # Pass params to call function attribute for external access f.__apispec__ = f.__dict__.get('__apispec__', {}) f.__apispec__["_params"] = self.schema # Wrapper function update_wrapper(self.wrapper, f) return self.wrapper(f) class use_kwargs(object): def __init__(self, argmap, **kwargs): class use_kwargs(use_args): def __init__(self, schema, **kwargs): """ Equivalent to webargs.flask_parser.use_kwargs """ kwargs["as_kwargs"] = True self.argmap = argmap self.wrapper = flaskparser.use_args(argmap, **kwargs) use_args.__init__(self, schema, **kwargs) class doc(object): def __init__(self, **kwargs): self.kwargs = kwargs def __call__(self, f): update_wrapper(self.wrapper, f) return self.wrapper(f) # Pass params to call function attribute for external access f.__apispec__ = f.__dict__.get('__apispec__', {}) f.__apispec__.update(self.kwargs) return f No newline at end of file openflexure_microscope/common/flask_labthings/labthing.py +56 −7 Original line number Diff line number Diff line 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 .views.tasks import TaskList, TaskResource from .spec import view2path from openflexure_microscope.common.labthings_core.utilities import get_docstring from .exceptions import JSONExceptionHandler from . import EXTENSION_NAME import logging class LabThing(object): def __init__( Loading @@ -17,6 +22,7 @@ class LabThing(object): prefix: str = "", title: str = "", description: str = "", version: str = "0.0.0", handle_errors: bool = True, ): self.app = app Loading @@ -32,17 +38,53 @@ class LabThing(object): self.endpoints = set() self.url_prefix = prefix self.description = description self.title = title self._description = description self._title = title self._version = version if handle_errors: self.error_handler = JSONExceptionHandler() else: self.error_handler = None self.spec = APISpec( title=self.title, version=self.version, openapi_version="3.0.2", plugins=[MarshmallowPlugin()], ) if app is not None: self.init_app(app) @property def description(self, ): return self._description @description.setter def description(self, description: str): self._description = description self.spec.description = description @property def title(self, ): return self._title @title.setter def title(self, title: str): self._title = title self.spec.title = title @property def version(self, ): return str(self._version) @version.setter def version(self, version: str): self._version = version self.spec.version = version ### Flask stuff def init_app(self, app): Loading @@ -56,14 +98,14 @@ class LabThing(object): if self.error_handler: self.error_handler.init_app(self.app) # Create base routes self._create_base_routes() # Add resources, if registered before tying to a Flask app if len(self.resources) > 0: for resource, urls, endpoint, kwargs in self.resources: self._register_view(app, resource, *urls, endpoint=endpoint, **kwargs) # Create base routes self._create_base_routes() def teardown(self, exception): pass Loading Loading @@ -158,9 +200,12 @@ class LabThing(object): api.add_resource(FooSpecial, '/special/foo', endpoint="foo") """ endpoint = endpoint or resource.__name__.lower() logging.debug(f"{endpoint}: {type(resource)}") if self.app is not None: self._register_view(self.app, resource, *urls, endpoint=endpoint, **kwargs) else: self.resources.append((resource, urls, endpoint, kwargs)) def resource(self, *urls, **kwargs): Loading Loading @@ -208,6 +253,10 @@ class LabThing(object): rule = self._complete_url(url, "") # Add the url to the application or blueprint app.add_url_rule(rule, view_func=resource_func, **kwargs) # Add the resource to our API spec self.spec.path( **view2path(rule, resource, self.spec) ) ### Utilities Loading openflexure_microscope/common/flask_labthings/resource.py +13 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,19 @@ class Resource(MethodView): """Currently identical to MethodView """ endpoint = None methods = ["get", "post", "put", "delete"] def __init__(self, *args, **kwargs): MethodView.__init__(self, *args, **kwargs) def doc(self): docs = {"operations": {}} if hasattr(self, "__apispec__"): docs.update(self.__apispec__) for meth in Resource.methods: if hasattr(self, meth) and hasattr(getattr(self, meth), "__apispec__"): docs["operations"][meth] = {} docs["operations"][meth] = getattr(self, meth).__apispec__ return docs Loading
openflexure_microscope/api/app.py +5 −1 Original line number Diff line number Diff line Loading @@ -168,4 +168,8 @@ def cleanup(): atexit.register(cleanup) if __name__ == "__main__": app.run(host="0.0.0.0", port="5000", threaded=True, debug=True, use_reloader=False) # app.run(host="0.0.0.0", port="5000", threaded=True, debug=True, use_reloader=False) #from pprint import pprint #pprint(labthing.spec.to_dict()) with open('spec.yaml', 'w') as f: f.write(labthing.spec.to_yaml()) No newline at end of file
openflexure_microscope/api/v2/views/actions/camera.py +2 −2 Original line number Diff line number Diff line from openflexure_microscope.api.utilities import get_bool, JsonResponse from openflexure_microscope.common.flask_labthings.resource import Resource from openflexure_microscope.common.flask_labthings.find import find_device from openflexure_microscope.common.flask_labthings.decorators import use_args, marshal_with from openflexure_microscope.common.flask_labthings.decorators import use_args, marshal_with, doc from openflexure_microscope.common.flask_labthings import fields from openflexure_microscope.utilities import filter_dict Loading @@ -10,7 +10,7 @@ from openflexure_microscope.api.v2.views.captures import capture_schema import logging from flask import jsonify, request, abort, url_for, redirect, send_file @doc(tags=["actions"]) class CaptureAPI(Resource): """ Create a new image capture. Loading
openflexure_microscope/common/flask_labthings/decorators.py +23 −9 Original line number Diff line number Diff line Loading @@ -32,6 +32,10 @@ class marshal_with(object): self.schema = schema def __call__(self, f): # Pass params to call function attribute for external access f.__apispec__ = f.__dict__.get('__apispec__', {}) f.__apispec__["_schema"] = self.schema # Wrapper function @wraps(f) def wrapper(*args, **kwargs): resp = f(*args, **kwargs) Loading @@ -46,27 +50,37 @@ class marshal_with(object): class use_args(object): def __init__(self, argmap, **kwargs): def __init__(self, schema, **kwargs): """ Equivalent to webargs.flask_parser.use_args """ self.argmap = argmap self.wrapper = flaskparser.use_args(argmap, **kwargs) self.schema = schema self.wrapper = flaskparser.use_args(schema, **kwargs) def __call__(self, f): # Pass params to call function attribute for external access f.__apispec__ = f.__dict__.get('__apispec__', {}) f.__apispec__["_params"] = self.schema # Wrapper function update_wrapper(self.wrapper, f) return self.wrapper(f) class use_kwargs(object): def __init__(self, argmap, **kwargs): class use_kwargs(use_args): def __init__(self, schema, **kwargs): """ Equivalent to webargs.flask_parser.use_kwargs """ kwargs["as_kwargs"] = True self.argmap = argmap self.wrapper = flaskparser.use_args(argmap, **kwargs) use_args.__init__(self, schema, **kwargs) class doc(object): def __init__(self, **kwargs): self.kwargs = kwargs def __call__(self, f): update_wrapper(self.wrapper, f) return self.wrapper(f) # Pass params to call function attribute for external access f.__apispec__ = f.__dict__.get('__apispec__', {}) f.__apispec__.update(self.kwargs) return f No newline at end of file
openflexure_microscope/common/flask_labthings/labthing.py +56 −7 Original line number Diff line number Diff line 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 .views.tasks import TaskList, TaskResource from .spec import view2path from openflexure_microscope.common.labthings_core.utilities import get_docstring from .exceptions import JSONExceptionHandler from . import EXTENSION_NAME import logging class LabThing(object): def __init__( Loading @@ -17,6 +22,7 @@ class LabThing(object): prefix: str = "", title: str = "", description: str = "", version: str = "0.0.0", handle_errors: bool = True, ): self.app = app Loading @@ -32,17 +38,53 @@ class LabThing(object): self.endpoints = set() self.url_prefix = prefix self.description = description self.title = title self._description = description self._title = title self._version = version if handle_errors: self.error_handler = JSONExceptionHandler() else: self.error_handler = None self.spec = APISpec( title=self.title, version=self.version, openapi_version="3.0.2", plugins=[MarshmallowPlugin()], ) if app is not None: self.init_app(app) @property def description(self, ): return self._description @description.setter def description(self, description: str): self._description = description self.spec.description = description @property def title(self, ): return self._title @title.setter def title(self, title: str): self._title = title self.spec.title = title @property def version(self, ): return str(self._version) @version.setter def version(self, version: str): self._version = version self.spec.version = version ### Flask stuff def init_app(self, app): Loading @@ -56,14 +98,14 @@ class LabThing(object): if self.error_handler: self.error_handler.init_app(self.app) # Create base routes self._create_base_routes() # Add resources, if registered before tying to a Flask app if len(self.resources) > 0: for resource, urls, endpoint, kwargs in self.resources: self._register_view(app, resource, *urls, endpoint=endpoint, **kwargs) # Create base routes self._create_base_routes() def teardown(self, exception): pass Loading Loading @@ -158,9 +200,12 @@ class LabThing(object): api.add_resource(FooSpecial, '/special/foo', endpoint="foo") """ endpoint = endpoint or resource.__name__.lower() logging.debug(f"{endpoint}: {type(resource)}") if self.app is not None: self._register_view(self.app, resource, *urls, endpoint=endpoint, **kwargs) else: self.resources.append((resource, urls, endpoint, kwargs)) def resource(self, *urls, **kwargs): Loading Loading @@ -208,6 +253,10 @@ class LabThing(object): rule = self._complete_url(url, "") # Add the url to the application or blueprint app.add_url_rule(rule, view_func=resource_func, **kwargs) # Add the resource to our API spec self.spec.path( **view2path(rule, resource, self.spec) ) ### Utilities Loading
openflexure_microscope/common/flask_labthings/resource.py +13 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,19 @@ class Resource(MethodView): """Currently identical to MethodView """ endpoint = None methods = ["get", "post", "put", "delete"] def __init__(self, *args, **kwargs): MethodView.__init__(self, *args, **kwargs) def doc(self): docs = {"operations": {}} if hasattr(self, "__apispec__"): docs.update(self.__apispec__) for meth in Resource.methods: if hasattr(self, meth) and hasattr(getattr(self, meth), "__apispec__"): docs["operations"][meth] = {} docs["operations"][meth] = getattr(self, meth).__apispec__ return docs