Remove yaspin and termcolor

Termcolor is a dependency of yaspin. Yaspin isn't used
anywhere in pipenv. There is a patch for it, and there is also
vistir dependency for it, but we have our own spinner.

Side note, we can consider using rich, which pip uses.
This commit is contained in:
Oz N Tiram
2022-08-15 22:26:19 +02:00
parent 77bc74dce5
commit bc56a44f4f
15 changed files with 0 additions and 2994 deletions
-451
View File
@@ -1,451 +0,0 @@
|Logo|
=====================================================================
``yaspin``: **Y**\ et **A**\ nother Terminal **Spin**\ ner for Python
=====================================================================
|Build Status| |Coverage| |Codacy| |pyup| |black-fmt|
|pypi| |Versions| |Wheel| |Examples|
|DownloadsTot| |DownloadsW|
``Yaspin`` provides a full-featured terminal spinner to show the progress during long-hanging operations.
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/demo.gif
It is easy to integrate into existing codebase by using it as a `context manager`_
or as a function `decorator`_:
.. code:: python
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:
.. code:: python
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)
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/shark.gif
Features
--------
- Runs at all major **CPython** versions (*3.6*, *3.7*, *3.8*, *3.9*), **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**:
.. code-block:: bash
$ python script_that_uses_yaspin.py > script.log
$ python script_that_uses_yaspin.py | grep ERROR
Installation
------------
From `PyPI`_ using ``pip`` package manager:
.. code-block:: bash
pip install --upgrade yaspin
Or install the latest sources from GitHub:
.. code-block:: bash
pip install https://github.com/pavdmyt/yaspin/archive/master.zip
Usage
-----
Basic Example
/////////////
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/basic_example.gif
.. code:: python
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:
.. code:: python
import time
from yaspin import yaspin
spinner = yaspin()
spinner.start()
time.sleep(3) # time consuming tasks
spinner.stop()
Run any spinner from `cli-spinners`_
////////////////////////////////////
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/cli_spinners.gif
.. code:: python
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 `🌈`_
/////////////////////////
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/basic_colors.gif
.. code:: python
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
/////////////////////
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/advanced_colors.gif
.. code:: python
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
////////////////////////
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/custom_spinners.gif
.. code:: python
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
////////////////////////////////////
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/sp_properties.gif
.. code:: python
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
//////////////////
.. code:: python
import time
from yaspin import yaspin
with yaspin(text="elapsed time", timer=True) as sp:
time.sleep(3.1415)
sp.ok()
Writing messages
////////////////
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/write_text.gif
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:
.. code:: python
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
////////////////////////////////
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/hide_show.gif
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:
.. code:: python
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):
.. code:: python
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:
.. code:: python
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
More `examples`_.
Development
-----------
Clone the repository:
.. code-block:: bash
git clone https://github.com/pavdmyt/yaspin.git
Install dev dependencies:
.. code-block:: bash
poetry install
# if you don't have poetry installed:
pip install -r requirements.txt
Lint code:
.. code-block:: bash
make lint
Format code:
.. code-block:: bash
make black-fmt
Run tests:
.. code-block:: bash
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
-------
* MIT - Pavlo Dmytrenko; https://twitter.com/pavdmyt
* Contains data from `cli-spinners`_: MIT License, Copyright (c) Sindre Sorhus sindresorhus@gmail.com (sindresorhus.com)
.. |Logo| image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/static/logo_80.png
:alt: yaspin Logo
.. |Build Status| image:: https://travis-ci.org/pavdmyt/yaspin.svg?branch=master
:target: https://travis-ci.org/pavdmyt/yaspin
.. |Coverage| image:: https://codecov.io/gh/pavdmyt/yaspin/branch/master/graph/badge.svg
:target: https://codecov.io/gh/pavdmyt/yaspin
.. |Codacy| image:: https://api.codacy.com/project/badge/Grade/797c7772d0d3467c88a5e2e9dc79ec98
:target: https://www.codacy.com/app/pavdmyt/yaspin?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=pavdmyt/yaspin&amp;utm_campaign=Badge_Grade
.. |pypi| image:: https://img.shields.io/pypi/v/yaspin.svg
:target: https://pypi.org/project/yaspin/
.. |Versions| image:: https://img.shields.io/pypi/pyversions/yaspin.svg
:target: https://pypi.org/project/yaspin/
.. |Wheel| image:: https://img.shields.io/pypi/wheel/yaspin.svg
:target: https://pypi.org/project/yaspin/
.. |Examples| image:: https://img.shields.io/badge/learn%20by-examples-0077b3.svg
:target: https://github.com/pavdmyt/yaspin/tree/master/examples
.. |pyup| image:: https://pyup.io/repos/github/pavdmyt/yaspin/shield.svg
:target: https://pyup.io/repos/github/pavdmyt/yaspin/
.. |black-fmt| image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/ambv/black
.. |DownloadsTot| image:: https://pepy.tech/badge/yaspin
:target: https://pepy.tech/project/yaspin
.. |DownloadsW| image:: https://pepy.tech/badge/yaspin/week
:target: https://pepy.tech/project/yaspin
.. _context manager: https://docs.python.org/3/reference/datamodel.html#context-managers
.. _decorator: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
.. _cli-spinners: https://github.com/sindresorhus/cli-spinners
.. _termcolor: https://pypi.org/project/termcolor/
.. _PyPI: https://pypi.org/
.. _🌈: https://en.wikipedia.org/wiki/Any_Colour_You_Like
.. _examples: https://github.com/pavdmyt/yaspin/tree/master/examples
.. _prompt-toolkit: https://github.com/jonathanslenders/python-prompt-toolkit/
.. _signals: https://www.computerhope.com/unix/signals.htm
-20
View File
@@ -1,20 +0,0 @@
Copyright (c) 2008-2011 Volvox Development Team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-168
View File
@@ -1,168 +0,0 @@
# coding: utf-8
# Copyright (c) 2008-2011 Volvox Development Team
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Author: Konstantin Lepa <konstantin.lepa@gmail.com>
"""ANSII Color formatting for output in terminal."""
from __future__ import print_function
import os
__ALL__ = [ 'colored', 'cprint' ]
VERSION = (1, 1, 0)
ATTRIBUTES = dict(
list(zip([
'bold',
'dark',
'',
'underline',
'blink',
'',
'reverse',
'concealed'
],
list(range(1, 9))
))
)
del ATTRIBUTES['']
HIGHLIGHTS = dict(
list(zip([
'on_grey',
'on_red',
'on_green',
'on_yellow',
'on_blue',
'on_magenta',
'on_cyan',
'on_white'
],
list(range(40, 48))
))
)
COLORS = dict(
list(zip([
'grey',
'red',
'green',
'yellow',
'blue',
'magenta',
'cyan',
'white',
],
list(range(30, 38))
))
)
RESET = '\033[0m'
def colored(text, color=None, on_color=None, attrs=None):
"""Colorize text.
Available text colors:
red, green, yellow, blue, magenta, cyan, white.
Available text highlights:
on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white.
Available attributes:
bold, dark, underline, blink, reverse, concealed.
Example:
colored('Hello, World!', 'red', 'on_grey', ['blue', 'blink'])
colored('Hello, World!', 'green')
"""
if os.getenv('ANSI_COLORS_DISABLED') is None:
fmt_str = '\033[%dm%s'
if color is not None:
text = fmt_str % (COLORS[color], text)
if on_color is not None:
text = fmt_str % (HIGHLIGHTS[on_color], text)
if attrs is not None:
for attr in attrs:
text = fmt_str % (ATTRIBUTES[attr], text)
text += RESET
return text
def cprint(text, color=None, on_color=None, attrs=None, **kwargs):
"""Print colorize text.
It accepts arguments of print function.
"""
print((colored(text, color, on_color, attrs)), **kwargs)
if __name__ == '__main__':
print('Current terminal type: %s' % os.getenv('TERM'))
print('Test basic colors:')
cprint('Grey color', 'grey')
cprint('Red color', 'red')
cprint('Green color', 'green')
cprint('Yellow color', 'yellow')
cprint('Blue color', 'blue')
cprint('Magenta color', 'magenta')
cprint('Cyan color', 'cyan')
cprint('White color', 'white')
print(('-' * 78))
print('Test highlights:')
cprint('On grey color', on_color='on_grey')
cprint('On red color', on_color='on_red')
cprint('On green color', on_color='on_green')
cprint('On yellow color', on_color='on_yellow')
cprint('On blue color', on_color='on_blue')
cprint('On magenta color', on_color='on_magenta')
cprint('On cyan color', on_color='on_cyan')
cprint('On white color', color='grey', on_color='on_white')
print('-' * 78)
print('Test attributes:')
cprint('Bold grey color', 'grey', attrs=['bold'])
cprint('Dark red color', 'red', attrs=['dark'])
cprint('Underline green color', 'green', attrs=['underline'])
cprint('Blink yellow color', 'yellow', attrs=['blink'])
cprint('Reversed blue color', 'blue', attrs=['reverse'])
cprint('Concealed Magenta color', 'magenta', attrs=['concealed'])
cprint('Bold underline reverse cyan color', 'cyan',
attrs=['bold', 'underline', 'reverse'])
cprint('Dark blink concealed white color', 'white',
attrs=['dark', 'blink', 'concealed'])
print(('-' * 78))
print('Test mixing:')
cprint('Underline red on grey color', 'red', 'on_grey',
['underline'])
cprint('Reversed green on red color', 'green', 'on_red', ['reverse'])
-2
View File
@@ -24,10 +24,8 @@ pythonfinder==1.2.10
requirementslib==1.6.9
shellingham==1.4.0
six==1.16.0
termcolor==1.1.0
toml==0.10.2
tomli==1.1.0
tomlkit==0.9.2
vistir==0.5.6
wheel==0.36.2
yaspin==2.0.0
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2021 Pavlo Dmytrenko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-7
View File
@@ -1,7 +0,0 @@
# :copyright: (c) 2021 by Pavlo Dmytrenko.
# :license: MIT, see LICENSE for more details.
from .api import kbi_safe_yaspin, yaspin
from .base_spinner import Spinner
__all__ = ("yaspin", "kbi_safe_yaspin", "Spinner")
-89
View File
@@ -1,89 +0,0 @@
# :copyright: (c) 2021 by Pavlo Dmytrenko.
# :license: MIT, see LICENSE for more details.
"""
yaspin.api
~~~~~~~~~~
This module implements the Yaspin API.
"""
import signal
from .core import Yaspin
from .signal_handlers import default_handler
def yaspin(*args, **kwargs):
"""Display spinner in stdout.
Can be used as a context manager or as a function decorator.
Arguments:
spinner (base_spinner.Spinner, optional): Spinner object to use.
text (str, optional): Text to show along with spinner.
color (str, optional): Spinner color.
on_color (str, optional): Color highlight for the spinner.
attrs (list, optional): Color attributes for the spinner.
reversal (bool, optional): Reverse spin direction.
side (str, optional): Place spinner to the right or left end
of the text string.
sigmap (dict, optional): Maps POSIX signals to their respective
handlers.
timer (bool, optional): Prints a timer showing the elapsed time.
Returns:
core.Yaspin: instance of the Yaspin class.
Raises:
ValueError: If unsupported ``color`` is specified.
ValueError: If unsupported ``on_color`` is specified.
ValueError: If unsupported color attribute in ``attrs``
is specified.
ValueError: If trying to register handler for SIGKILL signal.
ValueError: If unsupported ``side`` is specified.
Available text colors:
red, green, yellow, blue, magenta, cyan, white.
Available text highlights:
on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan,
on_white, on_grey.
Available attributes:
bold, dark, underline, blink, reverse, concealed.
Example::
# Use as a context manager
with yaspin():
some_operations()
# Context manager with text
with yaspin(text="Processing..."):
some_operations()
# Context manager with custom sequence
with yaspin(Spinner('-\\|/', 150)):
some_operations()
# As decorator
@yaspin(text="Loading...")
def foo():
time.sleep(5)
foo()
"""
return Yaspin(*args, **kwargs)
def kbi_safe_yaspin(*args, **kwargs):
kwargs["sigmap"] = {signal.SIGINT: default_handler}
return Yaspin(*args, **kwargs)
# Handle PYTHONOPTIMIZE=2 case, when docstrings are set to None.
if yaspin.__doc__:
_kbi_safe_doc = yaspin.__doc__.replace("yaspin", "kbi_safe_yaspin")
kbi_safe_yaspin.__doc__ = _kbi_safe_doc
-14
View File
@@ -1,14 +0,0 @@
# :copyright: (c) 2021 by Pavlo Dmytrenko.
# :license: MIT, see LICENSE for more details.
"""
yaspin.base_spinner
~~~~~~~~~~~~~~~~~~~
Spinner class, used to construct other spinners.
"""
from collections import namedtuple
Spinner = namedtuple("Spinner", "frames interval")
default_spinner = Spinner("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏", 80)
-124
View File
@@ -1,124 +0,0 @@
# :copyright: (c) 2021 by Pavlo Dmytrenko.
# :license: MIT, see LICENSE for more details.
"""
yaspin.constants
~~~~~~~~~~~~~~~~
Some setups.
"""
ENCODING = "utf-8"
COLOR_MAP = {
# name: type
"blink": "attrs",
"bold": "attrs",
"concealed": "attrs",
"dark": "attrs",
"reverse": "attrs",
"underline": "attrs",
"blue": "color",
"cyan": "color",
"green": "color",
"magenta": "color",
"red": "color",
"white": "color",
"yellow": "color",
"on_blue": "on_color",
"on_cyan": "on_color",
"on_green": "on_color",
"on_grey": "on_color",
"on_magenta": "on_color",
"on_red": "on_color",
"on_white": "on_color",
"on_yellow": "on_color",
}
COLOR_ATTRS = COLOR_MAP.keys()
# Get spinner names:
# $ < yaspin/data/spinners.json | jq '. | keys'
SPINNER_ATTRS = [
"aesthetic",
"arc",
"arrow",
"arrow2",
"arrow3",
"balloon",
"balloon2",
"betaWave",
"bluePulse",
"bounce",
"bouncingBall",
"bouncingBar",
"boxBounce",
"boxBounce2",
"christmas",
"circle",
"circleHalves",
"circleQuarters",
"clock",
"dots",
"dots10",
"dots11",
"dots12",
"dots2",
"dots3",
"dots4",
"dots5",
"dots6",
"dots7",
"dots8",
"dots8Bit",
"dots9",
"dqpb",
"earth",
"fingerDance",
"fistBump",
"flip",
"grenade",
"growHorizontal",
"growVertical",
"hamburger",
"hearts",
"layer",
"line",
"line2",
"material",
"mindblown",
"monkey",
"moon",
"noise",
"orangeBluePulse",
"orangePulse",
"pipe",
"point",
"pong",
"runner",
"shark",
"simpleDots",
"simpleDotsScrolling",
"smiley",
"soccerHeader",
"speaker",
"squareCorners",
"squish",
"star",
"star2",
"timeTravel",
"toggle",
"toggle10",
"toggle11",
"toggle12",
"toggle13",
"toggle2",
"toggle3",
"toggle4",
"toggle5",
"toggle6",
"toggle7",
"toggle8",
"toggle9",
"triangle",
"weather",
]
-546
View File
@@ -1,546 +0,0 @@
# :copyright: (c) 2021 by Pavlo Dmytrenko.
# :license: MIT, see LICENSE for more details.
"""
yaspin.yaspin
~~~~~~~~~~~~~
A lightweight terminal spinner.
"""
import contextlib
import datetime
import functools
import itertools
import signal
import sys
import threading
import time
from typing import List, Set, Union
from pipenv.vendor.termcolor import colored
from pipenv.vendor import colorama
from pipenv.vendor.vistir import cursor
from .base_spinner import Spinner, default_spinner
from .constants import COLOR_ATTRS, COLOR_MAP, SPINNER_ATTRS
from .helpers import to_unicode
colorama.init()
class Yaspin: # pylint: disable=useless-object-inheritance,too-many-instance-attributes
"""Implements a context manager that spawns a thread
to write spinner frames into a tty (stdout) during
context execution.
"""
# When Python finds its output attached to a terminal,
# it sets the sys.stdout.encoding attribute to the terminal's encoding.
# The print statement's handler will automatically encode unicode
# arguments into bytes.
def __init__( # pylint: disable=too-many-arguments
self,
spinner=None,
text="",
color=None,
on_color=None,
attrs=None,
reversal=False,
side="left",
sigmap=None,
timer=False,
):
# Spinner
self._spinner = self._set_spinner(spinner)
self._frames = self._set_frames(self._spinner, reversal)
self._interval = self._set_interval(self._spinner)
self._cycle = self._set_cycle(self._frames)
# Color Specification
self._color = self._set_color(color) if color else color
self._on_color = self._set_on_color(on_color) if on_color else on_color
self._attrs = self._set_attrs(attrs) if attrs else set()
self._color_func = self._compose_color_func()
# Other
self._text = text
self._side = self._set_side(side)
self._reversal = reversal
self._timer = timer
self._start_time = None
self._stop_time = None
# Helper flags
self._stop_spin = None
self._hide_spin = None
self._spin_thread = None
self._last_frame = None
self._stdout_lock = threading.Lock()
self._hidden_level = 0
# Signals
# In Python 2 signal.SIG* are of type int.
# In Python 3 signal.SIG* are enums.
#
# Signal = Union[enum.Enum, int]
# SigHandler = Union[enum.Enum, Callable]
self._sigmap = sigmap if sigmap else {} # Dict[Signal, SigHandler]
# Maps signals to their default handlers in order to reset
# custom handlers set by ``sigmap`` at the cleanup phase.
self._dfl_sigmap = {} # Dict[Signal, SigHandler]
#
# Dunders
#
def __repr__(self):
return "<Yaspin frames={0!s}>".format(self._frames)
def __enter__(self):
self.start()
return self
def __exit__(self, exc_type, exc_val, traceback):
# Avoid stop() execution for the 2nd time
if self._spin_thread.is_alive():
self.stop()
return False # nothing is handled
def __call__(self, fn):
@functools.wraps(fn)
def inner(*args, **kwargs):
with self:
return fn(*args, **kwargs)
return inner
def __getattr__(self, name):
# CLI spinners
if name in SPINNER_ATTRS:
from .spinners import Spinners # pylint: disable=import-outside-toplevel
sp = getattr(Spinners, name)
self.spinner = sp
# Color Attributes: "color", "on_color", "attrs"
elif name in COLOR_ATTRS:
attr_type = COLOR_MAP[name]
# Call appropriate property setters;
# _color_func is updated automatically by setters.
if attr_type == "attrs":
self.attrs = [name] # calls property setter
if attr_type in ("color", "on_color"):
setattr(self, attr_type, name) # calls property setter
# Side: "left" or "right"
elif name in ("left", "right"):
self.side = name # calls property setter
# Common error for unsupported attributes
else:
raise AttributeError(
"'{0}' object has no attribute: '{1}'".format(
self.__class__.__name__, name
)
)
return self
#
# Properties
#
@property
def spinner(self):
return self._spinner
@spinner.setter
def spinner(self, sp):
self._spinner = self._set_spinner(sp)
self._frames = self._set_frames(self._spinner, self._reversal)
self._interval = self._set_interval(self._spinner)
self._cycle = self._set_cycle(self._frames)
@property
def text(self):
return self._text
@text.setter
def text(self, txt):
self._text = txt
@property
def color(self):
return self._color
@color.setter
def color(self, value):
self._color = self._set_color(value) if value else value
self._color_func = self._compose_color_func() # update
@property
def on_color(self):
return self._on_color
@on_color.setter
def on_color(self, value):
self._on_color = self._set_on_color(value) if value else value
self._color_func = self._compose_color_func() # update
@property
def attrs(self):
return list(self._attrs)
@attrs.setter
def attrs(self, value):
new_attrs = self._set_attrs(value) if value else set()
self._attrs = self._attrs.union(new_attrs)
self._color_func = self._compose_color_func() # update
@property
def side(self):
return self._side
@side.setter
def side(self, value):
self._side = self._set_side(value)
@property
def reversal(self):
return self._reversal
@reversal.setter
def reversal(self, value):
self._reversal = value
self._frames = self._set_frames(self._spinner, self._reversal)
self._cycle = self._set_cycle(self._frames)
@property
def elapsed_time(self):
if self._start_time is None:
return 0
if self._stop_time is None:
return time.time() - self._start_time
return self._stop_time - self._start_time
#
# Public
#
def start(self):
if self._sigmap:
self._register_signal_handlers()
if sys.stdout.isatty():
self._hide_cursor()
self._start_time = time.time()
self._stop_time = None # Reset value to properly calculate subsequent spinner starts (if any) # pylint: disable=line-too-long
self._stop_spin = threading.Event()
self._hide_spin = threading.Event()
self._spin_thread = threading.Thread(target=self._spin)
self._spin_thread.start()
def stop(self):
self._stop_time = time.time()
if self._dfl_sigmap:
# Reset registered signal handlers to default ones
self._reset_signal_handlers()
if self._spin_thread:
self._stop_spin.set()
self._spin_thread.join()
sys.stdout.write("\r")
self._clear_line()
if sys.stdout.isatty():
self._show_cursor()
def hide(self):
"""Hide the spinner to allow for custom writing to the terminal."""
thr_is_alive = self._spin_thread and self._spin_thread.is_alive()
if thr_is_alive and not self._hide_spin.is_set():
with self._stdout_lock:
# set the hidden spinner flag
self._hide_spin.set()
# clear the current line
sys.stdout.write("\r")
self._clear_line()
# flush the stdout buffer so the current line
# can be rewritten to
sys.stdout.flush()
@contextlib.contextmanager
def hidden(self):
"""Hide the spinner within a block, can be nested"""
if self._hidden_level == 0:
self.hide()
self._hidden_level += 1
try:
yield
finally:
self._hidden_level -= 1
if self._hidden_level == 0:
self.show()
def show(self):
"""Show the hidden spinner."""
thr_is_alive = self._spin_thread and self._spin_thread.is_alive()
if thr_is_alive and self._hide_spin.is_set():
with self._stdout_lock:
# clear the hidden spinner flag
self._hide_spin.clear()
# clear the current line so the spinner is not appended to it
sys.stdout.write("\r")
self._clear_line()
def write(self, text):
"""Write text in the terminal without breaking the spinner."""
# similar to tqdm.write()
# https://pypi.python.org/pypi/tqdm#writing-messages
with self._stdout_lock:
sys.stdout.write("\r")
self._clear_line()
if isinstance(text, (str, bytes)):
_text = to_unicode(text)
else:
_text = str(text)
# Ensure output is Unicode
assert isinstance(_text, str)
sys.stdout.write("{0}\n".format(_text))
def ok(self, text="OK"):
"""Set Ok (success) finalizer to a spinner."""
_text = text if text else "OK"
self._freeze(_text)
def fail(self, text="FAIL"):
"""Set fail finalizer to a spinner."""
_text = text if text else "FAIL"
self._freeze(_text)
#
# Protected
#
def _freeze(self, final_text):
"""Stop spinner, compose last frame and 'freeze' it."""
text = to_unicode(final_text)
self._last_frame = self._compose_out(text, mode="last")
# Should be stopped here, otherwise prints after
# self._freeze call will mess up the spinner
self.stop()
with self._stdout_lock:
sys.stdout.write(self._last_frame)
def _spin(self):
while not self._stop_spin.is_set():
if self._hide_spin.is_set():
# Wait a bit to avoid wasting cycles
time.sleep(self._interval)
continue
# Compose output
spin_phase = next(self._cycle)
out = self._compose_out(spin_phase)
# Write
with self._stdout_lock:
sys.stdout.write(out)
self._clear_line()
sys.stdout.flush()
# Wait
self._stop_spin.wait(self._interval)
def _compose_color_func(self):
return functools.partial(
colored,
color=self._color,
on_color=self._on_color,
attrs=list(self._attrs),
)
def _compose_out(self, frame, mode=None):
# Ensure Unicode input
assert isinstance(frame, str)
assert isinstance(self._text, str)
text = self._text
# Colors
if self._color_func is not None:
frame = self._color_func(frame)
# Position
if self._side == "right":
frame, text = text, frame
if self._timer:
sec, fsec = divmod(round(100 * self.elapsed_time), 100)
text += " ({}.{:02.0f})".format(datetime.timedelta(seconds=sec), fsec)
# Mode
if not mode:
out = "\r{0} {1}".format(frame, text)
else:
out = "{0} {1}\n".format(frame, text)
# Ensure output is Unicode
assert isinstance(out, str)
return out
def _register_signal_handlers(self):
# SIGKILL cannot be caught or ignored, and the receiving
# process cannot perform any clean-up upon receiving this
# signal.
try:
if signal.SIGKILL in self._sigmap.keys():
raise ValueError(
"Trying to set handler for SIGKILL signal. "
"SIGKILL cannot be cought or ignored in POSIX systems."
)
except AttributeError:
pass
for sig, sig_handler in self._sigmap.items():
# A handler for a particular signal, once set, remains
# installed until it is explicitly reset. Store default
# signal handlers for subsequent reset at cleanup phase.
dfl_handler = signal.getsignal(sig)
self._dfl_sigmap[sig] = dfl_handler
# ``signal.SIG_DFL`` and ``signal.SIG_IGN`` are also valid
# signal handlers and are not callables.
if callable(sig_handler):
# ``signal.signal`` accepts handler function which is
# called with two arguments: signal number and the
# interrupted stack frame. ``functools.partial`` solves
# the problem of passing spinner instance into the handler
# function.
sig_handler = functools.partial(sig_handler, spinner=self)
signal.signal(sig, sig_handler)
def _reset_signal_handlers(self):
for sig, sig_handler in self._dfl_sigmap.items():
signal.signal(sig, sig_handler)
#
# Static
#
@staticmethod
def _set_color(value: str) -> str:
available_values = [k for k, v in COLOR_MAP.items() if v == "color"]
if value not in available_values:
raise ValueError(
"'{0}': unsupported color value. Use one of the: {1}".format(
value, ", ".join(available_values)
)
)
return value
@staticmethod
def _set_on_color(value: str) -> str:
available_values = [k for k, v in COLOR_MAP.items() if v == "on_color"]
if value not in available_values:
raise ValueError(
"'{0}': unsupported on_color value. "
"Use one of the: {1}".format(value, ", ".join(available_values))
)
return value
@staticmethod
def _set_attrs(attrs: List[str]) -> Set[str]:
available_values = [k for k, v in COLOR_MAP.items() if v == "attrs"]
for attr in attrs:
if attr not in available_values:
raise ValueError(
"'{0}': unsupported attribute value. "
"Use one of the: {1}".format(attr, ", ".join(available_values))
)
return set(attrs)
@staticmethod
def _set_spinner(spinner):
if hasattr(spinner, "frames") and hasattr(spinner, "interval"):
if not spinner.frames or not spinner.interval:
sp = default_spinner
else:
sp = spinner
else:
sp = default_spinner
return sp
@staticmethod
def _set_side(side: str) -> str:
if side not in ("left", "right"):
raise ValueError(
"'{0}': unsupported side value. " "Use either 'left' or 'right'."
)
return side
@staticmethod
def _set_frames(spinner: Spinner, reversal: bool) -> Union[str, List]:
uframes = None # unicode frames
uframes_seq = None # sequence of unicode frames
if isinstance(spinner.frames, str):
uframes = spinner.frames
# TODO (pavdmyt): support any type that implements iterable
if isinstance(spinner.frames, (list, tuple)):
# Empty ``spinner.frames`` is handled by ``Yaspin._set_spinner``
if spinner.frames and isinstance(spinner.frames[0], bytes):
uframes_seq = [to_unicode(frame) for frame in spinner.frames]
else:
uframes_seq = spinner.frames
_frames = uframes or uframes_seq
if not _frames:
# Empty ``spinner.frames`` is handled by ``Yaspin._set_spinner``.
# This code is very unlikely to be executed. However, it's still
# here to be on a safe side.
raise ValueError("{0!r}: no frames found in spinner".format(spinner))
# Builtin ``reversed`` returns reverse iterator,
# which adds unnecessary difficulty for returning
# unicode value;
# Hence using [::-1] syntax
frames = _frames[::-1] if reversal else _frames
return frames
@staticmethod
def _set_interval(spinner):
# Milliseconds to Seconds
return spinner.interval * 0.001
@staticmethod
def _set_cycle(frames):
return itertools.cycle(frames)
@staticmethod
def _hide_cursor():
cursor.hide_cursor()
@staticmethod
def _show_cursor():
cursor.show_cursor()
@staticmethod
def _clear_line():
sys.stdout.write("\033[K")
File diff suppressed because it is too large Load Diff
-17
View File
@@ -1,17 +0,0 @@
# :copyright: (c) 2021 by Pavlo Dmytrenko.
# :license: MIT, see LICENSE for more details.
"""
yaspin.helpers
~~~~~~~~~~~~~~
Helper functions.
"""
from .constants import ENCODING
def to_unicode(text_type, encoding=ENCODING):
if isinstance(text_type, bytes):
return text_type.decode(encoding)
return text_type
-36
View File
@@ -1,36 +0,0 @@
# :copyright: (c) 2021 by Pavlo Dmytrenko.
# :license: MIT, see LICENSE for more details.
"""
yaspin.signal_handlers
~~~~~~~~~~~~~~~~~~~~~~
Callback functions or "signal handlers", that are invoked
when the signal occurs.
"""
import sys
def default_handler(signum, frame, spinner): # pylint: disable=unused-argument
"""Signal handler, used to gracefully shut down the ``spinner`` instance
when specified signal is received by the process running the ``spinner``.
``signum`` and ``frame`` are mandatory arguments. Check ``signal.signal``
function for more details.
"""
spinner.fail()
spinner.stop()
sys.exit(0)
def fancy_handler(signum, frame, spinner): # pylint: disable=unused-argument
"""Signal handler, used to gracefully shut down the ``spinner`` instance
when specified signal is received by the process running the ``spinner``.
``signum`` and ``frame`` are mandatory arguments. Check ``signal.signal``
function for more details.
"""
spinner.red.fail("")
spinner.stop()
sys.exit(0)
-28
View File
@@ -1,28 +0,0 @@
# :copyright: (c) 2021 by Pavlo Dmytrenko.
# :license: MIT, see LICENSE for more details.
"""
yaspin.spinners
~~~~~~~~~~~~~~~
A collection of cli spinners.
"""
import pkgutil
from collections import namedtuple
try:
import simplejson as json
except ImportError:
import json
SPINNERS_DATA = pkgutil.get_data(__name__, "data/spinners.json").decode("utf-8")
def _hook(dct):
return namedtuple("Spinner", dct.keys())(*dct.values())
Spinners = json.loads(SPINNERS_DATA, object_hook=_hook)
@@ -1,56 +0,0 @@
diff --git a/pipenv/vendor/yaspin/core.py b/pipenv/vendor/yaspin/core.py
index 76dc2439..d8a0716c 100644
--- a/pipenv/vendor/yaspin/core.py
+++ b/pipenv/vendor/yaspin/core.py
@@ -19,11 +19,15 @@ import time
from typing import List, Set, Union
from pipenv.vendor.termcolor import colored
+from pipenv.vendor import colorama
+from pipenv.vendor.vistir import cursor
from .base_spinner import Spinner, default_spinner
from .constants import COLOR_ATTRS, COLOR_MAP, SPINNER_ATTRS
from .helpers import to_unicode
+colorama.init()
+
class Yaspin: # pylint: disable=useless-object-inheritance,too-many-instance-attributes
"""Implements a context manager that spawns a thread
@@ -401,11 +405,14 @@ class Yaspin: # pylint: disable=useless-object-inheritance,too-many-instance-at
# SIGKILL cannot be caught or ignored, and the receiving
# process cannot perform any clean-up upon receiving this
# signal.
- if signal.SIGKILL in self._sigmap.keys():
- raise ValueError(
- "Trying to set handler for SIGKILL signal. "
- "SIGKILL cannot be cought or ignored in POSIX systems."
- )
+ try:
+ if signal.SIGKILL in self._sigmap.keys():
+ raise ValueError(
+ "Trying to set handler for SIGKILL signal. "
+ "SIGKILL cannot be cought or ignored in POSIX systems."
+ )
+ except AttributeError:
+ pass
for sig, sig_handler in self._sigmap.items():
# A handler for a particular signal, once set, remains
@@ -528,13 +535,11 @@ class Yaspin: # pylint: disable=useless-object-inheritance,too-many-instance-at
@staticmethod
def _hide_cursor():
- sys.stdout.write("\033[?25l")
- sys.stdout.flush()
+ cursor.hide_cursor()
@staticmethod
def _show_cursor():
- sys.stdout.write("\033[?25h")
- sys.stdout.flush()
+ cursor.show_cursor()
@staticmethod
def _clear_line():