{"id":13495932,"url":"https://github.com/pavdmyt/yaspin","last_synced_at":"2025-12-31T00:53:36.487Z","repository":{"id":38206442,"uuid":"109303405","full_name":"pavdmyt/yaspin","owner":"pavdmyt","description":"A lightweight terminal spinner for Python with safe pipes and redirects 🎁","archived":false,"fork":false,"pushed_at":"2024-11-17T17:31:37.000Z","size":1717,"stargazers_count":827,"open_issues_count":13,"forks_count":38,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-03T11:01:49.578Z","etag":null,"topics":["awesome","cli","cli-utilities","console","easy-to-use","loader","python","python-library","spinner","terminal","unix","utilities"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/yaspin/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pavdmyt.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.rst","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"buy_me_a_coffee":"pavdmyt"}},"created_at":"2017-11-02T18:27:09.000Z","updated_at":"2025-04-02T03:53:12.000Z","dependencies_parsed_at":"2023-02-06T05:31:00.066Z","dependency_job_id":"194dbba4-340d-44b2-a401-ea3941da3e1c","html_url":"https://github.com/pavdmyt/yaspin","commit_stats":{"total_commits":378,"total_committers":21,"mean_commits":18.0,"dds":0.3756613756613757,"last_synced_commit":"61a24e68f2551b8d2c23d623b76e6012f68413b9"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavdmyt%2Fyaspin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavdmyt%2Fyaspin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavdmyt%2Fyaspin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavdmyt%2Fyaspin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pavdmyt","download_url":"https://codeload.github.com/pavdmyt/yaspin/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103865,"owners_count":21048245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["awesome","cli","cli-utilities","console","easy-to-use","loader","python","python-library","spinner","terminal","unix","utilities"],"created_at":"2024-07-31T19:01:39.849Z","updated_at":"2025-12-31T00:53:36.480Z","avatar_url":"https://github.com/pavdmyt.png","language":"Python","funding_links":["https://buymeacoffee.com/pavdmyt"],"categories":["Python"],"sub_categories":[],"readme":"![logo](https://raw.githubusercontent.com/pavdmyt/yaspin/master/static/logo_80.png)\n\n# `yaspin`: Yet Another Terminal Spinner for Python\n\n---\n\n[![Coverage](https://codecov.io/gh/pavdmyt/yaspin/branch/master/graph/badge.svg)](https://codecov.io/gh/pavdmyt/yaspin)\n[![pypi](https://img.shields.io/pypi/v/yaspin.svg)](https://pypi.org/project/yaspin/)\n[![Versions](https://img.shields.io/pypi/pyversions/yaspin.svg)](https://pypi.org/project/yaspin/)\n\n[![Wheel](https://img.shields.io/pypi/wheel/yaspin.svg)](https://pypi.org/project/yaspin/)\n[![Examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg)](https://github.com/pavdmyt/yaspin/tree/master/examples)\n[![DownloadsTot](https://static.pepy.tech/badge/yaspin)](https://pepy.tech/project/yaspin)\n[![DownloadsW](https://static.pepy.tech/badge/yaspin/week)](https://pepy.tech/project/yaspin)\n\n`Yaspin` provides a full-featured terminal spinner to show the progress during long-hanging operations.\n\n![demo](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/demo.gif)\n\nIt is easy to integrate into existing codebase by using it as a [context manager](https://docs.python.org/3/reference/datamodel.html#context-managers)\nor as a function [decorator](https://www.thecodeship.com/patterns/guide-to-python-function-decorators/):\n\n```python\nimport time\nfrom yaspin import yaspin\n\n# Context manager:\nwith yaspin():\n    time.sleep(3)  # time consuming code\n\n# Function decorator:\n@yaspin(text=\"Loading...\")\ndef some_operations():\n    time.sleep(3)  # time consuming code\n\nsome_operations()\n```\n\n**Yaspin** also provides an intuitive and powerful API. For example, you can easily summon a shark:\n\n```python\nimport time\nfrom yaspin import yaspin\n\nwith yaspin().white.bold.shark.on_blue as sp:\n    sp.text = \"White bold shark in a blue sea\"\n    time.sleep(5)\n```\n\n![shark](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/shark.gif)\n\n## Features\n\n- Runs at all major **CPython** versions (*3.10*, *3.11*, *3.12*, *3.13*, *3.14*), **PyPy**\n- Supports all (70+) spinners from [cli-spinners](https://github.com/sindresorhus/cli-spinners)\n- Supports all *colors*, *highlights*, *attributes* and their mixes from [termcolor](https://pypi.org/project/termcolor/) library\n- Easy to combine with other command-line libraries, e.g. [prompt-toolkit](https://github.com/jonathanslenders/python-prompt-toolkit/)\n- Flexible API, easy to integrate with existing code\n- User-friendly API for handling POSIX [signals](https://www.computerhope.com/unix/signals.htm)\n- Safe **pipes** and **redirects**:\n\n```bash\n$ python script_that_uses_yaspin.py \u003e script.log\n$ python script_that_uses_yaspin.py | grep ERROR\n```\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Basic Example](#basic-example)\n  - [Spinners from cli-spinners](#run-any-spinner-from-cli-spinners)\n  - [Colors](#any-colour-you-like-)\n  - [Advanced colors usage](#advanced-colors-usage)\n  - [Building custom spinners](#run-any-spinner-you-want)\n  - [Changing spinner properties on the fly](#change-spinner-properties-on-the-fly)\n  - [Timer](#spinner-with-timer)\n  - [Custom streams](#custom-streams)\n  - [Custom Ellipsis](#custom-ellipsis)\n  - [Dynamic text](#dynamic-text)\n  - [Writing messages](#writing-messages)\n  - [Integration with other libraries](#integration-with-other-libraries)\n  - [Handling POSIX signals](#handling-posix-signals)\n  - [Injecting spinner into a function](#injecting-spinner-into-a-function)\n- [Development](#development)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Installation\n\nFrom [PyPI](https://pypi.org/) using `pip` package manager:\n\n```bash\npip install --upgrade yaspin\n```\n\nOr install the latest sources from GitHub:\n\n```bash\npip install https://github.com/pavdmyt/yaspin/archive/master.zip\n```\n\n## Usage\n\n### Basic Example\n\n![basic_example](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/basic_example.gif)\n\n```python\nimport time\nfrom random import randint\nfrom yaspin import yaspin\n\nwith yaspin(text=\"Loading\", color=\"yellow\") as spinner:\n    time.sleep(2)  # time consuming code\n\n    success = randint(0, 1)\n    if success:\n        spinner.ok(\"✅ \")\n    else:\n        spinner.fail(\"💥 \")\n```\n\nIt is also possible to control spinner manually:\n\n```python\nimport time\nfrom yaspin import yaspin\n\nspinner = yaspin()\nspinner.start()\n\ntime.sleep(3)  # time consuming tasks\n\nspinner.stop()\n```\n\n### Run any spinner from [cli-spinners](https://github.com/sindresorhus/cli-spinners)\n\n![cli_spinners](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/cli_spinners.gif)\n\n```python\nimport time\nfrom yaspin import yaspin\nfrom yaspin.spinners import Spinners\n\nwith yaspin(Spinners.earth, text=\"Earth\") as sp:\n    time.sleep(2)                # time consuming code\n\n    # change spinner\n    sp.spinner = Spinners.moon\n    sp.text = \"Moon\"\n\n    time.sleep(2)                # time consuming code\n```\n\n### Any Colour You Like [🌈](https://en.wikipedia.org/wiki/Any_Colour_You_Like)\n\n![basic_colors](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/basic_colors.gif)\n\n```python\nimport time\nfrom yaspin import yaspin\n\nwith yaspin(text=\"Colors!\") as sp:\n    # Support all basic termcolor text colors\n    colors = (\"red\", \"green\", \"yellow\", \"blue\", \"magenta\", \"cyan\", \"white\")\n\n    for color in colors:\n        sp.color, sp.text = color, color\n        time.sleep(1)\n```\n\n### Advanced colors usage\n\n![advanced_colors](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/advanced_colors.gif)\n\n```python\nimport time\nfrom yaspin import yaspin\nfrom yaspin.spinners import Spinners\n\ntext = \"Bold blink magenta spinner on cyan color\"\nwith yaspin().bold.blink.magenta.bouncingBall.on_cyan as sp:\n    sp.text = text\n    time.sleep(3)\n\n# The same result can be achieved by passing arguments directly\nwith yaspin(\n    Spinners.bouncingBall,\n    color=\"magenta\",\n    on_color=\"on_cyan\",\n    attrs=[\"bold\", \"blink\"],\n) as sp:\n    sp.text = text\n    time.sleep(3)\n```\n\n### Run any spinner you want\n\n![custom_spinners](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/custom_spinners.gif)\n\n```python\nimport time\nfrom yaspin import yaspin, Spinner\n\n# Compose new spinners with custom frame sequence and interval value\nsp = Spinner([\"😸\", \"😹\", \"😺\", \"😻\", \"😼\", \"😽\", \"😾\", \"😿\", \"🙀\"], 200)\n\nwith yaspin(sp, text=\"Cat!\"):\n    time.sleep(3)  # cat consuming code :)\n```\n\n### Change spinner properties on the fly\n\n![sp_properties](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/sp_properties.gif)\n\n```python\nimport time\nfrom yaspin import yaspin\nfrom yaspin.spinners import Spinners\n\nwith yaspin(Spinners.noise, text=\"Noise spinner\") as sp:\n    time.sleep(2)\n\n    sp.spinner = Spinners.arc  # spinner type\n    sp.text = \"Arc spinner\"    # text along with spinner\n    sp.color = \"green\"         # spinner color\n    sp.side = \"right\"          # put spinner to the right\n    sp.reversal = True         # reverse spin direction\n\n    time.sleep(2)\n```\n\n### Spinner with timer\n\n```python\nimport time\nfrom yaspin import yaspin\n\nwith yaspin(text=\"elapsed time\", timer=True) as sp:\n    time.sleep(3.1415)\n    sp.ok()\n```\n\n### Custom streams\n\nBy default, yaspin outputs to `sys.stdout`. You can redirect spinner output to any stream using the `stream` parameter:\n\n```python\nimport sys\nimport time\nfrom io import StringIO\nfrom yaspin import yaspin\n\n# Output to stderr instead of stdout\nwith yaspin(text=\"Processing...\", stream=sys.stderr):\n    time.sleep(2)\n\n# Capture spinner output in a string\noutput_buffer = StringIO()\nwith yaspin(text=\"Buffered output\", stream=output_buffer):\n    time.sleep(1)\n\nprint(\"Captured:\", output_buffer.getvalue())\n```\n\nFor debugging stream lifecycle issues, enable warnings when operations are attempted on closed streams:\n\n```python\nimport time\nfrom yaspin import yaspin\n\n# Enable warnings for debugging (disabled by default)\nwith yaspin(text=\"Debug mode\", warn_on_closed_stream=True):\n    time.sleep(2)\n```\n\nThis is particularly useful in testing environments or when integrating with libraries that manage stream lifecycles.\n\n### Custom Ellipsis\n\nIf the text does not fit in the terminal it gets truncated, you can set a custom ellipsis to signal truncation.\n\n```python\nimport time\nfrom yaspin import yaspin\n\nwith yaspin(text=\"some long text\", ellipsis=\"...\") as sp:\n     time.sleep(2)\n```\n\n### Dynamic text\n\n```python\nimport time\nfrom datetime import datetime\nfrom yaspin import yaspin\n\nclass TimedText:\n    def __init__(self, text):\n        self.text = text\n        self._start = datetime.now()\n\n    def __str__(self):\n        now = datetime.now()\n        delta = now - self._start\n        return f\"{self.text} ({round(delta.total_seconds(), 1)}s)\"\n\nwith yaspin(text=TimedText(\"time passed:\")):\n    time.sleep(3)\n```\n\n### Writing messages\n\n![write_text](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/write_text.gif)\n\nYou should not write any message in the terminal using `print` while spinner is open.\nTo write messages in the terminal without any collision with `yaspin` spinner, a `.write()` method is provided:\n\n```python\nimport time\nfrom yaspin import yaspin\n\nwith yaspin(text=\"Downloading images\", color=\"cyan\") as sp:\n    # task 1\n    time.sleep(1)\n    sp.write(\"\u003e image 1 download complete\")\n\n    # task 2\n    time.sleep(2)\n    sp.write(\"\u003e image 2 download complete\")\n\n    # finalize\n    sp.ok(\"✔\")\n```\n\n### Integration with other libraries\n\n![hide_show](https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/hide_show.gif)\n\nUtilizing `hidden` context manager it is possible to toggle the display of\nthe spinner in order to call custom methods that write to the terminal. This is\nhelpful for allowing easy usage in other frameworks like [prompt-toolkit](https://github.com/jonathanslenders/python-prompt-toolkit/).\nUsing the powerful `print_formatted_text` function allows you even to apply\nHTML formats and CSS styles to the output:\n\n```python\nimport sys\nimport time\n\nfrom yaspin import yaspin\nfrom prompt_toolkit import HTML, print_formatted_text\nfrom prompt_toolkit.styles import Style\n\n# override print with feature-rich ``print_formatted_text`` from prompt_toolkit\nprint = print_formatted_text\n\n# build a basic prompt_toolkit style for styling the HTML wrapped text\nstyle = Style.from_dict({\n    'msg': '#4caf50 bold',\n    'sub-msg': '#616161 italic'\n})\n\n\nwith yaspin(text='Downloading images') as sp:\n    # task 1\n    time.sleep(1)\n    with sp.hidden():\n        print(HTML(\n            u'\u003cb\u003e\u003e\u003c/b\u003e \u003cmsg\u003eimage 1\u003c/msg\u003e \u003csub-msg\u003edownload complete\u003c/sub-msg\u003e'\n        ), style=style)\n\n    # task 2\n    time.sleep(2)\n    with sp.hidden():\n        print(HTML(\n            u'\u003cb\u003e\u003e\u003c/b\u003e \u003cmsg\u003eimage 2\u003c/msg\u003e \u003csub-msg\u003edownload complete\u003c/sub-msg\u003e'\n        ), style=style)\n\n    # finalize\n    sp.ok()\n```\n\n### Handling POSIX [signals](https://www.computerhope.com/unix/signals.htm)\n\nHandling keyboard interrupts (pressing Control-C):\n\n```python\nimport time\n\nfrom yaspin import kbi_safe_yaspin\n\n\nwith kbi_safe_yaspin(text=\"Press Control+C to send SIGINT (Keyboard Interrupt) signal\"):\n    time.sleep(5)  # time consuming code\n```\n\nHandling other types of signals:\n\n```python\nimport os\nimport time\nfrom signal import SIGTERM, SIGUSR1\n\nfrom yaspin import yaspin\nfrom yaspin.signal_handlers import default_handler, fancy_handler\n\n\nsigmap = {SIGUSR1: default_handler, SIGTERM: fancy_handler}\nwith yaspin(sigmap=sigmap, text=\"Handling SIGUSR1 and SIGTERM signals\") as sp:\n    sp.write(\"Send signals using `kill` command\")\n    sp.write(\"E.g. $ kill -USR1 {0}\".format(os.getpid()))\n    time.sleep(20)  # time consuming code\n```\n\n### Injecting spinner into a function\n\nThe `@inject_spinner` decorator provides access to the spinner instance from within the decorated function\nby injecting it as the first argument. This gives you the flexibility to control the spinner's behavior directly.\n\n```python\nimport time\nfrom yaspin import inject_spinner\nfrom yaspin.core import Yaspin\n\n@inject_spinner()\ndef simple_task(spinner: Yaspin, items: list) -\u003e None:\n    for i, _ in enumerate(items, 1):\n        spinner.text = f\"Processing item {i}/{len(items)}\"\n        time.sleep(1)\n    spinner.ok(\"✓\")\n\nsimple_task([\"item1\", \"item2\", \"item3\"])\n```\n\nMore [examples](https://github.com/pavdmyt/yaspin/tree/master/examples).\n\n## Development\n\nClone the repository:\n\n```bash\ngit clone https://github.com/pavdmyt/yaspin.git\n```\n\nInstall dev dependencies:\n\n```bash\npoetry install\n```\n\nLint code:\n\n```bash\nmake lint\n```\n\nFormat code:\n\n```bash\nmake fmt\n```\n\nRun tests:\n\n```bash\nmake test\n```\n\n## Contributing\n\n1. Fork it!\n2. Create your feature branch: `git checkout -b my-new-feature`\n3. Commit your changes: `git commit -m 'Add some feature'`\n4. Push to the branch: `git push origin my-new-feature`\n5. Submit a pull request\n6. Make sure tests are passing\n\n## License\n\n* MIT - Pavlo Dmytrenko; https://twitter.com/pavdmyt\n* Contains data from [cli-spinners](https://github.com/sindresorhus/cli-spinners): MIT License, Copyright (c) Sindre Sorhus sindresorhus@gmail.com (sindresorhus.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpavdmyt%2Fyaspin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpavdmyt%2Fyaspin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpavdmyt%2Fyaspin/lists"}