首页 > 解决方案 > Python 无法解析嵌套参数

问题描述

我想使用 argparse 来解析我的应用程序参数。我尝试了很多东西,但我没有找到正确的方法。

在这里我想做(python3 app.py与所有这些命令有关):

列表

list member <member_id>
list member addresses <member_id>
list members
list domains
list organisations

创造

create member <first_name> <last_name>
create member address <address> <display_name>

更新

update member name <member_id> <full_name>
update member storage <member_id> <storage_size>

删除

delete member <member_id>

禁用

disable member addresses <member_id>
disable member address <member_id> <addresses_id>

使能够

enable member addresses <member_id>
enable member address <member_id> <addresses_id>

这是我试图解析的内容List,但是当有多个参数和解析器时我无法区分:

def list_member_addresses(args):
    print(f'Member id {args.member_id}')

def list_member(args):
    print(f'Member id {args.member_id}')

def list_members():
    print('list members')

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='action', required=True)

# list
list_parser = subparsers.add_parser('list')
list_subparsers = list_parser.add_subparsers(dest='type', required = True)

# list members
members_parser = list_subparsers.add_parser('members')
members_parser.set_defaults(func=list_members)

# list member <member_id>
member_parser = list_subparsers.add_parser('member')
member_parser.add_argument('member_id')
member_parser.set_defaults(func=list_member)

# list member addresse <member_id>
addresses_member_subparser = member_parser.add_subparsers(dest='type')
addresses_member_parser = addresses_member_subparser.add_parser('addresses')
addresses_member_parser.add_argument('member_id')
addresses_member_parser.set_defaults(func=list_member_addresses)

# update
update_parser = subparsers.add_parser('update')
# TODO use similar case as "list"

# delete
delete_parser = subparsers.add_parser('delete')
# TODO use similar case as "list"

# enable
enable_parser = subparsers.add_parser('enable')
# TODO use similar case as "list"

# disable
disable_parser = subparsers.add_parser('disable')
# TODO use similar case as "list"

args = parser.parse_args()
# Commented on purpose
# args.func(args)
print(args)

测试输出:

user@hostname:$ python3 app.py list member
usage: test.py list member [-h] member_id {addresses} ...
test.py list member: error: the following arguments are required: member_id

user@hostname:$ python3 app.py list member member_id
Namespace(action='list', addresses=None, func=<function list_member at 0x7fa91eff85e0>, member_id='member_id', type='member')

user@hostname:$ python3 app.py list member addresses
Namespace(action='list', addresses=None, func=<function list_member at 0x7f1342e495e0>, member_id='addresses', type='member')

user@hostname:$ python3 app.py list member addresses member_id
usage: test.py list member [-h] member_id {addresses} ...
test.py list member: error: argument addresses: invalid choice: 'member_id' (choose from 'addresses')

user@hostname:$ python3 app.py list members
Namespace(action='list', func=<function list_members at 0x7f09a14b1670>, type='members')

您可以看到,在某些情况下,member_id键具有addresses作为值,但情况并非如此。此外,对于list member address,我们不能添加member_id参数。

你有什么主意吗 ?

- - - 编辑 - - -

在这里澄清我的期望和我得到的:

工作案例

list member <member_id>

user@hostname:$ python3 app.py list member member_id
Namespace(action='list', addresses=None, func=<function list_member at 0x7fa91eff85e0>, member_id='member_id', type='member')

list members

user@hostname:$ python3 app.py list members
Namespace(action='list', func=<function list_members at 0x7f09a14b1670>, type='members')

不工作的情况

list member addresses <member_id>

user@hostname:$ python3 app.py list member addresses member_id
usage: test.py list member [-h] member_id {addresses} ...
test.py list member: error: argument addresses: invalid choice: 'member_id' (choose from 'addresses')

使用下面的这个命令,我们可以在这里看到它接受addresses解析器member的参数addresses而不是解析器的参数。

user@hostname:$ python3 test.py list member addresses 
Namespace(action='list', func=<function list_member at 0x7f697cc3d5e0>, member_id='addresses', type=None)

在这里它正在工作,但不像预期的那样,因为我不想提供member_id1,而是addresses相反。

user@hostname:$ python3 test.py list member member_id1 addresses member_id2
Namespace(action='list', func=<function list_member_addresses at 0x7f1378530d30>, member_id='member_id2', type='addresses')

所以这就是我对该命令的期望:

user@hostname:$ python3 test.py list member addresses member_id
Namespace(action='list', func=<function list_member_addresses at 0x7f1378530d30>, member_id='member_id', type='addresses')

基本上,我希望有嵌套命令,但不一定有参数,反之亦然。

标签: pythonargparse

解决方案


python3 app.py list member addresses member_id

parser看到“列表”,并将解析传递给list_parser. 将解析传递给member_parser.

那得到['addresses', [member_id']. 根据usage错误消息中的,“addresses”被分配给“member_id”属性,留下“member_id”进行测试{addresses}

usage: test.py list member [-h] member_id {addresses} ...

从代码中,member_parser获取一个 'member_id' 位置,然后是一个 'subparsers' 位置:

member_parser = list_subparsers.add_parser('member')
member_parser.add_argument('member_id')
member_parser.set_defaults(func=list_member)

# list member addresse <member_id>
addresses_member_subparser = member_parser.add_subparsers(dest='type')
addresses_member_parser = addresses_member_subparser.add_parser('addresses')

addresses_member_parser也需要一个 'member_id' 参数,但member_parsers必须首先满足。

这应该有效:

python3 app.py list member member_id1 addresses member_id2

推荐阅读