Mi sembra che ci sia una leggera limitazione con sub_parser in argparse, se si dice che si dispone di una suite di strumenti che potrebbero avere opzioni simili che potrebbero diffondersi a diversi livelli. Potrebbe essere raro avere questa situazione, ma se stai scrivendo codice pluggable/modulare, potrebbe accadere.
Ho il seguente esempio. E 'inverosimile e non ben spiegato in questo momento, perché è piuttosto tardi, ma qui va:
Usage: tool [-y] {a, b}
a [-x] {create, delete}
create [-x]
delete [-y]
b [-y] {push, pull}
push [-x]
pull [-x]
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('-x', action = 'store_true')
parser.add_argument('-y', action = 'store_true')
subparsers = parser.add_subparsers(dest = 'command')
parser_a = subparsers.add_parser('a')
parser_a.add_argument('-x', action = 'store_true')
subparsers_a = parser_a.add_subparsers(dest = 'sub_command')
parser_a_create = subparsers_a.add_parser('create')
parser_a_create.add_argument('-x', action = 'store_true')
parser_a_delete = subparsers_a.add_parser('delete')
parser_a_delete.add_argument('-y', action = 'store_true')
parser_b = subparsers.add_parser('b')
parser_b.add_argument('-y', action = 'store_true')
subparsers_b = parser_b.add_subparsers(dest = 'sub_command')
parser_b_create = subparsers_b.add_parser('push')
parser_b_create.add_argument('-x', action = 'store_true')
parser_b_delete = subparsers_b.add_parser('pull')
parser_b_delete.add_argument('-y', action = 'store_true')
print parser.parse_args(['-x', 'a', 'create'])
print parser.parse_args(['a', 'create', '-x'])
print parser.parse_args(['b', '-y', 'pull', '-y'])
print parser.parse_args(['-x', 'b', '-y', 'push', '-x'])
uscita
Namespace(command='a', sub_command='create', x=True, y=False)
Namespace(command='a', sub_command='create', x=True, y=False)
Namespace(command='b', sub_command='pull', x=False, y=True)
Namespace(command='b', sub_command='push', x=True, y=True)
Come si può vedere, è difficile distinguere dove lungo la catena è stato impostato ogni argomento. Si potrebbe risolvere questo cambiando il nome per ogni variabile. Ad esempio, puoi impostare 'dest' su 'x', 'a_x', 'a_create_x', 'b_push_x', ecc., Ma ciò sarebbe doloroso e difficile da separare.
Un'alternativa sarebbe quella di arrestare ArgumentParser quando raggiunge un sottocomando e passare gli argomenti rimanenti a un altro parser indipendente, in modo che possa generare oggetti separati. Puoi provare a farlo usando 'parse_known_args()' e non definendo argomenti per ogni sottocomando. Tuttavia, ciò non sarebbe positivo perché qualsiasi argomento non analizzato di prima sarebbe ancora presente e potrebbe confondere il programma.
Mi sento un po 'a buon mercato, ma utile soluzione è di avere argparse interpretare i seguenti argomenti come stringhe in una lista. Questo può essere fatto impostando il prefisso su un terminatore null '\ 0' (o qualche altro carattere 'difficile da usare') - se il prefisso è vuoto, il codice genererà un errore, almeno in Python 2.7. 3.
Esempio:
parser = ArgumentParser()
parser.add_argument('-x', action = 'store_true')
parser.add_argument('-y', action = 'store_true')
subparsers = parser.add_subparsers(dest = 'command')
parser_a = subparsers.add_parser('a' prefix_chars = '\0')
parser_a.add_argument('args', type = str, nargs = '*')
print parser.parse_args(['-xy', 'a', '-y', '12'])
uscita:
Namespace(args=['-y', '12'], command='a', x=True, y=True)
Nota che non consuma la seconda opzione -y
. È quindi possibile passare il risultato 'args' a un altro ArgumentParser.
Svantaggi:
- Aiuto non potrebbero essere gestiti bene. Occorrerebbe fare qualche altra soluzione con questo
- Incontrare gli errori potrebbe essere difficile da rintracciare e richiedere qualche sforzo aggiuntivo per assicurarsi che i messaggi di errore siano correttamente concatenati.
- Un po 'più di overhead associato a più ArgumentParsers.
Se qualcuno ha più input su questo, per favore fatemelo sapere.
L'azienda per cui sto lavorando per ha una linea di base in modo da utilizzare v2.6 argparse è un problema in quanto avrebbe dovuto essere incluso come una libreria esterna e caricato solo se necessario. Lontano da impossibile, semplicemente non ideale. Per quanto riguarda la libreria cmdln, mi dà un bel po 'di funzionalità di base che preferirei non ricreare. Detto questo, sono contrario a usare qualcos'altro. – tima