Skip to main content

⚡ flashbar

🌐 English · 简体中文 · Русский

README: generated with AI

Lightweight progress bars and formatted CLI output for Python 3.8+.

flashbar demo

Install

pip install flashbar

Update checks

After a progress bar or spinner finishes successfully in an interactive terminal, flashbar checks PyPI for a newer release. The result is cached for 7 days, so neither the request nor the notice runs on every command:

ℹ  flashbar 1.4.0 is available (you have 1.3.0).
Run: pip install -U flashbar

Network and cache errors are silently ignored. Checks are skipped for redirected output, CI, GitHub Actions, and common JSON output flags. If the hosting CLI accepts --no-update-check, flashbar recognizes that flag. The universal opt-out is FLASHBAR_NO_UPDATE_CHECK=1.

Apps that only use the formatting helpers can run the same check explicitly after their real command has completed:

from flashbar import maybe_notify

maybe_notify()

Keep that call out of any other machine-readable output mode.

Quick start

from flashbar import track
import time

for item in track(range(100), label="Downloading"):
    time.sleep(0.02)

Formatted output

Build styled CLI output with a few small functions:

from flashbar import panel, rule, success, error, warn, info

print(panel("Build complete\n42 files compiled in 1.2s",
            title="Status", color="green", width=47))

print(rule("Status indicators", width=51))

print(success("Tests passed"))
print(error("Build failed"))
print(warn("Deprecated API"))
print(info("Update available"))

Output:

╭─ Status ────────────────────────────────────╮
│ Build complete                              │
│ 42 files compiled in 1.2s                   │
╰─────────────────────────────────────────────╯

──────────────── Status indicators ────────────────

✓ Tests passed
✗ Build failed
⚠ Deprecated API
ℹ Update available

Panel styles

Five border styles available:

panel("body", style="rounded")  # ╭ ╮ ╰ ╯  (default)
panel("body", style="square")   # ┌ ┐ └ ┘
panel("body", style="double")   # ╔ ╗ ╚ ╝
panel("body", style="heavy")    # ┏ ┓ ┗ ┛
panel("body", style="ascii")    # + + + +

Auto-fits to content, or pass width=N for a fixed size. Custom color (named or hex) and padding are supported.

Pass plain=True to panel(), rule(), or a status helper for ANSI-free ASCII decoration. Nested ANSI sequences in user text are stripped in this mode:

print(success("Tests passed", plain=True))  # [OK] Tests passed
print(rule("Build log", width=32, plain=True))

With the default plain=None, these helpers use styled Unicode only when stdout is an encodable TTY. Pass plain=False to force styling.

Rule

Horizontal divider, optionally with a centered label:

print(rule())                         # full-width line
print(rule("Section 1"))              # centered label
print(rule("Done", color="green"))    # colored

Print helper

If you don't want to call print() yourself:

from flashbar import print_panel

print_panel("Connection failed", title="Error", color="red")

When output isn't a TTY (logs, CI), styling strips automatically — your log files stay clean.

Progress bar

from flashbar import Bar

bar = Bar(100, label="Processing", theme="green")
for i in range(100):
    bar.update()

# or jump to a specific value
bar = Bar(100)
bar.set(50)  # jump to 50%
bar.set(100) # done

With context manager

Automatically completes the bar on exit, even on exceptions:

with Bar(100, theme="retro", label="Building") as bar:
    for i in range(100):
        do_work()
        bar.update()

ETA and speed

# ETA is on by default
bar = Bar(1000, label="Training", show_eta=True)

# show items/sec too
bar = Bar(1000, label="Training", show_speed=True)

Units and live status

Pass a unit to show completed and total values. unit_scale=True uses binary units for bytes and decimal units for everything else:

bar = Bar(file_size, label="Downloading", unit="B",
          unit_scale=True, show_speed=True)
# Downloading [████░░] 42% 4.2 MiB / 10.0 MiB 1.3 MiB/s

The label and postfix fields can change while a task is running:

bar.set_label("Compiling main.py")
bar.set_postfix(files=42, errors=0)
bar.set_postfix()  # clear it

Unknown totals

Use total=None while the amount of work is unknown. Each update() advances the indeterminate pulse and counter. Once the total becomes known, switch the same bar to percentages and ETA:

bar = Bar(None, label="Scanning", unit="files")
bar.update()
bar.update()
bar.set_total(1500)

Transient bars

transient=True removes the bar after completion and suppresses its final line when output is redirected:

with Bar(100, transient=True) as bar:
    run_task(bar)

Smooth rendering

Sub-character rendering makes bars look much more fluid. It's auto-enabled when the fill character is █, and you can toggle it explicitly:

# always smooth
Bar(100, smooth=True)

# always classic
Bar(100, smooth=False)

Spinner

For tasks where you don't know the total:

from flashbar import Spinner

with Spinner("Loading data...", style="dots"):
    load_big_file()

# manual control
sp = Spinner("Thinking...", style="circle", color="magenta")
sp.start()
result = heavy_computation()
sp.stop("Done!")

Themes

See the demo GIF above to see each theme in action with real colors.

from flashbar import Bar

for name in ["default", "green", "red", "retro", "minimal", "slim", "dots", "arrow"]:
    bar = Bar(30, theme=name, label=f"{name:8s}")
    for _ in range(30):
        bar.update()
Theme Look
default █████░░░░░ 🔵 blue
green █████░░░░░ 🟢 green
red █████░░░░░ 🔴 red
retro #####..... 🟡 yellow
minimal ───── ⚪ white
slim ━━━━━╺╺╺╺╺ 🔵 cyan
dots ●●●●●○○○○○ 🟣 magenta
arrow ▸▸▸▸▸▹▹▹▹▹ 🔵 blue

Spinner styles

Style Frames
dots ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧
line - \ | /
circle ◐ ◓ ◑ ◒
bounce ⠁ ⠂ ⠄ ⠂
arrows ← ↑ → ↓
grow ▏ ▎ ▍ ▌ ▋ ▊ ▉ █
moon 🌑🌒🌓🌔🌕🌖🌗🌘

Custom colors

# named
Bar(100, color="cyan", label="Cyan bar")

# any hex color
Bar(100, color="#FF5733", label="Orange bar")
Bar(100, color="#00FF99", label="Mint bar")

Custom characters

Bar(100, fill="▓", empty="▒")
Bar(100, fill="=", empty="-")
Bar(100, fill="●", empty="○", color="#FF69B4")

Custom fill and empty values must each occupy exactly one terminal cell.

Generators and iterators

track() works with anything that has len(). For generators, pass total=:

def my_generator():
    for i in range(1000):
        yield i

for item in track(my_generator(), total=1000, label="Generating"):
    process(item)

Behavior in non-TTY environments

When output is piped to a file or running in CI, flashbar detects that automatically and stays quiet — only the final line is printed, without any escape codes:

python myscript.py 2> log.txt    # log.txt stays clean
python myscript.py 2>&1 | tee    # no garbled output

API reference

Progress

Bar(total, **options)

Param Type Default Description
total int or None required Number of steps; None = unknown
width int 40 Bar width in characters
theme str "default" Theme name
label str "" Text before the bar
color str None Override color (name or hex)
fill str None Override fill character
empty str None Override empty character
show_eta bool True Show estimated time remaining
show_speed bool False Show items/sec
smooth bool None Sub-character rendering. None = auto
unit str None Unit displayed with counts and speed
unit_scale bool False Scale B as KiB/MiB and other units as k/M
transient bool False Remove completed output

Methods: .update(step=1), .set(value), .set_total(total), .set_label(label), .set_postfix(**fields), and the context manager. Negative steps are rejected. Calling .set() below the total or increasing the total reopens a completed bar and restarts its timer.

track(iterable, **options)

Same options as Bar, plus total= for iterables without len().

Spinner(label, **options)

Param Type Default Description
label str "" Text next to spinner
style str "dots" Spinner animation style
color str "cyan" Color (name or hex)
speed float 0.08 Positive finite seconds between frames

Methods: .start(), .stop(final_text=None), context manager.

Formatted output

panel(text, **options) -> str

Param Type Default Description
text str required Body content (may contain newlines)
title str None Optional title in the top border
color str None Border color (name or hex)
width int None Total width. None = auto-fit content
style str "rounded" rounded, square, double, heavy, ascii
padding int 1 Horizontal padding inside the box
plain bool or None None Auto-detect output; True = ASCII, False = styled

rule(label="", width=None, color=None, plain=None) -> str

Horizontal divider. Empty label creates an unlabelled line. Its visible width always matches width. With plain=None, output is styled only when sys.stdout is a TTY; pass plain=False to force styling.

Status indicators (return str)

Status helpers use the same plain=None auto-detection. Pass plain=False to force color or plain=True for portable ASCII text.

success("ok")  # ✓ ok
error("no")    # ✗ no
warn("hmm")    # ⚠ hmm
info("fyi")    # ℹ fyi

success("ok", plain=True)  # [OK] ok

print_panel(text, title=None, color=None, file=None, **kwargs)

Builds and prints a panel. Non-TTY output is compact by default. Pass plain=True to keep a full ASCII panel or plain=False to force the styled panel.

License

MIT

Metadata

Release files for flashbar 1.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flashbar 1.4.0
File Size Uploaded
flashbar-1.4.0.tar.gz 1.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for flashbar 1.4.0
File Interpreter ABI Platform
flashbar-1.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / flashbar-1.4.0.tar.gz

Download URL flashbar-1.4.0.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
ae8ac54d15a94c193a078a3770cf34e3fdfdd3f35f0d64d84049904008a9173c
BLAKE2b-256 checksum
How to use checksums
fe743d5857c1444156e264209c0674885d1ae310061a1ba2d6e9e2647355b7ab
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.

Transparency log

Release files / flashbar-1.4.0-py3-none-any.whl

Download URL flashbar-1.4.0-py3-none-any.whl
Size 24.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
368f364ea468af08ef034a814ff81e72baaaf12edd5867873629d5db7908384e
BLAKE2b-256 checksum
How to use checksums
cd0d27cf132f1dac2c3498d1e51d4b3f263f395edd55b604a3e74b78d4f8d681
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.4.0 This release

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page