Generate links at pre_dump time

This commit is contained in:
jtc42 2019-12-21 17:37:21 +00:00
parent d13f8d8b8c
commit 4793de1283
4 changed files with 547 additions and 101 deletions

View file

@ -7,24 +7,73 @@ from openflexure_microscope.common.flask_labthings.schema import Schema
from openflexure_microscope.common.flask_labthings import fields
from openflexure_microscope.common.flask_labthings.resource import Resource
from openflexure_microscope.common.flask_labthings.utilities import description_from_view
from openflexure_microscope.common.flask_labthings.decorators import marshal_with
from openflexure_microscope.common.flask_labthings.find import find_device
from marshmallow import pre_dump
class CaptureSchema(Schema):
id = fields.String()
file = fields.String(data_key="path")
exists = fields.Bool(data_key="available")
filename = fields.String()
metadata = fields.Dict()
links = fields.Dict()
# TODO: Automate this somewhat
@pre_dump
def generate_links(self, data, **kwargs):
data.links = {
"self": {
"href": url_for(CaptureResource.endpoint, id=data.id, _external=True),
"mimetype": "application/json",
**description_from_view(CaptureResource)
},
"tags": {
"href": url_for(CaptureTags.endpoint, id=data.id, _external=True),
"mimetype": "application/json",
**description_from_view(CaptureTags)
},
"metadata": {
"href": url_for(CaptureMetadata.endpoint, id=data.id, _external=True),
"mimetype": "application/json",
**description_from_view(CaptureMetadata)
},
"download": {
"href": url_for(
CaptureDownload.endpoint, id=data.id, filename=data.filename, _external=True
),
"mimetype": "image/jpeg",
**description_from_view(CaptureDownload)
},
}
return data
capture_schema = CaptureSchema()
capture_list_schema = CaptureSchema(many=True)
class CaptureList(Resource):
"""
List all image captures
"""
@marshal_with(CaptureSchema(many=True))
def get(self):
microscope = find_device("openflexure_microscope")
image_list = microscope.camera.images
return capture_list_schema.jsonify(image_list)
return image_list
class CaptureResource(Resource):
"""
Description of a single image capture
"""
@marshal_with(CaptureSchema())
def get(self, id):
microscope = find_device("openflexure_microscope")
capture_obj = microscope.camera.image_from_id(id)
@ -32,7 +81,7 @@ class CaptureResource(Resource):
if not capture_obj:
return abort(404) # 404 Not Found
return capture_schema.jsonify(capture_obj)
return capture_obj
def delete(self, id):
microscope = find_device("openflexure_microscope")
@ -43,7 +92,7 @@ class CaptureResource(Resource):
capture_obj.delete()
return ("", 204)
return "", 204
class CaptureDownload(Resource):
@ -162,46 +211,6 @@ class CaptureMetadata(Resource):
return jsonify(capture_obj.metadata)
class CaptureSchema(Schema):
id = fields.String()
file = fields.String(data_key="path")
exists = fields.Bool(data_key="available")
filename = fields.String()
metadata = fields.Dict()
# TODO: Add HTTP methods
links = fields.Hyperlinks(
{
"self": {
"href": fields.AbsoluteUrlFor(CaptureResource, id="<id>"),
"mimetype": "application/json",
**description_from_view(CaptureResource)
},
"tags": {
"href": fields.AbsoluteUrlFor(CaptureTags, id="<id>"),
"mimetype": "application/json",
**description_from_view(CaptureTags)
},
"metadata": {
"href": fields.AbsoluteUrlFor(CaptureMetadata, id="<id>"),
"mimetype": "application/json",
**description_from_view(CaptureMetadata)
},
"download": {
"href": fields.AbsoluteUrlFor(
CaptureDownload, id="<id>", filename="<filename>"
),
"mimetype": "image/jpeg",
**description_from_view(CaptureDownload)
},
}
)
capture_schema = CaptureSchema()
capture_list_schema = CaptureSchema(many=True)
def add_captures_to_labthing(labthing, prefix=""):
"""
Add all capture resources to a labthing

View file

@ -0,0 +1,44 @@
from webargs.flaskparser import use_args, use_kwargs
from functools import wraps
from flask import make_response
def unpack(value):
"""Return a three tuple of data, code, and headers"""
if not isinstance(value, tuple):
return value, 200, {}
try:
data, code, headers = value
return data, code, headers
except ValueError:
pass
try:
data, code = value
return data, code, {}
except ValueError:
pass
return value, 200, {}
class marshal_with(object):
def __init__(self, schema):
"""
:param schema: a dict of whose keys will make up the final
serialized response output
"""
self.schema = schema
def __call__(self, f):
@wraps(f)
def wrapper(*args, **kwargs):
resp = f(*args, **kwargs)
if isinstance(resp, tuple):
data, code, headers = unpack(resp)
print((data, code, headers))
return make_response(self.schema.jsonify(data), code, headers)
else:
return make_response(self.schema.jsonify(resp))
return wrapper

View file

@ -1,4 +1,4 @@
from flask import abort
from flask import abort, url_for
from openflexure_microscope.common.flask_labthings.schema import Schema
from openflexure_microscope.common.flask_labthings import fields
@ -6,6 +6,8 @@ from openflexure_microscope.common.labthings_core import tasks
from openflexure_microscope.common.flask_labthings.resource import Resource
from openflexure_microscope.common.flask_labthings.utilities import description_from_view
from marshmallow import pre_dump
class TaskList(Resource):
def get(self):
@ -43,16 +45,17 @@ class TaskSchema(Schema):
_start_time = fields.String(data_key="start_time")
_end_time = fields.String(data_key="end_time")
# TODO: Add HTTP methods
links = fields.Hyperlinks(
{
# TODO: Automate this somewhat
@pre_dump
def generate_links(self, data, **kwargs):
data.links = {
"self": {
"href": fields.AbsoluteUrlFor(TaskResource, id="<id>"),
"href": url_for(TaskResource.endpoint, id=data.id, _external=True),
"mimetype": "application/json",
**description_from_view(TaskResource)
}
},
}
)
return data
task_schema = TaskSchema()