Frage Python argparse: Kombinieren Sie optionale Parameter mit nargs = argparse.REMAINDER


Ich muss etwas Offensichtliches vermissen. Das Ziel besteht darin, argparse mit dem ersten erforderlichen Parameter, einem zweiten optionalen Parameter und allen anderen verbleibenden optionalen Parametern zu verwenden.

Um das Problem zu zeigen, habe ich zwei Test-Parser gemacht; Der einzige Unterschied zwischen ihnen ist die Verwendung von nargs = argparse.REMAINDER in der einen und nargs = '*' in der anderen.

def doParser1(argsin):
    parser = argparse.ArgumentParser(description='Parser demo.')
    parser.add_argument('req1', help='first required parameter')
    parser.add_argument('--opt1', help='first optional parameter')
    parser.add_argument('leftovers', nargs=argparse.REMAINDER,
                    help='all the other parameters')
    argsout = parser.parse_args(args=argsin)
    print argsout
    return argsout

def doParser2(argsin):
    parser = argparse.ArgumentParser(description='Parser demo.')
    parser.add_argument('req1', help='first required parameter')
    parser.add_argument('--opt1', help='first optional parameter')
    parser.add_argument('leftovers', nargs='*',
                    help='all the other parameters')
    argsout = parser.parse_args(args=argsin)
    print argsout
    return argsout

Wenn keine zusätzlichen Parameter vorhanden sind, arbeitet Parser2. Dies ist die Eingabe gefolgt von Parser1 und Parser 1:

input: ['req1value', '--opt1', 'opt1value']
Namespace(leftovers=['--opt1', 'opt1value'], opt1=None, req1='req1value')
Namespace(leftovers=None, opt1='opt1value', req1='req1value')

Wenn es zusätzliche Parameter gibt, wird der Wert von opt1 in Parser1 übersehen und Parser2 wird nur verwirrt:

input: ['req1value', '--opt1', 'opt1value', 'r1', 'r2']
Namespace(leftovers=['--opt1', 'opt1value', 'r1', 'r2'], opt1=None, req1='req1value')
usage: py-argparse.py [-h] [--opt1 OPT1]
                  [-leftovers [LEFTOVERS [LEFTOVERS ...]]]
                  req1
py-argparse.py: error: unrecognized arguments: r1 r2

Die erwartete Ausgabe sollte sein:

Namespace(leftovers=['r1', 'r2'], opt1='opt1value', req1='req1value')

Es scheint, dass dies ein einfacher Fall sein sollte und was hier ist, ist vereinfacht von dem, was ich wirklich versuche zu tun. Ich habe versucht, Reste optional zu machen und eine Vielzahl anderer Optionen hinzuzufügen, aber nichts funktioniert besser.

Jede Hilfe wäre willkommen.


8
2017-09-04 20:03


Ursprung


Antworten:


--opt1 muss vor "unbenannten" Argumenten stehen. Ihre echten Testfälle sollten sein:

    ['--opt1', 'opt1value', 'req1value']

und

    ['--opt1', 'opt1value', 'req1value', 'r1', 'r2']

4
2017-09-04 20:17



Du könntest benutzen parse_known_args:

import argparse
parser = argparse.ArgumentParser(description='Parser demo.')
parser.add_argument('req1', help='first required parameter')
parser.add_argument('--opt1', help='first optional parameter')

args, leftovers = parser.parse_known_args(['req1value', '--opt1', 'opt1value'])
print(args, leftovers)
# (Namespace(opt1='opt1value', req1='req1value'), [])

args, leftovers = parser.parse_known_args(['req1value', '--opt1', 'opt1value', 'r1', 'r2'])
print(args, leftovers)
# (Namespace(opt1='opt1value', req1='req1value'), ['r1', 'r2'])

4
2017-09-04 20:34



Das Mischen von Positionalen und Optionalen ist schwierig, wenn eines oder mehrere Positionale vom Typ 'Null oder mehr' sind (? * REMAINDER). Die einfache Lösung besteht darin, sie nicht zu mischen - geben Sie zuerst die Optionale und dann alle Positionale an.

Hier ist was los ist:

input: ['req1value', '--opt1', 'opt1value']
Namespace(leftovers=['--opt1', 'opt1value'], opt1=None, req1='req1value')

Wegen dem req1value Zeichenfolge, die der Parser zuerst für Positionale analysiert. req1 will 1 String, leftovers ergreift alles andere einschließlich --opt1.

Namespace(leftovers=None, opt1='opt1value', req1='req1value')

Mit *  leftovers ist zufrieden mit []Also keine Schnur None (eigentlich bekomme ich []). --opt1 wird als optional geparst.

input: ['req1value', '--opt1', 'opt1value', 'r1', 'r2']
...
py-argparse.py: error: unrecognized arguments: r1 r2

Wie vorher *  leftovers ist eingestellt auf []. -opt1 wird bearbeitet. Aber jetzt gibt es 2 Saiten ohne Platz für sie. Du beabsichtigtest, dass sie hineingehen leftovers, aber das wurde schon benutzt. Ob leftovers war + es hätte sie wie gewünscht genommen.

Der Schlüssel ist, dass, wenn es versucht, die erste Position zu analysieren, es auch versucht, alle Positionen zu analysieren, die es kann. Auf einer Ebene parse_args macht re.match('(A)(A*)','AOA') produzierende Gruppen ('A', '').

Es gibt 2 vorgeschlagene Patches, die sich mit diesem Problem befassen. Man benutzt den 2 Schritt parse_known_args um eine vollständige Mischung von Optionalen und Positionalen zu ermöglichen. Dies ist die Art von Verhalten, die Benutzer von optparse könnte erwartet haben.

Der andere Patch versucht, die Behandlung von Positionalen zu verzögern, die akzeptiert werden können 0 Argumentketten http://bugs.python.org/issue15112 .


2
2017-09-05 20:33