Argparse: argomenti richiesti elencati in "argomenti opzionali"?


229

Uso il seguente semplice codice per analizzare alcuni argomenti; si noti che uno di questi è richiesto. Sfortunatamente, quando l'utente esegue lo script senza fornire l'argomento, il testo di utilizzo / aiuto visualizzato non indica che esiste un argomento non facoltativo, che trovo molto confuso. Come posso ottenere Python per indicare che un argomento non è facoltativo?

Ecco il codice:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Foo')
    parser.add_argument('-i','--input', help='Input file name', required=True)
    parser.add_argument('-o','--output', help='Output file name', default="stdout")
    args = parser.parse_args()
    print ("Input file: %s" % args.input )
    print ("Output file: %s" % args.output )

Quando eseguo il codice sopra senza fornire l'argomento richiesto, ottengo il seguente output:

usage: foo.py [-h] -i INPUT [-o OUTPUT]

Foo

optional arguments:
    -h, --help            show this help message and exit
    -i INPUT, --input INPUT
                          Input file name
    -o OUTPUT, --output OUTPUT
                          Output file name

5
Nella riga di utilizzo, la -i INPUTparte non è racchiusa tra parentesi quadre, la quale sottigliezza indica che è effettivamente necessaria. Inoltre, si può spiegare manualmente che tramite il helpparam
Jaime RGP

7
@JaimeRGP Sì, ma questo non è sufficiente, ovviamente, ed è anche meno che prominente. Il nome del gruppo assegnato optional argumentsper gli argomenti richiesti è ancora fuorviante.
Acumenus,

Risposte:


316

I parametri che iniziano con -o --sono generalmente considerati opzionali. Tutti gli altri parametri sono parametri posizionali e come tali richiesti dalla progettazione (come gli argomenti delle funzioni posizionali). È possibile richiedere argomenti opzionali, ma questo è un po 'contrario al loro design. Poiché fanno ancora parte degli argomenti non posizionali, saranno comunque elencati sotto l'intestazione confusa "argomenti opzionali" anche se richiesti. Le parentesi quadre mancanti nella parte di utilizzo mostrano tuttavia che sono effettivamente richieste.

Vedi anche la documentazione :

In generale, il modulo argparse presuppone che flag come -f e --bar indicano argomenti opzionali, che possono sempre essere omessi dalla riga di comando.

Nota: le opzioni richieste sono generalmente considerate in cattive condizioni perché gli utenti si aspettano che le opzioni siano facoltative e quindi dovrebbero essere evitate quando possibile.

Detto questo, le intestazioni "argomenti posizionali" e "argomenti opzionali" nella guida sono generati da due gruppi di argomenti in cui gli argomenti vengono automaticamente separati. Ora, potresti "hackerarlo" e cambiare il nome di quelli opzionali, ma una soluzione molto più elegante sarebbe quella di creare un altro gruppo per "argomenti nominativi richiesti" (o come vuoi chiamarli):

parser = argparse.ArgumentParser(description='Foo')
parser.add_argument('-o', '--output', help='Output file name', default='stdout')
requiredNamed = parser.add_argument_group('required named arguments')
requiredNamed.add_argument('-i', '--input', help='Input file name', required=True)
parser.parse_args(['-h'])
usage: [-h] [-o OUTPUT] -i INPUT

Foo

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Output file name

required named arguments:
  -i INPUT, --input INPUT
                        Input file name

Ho avuto lo stesso problema. Ho provato la tua soluzione. Aggiunge gli argomenti al nuovo gruppo ma il mio codice non sembra funzionare dopo. Qualsiasi soluzione sarebbe apprezzata. Link al mio codice - pastebin.com/PvC2aujz
Zarar Mahmud

1
@ZararMahmud: stai passando argomenti vuoti nella riga 24 del tuo codice: parser.parse_args([])usa invece parser.parse_args()senza argomenti per acquisire il contenuto di sys.argv. Per argparse
Devin,

@poke: bella soluzione! Ma questo non aiuta nel caso abbiate bisogno di gruppi esclusivi reciproci o mi manchi qualcosa?
Giudice

@Judge consiglierei di leggere questo pymotw.com/3/argparse/#mutually-exclusive-options
Peter Moore

79

Dal momento che preferisco elencare gli argomenti richiesti prima dell'opzione facoltativa, ci circolo tramite:

    parser = argparse.ArgumentParser()
    parser._action_groups.pop()
    required = parser.add_argument_group('required arguments')
    optional = parser.add_argument_group('optional arguments')
    required.add_argument('--required_arg', required=True)
    optional.add_argument('--optional_arg')
    return parser.parse_args()

e questo produce:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
               [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  --optional_arg OPTIONAL_ARG

Posso vivere senza "aiuto" che compare nel gruppo di argomenti facoltativi.


3
Questo obbliga davvero Argparse a trattare gli argomenti come richiesto?
Anthony,

6
Penso che l'argomento 'richiesto' debba ancora essere impostato quando si aggiunge un argomento.
Karl Rosaen,

È molto carino.
Paul Cezanne,

7
@Anthony - no, per questo è necessario 'richiesto = Vero' in add_argument. La risposta sopra illustra solo il raggruppamento di argomenti.
user2275693,

47

Costruito fuori da @Karl Rosaen

parser = argparse.ArgumentParser()
optional = parser._action_groups.pop() # Edited this line
required = parser.add_argument_group('required arguments')
# remove this line: optional = parser...
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')
parser._action_groups.append(optional) # added this line
return parser.parse_args()

e questo produce:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

1
A proposito, ci sono modi (metodi) come accedere _action_groupsenza accedere al membro protetto? Nel mio caso, devo aggiungere qualche argomento al gruppo (personalizzato) già esistente.
machin,

Questo è fantastico Risolve l'elemento --help che compare in un secondo elenco opzionale.
Jeremy,

Nota : questa risposta rompe l'API esposta, controlla la risposta di Bryan_D in basso.
lol

18

Ancora una volta, partendo da @RalphyZ

Questo non rompe l'API esposta.

from argparse import ArgumentParser, SUPPRESS
# Disable default help
parser = ArgumentParser(add_help=False)
required = parser.add_argument_group('required arguments')
optional = parser.add_argument_group('optional arguments')

# Add back help 
optional.add_argument(
    '-h',
    '--help',
    action='help',
    default=SUPPRESS,
    help='show this help message and exit'
)
required.add_argument('--required_arg', required=True)
optional.add_argument('--optional_arg')

Che mostrerà lo stesso sopra e dovrebbe sopravvivere alle versioni future:

usage: main.py [-h] [--required_arg REQUIRED_ARG]
           [--optional_arg OPTIONAL_ARG]

required arguments:
  --required_arg REQUIRED_ARG

optional arguments:
  -h, --help                    show this help message and exit
  --optional_arg OPTIONAL_ARG

Puoi spiegare come la risposta di RalphyZ rompe l'API esposta?
jeremysprofile,

5
_action_groupsè destinato esclusivamente ad uso interno. Pertanto, non esiste alcuna garanzia di compatibilità tra le versioni.
Bryan_D,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.