From 851d70842c43ff3f7fc00b3c8831a0eeeb7fb32f Mon Sep 17 00:00:00 2001 From: jtc42 Date: Mon, 6 Jan 2020 17:03:05 +0000 Subject: [PATCH] Moved all API stuff to flask_labthings --- .../common/flask_labthings/decorators.py | 27 ++++++++++++- .../common/flask_labthings/fields.py | 2 +- .../common/flask_labthings/labthing.py | 5 +-- .../common/flask_labthings/resource.py | 21 ++++++++-- .../common/flask_labthings/schema.py | 40 ++++++++++++++++++- .../spec.py | 10 ++--- .../flask_labthings/views/extensions.py | 10 ++--- .../common/flask_labthings/views/tasks.py | 4 +- .../common/labthings_core/decorators.py | 26 ------------ .../common/labthings_core/fields.py | 1 - .../common/labthings_core/resource.py | 20 ---------- .../common/labthings_core/schema.py | 39 ------------------ 12 files changed, 96 insertions(+), 109 deletions(-) rename openflexure_microscope/common/{labthings_core => flask_labthings}/spec.py (93%) delete mode 100644 openflexure_microscope/common/labthings_core/decorators.py delete mode 100644 openflexure_microscope/common/labthings_core/fields.py delete mode 100644 openflexure_microscope/common/labthings_core/resource.py delete mode 100644 openflexure_microscope/common/labthings_core/schema.py diff --git a/openflexure_microscope/common/flask_labthings/decorators.py b/openflexure_microscope/common/flask_labthings/decorators.py index fa8e9ac0..12e94edb 100644 --- a/openflexure_microscope/common/flask_labthings/decorators.py +++ b/openflexure_microscope/common/flask_labthings/decorators.py @@ -3,9 +3,8 @@ from functools import wraps, update_wrapper from flask import make_response from openflexure_microscope.common.labthings_core.utilities import rupdate -from openflexure_microscope.common.labthings_core.spec import update_spec -from openflexure_microscope.common.labthings_core.decorators import doc, doc_response +from .spec import update_spec def unpack(value): @@ -76,3 +75,27 @@ class use_kwargs(use_args): """ kwargs["as_kwargs"] = True use_args.__init__(self, schema, **kwargs) + + +class doc(object): + def __init__(self, **kwargs): + self.kwargs = kwargs + + def __call__(self, f): + # Pass params to call function attribute for external access + update_spec(f, self.kwargs) + return f + + +class doc_response(object): + def __init__(self, code, description, **kwargs): + self.code = code + self.description = description + self.kwargs = kwargs + + def __call__(self, f): + # Pass params to call function attribute for external access + f.__apispec__ = f.__dict__.get("__apispec__", {}) + d = {"responses": {self.code: {"description": self.description, **self.kwargs}}} + rupdate(f.__apispec__, d) + return f diff --git a/openflexure_microscope/common/flask_labthings/fields.py b/openflexure_microscope/common/flask_labthings/fields.py index 7d413696..b8eb3d36 100644 --- a/openflexure_microscope/common/flask_labthings/fields.py +++ b/openflexure_microscope/common/flask_labthings/fields.py @@ -1 +1 @@ -from openflexure_microscope.common.labthings_core.fields import * +from marshmallow.fields import * diff --git a/openflexure_microscope/common/flask_labthings/labthing.py b/openflexure_microscope/common/flask_labthings/labthing.py index b1a64db3..b090ef2f 100644 --- a/openflexure_microscope/common/flask_labthings/labthing.py +++ b/openflexure_microscope/common/flask_labthings/labthing.py @@ -2,16 +2,15 @@ from flask import url_for, jsonify from apispec import APISpec from apispec.ext.marshmallow import MarshmallowPlugin +from . import EXTENSION_NAME from .extensions import BaseExtension from .utilities import description_from_view +from .spec import view2path from .views.extensions import ExtensionList from .views.tasks import TaskList, TaskResource from openflexure_microscope.common.labthings_core.utilities import get_docstring -from openflexure_microscope.common.labthings_core.spec import view2path - -from . import EXTENSION_NAME import logging diff --git a/openflexure_microscope/common/flask_labthings/resource.py b/openflexure_microscope/common/flask_labthings/resource.py index 6f598adb..ed3ef119 100644 --- a/openflexure_microscope/common/flask_labthings/resource.py +++ b/openflexure_microscope/common/flask_labthings/resource.py @@ -1,12 +1,27 @@ from flask.views import MethodView -from openflexure_microscope.common.labthings_core.resource import BaseResource -class Resource(MethodView, BaseResource): - """Currently identical to MethodView +class Resource(MethodView): + """ + A LabThing Resource class should make use of functions get(), put(), post(), and delete() + corresponding to HTTP methods. + + These functions will allow for automated documentation generation """ + methods = ["get", "post", "put", "delete"] endpoint = None 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 BaseResource.methods: + if hasattr(self, meth) and hasattr(getattr(self, meth), "__apispec__"): + docs["operations"][meth] = {} + docs["operations"][meth] = getattr(self, meth).__apispec__ + return docs diff --git a/openflexure_microscope/common/flask_labthings/schema.py b/openflexure_microscope/common/flask_labthings/schema.py index b9ae889a..83294a0e 100644 --- a/openflexure_microscope/common/flask_labthings/schema.py +++ b/openflexure_microscope/common/flask_labthings/schema.py @@ -1 +1,39 @@ -from openflexure_microscope.common.labthings_core.schema import * +# -*- coding: utf-8 -*- +import flask +import marshmallow + +MARSHMALLOW_VERSION_INFO = tuple( + [int(part) for part in marshmallow.__version__.split(".") if part.isdigit()] +) + +sentinel = object() + + +class Schema(marshmallow.Schema): + """Base serializer with which to define custom serializers. + See `marshmallow.Schema` for more details about the `Schema` API. + """ + + def jsonify(self, obj, many=sentinel, *args, **kwargs): + """Return a JSON response containing the serialized data. + :param obj: Object to serialize. + :param bool many: Whether `obj` should be serialized as an instance + or as a collection. If unset, defaults to the value of the + `many` attribute on this Schema. + :param kwargs: Additional keyword arguments passed to `flask.jsonify`. + .. versionchanged:: 0.6.0 + Takes the same arguments as `marshmallow.Schema.dump`. Additional + keyword arguments are passed to `flask.jsonify`. + .. versionchanged:: 0.6.3 + The `many` argument for this method defaults to the value of + the `many` attribute on the Schema. Previously, the `many` + argument of this method defaulted to False, regardless of the + value of `Schema.many`. + """ + if many is sentinel: + many = self.many + if MARSHMALLOW_VERSION_INFO[0] >= 3: + data = self.dump(obj, many=many) + else: + data = self.dump(obj, many=many).data + return flask.jsonify(data, *args, **kwargs) diff --git a/openflexure_microscope/common/labthings_core/spec.py b/openflexure_microscope/common/flask_labthings/spec.py similarity index 93% rename from openflexure_microscope/common/labthings_core/spec.py rename to openflexure_microscope/common/flask_labthings/spec.py index 99ba0015..fa8c3190 100644 --- a/openflexure_microscope/common/labthings_core/spec.py +++ b/openflexure_microscope/common/flask_labthings/spec.py @@ -1,11 +1,11 @@ -from .resource import BaseResource -from .utilities import rupdate +from .resource import Resource from apispec import APISpec from apispec.ext.marshmallow import MarshmallowPlugin from openflexure_microscope.common.labthings_core.utilities import ( get_docstring, get_summary, + rupdate, ) from .fields import Field @@ -20,7 +20,7 @@ def update_spec(obj, spec): return obj.__apispec__ -def view2path(rule: str, view: BaseResource, spec: APISpec): +def view2path(rule: str, view: Resource, spec: APISpec): params = { "path": rule, # TODO: Validate this slightly (leading / etc) "operations": view2operations(view, spec), @@ -35,9 +35,9 @@ def view2path(rule: str, view: BaseResource, spec: APISpec): return params -def view2operations(view: BaseResource, spec: APISpec, populate_default: bool = True): +def view2operations(view: Resource, spec: APISpec, populate_default: bool = True): ops = {} - for method in BaseResource.methods: + for method in Resource.methods: if hasattr(view, method): # Populate with default responses if populate_default: diff --git a/openflexure_microscope/common/flask_labthings/views/extensions.py b/openflexure_microscope/common/flask_labthings/views/extensions.py index 65bb3e56..947fa6cb 100644 --- a/openflexure_microscope/common/flask_labthings/views/extensions.py +++ b/openflexure_microscope/common/flask_labthings/views/extensions.py @@ -2,9 +2,9 @@ Top-level representation of attached and enabled Extensions """ -from openflexure_microscope.common.labthings_core.utilities import get_docstring -from openflexure_microscope.common.labthings_core.schema import Schema -from openflexure_microscope.common.labthings_core import fields +from openflexure_microscope.common.flask_labthings.utilities import get_docstring +from openflexure_microscope.common.flask_labthings.schema import Schema +from openflexure_microscope.common.flask_labthings import fields from ..utilities import description_from_view @@ -38,9 +38,7 @@ class ExtensionSchema(Schema): view_rule = view_data["rule"] # Make links dictionary if it doesn't yet exist d[view_id] = { - "href": url_for( - ExtensionList.endpoint, **view_kwargs, _external=True - ) + "href": url_for(ExtensionList.endpoint, **view_kwargs, _external=True) + view_rule, **description_from_view(view_cls), } diff --git a/openflexure_microscope/common/flask_labthings/views/tasks.py b/openflexure_microscope/common/flask_labthings/views/tasks.py index 310a6d2a..dad04b3e 100644 --- a/openflexure_microscope/common/flask_labthings/views/tasks.py +++ b/openflexure_microscope/common/flask_labthings/views/tasks.py @@ -2,13 +2,13 @@ from flask import abort, url_for from openflexure_microscope.common.flask_labthings.decorators import marshal_with from openflexure_microscope.common.flask_labthings.resource import Resource +from openflexure_microscope.common.flask_labthings.schema import Schema +from openflexure_microscope.common.flask_labthings import fields from openflexure_microscope.common.flask_labthings.utilities import ( description_from_view, ) from openflexure_microscope.common.labthings_core import tasks -from openflexure_microscope.common.labthings_core.schema import Schema -from openflexure_microscope.common.labthings_core import fields from marshmallow import pre_dump diff --git a/openflexure_microscope/common/labthings_core/decorators.py b/openflexure_microscope/common/labthings_core/decorators.py deleted file mode 100644 index 0fa8775e..00000000 --- a/openflexure_microscope/common/labthings_core/decorators.py +++ /dev/null @@ -1,26 +0,0 @@ -from .spec import update_spec -from .utilities import rupdate - - -class doc(object): - def __init__(self, **kwargs): - self.kwargs = kwargs - - def __call__(self, f): - # Pass params to call function attribute for external access - update_spec(f, self.kwargs) - return f - - -class doc_response(object): - def __init__(self, code, description, **kwargs): - self.code = code - self.description = description - self.kwargs = kwargs - - def __call__(self, f): - # Pass params to call function attribute for external access - f.__apispec__ = f.__dict__.get("__apispec__", {}) - d = {"responses": {self.code: {"description": self.description, **self.kwargs}}} - rupdate(f.__apispec__, d) - return f diff --git a/openflexure_microscope/common/labthings_core/fields.py b/openflexure_microscope/common/labthings_core/fields.py deleted file mode 100644 index b8eb3d36..00000000 --- a/openflexure_microscope/common/labthings_core/fields.py +++ /dev/null @@ -1 +0,0 @@ -from marshmallow.fields import * diff --git a/openflexure_microscope/common/labthings_core/resource.py b/openflexure_microscope/common/labthings_core/resource.py deleted file mode 100644 index 57882a94..00000000 --- a/openflexure_microscope/common/labthings_core/resource.py +++ /dev/null @@ -1,20 +0,0 @@ -class BaseResource: - """ - A LabThing Resource class should, regardless of the underlying framework, make use of - functions get(), put(), post(), and delete() corresponding to HTTP methods. - - These functions will allow for automated documentation generation - """ - - methods = ["get", "post", "put", "delete"] - - def doc(self): - docs = {"operations": {}} - if hasattr(self, "__apispec__"): - docs.update(self.__apispec__) - - for meth in BaseResource.methods: - if hasattr(self, meth) and hasattr(getattr(self, meth), "__apispec__"): - docs["operations"][meth] = {} - docs["operations"][meth] = getattr(self, meth).__apispec__ - return docs diff --git a/openflexure_microscope/common/labthings_core/schema.py b/openflexure_microscope/common/labthings_core/schema.py deleted file mode 100644 index 83294a0e..00000000 --- a/openflexure_microscope/common/labthings_core/schema.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -import flask -import marshmallow - -MARSHMALLOW_VERSION_INFO = tuple( - [int(part) for part in marshmallow.__version__.split(".") if part.isdigit()] -) - -sentinel = object() - - -class Schema(marshmallow.Schema): - """Base serializer with which to define custom serializers. - See `marshmallow.Schema` for more details about the `Schema` API. - """ - - def jsonify(self, obj, many=sentinel, *args, **kwargs): - """Return a JSON response containing the serialized data. - :param obj: Object to serialize. - :param bool many: Whether `obj` should be serialized as an instance - or as a collection. If unset, defaults to the value of the - `many` attribute on this Schema. - :param kwargs: Additional keyword arguments passed to `flask.jsonify`. - .. versionchanged:: 0.6.0 - Takes the same arguments as `marshmallow.Schema.dump`. Additional - keyword arguments are passed to `flask.jsonify`. - .. versionchanged:: 0.6.3 - The `many` argument for this method defaults to the value of - the `many` attribute on the Schema. Previously, the `many` - argument of this method defaulted to False, regardless of the - value of `Schema.many`. - """ - if many is sentinel: - many = self.many - if MARSHMALLOW_VERSION_INFO[0] >= 3: - data = self.dump(obj, many=many) - else: - data = self.dump(obj, many=many).data - return flask.jsonify(data, *args, **kwargs)