Mercurial > repos > shellac > guppy_basecaller
diff env/lib/python3.7/site-packages/humanfriendly/terminal/spinners.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
line wrap: on
line diff
--- a/env/lib/python3.7/site-packages/humanfriendly/terminal/spinners.py Thu May 14 16:47:39 2020 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ -# Human friendly input/output in Python. -# -# Author: Peter Odding <peter@peterodding.com> -# Last Change: March 1, 2020 -# URL: https://humanfriendly.readthedocs.io - -""" -Support for spinners that represent progress on interactive terminals. - -The :class:`Spinner` class shows a "spinner" on the terminal to let the user -know that something is happening during long running operations that would -otherwise be silent (leaving the user to wonder what they're waiting for). -Below are some visual examples that should illustrate the point. - -**Simple spinners:** - - Here's a screen capture that shows the simplest form of spinner: - - .. image:: images/spinner-basic.gif - :alt: Animated screen capture of a simple spinner. - - The following code was used to create the spinner above: - - .. code-block:: python - - import itertools - import time - from humanfriendly import Spinner - - with Spinner(label="Downloading") as spinner: - for i in itertools.count(): - # Do something useful here. - time.sleep(0.1) - # Advance the spinner. - spinner.step() - -**Spinners that show elapsed time:** - - Here's a spinner that shows the elapsed time since it started: - - .. image:: images/spinner-with-timer.gif - :alt: Animated screen capture of a spinner showing elapsed time. - - The following code was used to create the spinner above: - - .. code-block:: python - - import itertools - import time - from humanfriendly import Spinner, Timer - - with Spinner(label="Downloading", timer=Timer()) as spinner: - for i in itertools.count(): - # Do something useful here. - time.sleep(0.1) - # Advance the spinner. - spinner.step() - -**Spinners that show progress:** - - Here's a spinner that shows a progress percentage: - - .. image:: images/spinner-with-progress.gif - :alt: Animated screen capture of spinner showing progress. - - The following code was used to create the spinner above: - - .. code-block:: python - - import itertools - import random - import time - from humanfriendly import Spinner, Timer - - with Spinner(label="Downloading", total=100) as spinner: - progress = 0 - while progress < 100: - # Do something useful here. - time.sleep(0.1) - # Advance the spinner. - spinner.step(progress) - # Determine the new progress value. - progress += random.random() * 5 - -If you want to provide user feedback during a long running operation but it's -not practical to periodically call the :func:`~Spinner.step()` method consider -using :class:`AutomaticSpinner` instead. - -As you may already have noticed in the examples above, :class:`Spinner` objects -can be used as context managers to automatically call :func:`Spinner.clear()` -when the spinner ends. -""" - -# Standard library modules. -import multiprocessing -import sys -import time - -# Modules included in our package. -from humanfriendly import Timer -from humanfriendly.deprecation import deprecated_args -from humanfriendly.terminal import ANSI_ERASE_LINE - -# Public identifiers that require documentation. -__all__ = ("AutomaticSpinner", "GLYPHS", "MINIMUM_INTERVAL", "Spinner") - -GLYPHS = ["-", "\\", "|", "/"] -"""A list of strings with characters that together form a crude animation :-).""" - -MINIMUM_INTERVAL = 0.2 -"""Spinners are redrawn with a frequency no higher than this number (a floating point number of seconds).""" - - -class Spinner(object): - - """Show a spinner on the terminal as a simple means of feedback to the user.""" - - @deprecated_args('label', 'total', 'stream', 'interactive', 'timer') - def __init__(self, **options): - """ - Initialize a :class:`Spinner` object. - - :param label: - - The label for the spinner (a string or :data:`None`, defaults to - :data:`None`). - - :param total: - - The expected number of steps (an integer or :data:`None`). If this is - provided the spinner will show a progress percentage. - - :param stream: - - The output stream to show the spinner on (a file-like object, - defaults to :data:`sys.stderr`). - - :param interactive: - - :data:`True` to enable rendering of the spinner, :data:`False` to - disable (defaults to the result of ``stream.isatty()``). - - :param timer: - - A :class:`.Timer` object (optional). If this is given the spinner - will show the elapsed time according to the timer. - - :param interval: - - The spinner will be updated at most once every this many seconds - (a floating point number, defaults to :data:`MINIMUM_INTERVAL`). - - :param glyphs: - - A list of strings with single characters that are drawn in the same - place in succession to implement a simple animated effect (defaults - to :data:`GLYPHS`). - """ - # Store initializer arguments. - self.interactive = options.get('interactive') - self.interval = options.get('interval', MINIMUM_INTERVAL) - self.label = options.get('label') - self.states = options.get('glyphs', GLYPHS) - self.stream = options.get('stream', sys.stderr) - self.timer = options.get('timer') - self.total = options.get('total') - # Define instance variables. - self.counter = 0 - self.last_update = 0 - # Try to automatically discover whether the stream is connected to - # a terminal, but don't fail if no isatty() method is available. - if self.interactive is None: - try: - self.interactive = self.stream.isatty() - except Exception: - self.interactive = False - - def step(self, progress=0, label=None): - """ - Advance the spinner by one step and redraw it. - - :param progress: The number of the current step, relative to the total - given to the :class:`Spinner` constructor (an integer, - optional). If not provided the spinner will not show - progress. - :param label: The label to use while redrawing (a string, optional). If - not provided the label given to the :class:`Spinner` - constructor is used instead. - - This method advances the spinner by one step without starting a new - line, causing an animated effect which is very simple but much nicer - than waiting for a prompt which is completely silent for a long time. - - .. note:: This method uses time based rate limiting to avoid redrawing - the spinner too frequently. If you know you're dealing with - code that will call :func:`step()` at a high frequency, - consider using :func:`sleep()` to avoid creating the - equivalent of a busy loop that's rate limiting the spinner - 99% of the time. - """ - if self.interactive: - time_now = time.time() - if time_now - self.last_update >= self.interval: - self.last_update = time_now - state = self.states[self.counter % len(self.states)] - label = label or self.label - if not label: - raise Exception("No label set for spinner!") - elif self.total and progress: - label = "%s: %.2f%%" % (label, progress / (self.total / 100.0)) - elif self.timer and self.timer.elapsed_time > 2: - label = "%s (%s)" % (label, self.timer.rounded) - self.stream.write("%s %s %s ..\r" % (ANSI_ERASE_LINE, state, label)) - self.counter += 1 - - def sleep(self): - """ - Sleep for a short period before redrawing the spinner. - - This method is useful when you know you're dealing with code that will - call :func:`step()` at a high frequency. It will sleep for the interval - with which the spinner is redrawn (less than a second). This avoids - creating the equivalent of a busy loop that's rate limiting the - spinner 99% of the time. - - This method doesn't redraw the spinner, you still have to call - :func:`step()` in order to do that. - """ - time.sleep(MINIMUM_INTERVAL) - - def clear(self): - """ - Clear the spinner. - - The next line which is shown on the standard output or error stream - after calling this method will overwrite the line that used to show the - spinner. - """ - if self.interactive: - self.stream.write(ANSI_ERASE_LINE) - - def __enter__(self): - """ - Enable the use of spinners as context managers. - - :returns: The :class:`Spinner` object. - """ - return self - - def __exit__(self, exc_type=None, exc_value=None, traceback=None): - """Clear the spinner when leaving the context.""" - self.clear() - - -class AutomaticSpinner(object): - - """ - Show a spinner on the terminal that automatically starts animating. - - This class shows a spinner on the terminal (just like :class:`Spinner` - does) that automatically starts animating. This class should be used as a - context manager using the :keyword:`with` statement. The animation - continues for as long as the context is active. - - :class:`AutomaticSpinner` provides an alternative to :class:`Spinner` - for situations where it is not practical for the caller to periodically - call :func:`~Spinner.step()` to advance the animation, e.g. because - you're performing a blocking call and don't fancy implementing threading or - subprocess handling just to provide some user feedback. - - This works using the :mod:`multiprocessing` module by spawning a - subprocess to render the spinner while the main process is busy doing - something more useful. By using the :keyword:`with` statement you're - guaranteed that the subprocess is properly terminated at the appropriate - time. - """ - - def __init__(self, label, show_time=True): - """ - Initialize an automatic spinner. - - :param label: The label for the spinner (a string). - :param show_time: If this is :data:`True` (the default) then the spinner - shows elapsed time. - """ - self.label = label - self.show_time = show_time - self.shutdown_event = multiprocessing.Event() - self.subprocess = multiprocessing.Process(target=self._target) - - def __enter__(self): - """Enable the use of automatic spinners as context managers.""" - self.subprocess.start() - - def __exit__(self, exc_type=None, exc_value=None, traceback=None): - """Enable the use of automatic spinners as context managers.""" - self.shutdown_event.set() - self.subprocess.join() - - def _target(self): - try: - timer = Timer() if self.show_time else None - with Spinner(label=self.label, timer=timer) as spinner: - while not self.shutdown_event.is_set(): - spinner.step() - spinner.sleep() - except KeyboardInterrupt: - # Swallow Control-C signals without producing a nasty traceback that - # won't make any sense to the average user. - pass