Уведомления окончаний 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 удаленного сервера
        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 удаленного сервера
        Arguments: server='', date='', collection=''
    
    


    Люблю python :)
    • +15
    • 3,8k
    • 8
    Поделиться публикацией
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 8

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

    Самое читаемое