Interfaces de comandos con Python
Entre las muchas cosas para las que uso Python está
escribir pequeñas herramientas de líneas de comandos que me ayudan en el día a
día (especialmente cuando toca trabajar de devops). Aunque en la biblioteca
estándar existe argparse
y muchos están contentos con eso, personalmente me
gustan alternativas que me hagan la vida más fácil.
Docopt.
Docopt Es (en mi opinión) uno de los mejores frameworks para crear herramientas de líneas de comandos que existe y tiene además la ventaja de no ser exclusiva de Python, para utilizarla solo tienes que documentar el módulo o función que va a obtener los argumentos de la línea de comandos. Veamos un ejemplo de una herramienta que utilizo para subscribir ahorrarme tener que subscribir a un conjunto de usuarios cuando creo un repositorio.
"""Subscriber.
Usage:
subscriber.py repo <reponame> group <groupname>
"""
def main(arguments):
repo_name = arguments.get('<reponame>')
group_name = arguments.get('<groupname>')
# El resto va aqui
if __name__ == '__main__':
arguments = docopt(__doc__)
main(arguments)
Al invocar la herramienta sin parámetros obtenemos el siguiente mensaje de ayuda:
$ python subscriber.py
Usage:
subscriber.py repo <reponame> group <groupname>
Para utilizarla simplemente podemos
$ python subscriber.py repo https://my.repo.cu group developers
Ventajas:
- El código extra es mínimo (casi todo es documentación).
- Ganas la documentación de gratis.
- El minilenguaje de las cli es extremadamente poderoso.
Desventajas:
- Tienes que aprender el minilenguaje.
Lazycli.
Lazycli es un framework muy
nuevo pero de una simpleza y claridad que dan ganas de usarlo. En lugar de
documentación utilizamos decoradores para declarar nuestra CLI. El autor nos
muestra como ejemplo un clon de cp
#!/usr/bin/env python3
import lazycli
import shutil
import sys
@lazycli.script
def cp(*src, dst, recursive=False):
"""copy around files"""
for path in src:
try:
shutil.copy2(path, dst)
except IsADirectoryError as err:
if recursive:
shutil.copytree(path, dst)
else:
print(err, file=sys.stderr)
if __name__ == '__main__':
cp.run()
Si invocamos la herramienta obtenemos lo siguiente:
$ python cp.py -h
usage: cp.py [-h] [-r] [src [src ...]] dst
copy around files
positional arguments:
src
dst
optional arguments:
-h, --help show this help message and exit
-r, --recursive
Ventajas:
- Casi 0 código extra (ejecutar el objeto que devuelve el decorador).
- Convención sobre configuración.
Desventajas:
- No es tán versátil como
docopt
.