1# Authors: Karl MacMillan <kmacmillan@mentalrootkit.com>
2#
3# Copyright (C) 2006 Red Hat
4# see file 'COPYING' for use and warranty information
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License as
8# published by the Free Software Foundation; version 2 only
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19import locale
20import sys
21
22
23PY3 = sys.version_info[0] == 3
24
25if PY3:
26    bytes_type=bytes
27    string_type=str
28else:
29    bytes_type=str
30    string_type=unicode
31
32
33class ConsoleProgressBar:
34    def __init__(self, out, steps=100, indicator='#'):
35        self.blocks = 0
36        self.current = 0
37        self.steps = steps
38        self.indicator = indicator
39        self.out = out
40        self.done = False
41
42    def start(self, message=None):
43        self.done = False
44        if message:
45            self.out.write('\n%s:\n' % message)
46        self.out.write('%--10---20---30---40---50---60---70---80---90--100\n')
47
48    def step(self, n=1):
49        self.current += n
50
51        old = self.blocks
52        self.blocks = int(round(self.current / float(self.steps) * 100) / 2)
53
54        if self.blocks > 50:
55            self.blocks = 50
56
57        new = self.blocks - old
58
59        self.out.write(self.indicator * new)
60        self.out.flush()
61
62        if self.blocks == 50 and not self.done:
63            self.done = True
64            self.out.write("\n")
65
66def set_to_list(s):
67    l = []
68    l.extend(s)
69    return l
70
71def first(s, sorted=False):
72    """
73    Return the first element of a set.
74
75    It sometimes useful to return the first element from a set but,
76    because sets are not indexable, this is rather hard. This function
77    will return the first element from a set. If sorted is True, then
78    the set will first be sorted (making this an expensive operation).
79    Otherwise a random element will be returned (as sets are not ordered).
80    """
81    if not len(s):
82        raise IndexError("empty containter")
83
84    if sorted:
85        l = set_to_list(s)
86        l.sort()
87        return l[0]
88    else:
89        for x in s:
90            return x
91
92def encode_input(text):
93    """Encode given text via preferred system encoding"""
94    # locale will often find out the correct encoding
95    encoding = locale.getpreferredencoding()
96    try:
97        encoded_text = text.encode(encoding)
98    except UnicodeError:
99    # if it fails to find correct encoding then ascii is used
100    # which may lead to UnicodeError if `text` contains non ascii signs
101    # utf-8 is our guess to fix the situation
102        encoded_text = text.encode('utf-8')
103    return encoded_text
104
105def decode_input(text):
106    """Decode given text via preferred system encoding"""
107    # locale will often find out the correct encoding
108    encoding = locale.getpreferredencoding()
109    try:
110        decoded_text = text.decode(encoding)
111    except UnicodeError:
112    # if it fails to find correct encoding then ascii is used
113    # which may lead to UnicodeError if `text` contains non ascii signs
114    # utf-8 is our guess to fix the situation
115        decoded_text = text.decode('utf-8')
116    return decoded_text
117
118class Comparison():
119    """Class used when implementing rich comparison.
120
121    Inherit from this class if you want to have a rich
122    comparison withing the class, afterwards implement
123    _compare function within your class."""
124
125    def _compare(self, other, method):
126        return NotImplemented
127
128    def __eq__(self, other):
129        return self._compare(other, lambda a, b: a == b)
130
131    def __lt__(self, other):
132        return self._compare(other, lambda a, b: a < b)
133
134    def __le__(self, other):
135        return self._compare(other, lambda a, b: a <= b)
136
137    def __ge__(self, other):
138        return self._compare(other, lambda a, b: a >= b)
139
140    def __gt__(self, other):
141        return self._compare(other, lambda a, b: a > b)
142
143    def __ne__(self, other):
144        return self._compare(other, lambda a, b: a != b)
145
146if sys.version_info < (2,7):
147    # cmp_to_key function is missing in python2.6
148    def cmp_to_key(mycmp):
149        'Convert a cmp= function into a key= function'
150        class K:
151            def __init__(self, obj, *args):
152                self.obj = obj
153            def __lt__(self, other):
154                return mycmp(self.obj, other.obj) < 0
155            def __gt__(self, other):
156                return mycmp(self.obj, other.obj) > 0
157            def __eq__(self, other):
158                return mycmp(self.obj, other.obj) == 0
159            def __le__(self, other):
160                return mycmp(self.obj, other.obj) <= 0
161            def __ge__(self, other):
162                return mycmp(self.obj, other.obj) >= 0
163            def __ne__(self, other):
164                return mycmp(self.obj, other.obj) != 0
165        return K
166else:
167    from functools import cmp_to_key
168
169def cmp(first, second):
170    return (first > second) - (second > first)
171
172if __name__ == "__main__":
173    import time
174    p = ConsoleProgressBar(sys.stdout, steps=999)
175    p.start("computing pi")
176    for i in range(999):
177        p.step()
178        time.sleep(0.001)
179