Blackened

This commit is contained in:
jtc42 2020-01-03 00:21:16 +00:00
parent 6be8b0044a
commit ab6fa9f0e5
11 changed files with 104 additions and 80 deletions

View file

@ -5,6 +5,7 @@ from flask import make_response
from .utilities import rupdate
from .spec import update_spec
def unpack(value):
"""Return a three tuple of data, code, and headers"""
if not isinstance(value, tuple):
@ -93,14 +94,7 @@ class doc_response(object):
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
}
}
}
f.__apispec__ = f.__dict__.get("__apispec__", {})
d = {"responses": {self.code: {"description": self.description, **self.kwargs}}}
rupdate(f.__apispec__, d)
return f
return f

View file

@ -17,6 +17,7 @@ from . import EXTENSION_NAME
import logging
class LabThing(object):
def __init__(
self,
@ -60,32 +61,31 @@ class LabThing(object):
self.init_app(app)
@property
def description(self, ):
def description(self,):
return self._description
@description.setter
def description(self, description: str):
self._description = description
self.spec.description = description
@property
def title(self, ):
def title(self,):
return self._title
@title.setter
def title(self, title: str):
self._title = title
self.spec.title = title
@property
def version(self, ):
def version(self,):
return str(self._version)
@version.setter
def version(self, version: str):
self._version = version
self.spec.version = version
### Flask stuff
@ -117,7 +117,9 @@ class LabThing(object):
# Add thing description
self.app.add_url_rule(self._complete_url("/td", ""), "td", self.td)
# Add swagger spec
self.app.add_url_rule(self._complete_url("/swagger", ""), "swagger", self.swagger)
self.app.add_url_rule(
self._complete_url("/swagger", ""), "swagger", self.swagger
)
# Add plugin overview
self.add_resource(PluginListResource, "/plugins")
@ -212,7 +214,7 @@ class LabThing(object):
if self.app is not None:
self._register_view(self.app, resource, *urls, endpoint=endpoint, **kwargs)
self.resources.append((resource, urls, endpoint, kwargs))
def resource(self, *urls, **kwargs):
@ -261,9 +263,7 @@ class LabThing(object):
# 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)
)
self.spec.path(**view2path(rule, resource, self.spec))
### Utilities
@ -334,8 +334,8 @@ class LabThing(object):
"tasks": {
"href": self.url_for(TaskList, _external=True),
**description_from_view(TaskList),
}
}
},
},
}
return jsonify(rr)
@ -344,4 +344,4 @@ class LabThing(object):
"""
OpenAPI v3 documentation
"""
return jsonify(self.spec.to_dict())
return jsonify(self.spec.to_dict())

View file

@ -4,6 +4,7 @@ from flask.views import MethodView
class Resource(MethodView):
"""Currently identical to MethodView
"""
endpoint = None
methods = ["get", "post", "put", "delete"]
@ -15,7 +16,6 @@ class Resource(MethodView):
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] = {}

View file

@ -1,27 +1,31 @@
from .resource import Resource
from .utilities import rupdate
from apispec import APISpec
from apispec.ext.marshmallow import MarshmallowPlugin
from openflexure_microscope.common.labthings_core.utilities import get_docstring, get_summary
from openflexure_microscope.common.labthings_core.utilities import (
get_docstring,
get_summary,
)
from .fields import Field
from marshmallow import Schema as BaseSchema
from collections import Mapping
def update_spec(obj, spec):
obj.__apispec__ = obj.__dict__.get('__apispec__', {})
rupdate(obj.__apispec__, spec)
return obj.__apispec__
obj.__apispec__ = obj.__dict__.get("__apispec__", {})
rupdate(obj.__apispec__, spec)
return obj.__apispec__
def view2path(rule: str, view: Resource, spec: APISpec):
params = {
"path": rule, # TODO: Validate this slightly (leading / etc)
"operations": view2operations(view, spec),
"description": get_docstring(view),
"summary": get_summary(view)
"summary": get_summary(view),
}
if hasattr(view, "__apispec__"):
@ -30,6 +34,7 @@ def view2path(rule: str, view: Resource, spec: APISpec):
return params
def view2operations(view: Resource, spec: APISpec, populate_default: bool = True):
ops = {}
for method in Resource.methods:
@ -39,58 +44,67 @@ def view2operations(view: Resource, spec: APISpec, populate_default: bool = True
ops[method] = {
"responses": {
200: {
"description": get_summary(getattr(view, method)) or "Success"
"description": get_summary(getattr(view, method))
or "Success"
},
404: {
"description": "Resource not found"
}
},
404: {"description": "Resource not found"},
}
}
else:
ops[method] = {}
rupdate(ops[method], {
"description": get_docstring(getattr(view, method)),
"summary": get_summary(getattr(view, method))
})
rupdate(
ops[method],
{
"description": get_docstring(getattr(view, method)),
"summary": get_summary(getattr(view, method)),
},
)
if hasattr(getattr(view, method), "__apispec__"):
rupdate(ops[method], doc2operation(getattr(view, method).__apispec__, spec))
rupdate(
ops[method], doc2operation(getattr(view, method).__apispec__, spec)
)
return ops
def doc2operation(apispec: dict, spec: APISpec):
op = {}
if "_params" in apispec:
rupdate(op, {
"requestBody": {
"content": {
"application/json": {
"schema": convert_schema(apispec.get("_params"), spec)
}
}
}
})
if "_schema" in apispec:
rupdate(op,
{
"responses": {
200: {
rupdate(
op,
{
"requestBody": {
"content": {
"application/json": {
"schema": convert_schema(apispec.get("_schema"), spec)
"schema": convert_schema(apispec.get("_params"), spec)
}
},
}
}
}
})
},
)
if "_schema" in apispec:
rupdate(
op,
{
"responses": {
200: {
"content": {
"application/json": {
"schema": convert_schema(apispec.get("_schema"), spec)
}
}
}
}
},
)
for key, val in apispec.items():
if not key in ["_params", "_schema"]:
op[key] = val
return op
@ -100,12 +114,14 @@ def convert_schema(schema, spec: APISpec):
elif isinstance(schema, Mapping):
return map2properties(schema, spec)
else:
raise TypeError("Unsupported schema type. Ensure schema is a Schema class, or dictionary of Field objects")
raise TypeError(
"Unsupported schema type. Ensure schema is a Schema class, or dictionary of Field objects"
)
def map2properties(schema, spec: APISpec):
marshmallow_plugin = next(
plugin for plugin in spec.plugins
if isinstance(plugin, MarshmallowPlugin)
plugin for plugin in spec.plugins if isinstance(plugin, MarshmallowPlugin)
)
converter = marshmallow_plugin.converter
@ -118,4 +134,4 @@ def map2properties(schema, spec: APISpec):
else:
d[k] = v
return {"properties": d}
return {"properties": d}

View file

@ -1,4 +1,7 @@
from openflexure_microscope.common.labthings_core.utilities import get_docstring, get_summary
from openflexure_microscope.common.labthings_core.utilities import (
get_docstring,
get_summary,
)
from .schema import Schema, marshmallow, MARSHMALLOW_VERSION_INFO
import collections.abc
@ -25,4 +28,4 @@ def rupdate(d, u):
d[k] = rupdate(d.get(k, {}), v)
else:
d[k] = v
return d
return d

View file

@ -48,6 +48,7 @@ class PluginListResource(Resource):
"""
List and basic documentation for all enabled plugins
"""
@marshal_with(PluginSchema(many=True))
def get(self):
"""

View file

@ -39,6 +39,7 @@ class TaskList(Resource):
"""
List and basic documentation for all session tasks
"""
@marshal_with(TaskSchema(many=True))
def get(self):
return tasks.tasks()

View file

@ -5,5 +5,6 @@ def get_docstring(obj):
else:
return ""
def get_summary(obj):
return get_docstring(obj).partition("\n")[0].strip()
return get_docstring(obj).partition("\n")[0].strip()