1#!/usr/bin/python
2
3import sys
4import time
5
6class ProgressBar(object):
7    """ProgressBar class holds the options of the progress bar.
8    The options are:
9        start   State from which start the progress. For example, if start is
10                5 and the end is 10, the progress of this state is 50%
11        end     State in which the progress has terminated.
12        width   --
13        fill    String to use for "filled" used to represent the progress
14        blank   String to use for "filled" used to represent remaining space.
15        format  Format
16        incremental
17    """
18    light_block = unichr(0x2591).encode("utf-8")
19    solid_block = unichr(0x2588).encode("utf-8")
20    solid_right_arrow = unichr(0x25BA).encode("utf-8")
21
22    def __init__(self,
23                 start=0,
24                 end=10,
25                 width=12,
26                 fill=unichr(0x25C9).encode("utf-8"),
27                 blank=unichr(0x25CC).encode("utf-8"),
28                 marker=unichr(0x25CE).encode("utf-8"),
29                 format='[%(fill)s%(marker)s%(blank)s] %(progress)s%%',
30                 incremental=True):
31        super(ProgressBar, self).__init__()
32
33        self.start = start
34        self.end = end
35        self.width = width
36        self.fill = fill
37        self.blank = blank
38        self.marker = marker
39        self.format = format
40        self.incremental = incremental
41        self.step = 100 / float(width) #fix
42        self.reset()
43
44    def __add__(self, increment):
45        increment = self._get_progress(increment)
46        if 100 > self.progress + increment:
47            self.progress += increment
48        else:
49            self.progress = 100
50        return self
51
52    def complete(self):
53        self.progress = 100
54        return self
55
56    def __str__(self):
57        progressed = int(self.progress / self.step) #fix
58        fill = progressed * self.fill
59        blank = (self.width - progressed) * self.blank
60        return self.format % {'fill': fill, 'blank': blank, 'marker': self.marker, 'progress': int(self.progress)}
61
62    __repr__ = __str__
63
64    def _get_progress(self, increment):
65        return float(increment * 100) / self.end
66
67    def reset(self):
68        """Resets the current progress to the start point"""
69        self.progress = self._get_progress(self.start)
70        return self
71
72
73class AnimatedProgressBar(ProgressBar):
74    """Extends ProgressBar to allow you to use it straighforward on a script.
75    Accepts an extra keyword argument named `stdout` (by default use sys.stdout)
76    and may be any file-object to which send the progress status.
77    """
78    def __init__(self,
79                 start=0,
80                 end=10,
81                 width=12,
82                 fill=unichr(0x25C9).encode("utf-8"),
83                 blank=unichr(0x25CC).encode("utf-8"),
84                 marker=unichr(0x25CE).encode("utf-8"),
85                 format='[%(fill)s%(marker)s%(blank)s] %(progress)s%%',
86                 incremental=True,
87                 stdout=sys.stdout):
88        super(AnimatedProgressBar, self).__init__(start,end,width,fill,blank,marker,format,incremental)
89        self.stdout = stdout
90
91    def show_progress(self):
92        if hasattr(self.stdout, 'isatty') and self.stdout.isatty():
93            self.stdout.write('\r')
94        else:
95            self.stdout.write('\n')
96        self.stdout.write(str(self))
97        self.stdout.flush()
98
99class ProgressWithEvents(AnimatedProgressBar):
100    """Extends AnimatedProgressBar to allow you to track a set of events that
101       cause the progress to move. For instance, in a deletion progress bar, you
102       can track files that were nuked and files that the user doesn't have access to
103    """
104    def __init__(self,
105                 start=0,
106                 end=10,
107                 width=12,
108                 fill=unichr(0x25C9).encode("utf-8"),
109                 blank=unichr(0x25CC).encode("utf-8"),
110                 marker=unichr(0x25CE).encode("utf-8"),
111                 format='[%(fill)s%(marker)s%(blank)s] %(progress)s%%',
112                 incremental=True,
113                 stdout=sys.stdout):
114        super(ProgressWithEvents, self).__init__(start,end,width,fill,blank,marker,format,incremental,stdout)
115        self.events = {}
116
117    def add_event(self,event):
118        if event in self.events:
119            self.events[event] += 1
120        else:
121            self.events[event] = 1
122
123    def show_progress(self):
124        isatty = hasattr(self.stdout, 'isatty') and self.stdout.isatty()
125        if isatty:
126            self.stdout.write('\r')
127        else:
128            self.stdout.write('\n')
129        self.stdout.write(str(self))
130        if len(self.events) == 0:
131            return
132        self.stdout.write('\n')
133        for key in self.events.keys():
134            self.stdout.write(str(key) + ' = ' + str(self.events[key]) + ' ')
135        if isatty:
136            self.stdout.write('\033[1A')
137        self.stdout.flush()
138
139
140if __name__ == '__main__':
141    p = AnimatedProgressBar(end=200, width=200)
142
143    while True:
144        p + 5
145        p.show_progress()
146        time.sleep(0.3)
147        if p.progress == 100:
148            break
149    print #new line