Ihre Beschreibung und Code ist schwer zu folgen, aber ich habe festgestellt, dass Ihr Problem liegt mit, wie Standardwerte behandelt werden, wenn die Haupt- und Subparser ein Argument teilen dest
.
I kondensiert Code ein bisschen so konnte ich einen Testlauf machen:
import argparse
class Parsing(object):
def __init__(self):
self.parser = argparse.ArgumentParser(prog='prog',
description='some description')
self.subparser = self.parser.add_subparsers(dest='cmd', title='Cmds', help='help description')
self.make_subparsers(['cmd1','cmd2'])
def make_subparsers(self, parsers):
for each in parsers:
subp = self.subparser.add_parser(each)
self.optional(subp, default='sub')
self.optional(self.parser, default='main')
def optional(self, parser, default=None):
parser.add_argument('--foo', default=default)
args = Parsing().parser.parse_args()
print(args)
ich für 2 Läufe erhalten
1315:~/mypy$ python3.5 stack41431025.py cmd1 --foo 1
Namespace(cmd='cmd1', foo='1')
1316:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1
Namespace(cmd='cmd1', foo='sub')
Im ersten foo
durch die Saiten durch die analysiert gesetzt cmd1
Subparser.
In der zweiten Version erhält foo
den Standardwert, der vom Subparser festgelegt wird. Der Hauptparser analysierte --foo
, aber sein Wert wurde vom Subparser überschrieben.
Dies wurde in Bug/Issues diskutiert. http://bugs.python.org/issue9351 hat die Handhabung geändert, so dass der Subparser-Standard Vorrang vor Hauptparser-Werten hat. Ich denke, es gibt Probleme mit diesem Patch, aber es ist seit ein paar Jahren in Kraft.
Sie behalten mehr Kontrolle, wenn sie verschiedene dest
erhalten.
def make_subparsers(self, parsers):
for each in parsers:
subp = self.subparser.add_parser(each)
self.optional(subp, default='sub')
self.optional(self.parser, default='main', dest='main_foo')
def optional(self, parser, default=None, dest=None):
parser.add_argument('--foo', default=default, dest=dest)
1325:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1
Namespace(cmd='cmd1', foo='sub', main_foo='1')
1325:~/mypy$ python3.5 stack41431025.py cmd1
Namespace(cmd='cmd1', foo='sub', main_foo='main')
1325:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1 --foo 2
Namespace(cmd='cmd1', foo='2', main_foo='1')
====================
(frühe Antwort)
Ich werde versuchen, die möglichen Kombinationen von Argumenten zu skizzieren
parser = argparse.ArgumentParser()
parser.add_argument('mainpos', help='positional for main')
parser.add_argument('--mainopt', help='optional defined for main')
sp = parser.add_subparser(dest='cmd')
p1 = sp.add_parser('cmd1')
p1.add_argument('subpos', help='postional for sub')
p1.add_argument('--subopt', help='optional defined for sub')
Verbund usage
würde wie folgt aussehen:
python prog.py foo [--mainopt bar] cmd1 sfoo [--subopt baz]
Die entsprechenden positionals
müssen in der richtigen Reihenfolge angegeben werden. Der Subparser cmd
ist effektiv eine Position für die main
.
Das für main definierte Optional muss vor dem Subparser-Namen stehen. Das optional für den Subparser definierte muss danach auftreten. Sie könnten die gleichen flag
oder dest
haben, aber sie müssen separat definiert werden. Und wenn sie das gleiche haben dest
, könnte es einen Konflikt über Werte, insbesondere Standardwerte geben.
parser.parse_args()
beginnt mit den Eingabezeichenfolgen mit seinen Argumenten übereinzustimmen. Wenn es --mainopt
sieht, analysiert dieses optionale Argument. Ansonsten erwartet es zwei Optionen. Der zweite muss einer der Subparser-Namen sein.
Sobald es einen Subparser-Namen erhält, übergibt es die verbleibenden Zeichenfolgen an diesen Subparser. Der Subparser behandelt den Rest und legt die Werte im Hauptnamespace ab. Und das erste, was der Subparser tut, sind die Standardeinstellungen. Ob diese Aktion die vom Hauptparser gesetzten Werte überschreibt oder nicht, hängt davon ab, wie der namespace
zwischen den beiden übergeben wird.
================
Parsing wird durch die Reihenfolge der Argumente in der Befehlszeile angesteuert. Es versucht, markierte Argumente in beliebiger Reihenfolge zuzulassen. Sobald Parsing jedoch an den Subparser übergeben wird, erhält der Hauptparser beim Parsing keinen weiteren Versuch. Es macht nur ein paar Aufräumarbeiten.
Aber wenn ich parse_known_args
verwende, kann ich die Zeichenfolgen sammeln, die keiner der Parsers behandelt hat, und einen weiteren Stich machen, um sie zu analysieren.
parser1 = argparse.ArgumentParser()
parser1.add_argument('--foo')
sp = parser1.add_subparsers(dest='cmd')
sp1 = sp.add_parser('cmd1')
args, extra = parser1.parse_known_args()
parser2 = argparse.ArgumentParser()
parser2.add_argument('--foo')
if extra:
args = parser2.parse_args(extra)
print(args)
läuft
1815:~/mypy$ python stack41431025.py --foo 1 cmd1
Namespace(cmd='cmd1', foo='1')
1815:~/mypy$ python stack41431025.py cmd1 --foo 2
Namespace(foo='2')
1815:~/mypy$ python stack41431025.py --foo 1 cmd1 --foo 3
Namespace(foo='3')
Ich habe nicht diese Idee in etwas komplexer, getestet, so könnte es einige Interaktionen, die ich habe nicht gedacht. Aber das ist der nächste, dem ich zu einem markierten Argument kommen kann, das überall auftreten kann und keinen widersprüchlichen default
Problemen unterliegt.
Vielen Dank für Ihre ausführliche Antwort Hpaulj, lassen Sie mich testen, um meinen Code zu passen – Flippym
Wenn ich richtig verstanden habe, 'argparse' unterstützt keine globalen Argumente, würde ich sie mit' dest' kontrollieren, in jedem Subparser, richtig ? – Flippym
Ich habe ein Beispiel mit 'Parse_known_args' und einem zweiten Parsing-Lauf hinzugefügt. – hpaulj