Michael, thanks for responding to my question about,  "What is the best way
to implement Task subclass task-oriented logic: In Task.run() or in the
wrapped function?"

I believe that the fab task function decorators must be declared in
order,@task()first, with the remainder following.  Should
@runs_once precede @task() as follows, the following exception will occur:

@runs_once
@task(task_class=CustomTask, myarg='value', alias='ata')
def wrapped_custom_taska(instance):
    print("wrapped_custom_taska()")

  File "xxxxxx/local/lib/python2.7/site-packages/fabric/decorators.py",
line 136, in runs_once
    @wraps(func)
  File "/usr/lib/python2.7/functools.py", line 33, in update_wrapper
    setattr(wrapper, attr, getattr(wrapped, attr))
AttributeError: 'CustomTask' object has no attribute '__name__'

I believe this is expected behavior.

What is notable, is that if @task() does not have a task_class specified,
WrappedCallableTask is used.  When given the two fab task functions:

@task(task_class=CustomTask, myarg='value', alias='ata')
@runs_once
def wrapped_custom_taska(instance):
    print("wrapped_custom_taska()")

# WrappedCallableTask
@task()
@runs_once
def wrapped_custom_taskc():
    print("wrapped_custom_task()")

The following runs occur:

$ fab -f fab_busybox1.py -H a,b,c,d wrapped_custom_taskc
[a] Executing task 'wrapped_custom_taskc'
WrappedCallableTask run()
wrapped_custom_task()
WrappedCallableTask run()
WrappedCallableTask run()
WrappedCallableTask run()
Done.

$ fab -f fab_busybox1.py -H a,b,c,d wrapped_custom_taska
[a] Executing task 'wrapped_custom_taska'
<fab_busybox1.CustomTask object at 0x15cd2d0> run()
wrapped_custom_taska()
[b] Executing task 'wrapped_custom_taska'
<fab_busybox1.CustomTask object at 0x15cd2d0> run()
[c] Executing task 'wrapped_custom_taska'
<fab_busybox1.CustomTask object at 0x15cd2d0> run()
[d] Executing task 'wrapped_custom_taska'
<fab_busybox1.CustomTask object at 0x15cd2d0> run()
Done.

We might be closer to answering question with this example. It appears both
WrappedCallableTask and the Task subclass are run() for each host present
in the fab role being treated, though the @runs_once decorator is present.

So then a more articulate question may be, "How does a Task subclass know
the intentions of the decorators following its @task(task_class=)
declaration?"


On Mon, Dec 16, 2013 at 8:01 AM, Michael Gliwinski <
michael.gliwin...@henderson-group.com> wrote:

> On Sunday 15 Dec 2013 14:55:32 Rich Andrews wrote:
> ...
> > The desire is that a decorator such as @runs_once could then be stacked.
> >  But what happens in this case is that the customtask.run() is invoked
> for
> > each host specified in the role, and the wrapped function is what runs
> once.
>
> Off top of my head, this may have something to do with the order of
> decorators.  Have you tried ordering them differently?
>
_______________________________________________
Fab-user mailing list
Fab-user@nongnu.org
https://lists.nongnu.org/mailman/listinfo/fab-user

Reply via email to