You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
argparse claims '*' positional argument is required in error output #72795
In Python 3.5.2, with a positional argument with nargs='*', running the program with no arguments gives an error like this:
usage: caffeinate [-h] [-V] COMMAND [ARGUMENT [ARGUMENT ...]]
caffeinate: error: the following arguments are required: COMMAND, ARGUMENT
Here it is clear from the (correct, though redundant) syntax that "ARGUMENT" is optional, but the error message claims, incorrectly, that it is required.
The add_argument calls used were:
parser.add_argument('COMMAND', help='command to run')
parser.add_argument('ARGUMENT', nargs='*', help='arguments to COMMAND')
parser.add_argument('-V', '--version', action='version', version=PROGRAM_NAME+' '+VERSION)
Uploading one possible solution. I'm sure someone more familiar with the library might have a better approach...
rrt commented on Nov 4, 2016
rrtmannequin
MannequinAuthor
More actions
Thanks very much for this. It would be great if the redundancy I referred to in the usage message could also be removed, so that instead of "[ARGUMENT [ARGUMENT ...]]" it just said "[ARGUMENT ...]".
The 2nd patch reworked the test to include the revised handling of defaults.
So the current error message just lists all the positionals which haven't been consumed. ARGUMENT wasn't consumed because COMMAND wasn't consumed. And technically that would be true even if ARGUMENT required arguments. Well, to be pickier, it as a 're' pattern like 'AA*' that failed.
The proposed patch looks like it would work, but I haven't tested or looked at the unittests. But I wonder if such a patch is really needed. Are users really misled by the the current message?
===============
As for the usage, the current version allows you to give a tuple METAVAR, producing lines like:
In [359]: a.metavar=('A','B')
In [360]: parser.print_usage()
usage: ipython3 [-h] [A [B ...]]
In [361]: a.nargs='+'
In [362]: parser.print_usage()
usage: ipython3 [-h] A [B ...]
This display pattern is generated in HelpFormater._format_args, with these lines
elif action.nargs == ZERO_OR_MORE:
result = '[%s [%s ...]]' % get_metavar(2)
elif action.nargs == ONE_OR_MORE:
result = '%s [%s ...]' % get_metavar(2)
elif action.nargs == REMAINDER:
result = '...'
You could subclass HelpFormatter, and replace this method with one that performs as you want, (I just tried this)
result = '[%s ...]' % get_metavar(1)
I wouldn't recommend this as default change, but if there was a enough demand it could added as another HelpFormatter subclass.
METAVAR lets me approximate your shorter version:
In [4]: p.print_usage()
usage: ipython3 [-h] [pos [pos ...]]
In [5]: a.metavar=('pos','')
In [6]: p.print_usage()
usage: ipython3 [-h] [pos [...]]
In [7]: a.nargs='+'
In [8]: p.print_usage()
usage: ipython3 [-h] pos [...]
It still has the [], but the name is gone.
paulj3 commented on Nov 6, 2016
paulj3mannequin
Mannequin
More actions
Try nargs='?' or try providing a default along with the '*'.
Including your ARGUMENT action in the error message is intentional.
Originally the code just checked if positionals was empty. That was the list of positional Actions. Actions were popped as they were parsed. Now it maintains a set seen_actions, and checks the required attribute. This test applies to both positionals and optionals.
For optionals, required is set by the programmer. But for positionals it is set with:
def _get_positional_kwargs
...
# mark positional arguments as required if at least one is
# always required
if kwargs.get('nargs') not in [OPTIONAL, ZERO_OR_MORE]:
kwargs['required'] = True
if kwargs.get('nargs') == ZERO_OR_MORE and 'default' not in kwargs:
kwargs['required'] = True
So for '?' argument, required is False. But for '*', it must also have a 'default' parameter (not just the default None).
So the proposed patch is overriding the 'required' value that was set during 'add_argument'. And issuing this error message is the main purpose of the 'required' attribute.
I would not implement this patch.
But it would be a good idea to check if this method of setting the required attribute has been discussed in other bug/issues. (There is an open issue concerning how the 'required' is set/or not for the subparsers positional.)
Off hand I don't see anything about this in the documentation. Maybe that's what needs to be patched. (It's easier and safer to change the documentation than the working code. Backward compatibility is a major concern when changing the code.)
rrt commented on Nov 6, 2016
rrtmannequin
MannequinAuthor
More actions
Try nargs='?' or try providing a default along with the '*'.
Why would I do that? I want 0 or more arguments, and there's no default value.
Including your ARGUMENT action in the error message is intentional.
It will likely confuse the user. The syntax message says that it's optional, the error suggests (wrongly) that it is required.
Patching the Python documentation will not help in this case, because the user of my program will not be reading the Python documentation to understand how it works, only the program's own documentation.
Note that I did not suggest that the behavior be changed, only the message that is output.
The analysis of why the message is output is useful, but it does not demonstrate that the error message is correct; the error message, as I've already demonstrated, is undeniably wrong. In no sense is "ARGUMENT" missing, because 0 occurrences are entirely legal. Therefore although in terms of the API the argument is "required", it makes no sense to tell the user this (the user will assume that "required" has its colloquial sense, not a technical sense).
I entirely sympathise with the argument that the behavior of argparse should not change; I see nothing wrong with the behavior, in any case.
The problems are purely cosmetic:
The syntax message says, redundantly and confusingly, "[ARGUMENT [ARGUMENT ...]]" where it should say just "[ARGUMENT ...]".
The error message says that ARGUMENT is "required", whereas, from the user's point of view, it clearly is not.
These are serious annoyances from the developer's point of view (in this case, from my point of view), because they mean that in order to release a production-quality tool, I have to hack around argparse's shortcomings.
So in fact, you're quite right that the documentation should be fixed; only in this case it is the documentation generated by argparse, not the documentation of argparse (which, again, is fine as far as I can see).
paulj3 commented on Nov 7, 2016
paulj3mannequin
Mannequin
More actions
Simply including a default parameter, even with the default default None, changes the error message
In [395]: parser=argparse.ArgumentParser()
In [396]: parser.add_argument('cmd');
In [397]: a=parser.add_argument('args',nargs='*',default=None)
In [398]: a.required
Out[398]: False
In [399]: parser.parse_args([])
usage: ipython3 [-h] cmd [args [args ...]]
ipython3: error: the following arguments are required: cmd
You shouldn't see any other changes in behavior (except maybe if the positional is in a mutually_exclusive_group). The code that sets 'required' for positionals only looks for the presence of the parameter in kwargs, not its value: 'default' not in kwargs.
An alternative is to change the value of 'required' after creation:
a.required = False
Anyways I remain convinced that changing the 'required' attribute is the correct way to change the error message, not adding more tests to the message generator.
paulj3 commented on Nov 7, 2016
paulj3mannequin
Mannequin
More actions
My suggestion to use metavar=('A','') to streamline the usage creates problems with the help code
The tuple metavar does not work right for positionals. That's a old issue that should have been fixed long ago.
So streamlining the usage has to be done with a custom HelpFormatter subclass.
rrt commented on Nov 7, 2016
rrtmannequin
MannequinAuthor
More actions
Thanks, that's a simple, robust workaround.
I'll duck out now and leave the Python experts to sort out the underlying problem, if they can; I think it's still well worth sorting out, though documenting the problem and workaround would be much better than nothing.
benhoyt commented on Feb 27, 2017
benhoytmannequin
Mannequin
More actions
I definitely agree with Reuben here -- I just ran into this issue while creating a "production quality" tool, and the help message produced by argparse with nargs='*' confused me too. It's pretty clear that this is a simple bug in argparse's production of that usage message: it says ARGUMENT is required, but it isn't.
However, the workaround of specifying an (unused) default is a reasonable workaround in the meantime -- thanks Paul.
svenevs commented on May 27, 2019
svenevsmannequin
Mannequin
More actions
For optionals, required is set by the programmer. But for positionals it is set with: ...
So for '?' argument, required is False. But for '*', it must also have a 'default' parameter (not just the default None).
So the proposed patch is overriding the 'required' value that was set during 'add_argument'. And issuing this error message is the main purpose of the 'required' attribute.
nargs='*' being marked as required is incorrect though, isn't it?
I was also very confused by this behavior, the only reason I found this bug was to search before opening new, and had a patch prepared that is nearly identical to the one here.
It's really helpful to know about explicitly setting default=None|[] depending on use case. Would a docs PR briefly explaining at the bottom of the nargs [a] docs explaining how to change the error message via default be welcome? This is a slightly challenging problem to search for.
My understanding is the ultimate rejection of the patch is because it's bypassing the required attribute. So to fix this adequately, changing ? and * to not show up as required (when no default provided) should be done?
I agree that the current error message that requires an argument with nargs='*' is misleading.
It is even worse for nargs=REMAINDER, because it refers to argument name not mentioned in the "usage" line:
fromargparseimport*parser=ArgumentParser()
parser.add_argument('COMMAND', help='command to run')
parser.add_argument('ARGUMENT', nargs=REMAINDER, help='arguments to COMMAND')
parser.parse_args([])
Output:
usage: [-h] COMMAND ...
: error: the following arguments are required: COMMAND, ARGUMENT
I think that it is an error to mark such positional arguments as required.
I guess that the reason of marking nargs='*' without default as required lies in the way how conflicts in mutually exclusive groups were detected. The code simply checked if the value is the same as the default value, and this obviously does not work for []. Fixing this code allows to make all positional arguments with nargs='*' non-required.
As for nargs=REMAINDER, I think it was just an omission.
Activity
rrt commentedon Nov 4, 2016
In Python 3.5.2, with a positional argument with nargs='*', running the program with no arguments gives an error like this:
usage: caffeinate [-h] [-V] COMMAND [ARGUMENT [ARGUMENT ...]]
caffeinate: error: the following arguments are required: COMMAND, ARGUMENT
Here it is clear from the (correct, though redundant) syntax that "ARGUMENT" is optional, but the error message claims, incorrectly, that it is required.
The add_argument calls used were:
charlierproctor commentedon Nov 4, 2016
I agree that the message is slightly misleading.
Uploading one possible solution. I'm sure someone more familiar with the library might have a better approach...
rrt commentedon Nov 4, 2016
Thanks very much for this. It would be great if the redundancy I referred to in the usage message could also be removed, so that instead of "[ARGUMENT [ARGUMENT ...]]" it just said "[ARGUMENT ...]".
(Similarly, for a '+' argument, it could say just
ARGUMENT ...
)
paulj3 commentedon Nov 6, 2016
The current error message is the result of http://bugs.python.org/issue10424 and http://bugs.python.org/issue12776
Before the test was just:
The 2nd patch reworked the test to include the revised handling of defaults.
So the current error message just lists all the positionals which haven't been consumed. ARGUMENT wasn't consumed because COMMAND wasn't consumed. And technically that would be true even if ARGUMENT required arguments. Well, to be pickier, it as a 're' pattern like 'AA*' that failed.
The proposed patch looks like it would work, but I haven't tested or looked at the unittests. But I wonder if such a patch is really needed. Are users really misled by the the current message?
===============
As for the usage, the current version allows you to give a tuple METAVAR, producing lines like:
This display pattern is generated in HelpFormater._format_args, with these lines
You could subclass HelpFormatter, and replace this method with one that performs as you want, (I just tried this)
I wouldn't recommend this as default change, but if there was a enough demand it could added as another HelpFormatter subclass.
METAVAR lets me approximate your shorter version:
It still has the [], but the name is gone.
paulj3 commentedon Nov 6, 2016
Try
nargs='?'or try providing adefaultalong with the '*'.Including your ARGUMENT action in the error message is intentional.
The test for this error message is:
Originally the code just checked if
positionalswas empty. That was the list of positional Actions. Actions were popped as they were parsed. Now it maintains a setseen_actions, and checks therequiredattribute. This test applies to both positionals and optionals.For optionals,
requiredis set by the programmer. But for positionals it is set with:So for '?' argument, required is False. But for '*', it must also have a 'default' parameter (not just the default None).
So the proposed patch is overriding the 'required' value that was set during 'add_argument'. And issuing this error message is the main purpose of the 'required' attribute.
I would not implement this patch.
But it would be a good idea to check if this method of setting the required attribute has been discussed in other bug/issues. (There is an open issue concerning how the 'required' is set/or not for the subparsers positional.)
Off hand I don't see anything about this in the documentation. Maybe that's what needs to be patched. (It's easier and safer to change the documentation than the working code. Backward compatibility is a major concern when changing the code.)
rrt commentedon Nov 6, 2016
Why would I do that? I want 0 or more arguments, and there's no default value.
It will likely confuse the user. The syntax message says that it's optional, the error suggests (wrongly) that it is required.
Patching the Python documentation will not help in this case, because the user of my program will not be reading the Python documentation to understand how it works, only the program's own documentation.
Note that I did not suggest that the behavior be changed, only the message that is output.
The analysis of why the message is output is useful, but it does not demonstrate that the error message is correct; the error message, as I've already demonstrated, is undeniably wrong. In no sense is "ARGUMENT" missing, because 0 occurrences are entirely legal. Therefore although in terms of the API the argument is "required", it makes no sense to tell the user this (the user will assume that "required" has its colloquial sense, not a technical sense).
I entirely sympathise with the argument that the behavior of argparse should not change; I see nothing wrong with the behavior, in any case.
The problems are purely cosmetic:
The syntax message says, redundantly and confusingly, "[ARGUMENT [ARGUMENT ...]]" where it should say just "[ARGUMENT ...]".
The error message says that ARGUMENT is "required", whereas, from the user's point of view, it clearly is not.
These are serious annoyances from the developer's point of view (in this case, from my point of view), because they mean that in order to release a production-quality tool, I have to hack around argparse's shortcomings.
So in fact, you're quite right that the documentation should be fixed; only in this case it is the documentation generated by argparse, not the documentation of argparse (which, again, is fine as far as I can see).
paulj3 commentedon Nov 7, 2016
Simply including a
defaultparameter, even with the default default None, changes the error messageYou shouldn't see any other changes in behavior (except maybe if the positional is in a mutually_exclusive_group). The code that sets 'required' for positionals only looks for the presence of the parameter in kwargs, not its value:
'default' not in kwargs.An alternative is to change the value of 'required' after creation:
Anyways I remain convinced that changing the 'required' attribute is the correct way to change the error message, not adding more tests to the message generator.
paulj3 commentedon Nov 7, 2016
My suggestion to use
metavar=('A','')to streamline the usage creates problems with the help codehttp://bugs.python.org/issue14074
The tuple metavar does not work right for positionals. That's a old issue that should have been fixed long ago.
So streamlining the usage has to be done with a custom HelpFormatter subclass.
rrt commentedon Nov 7, 2016
Thanks, that's a simple, robust workaround.
I'll duck out now and leave the Python experts to sort out the underlying problem, if they can; I think it's still well worth sorting out, though documenting the problem and workaround would be much better than nothing.
benhoyt commentedon Feb 27, 2017
I definitely agree with Reuben here -- I just ran into this issue while creating a "production quality" tool, and the help message produced by argparse with nargs='*' confused me too. It's pretty clear that this is a simple bug in argparse's production of that usage message: it says ARGUMENT is required, but it isn't.
However, the workaround of specifying an (unused) default is a reasonable workaround in the meantime -- thanks Paul.
svenevs commentedon May 27, 2019
nargs='*' being marked as
requiredis incorrect though, isn't it?I was also very confused by this behavior, the only reason I found this bug was to search before opening new, and had a patch prepared that is nearly identical to the one here.
It's really helpful to know about explicitly setting
default=None|[]depending on use case. Would a docs PR briefly explaining at the bottom of the nargs [a] docs explaining how to change the error message viadefaultbe welcome? This is a slightly challenging problem to search for.My understanding is the ultimate rejection of the patch is because it's bypassing the
requiredattribute. So to fix this adequately, changing ? and * to not show up as required (when nodefaultprovided) should be done?[a] https://docs.python.org/3/library/argparse.html#nargs
iritkatriel commentedon Dec 10, 2021
Reproduced on 3.11.
7 remaining items
pythongh-72795: Make positional arguments with nargs='*' or REMAINDER…
serhiy-storchaka commentedon Sep 21, 2024
I agree that the current error message that requires an argument with
nargs='*'is misleading.It is even worse for
nargs=REMAINDER, because it refers to argument name not mentioned in the "usage" line:Output:
I think that it is an error to mark such positional arguments as required.
I guess that the reason of marking
nargs='*'withoutdefaultas required lies in the way how conflicts in mutually exclusive groups were detected. The code simply checked if the value is the same as the default value, and this obviously does not work for[]. Fixing this code allows to make all positional arguments withnargs='*'non-required.As for
nargs=REMAINDER, I think it was just an omission.gh-72795: Make positional arguments with nargs='*' or REMAINDER non-r…
pythongh-72795: Make positional arguments with nargs='*' or REMAINDER…
pythongh-72795: Make positional arguments with nargs='*' or REMAINDER…
[3.12] gh-72795: Make positional arguments with nargs='*' or REMAINDE…
[3.13] gh-72795: Make positional arguments with nargs='*' or REMAINDE…