Criando uma command-line interface(CLI) com Click

@allythy

o que é command-line interface?

Uma interface de linha de comandos (ILC), em inglês comand-line interface (CLI), é um meio de interagir com um programa de computador, onde o utilizador (ou cliente) emite comandos para o programa sob a forma de sucessivas linhas de texto (linhas de comando).

Exemplo

Command Line Interface Creation Kit (CLICK)

Click é um pacote Python para criar lindas interfaces de linha de comando de uma maneira simples com o mínimo de código necessário. É altamente configurável, mas vem com padrões sentados pronto para uso.

  • Cria páginas de ajuda(--help) automaticamente
  • Usa Decorators
  • Suporta manipulação de arquivos
  • Carregamento de variáveis de ambiente
  • ANSI colors
  • Prompt interativo

InstalaçÃO

pip install click

cONCEITOS

O Click é baseado na declaração de comandos por meio de decoradores(...)

import click


@click.command()
@click.option('-n', '--nome')
def boas_vindas(nome):
    click.echo(f'Oi, {nome} seja bem-vindo.')


if __name__ == '__main__':
    boas_vindas()
python hello.py -n Allythy
Oi, Allythy seja bem-vindo.

parâmetros

argumentos(@click.argument)

São posições fixas e obrigatórios para execucão da CLI

@click.command()
@click.argument('filename')
def touch(filename):
    click.echo(filename)

Opções (@click.option)

O  parâmetro option tem mais recursos que o arguments. E como o próprio nome diz, ele não é obrigatório.

tipos

argumentos(@click.argument)

  • Valor padrão STRING.
  • Aceita múltiplos argumentos: nargs=-1, nargs=1
@click.command()
@click.argument('src', nargs=-1)
@click.argument('dist', nargs=1)
def mv(src, dist):
    for file in src:
        click.echo(f'Movendo {file} para {dist}')
python  mv-file.py  Pipfile Pipfile.lock pasta
Movendo Pipfile para pasta
Movendo Pipfile.lock para pasta

Um ou vários argumentos

@click.command()
@click.argument('input', type=click.File('rb'))
@click.argument('output', type=click.File('wb'))
def inout(input, output):
    while True:
        chunk = input.read(1024)
        if not chunk:
            break
        output.write(chunk)
inout - hello.txt
hello
^D

Definindo o tipo

import click


@click.command()
@click.argument('file', type=click.Path(exists=True))
def touch(f):
    click.echo(file)
python path.py vida.txt 
vida.txt
python path.py nada.txt
Usage: path.py [OPTIONS] F
Try "path.py --help" for help.

Error: Invalid value for "F": Path "nada.txt" does not exist.
@click.command()
@click.argument('src', envvar='SRC', type=click.File('r'))
def echo(src):
    click.echo(src.read())
export src=hello.txt
$ echo
Hello World!

Lendo da variável de ambiente

Opções(@click.option)

  • Valor padrão STRING.
  • Aceita múltiplos argumentos: nargs=-1, nargs=1
  • Tem um valor padrão(default)
  • Aceita entrada do usuário(prompt)
  • Entre outras coisas
@click.command()
@click.option('--n', default=1)
def dots(n):
    click.echo('.' * n)
$ python test.py
.
$ python test.py --n 30
..............................

Definindo um valor padrão

@click.command()
@click.option('--name', prompt=True)
def hello(name):
    click.echo('Hello %s!' % name)
python test.py
Name: Allythy
Hello Allythy

Interagindo com o usuário

@click.command()
@click.password_option()
def encrypt(password):
    click.echo(f'Encrypting password to {password}')
$ python test.py
Password: 
Repeat for confirmation: 
Encrypting password to 12

Interagindo com o usuário

@click.command()
@click.option('--name', prompt=True)
def hello(name):
    click.secho(f'Hello {name}', fg='bright_yellow', bg='black')
python test.py
Name: Allythy
Hello Allythy

Colando cores

@groups

Os comandos podem ser unidos outros comandos por meio de um grupo.

@click.group()
def cli():
    pass

@click.command()
def initdb():
    click.echo('Initialized the database')

@click.command()
def dropdb():
    click.echo('Dropped the database')

criando setup.py

from setuptools import setup

setup(
    name='yourscript',
    version='0.1',
    py_modules=['yourscript'],
    install_requires=[
        'Click',
    ],
    entry_points='''
        [console_scripts]
        yourscript=yourscript:cli
    ''',
)

Exemplos

 

from random import sample
from csv import DictReader
import click


@click.command()
@click.option('-f', '--file', type=click.File('r'), help='Filename of the participants')
@click.option('-c', '--column', help='Column name')
@click.option('-w', '--winners', default=1, type=click.INT, help='Numbers winners')
def raffle(file, column, winners):
    """Raffle participants from a CSV file """
    reader = DictReader(file)
    participants = [row[column] for row in reader]
    click.echo(sample(participants, winners))


if __name__ == '__main__':
    raffle()

Sorteio

python raffle.py -f participantes.csv -c Nome -w2
['Ramon de Oliveira Araújo Mateus', 'Pedro Osvaldo Alencar Regis']
python raffle.py --help
Usage: raffle.py [OPTIONS]

  Raffle participants from a CSV file

Options:
  -f, --file FILENAME    Filename of the participants
  -c, --column TEXT      Column name
  -w, --winners INTEGER  Numbers winners
  --help                 Show this message and exit.

Click + Telethon

steve-cli --help
Usage: steve-cli [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  get-engagement  Traz a lista de pessoas mais engajadas em grupos.
  send-image      Envia imagem para grupos e usuarios.
  send-message    Envia mensagem para grupos e usuarios.
Usage: steve-cli send-message [OPTIONS] TEXT

  Envia mensagem para grupos e usuarios.

Options:
  -F, --force       Força o envio de mensagem para todos os seus dialogos e
                    membro de grupos
  -G, --all-groups  Envia para todos os grupos que você participa
  -U, --all-users   Envia para todos os seus dialogos
  --help            Show this message and exit.
steve-cli get-engagement --group grupyrn --total 200

1 - Pedro Arthur (@PEdrArthur) 51/200
2 - João Marcos (@marcospb19) 35/200
3 - Genilson Cacha (@jgdsfilho) 15/200
4 - Felipe (@fecaridade) 13/200
5 - Vinicius (@vinicius_melo) 10/200
6 - Allan (@Allanvgoncalves) 7/200
7 - Alex (@Alexxdantass) 5/200
8 - Helio (@heliomeiralins) 4/200
9 - Eduardo (@dunossauro) 4/200
10 - Joab (@joabdaluz) 3/200

Obrigado

Criando uma command-line interface(CLI) com Click

By allythy

Criando uma command-line interface(CLI) com Click

  • 284