Visualizzazione del messaggio di aiuto con python argparse quando lo script viene chiamato senza argomenti

StackOverflow https://stackoverflow.com/questions/4042452

  •  27-09-2019
  •  | 
  •  

Domanda

Questo potrebbe essere semplice.Si supponga ho un programma che utilizza argparse al processo di argomenti della riga di comando/opzioni.Segue stampa il messaggio:

./myprogram -h

o:

./myprogram --help

Ma, se ho eseguito lo script senza argomenti, di qualsiasi tipo, non fare nulla.Quello che voglio fare è visualizzare il messaggio d'uso quando viene chiamato senza argomenti.Come si fa?

È stato utile?

Soluzione

Questa risposta arriva da Steven Bethard sui gruppi di Google . Sto reinserire qui per rendere più facile per le persone senza un account Google per accedere.

È possibile ignorare il comportamento predefinito del metodo error:

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

Si noti che la soluzione sopra stamperà il messaggio di aiuto ogni volta che il error il metodo viene attivato. Ad esempio, test.py --blah stamperà il messaggio di aiuto Anche se --blah non è un'opzione valida.

Se si desidera stampare il messaggio di aiuto solo se nessun argomento è sulla linea di comando, allora forse questo è ancora il modo più semplice:

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

Si noti che le stampe parser.print_help() a stdout per default. Come init_js suggerisce , uso parser.print_help(sys.stderr) per stampare a stderr.

Altri suggerimenti

Invece di scrivere una classe, un blocco try / tranne che può essere utilizzato al posto

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

Il vantaggio è che il flusso di lavoro è più chiara e non hai bisogno di una classe stub. Il rovescio della medaglia è che la prima linea di 'utilizzo' viene stampato due volte.

Questo avrà bisogno di almeno un argomento obbligatorio. Senza argomenti obbligatori, fornendo a zero args dalla linea di comando è valido.

Con argparse si potrebbe fare:

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)

Se avete argomenti che devono essere specificate per l'esecuzione di script - utilizzare il richiesto parametro per ArgumentParser come mostrato di seguito:-

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

parse_args() verrà segnalato un errore se lo script viene eseguito senza argomenti.

Se le funzioni predefinite per associare (sotto) parser, come è indicato al add_subparsers , è sufficiente aggiungerlo come l'azione di default:

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

Aggiungi il try-tranne se si alza eccezioni a causa della mancanza argomenti posizionali.

Lanciare la mia versione nel mucchio qui:

import argparse

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

Si può notare il parser.exit - Io principalmente faccio così perché consente di risparmiare una linea di importazione se quella era l'unica ragione per sys nel file ...

La soluzione più pulita sarà quello di passare manualmente argomento di default se nessuno è stata data sulla riga di comando:

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

Esempio completo:

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

Questo stamperà aiuto completo (non a breve utilizzo) se chiamati w / o argomenti.

Ci sono un paio di battute con sys.argv[1:] (linguaggio molto comune di Python per fare riferimento gli argomenti della riga di comando, essendo sys.argv[0] nome dello script), che può fare il lavoro.

La prima si spiega da sé, pulito e divinatorio:

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

Il secondo è un po 'hackier. Combinando il fatto in precedenza valutato che una lista vuota è False con la True == 1 e False == 0 equivalenze si ottiene questo:

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

Forse troppe staffe, ma abbastanza chiaro se una selezione argomento precedente è stata fatta.

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

Il metodo parser.exit accetta anche una status (returncode), e un valore message (includere un ritorno a capo finale da soli!).

un esempio supponente, :)

#!/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

Esempio chiama:

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

 Example argparser based python file

optional arguments:
  -h, --help  show this help message and exit
  --example   Example Argument

I just don't know what went wrong, maybe missing --example condition?
128
$ python3 ~/helloworld.py --example; echo $?
0

Impostare le argomenti posizionali con nargs, e verificare se args posizionali sono vuote.

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

Python nargs

Ecco un altro modo per farlo, se avete bisogno di qualcosa di flessibile, in cui si desidera aiuto display se sono passati params specifici, del tutto assenti o più di 1 arg contrastanti:

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

Cheers!

Se il comando non è qualcosa in cui un utente ha bisogno di scegliere una certa azione, quindi utilizzare un gruppo si escludono a vicenda con required = True .

Questa è una specie di una proroga per la risposta data da pd321.

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

Output:

  

$ python3 a_test.py
  utilizzo: a_test.py [-h] (--batch pay_id | --list | --all)
  a_test.py: errore: uno degli argomenti --batch --list --all è necessario

Questa dare solo l'aiuto di base. E alcune delle altre risposte vi darà l'aiuto completo. Ma almeno gli utenti sanno di poter fare -h

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top