Python argparse karşılıklı özel grup


92

İhtiyacım olan şey:

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

Bunu denedim ama çalışmıyor. Biri bana yardım edebilir mi?

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

Teşekkürler!



Tıkalıyor, ama kütüphanem joffrey'den bahsetmek istedim . Örneğin, alt komutları kullanmanıza (kabul edilen cevapta olduğu gibi) veya her şeyi kendiniz doğrulamanıza (ikinci en yüksek oyu alan yanıtta olduğu gibi) yaptırmadan bu sorunun istediğini yapmanıza izin verir.
hallo

Yanıtlar:


110

add_mutually_exclusive_groupbütün bir grubu karşılıklı olarak dışlamaz. Grup içindeki seçenekleri karşılıklı olarak dışlar.

Aradığınız şey alt komutlar . Prog yerine [-a xxxx | [-b yyy -c zzz]], şunları yaparsınız:

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

İlk bağımsız değişken kümesiyle çağırmak için:

prog command_1 -a xxxx

İkinci argüman kümesiyle çağırmak için:

prog command_2 -b yyyy -c zzzz

Ayrıca alt komut argümanlarını konumsal olarak da ayarlayabilirsiniz.

prog command_1 xxxx

Bir çeşit git veya svn gibi:

git commit -am
git merge develop

Çalışma Örneği

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

Dene

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

İyi şanslar.


Onları zaten bir argüman grubuna koydum. Bu durumda nasıl alt komut ekleyebilirim? Teşekkürler!
Sean

1
Örnek kod ile güncellendi. Grupları değil alt ayrıştırıcıları kullanacaksınız.
Jonathan

7
Fakat OP'nin başlangıçta sorduğu şeyi nasıl yapardınız? Şu anda bir dizi alt [[-a <val>] | [-b <val1> -c <val2>]]
komutum var

3
Bu soruya cevap vermiyor çünkü "isimsiz" komutlar vermenize ve OP'nin istediği şeyi elde etmenize izin vermiyor[-a xxx | [-b yyy -c zzz]]
The Godfather

38

Jonathan'ın cevabı karmaşık seçenekler için mükemmel olsa da , basit durumlarda işe yarayacak çok basit bir çözüm var, örneğin 1 seçenek aşağıdaki gibi diğer 2 seçeneği hariç tutuyor

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

hatta orijinal soruda olduğu gibi:

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

İşte bunu nasıl yapacağım:

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)

Burada bir mongodb'u sorgulamak için bir komut satırı sarmalayıcısına verilen seçenekleri kullanıyorum. collectionÖrneği ya yöntemini çağırabilirsiniz aggregateveya yöntemi findisteğe bağlı argümanları ile queryve fieldsilk iki argüman uyumludur ve sonuncusu değil neden dolayısıyla Gördüğünüz.

Şimdi koşuyorum parser.parse_args()ve içeriğini kontrol ediyorum :

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)

Tabii ki, bu küçük hack sadece basit durumlar için çalışıyor ve birbirini dışlayan birçok seçeneğiniz ve grubunuz varsa, tüm olası seçenekleri kontrol etmek bir kabusa dönüşür. Bu durumda seçeneklerinizi Jonathan'ın önerdiği gibi komut gruplarına ayırmalısınız.


5
Hem daha okunabilir hem de yönetilebilir göründüğü için, bu vaka için buna 'hack' demezdim - bunu belirttiğiniz için teşekkürler!
sage

16
Daha da iyi bir yol kullanmaktır parser.error("-a and -q ..."). Bu şekilde tam kullanım yardımı otomatik olarak yazdırılacaktır.
WGH

Bu durumda da benzeri durumlarda doğrulamak için ihtiyaç duyacağı Lütfen not: (1) her iki qve fbirinci gruptaki gerekli olan kullanıcı, (2) ya grupların yeterlidir. Bu da "basit" çözümü artık o kadar basit hale getirmiyor. Bu yüzden bunun el yapımı senaryo için daha fazla hack olduğunu kabul ediyorum, ancak gerçek bir çözüm değil
The Godfather

4

Bunu yapmanıza izin verecek bir python yaması (geliştirme aşamasında) var.
http://bugs.python.org/issue10984

Buradaki fikir, birbiriyle örtüşen, birbirini dışlayan gruplara izin vermektir. Yani usageşöyle görünebilir:

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

Bunun gibi iki grup oluşturabilmek için argparse kodunu değiştirmek işin kolay kısmıydı. usageBiçimlendirme kodunu değiştirmek bir özel yazmayı gerektiriyordu HelpFormatter.

İçinde argparseeylem grupları ayrıştırmayı etkilemez. Onlar sadece bir helpbiçimlendirme aracıdır. Olarak help, birbirini dışlayan gruplar yalnızca etkiler usagehattı. Çözümlenirken, kullanıcı parserpotansiyel çatışmaların bir sözlük (inşa etmek dışlayan gruplarını kullanır aile oluşamaz bveya c, bortaya olamaz a, vs) ve sonra bir çakışma ortaya çıkarsa bir hata yükseltir.

Bu argparse yaması olmadan, en iyi seçeneğinizin kendi ürettiğiniz ad alanını test etmek olduğunu düşünüyorum parse_args(örneğin her ikisi de ave bvarsayılan olmayan değerlere sahipse ) ve kendi hatanızı artırın . Ayrıştırıcının kendi hata mekanizmasını bile kullanabilirsiniz.

parser.error('custom error message')

1
Python sorunu: bugs.python.org/issue11588 , özel dışlayıcı / kapsamlı testler yazmanıza izin vermenin yollarını araştırıyor.
hpaulj
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.