Programación de interfaz de línea de comandos en Python

Este artículo analiza cómo puede crear una CLI para sus programas de python utilizando un ejemplo en el que creamos un «administrador de archivos de texto» básico. 
Discutamos algunos conceptos básicos primero. 
 

¿Qué es una interfaz de línea de comandos (CLI)?

Una interfaz de línea de comandos o intérprete de lenguaje de comandos (CLI), también conocida como interfaz de usuario de línea de comandos, interfaz de usuario de consola e interfaz de usuario de caracteres (CUI), es un medio para interactuar con un programa de computadora donde el usuario (o cliente) emite comandos al programa en forma de líneas sucesivas de texto (líneas de comando). ( Wiki )
Ventajas de CLI: 
 

  • Requiere menos recursos
  • Conciso y poderoso
  • Apto para expertos
  • Más fácil de automatizar a través de secuencias de comandos

¿Por qué usar CLI en su programa python?

  • Tener incluso una interfaz de línea de comandos (CLI) muy básica para su programa puede hacer que la vida de todos sea más fácil para modificar parámetros, incluidos los programadores, pero también los no programadores.
  • Una CLI para su programa también puede facilitar la automatización de la ejecución y la modificación de variables dentro de su programa, para cuando desee ejecutar su programa con un cronjob o tal vez una llamada os.system.

Ahora, comencemos a hacer nuestro «Administrador de archivos de texto». Aquí, usaremos una biblioteca de python integrada llamada Argparse .
Acerca de Argparse: 
 

  • Facilita la escritura de interfaces de línea de comandos fáciles de usar.
  • El programa define qué argumentos requiere, y argparse descubrirá cómo analizarlos de sys.argv.
  • El módulo argparse también genera automáticamente mensajes de ayuda y uso y emite errores cuando los usuarios proporcionan argumentos no válidos al programa.

Ok, comencemos con un programa realmente básico para tener una idea de lo que hace argparse.
 

Python

# importing required modules
import argparse
 
# create a parser object
parser = argparse.ArgumentParser(description = "An addition program")
 
# add argument
parser.add_argument("add", nargs = '*', metavar = "num", type = int,
                     help = "All the numbers separated by spaces will be added.")
 
# parse the arguments from standard input
args = parser.parse_args()
 
# check if add argument has any input data.
# If it has, then print sum of the given numbers
if len(args.add) != 0:
    print(sum(args.add))

Repasemos algunos puntos importantes relacionados con el programa anterior: 
 

  • En primer lugar, importamos el módulo argparse.
  • Luego, creó un objeto ArgumentParser y también proporcionó una descripción de nuestro programa.
  • Ahora, podemos llenar nuestro objeto analizador con información agregando argumentos. En este ejemplo, creamos un argumento add. Se pueden pasar muchos argumentos a la función add_argument . Aquí explico los que he usado en el ejemplo anterior: 
    argumento 1: («añadir») No es más que el nombre del argumento. Usaremos este nombre para acceder a los argumentos de adición escribiendo args.add
    argumento 2: (nargs = ‘*’) El número de argumentos de la línea de comandos que deben consumirse. Especificarlo en ‘*’ significa que puede ser cualquier no. de argumentos, es decir, de 0 a cualquier cosa. 
    argumento 3: (metavar = ‘num’) Un nombre para el argumento en los mensajes de uso. 
    argumento 4:(tipo = int) El tipo al que se debe convertir el argumento de la línea de comandos. Es str por defecto. 
    argumento 5: (ayuda) Una breve descripción de lo que hace el argumento.
  • Una vez que hemos especificado todos los argumentos, es el momento de analizar los argumentos del flujo de entrada de la línea de comando estándar. Para esto, usamos la función parse_args().
  • Ahora, uno puede simplemente verificar si la entrada ha invocado un argumento específico. Aquí, verificamos la longitud de args.add para verificar si se recibieron datos de la entrada. Tenga en cuenta que los valores de un argumento se obtienen como una lista.
  • Hay dos tipos de argumentos: posicionales y opcionales. 
    Los posicionales son aquellos que no necesitan ninguna especificación para ser invocados. Mientras que los argumentos opcionales deben especificarse primero por su nombre (que comienza con el signo ‘-‘, ‘-‘ también es una abreviatura).
  • Siempre se puede usar el argumento opcional –help o -h para ver el mensaje de ayuda. 
    Aquí hay un ejemplo (el script de python se ha guardado como add.py): 
     

2

  • Ahora, echemos un vistazo a otro ejemplo donde se invoca nuestro argumento posicional add
     

  • Una característica especial más que vale la pena mencionar es cómo argparse emite errores cuando los usuarios dan al programa argumentos inválidos. 
     

Entonces, este fue un ejemplo básico para que pueda sentirse cómodo con argparse y el concepto CLI. Ahora, pasemos a nuestro programa «Administrador de archivos de texto» .
 

Python

# importing the required modules
import os
import argparse
 
# error messages
INVALID_FILETYPE_MSG = "Error: Invalid file format. %s must be a .txt file."
INVALID_PATH_MSG = "Error: Invalid file path/name. Path %s does not exist."
 
 
def validate_file(file_name):
    '''
    validate file name and path.
    '''
    if not valid_path(file_name):
        print(INVALID_PATH_MSG%(file_name))
        quit()
    else if not valid_filetype(file_name):
        print(INVALID_FILETYPE_MSG%(file_name))
        quit()
    return
     
def valid_filetype(file_name):
    # validate file type
    return file_name.endswith('.txt')
 
def valid_path(path):
    # validate file path
    return os.path.exists(path)
         
     
 
def read(args):
    # get the file name/path
    file_name = args.read[0]
 
    # validate the file name/path
    validate_file(file_name)
 
    # read and print the file content
    with open(file_name, 'r') as f:
        print(f.read())
 
 
def show(args):
    # get path to directory
    dir_path = args.show[0]
     
    # validate path
    if not valid_path(dir_path):
        print("Error: No such directory found.")
        exit()
 
    # get text files in directory
    files = [f for f in os.listdir(dir_path) if valid_filetype(f)]
    print("{} text files found.".format(len(files)))
    print('\n'.join(f for f in files))
     
 
def delete(args):
    # get the file name/path
    file_name = args.delete[0]
 
    # validate the file name/path
    validate_file(file_name)
     
    # delete the file
    os.remove(file_name)
    print("Successfully deleted {}.".format(file_name))
     
 
def copy(args):
    # file to be copied
    file1 = args.copy[0]
    # file to copy upon
    file2 = args.copy[1]
 
    # validate the file to be copied
    validate_file(file1)
 
    # validate the type of file 2
    if not valid_filetype(file2):
        print(INVALID_FILETYPE_MSG%(file2))
        exit()
 
    # copy file1 to file2
    with open(file1, 'r') as f1:
        with open(file2, 'w') as f2:
            f2.write(f1.read())
    print("Successfully copied {} to {}.".format(file1, file2))
 
 
def rename(args):
    # old file name
    old_filename = args.rename[0]
    # new file name
    new_filename = args.rename[1]
 
    # validate the file to be renamed
    validate_file(old_filename)
 
    # validate the type of new file name
    if not valid_filetype(new_filename):
        print(INVALID_FILETYPE_MSG%(new_filename))
        exit()
 
    # renaming
    os.rename(old_filename, new_filename)
    print("Successfully renamed {} to {}.".format(old_filename, new_filename))
def main():
    # create parser object
    parser = argparse.ArgumentParser(description = "A text file manager!")
 
    # defining arguments for parser object
    parser.add_argument("-r", "--read", type = str, nargs = 1,
                        metavar = "file_name", default = None,
                        help = "Opens and reads the specified text file.")
     
    parser.add_argument("-s", "--show", type = str, nargs = 1,
                        metavar = "path", default = None,
                        help = "Shows all the text files on specified directory path.\
                        Type '.' for current directory.")
     
    parser.add_argument("-d", "--delete", type = str, nargs = 1,
                        metavar = "file_name", default = None,
                        help = "Deletes the specified text file.")
     
    parser.add_argument("-c", "--copy", type = str, nargs = 2,
                        metavar = ('file1','file2'), help = "Copy file1 contents to \
                        file2 Warning: file2 will get overwritten.")
     
    parser.add_argument("--rename", type = str, nargs = 2,
                        metavar = ('old_name','new_name'),
                        help = "Renames the specified file to a new name.")
 
    # parse the arguments from standard input
    args = parser.parse_args()
     
    # calling functions depending on type of argument
    if args.read != None:
        read(args)
    elif args.show != None:
        show(args)
    elif args.delete !=None:
        delete(args)
    elif args.copy != None:
        copy(args)
    elif args.rename != None:
        rename(args)
 
 
if __name__ == "__main__":
    # calling the main function
    main()

Después del ejemplo anterior, el código anterior parece autoexplicativo. 
Todo lo que hicimos fue agregar un conjunto de argumentos para nuestro programa administrador de archivos. Tenga en cuenta que todos estos argumentos son argumentos opcionales. Por lo tanto, usamos algunas declaraciones if-elif para hacer coincidir la entrada de la línea de comando con la función de tipo de argumento correcto para que se pueda procesar la consulta. 
Aquí hay algunas capturas de pantalla que describen el uso del programa anterior: 
 

  • Mensaje de ayuda (el script de python se ha guardado como tfmanager.py): 
     

  • Aquí hay ejemplos de operaciones usando el administrador de archivos de texto: 
     

Entonces, este fue un ejemplo de un programa Python CLI simple que creamos. El módulo Argparse podría crear fácilmente muchas CLI complejas. Espero que estos ejemplos le den una ventaja en esta área.
Este artículo es una contribución de Nikhil Kumar . Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando write.geeksforgeeks.org o enviar tu artículo por correo a review-team@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.
Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.
 

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *