1 """Implements various support classes and functions used in a number of
2 places in Roundup code.
5 __docformat__
= 'restructuredtext'
7 import os
, time
, sys
, re
10 '''Returns True for valid keys, False for others.
12 def __init__(self
, keys
):
18 self
.__getitem__
= lambda name
: 1
20 def __getitem__(self
, name
):
21 return self
.keys
.has_key(name
)
23 def ensureParentsExist(dest
):
24 if not os
.path
.exists(os
.path
.dirname(dest
)):
25 os
.makedirs(os
.path
.dirname(dest
))
28 '''Manages a sorted list.
30 Currently only implements method 'append' and iteration from a
32 Implementation: We manage a "sorted" status and sort on demand.
33 Appending to the list will require re-sorting before use.
35 >>> for i in 5,7,1,-1:
51 def append(self
, item
):
52 self
.list.append(item
)
59 return iter(self
.list)
62 '''Progress display for console applications.
64 See __main__ block at end of file for sample usage.
66 def __init__(self
, info
, sequence
):
68 self
.sequence
= iter(sequence
)
69 self
.total
= len(sequence
)
70 self
.start
= self
.now
= time
.time()
72 self
.stepsize
= self
.total
/ 100 or 1
76 def __iter__(self
): return self
81 if self
.num
> self
.total
:
82 print self
.info
, 'done', ' '*(75-len(self
.info
)-6)
84 return self
.sequence
.next()
86 if self
.num
% self
.stepsize
:
87 return self
.sequence
.next()
90 return self
.sequence
.next()
93 # figure how long we've spent - guess how long to go
95 steptime
= now
- self
.now
96 self
.steptimes
.insert(0, steptime
)
97 if len(self
.steptimes
) > 5:
99 steptime
= sum(self
.steptimes
) / len(self
.steptimes
)
101 eta
= steptime
* ((self
.total
- self
.num
)/self
.stepsize
)
103 # tell it like it is (or might be)
104 if now
- self
.start
> 3:
110 s
= '%s %2d%% (ETA %02d:%02d:%02d)'%(self
.info
,
111 self
.num
* 100. / self
.total
, H
, M
, S
)
113 s
= '%s 0%% (ETA %02d:%02d:%02d)'%(self
.info
, H
, M
, S
)
115 s
= '%s %2d%%'%(self
.info
, self
.num
* 100. / self
.total
)
117 s
= '%s %d done'%(self
.info
, self
.num
)
118 sys
.stdout
.write(s
+ ' '*(75-len(s
)) + '\r')
122 LEFTN
= 'left no strip'
126 def align(line
, width
=70, alignment
=LEFTN
):
127 ''' Code from http://www.faqts.com/knowledge_base/view.phtml/aid/4476 '''
128 if alignment
== CENTER
:
130 space
= width
- len(line
)
131 return ' '*(space
/2) + line
+ ' '*(space
/2 + space
%2)
132 elif alignment
== RIGHT
:
134 space
= width
- len(line
)
135 return ' '*space
+ line
137 if alignment
== LEFT
:
139 space
= width
- len(line
)
140 return line
+ ' '*space
143 def format_line(columns
, positions
, contents
, spacer
=' | ',
144 collapse_whitespace
=True, wsre
=re
.compile(r
'\s+')):
145 ''' Fill up a single row with data from the contents '''
148 for i
in range(len(columns
)):
149 width
, alignment
= columns
[i
]
150 content
= contents
[i
]
152 while positions
[i
] < len(content
):
153 word
= content
[positions
[i
]]
154 # if we hit a newline, honor it
160 # make sure this word fits
161 if col
and len(word
) + len(col
) > width
:
164 # no whitespace at start-of-line
165 if collapse_whitespace
and wsre
.match(word
) and not col
:
175 col
= align(col
, width
, alignment
)
180 return spacer
.join(l
).rstrip()
183 def format_columns(columns
, contents
, spacer
=' | ', collapse_whitespace
=True,
184 splitre
=re
.compile(r
'(\n|\r\n|\r|[ \t]+|\S+)')):
185 ''' Format the contents into columns, with 'spacing' between the
188 assert len(columns
) == len(contents
), \
189 'columns and contents must be same length'
191 # split the text into words, spaces/tabs and newlines
192 for i
in range(len(contents
)):
193 contents
[i
] = splitre
.findall(contents
[i
])
195 # now process line by line
197 positions
= [0]*len(contents
)
199 l
.append(format_line(columns
, positions
, contents
, spacer
,
200 collapse_whitespace
))
203 for i
in range(len(contents
)):
204 if positions
[i
] < len(contents
[i
]):
210 def wrap(text
, width
=75, alignment
=LEFTN
):
211 return format_columns(((width
, alignment
),), [text
],
212 collapse_whitespace
=False)
214 # Python2.3 backwards-compatibility-hack. Should be removed (and clients
215 # fixed to use built-in reversed/sorted) when we abandon support for
228 def sorted(iter, cmp=None, key
=None, reverse
=False):
231 cnt
= 0 # cnt preserves original sort-order
232 inc
= [1, -1][bool(reverse
)] # count down on reverse
234 l
.append ((key(x
), cnt
, x
))
245 return [x
[-1] for x
in l
]
248 # vim: set et sts=4 sw=4 :