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