How do I stop the execution of a function line by line?

I find it difficult to discuss the issue, so I will describe what I am trying to do:

I am writing a test solution for a specific product, say a microwave oven. The goal is to measure all kinds of resources while the microwave is in use. For this, I wrote a context manager named measure()


Using the microwave API, I wrote a function that mimics the basic microwave use case and decorated it with a function that takes all measurements:

def test_function(fn):
    def wrapper(*args, **kwargs):
        with measure():
            fn(*args, **kwargs)

    return wrapper

def prepare_food():
    microwave = Microwave()
    microwave.turn_on(seconds = 60)



Of course, the microwave is just one example, and I have many of these "microwaves".

After a few days of testing and evaluating, my team decided that they wanted to measure each action separately, meaning my test function would now look like this:

def test_prepare_food():
    microwave = Microwave()
    actions = {
            microwave.open_door : [],
            microwave.insert_food : [],
            microwave.close_door() : [],
            microwave.turn_on : [60]
    for (action, args) in actions.items():
            with measure():


The problem with the new one test_prepare_food

is now for each function prepare_food

I need to add one more function test_*

(and I have many).

I'm looking for an elegant way to keep my function the prepare_food

same and wrap it in another function so that I still get the same functionality as in test_prepare_food


Edit: The goal is a solution that is implementation agnostic prepare_food()

, so changing to prepare_food()

does not require additional changes. In addition, the decision should not affect methods that are not used prepare_food


In other words, I would like to be able to "step in" prepare_food

and be able to execute code before and after each line. This is similar to what was done during debugging, but I couldn't find anything like it.

Any ideas?



source to share

1 answer

You can decorate each method of an instance of the Microwave class with a method measure

. This can be accomplished with a class decorator in the microwave class. In this example, I am simply modifying the Microwave class using the. The methods that do the work are wrap

and wrap_method


import inspect

class measure(object):
    def __enter__(self):
        print "Enter measure."
    def __exit__(self, *args):
        print "Exit measure."

class Microwave(object):
    def f(self, x):
        print "f: %s" % x
    def g(self, x):
        print "g: %s" % x

def wrap_method(method):
    def wrapper(*args, **kwargs):
        with measure():
            method(*args, **kwargs)
    return wrapper

def wrap(cls):
    for name, method in inspect.getmembers(cls, predicate=inspect.ismethod):
        setattr(cls, name, wrap_method(method))

m = Microwave()



Enter measure.
f: 1
Exit measure.
Enter measure.
g: 2
Exit measure.




All Articles