mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
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:
Vendored
-451
@@ -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&utm_medium=referral&utm_content=pavdmyt/yaspin&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
|
||||
Vendored
-20
@@ -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.
|
||||
|
||||
Vendored
-168
@@ -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'])
|
||||
|
||||
Vendored
-2
@@ -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
|
||||
|
||||
Vendored
-21
@@ -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.
|
||||
Vendored
-7
@@ -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")
|
||||
Vendored
-89
@@ -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
|
||||
Vendored
-14
@@ -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)
|
||||
Vendored
-124
@@ -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",
|
||||
]
|
||||
Vendored
-546
@@ -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")
|
||||
-1415
File diff suppressed because it is too large
Load Diff
Vendored
-17
@@ -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
@@ -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)
|
||||
Vendored
-28
@@ -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():
|
||||
Reference in New Issue
Block a user