Guia para Criação de Scripts de Linha de Comando Python Profissionais

Introdução

Como desenvolvedores Python, frequentemente precisamos criar scripts de linha de comando (CLI). Em projetos de ciência de dados, por exemplo, pode ser necessário executar scripts para treinar modelos ou calcular métricas de desempenho. Scripts de CLI bem projetados aumentam a produtividade, especialmente em ambientes com múltiplos desenvolvedores.

Para alcançar isso, recomenda-se seguir estas quatro diretrizes:

  • Forneça valores padrão para parâmetros sempre que possível.
  • Trate todos os casos de erro, como argumentos faltantes ou tipos incorretos.
  • Documente todos os parâmetros e opções claramente.
  • Exiba barras de progresso para tarefas demoradas.

Exemplo Prático: Cifra de César

Vamos aplicar essas regras em um script que usa a cifra de César para criptografar e descriptografar mensagens. O objetivo é permitir que o usuário selecione o modo (criptografar ou descriptografar) e uma chave via argumentos de linha de comando.

Primeiro, defina a função de criptografia:

def aplicar_cifra(texto, chave):
    saida = ''
    for caractere in texto:
        if caractere.isalpha():
            valor_ascii = ord(caractere)
            valor_ascii += chave
            if caractere.isupper():
                if valor_ascii > ord('Z'):
                    valor_ascii -= 26
                elif valor_ascii < ord('A'):
                    valor_ascii += 26
            else:
                if valor_ascii > ord('z'):
                    valor_ascii -= 26
                elif valor_ascii < ord('a'):
                    valor_ascii += 26
            caractere = chr(valor_ascii)
        saida += caractere
    return saida

Abordagem com sys.argv

Uma maneira inicial de obter argumentos é usando sys.argv, que retorna uma lista de argumentos da linha de comando. No entanto, isso requer análise manual, tornando o código extenso e propenso a erros.

Exemplo de script usando sys.argv:

import sys
from cifra_cesar import aplicar_cifra

def executar():
    chave = 1
    erro = False
    args = sys.argv[1:]

    for i, arg in enumerate(args):
        if arg in ['--chave', '-c'] and i + 1 < len(args):
            chave = int(args[i + 1])
            del args[i:i+2]
            break

    modo_descriptografar = False
    for i, arg in enumerate(args):
        if arg in ['--descriptografar', '-d']:
            modo_descriptografar = True
            del args[i]
            break

    if not args or any(a.startswith('-') for a in args):
        erro = True
    if erro:
        print(f'Uso: python {sys.argv[0]} [--chave <chave>] [--descriptografar] <texto>')
    else:
        texto = ' '.join(args)
        if modo_descriptografar:
            chave = -chave
        print(aplicar_cifra(texto, chave))

if __name__ == '__main__':
    executar()</texto></chave>

Esta abordagem atende parcialmente às diretrizes, mas o código é complexo e difícil de manter.

Utilizando argparse

A biblioteca padrão argparse simplifica a análise de argumentos, oferecendo melhor documentação e tratamento de erros.

Exemplo com argparse:

import argparse
from cifra_cesar import aplicar_cifra

def executar():
    parser = argparse.ArgumentParser(description='Cifra de César via CLI.')
    grupo = parser.add_mutually_exclusive_group()
    grupo.add_argument('-e', '--criptografar', action='store_true', help='Modo criptografia')
    grupo.add_argument('-d', '--descriptografar', action='store_true', help='Modo descriptografia')
    parser.add_argument('texto', nargs='*', help='Texto a processar')
    parser.add_argument('-c', '--chave', type=int, default=1, help='Chave numérica')
    args = parser.parse_args()

    texto_str = ' '.join(args.texto)
    chave = args.chave
    if args.descriptografar:
        chave = -chave
    resultado = aplicar_cifra(texto_str, chave)
    print(resultado)

if __name__ == '__main__':
    executar()

Este código é mais limpo, mas a definição de argumentos ainda pode ser verbosa.

Adotando a Biblioteca click

A biblioteca click oferece uma API mais declarativa e elegante para CLI. Ela usa decoradores para definir argumentos e opções diretamente na função.

Exemplo com click:

import click
from cifra_cesar import aplicar_cifra

@click.command()
@click.argument('texto', nargs=-1)
@click.option('--descriptografar/--criptografar', '-d/-e', default=False, help='Seleciona modo')
@click.option('--chave', '-c', default=1, help='Chave para cifra')
def executar(texto, descriptografar, chave):
    texto_completo = ' '.join(texto)
    if descriptografar:
        chave = -chave
    click.echo(aplicar_cifra(texto_completo, chave))

if __name__ == '__main__':
    executar()

Aqui, os argumentos são definidos como decoradores, tornando o código mais conciso. O nargs=-1 permite múltiplos argumentos posicionais.

Recursos Avançados com click

Para aprimorar a segurança e usabilidade, podemos adicionar suporte a arquivos e entradas ocultas.

import click
from cifra_cesar import aplicar_cifra

@click.command()
@click.option('--arquivo-entrada', type=click.File('r'), help='Arquivo com texto de entrada')
@click.option('--arquivo-saida', type=click.File('w'), help='Arquivo para salvar resultado')
@click.option('--descriptografar/--criptografar', '-d/-e', default=False, help='Modo de operação')
@click.option('--chave', '-c', default=1, help='Chave numérica')
def executar(arquivo_entrada, arquivo_saida, descriptografar, chave):
    if arquivo_entrada:
        texto = arquivo_entrada.read()
    else:
        texto = click.prompt('Digite o texto', hide_input=not descriptografar)
    if descriptografar:
        chave = -chave
    resultado = aplicar_cifra(texto, chave)
    if arquivo_saida:
        arquivo_saida.write(resultado)
    else:
        click.echo(resultado)

if __name__ == '__main__':
    executar()

Este script inclui opções para ler de arquivos, escrever para arquiovs e entrada oculta em modo de criptografia. A biblioteca click lida automaticamente com erros de arquivo, como arquivos inexistentes.

Tags: Python CLI argparse click linha de comando

Publicado em 7-21 07:57