usage pyimagesearch parser float argumentparser argument and python argparse

python - pyimagesearch - Argparse-Cómo especificar un subcomando predeterminado



arguments parser python (2)

Estoy utilizando el paquete argparse de Python 2.7 para escribir alguna lógica de análisis de opciones para una herramienta de línea de comandos. La herramienta debe aceptar uno de los siguientes argumentos:

"ON": enciende una función.
"OFF": desactiva una función.
[No se proporcionan argumentos]: se hace eco del estado actual de la función.

Mirar la documentación argparse me llevó a creer que quería que se definieran dos subcomandos, posiblemente tres, ya que estos tres estados se excluyen mutuamente y representan diferentes actividades conceptuales. Este es mi intento actual en el código:

parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() parser.set_defaults(func=print_state) # I think this line is wrong. parser_on = subparsers.add_parser(''ON'') parser_on.set_defaults(func=set_state, newstate=''ON'') parser_off = subparsers.add_parser(''OFF'') parser_off.set_defaults(func=set_state, newstate=''OFF'') args = parser.parse_args() if(args.func == set_state): set_state(args.newstate) elif(args.func == print_state): print_state() else: args.func() # Catchall in case I add more functions later

Tenía la impresión de que si proporcionaba 0 argumentos, el analizador principal configuraría func=print_state , y si proporcionaba 1 argumento, el analizador principal usaría los valores predeterminados del subcomando apropiado y llamaría func=set_state . En su lugar, me sale el siguiente error con 0 argumentos:

usage: cvsSecure.py [-h] {ON,OFF} ... cvsSecure.py: error: too few arguments

Y si proporciono "OFF" u "ON", se llama a set_state lugar de set_state . Si comento fuera de la línea set_state , set_state se llama correctamente.

Soy un programador a nivel de oficial, pero un principiante de rango para Python. ¿Alguna sugerencia sobre cómo puedo hacer que esto funcione?

Edit : Otra razón por la que estaba viendo subcomandos fue una cuarta función potencial que estoy considerando para el futuro:

"FORCE txtval": establece el estado de la función en txtval .


Hay dos problemas con su enfoque.

En primer lugar, probablemente ya haya notado que newstate no es un subvalor del sub parser y debe abordarse en el nivel superior de args.newstate como args.newstate . Eso debería explicar que al asignar un valor predeterminado a newstate dos veces, se sobrescribirá el primer valor. Ya sea que llame a su programa con ''ON'' o ''OFF'' como parámetro, cada vez que se set_state() con OFF . Si solo quieres poder hacer python cvsSecure ON y python cvsSecure OFF lo siguiente funcionaría:

from __future__ import print_function import sys import argparse def set_state(state): print("set_state", state) def do_on(args): set_state(''ON'') def do_off(args): set_state(''OFF'') parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() parser_on = subparsers.add_parser(''ON'') parser_on.set_defaults(func=do_on) parser_on.add_argument(''--fast'', action=''store_true'') parser_off = subparsers.add_parser(''OFF'') parser_off.set_defaults(func=do_off) args = parser.parse_args() args.func(args)

El segundo problema es que argparse maneja subparsers como argumentos de valor único, por lo que debe especificar uno antes de invocar parser.parse_args() . Puede automatizar la inserción de un argumento faltante agregando un subparser adicional ''PRINT'' e insertándolo automáticamente usando set_default_subparser agregado a argparse.ArgumentParser() (ese código es parte del paquete ruamel.std.argparse

from __future__ import print_function import sys import argparse def set_default_subparser(self, name, args=None): """default subparser selection. Call after setup, just before parse_args() name: is the name of the subparser to call by default args: if set is the argument list handed to parse_args() , tested with 2.7, 3.2, 3.3, 3.4 it works with 2.6 assuming argparse is installed """ subparser_found = False for arg in sys.argv[1:]: if arg in [''-h'', ''--help'']: # global help if no subparser break else: for x in self._subparsers._actions: if not isinstance(x, argparse._SubParsersAction): continue for sp_name in x._name_parser_map.keys(): if sp_name in sys.argv[1:]: subparser_found = True if not subparser_found: # insert default in first position, this implies no # global options without a sub_parsers specified if args is None: sys.argv.insert(1, name) else: args.insert(0, name) argparse.ArgumentParser.set_default_subparser = set_default_subparser def print_state(args): print("print_state") def set_state(state): print("set_state", state) def do_on(args): set_state(''ON'') def do_off(args): set_state(''OFF'') parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() parser_print = subparsers.add_parser(''PRINT'', help=''default action'') parser_print.set_defaults(func=print_state) parser_on = subparsers.add_parser(''ON'') parser_on.set_defaults(func=do_on) parser_on.add_argument(''--fast'', action=''store_true'') parser_off = subparsers.add_parser(''OFF'') parser_off.set_defaults(func=do_off) parser.set_default_subparser(''PRINT'') args = parser.parse_args() args.func(args)

No necesita manejar en args a do_on() , etc., pero es útil si comienza a especificar opciones para los diferentes subparsers.


Los valores predeterminados del analizador de nivel superior anulan los valores predeterminados en los subparadores, por lo que se ignora el establecimiento del valor predeterminado de func en los subparadores, pero el valor de newstate de los valores predeterminados del subparador es correcto.

No creo que quieras usar subcomandos. Los subcomandos se utilizan cuando las opciones disponibles y los argumentos posicionales cambian según el subcomando que se elija. Sin embargo, no tiene otras opciones o argumentos posicionales.

El siguiente código parece hacer lo que necesita:

import argparse def print_state(): print "Print state" def set_state(s): print "Setting state to " + s parser = argparse.ArgumentParser() parser.add_argument(''state'', choices = [''ON'', ''OFF''], nargs=''?'') args = parser.parse_args() if args.state is None: print_state() elif args.state in (''ON'', ''OFF''): set_state(args.state)

Tenga en cuenta los parámetros opcionales para parser.add_argument . El parámetro "opciones" especifica las opciones permitidas, mientras se configura "nargs" en "?" especifica que se debe consumir 1 argumento si está disponible, de lo contrario no se debe consumir ninguno.

Editar: Si desea agregar un comando FORCE con un argumento y tener un texto de ayuda separado para el comando ON y OFF, entonces necesita usar subcomandos. Desafortunadamente, no parece haber una forma de especificar un subcomando predeterminado. Sin embargo, puede solucionar el problema buscando una lista de argumentos vacía y proporcionando la suya propia. Aquí hay un código de ejemplo que ilustra lo que quiero decir:

import argparse import sys def print_state(ignored): print "Print state" def set_state(s): print "Setting state to " + s parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() on = subparsers.add_parser(''ON'', help = ''On help here.'') on.set_defaults(func = set_state, newstate = ''ON'') off = subparsers.add_parser(''OFF'', help = ''Off help here.'') off.set_defaults(func = set_state, newstate = ''OFF'') prt = subparsers.add_parser(''PRINT'') prt.set_defaults(func = print_state, newstate = ''N/A'') force = subparsers.add_parser(''FORCE'' , help = ''Force help here.'') force.add_argument(''newstate'', choices = [ ''ON'', ''OFF'' ]) force.set_defaults(func = set_state) if (len(sys.argv) < 2): args = parser.parse_args([''PRINT'']) else: args = parser.parse_args(sys.argv[1:]) args.func(args.newstate)