【问题标题】:how to pass arguments to a python fabric custom task如何将参数传递给python结构自定义任务
【发布时间】:2014-03-03 16:46:32
【问题描述】:

我无法弄清楚如何将参数实际传递给结构自定义任务。

我有一堆任务都需要进行相同的设置,所以我希望将任务子类化并让基类进行设置,然后运行特定的子任务。设置代码和子任务都需要访问从命令行传递给任务的一些参数。我还需要能够为参数设置默认值。

最初的尝试

我最初的尝试显示了我在没有任何子类的情况下尝试做的事情。 此代码工作正常。 下面的代码在文件 tmp1.py 中:

from fabric.api import task

def do_setup(myarg):
    ''' common setup for all tasks '''
    print "in do_setup(myarg=%s)" % myarg
    # do setup using myarg for something important

@task
def actual_task1(myarg='default_value', alias='at'):
    print "In actual_task1(myarg=%s)" % myarg
    do_setup(myarg)
    # do rest of work ...

@task
def actual_task2(myarg='default_value', alias='at'):
    print "In actual_task2(myarg=%s)" % myarg
    do_setup(myarg)
    # do rest of work ...

我在没有任何参数的情况下从命令行运行它,并且正确地看到了 myarg 的默认值 'default_value'

fab -f ./tmp1.py actual_task1

打印:

In actual_task1(myarg=default_value)
in do_setup(myarg=default_value)
Done.

然后我用 myarg='hello' 调用它,看到 'hello' 被正确传递了

fab -f ./tmp1.py actual_task1:myarg='hello'

它输出:

In actual_task1(myarg=hello)
in do_setup(myarg=hello)
Done.

尝试自定义任务

我的下一个尝试是做一个通用任务来封装设置部分。 这是从http://docs.fabfile.org/en/1.5/usage/tasks.html复制的 下面的代码在文件 tmp2.py 中:

from fabric.api import task
from fabric.tasks import Task

def do_setup(myarg):
    ''' common setup for all tasks '''
    print "in do_setup(myarg=%s)" % myarg
    # do setup using myarg for something important

'''
Attempt to make a common task to encapsulate the setup part
copied from http://docs.fabfile.org/en/1.5/usage/tasks.html
'''
class CustomTask(Task):
    def init(self, func, myarg, args, *kwargs):
        super(CustomTask, self).init(args, *kwargs)
        print("=> init(myarg=%s, args=%s, kwargs=%s" % (myarg, args, kwargs))
        self.func = func
        self.myarg = myarg
        print "in init: self.func=",self.func,"self.myarg=",self.myarg

    def run(self, *args, **kwargs):
        return self.func(self.myarg, *args, **kwargs)

@task(task_class=CustomTask, myarg='default_value', alias='at')
def actual_task1():
    print "In actual_task1(myarg=%s)" % myarg
    # do rest of work ...

运行时有2个问题:

  1. __init__ 获取“default_value”而不是“Hello”

  2. 它抱怨 actual_task1() 需要 0 个参数

我是这样运行的:

fab -f ./tmp2.py actual_task1:myarg="Hello"

打印:

=> init(myarg=default_value, args=(), kwargs={'alias': 'at'}
in init: self.func= self.myarg= default_value
Traceback (most recent call last):
File "/home/xxx/Documents/pyenvs/xxx/local/lib/python2.7/site-packages/fabric/main.py", line 743,      in main args, *kwargs
File "/home/xxx/Documents/pyenvs/xxx/local/lib/python2.7/site-packages/fabric/tasks.py", line 405,  in execute results[''] = task.run(args, *new_kwargs)
File "/home/xxx/test_fab/tmp2.py", line 21, in run
return self.func(self.myarg, args, *kwargs)
TypeError: actual_task1() takes no arguments (1 given)

我花了很多时间试图完成这项工作,但我似乎无法解决 default_value 问题。我肯定错过了什么?

如果您能帮我弄清楚如何运行这个示例程序,我将不胜感激。具有自定义任务的第二个版本需要像我展示的原始版本一样运行。

感谢您对此问题的任何帮助。

【问题讨论】:

    标签: python task subclass fabric


    【解决方案1】:

    带有设置的固定示例:

    from fabric.api import task
    from fabric.tasks import Task
    
    def do_setup(foo, verbose):
        ''' common setup for all tasks '''
        print "IN do_setup(foo=%s, verbose=%s)" % (foo, verbose)
        # do setup using foo and verbose...
    
    class CustomTask(Task):
        def __init__(self, func, *args, **kwargs):
            ''' 
            The special args like hosts and roles do not show up in
            args, and kwargs, they are stripped already.
    
            args and kwargs may contain task specific special arguments
            (e.g. aliases, alias, default, and name) to customize the
            task. They are set in the @task decorator and cannot be passed
            on the command-line. Note also that these special task
            arguments are not passed to the run method.
    
            Non-special arguments (there are none in this example) are
            set in the task decorator. These other arguments are not
            passed to the run method and cannot be overridden from the
            command-line.
    
            Note that if you pass any "task specific special arguments" or
            "non-special arguments declared in the task decorator" from the
            command-line, they are treated as different arguments and the
            command-line values are passed to the run method but not to
            this method.
            '''
            super(CustomTask, self).__init__(*args, **kwargs)
            print "IN __init__(args=%s, kwargs=%s)" % (args, kwargs)
            self.func = func
    
        def run(self, foo='foo_default_val', verbose='verbose_default_val', 
                *args, **kwargs):
            ''' 
            The arguments to this method will be:
            1) arguments from the actual task (e.g. foo and verbose). This method
            is where you set a default value for the arguments from the
            actual_task, not on the actual_task.
            2) task specific arguments from the command-line
            (e.g. actual_task:bar='xxx'). This example is not expecting any,
            so it strips them and does not pass them to the
            actual_function one (e.g. it calls self.func with only foo
            and verbose and does not pass args and kwargs)
            '''
            print "IN run(foo=%s, verbose=%s, args=%s, kwargs=%s)" % \
                      (foo, verbose, args, kwargs)
            do_setup(foo, verbose)
            return self.func(foo, verbose)
    
    @task(task_class=CustomTask, alias="RUNME")
    def actual_task(foo, verbose):
        print 'IN task actual_task(foo=%s, verbose=%s)' % (foo, verbose)
    

    仅在命令行上指定主机运行:

    fab -f ./example_with_setup.py actual_task:host='hhh'
    
    IN __init__(args=(), kwargs={'alias': 'RUNME'})
    [hhh] Executing task 'actual_task'
    IN run(foo=foo_default_val, verbose=verbose_default_val, args=(), kwargs={})
    IN do_setup(foo=foo_default_val, verbose=verbose_default_val)
    IN task actual_task(foo=foo_default_val, verbose=verbose_default_val)
    

    在命令行上运行指定 foo:

    fab -f ./example_with_setup.py actual_task:host='hhh',foo='bar'
    
    IN __init__(args=(), kwargs={'alias': 'RUNME'})
    [hhh] Executing task 'actual_task'
    IN run(foo=bar, verbose=verbose_default_val, args=(), kwargs={})
    IN do_setup(foo=bar, verbose=verbose_default_val)
    IN task actual_task(foo=bar, verbose=verbose_default_val)
    

    在命令行上同时指定 foo 和 verbose:

    fab -f ./example_with_setup.py actual_task:host='hhh',foo='bar',verbose=True
    
    IN __init__(args=(), kwargs={'alias': 'RUNME'})
    [hhh] Executing task 'actual_task'
    IN run(foo=bar, verbose=True, args=(), kwargs={})
    IN do_setup(foo=bar, verbose=True)
    IN task actual_task(foo=bar, verbose=True)
    

    【讨论】:

      【解决方案2】:

      在自定义类部分,actual_task1 函数实际上不带参数,因此调用您的结构文件的唯一有效方法是:

      fab -f ./tmp2.py actual_task1
      

      此外,我认为您实际上并没有在CustomTaskactual_task1 中调用do_setup

      【讨论】:

      • 我相信我想通了。这是修改后的代码,其中包含大量 cmets,解释了它是如何工作的。让我知道是否有人认为它有任何问题,但它似乎很有意义并且现在可以使用。我会尝试发布新代码。
      【解决方案3】:

      这是固定示例。

      # fixed the example from http://docs.fabfile.org/en/1.8/usage/tasks.html
      from fabric.api import task
      from fabric.tasks import Task
      
      class CustomTask(Task):
          def __init__(self, func, myarg1, *args, **kwargs):
              ''' 
              The special args like hosts and roles do not show up in
              args, and kwargs, they are stripped already.
      
              args and kwargs may contain task specific special arguments
              (e.g. aliases, alias, default, and name) to customize the
              task. They are set in the @task decorator and cannot be passed
              on the command-line. Note also that these special task
              arguments are not passed to the run method.
      
              Non-special arguments (in this example myarg1) are set in the task
              decorator. These other arguments are not passed to the run
              method and cannot be overridden from the command-line. 
      
              Note that if you pass any "task specific special arguments" or
              "non-special arguments declared in the task decorator" from the
              command-line, they are treated as different arguments and the
              command-line values are passed to the run method but not to
              this method.
              '''
              super(CustomTask, self).__init__(*args, **kwargs)
              print "IN __init__(myarg1=%s, args=%s, kwargs=%s)" % \
                  (myarg1, args, kwargs)
              self.func = func
              self.myarg1 = myarg1
      
          def run(self, myarg2='default_value2', *args, **kwargs):
              ''' 
              The arguments to this method will be:
              1) arguments from the actual task (e.g. myarg2). This method
              is where you set a default value for the arguments from the
              actual_task, not on the actual_task.
              2) task specific arguments from the command-line
              (e.g. actual_host:foo='foo'). This example is not expecting
              any, so it strips them and does not pass them to the
              actual_function (e.g. it calls self.func with only myarg2 and
              does not pass args and kwargs)
              '''
              print "IN run(myarg2=%s, args=%s, kwargs=%s)" % \
                  (myarg2, args, kwargs)
              return self.func(myarg2)
      
      @task(task_class=CustomTask, myarg1='special_value', alias='RUNME')
      def actual_task(myarg2):
          print "IN actual_task(myarg2=%s)" % myarg2
      

      仅使用命令行中指定的主机运行:

      fab -f ./fixed_example actual_task:hosts="hhh"
      
      IN __init__(myarg1=special_value, args=(), kwargs={'alias': 'RUNME'})
      [hhh] Executing task 'actual_task'
      IN run(myarg2=default_value2, args=(), kwargs={})
      IN actual_task(myarg2=default_value2)
      

      在命令行上运行指定 myarg2:

      fab -f ./fixed_example actual_task:hosts="hhh",myarg2="good_value"
      
      IN __init__(myarg1=special_value, args=(), kwargs={'alias': 'RUNME'})
      [hhh] Executing task 'actual_task'
      IN run(myarg2=good_value, args=(), kwargs={})
      IN actual_task(myarg2=good_value)
      

      在命令行上指定 myarg1 和别名时运行错误。请注意,init 获取任务装饰器中指定的值,而不是命令行中的值。请注意,run 现在将 myarg1 和 alias 作为参数。

      fab -f ./fixed_example actual_task:hosts="hhh",myarg1="myarg1_from_commandline",alias="alias_from_commandline"
      
      IN __init__(myarg1=special_value, args=(), kwargs={'alias': 'RUNME'})
      [hhh] Executing task 'actual_task'
      IN run(myarg2=default_value2, args=(), kwargs={'alias': 'alias_from_commandline', 'myarg1': 'myarg1_from_commandline'})
      IN actual_task(myarg2=default_value2)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-14
        • 2021-03-31
        • 1970-01-01
        • 2019-07-08
        • 1970-01-01
        • 2021-08-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多