Você já se perguntou onde estava seu longo processamento e quando ele terminaria? Você costuma apertar RETURN
várias vezes para ter certeza de que não travou ou que a conexão SSH não congelou? Você já pensou que seria incrível poder pausar algum processamento sem problemas, retornar ao prompt do Python para corrigir manualmente alguns itens e depois retomá-lo perfeitamente ? Eu fiz...
Comecei essa nova barra de progresso pensando em tudo isso, eis o alive-progress ! ?
Apresentando o mais novo conceito em barras de progresso para Python! alive-progress
está em uma classe própria, com uma série de recursos interessantes que o diferenciam. Aqui estão alguns destaques:
check()
super poderosa que ajuda você a criar suas próprias animações! Você pode ver como ficarão os frames gerados e os ciclos de animação, explodidos em sua tela e até mesmo vê-los vivos antes de instalar em alive-progress
! É a ferramenta mais legal do mundo! Liberte a sua criatividade! Este README está sempre evoluindo, então dê uma olhada mais abrangente de vez em quando... Você poderá encontrar ótimos novos detalhes em outras seções! ?
alive-progress
bar()
Após cerca de um ano de estabilidade tranquilizadora, o novo alive-progress
finalmente chegou!
Os principais recursos e melhorias são:
bar()
com 0
e até -N
para retroceder! Útil quando você não consegue progredir em uma iteração ou precisa reverter alguma coisa!E mais!
enrich_offset
personalizado para usar para mensagens impressas ou registradas, permitindo que você comece com on 1:
ou continue de onde parou nos cálculos anteriores! Uma atualização muito legal aqui! Além de aprimorar as coisas e melhorar o suporte do terminal, agora alive-progress
suporta a retomada dos cálculos!
Ao processar grandes conjuntos de dados ou coisas que levam muito tempo, você pode usar lotes ou armazenar em cache resultados parciais. Aí, caso ele pare e seja reiniciado, você acaba pulando todos aqueles itens já feitos muito rapidamente, o que faz o alive_bar
pensar que você está processando milhares de itens por segundo, o que por sua vez estraga completamente o ETA... Mas não mais ! Basta dizer bar()
que você pulou itens...?
Você pode usá-lo de duas maneiras:
1. Se você sabe onde parou:
with alive_bar ( 120000 ) as bar :
bar ( 60000 , skipped = True )
for i in range ( 60000 , 120000 ):
# process item
bar ()
Sim, basta ligar bar(N, skipped=True)
uma vez, com o número de itens.
2. Se você não sabe ou os itens estão espalhados:
with alive_bar ( 120000 ) as bar :
for i in range ( 120000 ):
if done ( i ):
bar ( skipped = True )
continue
# process item
bar ()
Sim, é tão simples quanto isso! Basta chamar bar(skipped=True)
quando um item já estiver concluído, ou bar()
como de costume, caso contrário. Você também pode compartilhar uma única chamada bar(skipped=?)
no final, com um bool informando se você ignorou aquele item ou não. Legal, hein?
Também nesta versão:
max_cols
, o número de colunas a serem usadas se não for possível buscá-lo, como em jupyter e outras plataformas que não suportam tamanhoSim, finalmente consegui lançar esta versão! Estas são as novidades:
B
, bytes
ou até °C
!sys.stderr
e outros arquivos em vez de sys.stdout
!Correções altamente esperadas:
TypeError: unhashable type: 'types.SimpleNamespace'
.RotatingFileHandler
s! Sim, buscar suporte está aqui.E por último, mas não menos importante, um layout mais sofisticado para você aproveitar seu progresso!
Agora, alive_bar
suporta o modo de texto Dual Line !
Se você sempre quis incluir mensagens situacionais mais longas na barra, provavelmente se sentiu espremido em uma linha. Você tinha que encolher a barra lindamente animada ou, pior ainda, remover widgets (!) para poder ver o que precisava...
Não mais!! Agora você pode fazer a barra Dual Line e colocar o texto abaixo dela!
Sim, há uma mensagem abaixo de toda a barra e quaisquer outras mensagens de impressão/registro rolam acima dela!
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 ()
Saída:
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...
Há também um novo parâmetro de função finalize
em alive_it
que permite definir o título e/ou texto do recibo final e suporte aprimorado de registro que detecta registradores personalizados.
Isto é tudo uma questão de personalização; os widgets principais agora podem ser alterados:
monitor
, elapsed
e stats
para que tenham a aparência que você quiser!É incrível que essas strings suportem todos os recursos de formato Python, então você pode, por exemplo,
{percent:.1%}
.
Eles podem ser ainda mais personalizados no recebimento final !
monitor_end
, elapsed_end
e stats_end
, com formatos dinâmicos herdados dos padrões!Se você ocultou alguns widgets antes, apenas para que não aparecessem no recibo, agora você pode vê-los em toda a sua glória e ocultar apenas os recibos! Ou o contrário?
Outra adição, agora alive-progress
renderiza lindamente seu recebimento final sempre que for interrompido, mesmo se você pressionar CTRL + C prematuramente! Não sei por que não pensei nisso antes...
Download |██████████████████︎ | (!) 45/100 [45%] in 4.8s (9.43/s)
E finalmente, você pode optar por desabilitar CTRL+C! O padrão é o mais seguro ctrl_c=True
, o que faz com que CTRL-C funcione normalmente.
Desative-o ctrl_c=False
, para tornar seu alive_bar
interativo muito mais fácil de usar (não há rastreamentos de pilha se você interrompê-lo) e/ou se estiver no nível superior do seu programa!
Cuidado: se estiver, por exemplo, dentro de um loop for, ele continuará na próxima iteração, que pode ou não ser o que você deseja...
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 ()
Saída:
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)
...
Alguns novos recursos importantes, frequentemente solicitados, finalmente chegaram!
click.echo()
SIM! Agora, alive-progress
tem suporte para Jupyter Notebooks e também inclui um estado Desativado ! Ambos foram muito procurados e finalmente chegaram!
E melhor, implementei um mecanismo de detecção automática para notebooks jupyter, para que funcione imediatamente, sem nenhuma alteração no seu código!!
Veja você mesmo:
Parece funcionar muito bem, mas neste momento deve ser considerado experimental .
Houve casos em que algumas falhas visuais apareceram, como duas atualizaçõesalive_bar
sendo concatenadas juntas em vez de uma sobre a outra... E é algo que acho que não posso contornar: parece que Jupyter às vezes atualiza a tela em momentos estranhos, o que faz com que ele perca alguns dados. Por favor, deixe-me saber sobre os problemas se surgir algo mais engraçado.
Este é um grande avanço no alive-progress
!
Levei 1 ano para desenvolvê-lo e estou muito orgulhoso do que conquistei o/
.check()
poderosas e refinadas que compilam e renderizam lindamente todos os quadros de todos os ciclos de animação de spinners e barras! eles podem até incluir dados completos de quadros, pontos de código internos e até mesmo suas animações! ?alive-progress
!alive_it
, que aceita um iterável e chama bar()
para você!Como esta é uma alteração importante de versão, a compatibilidade direta com versões anteriores não é garantida. Se algo não funcionar a princípio, basta verificar as novas importações e assinaturas de funções e você estará pronto. Todos os recursos anteriores ainda devem funcionar aqui! ?
alive-progress
Basta instalar com pip:
❯ pip install alive-progress
Se você está se perguntando quais estilos estão integrados, é showtime
! ;)
from alive_progress . styles import showtime
showtime ()
Obs: Desconsidere o caminho no gif animado abaixo, o correto está acima. Esses gifs longos consomem muito tempo para serem gerados, então não posso fazer outro a cada alteração. Obrigado pela sua compreensão.
Fiz esses estilos só para testar todas as fábricas de animação que criei, mas acho que algumas delas ficaram muito, muito legais! Use-os à vontade e misture-os como quiser!
Você deseja ver barras alive-progress
reais funcionando gloriosamente em seu sistema antes de experimentá-las você mesmo?
❯ python -m alive_progress.tools.demo
Legal, né?? Agora insira um REPL ipython
e tente isto:
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 ()
Você verá algo assim, com animações legais durante todo o processo?:
|████████████████████████████████████████| 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)
Legal, hein? Adorei? Eu sabia que você faria isso, obrigado?
Para realmente usá-lo, basta agrupar seu loop normal em um gerenciador de contexto 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
E está vivo! ?
Então, resumindo: recupere os itens como sempre, entre no gerenciador de contexto alive_bar
com o número de itens e, em seguida, itere/processe esses itens, chamando bar()
no final! É tão simples! :)
items
podem ser iteráveis, como, por exemplo, um conjunto de consultas;alive_bar
é o total esperado, como qs.count()
para querysets, len(items)
para iteráveis com comprimento, ou mesmo um número estático;bar()
é o que faz a barra avançar — você normalmente a chama a cada iteração, logo após terminar um item;bar()
demais (ou muito pouco no final), a barra renderizará graficamente esse desvio do total
esperado, tornando muito fácil perceber overflows e underflows;bar.current
.Você pode ser criativo! Como a barra só avança quando você chama
bar()
, ela é independente do loop ! Assim você pode usá-lo para monitorar o que quiser, como transações pendentes, itens quebrados, etc., ou até mesmo chamá-lo mais de uma vez na mesma iteração! Assim, ao final, você saberá quantos desses eventos “especiais” ocorreram, incluindo sua porcentagem em relação ao total!
Enquanto estiver dentro de um contexto alive_bar
, você pode exibir facilmente mensagens totalmente integradas à barra de progresso atual que está sendo exibida! Não vai quebrar de forma alguma e vai até enriquecer a sua mensagem!
bar.text('message')
e bar.text = 'message'
definem uma mensagem situacional dentro da barra, onde você pode exibir algo sobre o item atual ou a fase em que o processamento está;bar.title('Title')
e bar.title = 'Title'
- misture com title_length
para evitar que a barra mude seu comprimento;print()
usual do Python, onde alive_bar
limpa bem a linha, imprime sua mensagem ao lado da posição atual da barra no momento e continua a barra logo abaixo dela;logging
padrão do Python, incluindo saídas de arquivo, também é enriquecida exatamente como a anterior;click.echo()
para imprimir texto estilizado.Incrível, certo? E tudo isso funciona da mesma forma em um terminal ou em um notebook Jupyter!
Agora você tem uma maneira mais rápida de monitorar qualquer coisa! Aqui, os itens são rastreados automaticamente para você!
Veja o adaptador do iterador alive_it
=> alive_bar
!
Basta embrulhar seus itens com ele e passá-los como de costume!
A barra simplesmente funcionará; é tão simples!
from alive_progress import alive_it
for item in alive_it ( items ): # <<-- wrapped items
print ( item ) # process each item
Quão legal é isso?! ?
Todos os parâmetros alive_bar
se aplicam, exceto total
, que é mais inteligente (se não for fornecido, será inferido automaticamente a partir de seus dados usando len
ou length_hint
) e manual
que não faz sentido aqui.
Observe que não há nenhuma alça bar
ali. Mas e se você quiser, por exemplo, definir mensagens de texto ou recuperar o progresso atual?
Você pode interagir com o alive_bar
interno apenas atribuindo alive_it
a uma variável 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!
Observe que este é um bar
ligeiramente especial, que não suporta bar()
, já que o adaptador iterador rastreia itens automaticamente para você. Além disso, suporta finalize
, que permite definir o título e/ou texto do recibo final:
alive_it ( items , finalize = lambda bar : bar . text ( 'Success!' ))
...
Resumindo:
- o uso total é sempre
with alive_bar() as bar
, onde você itera e chamabar()
sempre que quiser;- o uso rápido do adaptador é
for item in alive_it(items)
, onde os itens são rastreados automaticamente;- o uso completo do adaptador é
bar = alive_it(items)
, onde além dos itens serem rastreados automaticamente, você obtém umabar
iterável especial capaz de personalizar oalive_progress
interno da maneira que desejar.
Os modos padrão são auto e desconhecido , que utilizam internamente um contador para acompanhar o progresso. Eles contam o número de itens processados e usam isso para atualizar a barra de progresso de acordo.
O argumento total
é opcional. Se você fornecer, a barra entrará no modo automático . Neste modo, o progresso da operação é rastreado automaticamente e todos os widgets que alive-progress
tem a oferecer estão disponíveis: barra precisa, girador, porcentagem, contador, rendimento e ETA.
Se você não fornecer total
, a barra entra em modo desconhecido . Neste modo, o progresso é indeterminável e, portanto, o ETA, portanto toda a barra de progresso é continuamente animada. Os widgets disponíveis são: barra animada, girador, contador e taxa de transferência.
O cool spinner funciona de forma totalmente independente da barra animada, ambos executando suas próprias animações simultaneamente, criando um show único em seu terminal! ?
Por último, mas não menos importante, o modo automático tem uma capacidade única: marcar itens como ignorados, tornando o rendimento e o ETA muito mais precisos! Mais sobre isso mais tarde.
O modo manual , ativado manualmente pelo argumento manual=True
, usa internamente uma porcentagem para acompanhar o progresso. Ele permite que você obtenha controle total da posição da barra. Geralmente é usado para monitorar processos que fornecem apenas uma porcentagem de conclusão ou para gerar alguns efeitos especiais aleatórios.
Você pode usá-lo diretamente com alive_bar
ou via config_handler
, e permite enviar porcentagens para o manipulador bar()
! Por exemplo, para configurá-lo para 15% de conclusão, basta chamar bar(0.15)
— que é 15/100.
Você também pode fornecer total
aqui. Se você fizer isso, alive-progress
inferirá automaticamente um contador interno e, assim, poderá oferecer a você todos os mesmos widgets disponíveis no modo automático!
Se você não fornecer total
, obterá pelo menos versões aproximadas dos widgets de taxa de transferência e ETA, calculados como "%/s" (porcentagem por segundo) e até 100%, respectivamente. Nenhum deles é muito preciso, mas são melhores que nada.
Quando total
é fornecido, tudo fica bem:
modo | contador | percentagem | rendimento | HEC | excesso/subfluxo |
---|---|---|---|---|---|
auto | ✅ (marcação do usuário) | ✅ (inferido) | ✅ | ✅ | ✅ |
manual | ✅ (inferido) | ✅ (conjunto do usuário) | ✅ | ✅ | ✅ |
Quando não é, alguns compromissos devem ser feitos:
modo | contador | percentagem | rendimento | HEC | excesso/subfluxo |
---|---|---|---|---|---|
desconhecido | ✅ (marcação do usuário) | ✅ | |||
manual | ✅ (conjunto do usuário) | ✅ |
Mas na verdade é simples de entender: você não precisa pensar em qual modo deve usar!
total
se tiver, e usar manual
se precisar!É isso! Simplesmente funcionará o melhor que puder! ? o/
bar()
Os manipuladores bar()
suportam semântica relativa ou absoluta, dependendo do modo:
bar()
para incrementar o contador em um ou enviar qualquer outro incremento como bar(200)
para incrementar em 200 de uma vez;eles ainda suportam
bar(0)
ebar(-5)
para manter ou diminuir, se necessário!
bar(0.35)
para fazer a barra saltar instantaneamente para 35% de progresso.Ambos os modos permitem que você seja criativo! Como você pode fazer a barra ir instantaneamente para qualquer posição desejada, você pode:
- fazê-lo retroceder — por exemplo, para exibir graficamente o tempo limite de algo;
- criar efeitos especiais - por exemplo, para imitar algum tipo de medidor analógico em tempo real.
Você pode chamar bar()
quantas vezes quiser! A taxa de atualização do terminal sempre será calculada de forma assíncrona de acordo com o rendimento e o progresso atuais, portanto, você não correrá o risco de enviar spam ao terminal com mais atualizações do que o necessário.
De qualquer forma, para recuperar o contador/porcentagem atual, basta chamar: bar.current
:
Finalmente, o manipulador bar()
aproveita a habilidade única do modo automático : basta chamar bar(skipped=True)
ou bar(N, skipped=True)
para usá-lo. Quando skipped
é definido como = True
, os itens associados são excluídos dos cálculos de rendimento, evitando que os itens ignorados afetem incorretamente o ETA.
Manter um projeto de código aberto é difícil e demorado, e eu coloquei muito ❤️ e esforço nisso.
Se você gostou do meu trabalho, pode me apoiar com uma doação! Obrigado ?
A exposição showtime
tem um argumento opcional para escolher qual show apresentar, Show.SPINNERS
(padrão), Show.BARS
ou Show.THEMES
, dê uma olhada neles! ;)
from alive_progress . styles import showtime , Show
showtime ( Show . BARS )
showtime ( Show . THEMES )
Obs: Desconsidere o caminho no gif animado abaixo, o correto está acima. Esses gifs longos consomem muito tempo para serem gerados, então não posso fazer outro a cada alteração. Obrigado pela sua compreensão.
E o tema (? novo no 2.0):
A exposição showtime
também aceita algumas opções de personalização:
Por exemplo, para obter um show marinho, você pode showtime(pattern='boat|fish|crab')
:
Você também pode acessar esses programas com os atalhos
show_bars()
,show_spinners()
eshow_themes()
!
Há também um pequeno utilitário chamado
print_chars()
, para ajudar a encontrar aquele caractere legal para colocar em seus spinners e barras personalizados ou para determinar se o seu terminal suporta caracteres Unicode.
Existem diversas opções para personalizar tanto a aparência quanto o comportamento!
Todos eles podem ser definidos diretamente no alive_bar
ou globalmente no config_handler
!
Estas são as opções - valores padrão entre colchetes:
title
: um título de barra opcional e sempre visívellength
: [ 40
] o número de colunas para renderizar a barra de progresso animadamax_cols
: [ 80
] o máximo de colunas a serem usadas se não for possível buscá-las, como em jupyterspinner
: o estilo do spinner a ser renderizado próximo à barrabar
: o estilo da barra a ser renderizado em modos conhecidosunknown
: o estilo da barra a ser renderizado no modo desconhecidotheme
: [ 'smooth'
] um conjunto de spinner, barra e desconhecido correspondentesforce_tty
: [ None
] força as animações a serem ativadas, desativadas ou de acordo com o tty (mais detalhes aqui)file
: [ sys.stdout
] o objeto de arquivo a ser usado: sys.stdout
, sys.stderr
ou um TextIOWrapper
semelhantedisable
: [ False
] se Verdadeiro, desativa completamente todas as saídas, não instala ganchosmanual
: [ False
] definido para controlar manualmente a posição da barraenrich_print
: [ True
] enriquece print() e registra mensagens com a posição da barraenrich_offset
: [ 0
] o deslocamento a ser aplicado a enriquecer_printreceipt
: [ True
] imprime o belo recibo final, desativa se for falsoreceipt_text
: [ False
] definido para repetir a última mensagem de texto no recibo finalmonitor
(bool|str): [ True
] configura o widget do monitor 152/200 [76%]
{count}
, {total}
e {percent}
para personalizá-laelapsed
(bool|str): [ True
] configura o widget de tempo decorrido in 12s
{elapsed}
para personalizá-lastats
(bool|str): [ True
] configura o widget de estatísticas (123.4/s, eta: 12s)
{rate}
e {eta}
para personalizá-lamonitor_end
(bool|str): [ True
] configura o widget do monitor no recebimento finalmonitor
elapsed_end
(bool|str): [ True
] configura o widget de tempo decorrido no recebimento finalelapsed
stats_end
(bool|str): [ True
] configura o widget de estatísticas no recebimento final{rate}
para personalizá-lo (sem relação com estatísticas)title_length
: [ 0
] corrige o comprimento dos títulos ou 0 para ilimitadospinner_length
: [ 0
] força o comprimento do spinner, ou 0
para o comprimento naturalrefresh_secs
: [ 0
] força o período de atualização para isso, 0
é o feedback visual reativoctrl_c
: [ True
] se False, desativa CTRL+C (captura)dual_line
: [ False
] se True, coloca o texto abaixo da barraunit
: qualquer texto que rotule suas entidadesscale
: a escala a ser aplicada às unidades: None
, SI
, IEC
ou SI2
False
ou ''
-> None
, True
-> SI
, 10
ou '10'
-> SI
, 2
ou '2'
-> IEC
precision
: [ 1
] quantos decimais são exibidos durante o dimensionamento E há também um que só pode ser definido localmente no contexto alive_bar
:
calibrate
: rendimento teórico máximo para calibrar a velocidade da animação (mais detalhes aqui) Para defini-los localmente, basta enviá-los como argumentos de palavras-chave para alive_bar
:
with alive_bar ( total , title = 'Processing' , length = 20 , bar = 'halloween' ) as bar :
...
Para usá-los globalmente, envie-os para config_handler
e qualquer alive_bar
criado depois disso incluirá essas opções! E você pode misturá-las e combiná-las, as opções locais sempre têm precedência sobre as globais:
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'.
...
Sim, você pode montar seus próprios spinners! E é fácil!
Eu criei uma infinidade de efeitos especiais, então você pode misturá-los e combiná-los da maneira que quiser! Existem quadros, rolagem, salto, sequenciais, paralelos e giradores atrasados! Seja criativo! ?
As animações dos spinners são projetadas por expressões geradoras muito avançadas, profundamente dentro de várias camadas de metafábricas, fábricas e geradores?!
alive_bar
e config_handler
;Esses geradores são capazes de vários ciclos de animação diferentes de acordo com o comportamento do botão giratório, por exemplo, um botão giratório saltitante pode executar um ciclo para trazer suavemente um objeto para a cena e, em seguida, reposicioná-lo repetidamente até o outro lado e, em seguida, fazê-lo desaparecer suavemente da cena = > e tudo isso é apenas um ciclo! Depois, pode ser seguido por outro ciclo para fazer tudo de novo, mas ao contrário! E os spinners saltitantes também aceitam padrões diferentes e alternados tanto na direção direita quanto na esquerda, o que os faz gerar o produto cartesiano de todas as combinações, possivelmente produzindo dezenas de ciclos diferentes até começarem a repeti-los!! ?
E tem mais, acho que uma das conquistas mais impressionantes que consegui nesse sistema de animação (além do próprio compilador giratório)... Eles só rendem mais quadros de animação até que o ciclo atual não se esgote, então eles param sozinhos ! Sim, o próximo ciclo ainda não começa! Esse comportamento cria quebras naturais exatamente nos pontos corretos, onde as animações não são interrompidas, para que eu possa vincular suavemente com qualquer outra animação que eu quiser!!
Isso tem todos os tipos de implicações interessantes: os ciclos podem ter diferentes contagens de quadros, diferentes comprimentos de tela, não precisam ser sincronizados, podem criar sequências longas e diferentes por si próprios, podem cooperar para reproduzir ciclos em sequência ou ao lado, e eu pode surpreendê-lo exibindo diversas animações totalmente distintas ao mesmo tempo, sem qualquer interferência!
É quase como se eles estivessem... vivos !! ?
==> Sim, foi daí que surgiu o nome deste projeto!
Agora, esses geradores de ciclos e quadros são totalmente consumidos antecipadamente pelo Spinner Compiler ! Este é um novo processador muito legal que fiz dentro do esforço da Cell Architecture , para fazer todas essas animações funcionarem mesmo na presença de caracteres largos ou clusters complexos de grafemas! Foi muito difícil fazer com que esses clusters entrassem e saíssem gradualmente dos quadros, sem problemas, evitando que quebrassem a codificação Unicode e, principalmente, mantendo seus comprimentos originais em todos os quadros! Sim, vários caracteres em sequência podem representar outro símbolo completamente diferente, por isso nunca podem ser divididos! Eles têm que entrar e sair do quadro sempre juntos, todos de uma vez, ou o grafema não vai aparecer (um Emoji por exemplo)!! Entre no compilador Spinner ......
Isso tornou possíveis coisas incríveis!! Como este compilador gera todos os dados do quadro giratório de antemão:
Então, posso simplesmente coletar todas as animações prontas para reproduzir e pronto, sem nenhuma sobrecarga de tempo de execução !! ?
Além disso, com os dados completos do quadro compilados e persistidos, eu poderia criar vários comandos para refatorar esses dados, como alterar formas, substituir caracteres, adicionar pausas visuais (repetições de quadros), gerar efeitos de salto sob demanda sobre qualquer conteúdo e até mesmo transpor ciclos com molduras!!
Mas como você pode ver esses efeitos? O efeito que você criou parece bom? Ou não está funcionando como você pensava? SIM, agora você pode ver todos os ciclos e frames gerados analiticamente, em uma representação muito bonita!!
Adorei o que consegui aqui?, é provavelmente A ferramenta mais linda que já criei... Eis a ferramenta check
!!
É incrível se eu disser isso sozinho, não é? E um software muito complexo da qual me orgulho, dê uma olhada em seu código, se quiser.
E a ferramenta check
é muito mais poderosa! Por exemplo, você pode ver os pontos de código dos quadros !!! E talvez tenha um vislumbre de por que esta versão era tão, muito difícil e complexa de fazer ...
Em vermelho, você vê os agrupamentos de grafema, que ocupam uma ou duas "posições lógicas", independentemente de seus tamanhos reais ... essas são as "células" da nova arquitetura de células ...
Veja como uma bandeira emoji é incrível:
A bandeira parece se mover tão bem porque usa "meio caracteres"! Como é um amplo char, alive-progress
sabe que será renderizado com "dois chars visíveis", e as animações consideram isso, mas comporá com espaços, que ocupam apenas um. Quando se usa fundos mistos, a situação é muito mais complexa ...
Os tipos de fábricas que criei são:
frames
: desenha qualquer sequência de caracteres à vontade, que será tocada quadro a quadro em sequência;scrolling
: gera um fluxo suave de um lado para o outro, escondido atrás ou envolvendo bordas invisíveis - permite o uso de assuntos um de cada vez, gerando vários ciclos de caracteres distintos;bouncing
: semelhante ao scrolling
, mas faz as animações se recuperarem até o início, escondendo -se atrás ou saltando imediatamente sobre fronteiras invisíveis;sequential
obtenha um punhado de fábricas e jogue uma após a outra sequencialmente! permite misturá -los ou não;alongside
obter um punhado de fábricas e tocá -las ao lado de simultaneamente, por que escolher quando você pode ter todas elas?! permite escolher o pivô da animação;delayed
: pegue qualquer outra fábrica e copie -a várias vezes, pulando cada vez mais alguns quadros em cada um! Efeitos muito legais são feitos aqui!Para mais detalhes, consulte os doces, que são muito completos.
A personalização de barras não está nem perto daquele envolvido. Digamos que eles sejam objetos passivos "imediatos". Eles não suportam animações, ou seja, eles sempre gerarão a mesma versão, dados os mesmos parâmetros. Lembre -se de que os spinners são geradores infinitos, capazes de gerar sequências longas e complexas.
Bem, as barras também têm uma meta fábrica, usam fechamentos para armazenar os parâmetros de estilo e receber parâmetros operacionais adicionais, mas a fábrica real não pode gerar nenhum conteúdo por si só. Ele ainda precisa de um parâmetro extra, um número de ponto flutuante entre 0 e 1, que é a porcentagem para se renderizar.
alive_bar
calcula essa porcentagem automaticamente com base no contador e no total, mas você pode enviá -lo quando no modomanual
!
As barras também não têm um compilador de barra, mas fornecem a ferramenta de verificação !! ?
Você pode até misturar e combinar chars largos e chars normais, como nos spinners! (E tudo se mantém perfeitamente alinhado?)
Use as ferramentas de verificação para o conteúdo do seu coração !! Eles têm ainda mais guloseimas aguardando você, até as animações em tempo real!
Crie as animações mais loucas e mais legais que você pode e envie -as para mim!
Estou pensando em criar algum tipo de pacotecontrib
, com spinners e bares contribuídos pelo usuário!
Uau, se você leu tudo até aqui, agora deve ter um bom conhecimento sobre como usar alive-progress
! ?
Mas prepare -se porque há ainda mais coisas emocionantes que estão por vir!
Manter um projeto de código aberto é difícil e demorado, e eu coloquei muito e esforço nisso.
Se você apreciou meu trabalho, pode me apoiar com uma doação! Obrigado ?
Oh, você quer fazer uma pausa completamente, eu ouço? Este é um conceito de romance incrível, não encontrado em nenhum lugar Afaik.
Com isso, você pode agir em alguns itens manualmente , à vontade, bem no meio de um processamento em andamento !!
Sim, você pode retornar ao prompt e consertar, mudar, enviar coisas, e o bar apenas "lembrará" onde estava ...
Suponha que você precise reconciliar transações de pagamento (esteve lá, feito isso). Você precisa iterar mais de milhares deles, detectar de alguma forma os defeituosos e consertá -los. Essa correção não é simples nem determinística, você precisa estudar cada um para entender o que fazer. Eles podem estar perdendo um destinatário ou a quantidade errada, ou não serem sincronizados com o servidor, etc., é difícil imaginar todas as possibilidades.
Normalmente, você teria que deixar o processo de detecção funcionar até a conclusão, anexando a uma lista cada inconsistência que encontra e esperando, potencialmente muito tempo, até que você possa finalmente começar a consertá -los ... você pode obviamente atenuar isso processando em pedaços , ou imprimi -los e agindo através de outra concha, etc., mas esses têm suas próprias deficiências ...?
Agora, há uma maneira melhor! Basta pausar o processo de detecção real por um tempo! Então você só tem que esperar até que a próxima falha seja encontrada e atue quase em tempo real!
Para usar o mecanismo de pausa, você só precisa escrever uma função, para que o código possa yield
os itens com os quais você deseja interagir. Você provavelmente já usa um no seu código, mas no shell ipython
ou em outro repl você provavelmente não. Então, envolva seu código de depuração em uma função e entre em um 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 ()
É isso! É tão simples! o//
Agora execute gen = reconcile_transactions()
para instanciar o gerador e sempre que quiser a próxima transação com defeito, basta ligar next(gen, None)
! Eu amo isso...
A barra alive-progress
começará e será executada como de costume, mas assim que qualquer inconsistência for encontrada, a barra se pausará, desligando o segmento de atualização e lembrando seu estado exato e produz a transação para você diretamente no prompt! É quase 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>
Você pode inspecionar a transação com o atalho usual _
de ipython
(ou apenas atribui -lo diretamente com t = next(gen, None)
), e está pronto para corrigi -lo!
Quando terminar, basta reativar a barra com a mesma next
chamada de antes !! O bar reaparece, liga tudo de volta e continua como se nunca tivesse parado !! Ok, é mágico?
In [21]: next(gen, None)
|█████████████████████ | ▁▃▅ 106/200 [52%] in 5s (18.8/s, eta: 4s)
Enxágue e repita até o recibo final aparecer, e não haverá mais transações com defeito. ?
Então, você precisa monitorar uma operação fixa, sem loops, certo?
Vai funcionar com certeza! Aqui está um exemplo ingênuo (faremos melhor em um 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`
É ingênuo porque assume que todas as etapas levam a mesma quantidade de tempo, mas, na verdade, cada um pode levar um tempo muito diferente para ser concluído. Pense read_file
e tokenize
podem ser extremamente rápidos, o que torna a porcentagem disparar para 50%e, em seguida, parar por um longo tempo na etapa process
... você entendeu o ponto, ele pode arruinar a experiência do usuário e criar um ETA muito enganoso.
Para melhorar isso, você precisa distribuir as porcentagens das etapas de acordo! Desde que você disse alive_bar
, havia quatro etapas, quando o primeiro foi concluído, ele entendeu 1/4 ou 25% de todo o processamento foi completo ... portanto, você precisa medir quanto tempo seus passos realmente tomam e usam o modo manual para Aumente a porcentagem da barra na quantidade certa em cada etapa!
Você pode usar meu outro projeto de código aberto sobre o tempo para medir facilmente essas durações! Apenas tente simular com algumas entradas representativas, para obter melhores 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 } ' )
Aí está! Agora você conhece os horários relativos de todas as etapas e pode usá -las para melhorar seu código original! Basta obter os horários cumulativos e colocá -los dentro de um modo manual alive_bar
!
Por exemplo, se os horários encontrados fossem 10%, 30%, 20%e 40%, você usaria 0,1, 0,4, 0,6 e 1,0 (o último sempre deve 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
É isso! A experiência do usuário e o ETA devem ser bastante aprimoradas agora.
Sim, você pode calibrar a velocidade do girador!
As barras alive-progress
têm feedback visual legal da taxa de transferência atual, para que você possa realmente ver a rapidez com que seu processamento é, pois o spinner corre mais rápido ou mais lento com ele.
Para que isso aconteça, eu reuni e implementei algumas curvas de FPS para descobrir empiricamente qual deles deu a melhor sensação de velocidade:
(versão interativa [aqui] (https://www.desmos.com/calculator/ema05elsux)))
O gráfico mostra as curvas logarítmicas (vermelhas), parabólicas (azuis) e lineares (verdes), essas são as que eu comecei. Não foi uma tarefa fácil, fiz dezenas de testes e nunca encontrei uma que realmente inspirasse a sensação de velocidade que estava procurando. O melhor parecia ser o logarítmico, mas reagiu mal com pequenos números. Eu sei que poderia fazê -lo funcionar com algumas reviravoltas para esses pequenos números, então experimentei muito e ajustei a curva logarítmica (pontilhada de laranja) até que finalmente encontrei o comportamento que esperava! É o que parecia fornecer as melhores mudanças de velocidade percebidas em todo o espectro de alguns a bilhões ... essa é a curva com a qual me deparei, e é o usado em todos os modos e condições. No futuro e se alguém achar útil, essa curva poderá ser configurável.
Bem, a calibração alive-progress
padrão é de 1.000.000 de modos limitados, ou seja, são necessárias 1 milhão de iterações por segundo para que o bar se refresque a 60 quadros por segundo. No modo manual ilimitado, é 1,0 (100%). Ambos permitem uma vasta faixa operacional e geralmente funcionam muito bem.
Por exemplo, dê uma olhada no efeito que essas calibrações muito diferentes têm, executando o mesmo código na mesma velocidade! Observe a sensação que o girador passa para o usuário, esse processamento está indo devagar ou indo rápido? E lembre -se de que não é apenas o spinner refrescante, mas toda a linha, completa com a versão do bar e todos os widgets, então tudo fica mais suave ou lento:
Então, se o seu processamento dificilmente atingir 20 itens por segundo, e você pensa que
alive-progress
está tornando lento, você pode aumentar essa sensação de velocidade calibrando-o para digitar40
, e estará correndo Waaaay mais rápido ... é Melhor sempre deixar um espaço para calibrá -lo e calibrá -lo entre 50% e 100% a mais e depois ajustá -lo a partir daí para encontrar o que você mais gosta! :)
Essas animações surpreendentes alive-progress
se recusam a exibir?
Pycharm é incrível, eu adoro! Mas nunca vou entender por que eles desabilitaram imitando um terminal por padrão ... se você usar o console de saída da Pycharm, ative isso em todas as suas configurações de execução:
Eu até recomendo que você entre no
File
>New Projects Setup
>Run Configuration Templates
, selecionePython
e também habilitá -lo lá; portanto, todos os novos que você criar já terão esse conjunto.
Além disso, alguns terminais se reportam como "não interativos", como ao ficar sem um terminal real (Pycharm e Jupyter, por exemplo), em pipelines de shell ( cat file.txt | python program.py
) ou em segundo plano processos (não conectados a um TTY).
Quando alive-progress
se encontra em um terminal não interativo, ele desativa automaticamente todos os tipos de animações, imprimindo apenas o recibo final. Isso é feito para evitar bagunçar a saída do pipeline e enviar spam seu arquivo de log com milhares de atualizações alive-progress
.
Então, quando você sabe que é seguro, pode forçá-los a ver alive-progress
em toda a sua glória! Aqui está o argumento force_tty
:
with alive_bar ( 1000 , force_tty = True ) as bar :
for i in range ( 1000 ):
time . sleep ( .01 )
bar ()
Os valores aceitos são:
force_tty=True
-> sempre permite animações e detecta automaticamente os notebooks Jupyter!force_tty=False
-> sempre desativa as animações, mantendo apenas o recibo finalforce_tty=None
(padrão) -> Detecção automática, de acordo com o estado tty do terminal Você também pode configurá-lo em todo o sistema usando config_handler
, para não precisar mais passar manualmente.
Observe que os notebooks do console e Jupyter de Pycharm são fortemente instrumentados e, portanto, têm muito mais sobrecarga; portanto, o resultado pode não ser tão fluido quanto seria de esperar. Além disso, os notebooks Jupyter não suportam códigos de escape da ANSI, então tive que desenvolver algumas soluções alternativas para imitar funções como "Limpar a linha" e "Clear From Cursor" ... para ver as animações fluidas e suaves
alive_bar
como eu pretendia , sempre prefira um terminal de pleno direito.
alive-progress
não tinha nenhuma dependência. Agora ele tem dois: um é sobre o tempo (outro projeto interessante meu, se eu disser isso mesmo), que é usado para rastrear o tempo que leva para a compilação Spinner e para gerar suas interpretações amigas do ser humano. O outro é o Grapheme, para detectar quebras de cluster de grafema (abri um problema perguntando sobre o futuro e a correção dele, e o autor garante que ele pretende atualizar o projeto em todas as novas versões Unicode);alive-progress
não tinha uma única aula de Python! Agora ele tem alguns minúsculos por razões muito específicas (altere os chamáveis, adaptadores de iterador e alguns descritores para os widgets alive_bar
).alive_bar
é apenas uma função! Embora, para ser justo, seja "apenas" uma função em que eu conectei dinamicamente vários fechamentos de dentro de si (lembre -se de que as funções do Python têm um __dict__
assim como as aulas?). alive_bar
percebe as mudanças no tamanho do terminal, mas apenas truques a linha de acordo).contrib
de alguma forma, para permitir uma maneira simples de compartilhar spinners e barras legais dos usuários.skipped
stderr
e outros arquivos em vez de stdout
monitor
, elapsed
, stats
Completo aqui.
alive_it
, detectar usos aninhados de alive_progress e lançar uma mensagem de erro mais claraalive_it
skipped
, nova configuração de configuração max_cols
para Jupyter, fixando o tamanho do terminal ao usar o Stderr, suporta oficialmente o Python 3.11sys.stderr
e outros arquivos em vez de sys.stdout
, suavizou a estimativa da taxa, mais perguntas nos widgets atualmente em execução ' dados, sistema de ajuda em erros de configuraçãomonitor
Customizável, elapsed
e stats
, New monitor_end
, elapsed_end
e stats_end
Core Widgets, Melhor suporte para Ctrl+C, o que torna alive_bar
Stop prematuramenteclick.echo()
suporte; desempenho mais rápido; detecção mais segura de colunas terminais; bar.current
age como uma propriedade; Remova o Python 3.6.check()
ferramentas em spinners e barras; Barras e motores de spinners renovar; novos modos de animação ao lado e spinners seqüenciais; novos spinners, bares e temas embutidos; Showtime dinâmico com temas, proteção de rolagem e padrões de filtro; logotging aprimorado para arquivos; várias novas opções de configuração para personalizar a aparência; novo adaptador iterador alive_it
; usa time.perf_counter()
relógio de alta resolução; Requer Python 3.6+ (e suporta oficialmente o Python 3.9 e 3.10)bar.current()
; As novas linhas são impressas em baunilha python repl; O bar é truncado para 80 chars nas janelasbar.text()
, para definir mensagens situacionais a qualquer momento, sem incrementar a posição (deprecia o parâmetro 'texto' em bar()
); Otimizações de desempenhobackground
em vez de blank
, que aceita cordas de tamanho arbitrariamente e permanece fixo em segundo plano, simulando uma barra "sobre isso"show_spinners
e show_bars
, New Utility print_chars
, show_bars
ganham algumas demonstrações avançadas (tente novamente!) alive_progress
sempre tentará acompanhar o Python; portanto, a partir da versão 2.0, soltarei o suporte para todas as versões do Python que entram na EOL. Veja a programação deles aqui.
Mas não se preocupe se você ainda não pode migrar: as versões alive_progress
são perenes, portanto, continue usando o que funciona para você e você é bom.
Eu recomendo fortemente definir os pacotes mais antigos alive_progress
em um arquivo requisitos.txt com os seguintes formatos. Isso sempre buscará os lançamentos de compilação mais recentes anteriores a uma determinada versão; portanto, se eu lançar correções de bugs, você também as receberá.
❯ pip install -U " alive_progress<2 "
❯ pip install -U " alive_progress<2.2 "
❯ pip install -U " alive_progress<3.2 "
Este software está licenciado sob a licença do MIT. Consulte o arquivo LICENSE no diretório de distribuição superior para obter o texto completo da licença.
Manter um projeto de código aberto é difícil e demorado, e eu coloquei muito e esforço nisso.
Se você apreciou meu trabalho, pode me apoiar com uma doação! Obrigado ?