$ cat tasks.py
from invoke import task
@task
def hi(ctx, name):
print("Hi {0}!".format(name))
$ invoke --help hi
Usage: inv[oke] [--core-opts] hi [--options] [other tasks here ...]
Docstring:
none
Options:
-n STRING, --name=STRING
$ invoke hi
'hi' did not receive all required positional arguments!
The auto-generated usage does not indicate that a positional argument is required. hi [--options] [other tasks here ...] seems to imply the opposite - that all arguments are optional.
In addition, we should be able to print the required positional arguments when we do not receive all of them.
Good catch, this feels like a bug to me. Thanks!
+1
To clarify, I think this change should both:
--help output re: positional arguments--help output in the situation causing us to complain about positional arguments, automatically (this comes up a lot actually.)I've posted a pull request for this issue at #504
I don't think the above commit fully fixes this bug. If you don't supply sufficient positional arguments, the help flag won't work properly, either. Here's an example:
If you have a task, something like this that was written by one of my coworkers, @ofek:
@task(help={
'package': 'The package to upgrade throughout the integrations',
'version': 'The version of the package to pin',
'verbose': 'Whether or not to produce output',
})
def upgrade(ctx, package, version, verbose=False):
"""
Do Something
"""
...
And you do not supply the positional arguments, the task will just fail:
❯❯❯ invoke upgrade -h
'upgrade' did not receive all required positional arguments!
If you put help before the task, it will print out normally:
❯❯❯ invoke -h upgrade
Usage: inv[oke] [--core-opts] upgrade [--options] [other tasks here ...]
Docstring:
Do Something
Options:
-e, --verbose Whether or not to produce output
-p STRING, --package=STRING The package to upgrade throughout the integrations
-v STRING, --version=STRING The version of the package to pin
May I ask is this one bug too? (i mean if there not have args, but there will raise error?)
code (invoke-0.22.1-py2.7.egg\invoke\tasks.py function: def argspec(self, body)):
...
print "+++arg_names", arg_names # add for debug
matched_args = [reversed(x) for x in [spec.args, spec.defaults or []]]
spec_dict = dict(zip_longest(*matched_args, fillvalue=NO_DEFAULT))
# Pop context argument
try:
context_arg = arg_names.pop(0)
except IndexError:
# TODO: see TODO under __call__, this should be same type
raise TypeError("Tasks must have an initial Context argument!")
del spec_dict[context_arg]
return arg_names, spec_dict
output:
E:\github\RIDE>inv --list
+++arg_names ['args']
+++context_arg args
+++arg_names ['test_filter']
+++context_arg test_filter
+++arg_names ['upgrade']
+++context_arg upgrade
+++arg_names []
Traceback (most recent call last):
File "C:\Python27\Scripts\inv-script.py", line 11, in
load_entry_point('invoke==0.22.1', 'console_scripts', 'inv')()
File "C:\Python27\lib\site-packages\invoke-0.22.1-py2.7.egg\invoke\program.py"
, line 282, in run
self.parse_collection()
File "C:\Python27\lib\site-packages\invoke-0.22.1-py2.7.egg\invoke\program.py"
, line 356, in parse_collection
self.load_collection()
File "C:\Python27\lib\site-packages\invoke-0.22.1-py2.7.egg\invoke\program.py"
, line 508, in load_collection
module, parent = loader.load(coll_name)
File "C:\Python27\lib\site-packages\invoke-0.22.1-py2.7.egg\invoke\loader.py",
line 69, in load
module = imp.load_module(name, fd, path, desc)
File "E:\github\RIDE\tasks.py", line 63, in
@task
File "C:\Python27\lib\site-packages\invoke-0.22.1-py2.7.egg\invoke\tasks.py",
line 292, in task
return Task(args[0], **kwargs)
File "C:\Python27\lib\site-packages\invoke-0.22.1-py2.7.egg\invoke\tasks.py",
line 63, in __init__
self.positional = self.fill_implicit_positionals(positional)
File "C:\Python27\lib\site-packages\invoke-0.22.1-py2.7.egg\invoke\tasks.py",
line 155, in fill_implicit_positionals
args, spec_dict = self.argspec(self.body)
File "C:\Python27\lib\site-packages\invoke-0.22.1-py2.7.egg\invoke\tasks.py",
line 149, in argspec
raise TypeError("Tasks must have an initial Context argument!")
TypeError: Tasks must have an initial Context argument!
Most helpful comment
I don't think the above commit fully fixes this bug. If you don't supply sufficient positional arguments, the help flag won't work properly, either. Here's an example:
If you have a task, something like this that was written by one of my coworkers, @ofek:
And you do not supply the positional arguments, the task will just fail:
If you put help before the task, it will print out normally: