I would love to make the 'subcommands' functionality provided in argparse more user-friendly. I think I have a worthwhile feature request to share:
* Be able to add multiple subcommands to an ArgumentParser, without needing to track the 'action_object'
I've outlined an motivating example below, and shared an implementation of this feature that I've started using in one of my projects.
Thanks! -Ryan
# Motivating Example
I am working with ArgumentParser subcommands a lot recently, and I've run into the interesting implementation detail when it comes to 'adding multiple subcommands to a parser': `argparse.ArgumentParser` provides a [special 'action object' to manage subcommands](https://docs.python.org/3/library/argparse.html#sub-commands).
Lets look at an example of how this works:
First, setup our `root_parser`:
root_parser = ArgumentParser()
Then, later on, lets add a 'post' subcommand:
action_object = root_parser.add_subparsers() post_parser = action_object.add_subparser("post")
Finally, lets add a 'get' subcommand to the `root_parser`:
action_object = root_parser.add_subparsers() <--- Error here! get_parser = action_object.add_subparser("get")
This second code block will not work, and will raise an error!
: error: cannot have multiple subparser arguments
So, it seems these ephemeral 'action objects' are a thorn in my side. Specifically, these objects are impeding the following functionality:
* Add multiple subcommands to an ArgumentParser **from multiple scopes**
So, I would like some way for to track the 'action object' alongside `root_parser` to enable 'adding subcommands from multiple scopes.' This can be done by extending `ArgumentParser` to track that 'action object, then provide some `add_subcommand(str)` method. Let's rewrite the example code blocks above assuming we have this new method -- we'll use the class name `SubcommandArgumentParser`.
root_parser = SubcommandArgumentParser()
The Post parser...
post_parser = root_parser.add_subcommand("post")
The Get parser...
get_parser = root_parser.add_subcommand("get")
I wonder, am I totally missing some obvious complexity of subparsers/subcommands with this suggested feature? that this could make working with subcommadns
# Example Implementation
Here is an implementation of that functionality that I put together for my project.
class SubcommandArgumentParser(configargparse.ArgumentParser): count = 0
def __init__(self, *args, **kwargs): self.subparser_factory = None super().__init__(args, kwargs)
def _create_subparser_factory(self): unique_str = f'action{SubcommandArgumentParser.count}' SubcommandArgumentParser.count += 1 # Create the subparser factory! self.subparser_factory = self.add_subparsers(dest=unique_str) self.subparser_factory.required = True
def add_subparser(self, subcommand: str) -> 'SubcommandArgumentParser': """Some programs split functionality up into subcommands. Each subcommand has a dedicated `configargparse.ArgumentParser`.
Arguments: subcommand (str): The subcommand to be added to this parser.
Returns: SubcommandArgumentParser: The ArgumentParser that can be
Example: Given a Subcommand parser.add_subparser() """ if self.subparser_factory is None: self._create_subparser_factory() return self.subparser_factory.add_parser(subcommand)
On Thu, Sep 16, 2021 at 5:28 AM rleonar7@uoregon.edu wrote:
I would love to make the 'subcommands' functionality provided in argparse more user-friendly. I think I have a worthwhile feature request to share:
- Be able to add multiple subcommands to an ArgumentParser, without needing to track the 'action_object'
I've outlined an motivating example below, and shared an implementation of this feature that I've started using in one of my projects.
A reasonable idea, but what I'd recommend is building a wrapper around argparse that does what you want. One good example is clize:
https://pypi.org/project/clize/
ChrisA