Уведомления окончаний fabric задач, с декораторами и детальной информацией

В существующем проекте есть долгоиграющие fab-задачки — получения дампов с удаленных серверов, агрегация данных, етс. Запускаешь задачу, отвлекаешься в соседнее окошко, через N минут(а то и через час) вспоминаешь, проверяешь… неэффективно.
Захотелось сделать всплывающие уведомления на десктоп по завершении задачи, а тут и статья про notify-send подвернулась. Решил сделать декоратор на fab-функции — самое ему место.

Для начала пишем простую функцию уведомления

from django.conf import settings as django_settings from fabric.operations import local  def _notify(message):     if django_settings.FAB_NOTIFY_TASK_ENDS:         local(u'notify-send --expire-time=10000 "Fabric notify" "{}"'.format(message)) 

Да, у меня джанга и настройку «показывать ли подсказки» вынеcем в настройки.

Использование _notify тоже простое:

from fab_utils import _notify  def mongo_get_from_remote(server='', date='', collection=''):     u"""Загрузить базы монго c удаленного сервера"""     ...     _notify(u"Базы загружены") 

Но в каждой функции писать вызов в конце… как-то не «сухо» (DRY рулит). Напишем декоратор

def notified(wrapped):     def internal(*args, **kwargs):         res = wrapped(*args, **kwargs)         params = [unicode(a) for a in args]         params.extend([u'{}={}'.format(k, v) for k, v in kwargs.iteritems()])         params = [_limit_str(p) for p in params]         message = "{}({}) ended!!!".format(wrapped.__name__, ', '.join(params))         _notify(message)         return res     return internal 

И тогда использование такое

from fab_utils import notified  @notified def mongo_get_from_remote(server='', date='', collection=''):     u"""Загрузить базы монго c удаленного сервера"""     ... 

Все бы хорошо, но перестала выводится справка по команде 🙁

wad@wad-vaio:~/aggregator (develop)$ bin/fab.sh -d mongo_get_from_remote Displaying detailed information for task 'mongo_get_from_remote':      No docstring provided     Arguments: 

Что же делать? надо переопределить докстринг!

def notified(wrapped):     def internal(*args, **kwargs):         ...         return res     internal.__doc__ = wrapped.__doc__     return internal 

wad@wad-vaio:~/aggregator (develop!)$ bin/fab.sh -d mongo_get_from_remote Displaying detailed information for task 'mongo_get_from_remote':      Загрузить базы монго c удаленного сервера server='', date='', collection=''     Arguments: 

Уже лучше, но где же аргументы? За ними пришлось лезть в кишочки fabric — как он их определяет?

В файле env/local/lib/python2.7/site-packages/fabric/main.py:466 нашлось

def display_command(name):     """     Print command function's docstring, then exit. Invoked with -d/--display.     """     ...     if hasattr(command, '__details__'):         task_details = command.__details__()     else:         task_details = get_task_details(command)     ... 

Ага, если у функции есть __details__ то он вызовется для определения аргументов. Отлично!

Итоговый код декоратора таков

from fabric.tasks import get_task_details  def notified(wrapped):      def internal(*args, **kwargs):         res = wrapped(*args, **kwargs)         params = [unicode(a) for a in args]         params.extend([u'{}={}'.format(k, v) for k, v in kwargs.iteritems()])         params = [_limit_str(p) for p in params]         message = "{}({}) ended!!!".format(wrapped.__name__, ', '.join(params))         _notify(message)         return res      def _details():         return get_task_details(wrapped)      internal.__doc__ = wrapped.__doc__     internal.__details__ = _details     return internal  

И описание fab-задачки на месте

wad@wad-vaio:~/aggregator (develop!)$ bin/fab.sh -d mongo_get_from_remote Displaying detailed information for task 'mongo_get_from_remote':      Загрузить базы монго c удаленного сервера server='', date='', collection=''     Arguments: server='', date='', collection=''  

Люблю python 🙂

ссылка на оригинал статьи http://habrahabr.ru/post/214259/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *