Mostrar mensaje de ayuda con argparse pitón cuando la escritura se llama sin argumentos

StackOverflow https://stackoverflow.com/questions/4042452

  •  27-09-2019
  •  | 
  •  

Pregunta

Esto podría ser un simple. Suponga que tengo un programa que utiliza argparse al comando de proceso de línea de argumentos / opciones. Lo siguiente imprimirá el mensaje 'ayuda':

./myprogram -h

o

./myprogram --help

Pero, si se me acaba el guión sin ningún argumento en absoluto, que no hace nada. Lo que yo quiero que haga es para mostrar el mensaje de uso cuando se llama sin argumentos. ¿Cómo se hace eso?

¿Fue útil?

Solución

Esta respuesta viene de Steven Bethard en grupos de Google . Estoy aquí para volver a colocar lo que sea más fácil para las personas sin una cuenta de Google para acceder.

Puede anular el comportamiento por defecto del método error:

import argparse
import sys

class MyParser(argparse.ArgumentParser):
    def error(self, message):
        sys.stderr.write('error: %s\n' % message)
        self.print_help()
        sys.exit(2)

parser = MyParser()
parser.add_argument('foo', nargs='+')
args = parser.parse_args()

Tenga en cuenta que la solución anterior se imprimirá el mensaje de ayuda siempre que la error método se dispara. Por ejemplo, test.py --blah imprimirá el mensaje de ayuda también si --blah no es una opción válida.

Si desea imprimir el mensaje de ayuda sólo si no hay argumentos se suministran en el línea de comandos, entonces tal vez esto sigue siendo la forma más fácil:

import argparse
import sys

parser=argparse.ArgumentParser()
parser.add_argument('foo', nargs='+')
if len(sys.argv)==1:
    parser.print_help(sys.stderr)
    sys.exit(1)
args=parser.parse_args()

Tenga en cuenta que las impresiones parser.print_help() a la salida estándar por defecto. Como init_js sugiere , el uso parser.print_help(sys.stderr) para imprimir en stderr.

Otros consejos

En lugar de escribir una clase, un try / except puede utilizarse en lugar

try:
    options = parser.parse_args()
except:
    parser.print_help()
    sys.exit(0)

La ventaja es que el flujo de trabajo es más clara y no necesita una clase trozo. La desventaja es que la primera línea 'uso' se imprime dos veces.

Esto necesitará al menos un argumento obligatorio. Sin argumentos obligatorios, proporcionando cero argumentos en la línea de comandos es válida.

Con argparse que podría hacer:

parser.argparse.ArgumentParser()
#parser.add_args here

#sys.argv includes a list of elements starting with the program
if len(sys.argv) < 2:
    parser.print_usage()
    sys.exit(1)

Si usted tiene argumentos que se deben especificar para el script para ejecutar - utilizar el requerida parámetro para ArgumentParser como se muestra a continuación: -

parser.add_argument('--foo', required=True)

parse_args () informará de un error si el script se ejecuta sin ningún argumento.

Si funciones por defecto asociado de (sub) programas de análisis, como se menciona en add_subparsers , simplemente puede añadirlo como la acción predeterminada:

parser = argparse.ArgumentParser()
parser.set_defaults(func=lambda x: parser.print_usage())
args = parser.parse_args()
args.func(args)

Añadir el try-excepto si se eleva excepciones debidas a falta de argumentos posicionales.

Lanzar mi versión en la pila aquí:

import argparse

parser = argparse.ArgumentParser()
args = parser.parse_args()
if not vars(args):
    parser.print_help()
    parser.exit(1)

puede observar el parser.exit - Me principalmente hacerlo así, ya que ahorra una línea de importación, si ésa era la única razón de sys en el archivo ...

La solución más limpia será pasar manualmente argumento por defecto si no se les dio en la línea de comandos:

parser.parse_args(args=None if sys.argv[1:] else ['--help'])

Ejemplo completo:

import argparse, sys

parser = argparse.ArgumentParser()
parser.add_argument('--host', default='localhost', help='Host to connect to')
# parse arguments
args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])

# use your args
print("connecting to {}".format(args.host))

Esto imprimirá ayuda completa (no uso a corto) si se llama w / o argumentos.

Hay un par de frases ingeniosas con sys.argv[1:] (modismo de un pitón muy común para referirse a los argumentos de línea de comandos, siendo sys.argv[0] el nombre del script) que pueden hacer el trabajo.

La primera es auto-explicativo, limpio y Pythonic:

args = parser.parse_args(None if sys.argv[1:] else ['-h'])

El segundo es un poco hackier. Combinando el hecho de que previamente evaluado una lista vacía es False con el True == 1 y False == 0 equivalencias se obtiene lo siguiente:

args = parser.parse_args([None, ['-h']][not sys.argv[1:]])

Tal vez demasiados corchetes, pero bastante claro si se ha realizado una selección argumento anterior.

_, *av = sys.argv
args = parser.parse_args([None, ['-h']][not av])
parser.print_help()
parser.exit()

El método parser.exit también aceptar una status (returnCode), y un valor message (incluir un salto de línea final usted mismo!).

un ejemplo pertinaz, :)

#!/usr/bin/env python3

""" Example argparser based python file
"""

import argparse

ARGP = argparse.ArgumentParser(
    description=__doc__,
    formatter_class=argparse.RawTextHelpFormatter,
)
ARGP.add_argument('--example', action='store_true', help='Example Argument')


def main(argp=None):
    if argp is None:
        argp = ARGP.parse_args()  # pragma: no cover

    if 'soemthing_went_wrong' and not argp.example:
        ARGP.print_help()
        ARGP.exit(status=128, message="\nI just don't know what went wrong, maybe missing --example condition?\n")


if __name__ == '__main__':
    main()  # pragma: no cover

Ejemplo llama:

$ python3 ~/helloworld.py; echo $?
usage: helloworld.py [-h] [--example]

 Example argparser based python file

optional arguments:
  -h, --help  show this help message and exit
  --example   Example Argument

I just don't know what went wrong, maybe missing --example condition?
128
$ python3 ~/helloworld.py --example; echo $?
0

Establecer sus argumentos posicionales con nargs y verificación si args posicionales están vacías.

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('file', nargs='?')
args = parser.parse_args()
if not args.file:
    parser.print_help()

Referencia Python nargs

Aquí hay otra manera de hacerlo, si necesita algo flexible, en el que desea ayuda pantalla si se pasan parametros específicos, ninguno en absoluto, o más de 1 conflictivos arg:

import argparse
import sys

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-d', '--days', required=False,  help="Check mapped inventory that is x days old", default=None)
    parser.add_argument('-e', '--event', required=False, action="store", dest="event_id",
                        help="Check mapped inventory for a specific event", default=None)
    parser.add_argument('-b', '--broker', required=False, action="store", dest="broker_id",
                        help="Check mapped inventory for a broker", default=None)
    parser.add_argument('-k', '--keyword', required=False, action="store", dest="event_keyword",
                        help="Check mapped inventory for a specific event keyword", default=None)
    parser.add_argument('-p', '--product', required=False, action="store", dest="product_id",
                        help="Check mapped inventory for a specific product", default=None)
    parser.add_argument('-m', '--metadata', required=False, action="store", dest="metadata",
                        help="Check mapped inventory for specific metadata, good for debugging past tix", default=None)
    parser.add_argument('-u', '--update', required=False, action="store_true", dest="make_updates",
                        help="Update the event for a product if there is a difference, default No", default=False)
    args = parser.parse_args()

    days = args.days
    event_id = args.event_id
    broker_id = args.broker_id
    event_keyword = args.event_keyword
    product_id = args.product_id
    metadata = args.metadata
    make_updates = args.make_updates

    no_change_counter = 0
    change_counter = 0

    req_arg = bool(days) + bool(event_id) + bool(broker_id) + bool(product_id) + bool(event_keyword) + bool(metadata)
    if not req_arg:
        print("Need to specify days, broker id, event id, event keyword or past tickets full metadata")
        parser.print_help()
        sys.exit()
    elif req_arg != 1:
        print("More than one option specified. Need to specify only one required option")
        parser.print_help()
        sys.exit()

    # Processing logic here ...

Saludos!

Si el comando es algo en lo que un usuario necesita para elegir alguna acción, a continuación, utilizar un grupo mutuamente excluyentes con requerida = true .

Esto es una especie de extensión de la respuesta dada por pd321.

import argparse

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--batch", action='store', type=int,  metavar='pay_id')
group.add_argument("--list", action='store_true')
group.add_argument("--all", action='store_true', help='check all payments')

args=parser.parse_args()

if args.batch:
    print('batch {}'.format(args.batch))

if args.list:
    print('list')

if args.all:
    print('all')

Salida:

  

$ python3 a_test.py
  Uso: a_test.py [-h] (--batch pay_id | --list | --all)
  a_test.py: error: uno de los argumentos --batch --list --all se requiere

Esto sólo dan la ayuda básica. Y algunas de las otras respuestas que dará la ayuda completa. Pero al menos los usuarios sepan que pueden hacer -h

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top