I have written a decorator that is working correctly but i stumbled with the correct solution by trial and error and my litle knowledge about decorators tells me that something is not well defined.
The case is i'm mocking a Rest Api to do some TDD, and this Rest is behind a token security. So before making any request i first must get my user token. I'm using httpretty for mocking the API.
So far i had to register_uri in every test case, one to mock the /token resource and another to test any other resource. But i found that very cumbersome, so a came with a solution to write a simple decorator that would mock the /token and then only had to mock the tested resource.
This is my currently working decorator...
def activate_security(func):
def test_case(test_case):
httpretty.enable()
uri = 'http://{}:{}/token'.format(HOST, PORT)
httpretty.register_uri(httpretty.GET, uri,
body=dumps({'token': 'dummy_token'}),
content_type='application/json')
test_case()
httpretty.disable()
return test_case
And this is how is called.
#activate_security
#httpretty.activate
def test_case_one(self):
#Test case here
I had to pass the test_case parameter to the inner function 'cause without it it wouldn't work, and that test_case is test_case_one method, which i thought it would be passed in the func argument, but func in the outer scope holds the object at memory of test_case.
Should't be func the returned value of a decorator? If i do that, the decorator doesn't work. When the inner function is passed that parameter?
You are decorating methods, so your resulting wrapper function needs a self parameter, just like normal functions being used in a class.
All that is different is that you used a different name fro that self parameter, test_case. As it happens, the instance is callable, and calling it runs the test, so you are in essence doing self() to run the test again.
Just name the parameter self and pass it to the wrapped function:
def activate_security(func):
def wrapper(self):
httpretty.enable()
uri = 'http://{}:{}/token'.format(HOST, PORT)
httpretty.register_uri(httpretty.GET, uri,
body=dumps({'token': 'dummy_token'}),
content_type='application/json')
func(self)
httpretty.disable()
return wrapper
The wrapper() function then replaces the original test_case_one function, and when the test is run the wrapper() function is bound to the test case instance and will be passed that instance as self; in your wrapper you can then call the unbound func() by simply passing on self to it.
For debugging purposes it is often nicer to have some function attributes copied over from the wrapped function to the wrapper; the #functools.wraps() decorator can take care of these details for you:
import functools
def activate_security(func):
#functools.wraps(func)
def wrapper(self):
httpretty.enable()
uri = 'http://{}:{}/token'.format(HOST, PORT)
httpretty.register_uri(httpretty.GET, uri,
body=dumps({'token': 'dummy_token'}),
content_type='application/json')
func(self)
httpretty.disable()
return wrapper
Related
is it possible to check in the test with what parameters the method is called and what result it returns, if we call the main method run which calls the method I'm interested in - self.get_request().
file.py
class A:
def run():
some logic...
request = self.get_request()
some logic...
return response
test.py
from file.py import A
def test():
"""
Inside this test, I want to check the parameters and the value returned by the
get_request method, but I don't want to check it separately
I want to check it by calling the parent method - run
"""
instance = A()
response = instance.run()
assertions logic for instance.get_request..
I know that it is possible to mock a method and then we have access to the number of calls, parameters, etc. If what I'm asking is possible in some way through mock, I just want to add that my mock would have to have the same logic as the method it mocks (be the same).
What you are asking for is probably the wraps argument that can be used in patch - this allows you to mock a function, while it still retains the previous (or some other) functionality (note that the argument itself is described under Mock). As with any mock, this does allow you to test the calls and call args, but does not allow you to check the return value of the function. This has to be tested via its side effects (in your case via the returned response which should depend on the return value of get_request).
Here is an illustration for your case:
from unittest import mock
class A:
def run(self):
request = self.get_request(21)
return request
def get_request(self, foo):
return foo * 2
def test_run():
instance = A()
with mock.patch.object(instance, "get_request", wraps=instance.get_request) as mocked:
assert instance.run() == 42
mocked.assert_called_once_with(21)
In this case the mock calls the real get_request method and returns its result, while recording the call and the call args.
I added some argument to get_request for demonstration, and returned the result of the call directly in run - in your case this will differ of course, but the idea should be the same.
I have a class named Server which can be started and stopped. Certain methods should not be called unless the Server is started, in which case a NotConnectedException should be raised. Is there a way to call a method before every method in a class and determine if class variable _started is set to True?
I tried using a decorator, but the decorator function does not have access to the class variable. I was trying to do something like this:
class Server(object):
_started = False
def started(self):
if(self._started == False):
raise NotConnectedException
#started
def doServerAction(self):
...
Remember what decorators are:
#decorate
def foo(...):
...
is exactly equivalent to:
def foo(...):
...
foo = decorate(foo)
The decorator is called on the function, so calling the first parameter self makes no sense. Also, the decorator is called on the function when it is defined, and whatever it returns is used in place of the function. So even if your started decorator didn't throw an AttributeError by trying to access the _started attribute of a function, it would then return None, making all your methods set to None, and thus not even be callable.
What you want is something like this:
import functools
def started(func):
#functools.wraps(func)
def wrapper(self, *args, **kwargs):
if not self._started:
raise ...
else:
return func(self, *args, **kwargs)
return wrapper
Almost all decorators are of this form; they take a function, create a wrapper that does something "around" the received function, and then return the wrapper. The use of functools.wraps here is a convenience if you ever end up working with this code in an interactive interpreter session; it automatically updates the wrapper function with the name and docstring of the original function, which makes the decorated functions "look like" the original function a bit more.
It's irrelevant whether this is defined inside the class or not.
I am trying to simply my Web application handlers, by using Python decorators.
Essentially I want to use decorators to abstract code that checks for authenticated sessions and the other that checks to see if the cache provider (Memcache in this instance) has a suitable response.
Consider this method definition with the decorators:
#auth.login_required
#cache.clear
def post(self, facility_type_id = None):
auth.login_required checks to see if the user is logged in, otherwise returns an appropriate error message, or executes the original function.
cache.clear would check to to see if the cache has a particular key and drop that, before it executes the calling method.
Both auth.login_required and cache.clear would want to eventually execute the calling method (post).
From what I've read both, doing what I am doing now would execute the calling method (post) twice.
My question, how do I chain decorators that end up executing the calling method, but ensure that it's only called once.
Appreciate any pointers and thanks for your time.
Each successive decorator receives the previously wrapped function, so the function itself only gets called once at the end of the chain. Here's a simple example:
def dec1(f):
def wrapped():
print 'dec1'
return f()
return wrapped
def dec2(f):
def wrapped():
print 'dec2'
return f()
return wrapped
#dec2
#dec1
def spam(): print 'spam'
>>> spam()
dec2
dec1
spam
You didn't understand how decorators work.
The two decorators are already "sequenced". The outer one will receive as function to act on an already decorated function. The inner function is not going to be called twice.
I need to decorate a object's method. It needs to be at runtime because the decorators applied on the object depends on the arguments that the user gave when calling the program (arguments supplied with argv), so a same object could be decorated 3 times, 2 times, or not be decorated at all.
Here is some context, the program is a puzzle solver, the main behavior is to find a solution for the puzzle automatically, by automatically I mean without user intervention. And here is where the decoration gets to play, one of the things I want to is draw a graph of what happened during the execution, but I want to do so only when the flag --draw-graph is used.
Here is what I've tried:
class GraphDecorator(object):
def __init__(self, wrappee):
self.wrappee = wrappee
def method(self):
# do my stuff here
self.wrappee.method()
# do more of stuff here
def __getattr__(self,attr):
return getattr(self.wrappee,attr)
And why it did NOT work:
It did not work because of the way I built the application, when a method that did not exist in my Decorator class was called it felt back to the implementation of the decorated class, the problem is that the application always started invoking the method run that did not need to be decorated, so the undecorated fall back was used and from inside the undecorated form it always called undecorated methods, what I needed was to replace the method from the object, not to proxy it:
# method responsible to replace the undecorated form by the decorated one
def graphDecorator(obj):
old_method = obj.method
def method(self):
# do my stuff here
old_method()
# do more of my stuff
setattr(obj,'method',method) # replace with the decorated form
And here is my problem, the decorated form does not receive self when it is called resulting on a TypeError because of the wrong number of arguments.
The problem was that I couldn't use func(self) as a method. The reason is that setattr() method does not bound the function, and the function acts like it a static method - not a class method -, thanks to the introspective nature of python I've able to come up with this solution:
def decorator(obj):
old_func = obj.func # can't call 'by name' because of recursion
def decorated_func(self):
# do my stuff here
old_func() # does not need pass obj
# do some othere stuff here
# here is the magic, this get the type of a 'normal method' of a class
method = type(obj.func)
# this bounds the method to the object, so self is passed by default
obj.func = method(decorated_func, obj)
I think this is the best way to decorate a object's method at runtime, though it would be nice to find a way to call method() directly, without the line method = type(obj.func)
You might want to use __getattribute__ instead of __getattr__ (the latter being only called if "standard" lookup fails):
class GraphDecorator(object):
def __init__(self, wrappee):
self.__wrappee = wrappee
def method(self):
# do my stuff here
self.wrappe.method()
# do more of stuff here
def __getattribute__(self, name):
try:
wrappee = object.__getattribute__(self, "_GraphDecorator__wrappee")
return getattr(wrappee, name)
except AttributeError:
return object.__getattribute__(self, name)
I need to decorate a object's method. It needs to be at runtime because the decorators applied on the object depends on the arguments that the user gave when calling the program (arguments supplied with argv), so a same object could be decorated 3 times, 2 times, or not be decorated at all.
The above is unfortunately incorrect, and what you are trying to do is unnecessary.
You can do this at runtime like so. Example:
import sys
args = sys.argv[1:]
class MyClass(object):
pass
if args[0]=='--decorateWithFoo':
MyClass = decoratorFoo(MyClass)
if args[1]=='--decorateWithBar'
MyClass = decoratorBar(MyClass)
The syntax:
#deco
define something
Is the same thing as:
define something
something = deco(something)
You could also make a decorator factory #makeDecorator(command_line_arguments)
"It needs to be at runtime because the decorators applied on the object depends on the arguments that the user gave when calling the program"
The don't use decorators. Decorators are only syntactical support for wrappers, you can just as well use normal function/method calls instead.
I'm trying to write a simple decorator to check the authentication of a user, and to redirect to the login page if s/he is not authenticated:
def authenticate(f):
try:
if user['authenticated'] is True:
return f
except:
redirect_to(controller='login', action='index')
class IndexController(BaseController):
#authenticate
def index(self):
return render('/index.mako' )
But this approach doesn't work. When a user is authenticated, everything is fine. But when the user is not authenticated, redirect_to() doesn't work and I am given this error:
HTTPFound: 302 Found Content-Type: text/html; charset=UTF-8 Content-Length: 0 location: /login
Thank for your help!
i don't know pylons, but it seems the way you wrote your decorator is not good.
a decorator is a callable which must return a callable. the decorator is called at the moment the function is defined, and it should return a callable (generally a function) which will be called in place of the function being decorated.
in your sample, your decorator returns a callable only if the user is authenticated at the moment the index() function is defined.
try rewriting it this way:
def authenticate(func):
def call(*args, **kwargs):
if user['authenticated'] is True:
return func(*args,**kwargs)
else:
return redirect_to(controller='login', action='index')
return call
here, authenticate() defines an inner function, which is returned in place of the function it decorates. now when you decorate a function using this decorator:
#authenticate
def index(self):
return render('/index.mako' )
this means that each time you call index(), you are in fact calling the inner function declared in your decorator.
you should note that: due to the way functions are defined in python, the function object returned by the decorator still remembers the value of arguments of the function in which it was defined. call() still knows about the argument func which was passed when the decorator was called. (this is called a closure)
decorators are difficult to understand although they are not complicated. you should search google for a tutorial on decorators: there are plenty of them which gives a very nice understanding of the concept, far much clearer than the python documentation.