如何动态注册Fabric功能?

时间:2017-11-28 16:35:50

标签: python python-3.6 fabric

问题

我正在试图弄清楚如何动态包装我的一些结构功能,为了创建一个小的mcve片段:

mcve_lib.py:

from fabric.api import run


def foo():
    run('hostname')

fabfile.py:

import sys
import mcve_lib

from fabric.api import settings, task, env, roles

env.roledefs = {
    'servers': ['foo_server']
}


def register_function(name, module, wrapped_func):

    @roles(['servers'])
    @task()
    def callback():
        with settings():
            getattr(module, wrapped_func)()

    setattr(sys.modules[__name__], name, callback)


register_function("wrapped_foo", mcve_lib, "foo")

print(dir())

当我尝试通过执行fab -l列出可用的结构任务时出现问题,输出将是:

(py362_32) D:\sources\personal\python\framework\pyfab>fab -l
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'env', 'mcve_lib', 'register_function', 'roles', 'settings', 'sys', 'task', 'wrapped_foo']
Available commands:

    callback

问题

知道如何正确指出wrapped_foo是一项结构任务吗?

失败的原因

Attempt1:

from fabric.tasks import WrappedCallableTask

...

def register_function(name, module, wrapped_func):

    @roles(['servers'])
    def callback():
        with settings():
            getattr(module, wrapped_func)()

    setattr(sys.modules[__name__], name, WrappedCallableTask(callback))

...

1 个答案:

答案 0 :(得分:0)

解决此问题的一种可能方法是使用functools.wraps,下面的用法示例:

import mcve_lib
import sys

from fabric.api import settings, task, env, roles
from functools import wraps

env.roledefs = {
    'servers': ['foo_server']
}


def register_function(f):

    @roles(['servers'])
    @task
    @wraps(f)
    def callback():
        with settings():
            f()

    return callback


module_funcs = [
    ('foo', mcve_lib.foo)
]

for dst_func, src_func in module_funcs:
    setattr(sys.modules[__name__], dst_func, register_function(src_func))

通过使用上面的代码,结构将能够正确枚举包装函数,即:

(py362_32) D:\sources\personal\python\framework\pyfab>fab -l
Available commands:

    foo