The @task decorator doesn't appear to play nicely with other decorators, unlike Fabric. I may not have read this part of the documentation yet, but I wouldn't expect @task to undermine python norms.
For example:
def capture_error(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
try:
return fn(*args, **kwargs)
except AssertionError as err:
print(err)
return wrapper
@task
@capture_error
def foo(c):
print('bar')
raise AssertionError('baz')
this looks fine:
inv foo
>>> bar
>>> baz
but when I add a parameter:
@task
@capture_error
def foo(c, p1):
print(p1)
raise AssertionError('baz')
I get:
inv foo bar
>>> No idea what 'bar' is!
The parameter handling docs offer no insight into what the problem is.
This is likely an oversight / lack of porting those extra careful parts of Fabric 1's decorator. #246 seems related and may fix it (though it's now kinda old so may need a revisit). Gonna leave this open and in a milestone since it's a regression (which is arguably worse than features which just aren't ported yet). Thanks!
hey, thanks for your attention on this. I've been using Fabric for so many years now I'm trialing Invoke on a personal project to unblock some work projects that need the Python3 upgrade as it doesn't look like Fabric will get there, which is frustrating, but I do appreciate your efforts and those of the other contributors.
@lsh-0 FWIW, Fabric 2 is technically out now (though it needs a few more feature releases to get up to par with 1.x) and supports Python 3. But it's also built heavily on top of Invoke so working with plain Invoke is a fine place to start; can always use fabric 2's API directly or switch later.
For future reference, I found a workaround:
def decorator(fn):
@functools.wraps(fn)
def _decorated(ctx, *args, **kwargs):
return fn(ctx, *args, **kwargs)
return _decorated
@invoke.task
def some_task(ctx, config="Something"):
@decorator
def _inner(ctx):
print(config)
...
return _inner(ctx)
This allows invoke.task to find the task and inspect the args
After finding your answer on stackoverflow I also found it here!
I was able to solve my problem by using the @functools.wraps decorator as well :
def ask(task_to_execute):
"""Decorator to ask if the user really wants to perform a task.
"""
def wrapper(*args, **kwargs):
y = ["y", "yes", "o", "oui", "Yes", "Oui", "go"]
if input("Do you want to execute " + task_to_execute.__name__ + "? [y/d/N] ") in y:
task_to_execute(*args, **kwargs)
return wrapper
from functools import wraps
def ask(task_to_execute):
"""Decorator to ask if the user really wants to perform a task.
"""
@wraps(task_to_execute)
def wrapped_wrapper(*args, **kwargs):
y = ["y", "yes", "o", "oui", "Yes", "Oui", "go"]
if input("Do you want to execute " + task_to_execute.__name__ + "? [y/d/N] ") in y:
task_to_execute(*args, **kwargs)
return wrapped_wrapper
And so tab-completion works again :)