argparse — Análisis de opciones y argumentos de línea de comando

Propósito:Análisis de opciones y argumentos de línea de comando.

El módulo argparse incluye herramientas para construir procesadores de argumentos y opciones de línea de comando. Fue agregado a Python 2.7 como reemplazo de optparse. La implementación de argparse admite funciones que no habrían sido fáciles de agregar a optparse, y que habría requerido cambios de interfaz de programación incompatibles con versiones anteriores, por lo que se introdujo un nuevo módulo en la biblioteca en su lugar. optparse está ahora en desuso.

Configurar un analizador

El primer paso cuando se usa argparse es crear un objeto analizador y decirle qué argumentos esperar. El analizador se puede usar para procesar los argumentos de la línea de comandos cuando se ejecuta el programa. El constructor para la clase analizador (ArgumentParser) toma varios argumentos para configurar la descripción utilizada en el texto de ayuda para el programa y otros comportamientos o configuraciones globales.

import argparse
parser = argparse.ArgumentParser(
    description='This is a PyMOTW sample program',
)

Definir argumentos

argparse es una biblioteca completa de procesamiento de argumentos. Argumentos puede desencadenar diferentes acciones, especificadas por el argumento action de add_argument(). Las acciones admitidas incluyen almacenar el argumento (individualmente o como parte de una lista), almacenando un valor constante cuando se encuentra un argumento (incluido un manejo especial para verdadero/falso valores para modificadores booleanos), contando el número de veces que un argumento se ve y se llama a una devolución de llamada para usar instrucciones de procesamiento personalizadas.

La acción predeterminada es almacenar el valor del argumento. Si se proporciona un tipo, el valor se convierta a ese tipo antes de almacenarse. Si se proporciona el argumento dest, el valor se guarda con ese nombre cuando se analizan los argumentos de la línea de comandos.

Analizar una línea de comando

Después de definir todos los argumentos, analiza la línea de comandos al pasar una secuencia de cadenas de argumentos a parse_args(). Por defecto, los argumentos se toman de sys.argv[1:], pero cualquier lista de cadenas se pueden utilizar. Las opciones se procesan utilizando la sintaxis GNU/POSIX, por lo que los valores de opción y argumento se pueden mezclar en la secuencia.

El valor de retorno de parse_args() es un Namespace que contiene los argumentos para el comando. El objeto contiene los valores del argumento como atributos, por lo que si el argumento dest se establece en "myoption", se puede acceder al valor como args.myoption.

Ejemplos simples

Aquí hay un ejemplo simple con tres opciones diferentes: una opción booleana (-a), una opción de cadena simple (` -b``) y una opción de número entero (-c).

argparse_short.py
import argparse

parser = argparse.ArgumentParser(description='Short sample app')

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)

print(parser.parse_args(['-a', '-bval', '-c', '3']))

Hay algunas formas de pasar valores a las opciones de un solo carácter. El ejemplo anterior utiliza dos formas diferentes, -bval y -c val.

$ python3 argparse_short.py

Namespace(a=True, b='val', c=3)

El tipo del valor asociado con 'c' en la salida es un número entero, ya que se le dijo al ArgumentParser que convirtiera el argumento antes de almacenarlo.

Nombres de opciones «largos», con más de un solo carácter en su nombre, se manejan de la misma manera.

argparse_long.py
import argparse

parser = argparse.ArgumentParser(
    description='Example with long option names',
)

parser.add_argument('--noarg', action="store_true",
                    default=False)
parser.add_argument('--witharg', action="store",
                    dest="witharg")
parser.add_argument('--witharg2', action="store",
                    dest="witharg2", type=int)

print(
    parser.parse_args(
        ['--noarg', '--witharg', 'val', '--witharg2=3']
    )
)

Los resultados son similares.

$ python3 argparse_long.py

Namespace(noarg=True, witharg='val', witharg2=3)

argparse es una herramienta completa de análisis de argumentos de línea de comandos, y maneja argumentos opcionales y requeridos.

argparse_arguments.py
import argparse

parser = argparse.ArgumentParser(
    description='Example with nonoptional arguments',
)

parser.add_argument('count', action="store", type=int)
parser.add_argument('units', action="store")

print(parser.parse_args())

En este ejemplo, el argumento «count» es un número entero y el argumento «units» guarda como una cadena. Si alguno queda fuera del línea de comando, o el valor dado no se puede convertir a la derecha tipo, se informa un error.

$ python3 argparse_arguments.py 3 inches

Namespace(count=3, units='inches')

$ python3 argparse_arguments.py some inches

usage: argparse_arguments.py [-h] count units
argparse_arguments.py: error: argument count: invalid int value:
'some'

$ python3 argparse_arguments.py

usage: argparse_arguments.py [-h] count units
argparse_arguments.py: error: the following arguments are
required: count, units

Acciones de argumento

Cualquiera de las seis acciones integradas se puede activar cuando un argumento es encontrado

store
Guarda el valor, después de convertirlo opcionalmente a un tipo diferente. Esta es la acción predeterminada que se toma si no se especifica ninguna explícitamente.
store_const
Guarda un valor definido como parte de la especificación del argumento, en lugar del valor que proviene de los argumentos que se analizan. Esto normalmente se usa para implementar banderas de línea de comandos que no son booleanos.
store_true / store_false
Guarda el valor booleano apropiado. Estas acciones se utilizan para implementar interruptores booleanos.
append
Guarda el valor en una lista. Se guardan varios valores si el argumento se repite.
append_const
Guarda un valor definido en la especificación del argumento en una lista.
versión
Imprime detalles de la versión sobre el programa y luego sale.

Este programa de ejemplo muestra cada tipo de acción, con la mínima configuración necesaria para que cada una funcione.

argparse_action.py
import argparse

parser = argparse.ArgumentParser()

parser.add_argument('-s', action='store',
                    dest='simple_value',
                    help='Store a simple value')

parser.add_argument('-c', action='store_const',
                    dest='constant_value',
                    const='value-to-store',
                    help='Store a constant value')

parser.add_argument('-t', action='store_true',
                    default=False,
                    dest='boolean_t',
                    help='Set a switch to true')
parser.add_argument('-f', action='store_false',
                    default=True,
                    dest='boolean_f',
                    help='Set a switch to false')

parser.add_argument('-a', action='append',
                    dest='collection',
                    default=[],
                    help='Add repeated values to a list')

parser.add_argument('-A', action='append_const',
                    dest='const_collection',
                    const='value-1-to-append',
                    default=[],
                    help='Add different values to list')
parser.add_argument('-B', action='append_const',
                    dest='const_collection',
                    const='value-2-to-append',
                    help='Add different values to list')

parser.add_argument('--version', action='version',
                    version='%(prog)s 1.0')

results = parser.parse_args()
print('simple_value     = {!r}'.format(results.simple_value))
print('constant_value   = {!r}'.format(results.constant_value))
print('boolean_t        = {!r}'.format(results.boolean_t))
print('boolean_f        = {!r}'.format(results.boolean_f))
print('collection       = {!r}'.format(results.collection))
print('const_collection = {!r}'.format(results.const_collection))

Las opciones -t y -f están configuradas para modificar diferentes valores de opción, cada una almacenando verdadero o falso. Los valores dest para -A y -B son los mismos para que sus valores constantes sean anexados a la misma lista.

$ python3 argparse_action.py -h

usage: argparse_action.py [-h] [-s SIMPLE_VALUE] [-c] [-t] [-f]
                          [-a COLLECTION] [-A] [-B] [--version]

optional arguments:
  -h, --help       show this help message and exit
  -s SIMPLE_VALUE  Store a simple value
  -c               Store a constant value
  -t               Set a switch to true
  -f               Set a switch to false
  -a COLLECTION    Add repeated values to a list
  -A               Add different values to list
  -B               Add different values to list
  --version        show program's version number and exit

$ python3 argparse_action.py -s value

simple_value     = 'value'
constant_value   = None
boolean_t        = False
boolean_f        = True
collection       = []
const_collection = []

$ python3 argparse_action.py -c

simple_value     = None
constant_value   = 'value-to-store'
boolean_t        = False
boolean_f        = True
collection       = []
const_collection = []

$ python3 argparse_action.py -t

simple_value     = None
constant_value   = None
boolean_t        = True
boolean_f        = True
collection       = []
const_collection = []

$ python3 argparse_action.py -f

simple_value     = None
constant_value   = None
boolean_t        = False
boolean_f        = False
collection       = []
const_collection = []

$ python3 argparse_action.py -a one -a two -a three

simple_value     = None
constant_value   = None
boolean_t        = False
boolean_f        = True
collection       = ['one', 'two', 'three']
const_collection = []

$ python3 argparse_action.py -B -A

simple_value     = None
constant_value   = None
boolean_t        = False
boolean_f        = True
collection       = []
const_collection = ['value-2-to-append', 'value-1-to-append']

$ python3 argparse_action.py --version

argparse_action.py 1.0

Prefijos de opción

La sintaxis predeterminada para las opciones se basa en la convención de Unix de señalar interruptores de línea de comandos usando un guión de prefijo («-«). argparse admite otros prefijos, por lo que un programa puede ajustarse al valor predeterminado de la plataforma local (es decir, usa «/» en Windows) o siga una convención diferente.

argparse_prefix_chars.py
import argparse

parser = argparse.ArgumentParser(
    description='Change the option prefix characters',
    prefix_chars='-+/',
)

parser.add_argument('-a', action="store_false",
                    default=None,
                    help='Turn A off',
                    )
parser.add_argument('+a', action="store_true",
                    default=None,
                    help='Turn A on',
                    )
parser.add_argument('//noarg', '++noarg',
                    action="store_true",
                    default=False)

print(parser.parse_args())

Establece el parámetro prefix_chars del ArgumentParser en la cadena que contiene todos los caracteres que están permitidos de señalar opciones. Es importante entender que aunque prefix_chars establece los caracteres de cambio permitidos, las definiciones de argumentos individuales especifican la sintaxis para un interruptor dado. Esto proporciona un control explícito sobre si las opciones que utilizan diferentes prefijos son alias (como podría ser el caso de sintaxis de línea de comandos independiente de la plataforma) o alternativas (por ejemplo, usar «+» para indicar que se activa un interruptor y «-» para deactivarlo). En el ejemplo anterior, +a y -a son argumentos separados, y //noarg también se puede dar como ++noarg, pero no como --noarg.

$ python3 argparse_prefix_chars.py -h

usage: argparse_prefix_chars.py [-h] [-a] [+a] [//noarg]

Change the option prefix characters

optional arguments:
  -h, --help        show this help message and exit
  -a                Turn A off
  +a                Turn A on
  //noarg, ++noarg

$ python3 argparse_prefix_chars.py +a

Namespace(a=True, noarg=False)

$ python3 argparse_prefix_chars.py -a

Namespace(a=False, noarg=False)

$ python3 argparse_prefix_chars.py //noarg

Namespace(a=None, noarg=True)

$ python3 argparse_prefix_chars.py ++noarg

Namespace(a=None, noarg=True)

$ python3 argparse_prefix_chars.py --noarg

usage: argparse_prefix_chars.py [-h] [-a] [+a] [//noarg]
argparse_prefix_chars.py: error: unrecognized arguments: --noarg

Fuentes de argumentos

En los ejemplos hasta ahora, la lista de argumentos dados al analizador provienen de una lista aprobada explícitamente o fueron tomadas implícitamente de sys.argv. Pasar la lista explícitamente es útil cuando se usa argparse para procesar instrucciones similares a la línea de comandos que no provienen de la línea de comandos (como en un archivo de configuración).

argparse_with_shlex.py
import argparse
from configparser import ConfigParser
import shlex

parser = argparse.ArgumentParser(description='Short sample app')

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)

config = ConfigParser()
config.read('argparse_with_shlex.ini')
config_value = config.get('cli', 'options')
print('Config  :', config_value)

argument_list = shlex.split(config_value)
print('Arg List:', argument_list)

print('Results :', parser.parse_args(argument_list))

Este ejemplo usa configparser para leer un archivo de configuración.

[cli]
options = -a -b 2

shlex facilita la división de la cadena almacenada en el archivo de configuración.

$ python3 argparse_with_shlex.py

Config  : -a -b 2
Arg List: ['-a', '-b', '2']
Results : Namespace(a=True, b='2', c=None)

Una alternativa para procesar el archivo de configuración en el código date la aplicación es decirle a argparse cómo reconocer un argumento que especifica un archivo de entrada que contiene un conjunto de argumentos para ser procesados usando fromfile_prefix_chars.

argparse_fromfile_prefix_chars.py
import argparse
import shlex

parser = argparse.ArgumentParser(description='Short sample app',
                                 fromfile_prefix_chars='@',
                                 )

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)

print(parser.parse_args(['@argparse_fromfile_prefix_chars.txt']))

Este ejemplo se detiene cuando encuentra un argumento con el prefijo @, luego lee el archivo nombrado para encontrar más argumentos. El archivo debe contener un argumento por línea, como en este ejemplo.

argparse_fromfile_prefix_chars.txt
-a
-b
2

La salida producida al procesar argparse_from_prefix_chars.txt sigue.

$ python3 argparse_fromfile_prefix_chars.py

Namespace(a=True, b='2', c=None)

Salida de ayuda

Ayuda generada automáticamente

argparse agregará automáticamente opciones para generar ayuda, si es configurado para hacerlo. El argumento add_help para ArgumentParser controla las opciones relacionadas con la ayuda.

argparse_with_help.py
import argparse

parser = argparse.ArgumentParser(add_help=True)

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)

print(parser.parse_args())

Las opciones de ayuda (-h y --help) se agregan de manera predeterminada, pero pueden ser deshabilitadas configurando add_help en falso.

argparse_without_help.py
import argparse

parser = argparse.ArgumentParser(add_help=False)

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)

print(parser.parse_args())

Aunque -h y --help son nombres de opción estándar de facto para solicitar ayuda, algunas aplicaciones o usos de argparse no necesitan brindar ayuda o necesitan usar esos nombres de opciones para otros fines.

$ python3 argparse_with_help.py -h

usage: argparse_with_help.py [-h] [-a] [-b B] [-c C]

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

$ python3 argparse_without_help.py -h

usage: argparse_without_help.py [-a] [-b B] [-c C]
argparse_without_help.py: error: unrecognized arguments: -h

Personalizar la ayuda

Para aplicaciones que necesitan manejar la salida de ayuda directamente, algunos de los métodos de utilidad de ArgumentParser serán útiles al crear acciones personalizadas para imprimir ayuda con información extra.

argparse_custom_help.py
import argparse

parser = argparse.ArgumentParser(add_help=True)

parser.add_argument('-a', action="store_true", default=False)
parser.add_argument('-b', action="store", dest="b")
parser.add_argument('-c', action="store", dest="c", type=int)

print('print_usage output:')
parser.print_usage()
print()

print('print_help output:')
parser.print_help()

print_usage() imprime el mensaje corto de uso para un analizador argumento y print_help() imprime la salida de ayuda completa.

$ python3 argparse_custom_help.py

print_usage output:
usage: argparse_custom_help.py [-h] [-a] [-b B] [-c C]

print_help output:
usage: argparse_custom_help.py [-h] [-a] [-b B] [-c C]

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

El ArgumentParser utiliza una clase de formateador para controlar la apariencia de la salida de ayuda. Para cambiar la clase, pasa formatter_class al instanciar el ArgumentParser.

Por ejemplo, el RawDescriptionHelpFormatter omite el ajuste de línea proporcionado por el formateador predeterminado.

argparse_raw_description_help_formatter.py
import argparse

parser = argparse.ArgumentParser(
    add_help=True,
    formatter_class=argparse.RawDescriptionHelpFormatter,
    description="""
    description
        not
           wrapped""",
    epilog="""
    epilog
      not
         wrapped""",
)

parser.add_argument(
    '-a', action="store_true",
    help="""argument
    help is
    wrapped
    """,
)

parser.print_help()

Todo el texto en la descripción y el epílogo del comando se dejarán sin alterar.

$ python3 argparse_raw_description_help_formatter.py

usage: argparse_raw_description_help_formatter.py [-h] [-a]

    description
        not
           wrapped

optional arguments:
  -h, --help  show this help message and exit
  -a          argument help is wrapped

    epilog
      not
         wrapped

El RawTextHelpFormatter trata todo el texto de ayuda como formateado previamente.

argparse_raw_text_help_formatter.py
import argparse

parser = argparse.ArgumentParser(
    add_help=True,
    formatter_class=argparse.RawTextHelpFormatter,
    description="""
    description
        not
           wrapped""",
    epilog="""
    epilog
      not
         wrapped""",
)

parser.add_argument(
    '-a', action="store_true",
    help="""argument
    help is not
    wrapped
    """,
)

parser.print_help()

El texto de ayuda para el argumento -a ya no está bien ajustado.

$ python3 argparse_raw_text_help_formatter.py

usage: argparse_raw_text_help_formatter.py [-h] [-a]

    description
        not
           wrapped

optional arguments:
  -h, --help  show this help message and exit
  -a          argument
                  help is not
                  wrapped


    epilog
      not
         wrapped

Los formateadores sin formato pueden ser útiles para aplicaciones con ejemplos en descripción o el epílogo, donde cambiar el formato del texto puede hacer que los ejemplos no sean válidos.

El MetavarTypeHelpFormatter imprime el nombre del tipo para cada opción, en lugar de la variable de destino, que puede ser útil para aplicaciones con muchas opciones de diferentes tipos.

argparse_metavar_type_help_formatter.py
import argparse

parser = argparse.ArgumentParser(
    add_help=True,
    formatter_class=argparse.MetavarTypeHelpFormatter,
)

parser.add_argument('-i', type=int, dest='notshown1')
parser.add_argument('-f', type=float, dest='notshown2')

parser.print_help()

En lugar de mostrar el valor de dest, el nombre del tipo asociado con la opción se imprime.

$ python3 argparse_metavar_type_help_formatter.py

usage: argparse_metavar_type_help_formatter.py [-h] [-i int] [-f
 float]

optional arguments:
  -h, --help  show this help message and exit
  -i int
  -f float

Organización del analizador

argparse incluye varias características para organizar argumentos analizadores, para facilitar la implementación o para mejorar la usabilidad de la salida de ayuda.

Compartir reglas de analizador

Los programadores comúnmente necesitan implementar un conjunto de herramientas de línea de comandos que toman todas un conjunto de argumentos y luego se especializan de alguna manera. Por ejemplo, si todos los programas necesitan autenticar al usuario antes tomando cualquier acción real, todos tendrían que soportar opciones --user y --password. En lugar de agregar las opciones explícitamente a cada ArgumentParser, es posible definir un analizador padre con las opciones compartidas, y luego tener que los analizadores para los programas individuales hereden de sus opciones.

El primer paso es configurar el analizador con las definiciones de argumento compartido. Dado que cada usuario posterior del analizador padre va para intentar agregar las mismas opciones de ayuda, causando una excepción, la generación automática de ayuda está desactivada en el analizador base.

argparse_parent_base.py
import argparse

parser = argparse.ArgumentParser(add_help=False)

parser.add_argument('--user', action="store")
parser.add_argument('--password', action="store")

A continuación, crea otro analizador con parents establecido:

argparse_uses_parent.py
import argparse
import argparse_parent_base

parser = argparse.ArgumentParser(
    parents=[argparse_parent_base.parser],
)

parser.add_argument('--local-arg',
                    action="store_true",
                    default=False)

print(parser.parse_args())

Y el programa resultante toma las tres opciones:

$ python3 argparse_uses_parent.py -h

usage: argparse_uses_parent.py [-h] [--user USER]
                               [--password PASSWORD]
                               [--local-arg]

optional arguments:
  -h, --help           show this help message and exit
  --user USER
  --password PASSWORD
  --local-arg

Opciones en conflicto

El ejemplo anterior señaló que agregar dos manejadores de argumentos a un analizador que usa el mismo nombre de argumento causa una excepción. El comportamiento de resolución de conflictos se puede cambiar pasando un conflict_handler. Los dos manejadores integrados son error (el predeterminado) y resolver, que elige un controlador basado en el orden en que se agregan.

argparse_conflict_handler_resolve.py
import argparse

parser = argparse.ArgumentParser(conflict_handler='resolve')

parser.add_argument('-a', action="store")
parser.add_argument('-b', action="store", help='Short alone')
parser.add_argument('--long-b', '-b',
                    action="store",
                    help='Long and short together')

print(parser.parse_args(['-h']))

Dado que el último controlador se utiliza con un nombre de argumento dado, en este ejemplo, la opción independiente -b está enmascarada por el alias de --long-b.

$ python3 argparse_conflict_handler_resolve.py

usage: argparse_conflict_handler_resolve.py [-h] [-a A]
[--long-b LONG_B]

optional arguments:
  -h, --help            show this help message and exit
  -a A
  --long-b LONG_B, -b LONG_B
                        Long and short together

Cambiar el orden de las llamadas a add_argument() desenmascara la opción independiente:

argparse_conflict_handler_resolve2.py
import argparse

parser = argparse.ArgumentParser(conflict_handler='resolve')

parser.add_argument('-a', action="store")
parser.add_argument('--long-b', '-b',
                    action="store",
                    help='Long and short together')
parser.add_argument('-b', action="store", help='Short alone')

print(parser.parse_args(['-h']))

Ahora ambas opciones se pueden usar juntas.

$ python3 argparse_conflict_handler_resolve2.py

usage: argparse_conflict_handler_resolve2.py [-h] [-a A]
                                             [--long-b LONG_B]
                                             [-b B]

optional arguments:
  -h, --help       show this help message and exit
  -a A
  --long-b LONG_B  Long and short together
  -b B             Short alone

Grupos de argumentos

argparse combina las definiciones de argumentos en «grupos». Por por defecto, utiliza dos grupos, uno para las opciones y otro para los argumentos requeridos basados en la posición.

argparse_default_grouping.py
import argparse

parser = argparse.ArgumentParser(description='Short sample app')

parser.add_argument('--optional', action="store_true",
                    default=False)
parser.add_argument('positional', action="store")

print(parser.parse_args())

La agrupación se refleja en los «argumentos posicionales» separados y secciones de «argumentos opcionales» de la salida de ayuda.

$ python3 argparse_default_grouping.py -h

usage: argparse_default_grouping.py [-h] [--optional] positional

Short sample app

positional arguments:
  positional

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

La agrupación se puede ajustar para que sea más lógica en la ayuda, para que las opciones o valores relacionados se documentan juntos. El ejemplo de opciones compartidas de antes podría escribirse usando una agrupación personalizada para que las opciones de autenticación se muestren juntas en la ayuda.

Crea el grupo «authentication» con add_argument_group() y luego agrega cada una de las opciones relacionadas con la autenticación al grupo, en lugar del analizador base.

argparse_parent_with_group.py
import argparse

parser = argparse.ArgumentParser(add_help=False)

group = parser.add_argument_group('authentication')

group.add_argument('--user', action="store")
group.add_argument('--password', action="store")

El programa que usa la lista padre agrupada enumera en los valores parents, como antes.

argparse_uses_parent_with_group.py
import argparse
import argparse_parent_with_group

parser = argparse.ArgumentParser(
    parents=[argparse_parent_with_group.parser],
)

parser.add_argument('--local-arg',
                    action="store_true",
                    default=False)

print(parser.parse_args())

La salida de ayuda ahora muestra las opciones de autenticación juntas.

$ python3 argparse_uses_parent_with_group.py -h

usage: argparse_uses_parent_with_group.py [-h] [--user USER]
                                          [--password PASSWORD]
                                          [--local-arg]

optional arguments:
  -h, --help           show this help message and exit
  --local-arg

authentication:
  --user USER
  --password PASSWORD

Opciones mutuamente excluyentes

La definición de opciones mutuamente excluyentes es un caso especial de la función de agrupación, y utiliza add_mutually_exclusive_group() en lugar de add_argument_group().

argparse_mutually_exclusive.py
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())

argparse hace cumplir la exclusividad mutua, de modo que solo se puede dar una de las opciones del grupo.

$ python3 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

$ python3 argparse_mutually_exclusive.py -a

Namespace(a=True, b=False)

$ python3 argparse_mutually_exclusive.py -b

Namespace(a=False, b=True)

$ python3 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

Anidar analizadores

El enfoque del analizador primario descrito anteriormente es una forma de compartir opciones entre comandos relacionados. Un enfoque alternativo es combinar los comandos en un solo programa y usar sub-analizadores para manejar cada porción de la línea de comando. El resultado funciona de la manera que svn, hg y otros programas con múltiples acciones de línea de comando, o sub-comandos, lo hacen.

Un programa para trabajar con directorios en el sistema de archivos podría definir comandos para crear, eliminar y enumerar el contenido de un directorio.

argparse_subparsers.py
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())

La salida de ayuda muestra los sub-analizadores nombrados como «comandos» que pueden ser especificados en la línea de comandos como argumentos posicionales.

$ python3 argparse_subparsers.py -h

usage: argparse_subparsers.py [-h] {list,create,delete} ...

positional arguments:
  {list,create,delete}  commands
    list                List contents
    create              Create a directory
    delete              Remove a directory

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

Cada analizador secundario también tiene su propia ayuda, que describe los argumentos y opciones para ese comando.

$ python3 argparse_subparsers.py create -h

usage: argparse_subparsers.py create [-h] [--read-only] dirname

positional arguments:
  dirname      New directory to create

optional arguments:
  -h, --help   show this help message and exit
  --read-only  Set permissions to prevent writing to the directo
ry

Y cuando se analizan los argumentos, el objeto Namespace devuelto por parse_args() incluye solo los valores relacionados con el comando especificado

$ python3 argparse_subparsers.py delete -r foo

Namespace(dirname='foo', recursive=True)

Procesamiento avanzado de argumentos

Los ejemplos hasta ahora han mostrado banderas booleanas simples, opciones con cadena o argumentos numéricos, y argumentos posicionales. argparse también admite una especificación sofisticada de argumentos para lista de argumentos de longitud variable, enumeraciones y valores constantes.

Listas de argumentos variables

Una definición de argumento único se puede configurar para consumir múltiples argumentos sobre la línea de comandos que se analiza. Establezca nargs en uno de los valores de indicador de the table below, basado en el número de argumentos requeridos o esperados.

Indicadores para definiciones de argumento variable en argparse
Valor Significado
N El número absoluto de argumentos. (p.e., 3).
? 0 o 1 argumentos
* 0 o todos los arguments
+ Todos, y al menos uno, argumento
argparse_nargs.py
import argparse

parser = argparse.ArgumentParser()

parser.add_argument('--three', nargs=3)
parser.add_argument('--optional', nargs='?')
parser.add_argument('--all', nargs='*', dest='all')
parser.add_argument('--one-or-more', nargs='+')

print(parser.parse_args())

El analizador aplica las instrucciones de conteo de argumentos y genera un diagrama de sintaxis precisa como parte del texto de ayuda del comando.

$ python3 argparse_nargs.py -h

usage: argparse_nargs.py [-h] [--three THREE THREE THREE]
                [--optional [OPTIONAL]]
                [--all [ALL [ALL ...]]]
                [--one-or-more ONE_OR_MORE [ONE_OR_MORE ...]]

optional arguments:
  -h, --help            show this help message and exit
  --three THREE THREE THREE
  --optional [OPTIONAL]
  --all [ALL [ALL ...]]
  --one-or-more ONE_OR_MORE [ONE_OR_MORE ...]

$ python3 argparse_nargs.py

Namespace(all=None, one_or_more=None, optional=None, three=None)

$ python3 argparse_nargs.py --three

usage: argparse_nargs.py [-h] [--three THREE THREE THREE]
                [--optional [OPTIONAL]]
                [--all [ALL [ALL ...]]]
                [--one-or-more ONE_OR_MORE [ONE_OR_MORE ...]]
argparse_nargs.py: error: argument --three: expected 3
argument(s)

$ python3 argparse_nargs.py --three a b c

Namespace(all=None, one_or_more=None, optional=None,
three=['a', 'b', 'c'])

$ python3 argparse_nargs.py --optional

Namespace(all=None, one_or_more=None, optional=None, three=None)

$ python3 argparse_nargs.py --optional with_value

Namespace(all=None, one_or_more=None, optional='with_value',
three=None)

$ python3 argparse_nargs.py --all with multiple values

Namespace(all=['with', 'multiple', 'values'], one_or_more=None,
optional=None, three=None)

$ python3 argparse_nargs.py --one-or-more with_value

Namespace(all=None, one_or_more=['with_value'], optional=None,
three=None)

$ python3 argparse_nargs.py --one-or-more with multiple values

Namespace(all=None, one_or_more=['with', 'multiple', 'values'],
optional=None, three=None)

$ python3 argparse_nargs.py --one-or-more

usage: argparse_nargs.py [-h] [--three THREE THREE THREE]
                [--optional [OPTIONAL]]
                [--all [ALL [ALL ...]]]
                [--one-or-more ONE_OR_MORE [ONE_OR_MORE ...]]
argparse_nargs.py: error: argument --one-or-more: expected
at least one argument

Tipos de argumentos

argparse trata todos los valores de argumento como cadenas, a menos que se le diga que convierta la cadena a otro tipo. El parámetro type para add_argument() define una función de conversión, que es utilizada por el ArgumentParser para transformar el valor del argumento de una cadena a otro tipo.

argparse_type.py
import argparse

parser = argparse.ArgumentParser()

parser.add_argument('-i', type=int)
parser.add_argument('-f', type=float)
parser.add_argument('--file', type=open)

try:
    print(parser.parse_args())
except IOError as msg:
    parser.error(str(msg))

Cualquier invocable que tome un solo argumento de cadena se puede pasar como type, incluyendo los tipos integrados como int y float o incluso open().

$ python3 argparse_type.py -i 1

Namespace(f=None, file=None, i=1)

$ python3 argparse_type.py -f 3.14

Namespace(f=3.14, file=None, i=None)

$ python3 argparse_type.py --file argparse_type.py

Namespace(f=None, file=<_io.TextIOWrapper
name='argparse_type.py' mode='r' encoding='UTF-8'>, i=None)

Si la conversión de tipo falla, argparse genera una excepción. Las excepciones TypeError y ValueError son atrapadas automáticamente y convertidas en un simple mensaje de error para el usuario. Otras excepciones, como el IOError en el siguiente ejemplo donde el archivo de entrada no existe, debe ser manejadas por la función llamante.

$ python3 argparse_type.py -i a

usage: argparse_type.py [-h] [-i I] [-f F] [--file FILE]
argparse_type.py: error: argument -i: invalid int value: 'a'

$ python3 argparse_type.py -f 3.14.15

usage: argparse_type.py [-h] [-i I] [-f F] [--file FILE]
argparse_type.py: error: argument -f: invalid float value:
'3.14.15'

$ python3 argparse_type.py --file does_not_exist.txt

usage: argparse_type.py [-h] [-i I] [-f F] [--file FILE]
argparse_type.py: error: [Errno 2] No such file or directory:
'does_not_exist.txt'

Para limitar un argumento de entrada a un valor dentro de un conjunto predefinido, usa el parámetro choices.

argparse_choices.py
import argparse

parser = argparse.ArgumentParser()

parser.add_argument(
    '--mode',
    choices=('read-only', 'read-write'),
)

print(parser.parse_args())

Si el argumento de --mode no es uno de los valores permitidos, se genera un error y el procesamiento se detiene.

$ python3 argparse_choices.py -h

usage: argparse_choices.py [-h] [--mode {read-only,read-write}]

optional arguments:
  -h, --help            show this help message and exit
  --mode {read-only,read-write}

$ python3 argparse_choices.py --mode read-only

Namespace(mode='read-only')

$ python3 argparse_choices.py --mode invalid

usage: argparse_choices.py [-h] [--mode {read-only,read-write}]
argparse_choices.py: error: argument --mode: invalid choice:
'invalid' (choose from 'read-only', 'read-write')

Argumentos de archivo

Aunque los objetos file se pueden instanciar con un solo argumento de cadena, que no incluye el argumento del modo de acceso. FileType proporciona una forma más flexible de especificar que un argumento debe ser un archivo, incluido el modo y el tamaño del búfer.

argparse_FileType.py
import argparse

parser = argparse.ArgumentParser()

parser.add_argument('-i', metavar='in-file',
                    type=argparse.FileType('rt'))
parser.add_argument('-o', metavar='out-file',
                    type=argparse.FileType('wt'))

try:
    results = parser.parse_args()
    print('Input file:', results.i)
    print('Output file:', results.o)
except IOError as msg:
    parser.error(str(msg))

El valor asociado con el nombre del argumento es el identificador de archivo abierto. La aplicación es responsable de cerrar el archivo cuando no ya no se usa.

$ python3 argparse_FileType.py -h

usage: argparse_FileType.py [-h] [-i in-file] [-o out-file]

optional arguments:
  -h, --help   show this help message and exit
  -i in-file
  -o out-file

$ python3 argparse_FileType.py -i argparse_FileType.py -o tmp_\
file.txt

Input file: <_io.TextIOWrapper name='argparse_FileType.py'
mode='rt' encoding='UTF-8'>
Output file: <_io.TextIOWrapper name='tmp_file.txt' mode='wt'
encoding='UTF-8'>

$ python3 argparse_FileType.py -i no_such_file.txt

usage: argparse_FileType.py [-h] [-i in-file] [-o out-file]
argparse_FileType.py: error: argument -i: can't open
'no_such_file.txt': [Errno 2] No such file or directory:
'no_such_file.txt'

Acciones personalizadas

Además de las acciones integradas descritas anteriormente, las acciones personalizadas se puede definir proporcionando un objeto que implemente la interfaz de programación de acción. El objeto pasado a add_argument() como action debería tomar parámetros que describen el argumento que se está definiendo (de todos modos argumentos dados a add_argument()) y devuelven un objeto invocable que toma como parámetros el parser que procesa los argumentos, el namespace que contiene los resultados del análisis, el value del argumento sobre el que se actuando, y la option_string que activó la acción.

Se proporciona una clase de Action como un punto de partida conveniente para definir nuevas acciones. El constructor maneja las definiciones de argumentos, por lo que solo __call__() debe anularse en la subclase.

argparse_custom_action.py
import argparse


class CustomAction(argparse.Action):
    def __init__(self,
                 option_strings,
                 dest,
                 nargs=None,
                 const=None,
                 default=None,
                 type=None,
                 choices=None,
                 required=False,
                 help=None,
                 metavar=None):
        argparse.Action.__init__(self,
                                 option_strings=option_strings,
                                 dest=dest,
                                 nargs=nargs,
                                 const=const,
                                 default=default,
                                 type=type,
                                 choices=choices,
                                 required=required,
                                 help=help,
                                 metavar=metavar,
                                 )
        print('Initializing CustomAction')
        for name, value in sorted(locals().items()):
            if name == 'self' or value is None:
                continue
            print('  {} = {!r}'.format(name, value))
        print()
        return

    def __call__(self, parser, namespace, values,
                 option_string=None):
        print('Processing CustomAction for {}'.format(self.dest))
        print('  parser = {}'.format(id(parser)))
        print('  values = {!r}'.format(values))
        print('  option_string = {!r}'.format(option_string))

        # Do some arbitrary processing of the input values
        if isinstance(values, list):
            values = [v.upper() for v in values]
        else:
            values = values.upper()
        # Save the results in the namespace using the destination
        # variable given to our constructor.
        setattr(namespace, self.dest, values)
        print()


parser = argparse.ArgumentParser()

parser.add_argument('-a', action=CustomAction)
parser.add_argument('-m', nargs='*', action=CustomAction)

results = parser.parse_args(['-a', 'value',
                             '-m', 'multivalue',
                             'second'])
print(results)

El tipo de values depende del valor de nargs. Si el argumento permite múltiples valores, values será una lista incluso si solo contiene un elemento.

El valor de option_string también depende de la especificación de argumento original. Para argumentos posicionales requeridos, option_string es siempre None.

$ python3 argparse_custom_action.py

Initializing CustomAction
  dest = 'a'
  option_strings = ['-a']
  required = False

Initializing CustomAction
  dest = 'm'
  nargs = '*'
  option_strings = ['-m']
  required = False

Processing CustomAction for a
  parser = 4315836992
  values = 'value'
  option_string = '-a'

Processing CustomAction for m
  parser = 4315836992
  values = ['multivalue', 'second']
  option_string = '-m'

Namespace(a='VALUE', m=['MULTIVALUE', 'SECOND'])

Ver también