argparse on demand imports for types, choices etc

后端 未结 4 1357
一整个雨季
一整个雨季 2021-01-20 11:10

I have quite a big program which has a CLI interaction based on argparse, with several sub parsers. The list of supported choices for the subparsers arguments a

4条回答
  •  北恋
    北恋 (楼主)
    2021-01-20 11:53

    Here's a quick and dirty example of a 'lazy' choices. In this case choices are a range of integers. I think a case that requires expensive DB lookups could implemented in a similar fashion.

    # argparse with lazy choices
    
    class LazyChoice(object):
        # large range
        def __init__(self, argmax):
            self.argmax=argmax
        def __contains__(self, item):
            # a 'lazy' test that does not enumerate all choices
            return item<=self.argmax
        def __iter__(self):
            # iterable for display in error message
            # use is in:
            # tup = value, ', '.join(map(repr, action.choices))
            # metavar bypasses this when formatting help/usage
            return iter(['integers less than %s'%self.argmax])
    
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('--regular','-r',choices=['one','two'])
    larg = parser.add_argument('--lazy','-l', choices=LazyChoice(10))
    larg.type = int
    print parser.parse_args()
    

    Implementing the testing part (__contains__) is easy. The help/usage can be customized with help and metavar attributes. Customizing the error message is harder. http://bugs.python.org/issue16468 discusses alternatives when choices are not iterable. (also on long list choices: http://bugs.python.org/issue16418)

    I've also shown how the type can be changed after the initial setup. That doesn't solve the problem of setting type based on subparser choice. But it isn't hard to write a custom type, one that does some sort of Db lookup. All a type function needs to do is take a string, return the correct converted value, and raise ValueError if there's a problem.

提交回复
热议问题