Skip to main content

logo

yaspin: Yet Another Terminal Spinner for Python


Coverage pypi Versions Ask DeepWiki

Wheel Examples DownloadsTot DownloadsW

Yaspin provides a full-featured terminal spinner to show the progress during long-hanging operations.

demo

It is easy to integrate into existing codebase by using it as a context manager or as a function decorator:

import time
from yaspin import yaspin

# Context manager:
with yaspin():
    time.sleep(3)  # time consuming code

# Function decorator:
@yaspin(text="Loading...")
def some_operations():
    time.sleep(3)  # time consuming code

some_operations()

Yaspin also provides an intuitive and powerful API. For example, you can easily summon a shark:

import time
from yaspin import yaspin

with yaspin().white.bold.shark.on_blue as sp:
    sp.text = "White bold shark in a blue sea"
    time.sleep(5)

shark

Features

  • Runs at all major CPython versions (3.10, 3.11, 3.12, 3.13, 3.14), PyPy
  • Supports all (70+) spinners from cli-spinners
  • Supports all colors, highlights, attributes and their mixes from termcolor library
  • Easy to combine with other command-line libraries, e.g. prompt-toolkit
  • Flexible API, easy to integrate with existing code
  • User-friendly API for handling POSIX signals
  • Safe pipes and redirects:
$ python script_that_uses_yaspin.py > script.log
$ python script_that_uses_yaspin.py | grep ERROR

Table of Contents

Installation

From PyPI using pip package manager:

pip install --upgrade yaspin

Or install the latest sources from GitHub:

pip install https://github.com/pavdmyt/yaspin/archive/master.zip

Usage

Basic Example

basic_example

import time
from random import randint
from yaspin import yaspin

with yaspin(text="Loading", color="yellow") as spinner:
    time.sleep(2)  # time consuming code

    success = randint(0, 1)
    if success:
        spinner.ok("✅ ")
    else:
        spinner.fail("💥 ")

It is also possible to control spinner manually:

import time
from yaspin import yaspin

spinner = yaspin()
spinner.start()

time.sleep(3)  # time consuming tasks

spinner.stop()

Run any spinner from cli-spinners

cli_spinners

import time
from yaspin import yaspin
from yaspin.spinners import Spinners

with yaspin(Spinners.earth, text="Earth") as sp:
    time.sleep(2)                # time consuming code

    # change spinner
    sp.spinner = Spinners.moon
    sp.text = "Moon"

    time.sleep(2)                # time consuming code

Any Colour You Like 🌈

basic_colors

import time
from yaspin import yaspin

with yaspin(text="Colors!") as sp:
    # Support all basic termcolor text colors
    colors = ("red", "green", "yellow", "blue", "magenta", "cyan", "white")

    for color in colors:
        sp.color, sp.text = color, color
        time.sleep(1)

Advanced colors usage

advanced_colors

import time
from yaspin import yaspin
from yaspin.spinners import Spinners

text = "Bold blink magenta spinner on cyan color"
with yaspin().bold.blink.magenta.bouncingBall.on_cyan as sp:
    sp.text = text
    time.sleep(3)

# The same result can be achieved by passing arguments directly
with yaspin(
    Spinners.bouncingBall,
    color="magenta",
    on_color="on_cyan",
    attrs=["bold", "blink"],
) as sp:
    sp.text = text
    time.sleep(3)

Run any spinner you want

custom_spinners

import time
from yaspin import yaspin, Spinner

# Compose new spinners with custom frame sequence and interval value
sp = Spinner(["😸", "😹", "😺", "😻", "😼", "😽", "😾", "😿", "🙀"], 200)

with yaspin(sp, text="Cat!"):
    time.sleep(3)  # cat consuming code :)

Change spinner properties on the fly

sp_properties

import time
from yaspin import yaspin
from yaspin.spinners import Spinners

with yaspin(Spinners.noise, text="Noise spinner") as sp:
    time.sleep(2)

    sp.spinner = Spinners.arc  # spinner type
    sp.text = "Arc spinner"    # text along with spinner
    sp.color = "green"         # spinner color
    sp.side = "right"          # put spinner to the right
    sp.reversal = True         # reverse spin direction

    time.sleep(2)

Spinner with timer

import time
from yaspin import yaspin

with yaspin(text="elapsed time", timer=True) as sp:
    time.sleep(3.1415)
    sp.ok()

To omit the fractions of a second, pass a format string with one automatic replacement field. It receives the elapsed time as a datetime.timedelta. Use a second field to receive hundredths of a second.

with yaspin(text="elapsed time", timer=" ({})") as sp:
    time.sleep(3.1415)
    sp.ok()

The default timer=True format is ({}.{:02.0f}). Custom formats must contain one or two automatic replacement fields.

Custom streams

By default, yaspin outputs to sys.stdout. You can redirect spinner output to any stream using the stream parameter:

import sys
import time
from io import StringIO
from yaspin import yaspin

# Output to stderr instead of stdout
with yaspin(text="Processing...", stream=sys.stderr):
    time.sleep(2)

# Capture spinner output in a string
output_buffer = StringIO()
with yaspin(text="Buffered output", stream=output_buffer):
    time.sleep(1)

print("Captured:", output_buffer.getvalue())

For debugging stream lifecycle issues, enable warnings when operations are attempted on closed streams:

import time
from yaspin import yaspin

# Enable warnings for debugging (disabled by default)
with yaspin(text="Debug mode", warn_on_closed_stream=True):
    time.sleep(2)

This is particularly useful in testing environments or when integrating with libraries that manage stream lifecycles.

Custom Ellipsis

If the text does not fit in the terminal it gets truncated, you can set a custom ellipsis to signal truncation.

import time
from yaspin import yaspin

with yaspin(text="some long text", ellipsis="...") as sp:
     time.sleep(2)

Dynamic text

import time
from datetime import datetime
from yaspin import yaspin

class TimedText:
    def __init__(self, text):
        self.text = text
        self._start = datetime.now()

    def __str__(self):
        now = datetime.now()
        delta = now - self._start
        return f"{self.text} ({round(delta.total_seconds(), 1)}s)"

with yaspin(text=TimedText("time passed:")):
    time.sleep(3)

Writing messages

write_text

You should not write any message in the terminal using print while spinner is open. To write messages in the terminal without any collision with yaspin spinner, a .write() method is provided:

import time
from yaspin import yaspin

with yaspin(text="Downloading images", color="cyan") as sp:
    # task 1
    time.sleep(1)
    sp.write("> image 1 download complete")

    # task 2
    time.sleep(2)
    sp.write("> image 2 download complete")

    # finalize
    sp.ok("✔")

Integration with other libraries

hide_show

Utilizing hidden context manager it is possible to toggle the display of the spinner in order to call custom methods that write to the terminal. This is helpful for allowing easy usage in other frameworks like prompt-toolkit. Using the powerful print_formatted_text function allows you even to apply HTML formats and CSS styles to the output:

import sys
import time

from yaspin import yaspin
from prompt_toolkit import HTML, print_formatted_text
from prompt_toolkit.styles import Style

# override print with feature-rich ``print_formatted_text`` from prompt_toolkit
print = print_formatted_text

# build a basic prompt_toolkit style for styling the HTML wrapped text
style = Style.from_dict({
    'msg': '#4caf50 bold',
    'sub-msg': '#616161 italic'
})


with yaspin(text='Downloading images') as sp:
    # task 1
    time.sleep(1)
    with sp.hidden():
        print(HTML(
            u'<b>></b> <msg>image 1</msg> <sub-msg>download complete</sub-msg>'
        ), style=style)

    # task 2
    time.sleep(2)
    with sp.hidden():
        print(HTML(
            u'<b>></b> <msg>image 2</msg> <sub-msg>download complete</sub-msg>'
        ), style=style)

    # finalize
    sp.ok()

Handling POSIX signals

Handling keyboard interrupts (pressing Control-C):

import time

from yaspin import kbi_safe_yaspin


with kbi_safe_yaspin(text="Press Control+C to send SIGINT (Keyboard Interrupt) signal"):
    time.sleep(5)  # time consuming code

Handling other types of signals:

import os
import time
from signal import SIGTERM, SIGUSR1

from yaspin import yaspin
from yaspin.signal_handlers import default_handler, fancy_handler


sigmap = {SIGUSR1: default_handler, SIGTERM: fancy_handler}
with yaspin(sigmap=sigmap, text="Handling SIGUSR1 and SIGTERM signals") as sp:
    sp.write("Send signals using `kill` command")
    sp.write("E.g. $ kill -USR1 {0}".format(os.getpid()))
    time.sleep(20)  # time consuming code

Injecting spinner into a function

The @inject_spinner decorator provides access to the spinner instance from within the decorated function by injecting it as the first argument. This gives you the flexibility to control the spinner's behavior directly.

import time
from yaspin import inject_spinner
from yaspin.core import Yaspin

@inject_spinner()
def simple_task(spinner: Yaspin, items: list) -> None:
    for i, _ in enumerate(items, 1):
        spinner.text = f"Processing item {i}/{len(items)}"
        time.sleep(1)
    spinner.ok("✓")

simple_task(["item1", "item2", "item3"])

More examples.

Development

Clone the repository:

git clone https://github.com/pavdmyt/yaspin.git

Install dev dependencies:

poetry install

Lint code:

make lint

Format code:

make fmt

Run tests:

make test

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -m 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request
  6. Make sure tests are passing

License

Release files for yaspin 3.5.1

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

Source distribution (sdist)

Source distribution for yaspin 3.5.1
File Size Uploaded
yaspin-3.5.1.tar.gz 44.5 kB Details

Built distribution (wheel)

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

Total release size: 67.4 kB

Release files / yaspin-3.5.1.tar.gz

Download URL yaspin-3.5.1.tar.gz
Size 44.5 kB
Tags Source
SHA-256 checksum
How to use checksums
5cb55fb774eae3543fdd30b5958c46e348dfd316a8b289c9f8db2c6f8a511846
BLAKE2b-256 checksum
How to use checksums
37204b44e31e5a1bfe09624267656dc02c31fe920e35e81697722dd45caac9f1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.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 Sep 18, 2026.

Transparency log

Release files / yaspin-3.5.1-py3-none-any.whl

Download URL yaspin-3.5.1-py3-none-any.whl
Size 22.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
193ef981f0796a93f77d91221dd19bd2c83b0f6a26f43edbc0507c457c54c1cb
BLAKE2b-256 checksum
How to use checksums
535474737771bfc9b945b7e11968100c096fc2d1af075644e43d5fa51ab773a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.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 Sep 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

3.5.1 This release

2 release files

3.5.0

2 release files

3.4.0

2 release files

3.3.0

2 release files

3.2.0

2 release files

3.1.0

2 release files

3.0.2

2 release files

3.0.1

2 release files

3.0.0

2 release files

2.5.0

2 release files

2.4.0

2 release files

2.3.0

2 release files

2.2.0

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.5.0

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.18.0

2 release files

0.16.0

2 release files

0.14.3

2 release files

0.14.2

2 release files

0.14.1

2 release files

0.13.0

2 release files

0.12.0

2 release files

0.11.1

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.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