web-dev-qa-db-fra.com

Comment faire python argparse arguments de groupe mutuellement exclusifs sans préfixe?

Python2.7 argparse accepte uniquement les arguments facultatifs (préfixés) dans les groupes mutuellement exclusifs:

parser = argparse.ArgumentParser(prog='mydaemon')
action = parser.add_mutually_exclusive_group(required=True)
action.add_argument('--start', action='store_true', help='Starts %(prog)s daemon')
action.add_argument('--stop', action='store_true', help='Stops %(prog)s daemon')
action.add_argument('--restart', action='store_true', help='Restarts %(prog)s daemon')

$ mydaemon -h

usage: mydaemon [-h] (--start | --stop | --restart)

optional arguments:
  -h, --help  show this help message and exit
  --start     Starts mydaemon daemon
  --stop      Stops mydaemon daemon
  --restart   Restarts mydaemon daemon

Existe-t-il un moyen de faire en sorte que les arguments argparse se comportent comme le contrôle traditionnel du démon Unix:

(start | stop | restart) and not (--start | --stop | --restart) ?
65
Carlo Pires

Pour toutes les capacités et options de argparse je ne pense pas que vous obtiendrez jamais une chaîne d'utilisation "en conserve" qui ressemble à ce que vous voulez.

Cela dit, avez-vous examiné les sous-analyseurs depuis votre message d'origine?

Voici une implémentation barebones:

import argparse

parser = argparse.ArgumentParser(prog='mydaemon')
sp = parser.add_subparsers()
sp_start = sp.add_parser('start', help='Starts %(prog)s daemon')
sp_stop = sp.add_parser('stop', help='Stops %(prog)s daemon')
sp_restart = sp.add_parser('restart', help='Restarts %(prog)s daemon')

parser.parse_args()

Exécuter ceci avec le -h les rendements de l'option:

usage: mydaemon [-h] {start,stop,restart} ...

positional arguments:
  {start,stop,restart}
    start               Starts mydaemon daemon
    stop                Stops mydaemon daemon
    restart             Restarts mydaemon daemon

L'un des avantages de cette approche est de pouvoir utiliser set_defaults pour que chaque sous-analyseur connecte une fonction directement à l'argument. J'ai également ajouté une option "gracieuse" pour stop et restart:

import argparse

def my_stop(args):
    if args.gracefully:
        print "Let's try to stop..."
    else:
        print 'Stop, now!'

parser = argparse.ArgumentParser(prog='mydaemon')

graceful = argparse.ArgumentParser(add_help=False)
graceful.add_argument('-g', '--gracefully', action='store_true', help='tries to terminate the process gracefully')
sp = parser.add_subparsers()
sp_start = sp.add_parser('start', help='Starts %(prog)s daemon')
sp_stop = sp.add_parser('stop', parents=[graceful],
                    description='Stops the daemon if it is currently running.',
                    help='Stops %(prog)s daemon')
sp_restart = sp.add_parser('restart', parents=[graceful], help='Restarts %(prog)s daemon')

# Hook subparsers up to functions
sp_stop.set_defaults(func=my_stop)

# Uncomment when my_start() and 
# my_restart() are implemented
#
# sp_start.set_defaults(func=my_start)
# sp_restart.set_defaults(func=my_restart)

args = parser.parse_args()
args.func(args)

Affichage du message "help" pour stop:

$ python mydaemon.py stop -h
usage: mydaemon stop [-h] [-g]

Stops the daemon if it is currently running.

optional arguments:
  -h, --help        show this help message and exit
  -g, --gracefully  tries to terminate the process gracefully

Arrêter "gracieusement":

$ python mydaemon.py stop -g
Let's try to stop...
67
Zachary Young

de pymotw

import argparse

parser = argparse.ArgumentParser()

group = parser.add_mutually_exclusive_group()
group.add_argument('-a', action='store_true')
group.add_argument('-b', action='store_true')

print parser.parse_args()

sortie:

$ python argparse_mutually_exclusive.py -h  
usage: argparse_mutually_exclusive.py [-h] [-a | -b]

optional arguments:  
  -h, --help  show this help message and exit  
  -a  
  -b  

$ python argparse_mutually_exclusive.py -a  
Namespace(a=True, b=False)

$ python argparse_mutually_exclusive.py -b  
Namespace(a=False, b=True)

$ python argparse_mutually_exclusive.py -a -b  
usage: argparse_mutually_exclusive.py [-h] [-a | -b]  
argparse_mutually_exclusive.py: error: argument -b: not allowed with argument -a

version2

import argparse

parser = argparse.ArgumentParser()

subparsers = parser.add_subparsers(help='commands')

# A list command
list_parser = subparsers.add_parser('list', help='List contents')
list_parser.add_argument('dirname', action='store', help='Directory to list')

# A create command
create_parser = subparsers.add_parser('create', help='Create a directory')
create_parser.add_argument('dirname', action='store', help='New directory to create')
create_parser.add_argument('--read-only', default=False, action='store_true',
                       help='Set permissions to prevent writing to the directory',
                       )

# A delete command
delete_parser = subparsers.add_parser('delete', help='Remove a directory')
delete_parser.add_argument('dirname', action='store', help='The directory to remove')
delete_parser.add_argument('--recursive', '-r', default=False, action='store_true',
                       help='Remove the contents of the directory, too',
                       )

print parser.parse_args(['list', 'a s d', ])
>>> Namespace(dirname='a s d')
print parser.parse_args(['list', 'a s d', 'create' ])
>>> error: unrecognized arguments: create
56
madjardi

Il semble que vous souhaitiez un argument positionnel au lieu d'options mutuellement exclusives. Vous pouvez utiliser des "choix" pour restreindre les options acceptables possibles.

parser = ArgumentParser()
parser.add_argument('action', choices=('start', 'stop', 'restart'))

Cela produit une ligne d'utilisation qui ressemble à ceci:

usage: foo.py [-h] {start,stop,restart}
37
Adam Wagner

S'appuyant sur la réponse d'Adam ... si vous vouliez spécifier une valeur par défaut, vous pouvez toujours faire ce qui suit afin qu'ils puissent effectivement le laisser vide.

import argparse

ActionHelp = """
    Start = Starts the daemon (default)
    Stop = Stops the daemon
    Restart = Restarts the daemon
    """
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('action', nargs = '?', choices=('start', 'stop', 'restart'),
    default = 'start', help = ActionHelp)

print parser.parse_args(''.split())
print
print parser.parse_args('-h'.split())

qui imprimera:

Namespace(action='start')

usage: program.py [-h] [{start,stop,restart}]

postional arguments:
    {start,stop,restart}
                      Start = Starts the daemon (default)
                      Stop = Stops the daemon
                      Restart = Restarts the daemon

optional arguments:
    -h, --help        show this help message and exit
11
Craig