commit to CouchDB only when necessary
[mygpo.git] / mygpo / utils.py
blob00fee5bdc864c44f4e0fa95b65b21ebcf68391f5
2 # This file is part of my.gpodder.org.
4 # my.gpodder.org is free software: you can redistribute it and/or modify it
5 # under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or (at your
7 # option) any later version.
9 # my.gpodder.org is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
12 # License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with my.gpodder.org. If not, see <http://www.gnu.org/licenses/>.
18 from datetime import datetime, timedelta
19 import time
21 def daterange(from_date, to_date=datetime.now(), leap=timedelta(days=1)):
22 """
23 >>> from_d = datetime(2010, 01, 01)
24 >>> to_d = datetime(2010, 01, 05)
25 >>> list(daterange(from_d, to_d))
26 [datetime.datetime(2010, 1, 1, 0, 0), datetime.datetime(2010, 1, 2, 0, 0), datetime.datetime(2010, 1, 3, 0, 0), datetime.datetime(2010, 1, 4, 0, 0), datetime.datetime(2010, 1, 5, 0, 0)]
27 """
28 while from_date <= to_date:
29 yield from_date
30 from_date = from_date + leap
31 return
33 def format_time(value):
34 """Format an offset (in seconds) to a string
36 The offset should be an integer or float value.
38 >>> format_time(0)
39 '00:00'
40 >>> format_time(20)
41 '00:20'
42 >>> format_time(3600)
43 '01:00:00'
44 >>> format_time(10921)
45 '03:02:01'
46 """
47 dt = datetime.utcfromtimestamp(value)
49 if dt.hour == 0:
50 return dt.strftime('%M:%S')
51 else:
52 return dt.strftime('%H:%M:%S')
54 def parse_time(value):
55 """
56 >>> parse_time(10)
59 >>> parse_time('05:10') #5*60+10
60 310
62 >>> parse_time('1:05:10') #60*60+5*60+10
63 3910
64 """
65 if value is None:
66 raise ValueError('None value in parse_time')
68 if isinstance(value, int):
69 # Don't need to parse already-converted time value
70 return value
72 if value == '':
73 raise ValueError('Empty valueing in parse_time')
75 for format in ('%H:%M:%S', '%M:%S'):
76 try:
77 t = time.strptime(value, format)
78 return t.tm_hour * 60*60 + t.tm_min * 60 + t.tm_sec
79 except ValueError, e:
80 continue
82 return int(value)
85 def parse_bool(val):
86 """
87 >>> parse_bool('True')
88 True
90 >>> parse_bool('true')
91 True
93 >>> parse_bool('')
94 False
95 """
96 if isinstance(val, bool):
97 return val
98 if val.lower() == 'true':
99 return True
100 return False
103 def iterate_together(l1, l2, compare=lambda x, y: cmp(x, y)):
105 takes two ordered, possible sparse, lists l1 and l2 with similar items
106 (some items have a corresponding item in the other list, some don't).
108 It then yield tuples of corresponding items, where one element is None is
109 there is no corresponding entry in one of the lists.
111 Tuples where both elements are None are skipped.
113 compare is a method for comparing items from both lists; it defaults
114 to cmp.
116 >>> list(iterate_together(range(1, 3), range(1, 4, 2)))
117 [(1, 1), (2, None), (None, 3)]
119 >>> list(iterate_together([], []))
122 >>> list(iterate_together(range(1, 3), range(3, 5)))
123 [(1, None), (2, None), (None, 3), (None, 4)]
125 >>> list(iterate_together(range(1, 3), []))
126 [(1, None), (2, None)]
128 >>> list(iterate_together([1, None, 3], [None, None, 3]))
129 [(1, None), (3, 3)]
132 l1 = iter(l1)
133 l2 = iter(l2)
135 def _take(it):
136 try:
137 i = it.next()
138 while i == None:
139 i = it.next()
140 return i, True
141 except StopIteration:
142 return None, False
144 i1, more1 = _take(l1)
145 i2, more2 = _take(l2)
147 while more1 or more2:
148 if not more2 or (i1 != None and compare(i1, i2) < 0):
149 yield(i1, None)
150 i1, more1 = _take(l1)
152 elif not more1 or (i2 != None and compare(i1, i2) > 0):
153 yield(None, i2)
154 i2, more2 = _take(l2)
156 elif compare(i1, i2) == 0:
157 yield(i1, i2)
158 i1, more1 = _take(l1)
159 i2, more2 = _take(l2)
162 def progress(val, max_val, status_str='', max_width=50):
163 print '\r',
164 print '[ %s ] %s / %s | %s' % (
165 '#'*int(float(val)/max_val*max_width) +
166 ' ' * (max_width-(int(float(val)/max_val*max_width))),
167 val,
168 max_val,
169 status_str),