~abentley/bzrtools/bzrtools.dev

14 by abentley
GPLed the project, ignored files
1
# Copyright (C) 2005 Aaron Bentley
2
# <aaron.bentley@utoronto.ca>
3
#
4
#    This program is free software; you can redistribute it and/or modify
5
#    it under the terms of the GNU General Public License as published by
6
#    the Free Software Foundation; either version 2 of the License, or
7
#    (at your option) any later version.
8
#
9
#    This program is distributed in the hope that it will be useful,
10
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
#    GNU General Public License for more details.
13
#
14
#    You should have received a copy of the GNU General Public License
15
#    along with this program; if not, write to the Free Software
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
11 by abentley
refactored out progress.py
18
import sys
47 by Aaron Bentley
merged ETA changes
19
import datetime
14 by abentley
GPLed the project, ignored files
20
11 by abentley
refactored out progress.py
21
class Progress(object):
22
    def __init__(self, units, current, total=None):
23
        self.units = units
24
        self.current = current
25
        self.total = total
26
        self.percent = None
27
        if self.total is not None:
28
            self.percent = 100.0 * current / total
29
30
    def __str__(self):
31
        if self.total is not None:
32
            return "%i of %i %s %.1f%%" % (self.current, self.total, self.units,
33
                                         self.percent)
34
        else:
35
            return "%i %s" (self.current, self.units) 
36
47 by Aaron Bentley
merged ETA changes
37
class ProgressBar(object):
38
    def __init__(self):
39
        self.start = None
40
        object.__init__(self)
41
42
    def __call__(self, progress):
43
        if self.start is None:
44
            self.start = datetime.datetime.now()
45
        progress_bar(progress, start_time=self.start)
46
        
47
def divide_timedelta(delt, divisor):
48
    """Divides a timedelta object"""
49
    return datetime.timedelta(float(delt.days)/divisor, 
50
                              float(delt.seconds)/divisor, 
51
                              float(delt.microseconds)/divisor)
52
53
def str_tdelta(delt):
54
    if delt is None:
55
        return "-:--:--"
56
    return str(datetime.timedelta(delt.days, delt.seconds))
57
58
def get_eta(start_time, progress, enough_samples=20):
59
    if start_time is None or progress.current == 0:
60
        return None
61
    elif progress.current < enough_samples:
62
        return None
63
    elapsed = datetime.datetime.now() - start_time
64
    total_duration = divide_timedelta((elapsed) * long(progress.total), 
65
                                      progress.current)
66
    if elapsed < total_duration:
67
        eta = total_duration - elapsed
68
    else:
69
        eta = total_duration - total_duration
70
    return eta
71
72
def progress_bar(progress, start_time=None):
73
    eta = get_eta(start_time, progress)
74
    if start_time is not None:
75
        eta_str = " "+str_tdelta(eta)
76
    else:
77
        eta_str = ""
78
11 by abentley
refactored out progress.py
79
    fmt = " %i of %i %s (%.1f%%)"
80
    f = fmt % (progress.total, progress.total, progress.units, 100.0)
81
    max = len(f)
82
    cols = 77 - max
47 by Aaron Bentley
merged ETA changes
83
    if start_time is not None:
84
        cols -= len(eta_str)
11 by abentley
refactored out progress.py
85
    markers = int (float(cols) * progress.current / progress.total)
86
    txt = fmt % (progress.current, progress.total, progress.units,
87
                 progress.percent)
47 by Aaron Bentley
merged ETA changes
88
    sys.stderr.write("\r[%s%s]%s%s" % ('='*markers, ' '*(cols-markers), txt, 
89
                                       eta_str))
11 by abentley
refactored out progress.py
90
91
def clear_progress_bar():
32 by Aaron Bentley
Made progress bars use stderr
92
    sys.stderr.write('\r%s\r' % (' '*79))
11 by abentley
refactored out progress.py
93
33 by Aaron Bentley
Added spinner progress indicator
94
def spinner_str(progress, show_text=False):
95
    """
96
    Produces the string for a textual "spinner" progress indicator
97
    :param progress: an object represinting current progress
98
    :param show_text: If true, show progress text as well
99
    :return: The spinner string
100
101
    >>> spinner_str(Progress("baloons", 0))
102
    '|'
103
    >>> spinner_str(Progress("baloons", 5))
104
    '/'
105
    >>> spinner_str(Progress("baloons", 6), show_text=True)
106
    '- 6 baloons'
107
    """
108
    positions = ('|', '/', '-', '\\')
109
    text = positions[progress.current % 4]
110
    if show_text:
111
        text+=" %i %s" % (progress.current, progress.units)
112
    return text
113
114
def spinner(progress, show_text=False, output=sys.stderr):
115
    """
116
    Update a spinner progress indicator on an output
117
    :param progress: The progress to display
118
    :param show_text: If true, show text as well as spinner
119
    :param output: The output to write to
120
121
    >>> spinner(Progress("baloons", 6), show_text=True, output=sys.stdout)
122
    \r- 6 baloons
123
    """
124
    output.write('\r%s' % spinner_str(progress, show_text))
125
126
def run_tests():
127
    import doctest
128
    result = doctest.testmod()
129
    if result[1] > 0:
130
        if result[0] == 0:
131
            print "All tests passed"
132
    else:
133
        print "No tests to run"
134
if __name__ == "__main__":
135
    run_tests()