Repository navigation
argparse: successive parsing wipes out nargs=? values #72920
Description
Activity
adamjstewart commented
on Nov 18, 2016 adamjstewartmannequinMannequinAuthorMore actionsI'm writing a wrapper that optionally accepts a file and reads more options from that file. The wrapper then needs to pass all of these options and the file to another program (qsub). Here is a minimal example to reproduce the behavior I'm seeing:
>>> import argparse >>> parser = argparse.ArgumentParser() >>> parser.add_argument('-a') >>> parser.add_argument('file', nargs='?') >>> args = parser.parse_args(['-a', '3', 'myFile']) >>> print(args) Namespace(file='myFile', a='3') >>> parser.parse_args(['-a', '4'], namespace=args) >>> print(args) Namespace(file=None, a='4')
The behavior I expect is that the file should remain as 'myFile', but it is being wiped out. Is there any way to prevent this, or is this actually a bug?
I can recreate this problem in Python 2.7 and 3.5.
- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Nov 18, 2016 try this:
parser.add_argument('file', nargs='?', default = argparse.SUPPRESS)I don't think this is a bug. The default for the default parameter is None so the behavior is consistent with the documentation.
adamjstewart commented
on Nov 18, 2016 adamjstewartmannequinMannequinAuthorMore actionsWorks for me, thanks Wolfgang!
The problem described here is restricted to
?and `*' positionals, and is caused by the subtle way in which 'empty' optional positionals are handled.The regular handling of defaults at the start of
parse_known_argsworks fine. The default is only written to the namespace if something isn't there already.if not hasattr(namespace, action.dest): if action.default is not SUPPRESS: setattr(namespace, action.dest, action.default)
But a positional with ? or * is always 'seen' because an empty list of strings satisfies the nargs pattern. 'get_values()' has special handling for this case:
if not arg_strings and action.nargs == OPTIONAL: .... value = action.default
That is, it replaces the empty list with the 'default'.
But take_action(), which does the actual saving, is conditional:
# take the action if we didn't receive a SUPPRESS value # (e.g. from a default) if argument_values is not SUPPRESS: action(self, namespace, argument_values, option_string)
That explains why 'default=SUPPRESS' solves this issue.
It's enough to satisfy the OP's situation, but I don't think it's a robust fix.
I don't have a patch idea yet, but this probably should be reopened so there's a record of the potential problem.
More on the complications raised by these 'seen default actions' in
Closing this issue, because the reported case is unusual, the OP is satisfied with the workeraund, and changing the current behavior is really hard.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDoc issues
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields: