/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
649 by Martin Pool
- some cleanups for the progressbar method
1
# Copyright (C) 2005 Aaron Bentley <aaron.bentley@utoronto.ca>
2
# Copyright (C) 2005 Canonical <canonical.com>
648 by Martin Pool
- import aaron's progress-indicator code
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
649 by Martin Pool
- some cleanups for the progressbar method
18
19
"""
20
Simple text-mode progress indicator.
21
22
Everyone loves ascii art!
23
24
To display an indicator, create a ProgressBar object.  Call it,
25
passing Progress objects indicating the current state.  When done,
26
call clear().
27
28
Progress is suppressed when output is not sent to a terminal, so as
29
not to clutter log files.
30
"""
31
32
# TODO: remove functions in favour of keeping everything in one class
33
652 by Martin Pool
doc
34
# TODO: should be a global option e.g. --silent that disables progress
35
# indicators, preferably without needing to adjust all code that
36
# potentially calls them.
37
655 by Martin Pool
- better calculation of progress bar position
38
# TODO: Perhaps don't write updates faster than a certain rate, say
39
# 5/second.
40
649 by Martin Pool
- some cleanups for the progressbar method
41
648 by Martin Pool
- import aaron's progress-indicator code
42
import sys
43
import datetime
44
649 by Martin Pool
- some cleanups for the progressbar method
45
46
def _width():
47
    """Return estimated terminal width.
48
49
    TODO: Do something smart on Windows?
50
51
    TODO: Is there anything that gets a better update when the window
52
          is resized while the program is running?
53
    """
54
    import os
55
    try:
56
        return int(os.environ['COLUMNS'])
57
    except (IndexError, KeyError, ValueError):
58
        return 80
59
60
61
def _supports_progress(f):
62
    return hasattr(f, 'isatty') and f.isatty()
63
64
65
648 by Martin Pool
- import aaron's progress-indicator code
66
class Progress(object):
653 by Martin Pool
doc
67
    """Description of progress through a task.
68
69
    Basically just a fancy tuple holding:
70
71
    units
72
        noun string describing what is being traversed, e.g.
73
        "balloons", "kB"
74
75
    current
76
        how many objects have been processed so far
77
78
    total
79
        total number of objects to process, if known.
80
    """
81
    
648 by Martin Pool
- import aaron's progress-indicator code
82
    def __init__(self, units, current, total=None):
83
        self.units = units
84
        self.current = current
85
        self.total = total
86
87
    def _get_percent(self):
88
        if self.total is not None and self.current is not None:
89
            return 100.0 * self.current / self.total
90
91
    percent = property(_get_percent)
92
93
    def __str__(self):
94
        if self.total is not None:
95
            return "%i of %i %s %.1f%%" % (self.current, self.total, self.units,
96
                                         self.percent)
97
        else:
649 by Martin Pool
- some cleanups for the progressbar method
98
            return "%i %s" (self.current, self.units)
99
100
648 by Martin Pool
- import aaron's progress-indicator code
101
102
class ProgressBar(object):
649 by Martin Pool
- some cleanups for the progressbar method
103
    def __init__(self, to_file=sys.stderr):
104
        object.__init__(self)
648 by Martin Pool
- import aaron's progress-indicator code
105
        self.start = None
649 by Martin Pool
- some cleanups for the progressbar method
106
        self.to_file = to_file
107
        self.suppressed = not _supports_progress(self.to_file)
108
648 by Martin Pool
- import aaron's progress-indicator code
109
110
    def __call__(self, progress):
111
        if self.start is None:
112
            self.start = datetime.datetime.now()
649 by Martin Pool
- some cleanups for the progressbar method
113
        if not self.suppressed:
114
            draw_progress_bar(progress, start_time=self.start,
115
                              to_file=self.to_file)
116
117
    def clear(self):
118
        if not self.suppressed:
119
            clear_progress_bar(self.to_file)
120
    
121
648 by Martin Pool
- import aaron's progress-indicator code
122
        
123
def divide_timedelta(delt, divisor):
124
    """Divides a timedelta object"""
125
    return datetime.timedelta(float(delt.days)/divisor, 
126
                              float(delt.seconds)/divisor, 
127
                              float(delt.microseconds)/divisor)
128
129
def str_tdelta(delt):
130
    if delt is None:
131
        return "-:--:--"
132
    return str(datetime.timedelta(delt.days, delt.seconds))
133
649 by Martin Pool
- some cleanups for the progressbar method
134
648 by Martin Pool
- import aaron's progress-indicator code
135
def get_eta(start_time, progress, enough_samples=20):
136
    if start_time is None or progress.current == 0:
137
        return None
138
    elif progress.current < enough_samples:
139
        return None
140
    elapsed = datetime.datetime.now() - start_time
141
    total_duration = divide_timedelta((elapsed) * long(progress.total), 
142
                                      progress.current)
143
    if elapsed < total_duration:
144
        eta = total_duration - elapsed
145
    else:
146
        eta = total_duration - total_duration
147
    return eta
148
649 by Martin Pool
- some cleanups for the progressbar method
149
150
def draw_progress_bar(progress, start_time=None, to_file=sys.stderr):
648 by Martin Pool
- import aaron's progress-indicator code
151
    eta = get_eta(start_time, progress)
152
    if start_time is not None:
153
        eta_str = " "+str_tdelta(eta)
154
    else:
155
        eta_str = ""
156
157
    fmt = " %i of %i %s (%.1f%%)"
158
    f = fmt % (progress.total, progress.total, progress.units, 100.0)
649 by Martin Pool
- some cleanups for the progressbar method
159
    cols = _width() - 3 - len(f)
648 by Martin Pool
- import aaron's progress-indicator code
160
    if start_time is not None:
161
        cols -= len(eta_str)
655 by Martin Pool
- better calculation of progress bar position
162
    markers = int(round(float(cols) * progress.current / progress.total))
648 by Martin Pool
- import aaron's progress-indicator code
163
    txt = fmt % (progress.current, progress.total, progress.units,
164
                 progress.percent)
649 by Martin Pool
- some cleanups for the progressbar method
165
    to_file.write("\r[%s%s]%s%s" % ('='*markers, ' '*(cols-markers), txt, 
648 by Martin Pool
- import aaron's progress-indicator code
166
                                       eta_str))
167
649 by Martin Pool
- some cleanups for the progressbar method
168
def clear_progress_bar(to_file=sys.stderr):
169
    to_file.write('\r%s\r' % (' '*79))
170
648 by Martin Pool
- import aaron's progress-indicator code
171
172
def spinner_str(progress, show_text=False):
173
    """
174
    Produces the string for a textual "spinner" progress indicator
175
    :param progress: an object represinting current progress
176
    :param show_text: If true, show progress text as well
177
    :return: The spinner string
178
179
    >>> spinner_str(Progress("baloons", 0))
180
    '|'
181
    >>> spinner_str(Progress("baloons", 5))
182
    '/'
183
    >>> spinner_str(Progress("baloons", 6), show_text=True)
184
    '- 6 baloons'
185
    """
186
    positions = ('|', '/', '-', '\\')
187
    text = positions[progress.current % 4]
188
    if show_text:
189
        text+=" %i %s" % (progress.current, progress.units)
190
    return text
191
649 by Martin Pool
- some cleanups for the progressbar method
192
648 by Martin Pool
- import aaron's progress-indicator code
193
def spinner(progress, show_text=False, output=sys.stderr):
194
    """
195
    Update a spinner progress indicator on an output
196
    :param progress: The progress to display
197
    :param show_text: If true, show text as well as spinner
198
    :param output: The output to write to
199
200
    >>> spinner(Progress("baloons", 6), show_text=True, output=sys.stdout)
201
    \r- 6 baloons
202
    """
203
    output.write('\r%s' % spinner_str(progress, show_text))
204
649 by Martin Pool
- some cleanups for the progressbar method
205
648 by Martin Pool
- import aaron's progress-indicator code
206
def run_tests():
207
    import doctest
208
    result = doctest.testmod()
209
    if result[1] > 0:
210
        if result[0] == 0:
211
            print "All tests passed"
212
    else:
213
        print "No tests to run"
649 by Martin Pool
- some cleanups for the progressbar method
214
215
216
def demo():
217
    from time import sleep
218
    pb = ProgressBar()
219
    for i in range(100):
220
        pb(Progress('Elephanten', i, 100))
221
        sleep(0.3)
222
    print 'done!'
223
648 by Martin Pool
- import aaron's progress-indicator code
224
if __name__ == "__main__":
649 by Martin Pool
- some cleanups for the progressbar method
225
    demo()