Reputation: 329
I'm trying to replace the marshal_with
decorator from flask-restful
with a decorator that does something before calling marshal_with
. My approach is to try to implement a new decorator that wraps marshal_with
.
My code looks like:
from flask.ext.restful import marshal_with as restful_marshal_with
def marshal_with(fields, envelope=None):
def wrapper(f):
print("Do something with fields and envelope")
@wraps(f)
def inner(*args, **kwargs):
restful_marshal_with(f(*args, **kwargs))
return inner
return wrapper
Unfortunately this seems to break things... no error messages but my API returns a null response when it shouldn't be. Any insights on what I'm doing wrong?
Upvotes: 0
Views: 1623
Reputation: 329
I was doing a couple things wrong here, first, failing to return the output of restful_marshal_with
as jonrsharpe pointed out, secondly, failing to understand a decorator written as a class instead of a function, and how to properly pass values to it. The correct code ended up being:
def marshal_with(fields, envelope=None):
def wrapper(f):
print("Do something with fields and envelope")
@wraps(f)
def inner(*args, **kwargs):
rmw = restful_marshal_with(fields, envelope)
return rmw(f)(*args, **kwargs)
return inner
return wrapper
As you can see, in addition to not returning rmw()
, I needed to properly initialize the request_marshal_with
class before calling it. Finally, it is important to remember that decorators return functions, therefore the arguments of the original function should be passed to the return value of rmw(f)
, hence the statement return rmw(f)(*args, **kwargs)
. This is perhaps more apparent if you take a look at the flask_restful.marshal_with
code here.
Upvotes: 0
Reputation: 474
I don't know the specifics of marshal_with
, but it's entirely possible to use multiple decorators on a single function. For instance:
def decorator_one(func):
def inner(*args, **kwargs):
print("I'm decorator one")
func(*args, **kwargs)
return inner
def decorator_two(text):
def wrapper(func):
def inner(*args, **kwargs):
print(text)
func(*args, **kwargs)
return inner
return wrapper
@decorator_one
@decorator_two("I'm decorator two")
def some_function(a, b):
print(a, b, a+b)
some_function(4, 7)
The output this gives is:
I'm decorator one
I'm decorator two
4 7 11
You can modify this little script by adding print statements after each inner
function call to see the exact flow control between each decorator as well.
Upvotes: 1