2014-09-13 6 views
5

Ich habe ein Python-Skript, das zwei Unterbefehle ausführt, die die gleiche Option --config akzeptieren. Ich möchte einen dritten Unterbefehl erstellen, der die ersten beiden Unterbefehle nacheinander ausführen kann.argparse Konfliktlöser für Optionen in Unterbefehlen verwandelt Schlüsselwortargument in Positionsargument

Mit argparse habe ich einen Subparser für jeden Unterbefehl erstellt, sowie einen dritten Subparser, dessen Eltern die beiden Unterbefehle sind. Nur um zu klären:

subcommand1 = subparsers.add_parser('subcommand1') 
subcommand1.add_argument('--config', help="The config") 

subcommand2 = subparsers.add_parser('subcommand2') 
subcommand2.add_argument('--config', help="The config") 

wrappercommand = subparsers.add_parser('wrappercommand', 
             parents=[subcommand1, subcommand2], 
             conflict_handler='resolve') 

Alles funktioniert, wenn ich Wrapper-Befehl oder Unterbefehl2 ausführen. Allerdings subcommand1 bricht, mit diesem als die Ausgabe:

$ run_command.py subcommand1 --config path_to_config.ini 

usage: run_command.py subcommand1 config 

optional arguments: 
    help     show this help message and exit 
    config    The config 

Es sieht aus wie argparse ein Schlüsselwort arg ("--config") in eine Positions ein ("config") gedreht hat. Ist dies das erwartete Verhalten, wenn Konflikte verursachende Optionen von argparse gelöst werden?

+0

Können Sie den vollständigen Parsing-Code posten? Ist das Argument "Helfer"? – Forge

+0

Das ist ein Tippfehler - es sollte 'help = "Die Config"' sein. – hpaulj

Antwort

3

Ich denke, dass Sie diesen Konflikthandler in unbeabsichtigtes und unerprobtes Territorium drängen. Normalerweise sind parents eigenständige Parser, die nicht verwendet werden. Sie sind nur eine Quelle für Actions. Und Konflikte bezüglich -h werden mit add_help=False behandelt.

Als Hintergrund: mit dem Standard conflict_handler (Fehler) Fehlermeldungen erhalten würde, wenn die Erstellung der wrappercommand subparser:

argparse.ArgumentError: argument -h/--help: conflicting option string(s): -h, --help 

und nach einiger add_help=False Zugabe, dann würden Sie noch erhalten:

argparse.ArgumentError: argument --config: conflicting option string(s): --config 

Der resolve Konflikthandler ersetzt die Fehlermeldungen durch eine Art "Auflösung". Das folgende Skript zeigt, was passiert.

Der Handler resolve löschte die option_strings für die Aktionen subcommand1, während die Aktionen bestehen bleiben. In der Tat werden beide zu Positionalen. Und da helpnargs=0 hat, wird es immer ausgeführt. Daher wird die Hilfe angezeigt.

Die Absicht von _handle_conflict_resolve ist, Beweise des ersten Arguments zu entfernen, so dass das neue Argument hinzugefügt werden kann. Das funktioniert gut, wenn der Konflikt durch zwei add_argument Befehle mit den gleichen Optionsstrings erzeugt wird. Aber hier entsteht der Konflikt, indem Aktionen von zwei Eltern "kopiert" werden. Die übergeordneten Aktionen werden jedoch als Verweis kopiert, sodass Änderungen am "untergeordneten" sich auf das "übergeordnete Element" auswirken.

Einige mögliche Lösungen: direkt

  • die Argumente wrappercommand hinzuzufügen. Dieser parents Mechanismus fügt nur Argumente von den Eltern zum Kind hinzu. Es "läuft" die Eltern nicht sequenziell.

  • Schreiben Sie Ihre eigene _handle_conflict_... Funktion, um den Konflikt korrekt zu lösen.

  • Entfernen Sie die Konflikte, so dass Sie die parents ohne den resolve Handler verwenden können.


ich einen Fehlerbericht mit diesem Beispiel eingereicht http://bugs.python.org/issue22401:

parent1 = argparse.ArgumentParser(add_help=False) 
parent1.add_argument('--config') 
parent2 = argparse.ArgumentParser(add_help=False) 
parent2.add_argument('--config') 

parser = argparse.ArgumentParser(parents=[parent1,parent2], 
    conflict_handler='resolve') 

def foo(parser): 
    print [(id(a), a.dest, a.option_strings) for a in parser._actions] 

foo(parent1) 
foo(parent2) 
foo(parser) 

, die produziert:

[(3077384012L, 'config', [])] 
[(3076863628L, 'config', ['--config'])] 
[(3076864428L, 'help', ['-h', '--help']), (3076863628L, 'config', ['--config'])] 

Notiere die fehlende option_strings für parent1 und die passende id für die anderen 2. parent1 kann nicht erneut als Parent oder Parser verwendet werden.


argparse - Combining parent parser, subparsers and default values ist ein weiterer Fall, in der Aktion des Kopierens Elternteil durch Bezugnahme Komplikationen (in wechselnder Defaults) erzeugt.

+0

Vielen Dank, Ihre Antwort ist in allen Punkten korrekt. Ich werde die Optionen direkt zum Subparser hinzufügen, ohne den Eltern-Mechanismus zu verwenden. – toothgrinder

Verwandte Themen