Захотелось сделать всплывающие уведомления на десктоп по завершении задачи, а тут и статья про 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/