首页 > 解决方案 > argparse and custom Actions - code path not obvious

问题描述

I'm using argparse to digest text commands rather than trying to roll my own custom parser, but the code path is not obvious. Consider the following:

import argparse

##class ReadAction(argparse.Action):
##    def __init__(self, option_strings, dest, nargs=None, **kwargs):
##        if nargs is not None:
##            raise ValueError("nargs not allowed")
##        super(ReadAction, self).__init__(option_strings, dest, **kwargs)
##    def __call__(self, parser, namespace, values, option_strings=None):
##        print("Read a file")
##        setattr(namespace, self.dest, values)

class ExitAction(argparse.Action):
    def __init__(self, option_strings, dest, nargs=None, **kwargs):
        if nargs is not None:
            raise ValueError("nargs not allowed")
        super(ExitAction, self).__init__(option_strings, dest, **kwargs)
    def __call__(self, parser, namespace, values, option_strings=None):
        print("Exiting the program")
        setattr(namespace, self.dest, values)

def setup_parser(parser):
##    parser.add_argument('read', help='Reads in a file', action=ReadAction)
    parser.add_argument('exit', help='Exit command', action=ExitAction)

def run():
    parser = argparse.ArgumentParser()
    setup_parser(parser)
    while True:
        raw_input = input("Command >>>").split(' ')
        args = parser.parse_args(raw_input)
        print(args)
    print('Good bye')

if __name__ == '__main__':
    run()

If I run it as is, I get the expected output:

Command >>>exit
Exiting the program
Namespace(exit='exit')

But if I take out the comments and run again, I get this unexpected behavior:

Command >>>exit
Read a file
usage: prog.py [-h] read exit
prog.py: error: the following arguments are required: exit

Does anyone understand the code path through this? It's like the __call__ method isn't being called (ironic).

标签: pythonargparse

解决方案


You aren't binding commands to the literal strings read and exit; that's not how argparse works. Instead, you are defining a parser that takes two arbitrary words, and binds the first to read and the second to exit. Your commented code would exit no matter what single word you typed, not just exit. Without the comments, the parser expects two words, and raises an error when you only provide one.

If you are going to (ab)use argparse in this fashion, I suggest you read up on subcommands in the documentation.


推荐阅读