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