argparse: reduce complexity around 'subcommand action objects'?
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
participants (2)
-
Chris Angelico
-
rleonar7@uoregon.edu