【问题标题】:Python cannot parse nested argumentsPython 无法解析嵌套参数
【发布时间】:2021-12-17 18:56:14
【问题描述】:

我想使用 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 &lt;member_id&gt;

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 &lt;member_id&gt;

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')

使用下面的这个命令,我们可以在这里看到它接受解析器member的参数addresses而不是参数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')

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

【问题讨论】:

  • 明确指出哪些测试用例是意外的以及原因。代码太复杂,不明显。
  • 感谢@hpaulj 重播。我在----- EDIT ----- 之后添加了有关我的问题(问题)的更多详细信息。

标签: python argparse


【解决方案1】:

python3 app.py list member addresses member_id

parser 看到'list',并将解析传递给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

【讨论】:

  • 感谢您的重播。我知道member_parsers 也需要一个参数(member_id),并且需要首先满足它,但就我而言,我想独立匹配这两种情况:list member &lt;member_id&gt;list member addresses &lt;member_id&gt;。我不想将这种情况与member_id1:list member member_id1 addresses member_id2 的论点相匹配。你知道如何存档吗?
  • 通常标记的参数更容易与子解析器一起使用。 subparsers 参数是 positionalpositionals 按照设置中定义的顺序进行解析。标记的 (optionals) 按照用户提供的顺序使用。在主解析器和子解析器中使用不同的 dest 也是一个好主意,以避免一个覆盖另一个。
  • 感谢您的重播。我仍在努力寻找独立运行这些命令的最佳方法:list member &lt;member_id&gt;list member addresses &lt;member_id&gt;list members。如果您有任何想法,请告诉我。
猜你喜欢
  • 2014-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-31
  • 1970-01-01
  • 2019-07-21
  • 2015-12-26
  • 2020-05-16
相关资源
最近更新 更多