Mon argparse n'a que 3 drapeaux (store_true) au niveau supérieur, tout le reste est géré par des sous-vendeurs. Lorsque je lance myprog.py --help
, la sortie affiche une liste de toutes les sous-commandes comme d'habitude, {sub1, sub2, sub3, sub4, ...}
. Donc, le défaut fonctionne très bien ...
Je ne me souviens généralement pas du nom exact de la sous-commande dont j'ai besoin et de toutes ses options. Alors je finis par faire 2 recherches d'aide:
myprog.py --help
myprog.py sub1 --help
Je le fais si souvent que j'ai décidé de le regrouper en une seule étape. Je préférerais que mon aide de niveau supérieur produise un résumé énorme, puis je fais défiler la liste manuellement. Je trouve que c'est beaucoup plus rapide (pour moi du moins).
J'utilisais RawDescriptionHelpFormatter et saisissais manuellement l'aide longue. Mais maintenant, j'ai beaucoup de sous-commandes et cela devient difficile à gérer.
Existe-t-il un moyen d'obtenir une sortie d'aide détaillée avec un seul appel de programme?
Si ce n'est pas le cas, comment puis-je parcourir les sous-vendeurs de mon instance argparse, puis récupérer l'aide de chaque fichier (que je vais ensuite coller ensemble)?
Voici un aperçu rapide de ma configuration argparse. J'ai nettoyé/effacé le code un peu, donc cela ne peut pas fonctionner sans un peu d'aide.
parser = argparse.ArgumentParser(
prog='myprog.py',
formatter_class=argparse.RawDescriptionHelpFormatter,
description=textwrap.dedent(""" You can manually type Help here """) )
parser.add_argument('--debuglog', action='store_true', help='Verbose logging for debug purposes.')
parser.add_argument('--ipyonexit', action='store_true', help='Drop into an embeded Ipython session instead of exiting command.')
subparser = parser.add_subparsers()
### --- Subparser B
parser_b = subparser.add_parser('pdfreport', description="Used to output reports in PDF format.")
parser_b.add_argument('type', type=str, choices=['flatlist', 'nested', 'custom'],
help="The type of PDF report to generate.")
parser_b.add_argument('--of', type=str, default='',
help="Override the path/name of the output file.")
parser_b.add_argument('--pagesize', type=str, choices=['letter', '3x5', '5x7'], default='letter',
help="Override page size in output PDF.")
parser_b.set_defaults(func=cmd_pdf_report)
### ---- Subparser C
parser_c = subparser.add_parser('dbtables', description="Used to perform direct DB import/export using XLS files.")
parser_c.add_argument('action', type=str, choices=['Push', 'pull', 'append', 'update'],
help="The action to perform on the Database Tables.")
parser_c.add_argument('tablename', nargs="+",
help="The name(s) of the DB-Table to operate on.")
parser_c.set_defaults(func=cmd_db_tables)
args = parser.parse_args()
args.func(args)
C'est un peu délicat, car argparse n'expose pas directement une liste de sous-analyseurs définis. Mais cela peut être fait:
import argparse
# create the top-level parser
parser = argparse.ArgumentParser(prog='PROG')
parser.add_argument('--foo', action='store_true', help='foo help')
subparsers = parser.add_subparsers(help='sub-command help')
# create the parser for the "a" command
parser_a = subparsers.add_parser('a', help='a help')
parser_a.add_argument('bar', type=int, help='bar help')
# create the parser for the "b" command
parser_b = subparsers.add_parser('b', help='b help')
parser_b.add_argument('--baz', choices='XYZ', help='baz help')
# print main help
print(parser.format_help())
# retrieve subparsers from parser
subparsers_actions = [
action for action in parser._actions
if isinstance(action, argparse._SubParsersAction)]
# there will probably only be one subparser_action,
# but better save than sorry
for subparsers_action in subparsers_actions:
# get all subparsers and print help
for choice, subparser in subparsers_action.choices.items():
print("Subparser '{}'".format(choice))
print(subparser.format_help())
Cet exemple devrait fonctionner avec python 2.7 et python 3. L'exemple d'analyse est tiré de la documentation Python 2.7 sur les sous-commandes argparse .
Il ne reste plus qu'à ajouter un nouvel argument pour l'aide complète ou à remplacer le -h/--help
intégré.
Voici la solution complète avec le gestionnaire d’aide personnalisé (presque tout le code de @Adaephon answer):
import argparse
class _HelpAction(argparse._HelpAction):
def __call__(self, parser, namespace, values, option_string=None):
parser.print_help()
# retrieve subparsers from parser
subparsers_actions = [
action for action in parser._actions
if isinstance(action, argparse._SubParsersAction)]
# there will probably only be one subparser_action,
# but better save than sorry
for subparsers_action in subparsers_actions:
# get all subparsers and print help
for choice, subparser in subparsers_action.choices.items():
print("Subparser '{}'".format(choice))
print(subparser.format_help())
parser.exit()
# create the top-level parser
parser = argparse.ArgumentParser(prog='PROG', add_help=False) # here we turn off default help action
parser.add_argument('--help', action=_HelpAction, help='help for help if you need some help') # add custom help
parser.add_argument('--foo', action='store_true', help='foo help')
subparsers = parser.add_subparsers(help='sub-command help')
# create the parser for the "a" command
parser_a = subparsers.add_parser('a', help='a help')
parser_a.add_argument('bar', type=int, help='bar help')
# create the parser for the "b" command
parser_b = subparsers.add_parser('b', help='b help')
parser_b.add_argument('--baz', choices='XYZ', help='baz help')
parsed_args = parser.parse_args()
Un moyen plus simple d'itérer sur les sous-vendeurs dans l'exemple d'Adaephon est
for subparser in [parser_a, parser_b]:
subparser.format_help()
Python vous permet d'accéder à des attributs cachés tels que parser._actions
, mais cela n'est pas recommandé. Il est tout aussi facile de créer votre propre liste tout en définissant l’analyseur. Même chose pour faire des choses spéciales avec les arguments. add_argument
et add_subparser
retournent leurs objets Action
et Parser
respectifs pour une raison.
Si je faisais une sous-classe de ArgumentParser
, je me sentirais libre d’utiliser _actions
. Mais pour une application unique, la construction de ma propre liste serait plus claire.
Un exemple:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('mainpos')
parser.add_argument('--mainopt')
sp = parser.add_subparsers()
splist = [] # list to collect subparsers
sp1 = sp.add_parser('cmd1')
splist.append(sp1)
sp1.add_argument('--sp1opt')
sp2 = sp.add_parser('cmd2')
splist.append(sp2)
sp2.add_argument('--sp2opt')
# collect and display for helps
helps = []
helps.append(parser.format_help())
for p in splist:
helps.append(p.format_help())
print('\n'.join(helps))
# or to show just the usage
helps = []
helps.append(parser.format_usage())
for p in splist:
helps.append(p.format_usage())
print(''.join(helps))
L’affichage «utilisation» combiné est:
usage: stack32607706.py [-h] [--mainopt MAINOPT] mainpos {cmd1,cmd2} ...
usage: stack32607706.py mainpos cmd1 [-h] [--sp1opt SP1OPT]
usage: stack32607706.py mainpos cmd2 [-h] [--sp2opt SP2OPT]
L'affichage des aides combinées est long et redondant. Il peut être édité de différentes manières, soit après le formatage, soit avec des formateurs d'aide spéciaux. Mais qui va faire de tels choix?
J'ai également été en mesure d'imprimer une aide courte pour les commandes utilisant _choices_actions
.
def print_help(parser):
print(parser.description)
print('\ncommands:\n')
# retrieve subparsers from parser
subparsers_actions = [
action for action in parser._actions
if isinstance(action, argparse._SubParsersAction)]
# there will probably only be one subparser_action,
# but better save than sorry
for subparsers_action in subparsers_actions:
# get all subparsers and print help
for choice in subparsers_action._choices_actions:
print(' {:<19} {}'.format(choice.dest, choice.help))