Skip to content

smorin/thothspinner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

79 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ThothSpinner

PyPI version Python 3.11+ Rich Coverage Documentation License: MIT

A highly configurable progress indicator library for Python, built on Rich. ThothSpinner provides beautiful, composable terminal UI components including spinners, progress bars, timers, and animated messages with shimmer effects.

Demo

ThothSpinner demo

✨ Features

  • 🎨 Modular Components: Mix and match spinner, progress, timer, message, and hint components
  • πŸ”„ State Management: Built-in success/error states with automatic transitions
  • ✨ Shimmer Effects: Eye-catching animation effects for messages
  • 🎯 Thread-Safe: Proper locking for concurrent operations
  • πŸš€ Performance Optimized: Efficient rendering with minimal CPU usage
  • 🎭 Rich Integration: Seamless integration with Rich Console and Live displays
  • πŸ“Ί Textual Support: Native Textual widgets with reactive state management

πŸ“š Documentation

πŸš€ Quick Start

Setup

# Install from PyPI
pip install thothspinner
# or with uv (recommended)
uv add thothspinner

Explore Spinner Styles

ThothSpinner Style Browser

# Preview all 48 spinner styles in the terminal
thothspinner preview

# Preview a specific style
thothspinner preview npm_dots

# Open interactive TUI style browser
thothspinner browse

Basic Usage

from thothspinner import ThothSpinner
from rich.console import Console
from rich.live import Live
import time

console = Console()

# Simple usage with all components
with Live(ThothSpinner(), console=console) as live:
    spinner = live.renderable
    spinner.start()

    # Simulate work with progress
    for i in range(100):
        spinner.update_progress(current=i, total=100)
        time.sleep(0.05)

    spinner.success("Task completed!")

Textual Quick Start

from textual.app import App, ComposeResult
from thothspinner.textual import TextualThothSpinner
import asyncio

class MyApp(App):
    def compose(self) -> ComposeResult:
        yield TextualThothSpinner(
            spinner_style="npm_dots",
            message_text="Processing data",
            message_shimmer=True,
        )

    async def on_mount(self) -> None:
        spinner = self.query_one(TextualThothSpinner)
        spinner.start()
        await asyncio.sleep(2)
        spinner.success("Done!")

MyApp().run()

Run the Examples

# Run all examples (Rich + Textual)
just examples

# Or run by category
just examples-thothspinner    # Rich ThothSpinner examples
just examples-textual         # Textual widget examples

# Or run individual examples
just example-thothspinner-basic
just example-thothspinner-full
just example-progress
just example-timer
just example-message
just example-message-shimmer

πŸ“¦ Installation

Prerequisites

  • Python 3.11+
  • uv package manager (recommended)
  • just command runner (optional)

Install from Source

# Clone the repository
git clone https://github.com/smorin/thothspinner.git
cd thothspinner

# Install with uv (recommended)
uv sync

# Or with pip
pip install -e .

Install from PyPI

pip install thothspinner

# Or with uv (recommended)
uv add thothspinner

🎯 Available Components

Core Components

  • SpinnerComponent: Animated spinners with multiple styles (npm_dots, claude_stars, etc.)
  • ProgressComponent: Progress counters with various formats (percentage, fraction, etc.)
  • TimerComponent: Elapsed time display with flexible formatting
  • MessageComponent: Rotating action words with shimmer effects
  • HintComponent: Static hint text for instructions
  • ThothSpinner: Orchestrator that combines all components

Example Usage

from thothspinner import ThothSpinner
from thothspinner.rich.components import SpinnerComponent, ProgressComponent

# Individual components
spinner = SpinnerComponent(style="claude_stars", color="#FFA500")
progress = ProgressComponent(format={"style": "percentage"}, color="#00FF00")

# Or use the orchestrator for everything
spinner = ThothSpinner(
    spinner_style="npm_dots",
    message_text="Processing data",  # initial rotating message text
    message_shimmer=True,
    progress_format="percentage",
    timer_format="auto",
    hint_text="(esc to cancel)"
)

set_message() updates the current rotating message text. Use set_message_pinned() only when you explicitly want a non-rotating message.

Configuration

ThothSpinner supports both kwargs and dictionary configuration:

# Using kwargs
spinner = ThothSpinner(
    spinner_style="claude_stars",
    message_shimmer=True,
    success_duration=2.0  # Auto-clear after 2 seconds
)

# Using configuration dictionary
config = {
    "defaults": {"color": "#D97706"},
    "elements": {
        "spinner": {"style": "npm_dots"},
        "message": {"shimmer": {"enabled": True, "width": 3}},
        "progress": {"format": {"style": "percentage"}}
    },
    "states": {
        "success": {
            "spinner": {"icon": "βœ“", "color": "#00FF00"},
            "message": {"text": "Complete!"}
        }
    }
}
spinner = ThothSpinner.from_dict(config)

πŸ› οΈ Development

Project Structure

thothspinner/
β”œβ”€β”€ src/thothspinner/       # Source code
β”‚   β”œβ”€β”€ rich/               # Rich-based components
β”‚   β”‚   β”œβ”€β”€ components/     # Individual components
β”‚   β”‚   └── thothspinner.py # Main orchestrator
β”‚   └── textual/            # Textual widgets
β”œβ”€β”€ tests/                  # Test suite (97%+ coverage)
β”œβ”€β”€ docs/                   # Documentation
β”‚   β”œβ”€β”€ thothspinner_rich.md     # Rich API reference
β”‚   β”œβ”€β”€ thothspinner_textual.md  # Textual API reference
β”‚   β”œβ”€β”€ examples/                # Example scripts
β”‚   └── troubleshooting.md       # Troubleshooting guide
β”œβ”€β”€ examples/               # Demo scripts
β”œβ”€β”€ justfile                # Task automation
└── pyproject.toml          # Project configuration

Development Commands

# Format code
just format

# Lint code
just lint

# Type check
just typecheck

# Run tests with coverage
just test-cov

# Security scan (bandit)
just security

# Generate changelog (git-cliff)
just changelog

# Version management
just current-version
just bump-patch
just bump-minor
just bump-major

# Regenerate visual regression snapshots
just update-snapshots

# Run all checks (format, lint, typecheck, security, test)
just all

# Clean build artifacts
just clean

CLI Tools

# Preview all 48 spinner styles
uv run thothspinner preview

# Preview a specific style
uv run thothspinner preview npm_dots

# Open interactive TUI style browser
uv run thothspinner browse

Generating the Demo GIF

# Install GIF generation tools (macOS only, one-time)
just install-readme-animation

# Generate demo.gif
just demo-gif

# Verify it looks right
open docs/images/demo.gif

# Commit and push
git add docs/images/demo.gif
git commit -m "docs: add demo.gif for README"
git push origin main

Testing

The project maintains 97%+ test coverage, including visual regression tests via pytest-textual-snapshot:

# Run tests
just test

# Run tests with coverage report
just test-cov
# Coverage report generated at htmlcov/index.html

# Run specific test file
just test tests/rich/test_spinner.py

# Regenerate visual regression snapshots (Textual widgets)
just update-snapshots

πŸ“– Examples

Basic Progress Bar

from thothspinner import ThothSpinner
from rich.live import Live

with Live(ThothSpinner()) as live:
    spinner = live.renderable
    spinner.start()

    for i in range(100):
        spinner.update_progress(current=i, total=100)
        time.sleep(0.05)

    spinner.success()

File Processing

from pathlib import Path

files = list(Path(".").glob("*.py"))
spinner = ThothSpinner(progress_format="fraction")

with Live(spinner) as live:
    spinner.start()

    for i, file in enumerate(files):
        spinner.set_message(text=f"Processing {file.name}")  # rotating message update
        spinner.update_progress(current=i, total=len(files))
        process_file(file)

    spinner.success(f"Processed {len(files)} files")

Error Handling

with Live(ThothSpinner()) as live:
    spinner = live.renderable
    spinner.start()

    try:
        risky_operation()
        spinner.success("Operation successful")
    except Exception as e:
        spinner.error(f"Operation failed: {e}")

More examples in the Examples Gallery.

πŸ—ΊοΈ Roadmap

Completed Milestones

βœ… M01–M05: Core Rich Components (v0.1.0–v0.5.0)

  • Hint, Spinner, Progress, Timer, and Message components
  • ThothSpinner orchestrator with state management
  • 97%+ test coverage, thread-safe operations with proper locking

βœ… M06: Rich Documentation (v0.6.0)

  • Comprehensive API reference, examples gallery with 20+ examples, troubleshooting guide

βœ… M07–M13: Textual Components & Documentation (v0.7.0–v0.13.0)

  • Full Textual widget set with reactive state management
  • Feature parity with all Rich components
  • Textual examples, integration guides, and API reference

βœ… M15: Progress Bar Format & Animation Smoothing (v1.1.0)

  • Bar format style for Textual ProgressWidget with configurable fill characters
  • Smooth animated transitions when progress values change

βœ… M14: Publishing to PyPI (v1.0.0)

  • PyPI package publication with OIDC trusted publishing
  • GitHub Actions CI/CD pipeline (test matrix, CodeQL, publish)
  • Release automation with git-cliff changelog generation

Releasing

First time? Follow the First-Time Publish Guide for step-by-step OIDC setup and the v1.0.0 publish walkthrough.

For subsequent releases, see the Release Guide. Quick reference:

# 1. Bump version (pick one), then run checks and commit:
just bump-patch          # or bump-minor / bump-major
just all                 # format, lint, typecheck, security, test β€” must all pass
git add pyproject.toml
git commit -m "chore: release v1.2.3"
git push origin main

# 2. Tag and publish (auto-generates changelog, builds, tags, pushes β†’ triggers CI β†’ PyPI)
just release 1.2.3

Releases are published automatically via OIDC trusted publishing β€” no API tokens required. See RELEASE.md for OIDC setup, CI/CD pipeline details, and troubleshooting.

🀝 Contributing

Contributions are welcome! See CONTRIBUTING.md for full details. Quick summary:

  1. Check the MILESTONES.md for current tasks
  2. Follow the established code patterns
  3. Maintain test coverage above 90%
  4. Use the development toolchain (just commands)
  5. Write tests for new features
  6. Update documentation as needed

For milestone-specific work, reference tasks in the milestone documents (M01.md, M02.md, etc.).

Zero-Setup with GitHub Codespaces

A .devcontainer config is included β€” open in Codespaces or VS Code Dev Containers for an instant, pre-configured development environment.

πŸ“„ License

MIT License - See LICENSE file for details.

πŸ™ Acknowledgments

  • Built on the excellent Rich and Textual libraries by Will McGugan
  • Inspired by various terminal UI libraries including ora, cli-spinners, and progress
  • Name inspired by Thoth, ancient Egyptian deity of wisdom and writing
  • Development patterns influenced by Rich's battle-tested implementation

πŸ’¬ Support

For issues, questions, or suggestions:


Current Version: 1.0.0 | Python: 3.11+ | Coverage: 97%+ | Rich Docs | Textual Docs

About

No description, website, or topics provided.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors