alive-progress

repository·main·Indexed 27 days ago

https://github.com/rsalmei/alive-progress

A highly customizable and efficient Python progress bar library featuring dynamic spinners, accurate ETA calculation via an Exponential Smoothing Algorithm, and a unique suspension mechanism. It supports automatic tracking with alive_it, manual control via alive_bar, and seamless integration with print() and logging. Key features include dual-line mode for situational messages, custom spinner factories, and various operation modes (Auto, Unknown, and Manual) to handle different processing scenarios.

Tokens
4.2K
Snippets
10
Records
23
Agent score
42%

What's inside alive-progress

  1. Overview of alive-progress

    main
    alive-progress is a Python library designed for high-performance, visually engaging progress bars. It is optimized for low CPU usage through multithreading and provides features like dynamic spinners that react to processing speed, accurate ETA calculation using an Exponential Smoothing Algorithm, and seamless integration with print() and logging calls. A unique feature is its ability to be suspended, allowing you to pause processing, interact with the Python prompt, and resume without losing progress state.
  2. Analyze animations and bars with the `check` tool

    main
    The check tool allows you to analytically view all generated cycles and frames for both spinners and bars. It provides a beautiful rendition of the animation, including the ability to see the specific codepoints of the frames. This is useful for debugging complex animations involving wide characters, emojis, or grapheme clusters to ensure they align and move smoothly without breaking Unicode encoding.
  3. Use Dual Line mode for longer situational messages

    main

    To include longer messages without shrinking the progress bar or removing widgets, enable dual_line=True. This places a message area below the progress bar, allowing standard print() or logging messages to scroll above it while the bar remains stable at the bottom.

    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()
  4. Understand modes of operation in alive-progress

    main

    The behavior of the progress bar depends on whether you provide a total value and whether you enable manual mode.

    Auto Mode

    Trigger: Provide a total argument to alive_bar. Behavior: Uses an internal counter to track progress. It provides the full suite of widgets: precise bar, spinner, percentage, counter, throughput, and ETA. Special Feature: Supports skipping items using bar(skipped=True) to keep ETA and throughput accurate.

    Unknown Mode

    Trigger: Do NOT provide a total argument. Behavior: Progress is indeterminable. The bar is continuously animated. Available widgets: animated bar, spinner, counter, and throughput. ETA is not available.

    Manual Mode

    Trigger: Set manual=True. Behavior: Uses a percentage (float between 0 and 1) to track progress. You have complete control over the bar position.

    • If total is provided: It behaves like Auto mode but allows manual percentage updates.
    • If total is NOT provided: It provides rough versions of throughput (%/s) and ETA (until 100%).
  5. Resume computations with skipped items in alive_bar

    main

    If you are processing large datasets in batches or from a cache and need to skip items that are already completed, you can inform alive_bar to prevent the ETA from being ruined.

    There are two ways to do this:

    1. If you know the exact number of skipped items: Call bar(N, skipped=True) once with the count of skipped items before starting your loop.
    2. If items are scattered: Call bar(skipped=True) whenever you encounter an item that is already done.
    # Option 1: Known number of skipped items
    with alive_bar(120000) as bar:
        bar(60000, skipped=True)
        for i in range(60000, 120000):
            # process item
            bar()
    
    # Option 2: Scattered skipped items
    with alive_bar(120000) as bar:
        for i in range(120000):
            if done(i):
                bar(skipped=True)
                continue
    
            # process item
            bar()
  6. Use manual mode for loop-less operations

    main

    If you are monitoring a fixed sequence of steps rather than a loop, use manual=True in alive_bar. This prevents the progress bar from jumping erratically if steps take different amounts of time.

    Instead of calling bar() without arguments, call bar(percentage) where percentage is the cumulative progress (e.g., 0.1 for 10%, 0.4 for 40%). The final call should always be bar(1.) to indicate 100% completion.

  7. Create custom spinner animations using Spinner Factories

    main

    You can assemble custom spinners by using various factory types. These factories are passed to alive_bar or config_handler. The available factory types are:

    • frames: Plays a sequence of characters frame by frame.
    • scrolling: Generates a smooth flow of characters from one side to the other, wrapping or hiding at borders.
    • bouncing: Similar to scrolling, but the animation bounces back to the start.
    • sequential: Plays multiple factories one after another in sequence.
    • alongside: Plays multiple factories simultaneously (allows choosing an animation pivot).
    • delayed: Takes another factory and creates multiple copies, increasingly skipping frames to create a trailing effect.
  8. Pause the progress bar for manual interaction

    main

    You can pause an ongoing progress bar to interact with specific items manually. This is useful for debugging or reconciling data where you need to inspect a faulty item before continuing.

    To use this, wrap the logic that identifies items to be inspected in a with bar.pause(): context and yield the item. When used in a REPL (like IPython), you can instantiate the function as a generator and call next(gen) to trigger the pause, inspect the yielded item, and then call next(gen) again to resume the bar exactly where it left off.

    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()
    
    # Usage in REPL:
    gen = reconcile_transactions()
    # To pause and get the item:
    next(gen, None)
    # To resume:
    next(gen, None)
  9. Disable CTRL+C handling in alive_bar

    main

    By default, ctrl_c=True is set, which allows CTRL+C to work as usual. If you want to prevent CTRL+C from raising a stack trace (making it smoother for interactive use or top-level programs), set ctrl_c=False.

    Warning: If used inside a loop, CTRL+C will simply move to the next iteration of that loop.

    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()
  10. Use alive_bar for manual progress tracking

    main

    The alive_bar context manager is the primary way to wrap a loop and manually control progress. You declare the expected total when entering the context, and call bar() at the end of each iteration to advance the bar.

    Key features:

    • Automatic Hooking: Standard Python print(), logging, and click.echo() are automatically hooked to display messages integrated with the progress bar without breaking the animation.
    • Deviation Detection: If you call bar() more or less frequently than expected based on the total, the bar will visually indicate the overflow or underflow.
    • Independence: The bar is independent of the loop; you can call bar() multiple times per iteration or use it to monitor unrelated background tasks.
  11. Use alive_it for automatic progress tracking

    main

    The alive_it function is an iterator adapter that automatically tracks items in an iterable. This is a quicker way to monitor progress without manually calling bar().

    Usage Modes:

    1. Simple Loop: Wrap your items in alive_it(items) and loop over them. The bar advances automatically for every item yielded.
    2. Full Adapter: Assign the result to a variable (e.g., bar = alive_it(items)). This gives you access to the bar handle to set text or retrieve progress, but note that this special bar does not support calling bar() manually as it tracks items automatically.
    3. Finalization: Use the finalize argument to pass a callback (e.g., a lambda) to set the title or text of the final receipt.
    from alive_progress import alive_it
    
    # Simple usage
    for item in alive_it(items):
        print(item)
    
    # Full adapter usage with customization
    bar = alive_it(items)
    for item in bar:
        print(item)
        bar.text(f'ok: {item}')
    
    # Using finalize for a custom receipt
    alive_it(items, finalize=lambda bar: bar.text('Success!'))