¿Alguna vez te has preguntado dónde estaba tu largo procesamiento y cuándo terminaría? ¿Sueles presionar RETURN
varias veces para asegurarte de que no falló o que la conexión SSH no se congeló? ¿Alguna vez pensaste que sería fantástico poder pausar algún procesamiento sin problemas, volver al indicador de Python para corregir manualmente algunos elementos y luego reanudarlo sin problemas ? Hice...
He empezado esta nueva barra de progreso pensando en todo eso, ¡mira el progreso vivo ! ?
¡Presentamos el concepto más nuevo en barras de progreso para Python! alive-progress
es único en su clase, con una variedad de características interesantes que lo distinguen. Aquí hay algunos aspectos destacados:
check()
súper poderosa que te ayuda a diseñar tus propias animaciones! ¡Puedes ver cómo se verán los fotogramas generados y los ciclos de animación, explotados en tu pantalla e incluso verlos vivos antes de instalarlos en alive-progress
! ¡Es la herramienta más genial del mundo! ¡Da rienda suelta a tu creatividad! Este archivo README siempre está evolucionando, así que eche un vistazo más completo de vez en cuando... ¡Es posible que encuentre nuevos detalles fantásticos en otras secciones! ?
alive-progress
bar()
Después de aproximadamente un año de estabilidad tranquilizadora, ¡el nuevo alive-progress
finalmente ha llegado!
Las principales características y mejoras son:
bar()
con 0
e incluso -N
para hacerlo retroceder. ¡Útil cuando no pudiste avanzar en una iteración o tuviste que retroceder algo!¡Y más!
enrich_offset
personalizado para usar en mensajes impresos o registrados, lo que le permite comenzar con on 1:
o continuar donde lo dejó en los cálculos anteriores. ¡Una actualización genial aquí! Además de pulir las cosas y mejorar el soporte del terminal, ¡ahora alive-progress
admite la reanudación de los cálculos!
Al procesar conjuntos de datos enormes o cosas que llevan mucho tiempo, puede utilizar lotes o almacenar en caché los resultados parciales. Luego, en caso de que se detenga y se reinicie, terminarás omitiendo todos los elementos ya hechos muy rápidamente, lo que hace que alive_bar
piense que estás procesando miles de elementos por segundo, lo que a su vez arruina por completo la ETA... Pero ya no ! ¿Simplemente dile bar()
que te has saltado elementos...?
Puedes usarlo de dos maneras:
1. Si sabes dónde te detuviste:
with alive_bar ( 120000 ) as bar :
bar ( 60000 , skipped = True )
for i in range ( 60000 , 120000 ):
# process item
bar ()
Sí, simplemente llame bar(N, skipped=True)
una vez, con la cantidad de elementos.
2. Si no lo sabes o los artículos están dispersos:
with alive_bar ( 120000 ) as bar :
for i in range ( 120000 ):
if done ( i ):
bar ( skipped = True )
continue
# process item
bar ()
¡Sí, es tan simple como eso! Simplemente llame bar(skipped=True)
cuando un elemento ya esté terminado, o bar()
como de costumbre en caso contrario. También puedes compartir una llamada de una sola bar(skipped=?)
al final, con un bool que indique si omitiste ese elemento o no. Genial, ¿eh?
También en esta versión:
max_cols
, la cantidad de columnas a usar si no es posible recuperarlas, como en jupyter y otras plataformas que no admiten el tamaño¡Sí, finalmente pude sacar esta versión! Estas son las novedades:
B
, bytes
o incluso °C
.sys.stderr
y otros archivos en lugar de sys.stdout
!Correcciones muy esperadas:
TypeError: unhashable type: 'types.SimpleNamespace'
.RotatingFileHandler
s! Sí, busque ayuda aquí.Y por último, pero no menos importante, ¡un diseño más pulido para que disfrutes de tu progreso!
¡Ahora, alive_bar
admite el modo de texto de doble línea !
Si alguna vez quisiste incluir mensajes situacionales más largos dentro de la barra, probablemente te sentiste apretado en una sola línea. Tenías que reducir la barra bellamente animada o, peor aún, eliminar los widgets (!) para poder ver lo que necesitabas...
¡¡Ya no!! ¡Ahora puedes hacer que la barra sea Línea Dual y poner texto debajo!
Sí, hay un mensaje debajo de toda la barra y cualquier otro mensaje de impresión/registro se desplaza encima de él.
letters = [ chr ( ord ( 'A' ) + x ) for x in range ( 26 )]
with alive_bar ( 26 , dual_line = True , title = 'Alphabet' ) as bar :
for c in letters :
bar . text = f'-> Teaching the letter: { c } , please wait...'
if c in 'HKWZ' :
print ( f'fail " { c } ", retry later' )
time . sleep ( 0.3 )
bar ()
Producción:
on 7: fail "H", retry later
on 10: fail "K", retry later
Alphabet |███████████████████████████▊ | ▃▅▇ 18/26 [69%] in 6s (3.2/s, eta: 3s)
-> Teaching the letter: S, please wait...
También hay un nuevo parámetro de función finalize
en alive_it
que le permite configurar el título y/o el texto del recibo final, y soporte de registro mejorado que detecta registradores personalizados.
Se trata de personalización; Los widgets principales ahora se pueden cambiar:
monitor
, elapsed
y stats
para que se vean como quieras.Es increíble que estas cadenas admitan todas las funciones del formato Python, por lo que puedes, por ejemplo,
{percent:.1%}
.
¡Se pueden personalizar aún más en el recibo final !
monitor_end
, elapsed_end
y stats_end
, con formatos dinámicos heredados de los estándar!Si ha ocultado algunos widgets antes, solo para que no aparecieran en el recibo, ahora puede verlos en todo su esplendor y ocultar solo los del recibo. ¿O al revés?
Otra adición, ahora alive-progress
muestra maravillosamente su genial recibo final cada vez que se detiene, ¡incluso si presiona CTRL+C prematuramente! No sé por qué no había pensado en eso antes...
Download |██████████████████︎ | (!) 45/100 [45%] in 4.8s (9.43/s)
Y finalmente, ¡puedes optar por desactivar CTRL+C por completo! El valor predeterminado es el más seguro ctrl_c=True
, lo que hace que CTRL-C funcione como de costumbre.
Desactívelo ctrl_c=False
, para hacer que su alive_bar
interactivo sea mucho más fluido de usar (no hay rastros de pila si lo detiene) y/o si está en el nivel superior de su programa.
Cuidado: si, por ejemplo, está dentro de un bucle for, simplemente continuará con la siguiente iteración, que puede ser o no lo que desea...
for i in range ( 10 ):
with alive_bar ( 100 , ctrl_c = False , title = f'Download { i } ' ) as bar :
for i in range ( 100 ):
time . sleep ( 0.02 )
bar ()
Producción:
Download 0 |████████▊︎ | (!) 22/100 [22%] in 0.6s (36.40/s)
Download 1 |████████████████▊︎ | (!) 42/100 [42%] in 1.0s (41.43/s)
Download 2 |██████▍︎ | (!) 16/100 [16%] in 0.4s (39.29/s)
Download 3 |█████▋︎ | (!) 14/100 [14%] in 0.4s (33.68/s)
Download 4 |█████████████▎︎ | (!) 33/100 [33%] in 0.8s (39.48/s)
Download 5 |███████▎︎ | (!) 18/100 [18%] in 0.5s (37.69/s)
Download 6 |█████▎︎ | (!) 13/100 [13%] in 0.3s (37.28/s)
Download 7 |████████████︎ | (!) 30/100 [30%] in 0.8s (38.43/s)
Download 8 |██████︎ | (!) 15/100 [15%] in 0.4s (36.26/s)
...
¡Algunas características nuevas importantes, a menudo solicitadas, finalmente han llegado!
click.echo()
¡SÍ! ¡Ahora alive-progress
es compatible con Jupyter Notebooks y también incluye un estado Desactivado ! ¡Ambos eran muy buscados y finalmente aterrizaron!
Y mejor aún, he implementado un mecanismo de detección automática para los cuadernos Jupyter, por lo que simplemente funciona, listo para usar, ¡sin ningún cambio en su código!
Vea usted mismo:
Parece funcionar muy bien, pero en este momento debería considerarse experimental .
Hubo casos en los que aparecieron algunos fallos visuales, como dos actualizacionesalive_bar
concatenadas juntas en lugar de una encima de la otra... Y es algo que creo que no puedo solucionar: parece que Jupyter a veces actualiza el lienzo en momentos extraños, lo que le hace perder algunos datos. Por favor, avíseme sobre los problemas si surge algo más divertido.
¡Este es un gran avance en alive-progress
!
Me tomó 1 año desarrollarlo y estoy muy orgulloso de lo que he logrado o/
.check()
potentes y pulidas que compilan y renderizan maravillosamente todos los fotogramas de todos los ciclos de animación de hilanderos y barras! ¡Incluso pueden incluir datos de fotogramas completos, puntos de código internos e incluso sus animaciones! ?alive-progress
!alive_it
, que acepta un iterable y llama bar()
por ti.Dado que se trata de un cambio de versión importante, no se garantiza la compatibilidad directa con versiones anteriores. Si algo no funciona al principio, simplemente verifique las nuevas importaciones y firmas de funciones, y estará listo. ¡Todas las funciones anteriores deberían seguir funcionando aquí! ?
alive-progress
Simplemente instale con pip:
❯ pip install alive-progress
Si te preguntas qué estilos están integrados, ¡es showtime
! ;)
from alive_progress . styles import showtime
showtime ()
Nota: ignore la ruta en el gif animado a continuación; la correcta está arriba. Generar estos gifs largos requiere mucho tiempo, por lo que no puedo hacer otro con cada cambio. Gracias por tu comprensión.
Hice estos estilos solo para probar todas las fábricas de animación que he creado, ¡pero creo que algunos de ellos terminaron muy, muy geniales! ¡Úsalos a tu antojo y mézclalos a tu gusto!
¿Quieres ver barras alive-progress
ejecutándose gloriosamente en tu sistema antes de probarlas tú mismo?
❯ python -m alive_progress.tools.demo
Genial, ¿eh? Ahora ingresa un REPL ipython
y prueba esto:
from alive_progress import alive_bar
import time
for x in 1000 , 1500 , 700 , 0 :
with alive_bar ( x ) as bar :
for i in range ( 1000 ):
time . sleep ( .005 )
bar ()
¿Verás algo como esto, con animaciones geniales durante todo el proceso?:
|████████████████████████████████████████| 1000/1000 [100%] in 5.8s (171.62/s)
|██████████████████████████▋︎ | (!) 1000/1500 [67%] in 5.8s (172.62/s)
|████████████████████████████████████████✗︎ (!) 1000/700 [143%] in 5.8s (172.06/s)
|████████████████████████████████████████| 1000 in 5.8s (172.45/s)
Bonito, ¿eh? ¿Te encantó? Sabía que lo harías, ¿gracias?.
Para usarlo realmente, simplemente envuelva su bucle normal en un administrador de contexto de alive_bar
como este:
with alive_bar ( total ) as bar : # declare your expected total
for item in items : # <<-- your original loop
print ( item ) # process each item
bar () # call `bar()` at the end
¡Y está vivo! ?
Entonces, en pocas palabras: recupere los elementos como siempre, ingrese al administrador de contexto alive_bar
con la cantidad de elementos y luego itere/procese esos elementos, llamando bar()
al final. ¡Es así de simple! :)
items
pueden ser iterables, como por ejemplo, un conjunto de consultas;alive_bar
es el total esperado, como qs.count()
para conjuntos de consultas, len(items)
para iterables con longitud o incluso un número estático;bar()
es lo que hace que la barra avance; normalmente la llamas en cada iteración, justo después de terminar un elemento;bar()
demasiado (o muy poco al final), la barra representará gráficamente esa desviación del total
esperado, haciendo que sea muy fácil notar desbordamientos y desbordamientos;bar.current
.¡Puedes ser creativo! Dado que la barra solo avanza cuando llamas
bar()
, ¡es independiente del bucle ! Así que puedes usarlo para monitorear cualquier cosa que quieras, como transacciones pendientes, artículos rotos, etc., ¡o incluso llamarlo más de una vez en la misma iteración! Entonces, al final, sabrás cuántos de esos eventos "especiales" hubo, ¡incluido su porcentaje en relación con el total!
Mientras esté dentro de un contexto alive_bar
, puede mostrar sin esfuerzo mensajes estrechamente integrados con la barra de progreso actual que se muestra. ¡No se romperá de ninguna manera e incluso enriquecerá tu mensaje!
bar.text('message')
y bar.text = 'message'
establecen un mensaje situacional justo dentro de la barra, donde puedes mostrar algo sobre el elemento actual o la fase en la que se encuentra el procesamiento;bar.title('Title')
y bar.title = 'Title'
; mezcle con title_length
para evitar que la barra cambie su longitud;print()
habitual de Python, donde alive_bar
limpia muy bien la línea, imprime su mensaje junto a la posición actual de la barra en ese momento y continúa la barra justo debajo de ella;logging
estándar de Python, incluidas las salidas de archivos, también está enriquecido exactamente como el anterior;click.echo()
para imprimir texto con estilo.Impresionante ¿verdad? ¡Y todos funcionan igual en una terminal o en una computadora portátil Jupyter!
¡Ahora tienes una manera más rápida de monitorear cualquier cosa! ¡Aquí, los artículos se rastrean automáticamente para usted!
¡Contempla el adaptador iterador alive_it
=> alive_bar
!
¡Simplemente envuelve tus artículos con él y envuélvelos como de costumbre!
La barra simplemente funcionará; ¡Es así de simple!
from alive_progress import alive_it
for item in alive_it ( items ): # <<-- wrapped items
print ( item ) # process each item
¡¿QUÉ GENIAL ES ESO?! ?
Se aplican todos los parámetros de alive_bar
, excepto total
, que es más inteligente (si no se proporciona, se inferirá automáticamente a partir de sus datos usando len
o length_hint
), y manual
, que no tiene sentido aquí.
Tenga en cuenta que no hay ninguna manija bar
allí. Pero ¿qué pasa si realmente lo desea, por ejemplo para configurar mensajes de texto o recuperar el progreso actual?
Puedes interactuar con la alive_bar
interna simplemente asignando alive_it
a una variable como esta:
bar = alive_it ( items ) # <<-- bar with wrapped items
for item in bar : # <<-- iterate on bar
print ( item ) # process each item
bar . text ( f'ok: { item } ' ) # WOW, it works!
Tenga en cuenta que esta es una bar
ligeramente especial, que no admite bar()
, ya que el adaptador del iterador rastrea los elementos automáticamente. Además, admite finalize
, que le permite configurar el título y/o texto del recibo final:
alive_it ( items , finalize = lambda bar : bar . text ( 'Success!' ))
...
En una palabra:
- el uso completo es siempre
with alive_bar() as bar
, donde iteras y llamasbar()
cuando quieras;- el uso rápido del adaptador es
for item in alive_it(items)
, donde los elementos se rastrean automáticamente;- El uso completo del adaptador es
bar = alive_it(items)
, donde además de los elementos que se rastrean automáticamente, obtienes unabar
iterable especial capaz de personalizar elalive_progress
interno como quieras.
Los modos predeterminados son automático y desconocido , que utilizan internamente un contador para seguir el progreso. Cuentan la cantidad de elementos procesados y lo usan para actualizar la barra de progreso en consecuencia.
El argumento total
es opcional. Si lo proporcionas, la barra entra en modo automático . En este modo, el progreso de la operación se rastrea automáticamente y todos los widgets alive-progress
tiene para ofrecer están disponibles: barra precisa, control giratorio, porcentaje, contador, rendimiento y ETA.
Si no proporcionas total
, la barra entra en modo desconocido . En este modo, el progreso es indeterminable, y por tanto la ETA, por lo que toda la barra de progreso está continuamente animada. Los widgets disponibles son: barra animada, rueda giratoria, contador y rendimiento.
¡La genial ruleta se ejecuta de forma completamente independiente de la barra animada, y ambas ejecutan sus propias animaciones al mismo tiempo, lo que genera un espectáculo único en tu terminal! ?
Por último, pero no menos importante, el modo automático tiene una capacidad única: marcar elementos como omitidos, lo que hace que el rendimiento y la ETA sean mucho más precisos. Más sobre eso más adelante.
El modo manual , activado manualmente por el argumento manual=True
, utiliza internamente un porcentaje para seguir el progreso. Le permite obtener un control total de la posición de la barra. Por lo general, se usa para monitorear procesos que solo le brindan un porcentaje de finalización o para generar algunos efectos especiales aleatorios.
¡Puedes usarlo directamente con alive_bar
o mediante config_handler
y te permite enviar porcentajes al controlador bar()
! Por ejemplo, para establecerlo en un 15% de finalización, simplemente llame bar(0.15)
, que es 15/100.
También puede proporcionar total
aquí. Si lo hace, alive-progress
inferirá automáticamente un contador interno y, por lo tanto, podrá ofrecerle los mismos widgets disponibles en modo automático.
Si no proporciona total
, al menos obtendrá versiones aproximadas de los widgets de rendimiento y ETA, calculados como "%/s" (porcentaje por segundo) y hasta 100%, respectivamente. Ninguno de ellos es muy preciso, pero es mejor que nada.
Cuando se proporciona total
, todo está bien:
modo | encimera | porcentaje | rendimiento | ETA | sobre/subdesbordamiento |
---|---|---|---|---|---|
auto | ✅ (tick de usuario) | ✅ (inferido) | ✅ | ✅ | ✅ |
manual | ✅ (inferido) | ✅ (conjunto de usuario) | ✅ | ✅ | ✅ |
Cuando no es así, se deben hacer algunos compromisos:
modo | encimera | porcentaje | rendimiento | ETA | sobre/subdesbordamiento |
---|---|---|---|---|---|
desconocido | ✅ (tick de usuario) | ✅ | |||
manual | ✅ (conjunto de usuario) | ✅ |
Pero en realidad es fácil de entender: ¡no necesitas pensar qué modo deberías usar!
total
si lo tiene y utilice manual
si lo necesita!¡Eso es todo! ¡Funcionará lo mejor que pueda! ? o/
bar()
Los controladores bar()
admiten semántica relativa o absoluta, según el modo:
bar()
para incrementar el contador en uno, o enviar cualquier otro incremento como bar(200)
para incrementar en 200 a la vez;¡Incluso admiten
bar(0)
ybar(-5)
para mantener o disminuir si es necesario!
bar(0.35)
para hacer que la barra salte instantáneamente al 35 % de progreso.¡Ambos modos te permiten ser creativo! Como puedes hacer que la barra vaya instantáneamente a la posición que desees, puedes:
- hacerlo retroceder, por ejemplo, para mostrar gráficamente el tiempo de espera de algo;
- crear efectos especiales, por ejemplo, para imitar algún tipo de indicador analógico en tiempo real.
¡Puedes llamar bar()
tantas veces como quieras! La frecuencia de actualización del terminal siempre se calculará de forma asincrónica de acuerdo con el rendimiento y el progreso actuales, por lo que no correrá el riesgo de enviar spam al terminal con más actualizaciones de las necesarias.
En cualquier caso, para recuperar el contador/porcentaje actual, simplemente llame a: bar.current
:
Finalmente, el controlador bar()
aprovecha la habilidad única del modo automático : simplemente llame bar(skipped=True)
o bar(N, skipped=True)
para usarlo. Cuando skipped
se establece en = True
, los elementos asociados se excluyen de los cálculos de rendimiento, lo que evita que los elementos omitidos afecten de manera inexacta la ETA.
Mantener un proyecto de código abierto es difícil y requiere mucho tiempo, y he puesto mucho ❤️ y esfuerzo en esto.
Si has apreciado mi trabajo, ¡puedes respaldarme con una donación! Gracias ?
La exposición showtime
tiene un argumento opcional para elegir qué programa presentar, Show.SPINNERS
(predeterminado), Show.BARS
o Show.THEMES
, ¡échales un vistazo! ;)
from alive_progress . styles import showtime , Show
showtime ( Show . BARS )
showtime ( Show . THEMES )
Nota: ignore la ruta en el gif animado a continuación; la correcta está arriba. Generar estos gifs largos requiere mucho tiempo, por lo que no puedo hacer otro con cada cambio. Gracias por tu comprensión.
Y el de temas (? nuevo en 2.0):
La exhibición showtime
también acepta algunas opciones de personalización:
Por ejemplo, para obtener un espectáculo marino, puede showtime(pattern='boat|fish|crab')
:
¡También puedes acceder a estos programas con las abreviaturas
show_bars()
,show_spinners()
yshow_themes()
!
También hay una pequeña utilidad llamada
print_chars()
, para ayudar a encontrar ese personaje interesante para colocar en sus barras y hilanderos personalizados, o para determinar si su terminal admite caracteres Unicode.
¡Hay varias opciones para personalizar tanto la apariencia como el comportamiento!
¡Todos ellos se pueden configurar directamente en alive_bar
o globalmente en config_handler
!
Estas son las opciones (valores predeterminados entre paréntesis):
title
: un título de barra opcional y siempre visiblelength
: [ 40
] el número de columnas para representar la barra de progreso animadamax_cols
: [ 80
] las columnas máximas a usar si no es posible recuperarlas, como en jupyterspinner
: el estilo del spinner que se representará junto a la barrabar
: el estilo de barra que se representará en modos conocidosunknown
: el estilo de barra que se representará en modo desconocidotheme
: [ 'smooth'
] un conjunto de ruleta, barra y desconocido coincidentesforce_tty
: [ None
] fuerza que las animaciones estén activadas, desactivadas o según el tty (más detalles aquí)file
: [ sys.stdout
] el objeto de archivo a utilizar: sys.stdout
, sys.stderr
o un TextIOWrapper
similardisable
: [ False
] si es Verdadero, desactiva completamente todos los resultados, no instale ganchosmanual
: [ False
] configurado para controlar manualmente la posición de la barraenrich_print
: [ True
] enriquece la impresión() y el registro de mensajes con la posición de la barraenrich_offset
: [ 0
] el desplazamiento que se aplicará a enrich_printreceipt
: [ True
] imprime el bonito recibo final, se desactiva si es Falsoreceipt_text
: [ False
] configurado para repetir el último mensaje de texto en el recibo finalmonitor
(bool|str): [ True
] configura el widget del monitor 152/200 [76%]
{count}
, {total}
y {percent}
para personalizarlaelapsed
(bool|str): [ True
] configura el widget de tiempo transcurrido in 12s
{elapsed}
para personalizarlostats
(bool|str): [ True
] configura el widget de estadísticas (123.4/s, eta: 12s)
{rate}
y {eta}
para personalizarlamonitor_end
(bool|str): [ True
] configura el widget del monitor dentro del recibo finalmonitor
elapsed_end
(bool|str): [ True
] configura el widget de tiempo transcurrido dentro del recibo finalelapsed
stats_end
(bool|str): [ True
] configura el widget de estadísticas dentro del recibo final{rate}
para personalizarla (sin relación con las estadísticas)title_length
: [ 0
] fija la longitud de los títulos, o 0 para ilimitadosspinner_length
: [ 0
] fuerza la longitud del spinner, o 0
para la naturalrefresh_secs
: [ 0
] fuerza el período de actualización a esto, 0
es la retroalimentación visual reactivactrl_c
: [ True
] si es falso, desactiva CTRL+C (lo captura)dual_line
: [ False
] si es Verdadero, coloca el texto debajo de la barraunit
: cualquier texto que etiquete sus entidadesscale
: la escala que se aplicará a las unidades: None
, SI
, IEC
o SI2
False
o ''
-> None
, True
-> SI
, 10
o '10'
-> SI
, 2
o '2'
-> IEC
precision
: [ 1
] cuántos decimales se muestran al escalar Y también hay uno que sólo se puede configurar localmente en el contexto de alive_bar
:
calibrate
: rendimiento teórico máximo para calibrar la velocidad de la animación (más detalles aquí) Para configurarlos localmente, simplemente envíelos como argumentos de palabras clave a alive_bar
:
with alive_bar ( total , title = 'Processing' , length = 20 , bar = 'halloween' ) as bar :
...
Para usarlos globalmente, envíelos a config_handler
, ¡y cualquier alive_bar
creado después incluirá esas opciones! Y puedes mezclarlas y combinarlas, las opciones locales siempre tienen prioridad sobre las globales:
from alive_progress import config_handler
config_handler . set_global ( length = 20 , spinner = 'wait' )
with alive_bar ( total , bar = 'blocks' , spinner = 'twirls' ) as bar :
# the length is 20, the bar is 'blocks' and the spinner is 'twirls'.
...
¡Sí, puedes armar tus propios hilanderos! ¡Y es fácil!
¡He creado una gran cantidad de efectos especiales, para que puedas mezclarlos y combinarlos como quieras! ¡Hay hilanderos de fotogramas, de desplazamiento, de rebote, secuenciales, paralelos y retrasados! ¡Sea creativo! ?
¿Las animaciones de los hilanderos están diseñadas mediante expresiones generadoras muy avanzadas, en lo profundo de varias capas de metafábricas, fábricas y generadores?
alive_bar
como a config_handler
;Estos generadores son capaces de realizar múltiples ciclos de animación diferentes según el comportamiento del girador, por ejemplo, un girador que rebota puede ejecutar un ciclo para traer suavemente un sujeto a la escena, luego reposicionarlo repetidamente hasta el otro lado y luego hacerlo desaparecer suavemente de la escena. > ¡y todo esto es solo un ciclo! Luego puede seguir otro ciclo para hacerlo todo de nuevo, ¡pero al revés! ¡Y los hilanderos que rebotan también aceptan patrones diferentes y alternos tanto en la dirección derecha como en la izquierda, lo que les hace generar el producto cartesiano de todas las combinaciones, posiblemente produciendo docenas de ciclos diferentes hasta que comienzan a repetirlos! ?
Y hay más, creo que uno de los logros más impresionantes que obtuve en este sistema de animación (además del compilador giratorio en sí)... ¡Solo producen más fotogramas de animación hasta que el ciclo actual no se agota, luego se detienen solos ! Sí, ¡el próximo ciclo aún no comienza! ¡Este comportamiento crea pausas naturales exactamente en los lugares correctos, donde las animaciones no se interrumpen, por lo que puedo vincular sin problemas con cualquier otra animación que quiera!
Esto tiene todo tipo de implicaciones interesantes: los ciclos pueden tener diferentes recuentos de cuadros, diferentes duraciones de pantalla, no necesitan estar sincronizados, pueden crear secuencias largas diferentes por sí mismos, pueden cooperar para reproducir ciclos en secuencia o al lado, y yo ¡Puede sorprenderte mostrando varias animaciones totalmente distintas al mismo tiempo sin interferencia alguna!
Es casi como si estuvieran... ¡¡vivos !! ?
==> ¡Sí, de ahí viene el nombre de este proyecto!
Ahora, estos generadores de ciclos y fotogramas son consumidos por completo antes de tiempo por el compilador Spinner . ¡Este es un nuevo procesador genial que hice dentro del esfuerzo de Cell Architecture , para hacer que todas estas animaciones funcionen incluso en presencia de caracteres anchos o grupos de grafemas complejos! Fue muy difícil hacer que estos grupos entraran y salieran gradualmente de los fotogramas, sin problemas, evitando al mismo tiempo que rompieran la codificación Unicode y, sobre todo, mantuvieran sus longitudes originales en todos los fotogramas. Sí, varios caracteres en secuencia pueden representar otro símbolo completamente diferente, por lo que nunca se pueden dividir. ¡¡Tienen que entrar y salir del cuadro siempre juntos, todos a la vez, o el grafema no aparecerá en absoluto (un Emoji por ejemplo)!! Ingrese al compilador Spinner ......
¡¡Esto ha hecho posible algunas cosas increíbles!! Dado que este compilador genera todos los datos del cuadro giratorio de antemano:
Entonces, puedo simplemente recopilar todas las animaciones listas para reproducir y terminar con ellas, ¡sin sobrecarga de tiempo de ejecución ! ?
Además, con los datos completos del cuadro compilados y persistidos, pude crear varios comandos para refactorizar esos datos, como cambiar formas, reemplazar caracteres, agregar pausas visuales (repeticiones de cuadros), generar efectos de rebote bajo demanda sobre cualquier contenido e incluso transponer ciclos. con marcos!!
Pero ¿cómo puedes ver estos efectos? ¿Se ve bien el efecto que creaste? ¿O no funciona como pensabas? ¡SÍ, ahora puedes ver todos los ciclos y fotogramas generados analíticamente, en una interpretación muy hermosa!
¿Me encanta lo que he logrado aquí?, es probablemente LA herramienta más hermosa que he creado... ¡¡He aquí la herramienta check
!!
Es increíble si lo digo yo mismo, ¿no? Y un software muy complejo del que estoy orgulloso, eche un vistazo a su código si lo desea.
¡Y la herramienta check
es mucho más poderosa! Por ejemplo, ¡puedes ver los puntos de código de los marcos! Y tal vez tenga una idea de por qué esta versión era tan, muy dura y compleja de hacer ...
En rojo, verá los clústeres de grafeme, que ocupan una o dos "posiciones lógicas", independientemente de sus tamaños reales ... estas son las "celdas" de la nueva arquitectura celular ...
Mira lo increíble que está representada una bandera de emoji:
¡La bandera parece moverse tan suavemente porque usa "medio personajes"! Dado que es un amplio carbón, alive-progress
sabe que se representará con "dos caracteres visibles", y las animaciones consideran esto, pero componen con espacios, que ocupan solo uno. Cuando uno usa fondos mixtos, la situación es mucho más compleja ...
Los tipos de fábricas que he creado son:
frames
: dibuja cualquier secuencia de caracteres a voluntad, que se reproducirá marco por marco en secuencia;scrolling
: genera un flujo suave de un lado al otro, escondido o envolviendo bordes invisibles, permite usar sujetos uno a la vez, generando varios ciclos de caracteres distintos;bouncing
: similar al scrolling
, pero hace que las animaciones se recuperen hasta el principio, escondiéndose o rebotando inmediatamente sobre bordes invisibles;sequential
obtenga un puñado de fábricas y juegue una tras otra secuencialmente! permite entremezclarlos o no;alongside
a obtener un puñado de fábricas y jugarlas junto con simultáneamente, ¿por qué elegir cuándo puedes tenerlas todas? permite elegir el pivote de la animación;delayed
: ¡Obtenga cualquier otra fábrica y cópiela varias veces, omitiendo cada vez más algunos cuadros en cada uno! ¡Los efectos muy geniales se hacen aquí!Para obtener más detalles, mire sus documentos, que son muy completos.
Personalizar bares no está cerca de eso involucrado. Digamos que son objetos pasivos "inmediatos". No admiten animaciones, es decir, siempre generarán la misma interpretación dados los mismos parámetros. Recuerde que los hilanderos son generadores infinitos, capaces de generar secuencias largas y complejas.
Bueno, las barras también tienen una meta fábrica, usan cierres para almacenar los parámetros de estilo y recibir parámetros operativos adicionales, pero luego la fábrica real no puede generar ningún contenido por sí solo. Todavía necesita un parámetro adicional, un número de punto flotante entre 0 y 1, que es el porcentaje para renderizarse.
alive_bar
calcula este porcentaje automáticamente en función del mostrador y el total, ¡pero puede enviarlo usted mismo cuando está en el modomanual
!
¡Las barras tampoco tienen un compilador de barras, pero sí proporcionan la herramienta de verificación ! ?
¡Incluso puede mezclar y combinar caracteres anchos y caracteres normales como en los hilanderos! (¿Y todo se mantiene perfectamente alineado?)
¡Use las herramientas de verificación del contenido de su corazón! ¡Tienen aún más golosinas esperando, incluso animaciones en tiempo real!
¡Crea las animaciones más salvajes y geniales que puedes y envíelas a mí!
¡Estoy pensando en crear algún tipo de paquetecontrib
, con hilanderos y barras de control de usuarios!
¡Vaya, si has leído todo hasta aquí, ahora deberías tener un buen conocimiento sobre el uso de alive-progress
! ?
¡Pero prepárate porque hay aún más y emocionantes cosas que se avecinan!
Mantener un proyecto de código abierto es difícil y que requiere mucho tiempo, y he puesto mucho ❤️ y esfuerzo en esto.
Si has apreciado mi trabajo, ¡puedes respaldarme con una donación! Gracias ?
Oh, quieres pausarlo por completo, ¿escucho? Este es un concepto de novela increíble, que no se encuentra en ningún lugar afaik.
¡Con esto puede actuar sobre algunos artículos manualmente , a voluntad, justo en medio de un procesamiento continuo!
Sí, puede volver a la solicitud y arreglar, cambiar, enviar cosas, y el bar simplemente "recordará" dónde estaba ...
Supongamos que necesita conciliar las transacciones de pago (he estado allí, hecho eso). Debe iterar más de miles de ellos, detectar de alguna manera los defectuosos y arreglarlos. Esta solución no es simple ni determinista, debe estudiar cada uno para comprender qué hacer. Podrían faltar a un destinatario, o tener la cantidad incorrecta, o no sincronizarse con el servidor, etc., es difícil incluso imaginar todas las posibilidades.
Por lo general, tendría que dejar que el proceso de detección se ejecute hasta su finalización, agregando a una lista cada inconsistencia que encuentre y esperando, potencialmente mucho tiempo, hasta que finalmente puede comenzar a solucionarlos ... podría mitigar eso procesando en trozos. , o imprimirlos y actuar a través de otro caparazón, etc., pero esas tienen sus propias deficiencias ...?
¡Ahora, hay una mejor manera! ¡Simplemente pause el proceso de detección real por un tiempo! Entonces solo tienes que esperar hasta que se encuentre la próxima falla, ¡y actúe en tiempo real!
Para usar el mecanismo de pausa, solo debe escribir una función, para que el código pueda yield
los elementos con los que desea interactuar. Lo más probable es que ya use uno en su código, pero en el shell ipython
u otro replice, probablemente no lo haga. ¡Así que envuelva su código de depuración en una función, luego ingrese dentro de un contexto de bar.pause()
!
def reconcile_transactions ():
qs = Transaction . objects . filter () # django example, or in sqlalchemy: session.query(Transaction).filter()
with alive_bar ( qs . count ()) as bar :
for transaction in qs :
if faulty ( transaction ):
with bar . pause ():
yield transaction
bar ()
¡Eso es todo! ¡Es así de simple! o/
Ahora ejecute gen = reconcile_transactions()
para instanciar el generador, y cuando desee la próxima transacción defectuosa, ¡simplemente llame next(gen, None)
! Me encanta...
La barra alive-progress
comenzará y funcionará como de costumbre, pero tan pronto como se encuentre cualquier inconsistencia, la barra se detendrá, apagará el hilo de actualización y recordando su estado exacto, ¡y le producirá la transacción directamente en el aviso! ¡Es casi mágico! ?
In [11]: gen = reconcile_transactions()
In [12]: next(gen, None)
|█████████████████████ | 105/200 [52%] in 5s (18.8/s, eta: 4s)
Out[12]: Transaction<#123>
Luego puede inspeccionar la transacción con el atajo _
habitual de ipython
(o simplemente asignarlo directamente con t = next(gen, None)
), ¡y está listo para solucionarlo!
¡Cuando haya terminado, simplemente reactive la barra con la misma next
llamada que antes! ¡La barra reaparece, vuelve a encender todo y continúa como si nunca se hubiera detenido ! Ok, ¿es mágico?
In [21]: next(gen, None)
|█████████████████████ | ▁▃▅ 106/200 [52%] in 5s (18.8/s, eta: 4s)
Enjuague y repita hasta que aparezca el recibo final, y ya no habrá transacciones defectuosas. ?
Entonces, debe monitorear una operación fija, sin bucles, ¿verdad?
¡Funcionará seguro! Aquí hay un ejemplo ingenuo (lo haremos mejor en un momento):
with alive_bar ( 4 ) as bar :
corpus = read_file ( file )
bar () # file was read, tokenizing
tokens = tokenize ( corpus )
bar () # tokens generated, processing
data = process ( tokens )
bar () # process finished, sending response
resp = send ( data )
bar () # we're done! four bar calls with `total=4`
Es ingenuo porque supone que todos los pasos toman la misma cantidad de tiempo, pero en realidad, cada uno puede tomar un tiempo muy diferente para completar. Piense en read_file
y tokenize
puede ser extremadamente rápido, lo que hace que el porcentaje se dispare al 50%, luego se detenga durante mucho tiempo en el paso process
... Entiende el punto, puede arruinar la experiencia del usuario y crear una ETA muy engañosa.
¡Para mejorar que debe distribuir los porcentajes de los pasos en consecuencia! Dado que le dijiste alive_bar
de que había cuatro pasos, cuando se completó el primero, entendió 1/4 o el 25% de todo el procesamiento se completó ... por lo tanto, debe medir cuánto tiempo tardan realmente sus pasos y usar el modo manual para ¡Aumente el porcentaje de barra por la cantidad correcta en cada paso!
¡Puede usar mi otro proyecto de código abierto a punto de tiempo para medir fácilmente estas duraciones! Solo intente simular con algunas entradas representativas, para obtener mejores resultados. Algo como:
from about_time import about_time
with about_time () as t_total : # this about_time will measure the whole time of the block.
with about_time () as t1 : # the other four will get the relative timings within the whole.
corpus = read_file ( file ) # `about_time` supports several calling conventions, including one-liners.
with about_time () as t2 : # see its documentation for more details.
tokens = tokenize ( corpus )
with about_time () as t3 :
data = process ( tokens )
with about_time () as t4 :
resp = send ( data )
print ( f'percentage1 = { t1 . duration / t_total . duration } ' )
print ( f'percentage2 = { t2 . duration / t_total . duration } ' )
print ( f'percentage3 = { t3 . duration / t_total . duration } ' )
print ( f'percentage4 = { t4 . duration / t_total . duration } ' )
¡Ahí tienes! ¡Ahora conoce los tiempos relativos de todos los pasos y puede usarlos para mejorar su código original! ¡Simplemente obtenga los tiempos acumulativos y póngalos dentro de un modo manual alive_bar
!
Por ejemplo, si los tiempos que encontró fueron 10%, 30%, 20%y 40%, usaría 0.1, 0.4, 0.6 y 1.0 (el último siempre debe ser 1.0):
with alive_bar ( 4 , manual = True ) as bar :
corpus = read_big_file ()
bar ( 0.1 ) # 10%
tokens = tokenize ( corpus )
bar ( 0.4 ) # 30% + 10% from previous steps
data = process ( tokens )
bar ( 0.6 ) # 20% + 40% from previous steps
resp = send ( data )
bar ( 1. ) # always 1. in the last step
¡Eso es todo! La experiencia del usuario y la ETA deberían mejorarse enormemente ahora.
Sí, ¡puedes calibrar la velocidad de la hilería!
Las barras alive-progress
tienen una retroalimentación visual genial del rendimiento actual, por lo que puede ver qué tan rápido es su procesamiento, ya que el spinner funciona más rápido o más lento con él.
Para que esto suceda, he reunido e implementado algunas curvas FPS para encontrar empíricamente cuál le dio la mejor sensación de velocidad:
(Versión interactiva [aquí] (https://www.desmos.com/calculator/ema05elsux)))
El gráfico muestra las curvas logarítmicas (rojo), parabólicas (azules) y lineales (verdes), estas son las que comencé. No fue una tarea fácil, he hecho docenas de pruebas, y nunca encontré una que realmente inspirara esa sensación de velocidad que estaba buscando. El mejor parecía ser el logarítmico, pero reaccionó mal con pequeños números. Sé que podría hacer que funcione con algunos giros para esos pequeños números, así que experimenté mucho y ajusté la curva logarítmica (naranja punteada) hasta que finalmente encontré el comportamiento que esperaba. Es el que parecía proporcionar los mejores cambios de velocidad percibidos en todo el espectro de unos pocos a miles de millones ... Esa es la curva con la que he establecido, y es la que se usa en todos los modos y condiciones. En el futuro y si alguien le resulte útil, esa curva podría ser configurable.
Bueno, la calibración predeterminada alive-progress
es de 1,000,000 en modos limitados, es decir, se necesitan 1 millón de iteraciones por segundo para que la barra se actualice a 60 cuadros por segundo. En el modo manual ilimitado, es 1.0 (100%). Ambos permiten un vasto rango operativo y generalmente funcionan bastante bien.
Por ejemplo, eche un vistazo al efecto que tienen estas calibraciones muy diferentes, ¡ejecutando el mismo código a la misma velocidad! Observe la sensación de que el spinner pasa al usuario, ¿es este procesamiento lento o va rápido? Y recuerde que eso no es solo la ruleta refrescante, sino toda la línea, completa con la interpretación de la barra y todos los widgets, por lo que todo se vuelve más suave o lento:
Entonces, si su procesamiento apenas llega a 20 ítems por segundo, y cree que
alive-progress
está en lente, podría aumentar esa sensación de velocidad al calibrarla para decir40
, y se ejecutará mucho más rápido ... es ¡Es mejor dejar siempre un poco de espacio para la cabeza y calibrarlo en algo entre 50% y 100% más, y luego ajustarlo desde allí para encontrar el que más le gusta! :)
¿Estas asombrosas animaciones alive-progress
se niegan a mostrar?
Pycharm es increíble, ¡me encanta! Pero nunca entenderé por qué han deshabilitado emulando un terminal de forma predeterminada ... Si usa la consola de salida de PyCharm, habilite esto en todas sus configuraciones de ejecución:
Incluso le recomiendo que ingrese a
File
>New Projects Setup
>Run Configuration Templates
, seleccionarPython
y también habilitarlo allí, por lo que cualquiera nueva que cree ya tendrá este conjunto.
Además de eso, algunos terminales se informan como "no interactivos", como cuando se quedan sin una terminal real (Pycharm y Jupyter, por ejemplo), en shell tuberías ( cat file.txt | python program.py
), o en segundo plano procesos (no conectados a un TTY).
Cuando alive-progress
se encuentra en un terminal no interactivo, automáticamente deshabilita todo tipo de animaciones, imprimiendo solo el recibo final. Esto se hace para evitar estropear la salida de la tubería y spam a su archivo de registro con miles de actualizaciones alive-progress
.
Entonces, cuando sabes que es seguro, ¡puedes obligarlos a ver alive-progress
en todo su gloria! Aquí está el argumento force_tty
:
with alive_bar ( 1000 , force_tty = True ) as bar :
for i in range ( 1000 ):
time . sleep ( .01 )
bar ()
Los valores aceptados son:
force_tty=True
-> ¡Siempre habilita animaciones, y Auto Detects Jupyter Notebooks!force_tty=False
-> Siempre deshabilita animaciones, manteniendo solo el recibo finalforce_tty=None
(predeterminado) -> Detección automática, de acuerdo con el estado TTY del terminal También puede configurarlo en todo el sistema usando config_handler
, por lo que ya no necesita pasarlo manualmente.
Tenga en cuenta que la consola de Pycharm y los cuadernos Jupyter están fuertemente instrumentados y, por lo tanto, tienen mucho más sobrecarga, por lo que el resultado puede no ser tan fluido como era de esperar. Además de eso, los cuadernos de Jupyter no admiten códigos de escape ANSI, por lo que tuve que desarrollar algunas soluciones para emular funciones como "despejar la línea" y "despejar del cursor" ... para ver las animaciones de fluido y suave
alive_bar
como pretendía , siempre prefiera una terminal de pleno derecho.
alive-progress
no había tenido ninguna dependencia. Ahora tiene dos: uno es casi tiempo (otro proyecto interesante mío, si lo digo yo mismo), que se usa para rastrear el tiempo que lleva la compilación de Spinner y generar sus interpretaciones amigables para los humanos. El otro es Grapheme, para detectar las rupturas de clúster Grapheme (he abierto un problema allí preguntando sobre el futuro y la corrección, y el autor garantiza que tiene la intención de actualizar el proyecto en cada nueva versión de Unicode);alive-progress
no había tenido una sola clase de Python! Ahora tiene algunos pequeños por razones muy específicas (cambie de llamadas, adaptadores iteradores y algunos descriptores para los widgets alive_bar
).alive_bar
en sí es solo una función! Aunque, para ser justos, es "solo" una función en la que conecto dinámicamente varios cierres dentro de sí mismo (¿recuerda que las funciones de Python tienen un __dict__
como las clases?). alive_bar
nota los cambios en el tamaño del terminal, pero simplemente trunca la línea en consecuencia).contrib
de alguna manera, para permitir una forma simple de compartir hilanderos y barras geniales de los usuarios.skipped
stderr
y otros archivos en lugar de stdout
monitor
, elapsed
, stats
Completa aquí.
alive_it
, detectar usos anidados de Alive_Progress y lanzar un mensaje de error más claroalive_it
skipped
, la nueva configuración de configuración max_cols
para Jupyter, corrige el tamaño del terminal cuando usa STDERR, es compatible oficial de Python 3.11sys.stderr
y otros archivos en lugar de sys.stdout
, suavizó la estimación de la tasa, más consultas en los widgets actualmente en ejecución '' datos, sistema de ayuda en errores de configuraciónmonitor
personalizable, elapsed
y stats
widgets centrales, nuevos widgets monitor_end
, elapsed_end
y stats_end
, mejor soporte para Ctrl+C, que hace que alive_bar
se detenga prematuramenteclick.echo()
Soporte; rendimiento más rápido; detección más segura de columnas terminales; bar.current
actúa como una propiedad; Eliminar Python 3.6.check()
tanto en hilanderos como en barras; Barras y motores de hilanderos se renovan; Nuevos modos de animación en un lado y hilanderos secuenciales; nuevos hilanderos, bares y temas construidos; Showtime dinámico con temas, protección de desplazamiento y patrones de filtro; Registro mejorado para archivos; Varias opciones de configuración nuevas para personalizar la apariencia; nuevo adaptador iterador alive_it
; usa time.perf_counter()
Reloj de alta resolución; Requiere Python 3.6+ (y es oficialmente admite Python 3.9 y 3.10)bar.current()
; Las nuevas líneas se imprimen en Vanilla Python Repl; La barra se trunca a 80 caracteres en Windowsbar.text()
, para establecer mensajes situacionales en cualquier momento, sin incrementar la posición (Deprecates 'Text' Parameter en bar()
); Optimizaciones de rendimientobackground
en lugar de blank
, que acepta cadenas de tamaño arbitrariamente y permanece fijo en segundo plano, simulando una barra que lo revisa "show_spinners
y show_bars
, nuevas utilidad print_chars
, show_bars
obtienen algunas demostraciones avanzadas (¡inténtelo de nuevo!) alive_progress
siempre intentará mantenerse al día con Python, por lo que a partir de la versión 2.0, lanzaré el soporte para todas las versiones de Python que ingresan a EOL. Vea su horario aquí.
Pero no se preocupe si aún no puede migrar: las versiones alive_progress
son perenne, así que sigue usando el que funciona para ti y estás bien.
Recomiendo encarecidamente establecer paquetes más antiguos alive_progress
en un archivo de requisitos.txt con los siguientes formatos. Estos siempre obtendrán las últimas versiones de compilación antes de una versión determinada, por lo que, si alguna vez lanzaré correcciones de errores, también las obtendrá.
❯ pip install -U " alive_progress<2 "
❯ pip install -U " alive_progress<2.2 "
❯ pip install -U " alive_progress<3.2 "
Este software tiene licencia bajo la licencia MIT. Consulte el archivo LICENCIA en el directorio de distribución superior para obtener el texto completo de la licencia.
Mantener un proyecto de código abierto es difícil y que requiere mucho tiempo, y he puesto mucho ❤️ y esfuerzo en esto.
Si has apreciado mi trabajo, ¡puedes respaldarme con una donación! Gracias ?