A minimal, dependency-free spinner for Python CLI applications with rich customization options.
- π Rich Color Options - 16 standard colors, RGB support, and special color cycles (rainbow, unicorn)
- π¨ Unicode & ASCII Support - Automatically falls back to ASCII in incompatible terminals
- π Context Manager - Clean, Pythonic usage with automatic cleanup
- π― Multiple End States - Success, failure, warning, and info completion states
- π οΈ Highly Customizable - Prefix, suffix, indent, and custom symbols
- π€ CI Aware - Automatically disables in CI environments
- πͺΆ Zero Dependencies - Lightweight with no external dependencies
- β‘ Thread Safe - Non-blocking animation using threading
Install from PyPI using pip:
pip install zero-spinnerOr using uv:
uv add zero-spinnerOr using poetry
poetry add zero-spinnerfrom yeeti.zero_spinner import spinner
# Basic usage
spin = spinner('Loading...').start()
# ... do work ...
spin.succeed()
# Context manager (recommended)
with spinner('Processing'):
# ... do work ...
passfrom yeeti.zero_spinner import spinner
# Simple spinner
with spinner('Loading data...'):
# Your code here
import time
time.sleep(2)# Standard colors
with spinner('Processing...', color='red'):
# ... work ...
pass
# RGB colors
with spinner('RGB spinner...', color='rgb(255,105,180)'):
# ... work ...
pass
# Special color cycles
spin = spinner('Rainbow effect...')
spin.color = spin._colors.rainbow # or rainbow_bright, rainbow_rgb, unicorn, unicorn_rgb
spin.start()
# ... work ...
spin.succeed()from yeeti.zero_spinner import spinner
spin = spinner('Processing...').start()
try:
# ... work that might fail ...
spin.succeed('Process completed successfully!')
except Exception as e:
spin.fail(f'Process failed: {str(e)}')
# Other states
spin = spinner('Checking...').start()
spin.warn('This is just a warning')
# or
spin.info('For your information')# All customization options
with spinner(
text='Main text',
prefix_text='[INFO] ',
suffix_text=' (processing)',
color='magenta',
hide_cursor=True,
indent=2,
stream=sys.stdout, # defaults to stdout
disabled=False # set to True to disable
):
# ... work ...
passThe spinner automatically ends with success if no exception occurs:
# Automatically succeeds
with spinner('Task 1'):
# ... work ...
pass
# Automatically fails
with spinner('Task 2'):
raise Exception('Something went wrong!')Creates and returns a new Spinner instance.
spinner(
text='',
prefix_text='',
suffix_text='',
color='cyan',
hide_cursor=True,
indent=0,
stream=None,
disabled=False,
spinner=None,
symbols=None,
colors=None
) -> SpinnerParameters:
text(str): Main text displayed next to spinnerprefix_text(str): Text before spinnersuffix_text(str): Text after spinner and main textcolor(str): Spinner color (standard name or 'rgb(r,g,b)')hide_cursor(bool): Hide terminal cursor while spinningindent(int): Number of spaces to indentstream(TextIO): Output stream (defaults to stdout)disabled(bool): Disable spinner (useful for testing)spinner(SpinnerDefinition): Custom spinner frames/intervalsymbols(Symbols): Custom completion symbolscolors(Colors): Custom color definitions
start(text=None)- Start spinningstop()- Stop spinningsucceed(text=None)- Stop with success symbolfail(text=None)- Stop with failure symbolwarn(text=None)- Stop with warning symbolinfo(text=None)- Stop with info symbolend(symbol, color=None, text=None)- Stop with custom symbol
text(str): Main textcolor(str): Current color
Standard colors:
black,red,green,yellow,blue,magenta,cyan,whitebright_black,bright_red,bright_green,bright_yellow,bright_blue,bright_magenta,bright_cyan,bright_white
Special color cycles:
random- Randomly selected colorrainbow- Standard rainbow colorsrainbow_bright- Bright rainbow colorsrainbow_rgb- Smooth RGB rainbowunicorn- Unicorn-themed colorsunicorn_rgb- Smooth RGB unicorn colors
RGB colors: rgb(255,0,0) (red) format
Completion symbols automatically adapt to terminal capabilities:
- Success: β (+ in ASCII mode)
- Failure: β (X in ASCII mode)
- Warning: β (! in ASCII mode)
- Info: βΉ (i in ASCII mode)
from yeeti.zero_spinner import spinner, SpinnerDefinition
custom_spinner = SpinnerDefinition()
custom_spinner.frames = ['-', '=', 'β‘', '=', '-', ' ']
custom_spinner.interval = 100 # ms
# or simply
# custom_spinner = SpinnerDefinition(['-', '=', 'β‘', '=', '-', ' '], 100)
with spinner('Custom animation...', spinner=custom_spinner):
# ... work ...
passspin = spinner('Processing items...').start()
for i, item in enumerate(items):
spin.text = f'Processing items... ({i+1}/{len(items)})'
# Process item
time.sleep(0.1)
spin.succeed('All items processed!')WARNING Currently not working!
# Nested spinners
with spinner('Main process') as spin:
with spinner('Subprocess 1', indent=2) as sub1:
# ... work ...
sub1.succeed()
with spinner('Subprocess 2', indent=2) as sub2:
# ... work ...
sub2.succeed()
spin.succeed()Zero Spinner works in:
- Unix terminals (Linux, macOS)
- Windows Command Prompt and PowerShell
- IDE terminals (VS Code, PyCharm, etc.)
- SSH sessions
- CI environments (automatically disabled)
The library automatically detects Unicode support and falls back to ASCII characters when needed.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.
Β© 2025 Yeeti