~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
84 by Aaron Bentley
Auto-determined percent
26
27
    def _get_percent(self):
28
        if self.total is None:
29
            return None
30
        return 100.0 * self.current / self.total
31
32
    percent = property(_get_percent)
11 by abentley
refactored out progress.py
33
34
    def __str__(self):
35
        if self.total is not None:
36
            return "%i of %i %s %.1f%%" % (self.current, self.total, self.units,
37
                                         self.percent)
38
        else:
39
            return "%i %s" (self.current, self.units) 
40
47 by Aaron Bentley
merged ETA changes
41
class ProgressBar(object):
42
    def __init__(self):
43
        self.start = None
44
        object.__init__(self)
45
46
    def __call__(self, progress):
47
        if self.start is None:
48
            self.start = datetime.datetime.now()
49
        progress_bar(progress, start_time=self.start)
50
        
51
def divide_timedelta(delt, divisor):
52
    """Divides a timedelta object"""
53
    return datetime.timedelta(float(delt.days)/divisor, 
54
                              float(delt.seconds)/divisor, 
55
                              float(delt.microseconds)/divisor)
56
57
def str_tdelta(delt):
58
    if delt is None:
59
        return "-:--:--"
60
    return str(datetime.timedelta(delt.days, delt.seconds))
61
62
def get_eta(start_time, progress, enough_samples=20):
63
    if start_time is None or progress.current == 0:
64
        return None
65
    elif progress.current < enough_samples:
66
        return None
67
    elapsed = datetime.datetime.now() - start_time
68
    total_duration = divide_timedelta((elapsed) * long(progress.total), 
69
                                      progress.current)
70
    if elapsed < total_duration:
71
        eta = total_duration - elapsed
72
    else:
73
        eta = total_duration - total_duration
74
    return eta
75
76
def progress_bar(progress, start_time=None):
77
    eta = get_eta(start_time, progress)
78
    if start_time is not None:
79
        eta_str = " "+str_tdelta(eta)
80
    else:
81
        eta_str = ""
82
11 by abentley
refactored out progress.py
83
    fmt = " %i of %i %s (%.1f%%)"
84
    f = fmt % (progress.total, progress.total, progress.units, 100.0)
85
    max = len(f)
86
    cols = 77 - max
47 by Aaron Bentley
merged ETA changes
87
    if start_time is not None:
88
        cols -= len(eta_str)
11 by abentley
refactored out progress.py
89
    markers = int (float(cols) * progress.current / progress.total)
90
    txt = fmt % (progress.current, progress.total, progress.units,
91
                 progress.percent)
47 by Aaron Bentley
merged ETA changes
92
    sys.stderr.write("\r[%s%s]%s%s" % ('='*markers, ' '*(cols-markers), txt, 
93
                                       eta_str))
11 by abentley
refactored out progress.py
94
95
def clear_progress_bar():
32 by Aaron Bentley
Made progress bars use stderr
96
    sys.stderr.write('\r%s\r' % (' '*79))
11 by abentley
refactored out progress.py
97
33 by Aaron Bentley
Added spinner progress indicator
98
def spinner_str(progress, show_text=False):
99
    """
100
    Produces the string for a textual "spinner" progress indicator
101
    :param progress: an object represinting current progress
102
    :param show_text: If true, show progress text as well
103
    :return: The spinner string
104
105
    >>> spinner_str(Progress("baloons", 0))
106
    '|'
107
    >>> spinner_str(Progress("baloons", 5))
108
    '/'
109
    >>> spinner_str(Progress("baloons", 6), show_text=True)
110
    '- 6 baloons'
111
    """
112
    positions = ('|', '/', '-', '\\')
113
    text = positions[progress.current % 4]
114
    if show_text:
115
        text+=" %i %s" % (progress.current, progress.units)
116
    return text
117
118
def spinner(progress, show_text=False, output=sys.stderr):
119
    """
120
    Update a spinner progress indicator on an output
121
    :param progress: The progress to display
122
    :param show_text: If true, show text as well as spinner
123
    :param output: The output to write to
124
125
    >>> spinner(Progress("baloons", 6), show_text=True, output=sys.stdout)
126
    \r- 6 baloons
127
    """
128
    output.write('\r%s' % spinner_str(progress, show_text))
129
130
def run_tests():
131
    import doctest
132
    result = doctest.testmod()
133
    if result[1] > 0:
134
        if result[0] == 0:
135
            print "All tests passed"
136
    else:
137
        print "No tests to run"
80 by Aaron Bentley
Disabled fancy output when stdout is not a tty
138
139
def rewriting_supported(out=sys.stdout):
140
    return hasattr(out, 'isatty') and out.isatty()
141
33 by Aaron Bentley
Added spinner progress indicator
142
if __name__ == "__main__":
143
    run_tests()