Creación de utilidades de línea de comandos con argparse de Python

A veces, las aplicaciones son lo suficientemente pequeñas como para que realmente no necesiten una GUI. En tales casos, una interfaz de línea de comandos es suficiente. En este artículo, usaremos el módulo argparse para crear algunas aplicaciones CLI en Python.

Introducción

La mayor parte del software orientado al usuario viene con una interfaz visualmente agradable o a través de una página web decorada. En otras ocasiones, un programa puede ser tan pequeño que no garantiza una interfaz gráfica de usuario completa o una aplicación web para exponer su funcionalidad al usuario final.

En estos casos, podemos crear programas a los que se pueda acceder a través de una Interfaz de línea de comandos o CLI.

En esta publicación, exploraremos el módulo argparse de Python y lo usaremos para crear una herramienta de línea de comandos simple que nos ayude a acortar las URL rápidamente.

Interfaz de línea de comandos {#interfaz de línea de comandos}

Una interfaz de línea de comandos es una interfaz de usuario basada en texto que proporciona un medio para interactuar con una computadora a través de comandos de texto. El programa que facilita esta interacción al exponer la interfaz se conoce como intérprete de línea de comandos o shell.

Recibe comandos en forma de entrada de texto, ejecuta programas basados ​​en la entrada proporcionada y luego muestra la salida en la interfaz. Hay muchas conchas disponibles, siendo las primeras populares la concha de bourne y [caparazón C](https://en.wikipedia.org/wiki /C_shell) para sistemas basados ​​en Unix. El Bourne Again Shell (también conocido como bash) es una extensión muy popular del Bourne Shell, junto con el [Concha Korn](https://en .wikipedia.org/wiki/KornShell) (ksh).

También vale la pena señalar que las CLI, como otro software, requieren cuentas de usuario para trabajar con ellas. El sistema impone permisos a estos usuarios para ayudar a controlar el nivel de acceso y el límite de lo que un usuario puede lograr con el sistema. Esta distinción es necesaria ya que el shell es una interfaz entre el usuario y el kernel del sistema operativo que controla todas las operaciones de la computadora. El acceso a esta funcionalidad debe restringirse para evitar el uso malintencionado de la interfaz de línea de comandos.

Las CLI ofrecen un aviso, que suele ser un signo de dólar ($) que indica que puede ingresar su comando. Sin embargo, este mensaje también indica que el comando ingresado se ejecutará sin acceso de root.

Cuando se otorga acceso raíz al usuario actual que interactúa con la CLI, el indicador cambia a un signo de almohadilla (#).

Si bien las Interfaces gráficas de usuario (GUI) son más fáciles de aprender y visualmente más intuitivas, las CLI permiten a los usuarios interactuar con el software usando solo un teclado, lo que puede resultar en un rendimiento más rápido. Las CLI también consumen menos recursos informáticos en comparación con las GUI, lo que las hace más ligeras y rápidas.

Secuencias de comandos

La mayoría de los intérpretes de línea de comandos vienen con algunos comandos básicos que se pueden invocar a través de la interfaz de línea de comandos para realizar tareas específicas. Algunos comunes incluyen:

  • uptime: Indica cuánto tiempo ha estado encendida la computadora
  • fecha: Devuelve la fecha y hora actual
  • ls: Devuelve una lista de todos los archivos y carpetas en un directorio
  • cd: Se utiliza para pasar de un directorio a otro
  • pwd: Se utiliza para mostrar el directorio de trabajo actual
  • man: Se usa para mostrar el manual o instrucciones de cualquier comando
  • touch: se usa para crear archivos nuevos y vacíos
  • mkdir: Usado para crear nuevos directorios

Un script de shell es un programa diseñado para ser ejecutado por un intérprete de línea de comandos. Contiene una serie de comandos, como los enumerados anteriormente, junto con variables y condiciones que instruyen al shell sobre qué tarea o tareas realizar.

A través de scripts de shell, un usuario puede ejecutar varios comandos en rápida sucesión sin necesidad de recordarlos todos. Se utilizan principalmente para lograr operaciones repetitivas sin la entrada repetitiva de comandos, por lo tanto, reducen el esfuerzo requerido por el usuario final.

Podemos escribir scripts de shell que consisten en los comandos de shell que se ejecutarán, pero también podemos ejecutar otros lenguajes de alto nivel, como Python y JavaScript.

¿Qué es argparse?

Un script de shell de Python es solo un programa normal de Python que ejecuta el intérprete de línea de comandos. Al ejecutar un script de shell, los argumentos se pasan a nuestro script a través de sys.argv. Esta variable es una lista de los argumentos pasados ​​a nuestro programa, incluido el nombre del script, que también es el primer argumento.

Normalmente, podemos escribir un script simple que no requiera argumentos adicionales, como un script simple para mostrar la fecha actual. Sin embargo, esto limitará la funcionalidad que podemos ofrecer. Para que nuestros scripts sean más versátiles y amplíen el alcance de su uso, tenemos que facilitar la personalización a través de argumentos que le den al usuario más control y opciones en términos de funcionalidad.

El módulo argparse nos ayuda a analizar los argumentos pasados ​​con nuestro script y procesarlos de una manera más conveniente. También añade funciones de personalización como poner nombre a nuestro programa y añadir descripciones de una forma más sencilla.

argparse también nos proporciona un medio para personalizar las instrucciones de uso de nuestro script e indicar qué argumentos son necesarios y cuáles son opcionales. Para explorar todas estas funciones y más, crearemos nuestra propia utilidad Python CLI en la siguiente sección.

Aplicación de demostración

Actualmente, si queremos acortar una URL, necesitaremos iniciar un navegador y navegar a un sitio de acortamiento de URL para realizar la tarea. Nuestro objetivo es acelerar y mejorar este proceso de acortamiento de URL a través de un script que podemos ejecutar en cualquier momento en nuestra terminal. Solo tendremos que pasar las URL que necesitamos acortar como argumentos y recibir las URL acortadas como respuesta.

Para esta demostración, usaremos Corto.st como nuestro proveedor, ya que su API es simple y directa.

Después de crear una cuenta, podemos dirigirnos a la sección Herramientas de enlace y seleccionar API de desarrolladores. Aquí encontraremos nuestro token de acceso y la URL que usará nuestro script para acortar nuestras URL.

Una vez que el usuario proporcione una URL a nuestra utilidad de línea de comandos para acortarla, enviaremos la URL al punto final Shorte.st API junto con nuestro token de acceso. La respuesta será nuestra URL abreviada y un mensaje de estado.

Comencemos creando un entorno virtual e instalando el módulo de solicitudes, que usaremos para enviar solicitudes HTTP a la API:

1
2
3
4
$ mkdir pyshortener && cd pyshortener
$ virtualenv --python=python3 env --no-site-packages
$ source env/bin/activate
$ pip install requests

En la primera línea de arriba hemos combinado dos comandos en uno usando el doble ampersand (&&). Esto nos permite ejecutar los comandos en secuencia, a menos que falle el primer comando, lo que impide que se ejecute el segundo comando.

Después de crear nuestro entorno virtual y activarlo, instalamos nuestra dependencia de Python.

Para esta demostración, primero construiremos nuestra función de acortamiento y luego envolveremos su funcionalidad usando argparse en el script final:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests
from requests.exceptions import ConnectionError
import json

def shorten_url(url):
    try:
        response = requests.put("https://api.shorte.st/v1/data/url",
                                {"urlToShorten": url},
                                headers={"public-api-token": "[MY-API-TOKEN]"})

        api_response = json.loads(response.content)

        return {"status": api_response['status'],
                "shortenedUrl": api_response['shortenedUrl'],
                "message": "URL shortened successfully"}

    except ConnectionError:
        return {"status": "error",
                "shortenedUrl": None,
                "message": "Please ensure you are connected to the internet and try again."}

shorten_url(www.wikihtp.com)

Nuestra función toma una URL y la envía a la API de Shorte.st y devuelve la URL acortada. Acortemos www.wikihtp.com ejecutando nuestro script:

1
2
$ python pyshortener.py
{'status': 'ok', 'shortenedUrl': 'http://gestyy.com/w6ph2J', 'message': 'URL shortened successfully'}

Como podemos ver, nuestra función funciona pero el resultado es menos que ideal. También tenemos que codificar la URL en el propio script, lo que nos proporciona una entrada y una salida fijas.

Vamos a llevar esto un paso más allá y permitiremos que los usuarios pasen la URL como argumento cuando ejecuten el script. Para hacer esto, ahora introduciremos argparse para ayudarnos a analizar los argumentos proporcionados por el usuario:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import requests
from requests.exceptions import ConnectionError
import json
import argparse # Add the argparse import

def shorten_url(url):
    # Code stays the same...

# Create a parser
parser = argparse.ArgumentParser(description='Shorten URLs on the terminal')

# Add argument
parser.add_argument('--url', default="google.com", help="The URL to be shortened")
args = vars(parser.parse_args())
print(args)

En esta versión del script, no llamamos shorten_url, sino que simplemente imprimimos los argumentos capturados y analizados por argparse.

Comenzamos creando un objeto ArgumentParser usando argparse, que contendrá toda la información necesaria para transformar los argumentos pasados ​​en tipos de datos de Python con los que podemos trabajar.

Después de crear el analizador, ahora podemos agregar argumentos usando parser.add_argument(). Esta función permite especificar la siguiente información sobre nuestros argumentos:

  • El primer argumento es un nombre o una bandera utilizada para identificar nuestros argumentos. Los argumentos opcionales se identifican con el prefijo -, en nuestro caso --url es un argumento opcional.
  • La opción default permite especificar un valor predeterminado cuando el usuario no ha proporcionado el argumento.
  • La opción ayuda describe brevemente cuál es el argumento.
  • También podemos usar la opción choice para especificar valores permitidos para un argumento, como sí y no.
  • A través de una opción tipo también podemos especificar el tipo al que se convertirá nuestro comando, por ejemplo, convertir argumentos en números enteros.

Cuando ejecutamos nuestro script sin proporcionar ningún argumento, la URL predeterminada es "google.com", tal como lo hemos establecido en el método add_argument:

1
2
$ python pyshortener.py
{'url': 'google.com'}

Ahora, cuando pasamos www.wikihtp.com usando el indicador --url, se establece como el valor de la clave url:

1
2
$ python pyshortener.py --url www.wikihtp.com
{'url': 'www.wikihtp.com'}

Ahora podemos recibir la URL de un usuario a través de la línea de comando y acortarla modificando nuestro script:

1
2
if args.get('url'):
   print(shorten_url(args['url']))

Cuando lo ejecutamos y pasamos una URL, deberíamos recibir el resultado de la API de Shorte.st:

1
2
$ python pyshortener.py --url wikihtp.com
{'status': 'ok', 'shortenedUrl': 'http://gestyy.com/w6pk2R', 'message': 'URL shortened successfully'}

Aunque nuestra salida no es tan amigable como nos gustaría, creemos una función para formatear nuestra salida de una manera más deseable:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def handle_output(result):
   """ Function to format and print the output
   """
   if result["status"] == "ok":
       print(f"{result['message']}. Your shortened URL is:\n"
             f"\t{result['shortenedUrl']}")
   elif result["status"] == "error":
       print(f"{result['message']}")

# Receive and process the argument
args = vars(parser.parse_args())

if args.get('url'):
   result = shorten_url(args['url'])
   handle_output(result)

Cuando ejecutamos nuestro script una vez más:

1
2
3
$ python pyshortener.py --url www.wikihtp.com
URL shortened successfully. Your shortened URL is:
        http://gestyy.com/w6pk2R

Nuestra salida ahora es más fácil de usar debido a la adición de la función handle_output(). Para ver cómo argparse ha generado el texto de ayuda para nuestro script, podemos ejecutar nuestro script con el indicador -h para mostrar el texto de ayuda de la siguiente manera:

1
2
3
4
5
6
7
8
$ python pyshortener.py -h
usage: pyshortener.py [-h] [--url URL]

Shorten URLs on the terminal

optional arguments:
  -h, --help  show this help message and exit
  --url URL   The URL to be shortened

Conclusión

Hemos creado un script de shell usando Python para ayudarnos a acortar las URL rápidamente en la terminal. Hemos utilizado el módulo argparse para analizar los argumentos que se pasan a nuestro script e incluso definimos un valor predeterminado en caso de que se proporcione el argumento.

Nuestro script ahora también tiene un hermoso mensaje de ayuda que se puede mostrar usando el indicador -h que fue generado por el módulo argparse, lo que significa que no tuvimos que escribirlo manualmente.

El siguiente paso sería mejorar nuestro script para aceptar una lista de URL o leer URL de un archivo de texto para facilitar el acortamiento por lotes de URL.

El código fuente del script de este proyecto se puede encontrar aquí en Github.

Licensed under CC BY-NC-SA 4.0