Moved all API stuff to flask_labthings
This commit is contained in:
parent
6bf178750b
commit
851d70842c
12 changed files with 96 additions and 109 deletions
|
|
@ -3,9 +3,8 @@ from functools import wraps, update_wrapper
|
||||||
from flask import make_response
|
from flask import make_response
|
||||||
|
|
||||||
from openflexure_microscope.common.labthings_core.utilities import rupdate
|
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):
|
def unpack(value):
|
||||||
|
|
@ -76,3 +75,27 @@ class use_kwargs(use_args):
|
||||||
"""
|
"""
|
||||||
kwargs["as_kwargs"] = True
|
kwargs["as_kwargs"] = True
|
||||||
use_args.__init__(self, schema, **kwargs)
|
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
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
from openflexure_microscope.common.labthings_core.fields import *
|
from marshmallow.fields import *
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,15 @@ 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 . import EXTENSION_NAME
|
||||||
from .extensions import BaseExtension
|
from .extensions import BaseExtension
|
||||||
from .utilities import description_from_view
|
from .utilities import description_from_view
|
||||||
|
from .spec import view2path
|
||||||
|
|
||||||
from .views.extensions import ExtensionList
|
from .views.extensions import ExtensionList
|
||||||
from .views.tasks import TaskList, TaskResource
|
from .views.tasks import TaskList, TaskResource
|
||||||
|
|
||||||
from openflexure_microscope.common.labthings_core.utilities import get_docstring
|
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
|
import logging
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,27 @@
|
||||||
from flask.views import MethodView
|
from flask.views import MethodView
|
||||||
from openflexure_microscope.common.labthings_core.resource import BaseResource
|
|
||||||
|
|
||||||
|
|
||||||
class Resource(MethodView, BaseResource):
|
class Resource(MethodView):
|
||||||
"""Currently identical to 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
|
endpoint = None
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
MethodView.__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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
from .resource import BaseResource
|
from .resource import Resource
|
||||||
from .utilities import rupdate
|
|
||||||
from apispec import APISpec
|
from apispec import APISpec
|
||||||
from apispec.ext.marshmallow import MarshmallowPlugin
|
from apispec.ext.marshmallow import MarshmallowPlugin
|
||||||
|
|
||||||
from openflexure_microscope.common.labthings_core.utilities import (
|
from openflexure_microscope.common.labthings_core.utilities import (
|
||||||
get_docstring,
|
get_docstring,
|
||||||
get_summary,
|
get_summary,
|
||||||
|
rupdate,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .fields import Field
|
from .fields import Field
|
||||||
|
|
@ -20,7 +20,7 @@ def update_spec(obj, spec):
|
||||||
return obj.__apispec__
|
return obj.__apispec__
|
||||||
|
|
||||||
|
|
||||||
def view2path(rule: str, view: BaseResource, spec: APISpec):
|
def view2path(rule: str, view: Resource, spec: APISpec):
|
||||||
params = {
|
params = {
|
||||||
"path": rule, # TODO: Validate this slightly (leading / etc)
|
"path": rule, # TODO: Validate this slightly (leading / etc)
|
||||||
"operations": view2operations(view, spec),
|
"operations": view2operations(view, spec),
|
||||||
|
|
@ -35,9 +35,9 @@ def view2path(rule: str, view: BaseResource, spec: APISpec):
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
|
||||||
def view2operations(view: BaseResource, spec: APISpec, populate_default: bool = True):
|
def view2operations(view: Resource, spec: APISpec, populate_default: bool = True):
|
||||||
ops = {}
|
ops = {}
|
||||||
for method in BaseResource.methods:
|
for method in Resource.methods:
|
||||||
if hasattr(view, method):
|
if hasattr(view, method):
|
||||||
# Populate with default responses
|
# Populate with default responses
|
||||||
if populate_default:
|
if populate_default:
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
Top-level representation of attached and enabled Extensions
|
Top-level representation of attached and enabled Extensions
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from openflexure_microscope.common.labthings_core.utilities import get_docstring
|
from openflexure_microscope.common.flask_labthings.utilities import get_docstring
|
||||||
from openflexure_microscope.common.labthings_core.schema import Schema
|
from openflexure_microscope.common.flask_labthings.schema import Schema
|
||||||
from openflexure_microscope.common.labthings_core import fields
|
from openflexure_microscope.common.flask_labthings import fields
|
||||||
|
|
||||||
from ..utilities import description_from_view
|
from ..utilities import description_from_view
|
||||||
|
|
||||||
|
|
@ -38,9 +38,7 @@ class ExtensionSchema(Schema):
|
||||||
view_rule = view_data["rule"]
|
view_rule = view_data["rule"]
|
||||||
# Make links dictionary if it doesn't yet exist
|
# Make links dictionary if it doesn't yet exist
|
||||||
d[view_id] = {
|
d[view_id] = {
|
||||||
"href": url_for(
|
"href": url_for(ExtensionList.endpoint, **view_kwargs, _external=True)
|
||||||
ExtensionList.endpoint, **view_kwargs, _external=True
|
|
||||||
)
|
|
||||||
+ view_rule,
|
+ view_rule,
|
||||||
**description_from_view(view_cls),
|
**description_from_view(view_cls),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.decorators import marshal_with
|
||||||
from openflexure_microscope.common.flask_labthings.resource import Resource
|
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 (
|
from openflexure_microscope.common.flask_labthings.utilities import (
|
||||||
description_from_view,
|
description_from_view,
|
||||||
)
|
)
|
||||||
|
|
||||||
from openflexure_microscope.common.labthings_core import tasks
|
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
|
from marshmallow import pre_dump
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
from marshmallow.fields import *
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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)
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue