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
Using parameter 'action' in function 'argparse.ArgumentParser.add_subparsers' #92811
Comments
An 'action' works as long as it's compatible with the default subparsers class. For example using that subclass itself:
While I've suggested using 'action' to supply a customized In other words, 'action' works if the subclass signature is like:
|
I was trying to use subparsers for the first time and basically tried to use Anyway, it should at least be possible to refine the error-message While I do see your point regarding the possible confusion in the docs, I doubt anyone will be able to use this feature/parameter at all, if it stays undocumented. Unfortunately reading the docs and even staring at the sourcecode for a couple of minutes did not yield me any useful information in this situation - just my two cents. |
You are trying to get around an intentional limitation. If you try to use The 'action' parameter is designed to be flexible and extensible. Registered words like "extend" map onto
The Use of |
Sorry, if my previous post was misleading is any way. In the first paragraph, I was just trying to tell you how people, that are new(ish) to argparse, could end up trying to invoke the And my goal certainly wasn't for you to rewrite the entire code because of some required argument. I was just thinking about adding a sanity check for the parameter
of the
Link to aforementioned subclass signature This way, the default action strings (like count, append, store_true, ...), which aren't supposed to work in this context (if I understand you correctly), would trigger an error message, that's tailored to this situation. |
I do not understand why this is intentional limitation.
would return
I do not see a simpler way of doing this using the current ideology of argparse library right now. |
An 'append' action cannot work across subparsers. It is best to give main
and subparsers arguments different `dest`. Otherwise you'll only see the
subparser values or defaults.
|
@hpaulj I am missing the same feature @ruzito mentioned. Given is a command-line requirement like:
This can be expressed by parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="command")
subparser_a = subparsers.add_parser("cmd1")
subparser_b = subparsers.add_parser("cmd2")
subsubparsers_a = subparser_a.add_subparsers(dest="command")
subsubparser_a = subsubparsers_a.add_parser("subcmd")
subsubparsers_b = subparser_b.add_subparsers(dest="command")
subsubparser_b = subsubparsers_b.add_parser("subcmd")
print(parser.parse_args(["cmd1", "subcmd"])) We wouldn't be able to identify, if
I'd like to assign an identifier or unique tuple (whole chain of commands) to
Giving different
This is what lists/sequences are naturally used for. Adding dest=lambda prev_cmds: ".".join(prev_cmds) I hope this is comprehensible so far. As this gets a bit orthogonal to OP, should I make up a separate feature request? |
This ability to nest subparsers is a feature, simply the result of how the
subparser mechanism is coded, not an intentional design. So I think it's
unreasonable to expect special enhancements.
Normally `action` is a string, which is registered with an `Action`
subclass. Or it's a user specified subclass. In either case it defines
the class of the `argument` created by `add_argument`, or in this case
`add_subparsers`. `action` doesn't just specify how the `dest` is
assigned; it defines an Action subclass.
When you read the code for `add_subparsers`, you'll see that it fetches the
class corresponding to `action='parsers', which is registered as
`_SubParsersAction`. It's that subclass that provides all the subparser
action - adding parsers (as `choices`), and passing the remaining argv
strings to the chosen subparser.
self.register('action', 'parsers', _SubParsersAction)
...
# create the parsers action and add it to the positionals list
parsers_class = self._pop_action_class(kwargs, 'parsers')
action = parsers_class(option_strings=[], **kwargs)
self._subparsers._add_action(action)
The `__call__` for the subparsers Action sets the command `dest`, if any
with:
def __call__(self, parser, namespace, values, option_string=None):
parser_name = values[0]
arg_strings = values[1:]
# set the parser name if requested
if self.dest is not SUPPRESS:
setattr(namespace, self.dest, parser_name)
That `parser_name` is used to select which subparser will be used:
parser = self._name_parser_map[parser_name]
This is what allows us to use aliases for the commands. You might be able
to play games with those. Or a custom subclass could set a special `dest`
based on the `parser_name` and its 'own name'.
Anyways, I don't think the standard `argparse` should have any added
features to allow/enhance this use of nested subparsers. This nesting is a
kludge used to get around the intended one-subparser per parser
constraint. But if you want to write your own `add_subparsers` and/or
` _SubParsersAction` class, feel free.
… Message ID: ***@***.***>
|
@hpaulj Thanks for pointing out the invoked code locations, it makes sense to me.
This was not clear to me from reading the docs. In this case it probably would be a good idea to document intended usage - only one direct subparser layer, no nesting - more clearly. If the goal is to identify the (possibly nested) used sub-parser afterwards, I have found a simple workaround for # Above example, with below additions
subsubparser_a.set_defaults(__ID__=["cmd1", "subcmd"])
subsubparser_b.set_defaults(__ID__=["cmd2", "subcmd"]) , which provides
|
Bug report
The function argparse.ArgumentParser.add_subparsers throws an error regarding parser_class, when passing the parameter action.
Sample-code "ArgParserTest.py":
Terminal output:
Possible resolutions
a. Have the error-message complain about the argument action instead of parser_class.
b. Remove the argument action from the parameter list to the add_subparser-function.
c. Update the documentation accordingly.
Environment
The text was updated successfully, but these errors were encountered: