2016-07-06 5 views
1

Ich suche ein Argument Parser mit folgenden Struktur zu erzeugen:argparse - Verschiedene obligatorische/verfügbare Parameter pro Aktion

options [ 'backup', 'consistency_check', 'backup_and_consistency_check'] 

--database [ required ] 
--action [ required choice from list options ] 
    --where_to_backup_to [ only required if --action is 'backup' ] 
    --what_file_to_consistency_check [ only required if --action is 'consistency_check'] 
--clean [ optional ] 
    --force [ optional if --clean is also in arguments ] 

Wie ich optionale Argumente mit dem ArgumentParser Modul implementieren kann, je nach Wahl, die war als ein anderes Kommandozeilenargument gemacht.

Ich suche die argparse machen scheitern, wenn zum Beispiel der Befehlszeilenargumente sind

--d database_name --a backup --what_file_to_consistency_check /var/tmp/file.bak 

Dies ist, was ich bisher bekommen (ich weiß, dass es sehr wenig, aber ich will nicht gehen in die falsche Richtung vollständig mit subparsers wenn ich es nicht von Anfang an bekommen haben)

actions = ['backup', 'consistency_check', 'backup_and_consistency_check'] 

def create_parser(): 
    parser = ArgumentParser(description='Parser for Backup/Consistency Check') 

    parser.add_argument('--database', '-d', dest='db', help='Database name', choices=get_active_database_list()) 

    parser.add_argument('--action', '-a', dest='action', help='Action option', choices=actions) 
    # --where_to_backup_to [ only if action = backup ] 
    # --what_file_to_consistency_check [ only if action = cc ] 
    parser.add_argument('--clean', '-c', dest='clean', help='Clean') 
    # --force [ only available if --clean is also in arguments ] 

    return parser 
+1

Geben Sie jeder Aktion einen eigenen Subparser. Übrigens würden Sie herkömmlicherweise ein Positionsargument machen. –

+0

Können Sie ein Beispiel geben? Es muss nicht wirklich Code sein - nur eine Beschreibung? Kann ich dem bestimmten Argument einen Subparser und nicht den ganzen Parser hinzufügen? – AK47

+0

Da Subparser * für * bedingt von Aktionen sind, gelten die Beispiele in den Docs alle. –

Antwort

1

Wenn Subparser im Moment zu komplex erscheinen, kann man trotzdem einen brauchbaren Parser ohne sie bekommen:

def create_parser(): 
    parser = ArgumentParser(description='Parser for Backup/Consistency Check') 

    parser.add_argument('--database', '-d', dest='db', help='Database name', choices=get_active_database_list()) 

    parser.add_argument('--action', '-a', help='Action option', choices=actions) 
    parser.add_argument('target', help='target for backup or check') 
    parser.add_argument('--clean', '-c', help='Clean') # default dest is 'clean' 
    parser.add_argument('--force', help='force clean') 
    return parser 

Wenn database erforderlich ist, können Sie einen Parameter required=True hinzufügen. Oder mach es zu einer Position. Ansonsten überlegen Sie, was Sie tun werden, wenn der Benutzer es nicht liefert. I.e. wenn args.db is None? Gibt es eine Standarddatenbank, die Sie verwenden können?

Es sieht so aus, als ob alle Aktionsoptionen eine Datei oder ein Dir-Argument erfordern - das Ziel für die Sicherung oder Überprüfung. Ist es wichtig, ob der Benutzer sie'where_to_backup_to 'oder' - what_file_to_consistency_check 'nennt? Indem ich hier eine Position verwende, fordere ich von ihnen, eine Art von Namen zu geben, aber es liegt an Ihnen, sie entsprechend der "Aktion" zu interpretieren.

Es sieht aus wie force ist nur eine stärkere Version von clean. Was denken Sie, der Benutzer will, wenn sie --force aber nicht --clean spezifizieren? Hier akzeptiere ich beides und lasse deinen Code wählen, was am sinnvollsten ist.

Meine Philosophie ist, dass das primäre Ziel eines Parsers ist herauszufinden, was der Benutzer will. Die Fehlerprüfung ist am nützlichsten, wenn mehrdeutige Eingaben verhindert werden. Aber es sollte nicht wählerisch sein. Ein einfaches Parser-Design ist normalerweise besser als ein zu komplexes.

1

ich denke Aktion macht ein Positionsparameter mit dynamischer Option Parser ist eine gute Wahl:

if __name__ == "__main__": 

    action = sys.argv[1] 

    parser = create_parser(action) 
    args = parser.parse_args() 
+1

argparse hat eingebaute Unterstützung für Unterbefehle - verwenden Sie es, und Ihre '--help 'deckt alle Möglichkeiten ab, anstatt selbst etwas Ähnliches zu hacken. Auf diese Weise können Sie Optionen * vor * Ihren Argumenten haben. –

+0

Hallo, danke für die Antwort. Ich versuche unnötige Bedingungen zu vermeiden und Argumente aus Argumenten usw. herauszunehmen, da die Optionen auch eine andere ähnliche Funktionalität beinhalten. Ich habe den Code mit einer neuen Option --clean aktualisiert, die dann auch eine optionale --force erlaubt (um sauber zu machen) - und ja, um auf dem zu bauen, was Charles gesagt hat, ist ArgParse intelligent genug, um die Magie zu machen, also möchte ich es maximal nutzen :) – AK47

1

Der herkömmliche Weg, dies zu tun, mehr wie folgt aussehen würde:

def create_parser(): 
    parser = ArgumentParser(description='Parser for Backup/Consistency Check') 

    parser.add_argument('--database', '-d', dest='db', help='Database name', choices=get_active_database_list()) 
    parser.add_argument('--timeout', '-t', dest='timeout', help='Timeout limit (in minutes)') 

    subparsers = parser.add_subparsers() 

    parser_backup = subparsers.add_parser('backup', help='Run a backup') 
    parser_backup.set_defaults(action='backup') # or even pass the backup function itself, vs a string 
    parser_backup.add_argument('dest', help='Where to backup to') # where to backup to 

    parser_check = subparsers.add_parser('consistency_check', help='Run a consistency check') 
    parser_check.set_defaults(action='consistency_check') 
    parser_check.add_argument('source', help='What file to check for consistency') 

    return parser 

... mit Nutzung als:

# here, action='backup' and dest='/path/to/dest' 
yourtool -d db -t 15 backup /path/to/dest 

... oder ...

# here, action='consistency_check' and source='/path/to/content/to/check' 
yourtool -d db -t 15 consistency_check /path/to/content/to/check 
+0

Danke, das löscht tatsächlich eine Menge Dinge auf. Durch Hinzufügen eines Unterparsers wird ein weiteres Argument hinzugefügt, außer dass dieses Argument auch optionale Argumente enthält. Ich wurde verwirrt, weil ich dachte, ich würde einen Subparser hinzufügen und dann dem Subparser Backup als Argument hinzufügen. Aber Backup ist der Subparser! – AK47

+0

Wenn 'add_subparsers (dest = 'action')' Sie brauchen nicht die 'set_defaults' Anweisungen (außer Sie wollen einen Funktionswert setzen). – hpaulj

Verwandte Themen