J'ai ce code dont je suis généralement satisfait:
import argparse
servers = [ "ApaServer", "BananServer", "GulServer", "SolServer", "RymdServer",
"SkeppServer", "HavsServer", "PiratServer", "SvartServer", "NattServer", "SovServer" ]
parser = argparse.ArgumentParser(description="A program to update components on servers.")
group = parser.add_mutually_exclusive_group()
group.add_argument('-l', '--list', dest="update", action='store_false', default=False, help='list server components')
group.add_argument('-u', '--updatepom', dest="update", action='store_true', help='update server components')
parser.add_argument('-o', '--only', nargs='*', choices=servers, help='Space separated list of case sensitive server names to process')
parser.add_argument('-s', '--skip', nargs='*', choices=servers, help='Space separated list of case sensitive server names to exclude from processing')
args = parser.parse_args()
J'aime que le choix = serveurs valide les noms de serveur dans l'entrée pour moi, donc je n'ai pas à le faire. Cependant, avoir autant de choix valides rend la sortie de l'aide terrible:
usage: args.py [-h] [-l | -u]
[-o [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]]]
[-s [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]]]
A program to update components on servers.
optional arguments:
-h, --help show this help message and exit
-l, --list list server components
-u, --updatepom update server components
-o [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]], --only [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]]
Space separated list of case sensitive server names to
process
-s [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]], --skip [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} [{ApaServer,BananServer,GulServer,SolServer,RymdServer,SkeppServer,HavsServer,PiratServer,SvartServer,NattServer,SovServer} ...]]
Space separated list of case sensitive server names to
exclude from processing
Quelle voie recommanderiez-vous si je veux:
servers
.Prime:
Ajouter
J'ai essayé d'utiliser la suggestion michaelfilms où le -o
-s
les options sont supprimées de la sortie ci-dessus et cette partie est ajoutée:
server optional arguments:
Valid server names are: ApaServer, BananServer, GulServer, SolServer,
RymdServer, SkeppServer, HavsServer, PiratServer, SvartServer,
NattServer, SovServer
Je pense que ça a l'air plutôt bien, mais j'ai vraiment besoin d'aide pour -o
et -s
options car l'utilisateur ne les connaîtrait pas autrement. Je ne suis donc pas encore tout à fait là-bas en utilisant cette approche.
Je répète essentiellement ce qu'Ernest a dit - pour éviter la longue liste de choix, définissez metavar = '' pour les arguments basés sur les choix (bien qu'il ne supprime pas l'espace entre l'argument et la virgule (par exemple -o ,
au lieu de -o,
). Vous pouvez ensuite décrire les choix disponibles en détail dans une description générale (RawDescriptionHelpFormatter est utile ici si vous souhaitez les répertorier avec une indentation évidente).
Je ne comprends pas pourquoi la réponse d'Ernest a été rejetée. Ce code
import argparse
servers = [ "ApaServer", "BananServer", "GulServer", "SolServer", "RymdServer",
"SkeppServer", "HavsServer", "PiratServer", "SvartServer", "NattServer", "SovServer" ]
parser = argparse.ArgumentParser(description="A program to update components on servers.")
group = parser.add_mutually_exclusive_group()
group.add_argument('-l', '--list', dest="update", action='store_false', default=False, help='list server components')
group.add_argument('-u', '--updatepom', dest="update", action='store_true', help='update server components')
parser.add_argument('-o', '--only', choices=servers, help='Space separated list of case sensitive server names to process. Allowed values are '+', '.join(servers), metavar='')
parser.add_argument('-s', '--skip', choices=servers, help='Space separated list of case sensitive server names to exclude from processing. Allowed values are '+', '.join(servers), metavar='')
args = parser.parse_args()
produit la sortie d'aide suivante
usage: run.py [-h] [-l | -u] [-o] [-s]
A program to update components on servers.
optional arguments:
-h, --help show this help message and exit
-l, --list list server components
-u, --updatepom update server components
-o , --only Space separated list of case sensitive server names to
process. Allowed values are ApaServer, BananServer,
GulServer, SolServer, RymdServer, SkeppServer, HavsServer,
PiratServer, SvartServer, NattServer, SovServer
-s , --skip Space separated list of case sensitive server names to
exclude from processing. Allowed values are ApaServer,
BananServer, GulServer, SolServer, RymdServer, SkeppServer,
HavsServer, PiratServer, SvartServer, NattServer, SovServer
J'espère que c'est ce que le message original recherchait.
Il n'est pas nécessaire de sous-classer quoi que ce soit. Passez simplement un argument metavar
avec la chaîne que vous souhaitez voir apparaître dans le message d'aide.
Voir documentation argparse pour plus de détails.
J'ai ce même problème, et comme solution de contournement, j'ai utilisé l'épilogue pour décrire chacun des choix d'options. J'ai dû utiliser argparse.RawTextHelpFormatter, qui vous permet de spécifier que l'épilogue est pré-formaté.
def choicesDescriptions():
return """
Choices supports the following:
choice1 - the FIRST option
choice2 - the SECOND option
...
choiceN - the Nth option
"""
def getChoices():
return ["choice1", "choice2", ..., "choiceN"]
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, epilog=choicesDescriptions())
parser.add_argument(
'choices',
choices=getChoices(),
help='Arg choice. See the choices options below'
)
args = parser.parse_args()
print(args)
Cela n'aidera pas dans les situations où la liste des options est extrêmement longue, comme dans la question d'origine, mais pour les personnes qui, comme moi, sont tombées sur cette question à la recherche d'un moyen de briser les chaînes d'options modérément longues en deux lignes, voici mon Solution:
import argparse
class CustomFormatter(argparse.HelpFormatter):
"""Custom formatter for setting argparse formatter_class. Identical to the
default formatter, except that very long option strings are split into two
lines.
"""
def _format_action_invocation(self, action):
if not action.option_strings:
metavar, = self._metavar_formatter(action, action.dest)(1)
return metavar
else:
parts = []
# if the Optional doesn't take a value, format is:
# -s, --long
if action.nargs == 0:
parts.extend(action.option_strings)
# if the Optional takes a value, format is:
# -s ARGS, --long ARGS
else:
default = action.dest.upper()
args_string = self._format_args(action, default)
for option_string in action.option_strings:
parts.append('%s %s' % (option_string, args_string))
if sum(len(s) for s in parts) < self._width - (len(parts) - 1) * 2:
return ', '.join(parts)
else:
return ',\n '.join(parts)
Ce code remplace la méthode argparse.HelpFormatter par défaut _format_action_invocation et est identique à l'implémentation par défaut, sauf dans les quatre dernières lignes.
Comportement du formateur par défaut:
parser = argparse.ArgumentParser(description="Argparse default formatter.")
parser.add_argument('-a', '--argument', help='not too long')
parser.add_argument('-u', '--ugly', choices=range(20), help='looks messy')
parser.print_help()
sorties:
usage: test.py [-h] [-a ARGUMENT]
[-u {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}]
Argparse default formatter.
optional arguments:
-h, --help show this help message and exit
-a ARGUMENT, --argument ARGUMENT
not too long
-u {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}, --ugly {0,1,2,3,4,5,6,
7,8,9,10,11,12,13,14,15,16,17,18,19}
looks messy
Comportement du formateur personnalisé:
parser = argparse.ArgumentParser(description="Argparse custom formatter.",
formatter_class=CustomFormatter)
parser.add_argument('-a', '--argument', help='not too long')
parser.add_argument('-l', '--less-ugly', choices=range(20), help='less messy')
sorties:
usage: test.py [-h] [-a ARGUMENT]
[-l {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}]
Argparse custom formatter.
optional arguments:
-h, --help show this help message and exit
-a ARGUMENT, --argument ARGUMENT
not too long
-l {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19},
--less-ugly {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}
less messy
Pour obtenir la sortie attendue, vous devrez sous-classer argparse.HelpFormatter
et implémentez la mise en forme dont vous avez besoin. En particulier, vous devrez implémenter votre propre _metavar_formatter
méthode, qui est celle chargée de joindre tous les choix en une seule chaîne séparée par des virgules.
Pourquoi ne pas utiliser parser.add_argument_group pour créer un groupe pour vos options basées sur le serveur et indiquer qu'un argument de description affiche la liste des choix possibles? Ensuite, passez argparse.SUPPRESS dans l'aide pour chacune des options individuelles. Je crois que cela vous donnera ce que vous voulez.
http://bugs.python.org/issue16468argparse only supports iterable choices
est le problème des bogues concernant la mise en forme des choix. La liste des choix peut apparaître à 3 endroits: la ligne d'utilisation, les lignes d'aide et les messages d'erreur.
Tout ce qui importe à l'analyseur, c'est de faire un in
(__contains__
) test. Mais pour le formatage, les listes longues, les `` listes '' non bornées (par exemple des entiers> 100) et d'autres objets qui ne sont pas itérables posent des problèmes. metavar
est la façon dont les utilisateurs actuels peuvent contourner la plupart des problèmes de formatage (cela peut ne pas aider avec les messages d'erreur). Examinez le problème pour avoir des idées sur la façon de modifier votre propre version de argparse
.