- Gooey convierte aplicaciones de consola en Python 3 en aplicaciones GUI fáciles de usar para usuarios finales, y funciona agregando una sola línea de decorador a una función que contiene declaraciones de
argparse
- La instalación básica se puede hacer con
pip install Gooey; al usar el decorador @Gooey junto con ArgumentParser, Gooey lee los argumentos y construye una UI basada en componentes WX
- Cuando la selección predeterminada de widgets no alcanza, se puede usar
GooeyParser como reemplazo de ArgumentParser y especificar el argumento widget para elegir widgets personalizados como FileChooser, DateChooser, PasswordField o Slider
- El público objetivo no son tanto las herramientas para desarrolladores que manejan directamente la CLI, sino scripts de oficina de tipo “ejecutar y listo” o herramientas para no programadores; admite modos de ejecución avanzado/básico/sin configuración, menús, visualización de progreso, internacionalización, cambio de íconos y empaquetado
- La validación dinámica y los eventos de ciclo de vida están marcados como funciones experimentales; actualmente no admite
optparse y asume código basado en ArgumentParser con suscripción opcional a eventos
Cómo convertir un programa de consola en GUI
- Gooey convierte aplicaciones de consola en aplicaciones GUI fáciles de manejar para usuarios finales
- El uso principal consiste en agregar el decorador
@Gooey a una función que contiene declaraciones de argparse
from gooey import Gooey
@Gooey
def main():
parser = ArgumentParser(...)
# rest of code
- El estilo y el comportamiento se pueden ajustar mediante argumentos del decorador
advanced: si se muestra la pantalla de configuración avanzada
language: selección de traducción basada en JSON
auto_start: omite la pantalla de configuración y ejecuta de inmediato
target: especifica el comando que se ejecutará como subproceso
program_name, program_description: nombre y descripción que se muestran en la GUI
default_size: tamaño inicial de la GUI
dump_build_config, load_build_config: guardar/cargar la configuración de build de Gooey en JSON
monospace_display: usar una fuente monoespaciada en la pantalla de salida
Instalación y ejemplos
- La forma más sencilla de instalarlo es con pip
pip install Gooey
- También se puede clonar el repositorio y ejecutar
setup.py para instalarlo
git clone https://github.com/chriskiehl/Gooey.git
python setup.py install
- Los scripts de ejemplo preparados se pueden obtener en el repositorio Gooey Examples
- El repositorio de ejemplos se ofrece para recorrer distintos layouts, widgets y funciones de Gooey
Por qué hace falta
- Gooey fue creado para reducir el problema de mostrar un prompt de comandos a usuarios que no están familiarizados con él
- Para que un programa haga una o más tareas, necesita recibir opciones; antes había que crear una GUI manualmente o explicar cómo pasar argumentos a una aplicación de consola
- Gooey permite crear programas configurables de una manera familiar para los desarrolladores, pero ofreciendo la visualización y la interacción mediante una GUI
Usuarios adecuados y casos no adecuados
- Gooey puede no ser adecuado para utilidades destinadas a uno mismo o a otros programadores, ni para herramientas que generan resultados para canalizarlos hacia otras aplicaciones de consola
- Es adecuado para scripts de ejecución de oficina, herramientas que mueven datos del punto A al B y programas dirigidos a no programadores
- El objetivo es crear aplicaciones complejas obteniendo la parte de GUI sin costo adicional
Funcionamiento interno y mapeo de argparse
- Gooey parsea en tiempo de ejecución la referencia a
ArgumentParser dentro del script de Python
- Actualmente no admite
optparse
- A los argumentos extraídos se les asigna un component type según la
action proporcionada, y se usan para construir la GUI
ArgumentParser._actions se mapea de forma predeterminada a los siguientes componentes WX
store: TextCtrl
store_const, store_true, store_False, version: CheckBox
append: TextCtrl
count: DropDown
Mutually Exclusive Group: RadioGroup
choice: DropDown
GooeyParser y widgets personalizados
- Si la selección predeterminada de widgets no es suficiente, se puede usar GooeyParser, un reemplazo directo de
ArgumentParser
GooeyParser ofrece el argumento de palabra clave adicional widget, con el que se puede especificar el nombre del componente que se mostrará
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")
- Entre los widgets personalizados admitidos se incluyen:
DirChooser, FileChooser, MultiFileChooser
FileSaver, MultiFileSaver
DateChooser, TimeChooser
PasswordField
Listbox
BlockCheckbox
ColourChooser
FilterableDropdown
IntegerField, DecimalField
Slider
- Los valores que
DateChooser y TimeChooser pasan a la aplicación siempre están en ISO format, aunque en partes de la GUI puedan verse valores localizados según la configuración del usuario final
BlockCheckbox mueve el bloque de texto a una posición normal cuando hay textos de ayuda largos, para que se vea mejor que un checkbox inline predeterminado, y muestra un block_label corto junto al control
Internacionalización
- Gooey selecciona el idioma de visualización mediante el argumento
language del decorador
@Gooey(language='russian')
def main():
...
- Todos los textos del programa se almacenan en archivos JSON externos
- Para agregar soporte para un idioma nuevo, se añaden pares clave/valor en el directorio
gooey/languages/
- Actualmente incluye más de 18 traducciones de forma predeterminada
Configuración global y construcción de la UI
- La apariencia y el comportamiento generales de Gooey se ajustan con argumentos del decorador
- Entre las principales opciones se incluyen:
encoding: codificación de caracteres para mostrar; el valor predeterminado es utf-8
advanced: elegir entre pantalla de configuración completa o simplificada
auto_start: ejecutar de inmediato sin configuración
target: especifica cómo Gooey debe volver a ejecutarse a sí mismo
suppress_gooey_flag: evita inyectar parámetros CLI adicionales al usar un target personalizado
fullscreen: iniciar en pantalla completa
image_dir: directorio de imágenes/íconos personalizados
language_dir: directorio de archivos de idioma personalizados
disable_stop_button, show_stop_warning: control del botón de detener y la advertencia durante la ejecución
show_success_modal, show_failure_modal: si se muestran modales de resumen de éxito/fallo
run_validators: si se ejecuta la validación antes de invocar el programa
progress_regex, progress_expr: parseo y transformación del texto de progreso
navigation: TABBED o SIDEBAR
body_bg_color, header_bg_color, footer_bg_color, sidebar_bg_color: configuración de colores
terminal_font_family, terminal_font_size, terminal_font_color: configuración de fuente para la visualización de terminal
menus: grupos y elementos de menú personalizados
clear_before_run: eliminar la salida anterior al volver a ejecutar
Layouts y modos de ejecución
- Gooey divide las entradas de forma predeterminada en dos grupos:
positional y optional
- Si se usa
add_argument_group() de argparse, se pueden agrupar las entradas de forma lógica y ajustar el 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'
)
Función de menú
- Desde Gooey 1.0.2 se puede agregar una Menu Bar en la parte superior
- Los menús se especifican como una lista de mapas con la forma
@Gooey(menu=[{}, {}, ...])
- Cada grupo de menú tiene
name e items
- Cada elemento de menú siempre incluye
type y menuTitle
- Los tipos de elementos de menú admitidos son:
AboutDialog: muestra información del programa, como nombre, versión y licencia
MessageDialog: muestra al usuario un mensaje informativo
Link: abre la URL indicada en el navegador predeterminado
HtmlDialog: muestra un diálogo usando un subconjunto limitado de HTML
Validación dinámica
- Dynamic Validation es una función experimental y su API puede cambiar o eliminarse
- Gooey puede realizar opcionalmente una validación previa antes de pasar la entrada del usuario al programa
- Esta función aprovecha el parámetro
type, disponible en la mayoría de los tipos de argumentos de 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!")
- La validación no se ejecuta de forma predeterminada
- Para activarla, hay que suscribirse al evento
VALIDATE_FORM
from gooey import Gooey, Events
@Gooey(use_events=[Events.VALIDATE_FORM])
def main():
...
- Actualmente esta función es opt-in porque internamente usa Monkey Patching intensivo
Eventos de ciclo de vida y control de UI
- Desde Gooey 1.2.0, se exponen hooks de ciclo de vida al programa
- Esta función también es experimental, y su API puede cambiar o eliminarse
- Actualmente hay dos hooks principales:
- Ambos hooks se ejecutan después de que el proceso finaliza
- El handler recibe el objeto Argparse parseado y el estado actual de la UI de Gooey; si devuelve un estado actualizado, este puede reflejarse en la UI
- Los handlers se conectan al crear
GooeyParser
parser = GooeyParser(
on_success=my_success_handler,
on_failure=my_failure_handler)
- Para usarlo, hay que suscribirse explícitamente a los eventos
from gooey import Gooey, Events
@Gooey(use_events=[Events.ON_SUCCESS, Events.ON_ERROR])
def main():
...
Progreso y visualización de tiempo
- Gooey puede leer salidas de texto de progreso existentes y con ellas controlar una Progress Bar
- En casos simples, convierte en progreso strings como
Progress 83% haciendo matching con una expresión regular
@Gooey(progress_regex=r"^progress: (\d+)%$")
- Para salidas más complejas, se puede transformar el resultado del matching de la expresión regular con
progress_expr
@Gooey(progress_regex=r"^progress: (?P<current>\d+)/(?P<total>\d+)$",
progress_expr="current / total * 100")
- Al especificar
hide_progress_msg=True, se puede ocultar en la consola el texto de salida que coincide con el progreso
- Con
timing_options, se pueden mostrar el tiempo transcurrido y el tiempo restante
- La visualización de tiempo solo funciona cuando se usan
progress_regex y progress_expr
Íconos y empaquetado
- Gooey ofrece 6 íconos predeterminados; se pueden sobrescribir indicando un directorio de imágenes personalizado con el argumento
image_dir
- Busca las imágenes por nombre de archivo, y los nombres de archivo que se pueden sobrescribir son:
program_icon.png
success_icon.png
running_icon.png
loading_icon.gif
config_icon.png
error_icon.png
- Para empaquetar ejecutables, ofrece un ejemplo con PyInstaller
- El procedimiento resumido consiste en colocar
build.spec en la raíz de la aplicación, modificar los valores APPPNAME, name y pathex según el proyecto, y luego ejecutarlo
pyinstaller -F --windowed build.spec
1 comentarios
Comentarios en Hacker News
Eh, este es mi proyecto ^_^ ¿por qué está hasta arriba de HN?
Para responder brevemente al comentario sobre
argparse, Gooey ya es un proyecto bastante viejo y cuando empezóargparseera una opción sólida.Hoy en día Gooey en sí funciona con JSON y está desacoplado de
argparse, pero casi nadie ha hecho otras interfaces, así queargparsesigue siendo la interfaz “oficial” principal.Algo interesante es que puede invocar no solo Python sino también cualquier ejecutable, así que es bastante útil: https://chriskiehl.com/article/gooey-as-a-universal-frontend
Sobre lo de que el último commit fue hace 2 años: cuando uno se hace mayor y cambian las prioridades, se vuelve difícil encontrar una justificación para seguir manteniendo gratis software de nicho :( No sé si sirva de consuelo, pero siempre me siento culpable.
Curiosamente, por donde vivo hay grafitis que dicen “GOOEY” por todos lados, así que parecen un recordatorio permanente de ese issue tracker abandonado haha
argparsesigue siendo una opción bastante buena. Se usa muchísimo, está bien documentado y es relativamente fácil.Typer y Click también tienen buena usabilidad, pero siento que la documentación tipo “tutorial” de Typer hace bastante difícil buscar respuestas como qué argumentos recibe
Typer.App().El programa en el que estoy trabajando ahora está estructurado para que el usuario empiece a manejar el parseo de argumentos directamente, así que
argparseencaja bien. Me gustaría ofrecer a los usuarios una UI basada en texto como alternativa, pero creo que Textualize requería Click, y aunque intenté integrar Textual directamente en el código para hacer una UI, le metí varias horas y ni siquiera logré arrancar.Hoy en día me frustra muchísimo que no se puedan controlar las aplicaciones por programación. Honestamente, ojalá hubiera una ley que obligara a que toda función de una aplicación tuviera API.
sys.argven un archivo local del directorio de trabajo actual? https://github.com/chriskiehl/Gooey/blob/be4b11b8f27f500e732...tmp.txtestá lejos de tener un nombre único, así que me pregunto si se me está escapando algo.argparse”.Antes de hacer clic, al ver solo el título pensé “seguro depende fuertemente de
argparse”, así que fue una sorpresa agradable.Yo soy un fanático de
getopt, porque considero que la comodidad del usuario importa mucho más que la comodidad del desarrollador. El usuario no debería tener que preocuparse por qué lenguaje de programación o librería para parsear opciones eligió el desarrollador.argparse, Click, el estiloflagde Go/X11 y muchas otras librerías rompen convenciones que llevan medio siglo grabadas en la memoria muscular colectiva. Pero si hay una capa intermedia, parece que sí se puede matar dos pájaros de un tiro.Lo peor es que tampoco ha salido una alternativa viable que lo reemplace, y ninguno de los dos forks ha logrado ganar tracción.
¿No habría que acotarlo a “basado en
argparse”?argparsesirve para casos simples, pero también hay muchos CLI basados en Click, y una buena parte de las librerías populares de CLI están construidas sobre Click. También hay herramientas CLI de Python que no usan niargparseni Click, pero probablemente esas dos sean las más populares.¿Se ha verificado que funcione también con Click? Por ahora solo veo cosas relacionadas con
argparse. Si la respuesta es no, entonces la expresión “casi todos” es claramente falsa, y un título más preciso sería “convertir casi cualquier programa de línea de comandos de Python basado enargparseen una aplicación GUI completa”.También está el hecho de que el último commit significativo fue hace más de 2 años. Eso en sí no es malo, pero viendo la cantidad de issues abiertos no inspira mucha confianza en el proyecto.
Aun así, es un proyecto genial. Me gustaría ver más cosas así. Como dice el README, es una herramienta multiplicadora de fuerza, así que alguien puede crear automatizaciones con CLI y compartirlas fácilmente con gente de oficina no técnica. Es parecido a lo que Access hizo por las bases de datos.
Igual que Access, al crecer en escala o complejidad va a topar con límites, pero para usos pequeños de oficina puede ser lo suficientemente “bueno”.
argparse. Yo tiendo a minimizar las dependencias externas.argparse?Publicaciones relacionadas:
Gooey: Turn almost any Python command line program into a GUI application - https://news.ycombinator.com/item?id=27490291 - junio de 2021, 115 comentarios
Gooey: Turn command line programs into GUI applications - https://news.ycombinator.com/item?id=8218785 - agosto de 2014, 74 comentarios
Estaría bien que el sistema operativo y el shell pudieran entender mejor cómo se ejecuta un programa sin depender de una librería de parsing específica
Sería ideal que los programas se comunicaran en un formato JSON/proto tipado, y que solo con inspeccionar los tipos de entrada y salida esperados se pudiera obtener estructuración y autocompletado de comandos en el shell, o incluso una GUI completa
Por ahora, parece que lo mejor que se puede hacer es una solución armada con cuidado pero algo improvisada. Cada programa tiene que exportar varios archivos de autocompletado para distintos shells, los estilos de flags varían mucho entre programas y librerías de parsing, y por supuesto no hay GUI
Aunque el principal problema de gRPC probablemente sea que muchos desarrolladores, incluyéndome, sienten que es algo más engorroso de manejar que una solución que se use de forma natural dentro del lenguaje
No estoy seguro de si PowerShell puede aprovechar por completo los tipos estáticos que son el núcleo del sistema, pero su capacidad para pasar objetos por la línea de comandos es casi única
En Linux se puede encadenar la línea de comandos combinando
jc(https://github.com/kellyjonbrazil/jc) yjq(https://jqlang.github.io/jq/), pero aun así son como dos pasos extra frente a lo que PowerShell ya trae integradoA veces una GUI se siente como comida reconfortante. Puedes simplemente explorar una interfaz gráfica sin la carga cognitiva que puede generar una CLI que usas muy rara vez
Cambiando un poco de tema, hace unos meses aquí conocí el editor CUDATEXT, que te permite usar elementos GUI arbitrarios como MENU, INPUTS, etc., mediante una API de Python de un solo archivo. Son los mismos elementos que usa el propio editor
Ahora mismo estoy usando esos elementos GUI simples para configurar cosas y generar un blog directamente dentro del editor
También vale la pena ver esto:
“Textual: framework ligero de aplicaciones para Python. Crea interfaces de usuario sofisticadas con una API simple de Python y ejecuta apps en la terminal y en el navegador web” https://github.com/textualize/textual/
camply: https://juftin.com/camply/
Solo quería decir gracias por crear este excelente software. Me gusta Gooey y lo he usado bastante en varios programas
Para mí encaja perfecto justo en ese espacio donde un script de Python hace algo importante y ahora hay que lograr que personas no programadoras también lo usen
Esto me recuerda a naked objects. La idea era que, si definías unas cuantas anotaciones y un tema para una clase Java, se generaba toda una GUI, o incluso una aplicación frontend web
Era una idea muy interesante, pero hasta donde sé, al final no terminó de funcionar bien
Creo que el problema es que se acoplan entre sí preocupaciones verticales como presentación, dominio e infraestructura. Está bien cuando la representación en pantalla y en base de datos del modelo de dominio es simple
Pero si quieres crear una interfaz compleja con muchas comodidades, esos requisitos terminan filtrándose hacia la capa de dominio. Y al revés, si quieres construir un modelo de dominio complejo, se vuelve poco realista hacer cumplir invariantes a nivel del lenguaje, porque cualquier código con una referencia a
Modelpuede modificarlo arbitrariamenteTambién estaría bien algo que hiciera lo contrario
argparse, y luego convertir eso de vuelta en un script de shell que ejecute y guarde los resultados como correspondeEn el antiguo Macintosh Programmer's Workshop, o MPW, el shell basado en texto para Mac OS de los 80 y 90, había una función parecida llamada Commando para casi todos los comandos
La información de Commando se guardaba en recursos
cmdo. Si el soporte para atributos extendidos no hubiera sido tan irregular, hoy todavía se podría hacer algo parecidoRevisando, veo que A/UX también tenía Commando. Si hacías doble clic en un comando de terminal desde Finder, aparecía un cuadro de Commando para elegir opciones de CLI, y luego se ejecutaba en una ventana de shell. Hoy, si ejecutas un comando de terminal desde Finder, simplemente se lanza en una ventana de shell sin argumentos
https://cohost.org/boredzo/post/804893-i-still-want-a-moder
http://toastytech.com/guis/aux3.html