A new kind of Progress Bar, with real time throughput, eta and very cool animations!

Overview

alive!

alive-progress :)

A new kind of Progress Bar, with real-time throughput, eta and very cool animations!

Maintenance PyPI version PyPI pyversions PyPI status Downloads

Ever found yourself in a remote ssh session, doing some lengthy operations, and every now and then you feel the need to hit [RETURN] just to ensure you didn't lose the connection? Ever wondered where your processing was in, and when would it finish? Ever needed to pause the progress bar for a while, return to the prompt for a manual inspection or for fixing an item, and then resume the process like it never happened? I did...

I've made this cool progress bar thinking about all that, the Alive-Progress bar! :)

alive-progress

I like to think of it as a new kind of progress bar for python, as it has among other things:

  • a cool live spinner, which clearly shows your lengthy process did not hang and your ssh connection is healthy;
  • a visual feedback of the current speed/throughput, as the spinner runs faster or slower according to the actual processing speed;
  • an efficient multi-threaded bar, which updates itself at a fraction of the actual speed (1,000,000 iterations per second equates to roughly 60 frames per second refresh rate) to keep CPU usage low and avoid terminal spamming; ( πŸ“Œ new: you can now calibrate this!)
  • an expected time of arrival (ETA), with a smart exponential smoothing algorithm that shows the remaining processing time in the most friendly way;
  • a print() hook and ( πŸ“Œ new) logging support, which allows print statements and logging messages effortlessly in the midst of an animated bar, automatically cleaning the screen and even enriching it with the current position when that occurred;
  • after your processing has finished, a nice receipt is printed with the statistics of that run, including the elapsed time and observed throughput;
  • it tracks your desired count, not necessarily the actual iterations, to detect under and overflows, so it will look different if you send in less or more than expected;
  • it automatically detects if there's an allocated tty, and if there isn't (like in a pipe redirection), only the final receipt is printed, so you can safely include it in any code and rest assure your log file won't get thousands of progress lines;
  • you can pause it! I think that's an unprecedented feature for a progress bar! It's incredible to be able to manually operate on some items while inside a running progress bar context, and get the bar back like it had never stopped whenever you want;
  • it is customizable, with a growing smorgasbord of different bar and spinner styles, as well as several factories to easily generate yours!

πŸ“Œ New in 1.6 series!

  • soft wrapping support - or lack thereof actually, it won't scroll your terminal desperately up if it doesn't fit the line anymore!
  • hiding cursor support - more beautiful and professional appearance!
  • python logging support - adequately clean and enriched messages from logging without any configuration or hack!
  • exponential smoothing of ETA - way smoother when you need it the most!
  • proper bar title - left aligned always visible title so you know what is expected from that processing!
  • enhanced elapsed time and ETA representation - the smallest rendition possible, so you can maximize the animations!
  • new bar.text() dedicated method - now you can change the situational message without making the bar going forward!
  • performance optimizations - even less overhead, your processing won't even notice it!

πŸ“Œ Fixed in 1.6.2!

  • new lines get printed on vanilla Python REPL;
  • bar is truncated to 80 chars on Windows.

Get it

Just install with pip:

$ pip install alive-progress

Awake it

Open a context manager like this:

from alive_progress import alive_bar

with alive_bar(total) as bar:  # declare your expected total
    for item in items:         # iterate as usual over your items
        ...                    # process each item
        bar()                  # call after consuming one item

And it's alive! πŸ‘

In general lines, just retrieve the items, enter the alive_bar context manager with their total, and just iterate/process normally, calling bar() once per item! It's that simple! :)

Understand it

  • the items can be any iterable, and usually will be some queryset;
  • the first argument of the alive_bar is the expected total, so it can be anything that returns an integer, like qs.count() for querysets, len(items) for iterables that support it, or even a static integer;
  • the bar() call is what makes the bar go forward -- you usually call it in every iteration after consuming an item, but you can get creative! Remember the bar is counting for you independently of the iteration process, only when you call bar() (something no other progress bar have), so you can use it to count anything you want! For example, you could call bar() only when you find something expected and then know how many of those there were, including the percentage that it represents! Or call it more than once in the same iteration, no problem at all, you choose what you are monitoring! The ETA will not be that useful unfortunately;
  • to retrieve the current bar() count/percentage, you can call bar.current().

So, you could even use it without any loops, like for example:

with alive_bar(3) as bar:
    corpus = read_big_file(file)
    bar()  # file read, tokenizing
    tokens = tokenize(corpus)
    bar()  # tokens ok, processing
    process(tokens)
    bar()  # we're done! 3 calls with total=3
Oops, there's a caveat using without a loop...

Note that if you use alive-progress without a loop it is your responsibility to equalize the steps! They probably do not have the same durations, so the ETA can be somewhat misleading. Since you are telling the alive-progress there're three steps, when the first one gets completed it will understand 1/3 or 33% of the whole processing is complete, but reading that big file can actually be much faster than tokenizing or processing it.
To improve on that, use the manual mode and increase the bar by different amounts at each step!

You could use my other open source project about-time to easily measure the durations of the steps, then dividing them by the total time and obtaining their percentages. Accumulate those to get the aggregate percentages and that's it! Just try to simulate with some representative inputs, to get better results. Something like:

from about_time import about_time

with about_time() as t_total:             # this about_time will measure the whole time of the block.
    t1 = about_time(read_big_file, file)  #
    t2 = about_time(tokenize, t1.result)  # these three will get the relative timings.
    t3 = about_time(process, t2.result)   #
    # if it gets complicated to write in this format, you can just open other `with` contexts!
    # `about_time` supports several syntaxes, just choose your prefered one.

print(f'percentage1 = {t1.duration / t_total.duration}')
print(f'percentage2 = {t2.duration / t_total.duration + percentage1}')
print(f'percentage3 = {t3.duration / t_total.duration + percentage2}')  # the last should always be 1.

Then you can use those percentages to improve the original code:

with alive_bar(3, manual=True) as bar:
    corpus = read_big_file()
    bar(0.01)  # bring the percentage till first step, e.g. 1% = 0.01
    tokens = tokenize(corpus)
    bar(0.3)  # bring the percentage till second step, e.g. 30% = 0.3
    process(tokens)
    bar(1.0)  # the last is always 100%, we're done!

Modes of operation

Actually, the total argument is optional. Providing it makes the bar enter the definite mode, the one used for well-bounded tasks. This mode has all statistics widgets alive-progress has to offer: count, throughput and eta.

If you do not provide a total, the bar enters the unknown mode. In this mode, the whole progress bar is animated like the cool spinners, as it's not possible to determine the percentage of completion. Therefore, it's also not possible to compute an eta, but you still get the count and throughput widgets.

The cool spinner are still present in this mode, and they're both running their own animations, concurrently and independently of each other, rendering a unique show in your terminal! 😜

Then you have the manual modes, where you get to actually control the bar position. It's used for processes that only feed you back the percentage of completion, so you can inform them directly to the bar. Just pass a manual=True argument to alive_bar (or config_handler), and you get to send your own percentage to the very same bar() handler! For example to set it to 15%, you would call bar(0.15), which is 15 / 100, as simple as that.
Call it as frequently as you need, the refresh rate will be asynchronously computed as usual, according to current progress and elapsed time.

And do provide the total if you have it, to get all the same count, throughput and eta widgets as the definite mode! If you don't, it's not possible to infer the count widget, and you'll only get simpler versions of the throughput and eta widgets: throughput is only "%/s" (percent per second) and ETA is only to get to 100%, which are very inaccurate, but better than nothing.

But it's quite simple: Do not think about which mode you should use, just always pass the expected total if you know it, and use manual if you need it! It will just work the best it can! πŸ‘ \o/

To summarize it all:

mode completion count throughput eta overflow and underflow
definite βœ…
automatic
βœ… βœ… βœ… βœ…
unknown ❌ βœ… βœ… ❌ ❌
manual
bounded
βœ…
you choose
βœ…
inferred
βœ… βœ… βœ…
manual
unbounded
βœ…
you choose
❌ ⚠️
simpler
⚠️
rough
βœ…

The bar() handler

  • in definite and unknown modes, it accepts an optional int argument, which increments the counter by any positive number, like bar(5) to increment the counter by 5 in one step βž” relative positioning;
  • in manual modes, it needs a mandatory float argument, which overwrites the progress percentage, like bar(.35) to put the bar in the 35% position βž” absolute positioning.
  • and it always returns the updated counter/progress value.

Deprecated: the bar() handlers used to also have a text parameter which is being removed, more details here.

Styles

Wondering what styles does it have bundled? It's showtime! ;)

alive-progress spinner styles

Actually I've made these styles just to put to use all combinations of the factories I've created, but I think some of them ended up very very cool! Use them at will, or create your own!

There's also a bars showtime, check it out! ;)

alive-progress bar styles

( πŸ“Œ new) Now there are new commands in exhibition! Try the show_bars() and show_spinners()!

from alive_progress import show_bars, show_spinners
# call them and enjoy the show ;)

There's also a ( πŸ“Œ new) utility called print_chars, to help finding that cool one to put in your customized spinner or bar, or to determine if your terminal do support unicode chars.

Displaying messages

While in any alive progress context, you can display messages with:

  • the usual Python print() statement and logging framework, which properly clean the line, print or log an enriched message (including the current bar position) and continues the bar right below it;
  • the ( πŸ“Œ new) bar.text('message') call, which sets a situational message right within the bar, usually to display something about the items being processed or the phase the processing is in.

Deprecated: there's still a bar(text='message') to update the situational message, but that did not allow you to update it without also changing the bar position, which was inconvenient. Now they are separate methods, and the message can be changed whenever you want. DeprecationWarnings should be displayed to alert you if needed, please update your software to bar.text('message'), since this will be removed in the next version.

alive-progress messages

Appearance and behavior

There are several options to customize appearance and behavior, most of them usable both locally and globally. But there's a few that only make sense locally, these are:

  • title: an optional yet always visible title if defined, that represents what is that processing;
  • calibrate: calibrates the fps engine (more details here)

Those used anywhere are [default values in brackets]:

  • length: [40] number of characters to render the animated progress bar
  • spinner: the spinner to be used in all renditions
    it's a predefined name in show_spinners(), or a custom spinner
  • bar: bar to be used in definite and both manual modes
    it's a predefined name in show_bars(), or a custom bar
  • unknown: bar to be used in unknown mode (whole bar is a spinner)
    it's a predefined name in show_spinners(), or a custom spinner
  • theme: ['smooth', which sets spinner, bar and unknown] theme name in alive_progress.THEMES
  • force_tty: [False] runs animations even without a tty (more details here)
  • manual: [False] set to manually control percentage
  • enrich_print: [True] includes the bar position in print() and logging messages
  • title_length: [0] fixed title length, or 0 for unlimited

To use them locally just send the option to alive_bar:

from alive_progress import alive_bar

with alive_bar(total, title='Title here', length=20, ...):
    ...

To use them globally, set them before in config_handler object, and any alive_bar created after that will also use those options:

from alive_progress import alive_bar, config_handler

config_handler.set_global(length=20, ...)

with alive_bar(total, ...):
    # both sets of options will be active here!
    ...

And you can mix and match them, local options always have precedence over global ones!

Click to see it in motion alive-progress customization

Advanced

You should now be completely able to use alive-progress, have fun!
If you've appreciated my work and would like me to continue improving it, you could buy me a coffee! I would really appreciate that 😊 ! Thank you!

And if you want to do even more, exciting stuff lies ahead!

You want to calibrate the engine?

Calibration ( πŸ“Œ new)

The alive-progress bars have a cool visual feedback of the current throughput, so you can instantly see how fast your processing is, as the spinner runs faster or slower with it. For this to happen, I've put together and implemented a few fps curves to empirically find which one gave the best feel of speed:

alive-progress fps curves (interactive version here)

The graph shows the logarithmic (red), parabolic (blue) and linear (green) curves, as well as an adjusted logarithmic curve (dotted orange), with a few twists for small numbers. I've settled with the adjusted logarithmic curve, as it seemed to provide the best all around perceived speed changes. In the future and if someone would find it useful, it could be configurable.

The default alive-progress calibration is 1,000,000 in auto (and manual bounded) modes, ie. it takes 1 million iterations per second for the bar to refresh itself at 60 frames per second. In the manual unbounded mode it is 1.0 (100%). Both enable a vast operating range and generally work well.

Let's say your processing hardly gets to 20 items per second, and you think alive-progress is rendering sluggish, you could:

    with alive_bar(total, calibrate=20) as bar:
        ...

And it will be running waaaay faster...
Perhaps too fast, consider calibrating to ~50% more, find the one you like the most! :)


Perhaps customize it even more?

Create your own animations

Make your own spinners and bars! All of the major components are individually customizable!

There's builtin support for a plethora of special effects, like frames, scrolling, bouncing, delayed and compound spinners! Get creative!

These animations are made by very advanced generators, defined by factories of factory methods: the first level receives and process the styling parameters to create the actual factory; this factory then receives operating parameters like screen length, to build the infinite animation generators.

These generators are capable of several different animation cycles, for example a bouncing ball has a cycle to the right and another to the left. They continually yield the next rendered animation frame in a cycle until it is exhausted. This just enables the next one, but does not start it! That has all kinds of cool implications: the cycles can have different animation sizes, different screen lengths, they do not need to be synchronized, they can create long different sequences by themselves, they can cooperate with each other to play cycles in sequence or simultaneously, and I can display several at once on the screen without any interferences! It's almost like they are alive! πŸ˜‰

The types I've made are:

  • frames: draw any sequence of characters, that will be played frame by frame in sequence;
  • scrolling: pick a frame or a sequence of characters and make it flow smoothly from one side to the other, hiding behind or wrapping upon the invisible borders; if using a sequence, generates several cycles of distinct characters;
  • bouncing: aggregates two scrolling in opposite directions, to make two frames or two sequences of characters flow interleaved from/to each side, hiding or immediately bouncing upon the invisible borders; supports several interleaved cycles too;
  • delayed: get any other animation generator, and copy it multiple times, skipping some frames at the start! very cool effects are made here;
  • compound get a handful of generators and play them side by side simultaneously! why choose if you can have them all?

A small example (Click to see it in motion)

alive-progress creative


Oh you want to stop it altogether!

The Pause mechanism

Why would you want to pause it, I hear? To get to manually act on some items at will, I say!
Suppose you need to reconcile payment transactions. You need to iterate over thousands of them, detect somehow the faulty ones, and fix them. This fix is not simple nor deterministic, you need to study each one to understand what to do. They could be missing a recipient, or have the wrong amount, or not be synced with the server, etc, it's hard to even imagine all possibilities. Typically you would have to let the detection process run until completion, appending to a list each inconsistency found, and waiting potentially a long time until you can actually start fixing them. You could of course mitigate this by processing in chunks or printing them and acting in another shell, but those have their own shortcomings.
Now there's a better way, pause the actual detection for a moment! Then you have to wait only until the next one is found, and act in near real time!

To use the pause mechanism, you must be inside a function, which you should already be in your code (in the ipython shell just wrap it inside one). This requires a function to act as a generator and yield the objects you want to interact with. The bar handler includes a context manager for this, just do with bar.pause(): yield transaction.

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 not validate(transaction):
                with bar.pause():
                    yield transaction
            bar()

That's it! Then you can use it in ipython (or your preferred REPL)! Just call the function to instantiate the generator and, whenever you want another transaction, call next(gen, None)! The progress bar will run as usual while searching, but as soon as an inconsistency is found, the bar pauses itself and you get the prompt back with a transaction! How cool is that πŸ˜ƒ ?

In [11]: gen = reconcile_transactions()

In [12]: next(gen, None)
|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ                   | 105/200 [52%] in 5s (18.8/s, eta: 4s)
Out[12]: Transaction<#123>

When you're done, continue the process with the same next as before... The bar reappears and continues like nothing happened!! :)

In [21]: next(gen, None)
|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ                   | ▁▃▅ 106/200 [52%] in 5s (18.8/s, eta: 4s)

Those astonishing animations refuse to display?

Forcing animations on non-interactive consoles (like Pycharm's)

Pycharm's python console for instance do not report itself as "interactive", so I've included a force_tty argument to be able to use the alive-progress bar in it.

So, just start it as:

with alive_bar(1000, force_tty=True) as bar:
    for i in range(1000):
        time.sleep(.01)
        bar()

You can also set it system-wide in config_handler.

Do note that this console is heavily instrumented and has more overhead, so the outcome may not be as fluid as you would expect.


Interesting facts

  • This whole project was implemented in functional style;
  • It does not declare even a single class;
  • It uses extensively (and very creatively) python Closures and Generators, they're in almost all modules (look for instance the spinners factories and spinner_player 😜 );
  • It does not have any dependencies.

To do

  • improve test coverage, hopefully achieving 100% branch coverage
  • variable width bar rendition, listening to changes in terminal size
  • enable multiple simultaneous bars, for nested or multiple statuses
  • create a contrib system, to allow a simple way to share users' spinners and bars styles
  • jupyter notebook support
  • support colors in spinners and bars
  • any other ideas welcome!
Already done.
  • create an unknown mode for bars (without a known total and eta)
  • implement a pausing mechanism
  • change spinner styles
  • change bar styles
  • include a global configuration system
  • create generators for scrolling, bouncing, delayed and compound spinners
  • create an exhibition of spinners and bars, to see them all in motion
  • include theme support in configuration
  • soft wrapping support
  • hiding cursor support
  • python logging support
  • exponential smoothing of ETA time series

Python 2 EOL

The alive_progress next major version 2.0 will support Python 3.5+ only. But if you still need support for Python 2, there is a full featured one you can use, just:

$ pip install -U "alive_progress<2"

Changelog highlights:

  • 1.6.2: new bar.current() method; newlines get printed on vanilla Python REPL; bar is truncated to 80 chars on Windows.
  • 1.6.1: fix logging support for python 3.6 and lower; support logging for file; support for wide unicode chars, which use 2 columns but have length 1
  • 1.6.0: soft wrapping support; hiding cursor support; python logging support; exponential smoothing of ETA time series; proper bar title, always visible; enhanced times representation; new bar.text() method, to set situational messages at any time, without incrementing position (deprecates 'text' parameter in bar()); performance optimizations
  • 1.5.1: fix compatibility with python 2.7 (should be the last one, version 2 is in the works, with python 3 support only)
  • 1.5.0: standard_bar accepts a background parameter instead of blank, which accepts arbitrarily sized strings and remains fixed in the background, simulating a bar going "over it"
  • 1.4.4: restructure internal packages; 100% branch coverage of all animations systems, i.e., bars and spinners
  • 1.4.3: protect configuration system against other errors (length='a' for example); first automated tests, 100% branch coverage of configuration system
  • 1.4.2: sanitize text input, keeping \n from entering and replicating bar on screen
  • 1.4.1: include license file in source distribution
  • 1.4.0: print() enrichment can now be disabled (locally and globally), exhibits now have a real time fps indicator, new exhibit functions show_spinners and show_bars, new utility print_chars, show_bars gains some advanced demonstrations (try it again!)
  • 1.3.3: further improve stream compatibility with isatty
  • 1.3.2: beautifully finalize bar in case of unexpected errors
  • 1.3.1: fix a subtle race condition that could leave artifacts if ended very fast, flush print buffer when position changes or bar terminates, keep total argument from unexpected types
  • 1.3.0: new fps calibration system, support force_tty and manual options in global configuration, multiple increment support in bar handler
  • 1.2.0: filled blanks bar styles, clean underflow representation of filled blanks
  • 1.1.1: optional percentage in manual mode
  • 1.1.0: new manual mode
  • 1.0.1: pycharm console support with force_tty, improve compatibility with python stdio streams
  • 1.0.0: first public release, already very complete and mature

License

This software is licensed under the MIT License. See the LICENSE file in the top distribution directory for the full license text.

Did you like it?

Thank you for your interest!

I've put much ❀️ and effort into this.
If you've appreciated my work and would like me to continue improving it, you could buy me a coffee! I would really appreciate that 😊 ! (the button is on the top-right corner) Thank you!

Comments
  • Bar soft wraps if terminal window is too narrow (wide unicode chars are tricky)

    Bar soft wraps if terminal window is too narrow (wide unicode chars are tricky)

    As in the title: when terminal window is too narrow progress bar stops animating and it prints itself line by line.

    I'm using code from README:

    with alive_bar(len(text)) as bar:
        for i in range(len(text)):
            #do some stuff
            bar(text="xd", incr=1)
    

    Here's output: 2019-12-08-14-08-43

    feature request ready for release 
    opened by igoro00 51
  • alive-bar spam in Windows 8

    alive-bar spam in Windows 8

    Then I try to look at progress bars that I can use with that code:

    from alive_progress import alive_bar, show_bars
    show_bars()
    

    Instead of replacing old bar with new one so it gives nice effect it just spam new one over console. image

    only_on_windows 
    opened by music-cat-bread 42
  • After hard work and dedication, finally 2.0! πŸ₯³πŸŽ‰

    After hard work and dedication, finally 2.0! πŸ₯³πŸŽ‰

    Wow, I'm very happy to finally release 2.0! It's the result of three full months of hard work, unemployed by choice, in the midst of a terrible coronavirus pandemic! And it came up a superb work, if I say so myself 😝

    New features:

    • spinners engine total revamp, with an ahead of time spinner compiler (zero overhead in runtime!), a check tool to inspect custom and built-in animations, and full support for wide 🀩 chars (support for emojis!), along with several new features: possibility of enlarging or shrinking spinners, smoother bouncing spinners with an additional frame at the edges, improved scrolling of text messages which pause for a moment at the edges, new animation mode to run spinners intermixed, new pivot support in side by side animations, nicer effect in side by side spinners using weighted spreading over the available space, smoother animation in scrolling spinners when the input is longer than available space!! WOW πŸ‘
    • bars engine revamp, with invisible fills and advanced support for multi-char tips, which gradually enter and leave the bar
    • new built-in spinners, bars and themes, using the new spinners' features
    • showtime revamp, which now has themes(!), is more concise, does not wrap screen and can filter patterns
    • bar() handle now supports absolute and relative positioning in all modes
    • improved logging for files, which are enriched as print
    • new advanced configuration for unknown bar, supporting spinner names, spinner factories and unknown bar factories
    • uses time.perf_counter() high resolution clock instead of time.time
    • improved print_chars() utility, which does not break in certain regions
    • requires python 3.6+ (and officially supports python 3.9 and 3.10)

    Now I'm updating the readme, and regenerating its animated gifs...

    Hope you like it! And if you do, you can always donate, appreciated πŸ˜„πŸ‘


    UPDATE Sep 18, 2020: While making the animated gifs, almost finishing the release, I've stumbled upon a challenging matter: correctly support Unicode wide chars, those that have length 1 in Python, but occupies 2 chars when printed on screen!! It is not actually a problem, since the code always had this behavior, and it works seamlessly without them. But I know how those chars can be seductive, and I've decided to dive deep into the problem (see #19 to see how much problem I've encountered just to make the bar title work).

    WOW, it is VERY complicated, way more than I could have ever imagined... Those chars break several things! When they appear on screen, the bar suddenly occupier more space on screen, so the wrap protection breaks and makes the bar scroll insanely up. When trying to fix that, I've inserted a Zero Width Space before these characters to adjust expectation to reality, which was a disaster! It made several animations loose synchronization, be miscalculated or even break altogether, since these chars are invisible and were now used to calculate animations distances! In block mode, where each character is scrolled in blocks, they were also picked, which made whole animation cycles seemingly empty πŸ˜….

    Yeah, I know what you're thinking, maybe I should have released it before. And then this could be the next minor version... Well maybe. OK probably. But this is 2.0, and I wanted to deliver the most awesomeness I could possibly do!!! 😝

    So here I am, full 6 weeks later, and only now I've made all the spinners work!!! πŸ₯³πŸŽ‰ I had one hell of a time, very challenging, and so much fun! This has made me rewrite almost the entire spinner system, and ended up developing a new concept in it: an ahead of time spinner compiler!! Since I needed to simulate all animation cycles and frames to detect and fix the simultaneous wide chars on screen, I went the extra mile and stored them, already calculated and fixed, into a new spinner runner object, ready to be played with ZERO runtime overhead!! It was fast, but now it is πŸš€ fast! πŸ‘

    To get the most performance out of this compiler system, I've refactored all spinner animation types into cool multiple generator expressions, which calculate on demand the cycles and the frames inside them, just when the compiler needs them! This has enabled me to improve several interactions between spinners types, avoiding any duplicate codes and even simplifying the code of the compound animations!

    And finally going the extra mile again, I've instrumented the compiler code to extract the specs of the frame data, including the time to compile them, and created a super cool check() tool! Now you can quickly check any animation you design, how much cycles it will generate, how much frames in each, their natural lengths, and even graphically see all the frame content!!!

    It's getting extremely advanced, and I'm very proud of it.

    image

    Now, to the bar engine!! It also does want wide chars support... 😜 Thank you for reading.

    Best, RogΓ©rio.

    size/XXL 
    opened by rsalmei 32
  • Use with logging module

    Use with logging module

    In my module, I use the python logging module to print out messages.

    During the operation which I want to monitor using alive-progress it may happen that messages are sent out using the logging module. Then, artifacts of the bar remain in the console:

    Loading the fmu took 0.34800148010253906 s.
    
    Starting simulation at t=0.0 s.          | ▁▃▅ 0/1000 [0%] in 0s (0.0/s, eta: ?)
    Simulation took 0.7570006847381592 s.β–ˆβ–ˆβ–ˆβ–Œ| β–…β–‡β–‡ 990/1000 [99%] in 0s (1126.2/s, eta: 0s)
    Simulation finished at t=1000.0 s.
    |β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1000/1000 [100%] in 0.9s (1096.43/s)
    

    The first message ("loading ... took ...") was logged before i instantiated the alive bar. The other messages were emitted while the bar was active. I am using a vanilla StreamHandler that sends everything to stdout.

    By the way - dunno if that's possible - is it possible to have the alive bar redirected to a logging module, too? Might be interesting to have the complete (or not, in case of an error!) progress bar in a log file. Gives structure...

    By the way 2: it's pretty awesome :)

    Cheers, Jan

    feature request 
    opened by jnjaeschke 27
  • Bar gets cut off after 80 characters

    Bar gets cut off after 80 characters

    image

    It cuts off stuff like the ETA and percentage when the numbers are large enough,

    This is the vscode terminal if that makes any difference, but it also happens on fluent terminal. Is there a way to make it adapt to my terminal width?

    code example:

    from alive_progress import alive_bar
    import time
    
    with alive_bar(15000, title="Sending messages...") as bar:
        for x in range(15000):
            time.sleep(10/15000)
            bar()
    
    opened by typecasto 25
  • Alive Progress with jupyter notebooks

    Alive Progress with jupyter notebooks

    Is there a way to use alive-progress with jupyter notebooks? I tried but it's printing in my command line instead of notebook, and the output is like this:

    |β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–Œ | β–…β–‡β–‡ 214/1000 [21%] in 21s ... |β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–Œ | β–†β–ˆβ–† 215/1000 [22%] in 21s ... |β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‹ | β–‡β–‡β–… 216/1000 [22%] in 21s ...

    Update: Python==2.7.15 Django==1.8.4

    I'm using jupyter notebook with django-shell-plus to use django models

    feature request ready for release improvement 
    opened by avlm 22
  • UnicodeEncodeError on some Linux'es (ubuntu 16.04 and Slackware 14.2)

    UnicodeEncodeError on some Linux'es (ubuntu 16.04 and Slackware 14.2)

    In [17]: from alive_progress import alive_bar
    
    In [18]: def pretty_sleep(sleep_time: int, bar='filling'):
        ...:     """pretty sleep with progress bar"""
        ...:     with alive_bar(int(sleep_time), bar=bar) as bar:
        ...:         for i in range(int(sleep_time)):
        ...:             time.sleep(0.001)
        ...:             bar()
        ...:
    
    In [19]: pretty_sleep(100)
    Exception in thread Thread-1851:
    Traceback (most recent call last):
      File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
        self.run()
      File "/usr/lib/python3.5/threading.py", line 862, in run
        self._target(*self._args, **self._kwargs)
      File "/home/rjosyula/x/lib/python3.5/site-packages/alive_progress/progress.py", line 100, in run
        alive_repr(next(player))
      File "/home/rjosyula/x/lib/python3.5/site-packages/alive_progress/progress.py", line 115, in alive_repr
        sys.__stdout__.write(line + (spin and '\r' or '\n'))
    UnicodeEncodeError: 'latin-1' codec can't encode characters in position 43-45: ordinal not in range(256)
    
    ---------------------------------------------------------------------------
    UnicodeEncodeError                        Traceback (most recent call last)
    <ipython-input-19-5b2d8b0fde03> in <module>
    ----> 1 pretty_sleep(100)
    
    <ipython-input-18-920a2b64dd16> in pretty_sleep(sleep_time, bar)
          4         for i in range(int(sleep_time)):
          5             time.sleep(0.001)
    ----> 6             bar()
          7
    
    /usr/lib/python3.5/contextlib.py in __exit__(self, type, value, traceback)
         64         if type is None:
         65             try:
    ---> 66                 next(self.gen)
         67             except StopIteration:
         68                 return
    
    ~/x/lib/python3.5/site-packages/alive_progress/progress.py in alive_bar(total, title, calibrate, **options)
        257
        258     end, run.text, run.stats = True, '', stats_end
    --> 259     alive_repr()
    
    ~/x/lib/python3.5/site-packages/alive_progress/progress.py in alive_repr(spin)
        113             if line_len < run.last_line_len:
        114                 clear_traces()
    --> 115             sys.__stdout__.write(line + (spin and '\r' or '\n'))
        116             sys.__stdout__.flush()
        117
    
    UnicodeEncodeError: 'latin-1' codec can't encode characters in position 1-40: ordinal not in range(256)
    
    
    help wanted 
    opened by qxlsz 22
  • unhashable type: 'types.SimpleNamespace' when using uninitialized logging or entering alive_bar's context twice

    unhashable type: 'types.SimpleNamespace' when using uninitialized logging or entering alive_bar's context twice

    The "incr" param is gone in v2.0 and I believe this arg is occasionally being misassigned. Error: Exception has occurred: TypeError unhashable type: 'types.SimpleNamespace'

    opened by dbrocha 21
  • Disable bar based on a parameter/variable?

    Disable bar based on a parameter/variable?

    Is it possible to disable the bar based on certain conditions? A good example of what I'm saying could be something like:

    progress_bar = False
    if progress_bar == False:
      # code to disable the progressbar
    else:
      #progressbar remains enabled
    
    with alive_bar(100) as bar:
      # Process code
    

    In this case the visibility of alive_bar depends on the value of progress_bar ... Another solution that I thought of was writing the process code 2 times to account for the progress_bar value but that is quite unconventional...

    feature request ready for release 
    opened by sortedcord 17
  • Automatic units in monitor for large quantities

    Automatic units in monitor for large quantities

    Would it be possible to support automatic unit conversion, similar to how tqdm implements this?

    • unit : str, optional String that will be used to define the unit of each iteration [default: it].
    • unit_scale : bool or int or float, optional If 1 or True, the number of iterations will be reduced/scaled automatically and a metric prefix following the International System of Units standard will be added (kilo, mega, etc.) [default: False]. If any other non-zero number, will scale total and n.
    feature request 
    opened by lschmelzeisen 17
  • pacman style progress bar

    pacman style progress bar

    I fail to make a pacman style progress bar with: pacman = standard_bar_factory(borders="[]", tip=None, chars="Cc-", blank=" o")

    It works sort of, but the dots move "away" from the "pacman". Example:

    [----------C  o  o  o  o  o  o  o  o  o  o]
    [-----------C  o  o  o  o  o  o  o  o  o  ]
    [------------C  o  o  o  o  o  o  o  o  o]
    

    ideally the dots would stay in place, like this:

    [----------C  o  o  o  o  o  o  o  o  o  o]
    [----------c  o  o  o  o  o  o  o  o  o  o]
    [-------------------------C  o  o  o  o]
    

    The problem arises from how the padding (right part of the progress bar) is handled in bars.py. My idea would be using some module tricks to scroll the padding. There is probably a better way.

    opened by FredBrockstedt 16
  • Multiple time estimations by category

    Multiple time estimations by category

    Hi all!, this idea was inspired initially from https://github.com/rsalmei/alive-progress/issues/215

    The start point is that, we in a flow we can have more than one function or way to process items, this causes to every one of them have a different way to estimate its own time, picking an example from the issue 215.

    • Time of the normal process
    • Time of the skipped element

    Well, one way is as the issue tells have a way to ignore that particular element in the calculation of estimated time, that is a good way but I think there is two points that can be handled too:

    • Skip an element has a time, depending of how we know if need to skip it or not can not be a marginal time
    • Have two times, one for a process and other for skipped content is a particular case of a major one, when a counter can have multiple functions, and every function uses different times.
    • Is not always easy to know how a element will be processed, like when want to skip something or not, so we end in a situation where we have multiples averages times, but we don't know how much of the total will be from the group of skipped ones, or the processed ones

    The idea (or as a base to create a new one) I propose to solve the issue 215 and the points above, is the bar have a category like this:

    #wait the fuc1 to finish
    bar(category="func1")
    #wait the func 1 to finish
    bar(category="func1")
    #wait until we know we want to skip
    bar(category="skip")
    #wait to func2 to finish
    bar(category="func2")
    #wait until we know we want to skip
    bar(category="skip")
    #wait to func2 to finish
    bar(category="func2")
    #wait to func2 to finish
    bar(category="func2")
    #wait to func2 to finish
    bar(category="func2")
    

    Now to shoe the average time, generate groups based on the category, in this case example:

    • func1: 2 times (25% of all the samples) (ex 60 segs and 50 segs)
    • func2: 4 times (50% of all the samples) (ex, 10s, 11s, 9s, 15s)
    • skip: 2 times (25% of all the samples) (ex, 1s, 1s)

    Then calculate the estimated time of every group, there is several ways, this project seems has its way, just to illustrate lets use the normal average:

    • func1: 55s
    • func2: 11.25s
    • skip: 1s

    Now, we can suppose the current proportion of all the categories will work over all the elements we want to process, this is not true for a small sample, but should be closer to the reality in several cases and when we have a bigger number of samples.

    Lets pick the total elements as 10000

    Total estimated time to finish all: 55s*0.25 + 0.5s*4 + 0.25s*1 = 16s (average), then 16 * 10000segs = 16000s

    Remaining time: 16000 - elapsed time: 16000 - 2*55 (func1) - 4*11.25 (func2) - 2*1 (skip) = 15843s

    Due to this method, multiply by the average time to get the elapsed time just returns the true elapsed time, maybe we should just substract the true elapsed time.

    With this data we can show average time per operations, or show the average by category, there is a lot of options from here :3

    Maybe the normal average is not the best for several part of this calculations, but remember is just to explain the concept :)

    The concept to categorize different calculations for estimations ends there.

    There is one other concept I would like to integrate here, changes a little some sections, but is a complement concept, and is use a number to change the "weight" of ever time in a particular function, like if func1 runs over a list, we can pass to bar the array size, use it as a "weight" for the estimation (the total time would be split by every category, and every category should have different times with its own weights). But before that, If ppl like the idea above I'll write this other one deeper.

    Personally, I never thought too much in good time estimations before, I never needed it, but today I'm working, and I learned good estimations are necessary to know how much time we need, is great indeed!

    Thx!

    opened by latot 0
  • Option to the bar to ignore the time counter of a particular step

    Option to the bar to ignore the time counter of a particular step

    Hi all!, Thx for this great project!

    This can be confuse to explain, so I'll start in other point, there is some cases where we put a progress bar, and the progress bar will show the remaining time... just some times, some of this process are resumable, this causes we call bar instantly and the timer does wrong calculations to get the estimated time.

    In this cases we can know when we will skip a particular step, maybe something like:

    bar(ignore_time = True)
    

    I think something would be great for this, the idea is that the reaming time ignore that step.

    Thx!

    opened by latot 5
  • with asyncio still print still after ctrl-c in ipython

    with asyncio still print still after ctrl-c in ipython

    import asyncio
    from alive_progress import alive_bar
    
    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')
            await asyncio.sleep(0.3)
            bar()
    
    opened by NewUserHa 2
  • Are new line characters

    Are new line characters "\n" allowed in the Dual Line feature?

    Hi @rsalmei , thank you for this awesome library!

    Referring to https://github.com/rsalmei/alive-progress/issues/135, are new line characters \n allowed in bar.text? Mine do not seem to be taking and keeps everything showing only on a single line. I've also tried using \r\n, with no success.

    My use case is that I output performance stats, with each metric being on its own line, that update in real-time as I'm going through the loop. Since I'm looking at 10+ lines, I do not want to print these lines over and over again as they continuously update throughout the loop. It would be much better to have them display below the progress bars.

    Thanks!

    feature request 
    opened by jakemayfield 2
  • Get seconds per iteration in progress bar

    Get seconds per iteration in progress bar

    Hi there!

    Love the package and the customisations so far!

    I have a process that takes around 2 seconds per iteration. and would like to see something like 2.01s/it. The tqdm package automatically switches between iterations per second and seconds per iteration, depending on which one there are more of per second.

    For example:

    import time
    from alive_progress import alive_bar
    
    with alive_bar(3) as bar:
        for i in range(3):
            time.sleep(2)
            bar()
    
    from tqdm import tqdm
    
    for i in tqdm(range(3)):
        time.sleep(2)
        bar()
    

    Output:

    alive-progress:
    |β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–                          | β–†β–„β–‚ 1/3 [33%] in 3s (0.3/s, eta: 4s)
    
    tqdm:
     33%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ               | 1/3 [00:02<00:04,  2.01s/it]
    

    I've seen the customisation of the stats option in the alive_bar, but don't see a way how to change the {rate} to {1/rate}

    stats (bool|str): [True] configures the stats widget (123.4/s, eta: 12s)
    ↳ send a string with {rate} and {eta} to customize it
    

    Thanks!

    feature request 
    opened by SanderLam 7
Owner
RogΓ©rio Sampaio de Almeida
A Python aficionado and a Rust enthusiast, perfectionist and curious about the art of computer programming in general.
RogΓ©rio Sampaio de Almeida
Run an FFmpeg command and see the percentage progress and ETA.

Run an FFmpeg command and see the percentage progress and ETA.

null 25 Dec 22, 2022
A simple file transfer tools, similar to rz / sz but compatible with tmux (control mode), which works with iTerm2 and has a nice progress bar

trzsz A simple file transfer tools, similar to rz/sz but compatible with tmux (control mode), which works with iTerm2 and has a nice progress bar. Why

null 561 Jan 5, 2023
Loading animation; a progress bar

Loading animation; a progress bar. When you know the remaining time or task completion percentage, then you’re able to show an animated progress bar:

Goldy 1 Jan 23, 2022
Multifunctional library for creating progress bars.

?? Content Installation Using github Using pypi Quickstart Flags Useful links Documentation Pypi Changelog TODO Contributing FAQ Bar structure βš™οΈ Inst

DenyS 27 Jan 1, 2023
A python package to display progress of loops to the user

ProgressBars A python package to display progress of loops to the user. Installation This package can be installed using pip. pip install progressbars

Matthias 3 Jan 16, 2022
Squirrel - A cli program to track writing progress

Squirrel Very much a WIP project squirrel is a command line program that tracks you writing progress and gives you useful information and cute and pic

null 3 Mar 23, 2022
πŸƒ Python3 Solutions of All Problems in GCJ 2022 (In Progress)

GoogleCodeJam 2022 Python3 solutions of Google Code Jam 2022. Solution begins with * means it will get TLE in the largest data set. Total computation

kamyu 12 Dec 20, 2022
TermPair lets developers securely share and control terminals in real timeπŸ”’

View and control terminals from your browser with end-to-end encryption ??

Chad Smith 1.5k Jan 5, 2023
Simple CLI tool to track your cryptocurrency portfolio in real time.

Simple tool to track your crypto portfolio in realtime. It can be used to track any coin on the BNB network, even obscure coins that are not listed or trackable by major portfolio tracking applications.

Trevor White 69 Oct 24, 2022
Konsave lets use save your KDE Plasma customizatios and restore them very easily!

Konsave (Save Plasma Customization) A CLI program that will let you save and apply your KDE Plasma customizations with just one command! Als

null 439 Jan 2, 2023
Very nice SMS & Mail Bomber for Termux and Linux.

Very nice SMS & Mail Bomber for Termux and Linux. Coded with love)))

nordbearbot.dev 5 Nov 6, 2022
A very simple and lightweight ToDo app using python that can be used from the command line

A very simple and lightweight ToDo app using python that can be used from the command line

Nilesh Sengupta 2 Jul 20, 2022
A very simple python script to encode and decode PowerShell one-liners.

PowerShell Encoder A very simple python script to encode and decode PowerShell one-liners. I used Raikia's PowerShell encoder ALOT, but one day it wen

John Tear 5 Jul 29, 2022
A terminal tool for git. When we use git, do you feel very uncomfortable with too long commands

PIGIT A terminal tool for git. When we use git, do you feel very uncomfortable with too long commands. For example: git status --short, this project c

Zachary 1 Apr 9, 2022
TerminalGV is a very simple client to display stats about your SNCF TGV/TER train in your terminal.

TerminalGV So I got bored in the train, TerminalGV is a very simple client to display stats about your SNCF TGV/TER train in your terminal. The "on-tr

Samuel 8 Dec 15, 2022
🎈 `st` is a CLI to quickly kick-off your new Streamlit project

?? st - a friendly Streamlit CLI st is a CLI that helps you kick-off a new Streamlit project so you can start crafting the app as soon as possible! Ho

Arnaud 18 Dec 19, 2022
This project contains the ClonedPerson dataset and code described in our paper "Cloning Outfits from Real-World Images to 3D Characters for Generalizable Person Re-Identification".

ClonedPerson This is the official repository for the ClonedPerson project, which contains the ClonedPerson dataset and code described in our paper "Cl

Yanan Wang 55 Dec 27, 2022
Albert launcher extension for converting units of length, mass, speed, temperature, time, current, luminosity, printing measurements, molecular substance, and more

unit-converter-albert-ext Extension for converting units of length, mass, speed, temperature, time, current, luminosity, printing measurements, molecu

Jonah Lawrence 2 Jan 13, 2022
Synchronization tool for external devices which does not support time stamps, e.g. over MTP.

MTP-Sync Tool to synchronize data to a slow device, e.g. a smartphone which is connected over MTP. A state file (.mtp_sync_state.json) is created in t

null 2 Jul 22, 2022