Send a python decorated method as a function parameter - python

I currently have the following code which uses a python library:
f = Foo(original_method, parameters)
I would like to augment original_method, and have a decorator add a few lines of code. Let's call the new decorated method decorated_method. Finally I would like to have something like this:
f = Foo(decorated_method(original_method), parameters)
My questions are: is this possible? how would the decorator look like?
I must say that I can't extend original_method, since it is part of an external library.
Edit: original_method is not executed, is only passed to Foo as a parameter. decorated_method function should do some logging and gather some statistics of the number of calls.
Later edit: the code in examples below works fine. I had a few additional problems because original_method had a few attributes, so this is the final code:
def decorated_method(method):
def _reporter(*args, **kwargs):
addmetric('apicall', method.__name__)
return method(*args, **kwargs)
_reporter.original_method_attribute = method.original_method_attribute
return _reporter

You don't mention what you want decorated_method to do, but this is certainly possible:
def decorated_method(f):
def _wrapped(*args, **kwargs):
print "About to call f!"
ret = f(*args, **kwargs)
print "Just got finished with f, ret = %r" % (ret,)
return ret
return _wrapped
This is just standard decorator structure: A decorator is a function which accepts a function and returns a function.

Absolutely:
def decorated_method(fn):
def inner_method(*args, **kwargs):
print("before calling")
result = fn(*args, **kwargs)
print("after calling")
return result
return inner_method
Once you've got this working, you should look at signature-preserving decorators.

Related

python decorator - is it possible to return a function that expects more params?

I have a really simple function, defined as
def test(x):
return x
I would like to wrap it with a decorator, that returns a function that expects another kwargs param.
#simple_dec
def test(x):
return x
Inside that decorator function, i would pop that param from the kwargs dict, and that just call test function with the params test would expect to get, without breaking it:
def simple_dec():
def simple_dec_logic(func, *args, **kwargs):
kwargs.pop("extra_param")
return func(*args, **kwargs)
return decorator.decorate(_func, simple_dec_logic)
My issue is - after wrapping it, if I call:
test(1, extra_param=2)
It fails on "test got unexpected param extra_param", although if the code would actually run, the decorator would handle this and call test func, without that param. If I get it correctly, the interpreter just fails it, before running the code and knowing it's defined with a decorator.
Is there any way to work around this? I would like the decorator to let me call the test function with more params, without defining them in the test function.
This works fine:
import functools
def decorator(func):
#functools.wraps(func)
def wrapper_decorator(*args, **kwargs):
kwargs.pop('extra_param')
value = func(*args, **kwargs)
return value
return wrapper_decorator
#decorator
def test(x):
return x
test(1, extra_param=2)

Why is this function decorator failing?

Here is my code:
name = "Arthur"
message = "Hello!"
def decorate(func_to_decorate):
def wrap(*args, **kwargs):
print ("........................")
func_to_decorate(*args, **kwargs)
print ("........................")
return wrap
#decorate
def send_message(your_name="unassigned", your_message="blank"):
print(your_name)
print(your_message)
send_message(name, message)
My error is in line 20:
send_message(name, message)
TypeError: 'NoneType' object is not callable
My understanding is that the wrapper is "replacing" itself with the function immediately following the decorator. This seems work when I am not passing arguments to the function being decorated, but not with the decorator present.
There are two things wrong with your decorator.
First, there's an indentation mistake:
def decorate(func_to_decorate):
def wrap(*args, **kwargs):
print ("........................")
func_to_decorate(*args, **kwargs)
print ("........................")
return wrap
That return wrap is part of the wrap function body, not part of the decorate function body. So, decorate has no return statement, which means it returns None. Hence the error you see: the decorator is in fact "replacing" the wrapped function with the wrapper it returns—but that wrapper is None, so you end up trying to call None as a function.
And meanwhile, you seem to understand that wrap should return something, but that something definitely shouldn't be itself. Usually, what you want to return is the result of the wrapped function (or some post-processed version of that result). In your test, you're only trying to wrap up a function that's used only for side-effects, not to mention that you never get to call the wrapper because of your first problem, so you wouldn't notice this problem yet, but you still want to fix it.
So:
def decorate(func_to_decorate):
def wrap(*args, **kwargs):
print ("........................")
retval = func_to_decorate(*args, **kwargs)
print ("........................")
return retval
return wrap

Wrapping a decorator, with arguments

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?
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.
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.

How can I get a Python decorator to run after the decorated function has completed?

I want to use a decorator to handle auditing of various functions (mainly Django view functions, but not exclusively). In order to do this I would like to be able to audit the function post-execution - i.e. the function runs as normal, and if it returns without an exception, then the decorator logs the fact.
Something like:
#audit_action(action='did something')
def do_something(*args, **kwargs):
if args[0] == 'foo':
return 'bar'
else:
return 'baz'
Where audit_action would only run after the function has completed.
Decorators usually return a wrapper function; just put your logic in the wrapper function after invoking the wrapped function.
def audit_action(action):
def decorator_func(func):
def wrapper_func(*args, **kwargs):
# Invoke the wrapped function first
retval = func(*args, **kwargs)
# Now do something here with retval and/or action
print('In wrapper_func, handling action {!r} after wrapped function returned {!r}'.format(action, retval))
return retval
return wrapper_func
return decorator_func
So audit_action(action='did something') is a decorator factory that returns a scoped decorator_func, which is used to decorate your do_something (do_something = decorator_func(do_something)).
After decorating, your do_something reference has been replaced by wrapper_func. Calling wrapper_func() causes the original do_something() to be called, and then your code in the wrapper func can do things.
The above code, combined with your example function, gives the following output:
>>> do_something('foo')
In wrapper_func, handling action 'did something' after wrapped function returned 'bar'
'bar'
Your decorator can handle it here itself, like
def audit_action(function_to_decorate):
def wrapper(*args, **kw):
# Calling your function
output = function_to_decorate(*args, **kw)
# Below this line you can do post processing
print "In Post Processing...."
return output
return wrapper

allow users to "extend" API functions

I'm writing a modding API for my game and I want to allow users to tell the game engine to run their mod's function immediately before or after one of the API functions, in other words to "extend" the functions.
Before now modders had to rewrite the function to add functionality to it which meant digging in the game's sourcecode, which I think sucks for them.
Right now I'm thinking of something like this:
def moddersFunction():
pass
myAPI.extendFunction('functionName', 'before-or-after', moddersFunction, extraArgs=[])
Now what will be comparably clean way to implement this?
In other words, what would the internals of myAPI.extendFunction look like if you were to write it?
I'm thinking of having a dictionary which myAPI.extendFunction will add functions to and the functions in my API will check and run the mod's function if it has been set ("registered").
But this means adding the code which checks the dictionary in every single function in my modding API which I want to allow to be extended (even if it's just a single function call which does the check and function calling itself, it seems to much itself).
I'm wondering if there's some neat Python trick which will allow such "extending" of functions without "butchering" (maybe I'm exaggerating) the existing sourcecode of my game's API.
I would do something along the following lines:
class hookable(object):
def __init__(self, fn):
self.pre = []
self.post = []
self.fn = fn
def add_pre(self, hook):
self.pre.append(hook)
def add_post(self, hook):
self.post.append(hook)
def __call__(self, *args, **kwargs):
for hook in self.pre:
hook(*args, **kwargs)
ret = self.fn(*args, **kwargs)
for hook in self.post:
hook(*args, **kwargs)
return ret
Any "extendable" function can now be decorated like so:
#hookable
def square(x):
return x**2
Now you can use square.add_pre() and square.add_post() to register functions that would automatically get called before and after each call to square():
print square(2)
def pre(x): print 'pre', x
def post(x): print 'post', x
square.add_pre(pre)
print square(2)
print square(3)
square.add_post(post)
print square(4)
print square(5)
I would probably do something like this. Obviously what you actually do is specific to your requirements.
class Extend(object):
def __init__(self, original_function):
self.original_function = original_function
def __call__(self, function):
def _wrapped(*args, **kwargs):
yield function(*args, **kwargs)
yield self.original_function(*args, **kwargs)
return _wrapped
import time
#Extend(time.asctime)
def funky_time():
return "This is the time in the UK"
print list(funky_time())

Categories