understanding functools.wraps - python

I am using Flask-RESTful and trying to have my REST endpoints using the technique showed here
The main code is
def authenticate(func):
#wraps(func)
def wrapper(*args, **kwargs):
if not getattr(func, 'authenticated', True):
return func(*args, **kwargs)
acct = basic_authentication() # custom account lookup function
if acct:
return func(*args, **kwargs)
restful.abort(401)
return wrapper
class Resource(restful.Resource):
method_decorators = [authenticate] # applies to all inherited resources
I do the same way and it seems to work, but I am not sure what happens with #wraps?
It seems magic to me at the moment and I did not understand the following
a.) It seems function which is wrapped with #wraps is passed to the wrapper, then what is the wrapper returning?
Possible answer: Everything that was passed to the function initially?
If yes, how can I pass more information like the acct object with everything so that my function receives the account object and I don't have to do a database fetch for it?
UPDATE
Based on the example, my rest endpoint looks like
class UserResource(RestResource):
def get(self, uuid):
return {'method': 'get user -> ' + uuid}
and I call it like
curl -X GET http://127.0.0.1:5000/users/validUUID
Now when my every request is authenticated, I see if a valid acct object exists and if it exists, I delegate the control to endpoint
Question:
Since I am actually making one database call to find out acct object, is it possible to pass in that to the endpoint when a valid acct is located?
This way two things happen
a.) I know the call is authenticated
b.) I reuse the acct object which I can use for my further work, rather than making the DB call again and get the acct object from validUUID again
How can I achieve this ?

authenticate is a decorator -- it takes a function and returns a modified version of that function (which is usually implemented by wrapping the function and wrapping it).
Now, the problem with wrappers is that they often don't act exactly like the original function in some ways -- they may be missing docstrings, have the wrong __name__ (wrapper instead of what it should be called), and other blemishes. This might be important if some other code is using that extra information. functools.wraps is a simple function that adds this information from the original function (here, func) to the wrapper function, so it behaves more like the original function. (Technically, it is itself a decorator, which is the confusing part, but you don't have to worry about that detail. Just know that it is a nice tool that copies attributes from a wrapped function to a wrapper function).
Thus, when you write
new_function = authenticate(old_function)
or more commonly
#authenticate
def function(...)
new_function will look more like old_function.

Related

Is there a pythonic way to skip decoration on a subclass' method?

I have an class which decorates some methods using a decorator from another library. Specifically, the class subclasses flask-restful resources, decorates the http methods with httpauth.HTTPBasicAuth().login_required(), and does some sensible defaults on a model service.
On most subclasses I want the decorator applied; therefore I'd rather remove it than add it in the subclasses.
My thought is to have a private method which does the operations and a public method which is decorated. The effects of decoration can be avoided by overriding the public method to call the private one and not decorating this override. Mocked example below.
I am curious to know if there's a better way to do this. Is there a shortcut for 'cancelling decorators' in python that gives this effect?
Or can you recommend a better approach?
Some other questions have suitable answers for this, e.g. Is there a way to get the function a decorator has wrapped?. But my question is about broader design - i am interested in any pythonic way to run the operations in decorated methods without the effects of decoration. E.g. my example is one such way but there may be others.
def auth_required(fn):
def new_fn(*args, **kwargs):
print('Auth required for this resource...')
fn(*args, **kwargs)
return new_fn
class Resource:
name = None
#auth_required
def get(self):
self._get()
def _get(self):
print('Getting %s' %self.name)
class Eggs(Resource):
name = 'Eggs'
class Spam(Resource):
name = 'Spam'
def get(self):
self._get()
# super(Spam, self)._get()
eggs = Eggs()
spam = Spam()
eggs.get()
# Auth required for this resource...
# Getting Eggs
spam.get()
# Getting Spam
Flask-HTTPAuth uses functools.wraps in the login_required decorator:
def login_required(self, f):
#wraps(f)
def decorated(*args, **kwargs):
...
From Python 3.2, as this calls update_wrapper, you can access the original function via __wrapped__:
To allow access to the original function for introspection and other
purposes (e.g. bypassing a caching decorator such as lru_cache()),
this function automatically adds a __wrapped__ attribute to the
wrapper that refers to the function being wrapped.
If you're writing your own decorators, as in your example, you can also use #wraps to get the same functionality (as well as keeping the docstrings, etc.).
See also Is there a way to get the function a decorator has wrapped?
Another common option is to have the decorated function keep a copy of the original function that can be accessed:
def auth_required(fn):
def new_fn(*args, **kwargs):
print('Auth required for this resource...')
fn(*args, **kwargs)
new_fn.original_fn = fn
return new_fn
Now, for any function that has been decorated, you can access its original_fn attribute to get a handle to the original, un-decorated function.
In that case, you could define some type of dispatcher that either makes plain function calls (when you are happy with the decorator behavior) or makes calls to thing.original_fn when you prefer to avoid the decorator behavior.
Your proposed method is also a valid way to structure it, and whether my suggestion is "better" depends on the rest of the code you're dealing with, who needs to read it, and other kinds of trade-offs.
I am curious to know if there's a better way to do this. Is there a
shortcut for 'cancelling decorators' in python that gives this effect?
Use the undecorated library. It digs through all the decorators and returns just the original function. The docs should be self-explanatory, basically you just call: undecorated(your_decorated_function)

daisy-chaining Python/Django custom decorators

Is it good style to daisy-chain Python/Django custom decorators? And pass different arguments than received?
Many of my Django view functions start off with the exact same code:
#login_required
def myView(request, myObjectID):
try:
myObj = MyObject.objects.get(pk=myObjectID)
except:
return myErrorPage(request)
try:
requester = Profile.objects.get(user=request.user)
except:
return myErrorPage(request)
# Do Something interesting with requester and myObj here
FYI, this is what the corresponding entry in urls.py file looks like:
url(r'^object/(?P<myObjectID>\d+)/?$', views.myView, ),
Repeating the same code in many different view functions is not DRY at all. I would like to improve it by creating a decorator that would do this repetitive work for me and make the new view functions much cleaner and look like this:
#login_required
#my_decorator
def myView(request, requester, myObj):
# Do Something interesting with requester and myObj here
So here are my questions:
Is this a valid thing to do? Is it good style? Notice that I will be changing the signature of the myView() function. That feels a bit strange and risky to me. But I'm not sure why
If I make multiple such decorators that do some common function but each call the wrapped function with different arguments than the decorator received, is it OK if I daisy-chain them together?
If it is OK to #1 and #2 above, what is the best way to indicate to the users of this myView what the set of arguments are that they should pass in (because just looking at the parameters in the function definition is no longer really valid)
That's a very interesting question ! Another one has already been answered in depth on the basic usage of decorators. But it does not provide much insight on modifying arguments
Stackable decorators
You can find on that other question an example of stacked decorators with the following piece of explanation hidden in a very, very long and detailed answer :
Yes, that’s all, it’s that simple. #decorator is just a shortcut to:
another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)
And that's the magic. As python documentation states : a decorator is a function returning another function.
That means you can do :
from functools import wraps
def decorator1(f):
#wraps(f)
def wrapper(*args, **kwargs):
do_something()
f(*args, **kwargs)
return wrapper
def decorator2(f):
#wraps(f)
def wrapper(*args, **kwargs):
do_something_else()
f(*args, **kwargs)
return wrapper
#decorator1
#decorator2
def myfunc(n):
print "."*n
#is equivalent to
def myfunc(n):
print "."*n
myfunc = decorator1(decorator2(myfunc))
Decorators are not Decorators
Python decorators might be puzzling for developpers who learned OOP with a language where GoF has already used half of the dictionary to name the patterns who fix the failures of the language is the de-facto design pattern shop.
GoF's decorators are subclasses of the component (interface) they're decorating, therefore sharing this interface with any other subclass of that component.
Python decorators are functions returning functions (or classes).
Functions all the way down
A python decorator is a function returning a function, any function.
Most decorators out there are designed to extend the decorated function without getting in the way of it's expected behavior. They are shaped after GoF's definition of the Decorator pattern, which describes a way to extend an object while keeping it's interface.
But GoF's Decorator is a pattern, whereas python's decorator is a feature.
Python decorators are functions, these functions are expected to return functions (when provided a function).
Adapters
Let's take another GoF pattern : Adapter
An adapter helps two incompatible interfaces to work together.
This is the real world definition for an adapter.
[An Object] adapter contains an instance of the class it wraps.
In this situation, the adapter makes calls to the instance of the wrapped
object.
Take for example an object — say a dispatcher, who would call a function which takes some defined parameters, and take a function who would do the job but provided another set of parameters. Parameters for the second function can be derived from those of the first.
A function (which is a first-class object in python) who would take the parameters of the first and derive them to call the second and return a value derived from its result would be an adapter.
A function returning an adapter for the function it is passed would be an adapter factory.
Python decorators are functions returning functions. Including adapters.
def my_adapter(f):
def wrapper(*args, **kwargs):
newargs, newkwargs = adapt(args, kwargs)
return f(*newargs, **newkwargs)
#my_adapter # This is the contract provider
def myfunc(*args, **kwargs):
return something()
Oooooh, I see what you did there… is it good style ?
I'd say, hell yeah, yet another built-in pattern ! But you'd have to forget about GoF Decorators and simply remember that python decorators are functions which return functions. Therefore, the interface you're dealing with is the one of the wrapper function, not the decorated one.
Once you decorate a function, the decorator defines the contract, either telling it's keeping the interface of the decorated function or abstracting it away. You don't call that decorated function anymore, it's even tricky to try it, you call the wrapper.
First of all, this block of code:
try:
myObj = MyObject.objects.get(pk=myObjectID)
except:
return myErrorPage(request)
can be replaced with:
from django.shortcuts import get_object_or_404
myObj = get_object_or_404(MyObject, pk=myObjectID)
The same applies with the second block of code you have.
That in and of itself makes this a lot more elegant.
If you'd like to go further and implement your own decorator, your best bet is to subclass #login_required. If you're passing different arguments or don't want to do that, then you can indeed make your own decorator and it wouldn't be wrong.
1) Yes, chaining decorators is valid as other answers have already pointed out. Good style is subjective, but personally I think it would make your code much harder to read for others. Someone familiar with Django but not your application would need to keep extra context in their head while working with your code. I think it's very important to stick to framework conventions to make your code as maintainable as possible.
2) The answer is yes, it is technically okay to pass in different arguments to the wrapped function, but consider a simple code example of how this would work:
def decorator1(func):
def wrapper1(a1):
a2 = "hello from decorator 1"
func(a1, a2)
return wrapper1
def decorator2(func):
def wrapper2(a1, a2):
a3 = "hello from decorator 2"
func(a1, a2, a3)
return wrapper2
#decorator1
#decorator2
def my_func(a1, a2, a3):
print a1, a2, a3
my_func("who's there?")
# Prints:
# who's there?
# hello from decorator 1
# hello from decorator2
In my opinion, any person reading this would need to be a mental gymnast to keep context of the method signatures at each level of the decorator stack.
3) I would use a class-based view and override the dispatch() method to set instance variables like this:
class MyView(View):
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
self.myObj = ...
self.requester = ...
return super(MyView, self).dispatch(*args, **kwargs)
The dispatch method is what calls your get()/post() methods. From the django docs:
The as_view entry point creates an instance of your class and calls its dispatch() method. dispatch looks at the request to determine whether it is a GET, POST, etc, and relays the request to a matching method if one is defined
Then you could access these instance variables in your get() and/or post() view methods. The advantage of this approach is that you could extract this out to a base class and use it in any number of View subclasses. It is also a lot more traceable in an IDE because this is standard inheritance.
An example of how a get() request would look like:
class MyView(View):
def get(self, request, id):
print 'requester is {}'.format(self.requester)

Decorator that can interact with the wrapped function's arguments

I am trying to build a decorator that can inspect the wrapped function's arguments, the context for the need is to allow easier validation of certain arguments before they hit the function, avoiding the boiler plate of checking in every place I need said check/validation.
This is not a difficult decorator to write though, and this gets the job done (to make sure a value is not None for example):
def check_arg(func):
def wrapped(value):
assert value is not None
func(value)
return wrapped
The above example is not production code, it is merely an example of something that will work, but the problem becomes apparent when the function to decorate can have other decorators being used.
In that case, the above decorator example will not work, because value can now be another decorator. I could add another nested function here but it looks like there should be a better way of dealing with it programmatically, plus, it would break whenever the number of decorators change.
How could I get to the arguments of the wrapped function regardless of the number of decorators used by it?
EDIT: I should've noted than I am not simply stacking decorators, I am using one decorator that decorates re-usable decorators. In the example above I would re-use that in this context:
#check_arg
def some_other_decorator(func):
def wrapped(*args, **kw):
... # some interaction here
return wrapped
As I was writing this edit, I realized that the check_arg decorator was in the wrong place, it should've been in the wrapped function call within the some_other_decorator.
Are you in control of the other decorators? If so, make sure all of them play nice by properly
wrapping the calling function:
import functools
def check_arg(func):
#functools.wraps(func)
def wrapped(value):
assert value is not None
func(value)
return wrapped

Python wrappers - Confusion about variable scope

I thought I would be clever and write a wrapper that called the session variables (many are present) and add that to the (django) views requiring session variables. However I seem to not be understanding the scope of the variables, or am writing this incorrectly.
The wrapper I have is:
def s_vars(func_to_decorate):
#wraps(func_to_decorate)
def wrapper(request, *args, **kwargs):
#add all the session variables to kwargs and accessible for the decorated function.
user_obj = request.user
datepicker = request.session['datepicker']
date_format = request.session['date_format']
.........
country = request.session['country']
metric = request.session['metric']
qrydtm = request.session.get("qrydtm",date.today())
result = func_to_decorate(request, *args, **kwargs)
#any post view checks to be done go here
#return to the function to be decorated.
return result
return wrapper
Then for the view I have something like:
#s_vars
def main(request, template_name='placeholder.html'):
return render_to_response(template_name, RequestContext(request,{
'user':user_obj
}))
But this leads to the error that user_obj is not accessible inside the method "main". My understanding was that this is an inner function and therefore the variables in the list under the "wrapper" method would be accessible to this inner function "main". What am I missing here?
The syntax
#spam
def ham():
pass
is precisely equivalent to the syntax
def ham():
pass
ham = spam(ham)
Does that clarify why what you are doing doesn't work?
If you want to pass stuffto a function from a decorator, the usual idiom is to send extra arguments to the function. This can be a little icky, because it means that the argspec that looks right is actually not.
Nested functions only take scoped variables from the scope where they are defined, and the binding takes place at compile time.
You cannot add scoped variables later on, and certainly not with a simple wrapper.
At the point where the inner function is called, it is just called by the outer scope function, not defined in it.
That distinction (also made by interpreter vs runtime) is definitely important in scoping. Take a look at the dis (disassembly) of the s_vars wrapper (or a reduced simple example of the same behaviour). The code is not reinterpreted for different values (it is just a value here) of func_to_decorate.
If you want to make a list of variables available to the inner function, perhaps an object passed in would make more sense. The wrapper could ensure that the external API is without it.

Is it bad practice to use self in decorators?

While I'm aware that you can't reference self directly in a decorator, I was wondering if it's bad practice to work around that by pulling it from args[0]. My hunch is that it is, but I want to be sure.
To be more specific, I'm working on an API to a web service. About half the commands require a token to be passed that can be later used to undo it. What I would like is to make that token an optional parameter and if none is supplied, to generate one. Generating a token requires making an authenticated call to the server, which needs data from the object.
While I know I could do it:
def some_command(self, ..., undo_token = None):
if undo_token = None:
undo_token = self.get_undo_token()
...
return fnord
I feel like there could be a better way than to have the same code in a dozen or so methods. My thought was to write a decorator:
#decorator
def undoable(fn, *args, **kwargs):
if 'undo_token' not in kwargs:
kwargs['undo_token'] = args[0].get_undo_token()
return (fn(*args, **kwargs), kwargs['undo_token'])
So I can more cleanly write
#undoable
def some_command(self, ...):
...
return foo
#undoable
def some_other_command(self, ...):
...
return bar
Am I setting myself up for trouble down the line?
I don't understand what you're coding for undoable -- that's not how decorators are normally coded and I don't know where that #decorator is coming from (is there a from youforgottotelluswhence import decorator or something even more evil? see why I can't stand the use of from to build "artificial barenames" instead of using nice decorated names?-).
With normal decorator coding, e.g....:
import functools
def undoable(f):
#functools.wraps(f)
def wrapper(self, *a, **k):
tok = k.get('undo_token')
if tok is None:
tok = k['undo_token'] = self.get_undo_token()
return f(self, *a, **k), tok
return wrapper
there's absolutely no problem naming the wrapper's first, mandatory positional argument self, and much gain of clarity in using this rather than the less-readable args[0].
Decorators extend the functionality of the function it decorates in a generic way. If decorators to do not make any assumption about the function or it's args or kwargs, it is in most generic form and can be easily used with many functions.
How ever, if you want to do something with what is being passed onto the function, it should be fine but their applicability is limited and can break, if the underlying details, which you have used in your decorator changes.
In the above decorator, if the object removes the method get_undo_token(), you will need to revisit the decorator too. It is fine to do that but document the constraints and also add that documentation to the method doc it self.
Do it only if absolutely necessary. It serves to create more generic decorators.

Categories