Skip to content

Commit

Permalink
added docstrings.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismeyers committed Feb 18, 2019
1 parent b340390 commit b155684
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 7 deletions.
72 changes: 72 additions & 0 deletions pleasehold/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@


class PleaseHold():
'''Manages the loading thread and handles pushing notifications.
This class supports the use of a context manager:
with pleasehold.hold() as holding:
...
Args:
begin_msg (str, optional): The message to the left of the loading bar
end_msg (str, optional): The message to the right of the loading bar
delay (float, optional): The delay between printing loading symbols
symbol (str, optional): The symbol to be used in the loading bar
'''
def __init__(self, begin_msg='begin', end_msg='end', delay=1.0, symbol='.'):
self._begin_msg = begin_msg
self._end_msg = end_msg
Expand All @@ -19,14 +31,21 @@ def __init__(self, begin_msg='begin', end_msg='end', delay=1.0, symbol='.'):
self._loading_event = threading.Event()

def __enter__(self):
'''Starts the loading thread if this class is initialized via a context
manager
'''
self.start()
return self

def __exit__(self, type, value, traceback):
'''Joins the loading thread if this class is initialized via a context
manager
'''
self.end()

@property
def begin_msg(self):
'''str: gets or sets the message to the left of the loading bar'''
return self._begin_msg

@begin_msg.setter
Expand All @@ -35,6 +54,7 @@ def begin_msg(self, value):

@property
def end_msg(self):
'''str: gets or sets the message to the right of the loading bar'''
return self._end_msg

@end_msg.setter
Expand All @@ -43,6 +63,7 @@ def end_msg(self, value):

@property
def delay(self):
'''float: gets or sets the delay between printing loading symbols'''
return self._delay

@delay.setter
Expand All @@ -51,6 +72,7 @@ def delay(self, value):

@property
def symbol(self):
'''str: gets or sets the symbol that's used in the loading bar'''
return self._symbol

@symbol.setter
Expand All @@ -59,9 +81,17 @@ def symbol(self, value):

@property
def loading_event(self):
'''str: gets the threading.Event() instance used to interact with the
loading thread
'''
return self._loading_event

def start(self, msg=None):
'''Starts the loading thread and prints the begin message.
Args:
msg (str, optional): Used to override self._begin_msg
'''
self._begin_msg = msg if msg is not None else self._begin_msg

print(f'{self._begin_msg}{self._loading_ticks}', end='', flush=True)
Expand All @@ -77,6 +107,11 @@ def start(self, msg=None):
self._loading_thread.start()

def end(self, msg=None):
'''Joins the loading thread and prints the end message.
Args:
msg (str, optional): Used to override self._end_msg
'''
self._end_msg = msg if msg is not None else self._end_msg

self._loading_event.clear()
Expand All @@ -85,6 +120,11 @@ def end(self, msg=None):
print(self._end_msg, flush=True)

def push(self, msg):
'''Pushes a message above the loading bar.
Args:
msg (str): The message to push
'''
with self._loading_lock:
term.clear_line()
term.move_line_up()
Expand All @@ -101,19 +141,34 @@ def _loading(self):


class Transfer():
'''Pauses the loading thread to allow for user input
This class supports the use of a context manager:
with pleasehold.transfer(holding) as t:
...
Args:
holding (PleaseHold): The instance of PleaseHold that should be paused
'''
def __init__(self, holding):
self._holding = holding
self._output_stream = io.StringIO()
self._stream_tee = stream_tee.StreamTee(
sys.stdout, self._output_stream, holding.symbol)

def __enter__(self):
'''Pauses the PleaseHold loading thread and prepares for input if this
class is initialized via a context manager
'''
sys.stdout = self._stream_tee
term.move_line_down()
self._holding.loading_event.clear()
return self

def __exit__(self, type, value, traceback):
'''Cleans up input prompts and resumes the PleaseHold loading thread if
this class is initialized via a context manager
'''
sys.stdout = sys.__stdout__
for _ in range(self._stream_tee.num_inputs + 1):
term.clear_line()
Expand All @@ -122,8 +177,25 @@ def __exit__(self, type, value, traceback):


def hold(begin_msg='begin', end_msg='end', delay=1.0, symbol='.'):
'''Instantiates an instance of PleaseHold.
The arguments are passed through to the PleaseHold constructor.
Args:
begin_msg (str, optional): The message to the left of the loading bar
end_msg (str, optional): The message to the right of the loading bar
delay (float, optional): The delay between printing loading symbols
symbol (str, optional): The symbol to be used in the loading bar
'''
return PleaseHold(begin_msg, end_msg, delay, symbol)


def transfer(holding):
'''Instantiates an instance of Transfer.
The arguments are passed through to the Transfer constructor.
Args:
holding (PleaseHold): The instance of PleaseHold that should be paused
'''
return Transfer(holding)
21 changes: 14 additions & 7 deletions pleasehold/stream_tee.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
'''
This class forks a stream, allowing you to capture output while still displaying
output in the terminal.
See: http://www.tentech.ca/2011/05/stream-tee-in-python-saving-stdout-to-file-while-keeping-the-console-alive/
'''
class StreamTee(object):
# Based on https://gist.github.com/327585 by Anand Kunal
'''Forks a stream, allowing you to capture output while still displaying
output in the terminal.
See: http://www.tentech.ca/2011/05/stream-tee-in-python-saving-stdout-to-file-while-keeping-the-console-alive/
Args:
stream1 (:obj:`TextIOWrapper`): The original stream (ex: stdin, stdout)
stream2 (:obj:`StringIO`): A fork of the original stream
symbol (str, optional): The loading symbol set in the current instance
of PleaseHold
'''
def __init__(self, stream1, stream2, symbol='.'):
self._stream1 = stream1
self._stream2 = stream2
Expand All @@ -21,6 +25,7 @@ def __getattr__(self, name):
return getattr(self, '__methodmissing__')

def __methodmissing__(self, *args, **kwargs):
'''Callback for events coming from the original stream'''
if len(args) > 0 and args[0] != '\n' and args[0] != self._loading_symbol:
self._num_inputs += 1

Expand All @@ -34,4 +39,6 @@ def __methodmissing__(self, *args, **kwargs):

@property
def num_inputs(self):
'''Gets the number of inputs that have occurred during the Transfer
context'''
return self._num_inputs
5 changes: 5 additions & 0 deletions pleasehold/terminal.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
'''A utility module that helps with terminal manipulation'''

import sys


def clear_line():
'''Clears all the text on the current line'''
sys.stdout.write('\x1b[2K\r')


def move_line_up():
'''Moves the terminal cursor up one line'''
sys.stdout.write('\033[F')


def move_line_down():
'''Moves the terminal cursor down one line'''
sys.stdout.write('\n')

0 comments on commit b155684

Please sign in to comment.