44from werkzeug .wrappers import Response as ResponseBase
55from http import HTTPStatus
66from marshmallow .exceptions import ValidationError
7- from collections import Mapping
7+ from collections .abc import Mapping
8+
9+ from marshmallow import Schema as _Schema
810
911from .spec .utilities import update_spec
1012from .schema import TaskSchema , Schema , FieldSchema
1113from .fields import Field
1214from .view import View
1315from .find import current_labthing
16+ from .utilities import unpack
1417
1518from labthings .core .tasks .pool import TaskThread
19+ from labthings .core .utilities import rupdate
1620
1721import logging
1822
1923# Useful externals to have included here
2024from marshmallow import pre_dump , pre_load
2125
2226
23- def unpack (value ):
24- """Return a three tuple of data, code, and headers"""
25- if not isinstance (value , tuple ):
26- return value , 200 , {}
27-
28- try :
29- data , code , headers = value
30- return data , code , headers
31- except ValueError :
32- pass
33-
34- try :
35- data , code = value
36- return data , code , {}
37- except ValueError :
38- pass
39-
40- return value , 200 , {}
41-
42-
4327class marshal_with :
4428 def __init__ (self , schema , code = 200 ):
45- """Decorator to format the response of a View with a Marshmallow schema
29+ """Decorator to format the return of a function with a Marshmallow schema
4630
4731 Args:
4832 schema: Marshmallow schema, field, or dict of Fields, describing
@@ -52,11 +36,11 @@ def __init__(self, schema, code=200):
5236 self .code = code
5337
5438 if isinstance (self .schema , Mapping ):
55- self .converter = Schema .from_dict (self .schema )().jsonify
39+ self .converter = Schema .from_dict (self .schema )().dump
5640 elif isinstance (self .schema , Field ):
57- self .converter = FieldSchema (self .schema ).jsonify
58- elif isinstance (self .schema , Schema ):
59- self .converter = self .schema .jsonify
41+ self .converter = FieldSchema (self .schema ).dump
42+ elif isinstance (self .schema , _Schema ):
43+ self .converter = self .schema .dump
6044 else :
6145 raise TypeError (
6246 f"Unsupported schema type { type (self .schema )} for marshal_with"
@@ -69,12 +53,15 @@ def __call__(self, f):
6953 @wraps (f )
7054 def wrapper (* args , ** kwargs ):
7155 resp = f (* args , ** kwargs )
72- if isinstance (resp , tuple ):
73- data , code , headers = unpack (resp )
56+ if isinstance (resp , ResponseBase ):
57+ resp .data = self .converter (resp .data )
58+ return resp
59+ elif isinstance (resp , tuple ):
60+ resp , code , headers = unpack (resp )
61+ return (self .converter (resp ), code , headers )
7462 else :
75- data , code , headers = resp , 200 , {}
76-
77- return make_response (self .converter (data ), code , headers )
63+ resp , code , headers = resp , 200 , {}
64+ return (self .converter (resp ), code , headers )
7865
7966 return wrapper
8067
@@ -90,15 +77,15 @@ def marshal_task(f):
9077 def wrapper (* args , ** kwargs ):
9178 resp = f (* args , ** kwargs )
9279 if isinstance (resp , tuple ):
93- data , code , headers = unpack (resp )
80+ resp , code , headers = unpack (resp )
9481 else :
95- data , code , headers = resp , 200 , {}
82+ resp , code , headers = resp , 201 , {}
9683
97- if not isinstance (data , TaskThread ):
84+ if not isinstance (resp , TaskThread ):
9885 raise TypeError (
99- f"Function { f .__name__ } expected to return a TaskThread object, but instead returned a { type (data ).__name__ } . If it does not return a task, remove the @marshall_task decorator from { f .__name__ } ."
86+ f"Function { f .__name__ } expected to return a TaskThread object, but instead returned a { type (resp ).__name__ } . If it does not return a task, remove the @marshall_task decorator from { f .__name__ } ."
10087 )
101- return make_response (TaskSchema ().jsonify ( data ), code , headers )
88+ return (TaskSchema ().dump ( resp ), code , headers )
10289
10390 return wrapper
10491
@@ -327,11 +314,12 @@ def __init__(self, code, description=None, mimetype=None, **kwargs):
327314 }
328315
329316 if self .mimetype :
330- self .response_dict .update (
317+ rupdate (
318+ self .response_dict ,
331319 {
332320 "responses" : {self .code : {"content" : {self .mimetype : {}}}},
333321 "_content_type" : self .mimetype ,
334- }
322+ },
335323 )
336324
337325 def __call__ (self , f ):
0 commit comments