enlighten Documentation

repository·main·Indexed 19 days ago

https://github.com/rockhopper-technologies/enlighten

A Python library for creating console progress bars, counters, and status bars. Enlighten allows standard stdout/stderr printing and logging without interfering with the progress bar display. It features a Manager for handling multiple indicators, specialized NotebookManager for Jupyter environments, and support for nested tracking via SubCounter. The library provides utilities for time formatting, text alignment via Justify, and custom terminal styling through the manager.term object.

Tokens
8K
Snippets
30
Records
37
Agent score
68%

What's inside enlighten

  1. Overview of Enlighten Progress Bar

    main
    Enlighten is a Python library designed for creating console progress bars. Its primary advantage is that it allows you to use standard print() statements or logging to stdout and stderr without requiring manual redirection or complex workarounds to prevent progress bars from being broken by output. It also includes experimental support for Jupyter Notebooks.
  2. Use human-readable numeric prefixes (SI/IEC)

    main

    Enlighten supports automatic metric (SI) and binary (IEC) prefixes for numeric values.

    • rate and interval fields use prefixed.Float.
    • total and count fields default to int.
    • If you set Counter.total or Counter.count to a float, or pass a float to Counter.update(), these fields will automatically use prefixed.Float formatting (e.g., converting bytes to MiB/GiB).
    import time
    import random
    import enlighten
    
    size = random.uniform(1.0, 10.0) * 2 ** 20  # 1-10 MiB (float)
    chunk_size = 64 * 1024  # 64 KiB
    
    # Use !.2j in the format string for prefixed float formatting
    bar_format = '{desc}{desc_pad}{percentage:3.0f}%|{bar}| ' \
                 '{count:!.2j}{unit} / {total:!.2j}{unit} ' \
                 '[{elapsed}<{eta}, {rate:!.2j}{unit}/s]'
    
    manager = enlighten.get_manager()
    pbar = manager.counter(total=size, desc='Downloading', unit='B', bar_format=bar_format)
    
    bytes_left = size
    while bytes_left:
        time.sleep(random.uniform(0.05, 0.15))
        next_chunk = min(chunk_size, bytes_left)
        pbar.update(next_chunk)
        bytes_left -= next_chunk
  3. Use Multicolored Progress Bars with subcounters

    main

    You can track multiple categories within a single progress bar by adding subcounters to a parent counter using add_subcounter().

    How it works:

    • Colors are drawn from right to left in the order they were added.
    • When all_fields=True is passed to add_subcounter, additional fields become available in the bar_format for that specific subcounter (indexed by _n or _2, etc.).

    Available Fields for bar_format:

    • count_n: Current value of subcounter $n$.
    • count_0: Remaining count after deducting all subcounters.
    • count_00: Sum of counts of all subcounters.
    • percentage_n: Percentage complete for subcounter $n$.
    • percentage_0: Remaining percentage after subcounters.
    • percentage_00: Total percentage of all subcounters.
    • eta_n (if all_fields=True): Estimated time to completion for subcounter $n$.
    • rate_n (if all_fields=True): Average increments per second for subcounter $n$.
    import random
    import time
    import enlighten
    
    # Format using subcounter fields (e.g., count_2 for the second subcounter)
    bar_format = u'{desc}{desc_pad}{percentage_2:3.0f}%|{bar}|' + \
                u' S:{count_0:{len_total}d} F:{count_2:{len_total}d} E:{count_1:{len_total}d}'
    
    manager = enlighten.get_manager()
    success = manager.counter(total=100, desc='Testing', unit='tests', color='green', bar_format=bar_format)
    errors = success.add_subcounter('white')
    failures = success.add_subcounter('red')
    
    # Update subcounters as work progresses
    # errors.update()
    # failures.update()
    # success.update()
  4. How Managers work in Enlighten

    main

    The Manager is the central object in Enlighten. It handles output to the terminal and manages multiple concurrent progress bars.

    To use Enlighten, you must first obtain a manager instance using enlighten.get_manager().

    Key Behavior:

    • Managers only display output when the output stream (defaulting to sys.__stdout__) is attached to a TTY.
    • If the stream is not a TTY, the returned manager instance will be disabled automatically.
    import enlighten
    manager = enlighten.get_manager()
  5. Use multicolored progress bars to track multiple categories

    main

    You can create multicolored progress bars to track different categories within a single bar. Colors are drawn from right to left in the order subcounters are added.

    When using multicolored progress bars, the following additional fields are available for bar_format:

    • count_n (int): Current value of count for the $n$-th subcounter.
    • count_0 (int): Remaining count after deducting counts for all subcounters.
    • count_00 (int): Sum of counts from all subcounters.
    • percentage_n (float): Percentage complete for the $n$-th subcounter.
    • percentage_0 (float): Remaining percentage after deducting percentages for all subcounters.
    • percentage_00 (float): Total of percentages from all subcounters.

    If you call Counter.add_subcounter_ with all_fields=True, the subcounter also provides:

    • eta_n (str): Estimated time to completion for the $n$-th subcounter.
    • rate_n (float): Average increments per second since the parent was created for the $n$-th subcounter.
    import random
    import time
    import enlighten
    
    # Example: Tracking test results (Success, Failures, Errors)
    bar_format = u'{desc}{desc_pad}{percentage:3.0f}%|{bar}| ' + \
                u'S:{count_0:{len_total}d} ' + \
                u'F:{count_2:{len_total}d} ' + \
                u'E:{count_1:{len_total}d} ' + \
                u'[{elapsed}<{eta}, {rate:.2f}{unit_pad}{unit}/s]'
    
    manager = enlighten.get_manager()
    success = manager.counter(total=100, desc='Testing', unit='tests', 
                              color='green', bar_format=bar_format)
    errors = success.add_subcounter('white')
    failures = success.add_subcounter('red')
    
    while success.count < 100:
        time.sleep(random.uniform(0.1, 0.3))
        result = random.randint(0, 10)
        if result == 7:
            errors.update()
        elif result in (5, 6):
            failures.update()
        else:
            success.update()
  6. Automatically update counters by iterating over collections

    main

    An enlighten.Counter or enlighten.SubCounter can be called as a function on one or more iterables. This returns a generator that yields each element from the iterables and automatically increments the counter by 1 after each yield.

    Note: Type checking for the iterables is lazy and occurs only when iteration begins.

    import time
    import enlighten
    
    flock1 = ['Harry', 'Sally', 'Randy', 'Mandy', 'Danny', 'Joe']
    flock2 = ['Punchy', 'Kicky', 'Spotty', 'Touchy', 'Brenda']
    total = len(flock1) + len(flock2)
    
    manager = enlighten.Manager()
    pbar = manager.counter(total=total, desc='Counting Sheep', unit='sheep')
    
    # The counter automatically updates as it iterates through the lists
    for sheep in pbar(flock1, flock2):
        time.sleep(0.2)
        print('%s: Baaa' % sheep)
  7. Manually print Counter output

    main

    If the manager is disabled (enabled=False), you can still retrieve the formatted string of a counter to print it manually. This is useful for custom logging or creating simple refreshing bars in environments without TTY support.

    • Use Counter.format(width=...) to get the string.
    • Coercing a Counter to a string (e.g., print(pbar)) calls .format() with default arguments.
    import enlighten
    
    # Method 1: Using .format()
    manager = enlighten.get_manager(enabled=False)
    pbar = manager.counter(desc='Progress', total=10)
    pbar.update()
    print(pbar.format(width=100))
    
    # Method 2: String coercion
    print(pbar)
    
    # Method 3: Manual refreshing bar implementation
    import time
    manager = enlighten.get_manager(enabled=False)
    pbar = manager.counter(desc='Progress', total=10)
    print()
    for _ in range(10):
        time.sleep(0.2)
        pbar.update()
        # Use carriage return \r to overwrite the line
        print(f'\r{pbar}', end='', flush=True)
    print()
  8. Use Enlighten in Jupyter Notebooks

    main

    Enlighten supports Jupyter Notebooks via the NotebookManager class (added in version 1.10.0). When running inside a Jupyter environment, enlighten.get_manager() automatically returns a NotebookManager instance.

    Note on Width: Jupyter Notebook support currently uses a static output width of 100 characters because notebook width cannot be detected. You can override this by passing the width keyword argument to enlighten.get_manager().

    import enlighten
    
    # Get the manager (returns NotebookManager automatically in Jupyter)
    manager = enlighten.get_manager(width=120)
    
    # Use the manager as usual
    counter = manager.add_counter(total=100)
  9. Enable or disable progress bars based on environment

    main

    You can conditionally enable or disable progress bars by checking if the output stream is a TTY (interactive terminal) or by using a configuration setting. This prevents progress bars from cluttering logs when output is redirected to a file or a pipe.

    Use enlighten.get_manager() to simplify this process. If enabled=False, no output will be produced, but you can still interact with the counter objects.

    import sys
    import enlighten
    
    # Example configuration object
    config = {'stream': sys.stdout,
              'useCounter': False}
    
    # Logic to determine if bars should be enabled
    enableCounter = config['useCounter'] and config['stream'].isatty()
    manager = enlighten.Manager(stream=config['stream'], enabled=enableCounter)
    
    # Simplified approach using get_manager
    manager = enlighten.get_manager(stream=config['stream'], enabled=config['useCounter'])