Detect if a method has been decorated before calling it

I wrote a Python flow control structure that is very similar to unittest.TestCase : the user creates a class derived from the framework class, and then writes the task_*(self) user methods. The frame detects them and launches them:

 ################### # FRAMEWORK LIBRARY ################### import functools class SkipTask(BaseException): pass def skip_if(condition): def decorator(task): @functools.wraps(task) def wrapper(self, *args, **kargs): if condition(self): raise SkipTask() return task(self, *args, **kargs) return wrapper return decorator class MyFramework(object): def run(self): print "Starting task" try: self.task() except SkipTask: print "Skipped task" except Exception: print "Failed task" raise else: print "Finished task" ############# # USER SCRIPT ############# class MyUserClass(MyFramework): skip_flag = True @skip_if(lambda self: self.skip_flag) def task(self): print "Doing something" if __name__ == '__main__': MyUserClass().run() 

Output:

 Starting task Skipped task 

I want to change the structure so that whenever the @skip_if condition is True , the shell does not print "Starting task" . I tried this, but it does not work:

 def skip_if(condition): def decorator(task): print "decorating " + str(task) task.__skip_condition = condition return task return decorator class MyFramework(object): def run(self): try: if self.task.__skip_condition(): print "Skipped task" return except AttributeError: print str(self.task) + " is not decorated" pass print "Starting task" try: self.task() except Exception as e: print "Failed task: " + str(e) raise else: print "Finished task" 

Output:

 decorating <function task at 0x194fcd70> <bound method MyUserClass.task of <__main__.MyUserClass object at 0x195010d0>> is not decorated Starting task Doing something Finished task 

Why was the task not missed?

+6
source share
1 answer

The run method uses the double underscore name that has undergone the private name .

When going through the debugger, I get:

 AttributeError: "'function' object has no attribute '_MyFramework__skip_condition 

Do not use double underscores here; if you rename the attribute of the function to _skip_condition , the code works (if you bind the function to the condition or pass it to self explicitly):

 def skip_if(condition): def decorator(task): print "decorating " + str(task) task._skip_condition = condition return task return decorator class MyFramework(object): def run(self): try: if self.task._skip_condition(self): print "Skipped task" return except AttributeError: print str(self.task) + " is not decorated" pass print "Starting task" try: self.task() except Exception as e: print "Failed task: " + str(e) raise else: print "Finished task" 

With these changes, the output will be:

 decorating <function task at 0x1071a1b90> Skipped task 
+6
source

Source: https://habr.com/ru/post/987035/


All Articles