2015-05-12 4 views
6

Я написал структуру управления потоком Python, которая работает очень точно так же, как и unittest.TestCase: пользователь создает класс, производный от класса framework, а затем записывает настраиваемые методы task_*(self). Структура обнаруживает их и управляет ими:Обнаруживать, если метод декорирован перед его вызовом

################### 
# 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() 

Выход:

Starting task 
Skipped task 

Я хочу, чтобы изменить структуру так, что всякий раз, когда условие @skip_if является True, оболочка не печатает "Starting task". Я попытался это, но он не работает:

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" 

Выход:

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

Почему не задача пропускаются вместо этого?

+0

Не могли бы вы быть более конкретным чем * «это не работает» * - что вы ожидали? – jonrsharpe

+0

@jonrsharpe: выход должен указывать, что тест пропущен; вместо этого он запускается. –

ответ

6

Вы используете двойное имя подчеркивание, который подвергся private name mangling в методе run.

При пошаговом через отладчик, я получаю:

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

Не используйте двойное подчеркивание имен здесь; если переименовать атрибут функции в _skip_condition код работает (при условии, вы связываете функцию условие или передать в self явно):

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" 

С учетом этих изменений на выходе становится:

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

Спасибо! Работает как шарм – crusaderky

Смежные вопросы