Does argparse supporto (python) reciprocamente gruppi esclusivi di argomenti?

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

  •  22-10-2019
  •  | 
  •  

Domanda

Se ho la '-a', '-b', '-c', '-d' argomenti, con la funzione di add_mutually_exclusive_group() mio programma dovrà utilizzare solo uno di loro. C'è un modo per combinare che, in modo che il programma accetterà solo uno o '-a 999 -b 999' '-c 999 -d 999'?

Modifica l'aggiunta di un semplice programma per maggiore chiarezza:

>>> parser = argparse.ArgumentParser()
>>> group = parser.add_mutually_exclusive_group()
>>> group.add_argument('-a')
>>> group.add_argument('-b')
>>> group.add_argument('-c')
>>> group.add_argument('-d')

Poi solo ./app.py -a | ./app.py -b | ./app.py -c | ./app.py -d può essere chiamato. E 'possibile avere gruppo argparse i gruppi di esclusione, in modo che solo ./app.py -a .. -b .. | ./app.py -c .. -d .. essere chiamato?

È stato utile?

Soluzione

Modifica : Mai mente. Perché argparse fa la scelta orribile di dover creare un'opzione quando si richiama group.add_argument. Non sarebbe la mia scelta di design. Se siete disperati per questa funzione, si può provare a farlo con ConflictsOptionParser :

# exclusivegroups.py
import conflictsparse

parser = conflictsparse.ConflictsOptionParser()
a_opt = parser.add_option('-a')
b_opt = parser.add_option('-b')
c_opt = parser.add_option('-c')
d_opt = parser.add_option('-d')

import itertools
compatible_opts1 = (a_opt, b_opt)
compatible_opts2 = (c_opt, d_opt)
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
    parser.register_conflict(exclusive_grp)


opts, args = parser.parse_args()
print "opts: ", opts
print "args: ", args

Così, quando invochiamo esso, possiamo vedere si ottiene l'effetto desiderato.

$ python exclusivegroups.py -a 1 -b 2
opts:  {'a': '1', 'c': None, 'b': '2', 'd': None}
args:  []
$ python exclusivegroups.py -c 3 -d 2
opts:  {'a': None, 'c': '3', 'b': None, 'd': '2'}
args:  []
$ python exclusivegroups.py -a 1 -b 2 -c 3
Usage: exclusivegroups.py [options]

exclusivegroups.py: error: -b, -c are incompatible options.

Il messaggio di avviso non si informa che sia '-a' e '-b' sono incompatibili con '-c', comunque un messaggio di errore più appropriata potrebbe essere realizzato. Più vecchio, risposta sbagliata sotto.

Modifica ANZIANI: [? Questa modifica è sbagliato, anche se non sarebbe solo un mondo perfetto se argparse lavorato in questo modo] La mia risposta precedente in realtà non era corretta, si dovrebbe essere in grado di fare questo con argparse specificando un gruppo per le opzioni si escludono a vicenda. Possiamo anche usare itertools di generalizzare il processo. E fare in modo che non c'è bisogno di digitare tutte le combinazioni in modo esplicito:

import itertools
compatible_opts1 = ('-a', '-b')
compatible_opts2 = ('-c', '-d')
exclusives = itertools.product(compatible_opts1, compatible_opts2)
for exclusive_grp in exclusives:
    group = parser.add_mutually_exclusive_group()
    group.add_argument(exclusive_grp[0])
    group.add_argument(exclusive_grp[1])

Altri suggerimenti

Proprio imbattuti in questo problema io stesso. Dalla mia lettura dei documenti argparse, non sembra essere un modo semplice per raggiungere questo obiettivo entro argparse. Ho considerato utilizzando parse_known_args, ma che presto ammonta a scrivere una versione speciale-scopo di argparse ;-)

Forse una segnalazione di bug è in ordine. Nel frattempo, se siete disposti a fare l'utente fare un pochino di battitura in più, si può fingere con sottogruppi (come come git e gli argomenti di lavoro svn), ad esempio,

    subparsers = parser.add_subparsers()
    p_ab = subparsers.add_parser('ab')
    p_ab.add_argument(...)

    p_cd = subparsers.add_parser('cd')
    p_cd.add_argument(...)

Non è l'ideale, ma almeno ti dà il bene dal argparse senza troppo brutto aggiustamenti. Ho finito per fare via con gli interruttori e usando solo le operazioni subparser con subarguments richieste.

Subparsers?

Simile a unhammer 's risposta, ma con più controllo utente. Nota:. Non ho effettivamente testato questo metodo, ma dovrebbe funzionare in teoria e con le funzionalità di python

È possibile creare due parser, uno per ciascuno dei due gruppi, e utilizzare condizionali per fare la parte escludono a vicenda. Essenzialmente usando argparse solo per una parte del parsing argomento. Utilizzando questo metodo, si può andare oltre i limiti di unhammer 's risposta pure.

# Python 3
import argparse

try:
    parser = argparse.ArgumentParser()
    parser.add_argument('-a')
    parser.add_argument('-b')
    args = parser.parse_args
except argparse.ArgumentError:
    parser = argparse.ArgumentParser()
    parser.add_argument('-c')
    parser.add_argument('-d')
    args = parser.parse_args
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top