argparse default option based on another option

后端 未结 2 780
面向向阳花
面向向阳花 2020-12-18 17:59

Suppose I have an argparse python script:

import argparse
parser = argparse.ArgumentParser()

parser.add_argument(\"--foo\", required=True)

相关标签:
2条回答
  • 2020-12-18 18:18

    Here's another attempt at writing a custom Action class

    import argparse
    class FooAction(argparse.Action):
        # adapted from documentation
        def __call__(self, parser, namespace, values, option_string=None):
            setattr(namespace, self.dest, values)
            defaultbar = getattr(namespace, 'bar')
            try:
                defaultbar = defaultbar%values
            except TypeError:
                # BAR has already been replaced
                pass
            setattr(namespace, 'bar', defaultbar)
    
    parser = argparse.ArgumentParser()
    parser.add_argument("--foo", required=True, action=FooAction)
    parser.add_argument("--bar", default="%s_BAR")
    
    args = parser.parse_args(['--foo', 'Foo', '--bar', 'Bar'])
    # Namespace(bar='Bar', foo='Foo')
    args = parser.parse_args(['--foo', 'Foo'])
    # Namespace(bar='Foo_BAR', foo='Foo')
    args = parser.parse_args(['--bar', 'Bar', '--foo', 'Foo'])
    # Namespace(bar='Bar', foo='Foo')
    

    Note that the class has to know the dest of the --bar argument. Also I use a '%s_BAR' to readily distinguish between a default value, and a non default one. This handles the case where --bar appears before --foo.

    Things that complicate this approach are:

    • default values are evaluated at add_argument time.
    • default values are placed in the Namespace at the start of parse_args.
    • flagged (optionals) arguments can occur in any order
    • the Action class is not designed to handle interacting arguments.
    • the bar action will not be called in the default case.
    • the bar default could be a function, but something would have to check after parse_args whether it needs to be evaluated or not.

    While this custom Action does the trick, I still think the addbar function in my other answer is a cleaner solution.

    0 讨论(0)
  • 2020-12-18 18:22

    I would, as a first try, get this working using an after-argparse function.

    def addbar(args):
        if args.bar is None:
            args.bar = args.foo+'_BAR'
    

    If this action needs to be reflected in the help, put it there yourself.

    In theory you could write a custom Action for foo that would set the value of the bar value as well. But that requires more familiarity with the Action class.

    I tried a custom Action that tweaks the default of the bar action, but that is tricky. parse_args uses the defaults right at the start, before it has acted on any of the arguments.

    0 讨论(0)
提交回复
热议问题