Argparse - accessing multiple arguments at once

2019-07-24 15:53发布

my application uses a database, so when adding a new element (from command line) I want to check if this one is already in the database, what I do with the "type" parameter of add_argument:

def check_uniq(project_name):
    if Project.exists(project_name):
        raise argparse.ArgumentTypeError(
    return project_name

this is working just fine, however to make think easier to the final user I'd like to add a --force option to my arguments so this variable is tested and delete before to add and in this case do note raise the argument. How can I access within the check_uniq to the --force option ?

2条回答
来,给爷笑一个
2楼-- · 2019-07-24 16:10

The purpose of the type function is to convert an argument string to some other kind of object (int, float, file). It does not have access to the namespace or other attributes of the parser. Indirectly it has access to the global state, such as when trying to open a file in FileType.

The action has access to the namespace, though usually that is for the purpose of setting a value (attribute). It can check the values of other attributes, but that ends up limiting the order in which attributes are set (e.g. --force has to come before database).

You can also check namespace attributes after parse_args. You can still used the argparse error mechanism by calling parser.error('your message'). It may be easier to check values at this stage, since you don't have to worry about the order of the strings in sys.argv.

查看更多
干净又极端
3楼-- · 2019-07-24 16:21

Test if the option is set in the same if stamement:

def check_uniq(project_name, options):
    if Project.exists(project_name) and not options.force:
        raise argparse.ArgumentTypeError('Project already exists')
    return project_name

where options takes the Namespace instance returned by parser.parse_args().

Unfortunately, you cannot verify this until all arguments have been parsed, you cannot use this function as a type parameter, because the --force option can be specified anywhere on the command line, before or after the option that specifies your project name.

If you require that --force is listed before any projects on your command line, you could use a custom action instead; a custom action is passed the namespace object as parsed so far:

class UniqueProjectAction(argparse.Action):
    def __call__(self, parser, namespace, value, option_string=None):
        if Project.exists(value) and not namespace.force:
            raise argparse.ArgumentTypeError('Project already exists')
        setattr(namespace, self.dest, values)
查看更多
登录 后发表回答