我希望能够验证传递给脚本的参数,以便我可以使用以下选项:
test.py user info <user name>
test.py user create <user name> <last name> <first name> <email>
test.py user create batch <file name>
test.py user delete <user name>
test.py room info <room number>
test.py room create <room number> <room name>
test.py room delete <room number
我目前有一个非常复杂的if, elif, else
级联:
if len(sys.argv) >= 2:
if (sys.argv[1]).lower() == "user":
if len(sys.argv) >= 3:
if (sys.argv[2]).lower() == "info":
if len(sys.argv) >= 4:
username = sys.argv[3]
get_user_info(username)
else:
print("username not specified")
我甚至不打算添加elif,以及其他陈述。
我已经读到使用argparse是一种更好的方法,但我还没有看到如何以满足我需求的方式实现它。
就像现在一样,如果有人只执行test.py
文件本身,它会打印出有效的参数。然后,如果它们自己执行test.py user
,它会为它们提供下一组有效参数,依此类推,依此类推。一旦进入,就没有对这些进行验证。
请帮忙!并提前感谢。
答案 0 :(得分:0)
这是使用 argparse 的解决方案。它的灵感来自_catkin_tools_的方式。
parse_config
字典字典为<category> <verb>
user info
创建条目。parse_config
中找到user info
的{{1}},其中包含字段parse_config['user']['info']
,desc(ription)
和main
。prepare_parser
是一个可调用对象(即函数),在脚本的最后一行调用,如下所示:main
。为此忽略sys.exit(args.main(args))
。 sys.exit(..)
是解析从命令行给出的参数后将根据给定的参数指向正确的入口点的函数。这是如何工作的,使用args.main
。这意味着如果此特定子分析器被激活,则subparser.set_defaults(main=main_for_this_subparser)
指向args.main
,这可以是任何功能。main_for_this_subparser
也是一个函数,可以为每个命令自定义以添加更多参数。由于用户始终要求prepare_parser
作为第一个参数,我对所有三个动词使用了<user name>
( info , create < / em>,删除)。由于 create 需要更多参数,因此会获得一个特殊的def parser_user_default(parser): parser.add_argument('user_name')
函数,其中第一个parser_user_create
被调用但随后会添加更多参数。documentation of set_defaults很有帮助:
使用多个解析器时,解析器级默认值特别有用。有关此类型的示例,请参阅add_subparsers()方法。
Catkin-Tools代码非常有用(而且很聪明):
parser_user_default
:https://github.com/catkin/catkin_tools/blob/master/setup.py setup.py
的示例prepare_parser
/ prepare_arguments
:https://github.com/catkin/catkin_tools/blob/master/catkin_tools/verbs/catkin_build/cli.py#L95 到目前为止,我的解决方案无法处理调用catkin build
。首先,我认为这实际上不是一个好的CLI,因为用户可能永远不会被称为“批处理”。也许用作test.py user create batch <batch file>
会更好。另一方面,我无法直接使用argparse。如果您对此进行了实验,请考虑user create --batch <file>
,它可以让您将argparse与手动参数处理混合使用。
我对我的实施并不完全满意。事后看来,一个递归实现,可以处理任何级别的嵌套字典,将更加清晰。目前,该实现正好处理parse_known_args()
。
<category> <verb>
答案 1 :(得分:0)
您可以使用argparse选项来限制前2个字符串的输入。剩余的字符串更加可变,但if测试可以利用共性。
import argparse
def lower(astr):
return astr.lower()
parser = argparse.ArgumentParser()
parser.add_argument('first', type=lower, choices=['user', 'room'])
parser.add_argument('second', type=lower, choices=['info','create','delete'])
parser.add_argument('rest', nargs='+')
parser.set_defaults(file=[], user=[], room=[]) # defaults
args = parser.parse_args()
print(args)
# partial parse of the `rest` list of strings:
if args.first in ['user']:
if args.second in ['create']:
if args.rest[0] in ['batch']:
args.files=args.rest[1:]
else:
args.user = args.rest
else:
args.user = args.rest[0]
else:
args.room = args.rest
args.rest=[]
print(args)
帮助:
1553:~/mypy$ python stack50071515.py -h
usage: stack50071515.py [-h] {user,room} {info,create,delete} rest [rest ...]
positional arguments:
{user,room}
{info,create,delete}
rest
optional arguments:
-h, --help show this help message and exit
测试输入:
1545:~/mypy$ python stack50071515.py user info name
Namespace(file=[], first='user', rest=['name'], room=[], second='info', user=[])
Namespace(file=[], first='user', rest=[], room=[], second='info', user='name')
1549:~/mypy$ python stack50071515.py user create a b c
Namespace(file=[], first='user', rest=['a', 'b', 'c'], room=[], second='create', user=[])
Namespace(file=[], first='user', rest=[], room=[], second='create', user=['a', 'b', 'c'])
1549:~/mypy$ python stack50071515.py user create batch file
Namespace(file=[], first='user', rest=['batch', 'file'], room=[], second='create', user=[])
Namespace(file=[], files=['file'], first='user', rest=[], room=[], second='create', user=[])
1550:~/mypy$ python stack50071515.py user delete name
Namespace(file=[], first='user', rest=['name'], room=[], second='delete', user=[])
Namespace(file=[], first='user', rest=[], room=[], second='delete', user='name')
1550:~/mypy$ python stack50071515.py room info number
Namespace(file=[], first='room', rest=['number'], room=[], second='info', user=[])
Namespace(file=[], first='room', rest=[], room=['number'], second='info', user=[])
1550:~/mypy$ python stack50071515.py room create a b
Namespace(file=[], first='room', rest=['a', 'b'], room=[], second='create', user=[])
Namespace(file=[], first='room', rest=[], room=['a', 'b'], second='create', user=[])
1550:~/mypy$ python stack50071515.py room delete 23
Namespace(file=[], first='room', rest=['23'], room=[], second='delete', user=[])
Namespace(file=[], first='room', rest=[], room=['23'], second='delete', user=[])