2016-12-12 1 views
1

Le plus souvent moyen de définir un subparser est de fairesubparser argparse sous-entendus par d'autres paramètres

master_parser = argparse.ArgumentParser() 
subparsers = master_parser.add_subparsers() 
parser = subparsers.add_parser('sub') 
parser.add_argument('--subopt') 

et la subparser sera appelée avec

command sub --subopt 

Je mettre en œuvre un paquet qui appelle un certain nombre de convertisseurs. Si j'utilise l'approche subparser habituelle, je dois faire

convert ext1_to_ext2 file.ext1 file.ext2 --args 

qui est à la fois répétitive et sujette aux erreurs car les utilisateurs peuvent appeler

convert ext1_to_ext3 file.ext1 file.ext2 --args 

Je préférerais que le subparser est automatiquement déterminée à partir de la analyseur maître afin que les utilisateurs peuvent utiliser la commande

convert file.ext1 file.ext2 EXTRA 

et argparse déterminerait subparser ext1_to_ext2 de file.ext1 et file.ext2 et appeler le sous-registre ext1_to_ext2 pour analyser EXTRA. Bien sûr, EXTRA est spécifique au sous-groupe. J'ai essayé d'utiliser des groupes de paramètres pour chaque convertisseur (add_argument_group) mais les paramètres dans les groupes d'arguments ne peuvent pas se chevaucher et j'ai obtenu une liste désordonnée d'arguments combinés de tous les analyseurs, donc l'utilisation de subparser semble être la bonne solution.

J'ai essayé d'utiliser parse_known_args avec deux arguments de position, déterminer et utiliser le sous-analyseur approprié pour analyser les arguments restants, mais il est difficile de fournir aux utilisateurs une liste de convertisseurs et leurs arguments du message d'aide.

Existe-t-il un moyen de le faire?

+0

Pourriez-vous utiliser ['parse_known_args'] (https://docs.python.org/3.5/library/argparse.html#partial-parsing)? Cela vous permettrait d'analyser la première partie des arguments, d'évaluer vous-même le subparser approprié, puis de passer les arguments restants au sous-parent approprié. – SethMMorton

+0

C'est l'approche que je prends en ce moment, mais je me bats sur la façon de fournir un message d'aide pour les utilisateurs. Il semble que j'ai besoin de pirater 'convertir fichier.ext1 fichier.ext2 -h' pour imprimer le message d'aide d'un autre analyseur, mais je ne peux toujours pas lister tous les convertisseurs disponibles de' convert -h' (peut-être un 'epilog' pourrait fonctionner). – user2283347

+0

Le type de logique que vous demandez est déraisonnable pour 'argparse'. Soit analyser 'sys.argv' directement ou obtenir les valeurs sous forme de chaînes simples via' argparse', puis en déduire quelle action vous devriez entreprendre. – hpaulj

Répondre

1

Il est difficile d'inférer le sous-composant à utiliser car il nécessite de réimplémenter une grande partie de la logique utilisée par argparse lui-même pendant que vous examinez chacun des arguments suivants.

Une approche plus simple consiste à prendre la commande subparser, qui vous permet ensuite de "typecheck" les arguments suivants pour s'assurer qu'ils utilisent l'argument correct. Par exemple

# This allows a file name ending with any of the given extensions, 
# or allows "file.1" in place of "file.1.jpg" 
def jpeg_file(s): 
    for ext in ("jpg", "jpeg"): 
     if s.endswith(ext) or os.path.exists("%s.%s" % (s, ext)): 
      return s 
    raise argparse.ArgumentTypeError() 

def tiff_file(s): 
    # similar to jpeg_file 

master_parser = argparse.ArgumentParser() 
subparsers = master_parser.add_subparsers() 
jpg_to_tiff_parser = subparsers.add_parser('sub') 
jpg_to_tiff_parser = parse.add_argument('jpg', type=jpg_file) 
jpg_to_tiff_parser = parse.add_argument('tiff', type=tiff_file) 
+0

Mais la ligne de commande serait toujours 'convertir sub fichier.jpg fichier.tiff'. J'ai juste eu une idée (?) Merveilleuse, que diriez-vous de pirater 'sys.argv'? Je peux vérifier 'sys.argv [1]' et 'sys.argv [2]', insérer le nom du sous-programme approprié avant 'sys.argv [1]', et appeler le 'master_parser' avec tous les sous-programmes. Le message '-h' serait un peu éteint. – user2283347

+0

Aucun problème évident à cette approche ne vient à l'esprit, bien que les deux premiers arguments positionnels ne soient pas nécessairement 'sys.argv [1]' et 'sys.argv [2]'. – chepner

0

Cela vous donne un peu plus de contrôle à mon avis. C'est en cours de route vers ce que vous demandez. Ajoutez simplement l'extension de fichier vérifiant vos besoins.

#prog.py 
topParser=argparse.ArgumentParser() 

subParsers = topParser.add_subparsers(
    title='SubCommands', 
    description='Use "prog.py <subCommand> (-h | --help)" to learn more about each subcommand', 
    help='I can do stuff') 

subParser1 = subParsers.add_parser('use1', help="Use1 does one thing") 
subParser2 = subParsers.add_parser('use2', help='Use2 does another thing') 

subParser1.add_argument(
    '-f','--first-arg-for-use1', 
    help="A text file", 
    required=True 
    ) 

subParser1.add_argument(
    '-s','--second-arg-for-use1', 
    help="An encoding", 
    required=True 
    ) 

subParser2.add_argument(
    '-f','--first-arg-for-use2', 
    help="An image format", 
    required=True 
    ) 

args = topParser.parse_args() 
print(args) 

Si rien d'autre, il montre comment gérer le texte d'aide pour les différentes couches.