Hook python module function

Hook python module function

Something like this? It avoids using globals, which is generally a good thing.

import whatever
import functools

def prefix_function(function, prefunction):
    @functools.wraps(function)
    def run(*args, **kwargs):
        prefunction(*args, **kwargs)
        return function(*args, **kwargs)
    return run

def this_is_a_function(parameter):
    pass # Your own code here that will be run before

whatever.this_is_a_function = prefix_function(
    whatever.this_is_a_function, this_is_a_function)

prefix_function is a function that takes two functions: function and prefunction. It returns a function that takes any parameters, and calls prefunction followed by function with the same parameters. The prefix_function function works for any callable, so you only need to program the prefixing code once for any other hooking you might need to do.

@functools.wraps makes it so that the docstring and name of the returned wrapper function is the same.

If you need this_is_a_function to call the old whatever.this_is_a_function with arguments different than what was passed to it, you could do something like this:

import whatever
import functools

def wrap_function(oldfunction, newfunction):
    @functools.wraps(function)
    def run(*args, **kwargs):
        return newfunction(oldfunction, *args, **kwargs)
    return run

def this_is_a_function(oldfunc, parameter):
    # Do some processing or something to customize the parameters to pass
    newparams = parameter * 2  # Example of a change to newparams
    return oldfunc(newparams)

whatever.this_is_a_function = wrap_function(
        whatever.this_is_a_function, this_is_a_function)

There is a problem that if whatever is a pure C module, its typically impossible (or very difficult) to change its internals in the first place.

This is the perfect time to tout my super-simplistic Hooker

def hook(hookfunc, oldfunc):
    def foo(*args, **kwargs):
        hookfunc(*args, **kwargs)
        return oldfunc(*args, **kwargs)
    return foo

Incredibly simple. It will return a function that first runs the desired hook function (with the same parameters, mind you) and will then run the original function that you are hooking and return that original value. This also works to overwrite a class method. Say we have static method in a class.

class Foo:
    @staticmethod
    def bar(data):
        for datum in data:
            print(datum, end=) # assuming python3 for this
        print()

But we want to print the length of the data before we print out its elements

def myNewFunction(data):
    print(The length is {}..format(len(data)))

And now we simple hook the function

Foo.bar([a, b, c])
# => a b c
Foo.bar = hook(Foo.bar, myNewFunction)
Foo.bar([x, y, z])
# => The length is 3.
# => x y z 

Hook python module function

So, heres an example of monkey-patching the time function from the time module.

import time

old_time = time.time

def time():
    print(It is today... but more specifically the time is:)
    return old_time()

time.time = time

print time.time()
# Output:
# It is today... but more specifically the time is:
# 1456954003.2

However, if you are trying to do this to C code, you will most likely get an error like cannot overwrite attribute. In that case, you probably want to subclass the C module.

You may want to take a look at this question.

Leave a Reply

Your email address will not be published. Required fields are marked *