Komut dosyası herhangi bir argüman olmadan çağrıldığında python argparse ile yardım mesajını göster


227

Bu basit olabilir. Komut satırı bağımsız değişkenlerini / seçeneklerini işlemek için argparse kullanan bir programım olduğunu varsayalım. Aşağıdakiler 'yardım' mesajını yazdıracaktır:

./myprogram -h

veya:

./myprogram --help

Ancak, senaryoyu herhangi bir argüman olmadan çalıştırırsam, hiçbir şey yapmaz. Ne yapmak istiyorum argüman olmadan çağrıldığında kullanım iletisi görüntülemek için. Bu nasıl yapılır?

Yanıtlar:


273

Bu cevap Google gruplarındaki Steven Bethard'dan geliyor . Google hesabı olmayan kişilerin erişimini kolaylaştırmak için burada yeniden gönderiyorum.

errorYöntemin varsayılan davranışını geçersiz kılabilirsiniz :

import argparse
import sys

class MyParser(argparse.ArgumentParser):
    def error(self, message):
        sys.stderr.write('error: %s\n' % message)
        self.print_help()
        sys.exit(2)

parser = MyParser()
parser.add_argument('foo', nargs='+')
args = parser.parse_args()

Yukarıdaki çözümün, error yöntem her tetiklendiğinde yardım mesajını yazdıracağını unutmayın . Örneğin, geçerli bir seçenek test.py --blahdeğilse yardım iletisini de yazdıracaktır --blah.

Yardım iletisini yalnızca komut satırında herhangi bir bağımsız değişken sağlanmadığında yazdırmak istiyorsanız, belki de bu en kolay yoldur:

import argparse
import sys

parser=argparse.ArgumentParser()
parser.add_argument('foo', nargs='+')
if len(sys.argv)==1:
    parser.print_help(sys.stderr)
    sys.exit(1)
args=parser.parse_args()

parser.print_help()Varsayılan olarak stdout'a yazdırıldığını unutmayın . İnit_js'nin önerdiği gibi stderr'eparser.print_help(sys.stderr) yazdırmak için kullanın .


Evet, bu senaryoyu ele almak için argparse için bir yol olup olmadığı merak ediyorum. Teşekkürler!
musashiXXX

6
parser.print_usage()Yerine kullandığım ikinci çözümde parser.print_help()- yardım mesajı kullanımı içerir, ancak daha ayrıntılıdır.
user2314737

5
Cevabın ikinci kısmı için oy verirdim, ama geçersiz kılmak error()benim için korkunç bir fikir gibi görünüyor. Farklı bir amaca hizmet eder, kolay kullanım veya yardım yazdırmak için tasarlanmamıştır.
Peterino

@Peterino - geçersiz kılma bir alt sınıfta gerçekleşiyor, bu yüzden bu bir sorun olmamalı. Açıktır.
Marcel Wilson

1
@unutbu HARİKA! Tam olarak ihtiyacım olan şey. Bir soru, bu alt komutlara da uygulanabilir mi? Genellikle `` Ad Alanı (çıktı = Yok) '' alırım. TÜM alt komutlarda bir hatayı kolayca nasıl tetikleyebilirim? Orada bir hata tetiklemek istiyorum.
Jonathan Komar

56

Sınıf yazmak yerine, bunun yerine bir try / hariç kullanılabilir

try:
    options = parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

Tersi, iş akışının daha net olması ve bir saplama sınıfına ihtiyacınız olmamasıdır. Dezavantajı, ilk 'kullanım' çizgisinin iki kez basılmasıdır.

Bunun en az bir zorunlu argümana ihtiyacı olacaktır. Zorunlu bağımsız değişken olmadan, komut satırında sıfır bağımsız değişken sağlamak geçerlidir.


ben de bunu kabul edilen cevaba tercih ederim. Bağımsız değişkenler beklenmedik olduğunda yazdırma eklemek için sınıf eklemek aşırıya kaçmıştır. Mükemmel modül argparse hata durumlarını sizin için halletsin.
Nicole Finnie

7
Bu kod, -hbayrak kullanılırsa 2 kez yardımcı olur ve bayrak kullanılırsa gereksiz baskılar yardımcı olur --version. Bu sorunları azaltmak için aşağıdaki gibi hata türünü kontrol edebilirsiniz:except SystemExit as err: if err.code == 2: parser.print_help()
pkowalczyk

25

Argparse ile şunları yapabilirsiniz:

parser.argparse.ArgumentParser()
#parser.add_args here

#sys.argv includes a list of elements starting with the program
if len(sys.argv) < 2:
    parser.print_usage()
    sys.exit(1)

5
Bu çağrıdan önce gelmeliparser.parse_args()
Bob Stein

18

Komut dosyasının çalışması için belirtilmesi gereken bağımsız değişkenleriniz varsa - ArgumentParser için gerekli parametreyi aşağıda gösterildiği gibi kullanın: -

parser.add_argument('--foo', required=True)

komut dosyası bağımsız değişkenler olmadan çalıştırılırsa parse_args () bir hata bildirir.


2
Bu en basit çözümdür ve belirtilen geçersiz seçeneklerle de çalışır.
Steve Scherer

1
Kabul. Bence, argüman ayrıştırıcısının yerleşik yeteneklerinden yararlanmak ve daha sonra bir tür ek işleyici yazmak her zaman daha iyidir.
Christopher Hunter

18

(Alt) ayrıştırıcılar için varsayılan işlevleri, aşağıda belirtildiği add_subparsersgibi ilişkilendirirseniz, varsayılan eylem olarak ekleyebilirsiniz:

parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)

Eksik konumsal argümanlar nedeniyle istisnalar ortaya çıkarırsanız try-hariç ekleyin.


1
Bu cevap çok küçümseniyor. Basit ve alt ayrıştırıcılarla çok iyi çalışır.
orodbhen

Mükemmel cevap! Yaptığım tek değişiklik parametresiz bir lambda kullanmaktı.
boh717

12

En temiz çözüm, komut satırında hiçbiri verilmemişse varsayılan bağımsız değişkeni elle geçirmek olacaktır:

parser.parse_args(args=None if sys.argv[1:] else ['--help'])

Komple örnek:

import argparse, sys

parser = argparse.ArgumentParser()
parser.add_argument('--host', default='localhost', help='Host to connect to')
# parse arguments
args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])

# use your args
print("connecting to {}".format(args.host))

Bu, argüman olmadan çağrılırsa tam yardım (kısa kullanım değil) yazdırır.


2
sys.argv[1:]çok yaygın bir deyimdir. parser.parse_args(None if sys.argv[1:] else ['-h'])Daha deyimsel ve temiz görüyorum .
Nuno André

1
@ NunoAndré teşekkürler - cevabı güncelledi. Gerçekten daha pitonik geliyor.
Ievgen Popovych

10

Sürümümü buraya yığına atmak:

import argparse

parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
    parser.print_help()
    parser.exit(1)

Fark edebilirsiniz parser.exit- Ben esas olarak böyle yapmak çünkü bu sysdosyada tek nedeni olsaydı bir ithalat hattı kaydeder ...


parser.exit (1) güzel! İyi bir ek.
cgseller

4
Maalesef konumsal bir argüman eksikse parser.parse_args () çıkacaktır. Bu sadece isteğe bağlı argümanlar kullanırken işe yarar.
Marcel Wilson

1
@MarcelWilson, gerçekten de öyle - iyi yakalama! Bunu nasıl değiştireceğimi düşüneceğim.
pauricthelodger

not vars(args)bağımsız değişkenler defaultyöntemi olduğunda çalışmaz .
funkid

5

İşi yapabilen bir çift tek sys.argv[1:]satır sys.argv[0](komut dosyasının adı olan komut satırı argümanlarına atıfta bulunmak için çok yaygın bir Python deyimi ) vardır.

Birincisi açıklayıcı, temiz ve pitonik:

args = parser.parse_args(None if sys.argv[1:] else ['-h'])

İkincisi biraz hackier. Boş bir liste olduğunu daha önce değerlendirilen gerçeği birleştiren Falseile True == 1ve False == 0bunu elde DENKLİĞİ:

args = parser.parse_args([None, ['-h']][not sys.argv[1:]])

Belki çok fazla parantez, ancak daha önce bir argüman seçimi yapılmışsa oldukça açıktır.

_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])

1
parser.print_help()
parser.exit()

parser.exitYöntem aynı zamanda bir kabul status(dönüş kodu) ve bir messagedeğer (bir eğik yeni satır kendin dahil!).

düşünülmüş bir örnek, :)

#!/usr/bin/env python3

""" Example argparser based python file
"""

import argparse

ARGP = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawTextHelpFormatter,
)
ARGP.add_argument('--example', action='store_true', help='Example Argument')


def main(argp=None):
    if argp is None:
        argp = ARGP.parse_args()  # pragma: no cover

    if 'soemthing_went_wrong' and not argp.example:
        ARGP.print_help()
        ARGP.exit(status=128, message="\nI just don't know what went wrong, maybe missing --example condition?\n")


if __name__ == '__main__':
    main()  # pragma: no cover

Örnek çağrılar:

$ python3 ~ / helloworld.py; echo $?
kullanım: helloworld.py [-h] [--example]

 Örnek argparser tabanlı python dosyası

isteğe bağlı argümanlar:
  -h, --help bu yardım mesajını göster ve çık
  --example Örnek Bağımsız Değişken

Neyin yanlış gittiğini bilmiyorum, belki eksik - örnek durum?
128
$ python3 ~ / helloworld.py --örnek; echo $?
0

0

Konumsal bağımsız değişkenlerinizi parantez içinde ayarlayın ve konumsal bağımsız değişkenlerin boş olup olmadığını kontrol edin.

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
    parser.print_help()

Referans Python anlatımları


0

İşte bunu yapmanın başka bir yolu, eğer belirli parametreler geçilirse yardım görüntülemek istediğiniz esnek bir şeye ihtiyacınız varsa, hiçbiri veya 1'den fazla çakışan arg.

import argparse
import sys

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--days', required=False,  help="Check mapped inventory that is x days old", default=None)
    parser.add_argument('-e', '--event', required=False, action="store", dest="event_id",
                        help="Check mapped inventory for a specific event", default=None)
    parser.add_argument('-b', '--broker', required=False, action="store", dest="broker_id",
                        help="Check mapped inventory for a broker", default=None)
    parser.add_argument('-k', '--keyword', required=False, action="store", dest="event_keyword",
                        help="Check mapped inventory for a specific event keyword", default=None)
    parser.add_argument('-p', '--product', required=False, action="store", dest="product_id",
                        help="Check mapped inventory for a specific product", default=None)
    parser.add_argument('-m', '--metadata', required=False, action="store", dest="metadata",
                        help="Check mapped inventory for specific metadata, good for debugging past tix", default=None)
    parser.add_argument('-u', '--update', required=False, action="store_true", dest="make_updates",
                        help="Update the event for a product if there is a difference, default No", default=False)
    args = parser.parse_args()

    days = args.days
    event_id = args.event_id
    broker_id = args.broker_id
    event_keyword = args.event_keyword
    product_id = args.product_id
    metadata = args.metadata
    make_updates = args.make_updates

    no_change_counter = 0
    change_counter = 0

    req_arg = bool(days) + bool(event_id) + bool(broker_id) + bool(product_id) + bool(event_keyword) + bool(metadata)
    if not req_arg:
        print("Need to specify days, broker id, event id, event keyword or past tickets full metadata")
        parser.print_help()
        sys.exit()
    elif req_arg != 1:
        print("More than one option specified. Need to specify only one required option")
        parser.print_help()
        sys.exit()

    # Processing logic here ...

Şerefe!


Ben subparsers veya mutually_exclusive_group kullanmak çok daha kolay olacağını düşünüyorum
Tim Bray

0

Komutunuz, kullanıcının bir eylem seçmesi gereken bir şeyse , required = True ile karşılıklı olarak ayrı bir grup kullanın .

Bu, pd321 tarafından verilen cevabın bir uzantısıdır.

import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--batch", action='store', type=int,  metavar='pay_id')
group.add_argument("--list", action='store_true')
group.add_argument("--all", action='store_true', help='check all payments')

args=parser.parse_args()

if args.batch:
    print('batch {}'.format(args.batch))

if args.list:
    print('list')

if args.all:
    print('all')

Çıktı:

$ python3 a_test.py
usage: a_test.py [-h] (--batch pay_id | --list | --all)
a_test.py: hata: bağımsız değişkenlerden biri --batch --list --all gerekli

Bu sadece temel yardımı verir. Ve diğer bazı cevaplar size tam yardımı verecektir. Ama en azından kullanıcıların yapabilecekleri biliyorum -h


0

Bu iyi değil (ayrıca, tüm hataları kestiği için), ancak:

def _error(parser):
    def wrapper(interceptor):
        parser.print_help()

        sys.exit(-1)

    return wrapper

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error(parser)

    parser.add_argument(...)
    ...

İşte sınıfın errorfonksiyonunun tanımı ArgumentParser:

https://github.com/python/cpython/blob/276eb67c29d05a93fbc22eea5470282e73700d20/Lib/argparse.py#L2374

. Gördüğünüz gibi, imzayı takiben iki argüman alıyor. Ancak, sınıf dışındaki işlevler ilk argüman hakkında hiçbir şey bilmez: selfçünkü kabaca konuşmak gerekirse, bu sınıf için bir parametredir. Böylece, sadece kendi pass (ı ... bildiğine göre, biliyorum) selfve messagede _error(...)(olamaz

def _error(self, message):
    self.print_help()

    sys.exit(-1)

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error
    ...
...

çıktı olacak:

...
"AttributeError: 'str' object has no attribute 'print_help'"

). İşlevde parser( self) _errorişlevini çağırarak iletebilirsiniz :

def _error(self, message):
    self.print_help()

    sys.exit(-1)

def _args_get(args=sys.argv[1:]):
    parser = argparser.ArgumentParser()

    parser.error = _error(parser)
    ...
...

, ancak şu anda programdan çıkmak istemiyorsunuz. Sonra iade et:

def _error(parser):
    def wrapper():
        parser.print_help()

        sys.exit(-1)

    return wrapper
...

. Bununla birlikte, parserdeğiştirildiğini bilmiyor, bu nedenle bir hata oluştuğunda, bunun nedenini gönderecek (bu arada, yerelleştirilmiş çevirisi). Peki, o zaman kesiş:

def _error(parser):
    def wrapper(interceptor):
        parser.print_help()

        sys.exit(-1)

    return wrapper
...

. Şimdi, hata oluştuğunda ve parserbunun nedenini göndereceği zaman, onu kesecek, şuna bakacak ve ... atacaksınız.

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.