inquirer - python cmd
¿Implementando un estilo de interfaz de línea de comando "[comando][acción][parámetro]"? (6)
¿Cuál es la forma más "limpia" de implementar una interfaz de usuario de línea de comando, similar a la de git, por ejemplo:
git push origin/master
git remote add origin git://example.com master
Lo ideal también es permitir un análisis más flexible, por ejemplo,
jump_to_folder app theappname v2
jump_to_folder app theappname source
jump_to_folder app theappname source v2
jump_to_folder app theappname build v1
jump_to_folder app theappname build 1
jump_to_folder app theappname v2 build
jump_to_folder
es el nombre de los scripts, la app
es el comando, theappname
es un parámetro de "ubicación fija", "build" y "v2" etc. son argumentos (por ejemplo, los posibles argumentos serían cualquier número / cualquier número con prefijo av, o build / source / tmp / config)
Podría analizar manualmente los argumentos con una serie de if
/ else
/ elifs
, pero debe haber una forma más elegante de hacerlo.
Como un ejemplo completamente teórico, podría describir el esquema de UI ...
app:
fixed: application_name
optional params:
arg subsection:
"build"
"source"
"tmp"
"config"
arg version:
integer
"v" + integer
Luego, analice los argumentos proporcionados a través del esquema anterior y obtenga un diccionario:
>>> print schema.parse(["app", "theappname", "v1", "source"])
{
"application_name": "theappname",
"params":{
"subsection": "source",
"version":"v1"
}
}
¿Existe tal sistema? Si no, ¿cómo podría implementar algo en esta línea?
argparse es perfecto para esto, específicamente "sub-comandos" y argumentos posicionales
import argparse
def main():
arger = argparse.ArgumentParser()
# Arguments for top-level, e.g "subcmds.py -v"
arger.add_argument("-v", "--verbose", action="count", default=0)
subparsers = arger.add_subparsers(dest="command")
# Make parser for "subcmds.py info ..."
info_parser = subparsers.add_parser("info")
info_parser.add_argument("-m", "--moo", dest="moo")
# Make parser for "subcmds.py create ..."
create_parser = subparsers.add_parser("create")
create_parser.add_argument("name")
create_parser.add_argument("additional", nargs="*")
# Parse
opts = arger.parse_args()
# Print option object for debug
print opts
if opts.command == "info":
print "Info command"
print "--moo was %s" % opts.moo
elif opts.command == "create":
print "Creating %s" % opts.name
print "Additional: %s" % opts.additional
else:
# argparse will error on unexpected commands, but
# in case we mistype one of the elif statements...
raise ValueError("Unhandled command %s" % opts.command)
if __name__ == ''__main__'':
main()
Esto se puede usar así:
$ python subcmds.py create myapp v1 blah
Namespace(additional=[''v1'', ''blah''], command=''create'', name=''myapp'', verbose=0)
Creating myapp
Additional: [''v1'', ''blah'']
$ python subcmds.py info --moo
usage: subcmds.py info [-h] [-m MOO]
subcmds.py info: error: argument -m/--moo: expected one argument
$ python subcmds.py info --moo 1
Namespace(command=''info'', moo=''1'', verbose=0)
Info command
--moo was 1
Aquí está mi sugerencia.
Cambia tu gramática un poco.
Use optparse.
Lo ideal también es permitir un análisis más flexible, por ejemplo,
jump_to_folder -n theappname -v2 cmd
jump_to_folder -n theappname cmd source
jump_to_folder -n theappname -v2 cmd source
jump_to_folder -n theappname -v1 cmd build
jump_to_folder -n theappname -1 cmd build
jump_to_folder -n theappname -v2 cmd build
Entonces tienes 1 o 2 args: el comando es siempre el primer arg. Su argumento opcional es siempre el segundo arg.
Todo lo demás son opciones, sin ningún orden en particular.
Directamente de uno de mis guiones:
import sys
def prog1_func1_act1(): print "pfa1"
def prog2_func2_act2(): print "pfa2"
commands = {
"prog1 func1 act1": prog1_func1_act1,
"prog2 func2 act2": prog2_func2_act2
}
try:
commands[" ".join(sys.argv[1:])]()
except KeyError:
print "Usage: ", commands.keys()
Es una solución bastante rápida y sucia, pero funciona muy bien para mi uso. Si tuviera que limpiarlo un poco, probablemente agregaría argparse a la mezcla para analizar argumentos posicionales y palabras clave.
Python tiene un módulo para analizar las opciones de línea de comando, optparse .
El módulo cmd
probablemente funcionaría bien para esto.
Ejemplo:
import cmd
class Calc(cmd.Cmd):
def do_add(self, arg):
print sum(map(int, arg.split()))
if __name__ == ''__main__'':
Calc().cmdloop()
Ejecutarlo:
$python calc.py
(Cmd) add 4 5
9
(Cmd) help
Undocumented commands:
======================
add help
(Cmd)
Consulte los documentos Python o el sitio PyMOTW para obtener más información.
Es posible que desee echar un vistazo a cliff - Marco de formulación de interfaz de línea de comandos