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
@test_function
def prepare_food():
microwave = Microwave()
microwave.open_door()
microwave.insert_food()
microwave.close_door()
microwave.turn_on(seconds = 60)
prepare_food()
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():
action(*args)
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?
Thank!
source to share
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))
wrap(Microwave)
m = Microwave()
m.f(1)
m.g(2)
Output:
Enter measure.
f: 1
Exit measure.
Enter measure.
g: 2
Exit measure.
source to share