Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Positional arguments not described in help #449

Open
cyounkins opened this issue May 30, 2017 · 8 comments
Open

Positional arguments not described in help #449

cyounkins opened this issue May 30, 2017 · 8 comments

Comments

@cyounkins
Copy link

$ 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.

@bitprophet
Copy link
Member

Good catch, this feels like a bug to me. Thanks!

@dmulter
Copy link

dmulter commented Jul 10, 2017

+1

@bitprophet
Copy link
Member

To clarify, I think this change should both:

  • add more info to --help output re: positional arguments
  • display --help output in the situation causing us to complain about positional arguments, automatically (this comes up a lot actually.)

riverfr0zen added a commit to riverfr0zen/invoke that referenced this issue Feb 7, 2018
@riverfr0zen
Copy link

I've posted a pull request for this issue at #504

bitprophet added a commit that referenced this issue Feb 20, 2018
@gmmeyer
Copy link

gmmeyer commented Mar 17, 2018

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

@dongfengdejia
Copy link

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!

@jungerm2
Copy link

Sorry in advance, I know this is an old issue, but this behavior seems to persist even today. Any updates on this?

@jungerm2
Copy link

jungerm2 commented Jul 3, 2023

This is, in my view, a key issue that likely limits wider invoke adoption: It doesn't make it clear to the user what arguments are required.

I have some time on my hands and could look at this closer, what would you recommend we start with @bitprophet? While I do use invoke a lot, I'm not too familiar with its internals. It seems some work has been done on this by @riverfr0zen, but it only raises an error when the user forgets an argument, it doesn't modify the help message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants