How to call parse_args() twice on the same set of arguments in Python's argparse?

∥☆過路亽.° 提交于 2020-05-28 05:58:24

问题


Simplified test case: I have a script that takes two arguments. The first is a list of integers. The second is a single integer that must be contained in the first argument's set of integers.

For example:

$ python argtest.py --valid_nums 1 2 3 --num 2

Should work, but:

$ python argtest.py --valid_nums 1 2 3 --num 4

Should not work, since num is not in valid_nums. However, I have had some difficulty (read: I suspect it is more trouble than it's worth, but I really want it to work) implementing this functionality.

Implementation attempt:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--valid_nums',
                    type=int,
                    nargs='+')

args = parser.parse_args()
print "Numbers: ", args.valid_nums


parser.add_argument('--num',
                    type=int,
                    choices=args.valid_nums)

args = parser.parse_args()
print args

Actual output:

$ python argtesttest.py --valid_nums 1 2 3 --num 2
usage: argtesttest.py [-h] [--valid_nums VALID_NUMS [VALID_NUMS ...]]
argtesttest.py: error: unrecognized arguments: --num 2

Desired output:

$ python argtesttest.py --valid_nums 1 2 3 --num 2
Namespace(num=2, valid_nums=[1, 2, 3])

Now, (I think) the issue here is that I cannot add a new argument to the parser after I have called parse_args(), which yields the error about an unrecognized argument, but I can't think of a way around it. Is there any way to break up the processing of arguments such that it isn't all at once?

Obviously this would be pretty trivial to do if I only called parse_args() once and handled the container membership checking myself, but I'd like to get it working 'natively' using argparse's built-in error-checking.

Any ideas?


回答1:


you need to use parser.parse_known_args() as opposed to parser.parse_args(), or add all the arguments to parser before calling parse_args().

parse_args() needs to understand all the current arguments in sys.argv, which already contains --num at the time of first parsing, hence the exception.




回答2:


You can do it with namespace and parse_known_args, and call parse_args at the end

class UserNamespace(object):
    pass
user_namespace = UserNamespace()

p = argparse.ArgumentParser() 
p.add_argument('-c', '--config', dest='config', default='')
p.parse_known_args(namespace=user_namespace)
if user_namespace.config == '':
    p.add_argument('-w', '--whatever', dest='whatever', default='')

parsed_args = p.parse_args(namespace=user_namespace)

for the specific case:

num.py:

import argparse
class UserNamespace(object):
    pass
user_namespace = UserNamespace()

parser = argparse.ArgumentParser()
parser.add_argument('--valid_nums', dest='valid_nums',
                    type=int,
                    nargs='+')

parser.parse_known_args(namespace=user_namespace)

parser.add_argument('--num',
                    type=int,
                    choices=user_namespace.valid_nums)

args = parser.parse_args(namespace=user_namespace)

print "Numbers: ", user_namespace.valid_nums

so you call:

$python num.py --valid_nums 1 2 3 --num 2  
Numbers:  [1, 2, 3]

$python num.py --valid_nums 1 2 3 --num 4  
usage: num.py [-h] [--valid_nums VALID_NUMS [VALID_NUMS ...]] [--num {1,2,3}]
num.py: error: argument --num: invalid choice: 4 (choose from 1, 2, 3)

references : argparse namespace
argparse parse_known_args

bye!

Update March 4 2017 Better to instantiate the UserNamespace, or other functionalities (like add_subparsers) could not work properly.



来源:https://stackoverflow.com/questions/32362008/how-to-call-parse-args-twice-on-the-same-set-of-arguments-in-pythons-argparse

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!