- Gooey transforma aplicações de console em Python 3 em aplicações GUI fáceis de usar para o usuário final, funcionando com a adição de uma única linha de decorador a uma função com declaração
argparse
- A instalação básica pode ser feita com
pip install Gooey, e ao usar o decorador @Gooey junto com ArgumentParser, o Gooey lê os argumentos e monta uma UI baseada em componentes WX
- Quando a seleção de widgets padrão não é suficiente, é possível usar
GooeyParser como substituto do ArgumentParser e definir o argumento widget para escolher widgets personalizados como FileChooser, DateChooser, PasswordField e Slider
- O público-alvo não são ferramentas para desenvolvedores que usam CLI diretamente, mas sim scripts de escritório do tipo “executar e pronto” ou ferramentas voltadas a não programadores; ele oferece modos de execução avançado/básico/sem configuração, além de menus, barra de progresso, internacionalização, troca de ícones e empacotamento
- A validação dinâmica e os eventos de ciclo de vida são marcados como recursos experimentais,
optparse não é compatível no momento, e o funcionamento parte de código baseado em ArgumentParser com assinatura opcional de eventos
Como transformar programas de console em GUI
- Gooey converte aplicações de console em aplicações GUI fáceis de usar para o usuário final
- O uso principal consiste em aplicar o decorador
@Gooey a uma função que contém a declaração argparse
from gooey import Gooey
@Gooey
def main():
parser = ArgumentParser(...)
# rest of code
- O estilo e o comportamento podem ser ajustados com argumentos do decorador
advanced: exibir ou não a tela de configurações avançadas
language: selecionar tradução baseada em JSON
auto_start: pular a tela de configuração e executar imediatamente
target: definir o comando a ser executado como subprocesso
program_name, program_description: nome e descrição exibidos na GUI
default_size: tamanho inicial da GUI
dump_build_config, load_build_config: salvar/carregar JSON de configuração de build do Gooey
monospace_display: usar fonte monoespaçada na tela de saída
Instalação e exemplos
- A forma mais fácil de instalar é com pip
pip install Gooey
- Também é possível instalar clonando o repositório e executando
setup.py
git clone https://github.com/chriskiehl/Gooey.git
python setup.py install
- Scripts de exemplo prontos podem ser obtidos no repositório Gooey Examples
- O repositório de exemplos serve para explorar vários layouts, widgets e recursos do Gooey
Por que isso é necessário
- O Gooey foi criado para reduzir o problema de expor o prompt de comando a usuários que não estão familiarizados com ele
- Se um programa precisa realizar uma ou mais tarefas, ele precisa receber opções, e antes era necessário criar uma GUI manualmente ou explicar como passar argumentos para uma aplicação de console
- O Gooey permite que desenvolvedores criem programas configuráveis da forma com que já estão acostumados, enquanto oferecem uma GUI para exibição e interação
Usuários adequados e casos inadequados
- Gooey pode não ser adequado para utilitários feitos para você mesmo ou para outros programadores, nem para ferramentas que geram resultados para serem canalizados para outras aplicações de console
- É adequado para scripts de escritório para executar, ferramentas que movem dados do ponto A ao B e programas voltados a não programadores
- O objetivo é criar aplicações complexas e obter a parte de GUI sem custo adicional
Funcionamento interno e mapeamento do argparse
- O Gooey analisa em tempo de execução as referências a
ArgumentParser em scripts Python
optparse não é compatível no momento
- Os argumentos extraídos recebem um tipo de componente de acordo com a
action fornecida e são usados na composição da GUI
ArgumentParser._actions é mapeado por padrão para os seguintes componentes WX
store: TextCtrl
store_const, store_true, store_False, version: CheckBox
append: TextCtrl
count: DropDown
Mutually Exclusive Group: RadioGroup
choice: DropDown
GooeyParser e widgets personalizados
- Se a seleção de widgets padrão não for suficiente, você pode usar GooeyParser, um substituto compatível com
ArgumentParser
GooeyParser oferece o argumento adicional widget para definir o nome do componente a ser exibido
from gooey import Gooey, GooeyParser
@Gooey
def main():
parser = GooeyParser(description="My Cool GUI Program!")
parser.add_argument('Filename', widget="FileChooser")
parser.add_argument('Date', widget="DateChooser")
- Os widgets personalizados compatíveis incluem
DirChooser, FileChooser, MultiFileChooser
FileSaver, MultiFileSaver
DateChooser, TimeChooser
PasswordField
Listbox
BlockCheckbox
ColourChooser
FilterableDropdown
IntegerField, DecimalField
Slider
- Os valores que
DateChooser e TimeChooser passam para a aplicação estão sempre em formato ISO, embora partes da GUI possam mostrar valores localizados conforme a configuração do usuário final
BlockCheckbox move o bloco de texto para a posição normal e exibe um block_label curto ao lado do controle, para ficar visualmente melhor do que um checkbox inline padrão quando há textos de ajuda longos
Internacionalização
- O Gooey seleciona o idioma de exibição com o argumento
language do decorador
@Gooey(language='russian')
def main():
...
- Todo o texto do programa é armazenado em arquivos JSON externos
- O suporte a novos idiomas é feito adicionando pares chave/valor no diretório
gooey/languages/
- Atualmente, mais de 18 traduções são fornecidas por padrão
Configurações globais e composição da UI
- A aparência e o comportamento gerais do Gooey são ajustados com argumentos do decorador
- As principais configurações incluem
encoding: codificação de caracteres exibidos, padrão utf-8
advanced: escolher entre tela completa de configurações ou tela simplificada
auto_start: executar imediatamente sem configuração
target: definir como o Gooey deve executar a si mesmo novamente
suppress_gooey_flag: impedir a injeção de parâmetros CLI adicionais ao usar target personalizado
fullscreen: iniciar em tela cheia
image_dir: diretório de imagens/ícones personalizados
language_dir: diretório de arquivos de idioma personalizados
disable_stop_button, show_stop_warning: controlar o botão de parar e o aviso durante a execução
show_success_modal, show_failure_modal: exibir ou não modais de resumo de sucesso/falha
run_validators: executar validação antes de chamar o programa
progress_regex, progress_expr: análise e conversão de texto de progresso
navigation: TABBED ou SIDEBAR
body_bg_color, header_bg_color, footer_bg_color, sidebar_bg_color: configurações de cor
terminal_font_family, terminal_font_size, terminal_font_color: configurações de fonte da área de terminal
menus: grupos e itens de menu personalizados
clear_before_run: apagar a saída anterior ao executar novamente
Layouts e modos de execução
- O Gooey divide as entradas por padrão em dois grupos:
positional e optional
- Ao usar
add_argument_group() do argparse, é possível agrupar entradas logicamente e ajustar o layout de cada grupo
parser = ArgumentParser()
search_group = parser.add_argument_group(
"Search Options",
"Customize the search options"
)
search_group.add_argument(
'--query',
help='Base search string'
)
Recurso de menu
- Desde o Gooey 1.0.2, é possível adicionar uma Menu Bar no topo
- Os menus são definidos como uma lista de mapas no formato
@Gooey(menu=[{}, {}, ...])
- Cada grupo de menu possui
name e items
- Cada item de menu sempre inclui
type e menuTitle
- Os tipos de item de menu compatíveis são
AboutDialog: exibe informações do programa, como nome, versão e licença
MessageDialog: mostra uma mensagem informativa ao usuário
Link: abre a URL especificada no navegador padrão
HtmlDialog: exibe um diálogo usando um subconjunto limitado de HTML
Validação dinâmica
- Dynamic Validation é um recurso experimental e sua API pode mudar ou ser removida
- O Gooey pode opcionalmente fazer validação prévia antes de enviar a entrada do usuário ao programa
- Esse recurso aproveita o parâmetro
type, disponível na maioria dos tipos de argumento do Argparse
def must_be_exactly_ten(value):
number = int(value)
if number == 10:
return number
else:
raise TypeError("Hey! you need to provide exactly the number 10!")
- A validação não é executada por padrão
- Para ativá-la, é preciso assinar o evento
VALIDATE_FORM
from gooey import Gooey, Events
@Gooey(use_events=[Events.VALIDATE_FORM])
def main():
...
- Atualmente, esse recurso é opt-in porque usa Monkey Patching pesado internamente
Eventos de ciclo de vida e controle da UI
- Desde o Gooey 1.2.0, o programa expõe hooks de ciclo de vida
- Esse recurso também é experimental e sua API pode mudar ou ser removida
- No momento, existem dois hooks principais
- Ambos são executados após a conclusão do processo
- Os handlers recebem o objeto Argparse já analisado e o estado atual da UI do Gooey; se retornarem um estado atualizado, ele poderá ser refletido na interface
- Os handlers são conectados ao criar o
GooeyParser
parser = GooeyParser(
on_success=my_success_handler,
on_failure=my_failure_handler)
- Para usar, é necessário assinar explicitamente os eventos
from gooey import Gooey, Events
@Gooey(use_events=[Events.ON_SUCCESS, Events.ON_ERROR])
def main():
...
Progresso e exibição de tempo
- O Gooey pode ler saídas de progresso em texto já existentes para alimentar uma Progress Bar
- Em casos simples, ele converte o progresso correspondendo a strings como
Progress 83% via expressão regular
@Gooey(progress_regex=r"^progress: (\d+)%$")
- Saídas mais complexas podem ser convertidas com
progress_expr, usando os resultados capturados pela regex
@Gooey(progress_regex=r"^progress: (?P<current>\d+)/(?P<total>\d+)$",
progress_expr="current / total * 100")
- Se
hide_progress_msg=True for definido, o texto de saída que corresponder ao progresso pode ser ocultado no console
- Com
timing_options, é possível exibir tempo decorrido e tempo restante
- A exibição de tempo só funciona ao usar
progress_regex e progress_expr
Ícones e empacotamento
- O Gooey fornece 6 ícones padrão, e eles podem ser substituídos definindo um diretório de imagens personalizado com o argumento
image_dir
- As imagens são buscadas pelo nome do arquivo, e os nomes que podem ser sobrescritos são
program_icon.png
success_icon.png
running_icon.png
loading_icon.gif
config_icon.png
error_icon.png
- O empacotamento em executável inclui um exemplo com PyInstaller
- O procedimento resumido é colocar
build.spec na raiz da aplicação, ajustar os valores de APPPNAME, name e pathex de acordo com o projeto e então executar
pyinstaller -F --windowed build.spec
1 comentários
Comentários no Hacker News
Ei, esse é o meu projeto ^_^ Por que ele está no topo do HN?
Respondendo rapidamente aos comentários sobre
argparse: o Gooey já é um projeto bem antigo, e na época em que começouargparseera uma escolha sólidaHoje em dia, o Gooey em si funciona com JSON e é desacoplado do
argparse, mas quase ninguém criou outras interfaces, então oargparseainda continua sendo a principal interface “oficial”Um ponto interessante é que ele pode chamar não só Python, mas também executáveis arbitrários, então é bem útil: https://chriskiehl.com/article/gooey-as-a-universal-frontend
Sobre dizerem que o último commit foi há 2 anos: quando a gente envelhece e as prioridades mudam, fica difícil encontrar motivo para continuar mantendo de graça um software de nicho :( Não sei se serve de consolo, mas sempre sinto culpa
Estranhamente, há grafites “GOOEY” por todos os lados no bairro onde moro, então parecem lembretes permanentes que me fazem lembrar do issue tracker abandonado haha
argparseainda é uma escolha bem boa. É extremamente usado, tem boa documentação e é relativamente simplesTyper e Click também têm boa usabilidade, mas sinto que a documentação em formato de “tutorial” do Typer é bem difícil de pesquisar quando se quer encontrar respostas como quais argumentos
Typer.App()recebeO programa em que estou trabalhando agora tem uma estrutura em que o próprio usuário inicia o parsing de argumentos, então
argparsese encaixa bem. Quero oferecer ao usuário uma UI baseada em texto como opção, mas acho que o Textualize exigia Click, e mesmo tentando criar uma UI acoplando o Textual diretamente ao código, gastei algumas horas e nem consegui começarHoje há frustrações demais causadas pelo fato de não ser possível controlar aplicações programaticamente. Sinceramente, eu gostaria que existisse uma lei dizendo que toda funcionalidade de aplicação deve ter uma API
sys.argvem um arquivo local no diretório de trabalho atual? https://github.com/chriskiehl/Gooey/blob/be4b11b8f27f500e732...tmp.txtestá longe de ser um nome único; fico me perguntando se estou deixando passar alguma coisaargparse” é bacanaAntes de clicar, só pelo título, pensei: “com certeza ele depende fortemente de
argparse”, então fui surpreendido positivamenteSou um fã fervoroso de
getopt, porque considero a conveniência do usuário muito mais importante do que a conveniência do desenvolvedor. O usuário não deveria precisar se importar com a linguagem de programação ou a biblioteca de parsing de opções que o desenvolvedor escolheuMuitas bibliotecas, como
argparse, Click e oflagdo Go/estilo X11, quebram convenções gravadas na memória muscular coletiva acumulada ao longo de meio século. Mas, com uma camada intermediária, parece possível ter o melhor dos dois mundosO pior é que também não surgiu nenhuma alternativa viável para substituí-lo, e nenhum dos dois forks ganhou traction
Isto não deveria ser qualificado como “baseado em
argparse”?argparseé bom para usos simples, mas também há muitas CLIs baseadas em Click, e boa parte das bibliotecas populares de CLI é construída sobre Click. Também existem ferramentas de CLI em Python que não usam nemargparsenem Click, mas essas duas provavelmente estão entre as mais popularesFoi confirmado que funciona com Click também? Por enquanto só vejo conteúdo relacionado a
argparse. Se a resposta for não, a expressão “quase todos” é claramente falsa, e um título mais preciso seria “Transformar quase todo programa de linha de comando Python baseado emargparseem uma aplicação GUI completa”Há também o fato de que o último commit significativo foi há mais de 2 anos. Isso por si só não é ruim, mas o número de issues abertas não inspira muita confiança no projeto
Ainda assim, é um projeto bacana. Gostaria de ver mais coisas assim. Como o README diz, é uma ferramenta multiplicadora de força, permitindo que alguém crie automação via CLI e a compartilhe facilmente com pessoas de escritório sem perfil técnico. É parecido com o papel que o Access teve para bancos de dados
Assim como o Access, vai bater em limites quando houver escala ou complexidade, mas para usos em pequenos escritórios pode ser “bom o bastante”
argparse. Minha tendência é de minimizar dependências externasargparse?Posts relacionados:
Gooey: Turn almost any Python command line program into a GUI application - https://news.ycombinator.com/item?id=27490291 - junho de 2021, 115 comentários
Gooey: Turn command line programs into GUI applications - https://news.ycombinator.com/item?id=8218785 - agosto de 2014, 74 comentários
Seria bom se o sistema operacional e o shell conseguissem entender melhor como executar programas sem depender de uma biblioteca de parsing específica.
Seria bom se os programas se comunicassem em um formato JSON/proto tipado, e se apenas inspecionando os tipos esperados de entrada e saída fosse possível obter estruturação e autocompletar de comandos no shell, ou até uma GUI completa.
Hoje, o melhor que parece existir é algo feito com cuidado, meio que enfiando um canudinho. Cada programa precisa exportar arquivos de autocompletar para vários shells, os estilos de flags variam bastante entre programas e bibliotecas de parsing, e, claro, não há GUI.
O principal problema do gRPC, porém, parece ser que muitos desenvolvedores, inclusive eu, o acham um pouco mais incômodo de lidar do que soluções que parecem naturais dentro da linguagem.
Não tenho certeza se o PowerShell consegue aproveitar plenamente a tipagem estática que está em seu núcleo, mas sua capacidade de passar objetos pela linha de comando é quase única.
No Linux, dá para encadear comandos combinando
jc(https://github.com/kellyjonbrazil/jc) ejq(https://jqlang.github.io/jq/), mas isso ainda exige duas etapas a mais em comparação com os recursos embutidos do PowerShell.Às vezes, uma GUI parece comida de conforto. Porque dá para simplesmente explorar uma interface GUI, sem a carga cognitiva que pode surgir em uma CLI usada raramente.
Meio mudando de assunto, há alguns meses descobri por aqui o editor CUDATEXT, que permite usar elementos de GUI arbitrários, como MENU e INPUTS, por meio de uma API Python em um único arquivo. Esses elementos também são usados pelo próprio editor.
Agora estou usando esses elementos simples de GUI para configuração e gerando um blog diretamente dentro do editor.
Algo relacionado para ver também:
“Textual: um framework leve de aplicações para Python. Crie interfaces de usuário sofisticadas com uma API Python simples e execute apps no terminal e no navegador web” https://github.com/textualize/textual/
camply: https://juftin.com/camply/
Quero agradecer por terem criado este excelente software. Gosto do Gooey e já o usei bastante em vários programas.
Para mim, ele se encaixa perfeitamente naquele ponto em que um script Python faz algo importante, e agora preciso torná-lo utilizável por não programadores.
Isso me lembra naked objects. A ideia era que, definindo algumas anotações e um tema em classes Java, uma GUI inteira, ou uma aplicação web de frontend, seria gerada.
Era uma ideia muito legal, mas, até onde sei, no fim não deu muito certo.
Na minha opinião, o problema é que preocupações verticais como apresentação, domínio e infraestrutura acabam acopladas entre si. Quando a representação em tela e a representação no banco de dados do modelo de domínio são simples, tudo bem.
Mas, se você quer criar uma interface complexa e cheia de recursos de conveniência, esses requisitos precisam vazar para a camada de domínio. Por outro lado, se você quer criar um modelo de domínio complexo, fica impraticável impor invariantes no nível da linguagem, porque qualquer código que tenha uma referência a
Modelpode mexer nele arbitrariamente.Seria bom se também existisse algo que fizesse o inverso.
argparsee depois convertê-la de volta em um script de shell que execute e salve os resultados adequadamente.O antigo Macintosh Programmer's Workshop, ou MPW, um shell baseado em texto para o Mac OS dos anos 80 e 90, tinha um recurso parecido chamado Commando para quase todos os comandos.
As informações do Commando ficavam armazenadas em recursos
cmdo. Se o suporte a atributos estendidos não fosse tão irregular, poderíamos fazer algo parecido hoje.Pesquisando, vi que o A/UX também tinha Commando. Ao dar dois cliques em um comando de terminal no Finder, aparecia uma caixa do Commando para escolher as opções da CLI, e depois ele era executado em uma janela do shell. Hoje, quando se executa um comando de terminal no Finder, ele simplesmente roda em uma janela do shell sem argumentos.
https://cohost.org/boredzo/post/804893-i-still-want-a-moder
http://toastytech.com/guis/aux3.html