Python argparse nhóm độc quyền lẫn nhau


88

Những gì tôi cần là:

pro [-a xxx | [-b yyy -c zzz]]

Tôi đã thử điều này nhưng không hoạt động. ai đó có thể giúp tôi không?

group= parser.add_argument_group('Model 2')
group_ex = group.add_mutually_exclusive_group()
group_ex.add_argument("-a", type=str, action = "store", default = "", help="test")
group_ex_2 = group_ex.add_argument_group("option 2")
group_ex_2.add_argument("-b", type=str, action = "store", default = "", help="test")
group_ex_2.add_argument("-c", type=str, action = "store", default = "", help="test")

Cảm ơn!



Đang cắm, nhưng tôi muốn đề cập đến joffrey thư viện của mình . Ví dụ: cho phép bạn làm những gì câu hỏi này muốn mà không bắt bạn phải sử dụng các lệnh con (như trong câu trả lời được chấp nhận) hoặc tự mình xác thực mọi thứ (như trong câu trả lời được bình chọn cao thứ hai).
hallo

Câu trả lời:


109

add_mutually_exclusive_groupkhông làm cho cả một nhóm loại trừ lẫn nhau. Nó làm cho các tùy chọn trong nhóm loại trừ lẫn nhau.

Những gì bạn đang tìm kiếm là các lệnh con . Thay vì prog [-a xxxx | [-b yyy -c zzz]], bạn có:

prog 
  command 1 
    -a: ...
  command 2
    -b: ...
    -c: ...

Để gọi với tập đối số đầu tiên:

prog command_1 -a xxxx

Để gọi với tập đối số thứ hai:

prog command_2 -b yyyy -c zzzz

Bạn cũng có thể đặt các đối số lệnh phụ là vị trí.

prog command_1 xxxx

Kiểu như git hoặc svn:

git commit -am
git merge develop

Ví dụ làm việc

# create the top-level parser
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--foo', action='store_true', help='help for foo arg.')
subparsers = parser.add_subparsers(help='help for subcommand')

# create the parser for the "command_1" command
parser_a = subparsers.add_parser('command_1', help='command_1 help')
parser_a.add_argument('a', type=str, help='help for bar, positional')

# create the parser for the "command_2" command
parser_b = subparsers.add_parser('command_2', help='help for command_2')
parser_b.add_argument('-b', type=str, help='help for b')
parser_b.add_argument('-c', type=str, action='store', default='', help='test')

Kiểm tra nó

>>> parser.print_help()
usage: PROG [-h] [--foo] {command_1,command_2} ...

positional arguments:
  {command_1,command_2}
                        help for subcommand
    command_1           command_1 help
    command_2           help for command_2

optional arguments:
  -h, --help            show this help message and exit
  --foo                 help for foo arg.
>>>

>>> parser.parse_args(['command_1', 'working'])
Namespace(a='working', foo=False)
>>> parser.parse_args(['command_1', 'wellness', '-b x'])
usage: PROG [-h] [--foo] {command_1,command_2} ...
PROG: error: unrecognized arguments: -b x

Chúc may mắn.


Tôi đã đưa họ vào một nhóm tranh luận. Làm cách nào để thêm lệnh phụ trong trường hợp này? Cảm ơn!
Sean

1
Cập nhật mã mẫu. Bạn sẽ không sử dụng các nhóm mà sử dụng các subparsers.
Jonathan

6
Nhưng làm thế nào bạn sẽ làm những gì OP yêu cầu ban đầu? Tôi hiện đang có một tập hợp các tiểu lệnh, nhưng một trong những phụ lệnh không cần có khả năng để lựa chọn giữa[[-a <val>] | [-b <val1> -c <val2>]]
code_dredd

2
Điều này không trả lời câu hỏi vì nó không cho phép bạn thực hiện các lệnh "noname" và đạt được những gì OP yêu cầu[-a xxx | [-b yyy -c zzz]]
The Godfather

34

Mặc dù câu trả lời của Jonathan hoàn toàn ổn đối với các tùy chọn phức tạp, nhưng có một giải pháp rất đơn giản sẽ hoạt động cho các trường hợp đơn giản, ví dụ: 1 tùy chọn loại trừ 2 tùy chọn khác như trong

command [- a xxx | [ -b yyy | -c zzz ]] 

hoặc thậm chí như trong câu hỏi ban đầu:

pro [-a xxx | [-b yyy -c zzz]]

Đây là cách tôi sẽ làm điều đó:

parser = argparse.ArgumentParser()

# group 1 
parser.add_argument("-q", "--query", help="query", required=False)
parser.add_argument("-f", "--fields", help="field names", required=False)

# group 2 
parser.add_argument("-a", "--aggregation", help="aggregation",
                    required=False)

Tôi đang sử dụng ở đây các tùy chọn được cung cấp cho trình bao bọc dòng lệnh để truy vấn mongodb. Cá collectionthể có thể gọi phương thức aggregatehoặc phương thức findvới các đối số tùy chọn queryfieldsdo đó bạn thấy lý do tại sao hai đối số đầu tiên tương thích và đối số cuối cùng thì không.

Vì vậy, bây giờ tôi chạy parser.parse_args()và kiểm tra nội dung của nó:

args = parser().parse_args()

print args.aggregation
if args.aggregation and (args.query or args.fields):
    print "-a and -q|-f are mutually exclusive ..."
    sys.exit(2)

Tất nhiên, thủ thuật nhỏ này chỉ hoạt động đối với những trường hợp đơn giản và sẽ trở thành một cơn ác mộng khi kiểm tra tất cả các tùy chọn khả thi nếu bạn có nhiều tùy chọn và nhóm loại trừ lẫn nhau. Trong trường hợp đó, bạn nên chia nhỏ các tùy chọn của mình thành các nhóm lệnh như Jonathan đã đề xuất.


5
Tôi sẽ không gọi đây là 'hack' cho trường hợp này, vì nó có vẻ dễ đọc và dễ quản lý hơn - cảm ơn bạn đã chỉ ra nó!
sage

13
Một cách tốt hơn sẽ được sử dụng parser.error("-a and -q ..."). Bằng cách này, trợ giúp sử dụng hoàn chỉnh sẽ được in ra tự động.
WGH

Xin lưu ý rằng trong trường hợp này, bạn cũng cần xác thực các trường hợp như: (1) cả hai qfđược yêu cầu trong nhóm đầu tiên là người dùng, (2) một trong hai nhóm là bắt buộc. Và điều này làm cho giải pháp "đơn giản" không còn đơn giản nữa. Vì vậy, tôi đồng ý rằng đây là một cuộc tấn công nhiều hơn cho kịch bản thủ công, nhưng không phải là một giải pháp thực sự
The Godfather

4

Có một bản vá python (đang được phát triển) cho phép bạn thực hiện điều này.
http://bugs.python.org/issue10984

Ý tưởng là cho phép các nhóm chồng chéo loại trừ lẫn nhau. Vì vậy, usagecó thể trông giống như:

pro [-a xxx | -b yyy] [-a xxx | -c zzz]

Thay đổi mã argparse để bạn có thể tạo hai nhóm như thế này là một phần dễ dàng. Thay đổi usagemã định dạng bắt buộc phải viết tùy chỉnh HelpFormatter.

Trong argparse, nhóm hành động không ảnh hưởng đến việc phân tích cú pháp. Chúng chỉ là một helpcông cụ định dạng. Trong các helpnhóm loại trừ lẫn nhau chỉ ảnh hưởng đến usagedòng. Khi phân tích cú pháp, hàm parsersử dụng các nhóm loại trừ lẫn nhau để xây dựng một từ điển về các xung đột tiềm ẩn ( akhông thể xảy ra với bhoặc c, bkhông thể xảy ra với a, v.v.) và sau đó phát sinh lỗi nếu xung đột phát sinh.

Nếu không có bản vá argparse đó, tôi nghĩ lựa chọn tốt nhất của bạn là kiểm tra không gian tên do parse_argschính bạn tạo ra (ví dụ: nếu cả hai abcó giá trị nondefault) và nêu ra lỗi của chính bạn. Bạn thậm chí có thể sử dụng cơ chế lỗi của chính trình phân tích cú pháp.

parser.error('custom error message')

1
Vấn đề Python: bug.python.org/issue11588 đang khám phá các cách cho phép bạn viết các thử nghiệm độc quyền / bao gồm tùy chỉnh.
hpaulj
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.