2013-04-03 5 views
7

Ich habe folgenden TestcodeWie Sub-Parser-Argumente in separaten Namespace mit Argparse haben?

import argparse 
parser = argparse.ArgumentParser() 
parser.add_argument("--verbose", default = 0, type=int) 

subparsers = parser.add_subparsers(dest = "parser_name") 

parser_lan = subparsers.add_parser('car') 
parser_lan.add_argument("--boo") 
parser_lan.add_argument("--foo") 

parser_serial = subparsers.add_parser('bus') 
parser_serial.add_argument("--fun") 

print parser.parse_args() 

die zwei Unter Parsern definiert, einen anderen Satz von Argumenten aufweisen. Als ich den Testcode als

tester.py --verbose 3 car --boo 1 --foo 2 

nennen bekomme ich das erwartete Ergebnis

Namespace(boo='1', foo='2', parser_name='car', verbose=3) 

Was will ich stattdessen haben, ist der Wert von jedem subparser in einem eigenen Namensraum oder dict, so etwas wie

Namespace(subparseargs={boo:'1', foo:'2'}, parser_name='car', verbose=3) 

so dass die Argumente von jedem Subparser logisch getrennt von den Argumenten vom Hauptparser sind (wie in diesem Beispiel verbose).

Wie kann ich dies erreichen, mit den Argumenten für jeden Subparser im gleichen Namensraum (im Beispiel subparseargs).

+0

Beantwortet Ihre Frage nicht, aber moderne [argparse wrappers] (http://stackoverflow.com/q/13248487/989121) sind viel mehr Spaß mit der Arbeit als roh argarse. – georg

Antwort

1

Ich habe angefangen, einen anderen Ansatz (aber ähnlich dem Vorschlag von Anthon zu entwickeln) und mit einem viel kürzeren Code kommen. Ich bin jedoch nicht sicher, ob mein Ansatz eine allgemeine Lösung für das Problem ist.

Um ähnliche was Anthon schlägt definiere ich eine neue Methode, die eine Liste der "Top-Level-Argumente erstellt, die in args gehalten werden, während alle anderen Argumente als zusätzliches Wörterbuch zurückgegeben werden:

class MyArgumentParser(argparse.ArgumentParser): 
    def parse_subargs(self, *args, **kw): 
     # parse as usual 
     args = argparse.ArgumentParser.parse_args(self, *args, **kw) 

     # extract the destination names for top-level arguments 
     topdest = [action.dest for action in parser._actions] 

     # loop over all arguments given in args 
     subargs = {} 
     for key, value in args.__dict__.items(): 

      # if sub-parser argument found ... 
      if key not in topdest: 

       # ... remove from args and add to dictionary 
       delattr(args,key) 
       subargs[key] = value 

     return args, subargs 

Kommentare zu diesem Ansatz willkommen, vor allem alle Schlupflöcher, die ich übersehen habe.

2

Sie müssen ein bisschen in die Eingeweide von argparse gehen, aber wenn Sie Ihre Skript der folgenden sollte es tun:

import argparse 
from argparse import _HelpAction, _SubParsersAction 

class MyArgumentParser(argparse.ArgumentParser): 
    def parse_args(self, *args, **kw): 
     res = argparse.ArgumentParser.parse_args(self, *args, **kw) 
     from argparse import _HelpAction, _SubParsersAction 
     for x in parser._subparsers._actions: 
      if not isinstance(x, _SubParsersAction): 
       continue 
      v = x.choices[res.parser_name] # select the subparser name 
      subparseargs = {} 
      for x1 in v._optionals._actions: # loop over the actions 
       if isinstance(x1, _HelpAction): # skip help 
        continue 
       n = x1.dest 
       if hasattr(res, n): # pop the argument 
        subparseargs[n] = getattr(res, n) 
        delattr(res, n) 
      res.subparseargs = subparseargs 
     return res 

parser = MyArgumentParser() 
parser.add_argument("--verbose", default = 0, type=int) 

subparsers = parser.add_subparsers(dest = "parser_name") 

parser_lan = subparsers.add_parser('car') 
parser_lan.add_argument("--boo") 
parser_lan.add_argument("--foo") 

parser_serial = subparsers.add_parser('bus') 
parser_serial.add_argument("--fun") 

print parser.parse_args() 
Verwandte Themen