2016-12-28 1 views
1

J'écris un analyseur d'arguments pour un module python avec différents sous-composants. Mon objectif est d'avoir un argument qui est partagé dont le constructeur argument est passé à plusieurs enfants:Python argparse: Récupère le nom du programme subparser dans la chaîne d'aide

from argparse import ArgumentParser 
parser = ArgumentParser(prog = 'master') 
parser1 = ArgumentParser(help = None) 
parser1.add_argument('foo', type = int, help = 'Number of times to process %(prog)s') # Line of interest 
parser2 = ArgumentParser(help = None) 
parser2.add_argument('--bar', type = int, default = 0, help = 'Start at this number') 
parser3 = ArgumentParser(help = None) 
parser3.add_argument('--baz', type = str, default = 'DEFAULT', help = 'Init file with this text') 
subparsers = parser.add_subparsers() 
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2]) 
sp2 = subparsers.add_parser('prog2', parents = [parser1, parser3]) 
parser.parse_args('prog1 -h'.split()) 

La sortie souhaitée serait quelque chose comme

usage: master prog1 [-h] [--bar BAR] foo 

positional arguments: 
    foo   Number of times to process prog1 

optional arguments: 
    -h, --help  show this message and exit 
    --bar   Start at this number 

Lorsque j'utilise cette configuration exacte, je reçois master prog1 place de prog1 dans la chaîne d'aide pour foo. Que dois-je changer dans la ligne marquée #Line of interest pour obtenir le résultat souhaité?

Répondre

0

Ce n'est pas une réponse directe à votre question, mais j'utiliserais Click_ pour ce que vous essayez de faire.

Click_ en trois points:

  1. imbrication arbitraire des commandes
  2. aide page automatique génération
  3. supporte le chargement paresseux de sous-commandes lors de l'exécution
0

Je peux expliquer ce qui se passe, mais peut ne pas être en mesure d'offrir une solution.

La réponse courte est que le sp1.prog est utilisé à la fois dans son format usage et comme valeur %(prog)s dans les lignes d'aide. Et il est construit avec cette ligne à l'esprit.

===============

sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2]) 

crée un analyseur, et ajoute des arguments de la parents. add_parser est une méthode de la classe class _SubParsersAction (la classe d'action subparser). Et l'attribut prog pour cet analyseur est créé avec:

 if kwargs.get('prog') is None: 
     kwargs['prog'] = '%s %s' % (self._prog_prefix, name) 

Vous devriez être en mesure de voir cet attribut avec print(sp1.prog) (je pense « maître prog1 »). C'est la valeur qui est utilisée dans la ligne usage et dans l'une des lignes d'aide avec %(prog)s.

subparsers._prog_prefix est dérivé de parser.prog (voir le code add_subparsers pour les détails). Mais vous pouvez également spécifier un paramètre prog:

sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='prog1') 

Cela devrait corriger la chaîne dans la ligne help. Mais il va également changer la chaîne usage.

Vous pouvez également donner un subparser usage explicite:

sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='prog1', usage='master prog1 ...') 

Sans faire une intervention chirurgicale pour la HelpFormatter Je ne pense pas que vous pouvez changer prog dans les lignes d'aide sans elle changer aussi dans l'utilisation.

Et donné la façon parents fonctionne vous ne pouvez pas changer la ligne d'aide pour prog1 foo sans également le changer pour prog2 foo. parents Copie des objets d'action par référence, de sorte que les deux sous-composants partagent l'objet Action foo.

Vous devez souvent abandonner l'approche parents, au moins pour cet argument, et coder en dur le nom. Si vous devez ajouter l'argument à plusieurs sous-parties, écrivez une petite fonction d'utilité pour faciliter cela. Le mécanisme parents est juste (habituellement) une commodité, quelque chose qui évite de taper/éditer.

===================

Ce script modifié illustrera mes points

parser = ArgumentParser(prog = 'master') 

parser1 = ArgumentParser(add_help = False) 
fooarg=parser1.add_argument('foo', type = int, help = 'foo prog: %(prog)s') # Line of interest 
parser2 = ArgumentParser(add_help = False) 
parser2.add_argument('--bar', type = int, default = 0, help = 'Start at this number') 
parser3 = ArgumentParser(add_help = False) 
parser3.add_argument('--baz', type = str, default = 'DEFAULT', help = 'Init file with this text') 

subparsers = parser.add_subparsers(prog='subparsers') 
sp1 = subparsers.add_parser('prog1', parents = [parser1, parser2], prog='name1') 
sp2 = subparsers.add_parser('prog2', parents = [parser1, parser3]) 

#parser.print_help() 

# fooarg is an Action for both subparsers 
# print(fooarg.help) 
# fooarg.help = 'FOO HELP' 

print('==>sp1 prog:', sp1.prog) 
sp1.print_help() 
print('==>sp2 prog:', sp2.prog) 
sp2.print_help() 

sp1.prog = 'custom' 
sp1.print_help() 

# addition 
fooarg.default = 'default' 
fooarg.metavar = 'META' 
fooarg.help = 'prog: %(prog)s, dest=%(dest)s, nargs=%(nargs)s, type=%(type)s, default=%(default)s' 
sp1.print_help() 

Ce dernier bit ajoute un tas d'attributs d'action à l'aide. Mais prog est le seul qui vient du parser:

positional arguments: 
    META  prog: custom, dest=foo, nargs=None, type=int, default=default