Moved all API stuff to flask_labthings

This commit is contained in:
jtc42 2020-01-06 17:03:05 +00:00
parent 6bf178750b
commit 851d70842c
12 changed files with 96 additions and 109 deletions

View file

@ -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

View file

@ -1 +1 @@
from openflexure_microscope.common.labthings_core.fields import *
from marshmallow.fields import *

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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:

View file

@ -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),
}

View file

@ -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

View file

@ -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

View file

@ -1 +0,0 @@
from marshmallow.fields import *

View file

@ -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

View file

@ -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)