Search code examples
pythoncommand-line-interfaceargparse

How to nest custom argument parser instance in argparse


I'm trying to nest multiple custom ArgumentParser I've created (and tested), into a bigger argument parser.

Think of it as having multiple independent components for a script, that each have its own options. I've created an ArgumentParser for each, tested whether they work correctly with unittests, and want to piece together a "mother" argument parser that gets all of the options at once, but is component based. Each component has some required options that will make it a hassle if I want to unify them under groups.

So my current pseudocode is like this:

def create_custom_parser1():
    parser = ArgumentParser()
    parser.add_argument('--component1-argument1')
    ...

def create_custom_parser2():
    parser = ArgumentParser()
    parser.add_argument('--component2-argument2')
    ...

def create_unified_parser():
    unified = ArgumentParser()
    component1_parser = create_custom_parser1()
    component2_parser = create_custom_parser2()
    # somehow do this:
    # unified.add_parsers([component1_parser, component2_parser])

EDIT: My command is super long (it's a machine learning training pipeline cli), but it has multiple independent component (e.g. preprocessing component, modelling component,etc). What I want is to have a unified command with all of the component parsers sewn together, but I want to start from independent parsers to keep my sanity and make each testable independently.


Solution

  • The parents mechanism copies Actions from the parents to the new parser. It's intended as a way of incorporating 'imported' parsers, without knowing what's in them (though it isn't hard to discover that). It may be worth searching SO for past experiences with it.

    Subcommands/parsers, passes the parsing action to the new parser (as you note, only one). There are lot more SO questions about it. It cannot use predefined parsers (though I've seen a bug/issue request for such a feature). But a predefined parser could be used as a parent.

    You could call all parsers independently. A parse_args() does not change the sys.argv, so multiple parsers can use the same list. parse_known_args is better for this, so a parser doesn't quit over unrecognized strings. Also no-required (default) optionals are best. Usually though, multiple parsers is an error, when a user doesn't realize that some imported module (e.g. a google youtube app) is looking at the commandline as well.

    Or you could look at sys.argv before, and split it into sublists that you pass on to different parsers, e.g. parser1.parse_args(part_argv) etc.