2016-02-12 9 views
14

Mam zestaw argumentów, które mogą być logicznie oddzielone w 2 grupach:argparse: niektóre wzajemnie wykluczające się argumenty wymaganej grupy

  • czynności: A1, A2, A3 itp
  • Informacje: I1, I2, I3 itp

przynajmniej jeden z tych argumentów nie jest wymagane w przypadku program do uruchomienia, ale „informacyjne” args może być używany z „akcji” args. Więc

  • Przynajmniej jeden w działaniach lub Informations jest wymagane
  • Wszystkie działania wzajemnie się wykluczają

nie mogę znaleźć jak to zrobić za pomocą argparse. Wiem o add_mutually_exclusive_group i jego argumencie required, ale nie mogę go użyć w "Actions", ponieważ nie jest on faktycznie wymagany. Oczywiście, mógłbym dodać warunek po argparse, aby ręcznie sprawdzić moje reguły, ale wydaje się, że to hack. Czy argparse może to zrobić?

Edytuj: Przykro nam, oto kilka przykładów.

# Should pass 
--A1 
--I1 
--A1 --I2 
--A2 --I1 --I2 

# Shouldn't pass 
--A1 --A2 
--A1 --A2 --I1 
+1

Czy użytkownik może podać argument informacyjny i czynność? Lub tylko jeden lub drugi. –

+0

Tak, chcę - A1 - I1 - I2 do pracy. – Nil

Odpowiedz

3

Nie ma nic hackowego w sprawdzaniu argumentów po ich przetworzeniu. Wystarczy zebrać je wszystkie w jednym zestawie, a następnie potwierdzić, że nie jest on pusty i zawiera co najwyżej jedną akcję.

actions = {"a1", "a2", "a3"} 
informations = {"i1", "i2", "i3"} 
p = argparse.ArgumentParser() 
# Contents of actions and informations contrived 
# to make the example short. You may need a series 
# of calls to add_argument to define the options and 
# constants properly 
for ai in actions + informations: 
    p.add_argument("--" + ai, action='append_const', const=ai, dest=infoactions) 

args = p.parse_args() 
if not args.infoactions: 
    p.error("At least one action or information required") 
elif len(actions.intersection(args.infoactions)) > 1: 
    p.error("At most one action allowed") 
2

Im ja czegoś brakuje, czy po prostu chcesz:

import argparse 
import os 

def main(): 
    parser = argparse.ArgumentParser() 
    actions = parser.add_mutually_exclusive_group() 
    actions.add_argument("-A1", action="store_true") 
    actions.add_argument("-A2", action="store_true") 
    actions.add_argument("-A3", action="store_true") 
    low = int(os.environ.get('LOWER_BOUNDS', 0)) 
    high = int(os.environ.get('UPPER_BOUNDS', 3)) + 1 
    infos = parser.add_argument_group() 
    for x in range(low, high): 
     infos.add_argument("-I" + str(x), action="store_true") 

    args = parser.parse_args() 
    if not any(vars(args).values()): 
     parser.error('No arguments provided.') 
    print args 

if __name__ == '__main__': 
    main() 

wyjściowa:

$ python test.py 
usage: test.py [-h] [-A1 | -A2 | -A3] [-I0] [-I1] [-I2] [-I3] 
test.py: error: No arguments provided. 
$ python test.py -A1 
Namespace(A1=True, A2=False, A3=False, I1=False, I2=False, I3=False) 
$ python test.py -A1 -A2 
usage: test.py [-h] [-A1 | -A2 | -A3] [-I1] [-I2] [-I3] 
test.py: error: argument -A2: not allowed with argument -A1 
$ python test.py -A1 -I1 
Namespace(A1=True, A2=False, A3=False, I1=True, I2=False, I3=False) 
$ python test.py -A1 -I1 -I2 
Namespace(A1=True, A2=False, A3=False, I1=True, I2=True, I3=False) 
$ python test.py -A1 -I1 -I2 -I3 
Namespace(A1=True, A2=False, A3=False, I1=True, I2=True, I3=True) 
$ UPPER_BOUNDS=40 python test.py -A1 -I1 -I2 -I40 
Namespace(A1=True, A2=False, A3=False, I0=False, I1=True, I10=False, I11=False, I12=False, I13=False, I14=False, I15=False, I16=False, I17=False, I18=False, I19=False, I2=True, I20=False, I21=False, I22=False, I23=False, I24=False, I25=False, I26=False, I27=False, I28=False, I29=False, I3=False, I30=False, I31=False, I32=False, I33=False, I34=False, I35=False, I36=False, I37=False, I38=False, I39=False, I4=False, I40=True, I5=False, I6=False, I7=False, I8=False, I9=False) 

PS. Naprawdę nie sugeruję tego "nieograniczonego" podejścia -I# .. ale tutaj jest to przykład.

+0

Tak, czegoś brakuje, możliwe jest użycie wielu flag informacyjnych. Dodałem to w komentarzu po, przepraszam. Będę edytować mój post. – Nil

+0

@Nil: co znaczy "tyle"? Jak nieskończona ilość po prostu '-I #' gdzie '#' jest tym, czego chce użytkownik? –

+0

@Nil uważam, że mój ostatni przykład, 'python test.py -A1 -I1 -I2 -I3' jest to, czego szukasz –

1

mutually_exclusive_group jest prosty test xor logika. Możesz zdefiniować 2 oddzielne grupy, ale nie zapewnia żadnych środków do pracy pomiędzy grupami.

Pracowałem nad poprawką, aby umożliwić bardziej złożoną logikę i zagnieżdżone grupy. Logika testowania nie jest taka zła, ale zaprojektowanie dobrego interfejsu użytkownika jest trudne, podobnie jak stworzenie znaczącej linii usage. Tak więc ulepszenie prawdopodobnie nigdy nie ujrzy produkcji.

Testowanie argumentów po parsowaniu jest całkowicie dobre. Staje się to trudne tylko wtedy, gdy nie możesz rozróżnić atrybutów od wartości domyślnych i tych, których użyjesz - więc domyślna wartość domyślna to None. argparse to przede wszystkim analizator składni, który określa, czego chce użytkownik. To, czy chcą czegoś legit (poza najprostszymi przypadkami), to inna kwestia.

Powiązane problemy