##// END OF EJS Templates
add genutils.wrap_deprecated
vivainio -
Show More
@@ -1,1719 +1,1731 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 General purpose utilities.
3 General purpose utilities.
4
4
5 This is a grab-bag of stuff I find useful in most programs I write. Some of
5 This is a grab-bag of stuff I find useful in most programs I write. Some of
6 these things are also convenient when working at the command line.
6 these things are also convenient when working at the command line.
7
7
8 $Id: genutils.py 1845 2006-10-27 20:35:47Z fptest $"""
8 $Id: genutils.py 1930 2006-11-26 17:22:13Z vivainio $"""
9
9
10 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #*****************************************************************************
15 #*****************************************************************************
16
16
17 from IPython import Release
17 from IPython import Release
18 __author__ = '%s <%s>' % Release.authors['Fernando']
18 __author__ = '%s <%s>' % Release.authors['Fernando']
19 __license__ = Release.license
19 __license__ = Release.license
20
20
21 #****************************************************************************
21 #****************************************************************************
22 # required modules from the Python standard library
22 # required modules from the Python standard library
23 import __main__
23 import __main__
24 import commands
24 import commands
25 import os
25 import os
26 import re
26 import re
27 import shlex
27 import shlex
28 import shutil
28 import shutil
29 import sys
29 import sys
30 import tempfile
30 import tempfile
31 import time
31 import time
32 import types
32 import types
33 import warnings
33
34
34 # Other IPython utilities
35 # Other IPython utilities
35 from IPython.Itpl import Itpl,itpl,printpl
36 from IPython.Itpl import Itpl,itpl,printpl
36 from IPython import DPyGetOpt
37 from IPython import DPyGetOpt
37 from path import path
38 from path import path
38 if os.name == "nt":
39 if os.name == "nt":
39 from IPython.winconsole import get_console_size
40 from IPython.winconsole import get_console_size
40
41
41 #****************************************************************************
42 #****************************************************************************
42 # Exceptions
43 # Exceptions
43 class Error(Exception):
44 class Error(Exception):
44 """Base class for exceptions in this module."""
45 """Base class for exceptions in this module."""
45 pass
46 pass
46
47
47 #----------------------------------------------------------------------------
48 #----------------------------------------------------------------------------
48 class IOStream:
49 class IOStream:
49 def __init__(self,stream,fallback):
50 def __init__(self,stream,fallback):
50 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
51 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
51 stream = fallback
52 stream = fallback
52 self.stream = stream
53 self.stream = stream
53 self._swrite = stream.write
54 self._swrite = stream.write
54 self.flush = stream.flush
55 self.flush = stream.flush
55
56
56 def write(self,data):
57 def write(self,data):
57 try:
58 try:
58 self._swrite(data)
59 self._swrite(data)
59 except:
60 except:
60 try:
61 try:
61 # print handles some unicode issues which may trip a plain
62 # print handles some unicode issues which may trip a plain
62 # write() call. Attempt to emulate write() by using a
63 # write() call. Attempt to emulate write() by using a
63 # trailing comma
64 # trailing comma
64 print >> self.stream, data,
65 print >> self.stream, data,
65 except:
66 except:
66 # if we get here, something is seriously broken.
67 # if we get here, something is seriously broken.
67 print >> sys.stderr, \
68 print >> sys.stderr, \
68 'ERROR - failed to write data to stream:', self.stream
69 'ERROR - failed to write data to stream:', self.stream
69
70
70 class IOTerm:
71 class IOTerm:
71 """ Term holds the file or file-like objects for handling I/O operations.
72 """ Term holds the file or file-like objects for handling I/O operations.
72
73
73 These are normally just sys.stdin, sys.stdout and sys.stderr but for
74 These are normally just sys.stdin, sys.stdout and sys.stderr but for
74 Windows they can can replaced to allow editing the strings before they are
75 Windows they can can replaced to allow editing the strings before they are
75 displayed."""
76 displayed."""
76
77
77 # In the future, having IPython channel all its I/O operations through
78 # In the future, having IPython channel all its I/O operations through
78 # this class will make it easier to embed it into other environments which
79 # this class will make it easier to embed it into other environments which
79 # are not a normal terminal (such as a GUI-based shell)
80 # are not a normal terminal (such as a GUI-based shell)
80 def __init__(self,cin=None,cout=None,cerr=None):
81 def __init__(self,cin=None,cout=None,cerr=None):
81 self.cin = IOStream(cin,sys.stdin)
82 self.cin = IOStream(cin,sys.stdin)
82 self.cout = IOStream(cout,sys.stdout)
83 self.cout = IOStream(cout,sys.stdout)
83 self.cerr = IOStream(cerr,sys.stderr)
84 self.cerr = IOStream(cerr,sys.stderr)
84
85
85 # Global variable to be used for all I/O
86 # Global variable to be used for all I/O
86 Term = IOTerm()
87 Term = IOTerm()
87
88
88 import IPython.rlineimpl as readline
89 import IPython.rlineimpl as readline
89 # Remake Term to use the readline i/o facilities
90 # Remake Term to use the readline i/o facilities
90 if sys.platform == 'win32' and readline.have_readline:
91 if sys.platform == 'win32' and readline.have_readline:
91
92
92 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
93 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
93
94
94
95
95 #****************************************************************************
96 #****************************************************************************
96 # Generic warning/error printer, used by everything else
97 # Generic warning/error printer, used by everything else
97 def warn(msg,level=2,exit_val=1):
98 def warn(msg,level=2,exit_val=1):
98 """Standard warning printer. Gives formatting consistency.
99 """Standard warning printer. Gives formatting consistency.
99
100
100 Output is sent to Term.cerr (sys.stderr by default).
101 Output is sent to Term.cerr (sys.stderr by default).
101
102
102 Options:
103 Options:
103
104
104 -level(2): allows finer control:
105 -level(2): allows finer control:
105 0 -> Do nothing, dummy function.
106 0 -> Do nothing, dummy function.
106 1 -> Print message.
107 1 -> Print message.
107 2 -> Print 'WARNING:' + message. (Default level).
108 2 -> Print 'WARNING:' + message. (Default level).
108 3 -> Print 'ERROR:' + message.
109 3 -> Print 'ERROR:' + message.
109 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
110 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
110
111
111 -exit_val (1): exit value returned by sys.exit() for a level 4
112 -exit_val (1): exit value returned by sys.exit() for a level 4
112 warning. Ignored for all other levels."""
113 warning. Ignored for all other levels."""
113
114
114 if level>0:
115 if level>0:
115 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
116 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
116 print >> Term.cerr, '%s%s' % (header[level],msg)
117 print >> Term.cerr, '%s%s' % (header[level],msg)
117 if level == 4:
118 if level == 4:
118 print >> Term.cerr,'Exiting.\n'
119 print >> Term.cerr,'Exiting.\n'
119 sys.exit(exit_val)
120 sys.exit(exit_val)
120
121
121 def info(msg):
122 def info(msg):
122 """Equivalent to warn(msg,level=1)."""
123 """Equivalent to warn(msg,level=1)."""
123
124
124 warn(msg,level=1)
125 warn(msg,level=1)
125
126
126 def error(msg):
127 def error(msg):
127 """Equivalent to warn(msg,level=3)."""
128 """Equivalent to warn(msg,level=3)."""
128
129
129 warn(msg,level=3)
130 warn(msg,level=3)
130
131
131 def fatal(msg,exit_val=1):
132 def fatal(msg,exit_val=1):
132 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
133 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
133
134
134 warn(msg,exit_val=exit_val,level=4)
135 warn(msg,exit_val=exit_val,level=4)
135
136
136 #---------------------------------------------------------------------------
137 #---------------------------------------------------------------------------
137 # Debugging routines
138 # Debugging routines
138 #
139 #
139 def debugx(expr,pre_msg=''):
140 def debugx(expr,pre_msg=''):
140 """Print the value of an expression from the caller's frame.
141 """Print the value of an expression from the caller's frame.
141
142
142 Takes an expression, evaluates it in the caller's frame and prints both
143 Takes an expression, evaluates it in the caller's frame and prints both
143 the given expression and the resulting value (as well as a debug mark
144 the given expression and the resulting value (as well as a debug mark
144 indicating the name of the calling function. The input must be of a form
145 indicating the name of the calling function. The input must be of a form
145 suitable for eval().
146 suitable for eval().
146
147
147 An optional message can be passed, which will be prepended to the printed
148 An optional message can be passed, which will be prepended to the printed
148 expr->value pair."""
149 expr->value pair."""
149
150
150 cf = sys._getframe(1)
151 cf = sys._getframe(1)
151 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
152 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
152 eval(expr,cf.f_globals,cf.f_locals))
153 eval(expr,cf.f_globals,cf.f_locals))
153
154
154 # deactivate it by uncommenting the following line, which makes it a no-op
155 # deactivate it by uncommenting the following line, which makes it a no-op
155 #def debugx(expr,pre_msg=''): pass
156 #def debugx(expr,pre_msg=''): pass
156
157
157 #----------------------------------------------------------------------------
158 #----------------------------------------------------------------------------
158 StringTypes = types.StringTypes
159 StringTypes = types.StringTypes
159
160
160 # Basic timing functionality
161 # Basic timing functionality
161
162
162 # If possible (Unix), use the resource module instead of time.clock()
163 # If possible (Unix), use the resource module instead of time.clock()
163 try:
164 try:
164 import resource
165 import resource
165 def clock():
166 def clock():
166 """clock() -> floating point number
167 """clock() -> floating point number
167
168
168 Return the CPU time in seconds (user time only, system time is
169 Return the CPU time in seconds (user time only, system time is
169 ignored) since the start of the process. This is done via a call to
170 ignored) since the start of the process. This is done via a call to
170 resource.getrusage, so it avoids the wraparound problems in
171 resource.getrusage, so it avoids the wraparound problems in
171 time.clock()."""
172 time.clock()."""
172
173
173 return resource.getrusage(resource.RUSAGE_SELF)[0]
174 return resource.getrusage(resource.RUSAGE_SELF)[0]
174
175
175 def clock2():
176 def clock2():
176 """clock2() -> (t_user,t_system)
177 """clock2() -> (t_user,t_system)
177
178
178 Similar to clock(), but return a tuple of user/system times."""
179 Similar to clock(), but return a tuple of user/system times."""
179 return resource.getrusage(resource.RUSAGE_SELF)[:2]
180 return resource.getrusage(resource.RUSAGE_SELF)[:2]
180
181
181 except ImportError:
182 except ImportError:
182 clock = time.clock
183 clock = time.clock
183 def clock2():
184 def clock2():
184 """Under windows, system CPU time can't be measured.
185 """Under windows, system CPU time can't be measured.
185
186
186 This just returns clock() and zero."""
187 This just returns clock() and zero."""
187 return time.clock(),0.0
188 return time.clock(),0.0
188
189
189 def timings_out(reps,func,*args,**kw):
190 def timings_out(reps,func,*args,**kw):
190 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
191 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
191
192
192 Execute a function reps times, return a tuple with the elapsed total
193 Execute a function reps times, return a tuple with the elapsed total
193 CPU time in seconds, the time per call and the function's output.
194 CPU time in seconds, the time per call and the function's output.
194
195
195 Under Unix, the return value is the sum of user+system time consumed by
196 Under Unix, the return value is the sum of user+system time consumed by
196 the process, computed via the resource module. This prevents problems
197 the process, computed via the resource module. This prevents problems
197 related to the wraparound effect which the time.clock() function has.
198 related to the wraparound effect which the time.clock() function has.
198
199
199 Under Windows the return value is in wall clock seconds. See the
200 Under Windows the return value is in wall clock seconds. See the
200 documentation for the time module for more details."""
201 documentation for the time module for more details."""
201
202
202 reps = int(reps)
203 reps = int(reps)
203 assert reps >=1, 'reps must be >= 1'
204 assert reps >=1, 'reps must be >= 1'
204 if reps==1:
205 if reps==1:
205 start = clock()
206 start = clock()
206 out = func(*args,**kw)
207 out = func(*args,**kw)
207 tot_time = clock()-start
208 tot_time = clock()-start
208 else:
209 else:
209 rng = xrange(reps-1) # the last time is executed separately to store output
210 rng = xrange(reps-1) # the last time is executed separately to store output
210 start = clock()
211 start = clock()
211 for dummy in rng: func(*args,**kw)
212 for dummy in rng: func(*args,**kw)
212 out = func(*args,**kw) # one last time
213 out = func(*args,**kw) # one last time
213 tot_time = clock()-start
214 tot_time = clock()-start
214 av_time = tot_time / reps
215 av_time = tot_time / reps
215 return tot_time,av_time,out
216 return tot_time,av_time,out
216
217
217 def timings(reps,func,*args,**kw):
218 def timings(reps,func,*args,**kw):
218 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
219 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
219
220
220 Execute a function reps times, return a tuple with the elapsed total CPU
221 Execute a function reps times, return a tuple with the elapsed total CPU
221 time in seconds and the time per call. These are just the first two values
222 time in seconds and the time per call. These are just the first two values
222 in timings_out()."""
223 in timings_out()."""
223
224
224 return timings_out(reps,func,*args,**kw)[0:2]
225 return timings_out(reps,func,*args,**kw)[0:2]
225
226
226 def timing(func,*args,**kw):
227 def timing(func,*args,**kw):
227 """timing(func,*args,**kw) -> t_total
228 """timing(func,*args,**kw) -> t_total
228
229
229 Execute a function once, return the elapsed total CPU time in
230 Execute a function once, return the elapsed total CPU time in
230 seconds. This is just the first value in timings_out()."""
231 seconds. This is just the first value in timings_out()."""
231
232
232 return timings_out(1,func,*args,**kw)[0]
233 return timings_out(1,func,*args,**kw)[0]
233
234
234 #****************************************************************************
235 #****************************************************************************
235 # file and system
236 # file and system
236
237
237 def arg_split(s,posix=False):
238 def arg_split(s,posix=False):
238 """Split a command line's arguments in a shell-like manner.
239 """Split a command line's arguments in a shell-like manner.
239
240
240 This is a modified version of the standard library's shlex.split()
241 This is a modified version of the standard library's shlex.split()
241 function, but with a default of posix=False for splitting, so that quotes
242 function, but with a default of posix=False for splitting, so that quotes
242 in inputs are respected."""
243 in inputs are respected."""
243
244
244 lex = shlex.shlex(s, posix=posix)
245 lex = shlex.shlex(s, posix=posix)
245 lex.whitespace_split = True
246 lex.whitespace_split = True
246 return list(lex)
247 return list(lex)
247
248
248 def system(cmd,verbose=0,debug=0,header=''):
249 def system(cmd,verbose=0,debug=0,header=''):
249 """Execute a system command, return its exit status.
250 """Execute a system command, return its exit status.
250
251
251 Options:
252 Options:
252
253
253 - verbose (0): print the command to be executed.
254 - verbose (0): print the command to be executed.
254
255
255 - debug (0): only print, do not actually execute.
256 - debug (0): only print, do not actually execute.
256
257
257 - header (''): Header to print on screen prior to the executed command (it
258 - header (''): Header to print on screen prior to the executed command (it
258 is only prepended to the command, no newlines are added).
259 is only prepended to the command, no newlines are added).
259
260
260 Note: a stateful version of this function is available through the
261 Note: a stateful version of this function is available through the
261 SystemExec class."""
262 SystemExec class."""
262
263
263 stat = 0
264 stat = 0
264 if verbose or debug: print header+cmd
265 if verbose or debug: print header+cmd
265 sys.stdout.flush()
266 sys.stdout.flush()
266 if not debug: stat = os.system(cmd)
267 if not debug: stat = os.system(cmd)
267 return stat
268 return stat
268
269
269 # This function is used by ipython in a lot of places to make system calls.
270 # This function is used by ipython in a lot of places to make system calls.
270 # We need it to be slightly different under win32, due to the vagaries of
271 # We need it to be slightly different under win32, due to the vagaries of
271 # 'network shares'. A win32 override is below.
272 # 'network shares'. A win32 override is below.
272
273
273 def shell(cmd,verbose=0,debug=0,header=''):
274 def shell(cmd,verbose=0,debug=0,header=''):
274 """Execute a command in the system shell, always return None.
275 """Execute a command in the system shell, always return None.
275
276
276 Options:
277 Options:
277
278
278 - verbose (0): print the command to be executed.
279 - verbose (0): print the command to be executed.
279
280
280 - debug (0): only print, do not actually execute.
281 - debug (0): only print, do not actually execute.
281
282
282 - header (''): Header to print on screen prior to the executed command (it
283 - header (''): Header to print on screen prior to the executed command (it
283 is only prepended to the command, no newlines are added).
284 is only prepended to the command, no newlines are added).
284
285
285 Note: this is similar to genutils.system(), but it returns None so it can
286 Note: this is similar to genutils.system(), but it returns None so it can
286 be conveniently used in interactive loops without getting the return value
287 be conveniently used in interactive loops without getting the return value
287 (typically 0) printed many times."""
288 (typically 0) printed many times."""
288
289
289 stat = 0
290 stat = 0
290 if verbose or debug: print header+cmd
291 if verbose or debug: print header+cmd
291 # flush stdout so we don't mangle python's buffering
292 # flush stdout so we don't mangle python's buffering
292 sys.stdout.flush()
293 sys.stdout.flush()
293 if not debug:
294 if not debug:
294 os.system(cmd)
295 os.system(cmd)
295
296
296 # override shell() for win32 to deal with network shares
297 # override shell() for win32 to deal with network shares
297 if os.name in ('nt','dos'):
298 if os.name in ('nt','dos'):
298
299
299 shell_ori = shell
300 shell_ori = shell
300
301
301 def shell(cmd,verbose=0,debug=0,header=''):
302 def shell(cmd,verbose=0,debug=0,header=''):
302 if os.getcwd().startswith(r"\\"):
303 if os.getcwd().startswith(r"\\"):
303 path = os.getcwd()
304 path = os.getcwd()
304 # change to c drive (cannot be on UNC-share when issuing os.system,
305 # change to c drive (cannot be on UNC-share when issuing os.system,
305 # as cmd.exe cannot handle UNC addresses)
306 # as cmd.exe cannot handle UNC addresses)
306 os.chdir("c:")
307 os.chdir("c:")
307 # issue pushd to the UNC-share and then run the command
308 # issue pushd to the UNC-share and then run the command
308 try:
309 try:
309 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
310 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
310 finally:
311 finally:
311 os.chdir(path)
312 os.chdir(path)
312 else:
313 else:
313 shell_ori(cmd,verbose,debug,header)
314 shell_ori(cmd,verbose,debug,header)
314
315
315 shell.__doc__ = shell_ori.__doc__
316 shell.__doc__ = shell_ori.__doc__
316
317
317 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
318 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
318 """Dummy substitute for perl's backquotes.
319 """Dummy substitute for perl's backquotes.
319
320
320 Executes a command and returns the output.
321 Executes a command and returns the output.
321
322
322 Accepts the same arguments as system(), plus:
323 Accepts the same arguments as system(), plus:
323
324
324 - split(0): if true, the output is returned as a list split on newlines.
325 - split(0): if true, the output is returned as a list split on newlines.
325
326
326 Note: a stateful version of this function is available through the
327 Note: a stateful version of this function is available through the
327 SystemExec class.
328 SystemExec class.
328
329
329 This is pretty much deprecated and rarely used,
330 This is pretty much deprecated and rarely used,
330 genutils.getoutputerror may be what you need.
331 genutils.getoutputerror may be what you need.
331
332
332 """
333 """
333
334
334 if verbose or debug: print header+cmd
335 if verbose or debug: print header+cmd
335 if not debug:
336 if not debug:
336 output = os.popen(cmd).read()
337 output = os.popen(cmd).read()
337 # stipping last \n is here for backwards compat.
338 # stipping last \n is here for backwards compat.
338 if output.endswith('\n'):
339 if output.endswith('\n'):
339 output = output[:-1]
340 output = output[:-1]
340 if split:
341 if split:
341 return output.split('\n')
342 return output.split('\n')
342 else:
343 else:
343 return output
344 return output
344
345
345 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
346 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
346 """Return (standard output,standard error) of executing cmd in a shell.
347 """Return (standard output,standard error) of executing cmd in a shell.
347
348
348 Accepts the same arguments as system(), plus:
349 Accepts the same arguments as system(), plus:
349
350
350 - split(0): if true, each of stdout/err is returned as a list split on
351 - split(0): if true, each of stdout/err is returned as a list split on
351 newlines.
352 newlines.
352
353
353 Note: a stateful version of this function is available through the
354 Note: a stateful version of this function is available through the
354 SystemExec class."""
355 SystemExec class."""
355
356
356 if verbose or debug: print header+cmd
357 if verbose or debug: print header+cmd
357 if not cmd:
358 if not cmd:
358 if split:
359 if split:
359 return [],[]
360 return [],[]
360 else:
361 else:
361 return '',''
362 return '',''
362 if not debug:
363 if not debug:
363 pin,pout,perr = os.popen3(cmd)
364 pin,pout,perr = os.popen3(cmd)
364 tout = pout.read().rstrip()
365 tout = pout.read().rstrip()
365 terr = perr.read().rstrip()
366 terr = perr.read().rstrip()
366 pin.close()
367 pin.close()
367 pout.close()
368 pout.close()
368 perr.close()
369 perr.close()
369 if split:
370 if split:
370 return tout.split('\n'),terr.split('\n')
371 return tout.split('\n'),terr.split('\n')
371 else:
372 else:
372 return tout,terr
373 return tout,terr
373
374
374 # for compatibility with older naming conventions
375 # for compatibility with older naming conventions
375 xsys = system
376 xsys = system
376 bq = getoutput
377 bq = getoutput
377
378
378 class SystemExec:
379 class SystemExec:
379 """Access the system and getoutput functions through a stateful interface.
380 """Access the system and getoutput functions through a stateful interface.
380
381
381 Note: here we refer to the system and getoutput functions from this
382 Note: here we refer to the system and getoutput functions from this
382 library, not the ones from the standard python library.
383 library, not the ones from the standard python library.
383
384
384 This class offers the system and getoutput functions as methods, but the
385 This class offers the system and getoutput functions as methods, but the
385 verbose, debug and header parameters can be set for the instance (at
386 verbose, debug and header parameters can be set for the instance (at
386 creation time or later) so that they don't need to be specified on each
387 creation time or later) so that they don't need to be specified on each
387 call.
388 call.
388
389
389 For efficiency reasons, there's no way to override the parameters on a
390 For efficiency reasons, there's no way to override the parameters on a
390 per-call basis other than by setting instance attributes. If you need
391 per-call basis other than by setting instance attributes. If you need
391 local overrides, it's best to directly call system() or getoutput().
392 local overrides, it's best to directly call system() or getoutput().
392
393
393 The following names are provided as alternate options:
394 The following names are provided as alternate options:
394 - xsys: alias to system
395 - xsys: alias to system
395 - bq: alias to getoutput
396 - bq: alias to getoutput
396
397
397 An instance can then be created as:
398 An instance can then be created as:
398 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
399 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
399
400
400 And used as:
401 And used as:
401 >>> sysexec.xsys('pwd')
402 >>> sysexec.xsys('pwd')
402 >>> dirlist = sysexec.bq('ls -l')
403 >>> dirlist = sysexec.bq('ls -l')
403 """
404 """
404
405
405 def __init__(self,verbose=0,debug=0,header='',split=0):
406 def __init__(self,verbose=0,debug=0,header='',split=0):
406 """Specify the instance's values for verbose, debug and header."""
407 """Specify the instance's values for verbose, debug and header."""
407 setattr_list(self,'verbose debug header split')
408 setattr_list(self,'verbose debug header split')
408
409
409 def system(self,cmd):
410 def system(self,cmd):
410 """Stateful interface to system(), with the same keyword parameters."""
411 """Stateful interface to system(), with the same keyword parameters."""
411
412
412 system(cmd,self.verbose,self.debug,self.header)
413 system(cmd,self.verbose,self.debug,self.header)
413
414
414 def shell(self,cmd):
415 def shell(self,cmd):
415 """Stateful interface to shell(), with the same keyword parameters."""
416 """Stateful interface to shell(), with the same keyword parameters."""
416
417
417 shell(cmd,self.verbose,self.debug,self.header)
418 shell(cmd,self.verbose,self.debug,self.header)
418
419
419 xsys = system # alias
420 xsys = system # alias
420
421
421 def getoutput(self,cmd):
422 def getoutput(self,cmd):
422 """Stateful interface to getoutput()."""
423 """Stateful interface to getoutput()."""
423
424
424 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
425 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
425
426
426 def getoutputerror(self,cmd):
427 def getoutputerror(self,cmd):
427 """Stateful interface to getoutputerror()."""
428 """Stateful interface to getoutputerror()."""
428
429
429 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
430 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
430
431
431 bq = getoutput # alias
432 bq = getoutput # alias
432
433
433 #-----------------------------------------------------------------------------
434 #-----------------------------------------------------------------------------
434 def mutex_opts(dict,ex_op):
435 def mutex_opts(dict,ex_op):
435 """Check for presence of mutually exclusive keys in a dict.
436 """Check for presence of mutually exclusive keys in a dict.
436
437
437 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
438 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
438 for op1,op2 in ex_op:
439 for op1,op2 in ex_op:
439 if op1 in dict and op2 in dict:
440 if op1 in dict and op2 in dict:
440 raise ValueError,'\n*** ERROR in Arguments *** '\
441 raise ValueError,'\n*** ERROR in Arguments *** '\
441 'Options '+op1+' and '+op2+' are mutually exclusive.'
442 'Options '+op1+' and '+op2+' are mutually exclusive.'
442
443
443 #-----------------------------------------------------------------------------
444 #-----------------------------------------------------------------------------
444 def get_py_filename(name):
445 def get_py_filename(name):
445 """Return a valid python filename in the current directory.
446 """Return a valid python filename in the current directory.
446
447
447 If the given name is not a file, it adds '.py' and searches again.
448 If the given name is not a file, it adds '.py' and searches again.
448 Raises IOError with an informative message if the file isn't found."""
449 Raises IOError with an informative message if the file isn't found."""
449
450
450 name = os.path.expanduser(name)
451 name = os.path.expanduser(name)
451 if not os.path.isfile(name) and not name.endswith('.py'):
452 if not os.path.isfile(name) and not name.endswith('.py'):
452 name += '.py'
453 name += '.py'
453 if os.path.isfile(name):
454 if os.path.isfile(name):
454 return name
455 return name
455 else:
456 else:
456 raise IOError,'File `%s` not found.' % name
457 raise IOError,'File `%s` not found.' % name
457
458
458 #-----------------------------------------------------------------------------
459 #-----------------------------------------------------------------------------
459 def filefind(fname,alt_dirs = None):
460 def filefind(fname,alt_dirs = None):
460 """Return the given filename either in the current directory, if it
461 """Return the given filename either in the current directory, if it
461 exists, or in a specified list of directories.
462 exists, or in a specified list of directories.
462
463
463 ~ expansion is done on all file and directory names.
464 ~ expansion is done on all file and directory names.
464
465
465 Upon an unsuccessful search, raise an IOError exception."""
466 Upon an unsuccessful search, raise an IOError exception."""
466
467
467 if alt_dirs is None:
468 if alt_dirs is None:
468 try:
469 try:
469 alt_dirs = get_home_dir()
470 alt_dirs = get_home_dir()
470 except HomeDirError:
471 except HomeDirError:
471 alt_dirs = os.getcwd()
472 alt_dirs = os.getcwd()
472 search = [fname] + list_strings(alt_dirs)
473 search = [fname] + list_strings(alt_dirs)
473 search = map(os.path.expanduser,search)
474 search = map(os.path.expanduser,search)
474 #print 'search list for',fname,'list:',search # dbg
475 #print 'search list for',fname,'list:',search # dbg
475 fname = search[0]
476 fname = search[0]
476 if os.path.isfile(fname):
477 if os.path.isfile(fname):
477 return fname
478 return fname
478 for direc in search[1:]:
479 for direc in search[1:]:
479 testname = os.path.join(direc,fname)
480 testname = os.path.join(direc,fname)
480 #print 'testname',testname # dbg
481 #print 'testname',testname # dbg
481 if os.path.isfile(testname):
482 if os.path.isfile(testname):
482 return testname
483 return testname
483 raise IOError,'File' + `fname` + \
484 raise IOError,'File' + `fname` + \
484 ' not found in current or supplied directories:' + `alt_dirs`
485 ' not found in current or supplied directories:' + `alt_dirs`
485
486
486 #----------------------------------------------------------------------------
487 #----------------------------------------------------------------------------
487 def file_read(filename):
488 def file_read(filename):
488 """Read a file and close it. Returns the file source."""
489 """Read a file and close it. Returns the file source."""
489 fobj = open(filename,'r');
490 fobj = open(filename,'r');
490 source = fobj.read();
491 source = fobj.read();
491 fobj.close()
492 fobj.close()
492 return source
493 return source
493
494
494 def file_readlines(filename):
495 def file_readlines(filename):
495 """Read a file and close it. Returns the file source using readlines()."""
496 """Read a file and close it. Returns the file source using readlines()."""
496 fobj = open(filename,'r');
497 fobj = open(filename,'r');
497 lines = fobj.readlines();
498 lines = fobj.readlines();
498 fobj.close()
499 fobj.close()
499 return lines
500 return lines
500
501
501 #----------------------------------------------------------------------------
502 #----------------------------------------------------------------------------
502 def target_outdated(target,deps):
503 def target_outdated(target,deps):
503 """Determine whether a target is out of date.
504 """Determine whether a target is out of date.
504
505
505 target_outdated(target,deps) -> 1/0
506 target_outdated(target,deps) -> 1/0
506
507
507 deps: list of filenames which MUST exist.
508 deps: list of filenames which MUST exist.
508 target: single filename which may or may not exist.
509 target: single filename which may or may not exist.
509
510
510 If target doesn't exist or is older than any file listed in deps, return
511 If target doesn't exist or is older than any file listed in deps, return
511 true, otherwise return false.
512 true, otherwise return false.
512 """
513 """
513 try:
514 try:
514 target_time = os.path.getmtime(target)
515 target_time = os.path.getmtime(target)
515 except os.error:
516 except os.error:
516 return 1
517 return 1
517 for dep in deps:
518 for dep in deps:
518 dep_time = os.path.getmtime(dep)
519 dep_time = os.path.getmtime(dep)
519 if dep_time > target_time:
520 if dep_time > target_time:
520 #print "For target",target,"Dep failed:",dep # dbg
521 #print "For target",target,"Dep failed:",dep # dbg
521 #print "times (dep,tar):",dep_time,target_time # dbg
522 #print "times (dep,tar):",dep_time,target_time # dbg
522 return 1
523 return 1
523 return 0
524 return 0
524
525
525 #-----------------------------------------------------------------------------
526 #-----------------------------------------------------------------------------
526 def target_update(target,deps,cmd):
527 def target_update(target,deps,cmd):
527 """Update a target with a given command given a list of dependencies.
528 """Update a target with a given command given a list of dependencies.
528
529
529 target_update(target,deps,cmd) -> runs cmd if target is outdated.
530 target_update(target,deps,cmd) -> runs cmd if target is outdated.
530
531
531 This is just a wrapper around target_outdated() which calls the given
532 This is just a wrapper around target_outdated() which calls the given
532 command if target is outdated."""
533 command if target is outdated."""
533
534
534 if target_outdated(target,deps):
535 if target_outdated(target,deps):
535 xsys(cmd)
536 xsys(cmd)
536
537
537 #----------------------------------------------------------------------------
538 #----------------------------------------------------------------------------
538 def unquote_ends(istr):
539 def unquote_ends(istr):
539 """Remove a single pair of quotes from the endpoints of a string."""
540 """Remove a single pair of quotes from the endpoints of a string."""
540
541
541 if not istr:
542 if not istr:
542 return istr
543 return istr
543 if (istr[0]=="'" and istr[-1]=="'") or \
544 if (istr[0]=="'" and istr[-1]=="'") or \
544 (istr[0]=='"' and istr[-1]=='"'):
545 (istr[0]=='"' and istr[-1]=='"'):
545 return istr[1:-1]
546 return istr[1:-1]
546 else:
547 else:
547 return istr
548 return istr
548
549
549 #----------------------------------------------------------------------------
550 #----------------------------------------------------------------------------
550 def process_cmdline(argv,names=[],defaults={},usage=''):
551 def process_cmdline(argv,names=[],defaults={},usage=''):
551 """ Process command-line options and arguments.
552 """ Process command-line options and arguments.
552
553
553 Arguments:
554 Arguments:
554
555
555 - argv: list of arguments, typically sys.argv.
556 - argv: list of arguments, typically sys.argv.
556
557
557 - names: list of option names. See DPyGetOpt docs for details on options
558 - names: list of option names. See DPyGetOpt docs for details on options
558 syntax.
559 syntax.
559
560
560 - defaults: dict of default values.
561 - defaults: dict of default values.
561
562
562 - usage: optional usage notice to print if a wrong argument is passed.
563 - usage: optional usage notice to print if a wrong argument is passed.
563
564
564 Return a dict of options and a list of free arguments."""
565 Return a dict of options and a list of free arguments."""
565
566
566 getopt = DPyGetOpt.DPyGetOpt()
567 getopt = DPyGetOpt.DPyGetOpt()
567 getopt.setIgnoreCase(0)
568 getopt.setIgnoreCase(0)
568 getopt.parseConfiguration(names)
569 getopt.parseConfiguration(names)
569
570
570 try:
571 try:
571 getopt.processArguments(argv)
572 getopt.processArguments(argv)
572 except:
573 except:
573 print usage
574 print usage
574 warn(`sys.exc_value`,level=4)
575 warn(`sys.exc_value`,level=4)
575
576
576 defaults.update(getopt.optionValues)
577 defaults.update(getopt.optionValues)
577 args = getopt.freeValues
578 args = getopt.freeValues
578
579
579 return defaults,args
580 return defaults,args
580
581
581 #----------------------------------------------------------------------------
582 #----------------------------------------------------------------------------
582 def optstr2types(ostr):
583 def optstr2types(ostr):
583 """Convert a string of option names to a dict of type mappings.
584 """Convert a string of option names to a dict of type mappings.
584
585
585 optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
586 optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
586
587
587 This is used to get the types of all the options in a string formatted
588 This is used to get the types of all the options in a string formatted
588 with the conventions of DPyGetOpt. The 'type' None is used for options
589 with the conventions of DPyGetOpt. The 'type' None is used for options
589 which are strings (they need no further conversion). This function's main
590 which are strings (they need no further conversion). This function's main
590 use is to get a typemap for use with read_dict().
591 use is to get a typemap for use with read_dict().
591 """
592 """
592
593
593 typeconv = {None:'',int:'',float:''}
594 typeconv = {None:'',int:'',float:''}
594 typemap = {'s':None,'i':int,'f':float}
595 typemap = {'s':None,'i':int,'f':float}
595 opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
596 opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
596
597
597 for w in ostr.split():
598 for w in ostr.split():
598 oname,alias,otype = opt_re.match(w).groups()
599 oname,alias,otype = opt_re.match(w).groups()
599 if otype == '' or alias == '!': # simple switches are integers too
600 if otype == '' or alias == '!': # simple switches are integers too
600 otype = 'i'
601 otype = 'i'
601 typeconv[typemap[otype]] += oname + ' '
602 typeconv[typemap[otype]] += oname + ' '
602 return typeconv
603 return typeconv
603
604
604 #----------------------------------------------------------------------------
605 #----------------------------------------------------------------------------
605 def read_dict(filename,type_conv=None,**opt):
606 def read_dict(filename,type_conv=None,**opt):
606
607
607 """Read a dictionary of key=value pairs from an input file, optionally
608 """Read a dictionary of key=value pairs from an input file, optionally
608 performing conversions on the resulting values.
609 performing conversions on the resulting values.
609
610
610 read_dict(filename,type_conv,**opt) -> dict
611 read_dict(filename,type_conv,**opt) -> dict
611
612
612 Only one value per line is accepted, the format should be
613 Only one value per line is accepted, the format should be
613 # optional comments are ignored
614 # optional comments are ignored
614 key value\n
615 key value\n
615
616
616 Args:
617 Args:
617
618
618 - type_conv: A dictionary specifying which keys need to be converted to
619 - type_conv: A dictionary specifying which keys need to be converted to
619 which types. By default all keys are read as strings. This dictionary
620 which types. By default all keys are read as strings. This dictionary
620 should have as its keys valid conversion functions for strings
621 should have as its keys valid conversion functions for strings
621 (int,long,float,complex, or your own). The value for each key
622 (int,long,float,complex, or your own). The value for each key
622 (converter) should be a whitespace separated string containing the names
623 (converter) should be a whitespace separated string containing the names
623 of all the entries in the file to be converted using that function. For
624 of all the entries in the file to be converted using that function. For
624 keys to be left alone, use None as the conversion function (only needed
625 keys to be left alone, use None as the conversion function (only needed
625 with purge=1, see below).
626 with purge=1, see below).
626
627
627 - opt: dictionary with extra options as below (default in parens)
628 - opt: dictionary with extra options as below (default in parens)
628
629
629 purge(0): if set to 1, all keys *not* listed in type_conv are purged out
630 purge(0): if set to 1, all keys *not* listed in type_conv are purged out
630 of the dictionary to be returned. If purge is going to be used, the
631 of the dictionary to be returned. If purge is going to be used, the
631 set of keys to be left as strings also has to be explicitly specified
632 set of keys to be left as strings also has to be explicitly specified
632 using the (non-existent) conversion function None.
633 using the (non-existent) conversion function None.
633
634
634 fs(None): field separator. This is the key/value separator to be used
635 fs(None): field separator. This is the key/value separator to be used
635 when parsing the file. The None default means any whitespace [behavior
636 when parsing the file. The None default means any whitespace [behavior
636 of string.split()].
637 of string.split()].
637
638
638 strip(0): if 1, strip string values of leading/trailinig whitespace.
639 strip(0): if 1, strip string values of leading/trailinig whitespace.
639
640
640 warn(1): warning level if requested keys are not found in file.
641 warn(1): warning level if requested keys are not found in file.
641 - 0: silently ignore.
642 - 0: silently ignore.
642 - 1: inform but proceed.
643 - 1: inform but proceed.
643 - 2: raise KeyError exception.
644 - 2: raise KeyError exception.
644
645
645 no_empty(0): if 1, remove keys with whitespace strings as a value.
646 no_empty(0): if 1, remove keys with whitespace strings as a value.
646
647
647 unique([]): list of keys (or space separated string) which can't be
648 unique([]): list of keys (or space separated string) which can't be
648 repeated. If one such key is found in the file, each new instance
649 repeated. If one such key is found in the file, each new instance
649 overwrites the previous one. For keys not listed here, the behavior is
650 overwrites the previous one. For keys not listed here, the behavior is
650 to make a list of all appearances.
651 to make a list of all appearances.
651
652
652 Example:
653 Example:
653 If the input file test.ini has:
654 If the input file test.ini has:
654 i 3
655 i 3
655 x 4.5
656 x 4.5
656 y 5.5
657 y 5.5
657 s hi ho
658 s hi ho
658 Then:
659 Then:
659
660
660 >>> type_conv={int:'i',float:'x',None:'s'}
661 >>> type_conv={int:'i',float:'x',None:'s'}
661 >>> read_dict('test.ini')
662 >>> read_dict('test.ini')
662 {'i': '3', 's': 'hi ho', 'x': '4.5', 'y': '5.5'}
663 {'i': '3', 's': 'hi ho', 'x': '4.5', 'y': '5.5'}
663 >>> read_dict('test.ini',type_conv)
664 >>> read_dict('test.ini',type_conv)
664 {'i': 3, 's': 'hi ho', 'x': 4.5, 'y': '5.5'}
665 {'i': 3, 's': 'hi ho', 'x': 4.5, 'y': '5.5'}
665 >>> read_dict('test.ini',type_conv,purge=1)
666 >>> read_dict('test.ini',type_conv,purge=1)
666 {'i': 3, 's': 'hi ho', 'x': 4.5}
667 {'i': 3, 's': 'hi ho', 'x': 4.5}
667 """
668 """
668
669
669 # starting config
670 # starting config
670 opt.setdefault('purge',0)
671 opt.setdefault('purge',0)
671 opt.setdefault('fs',None) # field sep defaults to any whitespace
672 opt.setdefault('fs',None) # field sep defaults to any whitespace
672 opt.setdefault('strip',0)
673 opt.setdefault('strip',0)
673 opt.setdefault('warn',1)
674 opt.setdefault('warn',1)
674 opt.setdefault('no_empty',0)
675 opt.setdefault('no_empty',0)
675 opt.setdefault('unique','')
676 opt.setdefault('unique','')
676 if type(opt['unique']) in StringTypes:
677 if type(opt['unique']) in StringTypes:
677 unique_keys = qw(opt['unique'])
678 unique_keys = qw(opt['unique'])
678 elif type(opt['unique']) in (types.TupleType,types.ListType):
679 elif type(opt['unique']) in (types.TupleType,types.ListType):
679 unique_keys = opt['unique']
680 unique_keys = opt['unique']
680 else:
681 else:
681 raise ValueError, 'Unique keys must be given as a string, List or Tuple'
682 raise ValueError, 'Unique keys must be given as a string, List or Tuple'
682
683
683 dict = {}
684 dict = {}
684 # first read in table of values as strings
685 # first read in table of values as strings
685 file = open(filename,'r')
686 file = open(filename,'r')
686 for line in file.readlines():
687 for line in file.readlines():
687 line = line.strip()
688 line = line.strip()
688 if len(line) and line[0]=='#': continue
689 if len(line) and line[0]=='#': continue
689 if len(line)>0:
690 if len(line)>0:
690 lsplit = line.split(opt['fs'],1)
691 lsplit = line.split(opt['fs'],1)
691 try:
692 try:
692 key,val = lsplit
693 key,val = lsplit
693 except ValueError:
694 except ValueError:
694 key,val = lsplit[0],''
695 key,val = lsplit[0],''
695 key = key.strip()
696 key = key.strip()
696 if opt['strip']: val = val.strip()
697 if opt['strip']: val = val.strip()
697 if val == "''" or val == '""': val = ''
698 if val == "''" or val == '""': val = ''
698 if opt['no_empty'] and (val=='' or val.isspace()):
699 if opt['no_empty'] and (val=='' or val.isspace()):
699 continue
700 continue
700 # if a key is found more than once in the file, build a list
701 # if a key is found more than once in the file, build a list
701 # unless it's in the 'unique' list. In that case, last found in file
702 # unless it's in the 'unique' list. In that case, last found in file
702 # takes precedence. User beware.
703 # takes precedence. User beware.
703 try:
704 try:
704 if dict[key] and key in unique_keys:
705 if dict[key] and key in unique_keys:
705 dict[key] = val
706 dict[key] = val
706 elif type(dict[key]) is types.ListType:
707 elif type(dict[key]) is types.ListType:
707 dict[key].append(val)
708 dict[key].append(val)
708 else:
709 else:
709 dict[key] = [dict[key],val]
710 dict[key] = [dict[key],val]
710 except KeyError:
711 except KeyError:
711 dict[key] = val
712 dict[key] = val
712 # purge if requested
713 # purge if requested
713 if opt['purge']:
714 if opt['purge']:
714 accepted_keys = qwflat(type_conv.values())
715 accepted_keys = qwflat(type_conv.values())
715 for key in dict.keys():
716 for key in dict.keys():
716 if key in accepted_keys: continue
717 if key in accepted_keys: continue
717 del(dict[key])
718 del(dict[key])
718 # now convert if requested
719 # now convert if requested
719 if type_conv==None: return dict
720 if type_conv==None: return dict
720 conversions = type_conv.keys()
721 conversions = type_conv.keys()
721 try: conversions.remove(None)
722 try: conversions.remove(None)
722 except: pass
723 except: pass
723 for convert in conversions:
724 for convert in conversions:
724 for val in qw(type_conv[convert]):
725 for val in qw(type_conv[convert]):
725 try:
726 try:
726 dict[val] = convert(dict[val])
727 dict[val] = convert(dict[val])
727 except KeyError,e:
728 except KeyError,e:
728 if opt['warn'] == 0:
729 if opt['warn'] == 0:
729 pass
730 pass
730 elif opt['warn'] == 1:
731 elif opt['warn'] == 1:
731 print >>sys.stderr, 'Warning: key',val,\
732 print >>sys.stderr, 'Warning: key',val,\
732 'not found in file',filename
733 'not found in file',filename
733 elif opt['warn'] == 2:
734 elif opt['warn'] == 2:
734 raise KeyError,e
735 raise KeyError,e
735 else:
736 else:
736 raise ValueError,'Warning level must be 0,1 or 2'
737 raise ValueError,'Warning level must be 0,1 or 2'
737
738
738 return dict
739 return dict
739
740
740 #----------------------------------------------------------------------------
741 #----------------------------------------------------------------------------
741 def flag_calls(func):
742 def flag_calls(func):
742 """Wrap a function to detect and flag when it gets called.
743 """Wrap a function to detect and flag when it gets called.
743
744
744 This is a decorator which takes a function and wraps it in a function with
745 This is a decorator which takes a function and wraps it in a function with
745 a 'called' attribute. wrapper.called is initialized to False.
746 a 'called' attribute. wrapper.called is initialized to False.
746
747
747 The wrapper.called attribute is set to False right before each call to the
748 The wrapper.called attribute is set to False right before each call to the
748 wrapped function, so if the call fails it remains False. After the call
749 wrapped function, so if the call fails it remains False. After the call
749 completes, wrapper.called is set to True and the output is returned.
750 completes, wrapper.called is set to True and the output is returned.
750
751
751 Testing for truth in wrapper.called allows you to determine if a call to
752 Testing for truth in wrapper.called allows you to determine if a call to
752 func() was attempted and succeeded."""
753 func() was attempted and succeeded."""
753
754
754 def wrapper(*args,**kw):
755 def wrapper(*args,**kw):
755 wrapper.called = False
756 wrapper.called = False
756 out = func(*args,**kw)
757 out = func(*args,**kw)
757 wrapper.called = True
758 wrapper.called = True
758 return out
759 return out
759
760
760 wrapper.called = False
761 wrapper.called = False
761 wrapper.__doc__ = func.__doc__
762 wrapper.__doc__ = func.__doc__
762 return wrapper
763 return wrapper
763
764
764 #----------------------------------------------------------------------------
765 #----------------------------------------------------------------------------
765 class HomeDirError(Error):
766 class HomeDirError(Error):
766 pass
767 pass
767
768
768 def get_home_dir():
769 def get_home_dir():
769 """Return the closest possible equivalent to a 'home' directory.
770 """Return the closest possible equivalent to a 'home' directory.
770
771
771 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
772 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
772
773
773 Currently only Posix and NT are implemented, a HomeDirError exception is
774 Currently only Posix and NT are implemented, a HomeDirError exception is
774 raised for all other OSes. """
775 raised for all other OSes. """
775
776
776 isdir = os.path.isdir
777 isdir = os.path.isdir
777 env = os.environ
778 env = os.environ
778 try:
779 try:
779 homedir = env['HOME']
780 homedir = env['HOME']
780 if not isdir(homedir):
781 if not isdir(homedir):
781 # in case a user stuck some string which does NOT resolve to a
782 # in case a user stuck some string which does NOT resolve to a
782 # valid path, it's as good as if we hadn't foud it
783 # valid path, it's as good as if we hadn't foud it
783 raise KeyError
784 raise KeyError
784 return homedir
785 return homedir
785 except KeyError:
786 except KeyError:
786 if os.name == 'posix':
787 if os.name == 'posix':
787 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
788 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
788 elif os.name == 'nt':
789 elif os.name == 'nt':
789 # For some strange reason, win9x returns 'nt' for os.name.
790 # For some strange reason, win9x returns 'nt' for os.name.
790 try:
791 try:
791 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
792 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
792 if not isdir(homedir):
793 if not isdir(homedir):
793 homedir = os.path.join(env['USERPROFILE'])
794 homedir = os.path.join(env['USERPROFILE'])
794 if not isdir(homedir):
795 if not isdir(homedir):
795 raise HomeDirError
796 raise HomeDirError
796 return homedir
797 return homedir
797 except:
798 except:
798 try:
799 try:
799 # Use the registry to get the 'My Documents' folder.
800 # Use the registry to get the 'My Documents' folder.
800 import _winreg as wreg
801 import _winreg as wreg
801 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
802 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
802 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
803 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
803 homedir = wreg.QueryValueEx(key,'Personal')[0]
804 homedir = wreg.QueryValueEx(key,'Personal')[0]
804 key.Close()
805 key.Close()
805 if not isdir(homedir):
806 if not isdir(homedir):
806 e = ('Invalid "Personal" folder registry key '
807 e = ('Invalid "Personal" folder registry key '
807 'typically "My Documents".\n'
808 'typically "My Documents".\n'
808 'Value: %s\n'
809 'Value: %s\n'
809 'This is not a valid directory on your system.' %
810 'This is not a valid directory on your system.' %
810 homedir)
811 homedir)
811 raise HomeDirError(e)
812 raise HomeDirError(e)
812 return homedir
813 return homedir
813 except HomeDirError:
814 except HomeDirError:
814 raise
815 raise
815 except:
816 except:
816 return 'C:\\'
817 return 'C:\\'
817 elif os.name == 'dos':
818 elif os.name == 'dos':
818 # Desperate, may do absurd things in classic MacOS. May work under DOS.
819 # Desperate, may do absurd things in classic MacOS. May work under DOS.
819 return 'C:\\'
820 return 'C:\\'
820 else:
821 else:
821 raise HomeDirError,'support for your operating system not implemented.'
822 raise HomeDirError,'support for your operating system not implemented.'
822
823
823 #****************************************************************************
824 #****************************************************************************
824 # strings and text
825 # strings and text
825
826
826 class LSString(str):
827 class LSString(str):
827 """String derivative with a special access attributes.
828 """String derivative with a special access attributes.
828
829
829 These are normal strings, but with the special attributes:
830 These are normal strings, but with the special attributes:
830
831
831 .l (or .list) : value as list (split on newlines).
832 .l (or .list) : value as list (split on newlines).
832 .n (or .nlstr): original value (the string itself).
833 .n (or .nlstr): original value (the string itself).
833 .s (or .spstr): value as whitespace-separated string.
834 .s (or .spstr): value as whitespace-separated string.
834
835
835 Any values which require transformations are computed only once and
836 Any values which require transformations are computed only once and
836 cached.
837 cached.
837
838
838 Such strings are very useful to efficiently interact with the shell, which
839 Such strings are very useful to efficiently interact with the shell, which
839 typically only understands whitespace-separated options for commands."""
840 typically only understands whitespace-separated options for commands."""
840
841
841 def get_list(self):
842 def get_list(self):
842 try:
843 try:
843 return self.__list
844 return self.__list
844 except AttributeError:
845 except AttributeError:
845 self.__list = self.split('\n')
846 self.__list = self.split('\n')
846 return self.__list
847 return self.__list
847
848
848 l = list = property(get_list)
849 l = list = property(get_list)
849
850
850 def get_spstr(self):
851 def get_spstr(self):
851 try:
852 try:
852 return self.__spstr
853 return self.__spstr
853 except AttributeError:
854 except AttributeError:
854 self.__spstr = self.replace('\n',' ')
855 self.__spstr = self.replace('\n',' ')
855 return self.__spstr
856 return self.__spstr
856
857
857 s = spstr = property(get_spstr)
858 s = spstr = property(get_spstr)
858
859
859 def get_nlstr(self):
860 def get_nlstr(self):
860 return self
861 return self
861
862
862 n = nlstr = property(get_nlstr)
863 n = nlstr = property(get_nlstr)
863
864
864 def get_paths(self):
865 def get_paths(self):
865 try:
866 try:
866 return self.__paths
867 return self.__paths
867 except AttributeError:
868 except AttributeError:
868 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
869 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
869 return self.__paths
870 return self.__paths
870
871
871 p = paths = property(get_paths)
872 p = paths = property(get_paths)
872
873
873
874
874 #----------------------------------------------------------------------------
875 #----------------------------------------------------------------------------
875 class SList(list):
876 class SList(list):
876 """List derivative with a special access attributes.
877 """List derivative with a special access attributes.
877
878
878 These are normal lists, but with the special attributes:
879 These are normal lists, but with the special attributes:
879
880
880 .l (or .list) : value as list (the list itself).
881 .l (or .list) : value as list (the list itself).
881 .n (or .nlstr): value as a string, joined on newlines.
882 .n (or .nlstr): value as a string, joined on newlines.
882 .s (or .spstr): value as a string, joined on spaces.
883 .s (or .spstr): value as a string, joined on spaces.
883
884
884 Any values which require transformations are computed only once and
885 Any values which require transformations are computed only once and
885 cached."""
886 cached."""
886
887
887 def get_list(self):
888 def get_list(self):
888 return self
889 return self
889
890
890 l = list = property(get_list)
891 l = list = property(get_list)
891
892
892 def get_spstr(self):
893 def get_spstr(self):
893 try:
894 try:
894 return self.__spstr
895 return self.__spstr
895 except AttributeError:
896 except AttributeError:
896 self.__spstr = ' '.join(self)
897 self.__spstr = ' '.join(self)
897 return self.__spstr
898 return self.__spstr
898
899
899 s = spstr = property(get_spstr)
900 s = spstr = property(get_spstr)
900
901
901 def get_nlstr(self):
902 def get_nlstr(self):
902 try:
903 try:
903 return self.__nlstr
904 return self.__nlstr
904 except AttributeError:
905 except AttributeError:
905 self.__nlstr = '\n'.join(self)
906 self.__nlstr = '\n'.join(self)
906 return self.__nlstr
907 return self.__nlstr
907
908
908 n = nlstr = property(get_nlstr)
909 n = nlstr = property(get_nlstr)
909
910
910 def get_paths(self):
911 def get_paths(self):
911 try:
912 try:
912 return self.__paths
913 return self.__paths
913 except AttributeError:
914 except AttributeError:
914 self.__paths = [path(p) for p in self if os.path.exists(p)]
915 self.__paths = [path(p) for p in self if os.path.exists(p)]
915 return self.__paths
916 return self.__paths
916
917
917 p = paths = property(get_paths)
918 p = paths = property(get_paths)
918
919
919 #----------------------------------------------------------------------------
920 #----------------------------------------------------------------------------
920 def esc_quotes(strng):
921 def esc_quotes(strng):
921 """Return the input string with single and double quotes escaped out"""
922 """Return the input string with single and double quotes escaped out"""
922
923
923 return strng.replace('"','\\"').replace("'","\\'")
924 return strng.replace('"','\\"').replace("'","\\'")
924
925
925 #----------------------------------------------------------------------------
926 #----------------------------------------------------------------------------
926 def make_quoted_expr(s):
927 def make_quoted_expr(s):
927 """Return string s in appropriate quotes, using raw string if possible.
928 """Return string s in appropriate quotes, using raw string if possible.
928
929
929 Effectively this turns string: cd \ao\ao\
930 Effectively this turns string: cd \ao\ao\
930 to: r"cd \ao\ao\_"[:-1]
931 to: r"cd \ao\ao\_"[:-1]
931
932
932 Note the use of raw string and padding at the end to allow trailing backslash.
933 Note the use of raw string and padding at the end to allow trailing backslash.
933
934
934 """
935 """
935
936
936 tail = ''
937 tail = ''
937 tailpadding = ''
938 tailpadding = ''
938 raw = ''
939 raw = ''
939 if "\\" in s:
940 if "\\" in s:
940 raw = 'r'
941 raw = 'r'
941 if s.endswith('\\'):
942 if s.endswith('\\'):
942 tail = '[:-1]'
943 tail = '[:-1]'
943 tailpadding = '_'
944 tailpadding = '_'
944 if '"' not in s:
945 if '"' not in s:
945 quote = '"'
946 quote = '"'
946 elif "'" not in s:
947 elif "'" not in s:
947 quote = "'"
948 quote = "'"
948 elif '"""' not in s and not s.endswith('"'):
949 elif '"""' not in s and not s.endswith('"'):
949 quote = '"""'
950 quote = '"""'
950 elif "'''" not in s and not s.endswith("'"):
951 elif "'''" not in s and not s.endswith("'"):
951 quote = "'''"
952 quote = "'''"
952 else:
953 else:
953 # give up, backslash-escaped string will do
954 # give up, backslash-escaped string will do
954 return '"%s"' % esc_quotes(s)
955 return '"%s"' % esc_quotes(s)
955 res = itpl("$raw$quote$s$tailpadding$quote$tail")
956 res = itpl("$raw$quote$s$tailpadding$quote$tail")
956 return res
957 return res
957
958
958
959
959 #----------------------------------------------------------------------------
960 #----------------------------------------------------------------------------
960 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
961 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
961 """Take multiple lines of input.
962 """Take multiple lines of input.
962
963
963 A list with each line of input as a separate element is returned when a
964 A list with each line of input as a separate element is returned when a
964 termination string is entered (defaults to a single '.'). Input can also
965 termination string is entered (defaults to a single '.'). Input can also
965 terminate via EOF (^D in Unix, ^Z-RET in Windows).
966 terminate via EOF (^D in Unix, ^Z-RET in Windows).
966
967
967 Lines of input which end in \\ are joined into single entries (and a
968 Lines of input which end in \\ are joined into single entries (and a
968 secondary continuation prompt is issued as long as the user terminates
969 secondary continuation prompt is issued as long as the user terminates
969 lines with \\). This allows entering very long strings which are still
970 lines with \\). This allows entering very long strings which are still
970 meant to be treated as single entities.
971 meant to be treated as single entities.
971 """
972 """
972
973
973 try:
974 try:
974 if header:
975 if header:
975 header += '\n'
976 header += '\n'
976 lines = [raw_input(header + ps1)]
977 lines = [raw_input(header + ps1)]
977 except EOFError:
978 except EOFError:
978 return []
979 return []
979 terminate = [terminate_str]
980 terminate = [terminate_str]
980 try:
981 try:
981 while lines[-1:] != terminate:
982 while lines[-1:] != terminate:
982 new_line = raw_input(ps1)
983 new_line = raw_input(ps1)
983 while new_line.endswith('\\'):
984 while new_line.endswith('\\'):
984 new_line = new_line[:-1] + raw_input(ps2)
985 new_line = new_line[:-1] + raw_input(ps2)
985 lines.append(new_line)
986 lines.append(new_line)
986
987
987 return lines[:-1] # don't return the termination command
988 return lines[:-1] # don't return the termination command
988 except EOFError:
989 except EOFError:
989 print
990 print
990 return lines
991 return lines
991
992
992 #----------------------------------------------------------------------------
993 #----------------------------------------------------------------------------
993 def raw_input_ext(prompt='', ps2='... '):
994 def raw_input_ext(prompt='', ps2='... '):
994 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
995 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
995
996
996 line = raw_input(prompt)
997 line = raw_input(prompt)
997 while line.endswith('\\'):
998 while line.endswith('\\'):
998 line = line[:-1] + raw_input(ps2)
999 line = line[:-1] + raw_input(ps2)
999 return line
1000 return line
1000
1001
1001 #----------------------------------------------------------------------------
1002 #----------------------------------------------------------------------------
1002 def ask_yes_no(prompt,default=None):
1003 def ask_yes_no(prompt,default=None):
1003 """Asks a question and returns an integer 1/0 (y/n) answer.
1004 """Asks a question and returns an integer 1/0 (y/n) answer.
1004
1005
1005 If default is given (one of 'y','n'), it is used if the user input is
1006 If default is given (one of 'y','n'), it is used if the user input is
1006 empty. Otherwise the question is repeated until an answer is given.
1007 empty. Otherwise the question is repeated until an answer is given.
1007
1008
1008 An EOF is treated as the default answer. If there is no default, an
1009 An EOF is treated as the default answer. If there is no default, an
1009 exception is raised to prevent infinite loops.
1010 exception is raised to prevent infinite loops.
1010
1011
1011 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1012 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1012
1013
1013 answers = {'y':True,'n':False,'yes':True,'no':False}
1014 answers = {'y':True,'n':False,'yes':True,'no':False}
1014 ans = None
1015 ans = None
1015 while ans not in answers.keys():
1016 while ans not in answers.keys():
1016 try:
1017 try:
1017 ans = raw_input(prompt+' ').lower()
1018 ans = raw_input(prompt+' ').lower()
1018 if not ans: # response was an empty string
1019 if not ans: # response was an empty string
1019 ans = default
1020 ans = default
1020 except KeyboardInterrupt:
1021 except KeyboardInterrupt:
1021 pass
1022 pass
1022 except EOFError:
1023 except EOFError:
1023 if default in answers.keys():
1024 if default in answers.keys():
1024 ans = default
1025 ans = default
1025 print
1026 print
1026 else:
1027 else:
1027 raise
1028 raise
1028
1029
1029 return answers[ans]
1030 return answers[ans]
1030
1031
1031 #----------------------------------------------------------------------------
1032 #----------------------------------------------------------------------------
1032 def marquee(txt='',width=78,mark='*'):
1033 def marquee(txt='',width=78,mark='*'):
1033 """Return the input string centered in a 'marquee'."""
1034 """Return the input string centered in a 'marquee'."""
1034 if not txt:
1035 if not txt:
1035 return (mark*width)[:width]
1036 return (mark*width)[:width]
1036 nmark = (width-len(txt)-2)/len(mark)/2
1037 nmark = (width-len(txt)-2)/len(mark)/2
1037 if nmark < 0: nmark =0
1038 if nmark < 0: nmark =0
1038 marks = mark*nmark
1039 marks = mark*nmark
1039 return '%s %s %s' % (marks,txt,marks)
1040 return '%s %s %s' % (marks,txt,marks)
1040
1041
1041 #----------------------------------------------------------------------------
1042 #----------------------------------------------------------------------------
1042 class EvalDict:
1043 class EvalDict:
1043 """
1044 """
1044 Emulate a dict which evaluates its contents in the caller's frame.
1045 Emulate a dict which evaluates its contents in the caller's frame.
1045
1046
1046 Usage:
1047 Usage:
1047 >>>number = 19
1048 >>>number = 19
1048 >>>text = "python"
1049 >>>text = "python"
1049 >>>print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1050 >>>print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1050 """
1051 """
1051
1052
1052 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1053 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1053 # modified (shorter) version of:
1054 # modified (shorter) version of:
1054 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1055 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1055 # Skip Montanaro (skip@pobox.com).
1056 # Skip Montanaro (skip@pobox.com).
1056
1057
1057 def __getitem__(self, name):
1058 def __getitem__(self, name):
1058 frame = sys._getframe(1)
1059 frame = sys._getframe(1)
1059 return eval(name, frame.f_globals, frame.f_locals)
1060 return eval(name, frame.f_globals, frame.f_locals)
1060
1061
1061 EvalString = EvalDict # for backwards compatibility
1062 EvalString = EvalDict # for backwards compatibility
1062 #----------------------------------------------------------------------------
1063 #----------------------------------------------------------------------------
1063 def qw(words,flat=0,sep=None,maxsplit=-1):
1064 def qw(words,flat=0,sep=None,maxsplit=-1):
1064 """Similar to Perl's qw() operator, but with some more options.
1065 """Similar to Perl's qw() operator, but with some more options.
1065
1066
1066 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1067 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1067
1068
1068 words can also be a list itself, and with flat=1, the output will be
1069 words can also be a list itself, and with flat=1, the output will be
1069 recursively flattened. Examples:
1070 recursively flattened. Examples:
1070
1071
1071 >>> qw('1 2')
1072 >>> qw('1 2')
1072 ['1', '2']
1073 ['1', '2']
1073 >>> qw(['a b','1 2',['m n','p q']])
1074 >>> qw(['a b','1 2',['m n','p q']])
1074 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1075 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1075 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1076 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1076 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] """
1077 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q'] """
1077
1078
1078 if type(words) in StringTypes:
1079 if type(words) in StringTypes:
1079 return [word.strip() for word in words.split(sep,maxsplit)
1080 return [word.strip() for word in words.split(sep,maxsplit)
1080 if word and not word.isspace() ]
1081 if word and not word.isspace() ]
1081 if flat:
1082 if flat:
1082 return flatten(map(qw,words,[1]*len(words)))
1083 return flatten(map(qw,words,[1]*len(words)))
1083 return map(qw,words)
1084 return map(qw,words)
1084
1085
1085 #----------------------------------------------------------------------------
1086 #----------------------------------------------------------------------------
1086 def qwflat(words,sep=None,maxsplit=-1):
1087 def qwflat(words,sep=None,maxsplit=-1):
1087 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1088 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1088 return qw(words,1,sep,maxsplit)
1089 return qw(words,1,sep,maxsplit)
1089
1090
1090 #----------------------------------------------------------------------------
1091 #----------------------------------------------------------------------------
1091 def qw_lol(indata):
1092 def qw_lol(indata):
1092 """qw_lol('a b') -> [['a','b']],
1093 """qw_lol('a b') -> [['a','b']],
1093 otherwise it's just a call to qw().
1094 otherwise it's just a call to qw().
1094
1095
1095 We need this to make sure the modules_some keys *always* end up as a
1096 We need this to make sure the modules_some keys *always* end up as a
1096 list of lists."""
1097 list of lists."""
1097
1098
1098 if type(indata) in StringTypes:
1099 if type(indata) in StringTypes:
1099 return [qw(indata)]
1100 return [qw(indata)]
1100 else:
1101 else:
1101 return qw(indata)
1102 return qw(indata)
1102
1103
1103 #-----------------------------------------------------------------------------
1104 #-----------------------------------------------------------------------------
1104 def list_strings(arg):
1105 def list_strings(arg):
1105 """Always return a list of strings, given a string or list of strings
1106 """Always return a list of strings, given a string or list of strings
1106 as input."""
1107 as input."""
1107
1108
1108 if type(arg) in StringTypes: return [arg]
1109 if type(arg) in StringTypes: return [arg]
1109 else: return arg
1110 else: return arg
1110
1111
1111 #----------------------------------------------------------------------------
1112 #----------------------------------------------------------------------------
1112 def grep(pat,list,case=1):
1113 def grep(pat,list,case=1):
1113 """Simple minded grep-like function.
1114 """Simple minded grep-like function.
1114 grep(pat,list) returns occurrences of pat in list, None on failure.
1115 grep(pat,list) returns occurrences of pat in list, None on failure.
1115
1116
1116 It only does simple string matching, with no support for regexps. Use the
1117 It only does simple string matching, with no support for regexps. Use the
1117 option case=0 for case-insensitive matching."""
1118 option case=0 for case-insensitive matching."""
1118
1119
1119 # This is pretty crude. At least it should implement copying only references
1120 # This is pretty crude. At least it should implement copying only references
1120 # to the original data in case it's big. Now it copies the data for output.
1121 # to the original data in case it's big. Now it copies the data for output.
1121 out=[]
1122 out=[]
1122 if case:
1123 if case:
1123 for term in list:
1124 for term in list:
1124 if term.find(pat)>-1: out.append(term)
1125 if term.find(pat)>-1: out.append(term)
1125 else:
1126 else:
1126 lpat=pat.lower()
1127 lpat=pat.lower()
1127 for term in list:
1128 for term in list:
1128 if term.lower().find(lpat)>-1: out.append(term)
1129 if term.lower().find(lpat)>-1: out.append(term)
1129
1130
1130 if len(out): return out
1131 if len(out): return out
1131 else: return None
1132 else: return None
1132
1133
1133 #----------------------------------------------------------------------------
1134 #----------------------------------------------------------------------------
1134 def dgrep(pat,*opts):
1135 def dgrep(pat,*opts):
1135 """Return grep() on dir()+dir(__builtins__).
1136 """Return grep() on dir()+dir(__builtins__).
1136
1137
1137 A very common use of grep() when working interactively."""
1138 A very common use of grep() when working interactively."""
1138
1139
1139 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1140 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1140
1141
1141 #----------------------------------------------------------------------------
1142 #----------------------------------------------------------------------------
1142 def idgrep(pat):
1143 def idgrep(pat):
1143 """Case-insensitive dgrep()"""
1144 """Case-insensitive dgrep()"""
1144
1145
1145 return dgrep(pat,0)
1146 return dgrep(pat,0)
1146
1147
1147 #----------------------------------------------------------------------------
1148 #----------------------------------------------------------------------------
1148 def igrep(pat,list):
1149 def igrep(pat,list):
1149 """Synonym for case-insensitive grep."""
1150 """Synonym for case-insensitive grep."""
1150
1151
1151 return grep(pat,list,case=0)
1152 return grep(pat,list,case=0)
1152
1153
1153 #----------------------------------------------------------------------------
1154 #----------------------------------------------------------------------------
1154 def indent(str,nspaces=4,ntabs=0):
1155 def indent(str,nspaces=4,ntabs=0):
1155 """Indent a string a given number of spaces or tabstops.
1156 """Indent a string a given number of spaces or tabstops.
1156
1157
1157 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1158 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1158 """
1159 """
1159 if str is None:
1160 if str is None:
1160 return
1161 return
1161 ind = '\t'*ntabs+' '*nspaces
1162 ind = '\t'*ntabs+' '*nspaces
1162 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1163 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1163 if outstr.endswith(os.linesep+ind):
1164 if outstr.endswith(os.linesep+ind):
1164 return outstr[:-len(ind)]
1165 return outstr[:-len(ind)]
1165 else:
1166 else:
1166 return outstr
1167 return outstr
1167
1168
1168 #-----------------------------------------------------------------------------
1169 #-----------------------------------------------------------------------------
1169 def native_line_ends(filename,backup=1):
1170 def native_line_ends(filename,backup=1):
1170 """Convert (in-place) a file to line-ends native to the current OS.
1171 """Convert (in-place) a file to line-ends native to the current OS.
1171
1172
1172 If the optional backup argument is given as false, no backup of the
1173 If the optional backup argument is given as false, no backup of the
1173 original file is left. """
1174 original file is left. """
1174
1175
1175 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1176 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1176
1177
1177 bak_filename = filename + backup_suffixes[os.name]
1178 bak_filename = filename + backup_suffixes[os.name]
1178
1179
1179 original = open(filename).read()
1180 original = open(filename).read()
1180 shutil.copy2(filename,bak_filename)
1181 shutil.copy2(filename,bak_filename)
1181 try:
1182 try:
1182 new = open(filename,'wb')
1183 new = open(filename,'wb')
1183 new.write(os.linesep.join(original.splitlines()))
1184 new.write(os.linesep.join(original.splitlines()))
1184 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1185 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1185 new.close()
1186 new.close()
1186 except:
1187 except:
1187 os.rename(bak_filename,filename)
1188 os.rename(bak_filename,filename)
1188 if not backup:
1189 if not backup:
1189 try:
1190 try:
1190 os.remove(bak_filename)
1191 os.remove(bak_filename)
1191 except:
1192 except:
1192 pass
1193 pass
1193
1194
1194 #----------------------------------------------------------------------------
1195 #----------------------------------------------------------------------------
1195 def get_pager_cmd(pager_cmd = None):
1196 def get_pager_cmd(pager_cmd = None):
1196 """Return a pager command.
1197 """Return a pager command.
1197
1198
1198 Makes some attempts at finding an OS-correct one."""
1199 Makes some attempts at finding an OS-correct one."""
1199
1200
1200 if os.name == 'posix':
1201 if os.name == 'posix':
1201 default_pager_cmd = 'less -r' # -r for color control sequences
1202 default_pager_cmd = 'less -r' # -r for color control sequences
1202 elif os.name in ['nt','dos']:
1203 elif os.name in ['nt','dos']:
1203 default_pager_cmd = 'type'
1204 default_pager_cmd = 'type'
1204
1205
1205 if pager_cmd is None:
1206 if pager_cmd is None:
1206 try:
1207 try:
1207 pager_cmd = os.environ['PAGER']
1208 pager_cmd = os.environ['PAGER']
1208 except:
1209 except:
1209 pager_cmd = default_pager_cmd
1210 pager_cmd = default_pager_cmd
1210 return pager_cmd
1211 return pager_cmd
1211
1212
1212 #-----------------------------------------------------------------------------
1213 #-----------------------------------------------------------------------------
1213 def get_pager_start(pager,start):
1214 def get_pager_start(pager,start):
1214 """Return the string for paging files with an offset.
1215 """Return the string for paging files with an offset.
1215
1216
1216 This is the '+N' argument which less and more (under Unix) accept.
1217 This is the '+N' argument which less and more (under Unix) accept.
1217 """
1218 """
1218
1219
1219 if pager in ['less','more']:
1220 if pager in ['less','more']:
1220 if start:
1221 if start:
1221 start_string = '+' + str(start)
1222 start_string = '+' + str(start)
1222 else:
1223 else:
1223 start_string = ''
1224 start_string = ''
1224 else:
1225 else:
1225 start_string = ''
1226 start_string = ''
1226 return start_string
1227 return start_string
1227
1228
1228 #----------------------------------------------------------------------------
1229 #----------------------------------------------------------------------------
1229 if os.name == "nt":
1230 if os.name == "nt":
1230 import msvcrt
1231 import msvcrt
1231 def page_more():
1232 def page_more():
1232 """ Smart pausing between pages
1233 """ Smart pausing between pages
1233
1234
1234 @return: True if need print more lines, False if quit
1235 @return: True if need print more lines, False if quit
1235 """
1236 """
1236 Term.cout.write('---Return to continue, q to quit--- ')
1237 Term.cout.write('---Return to continue, q to quit--- ')
1237 ans = msvcrt.getch()
1238 ans = msvcrt.getch()
1238 if ans in ("q", "Q"):
1239 if ans in ("q", "Q"):
1239 result = False
1240 result = False
1240 else:
1241 else:
1241 result = True
1242 result = True
1242 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
1243 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
1243 return result
1244 return result
1244 else:
1245 else:
1245 def page_more():
1246 def page_more():
1246 ans = raw_input('---Return to continue, q to quit--- ')
1247 ans = raw_input('---Return to continue, q to quit--- ')
1247 if ans.lower().startswith('q'):
1248 if ans.lower().startswith('q'):
1248 return False
1249 return False
1249 else:
1250 else:
1250 return True
1251 return True
1251
1252
1252 esc_re = re.compile(r"(\x1b[^m]+m)")
1253 esc_re = re.compile(r"(\x1b[^m]+m)")
1253
1254
1254 def page_dumb(strng,start=0,screen_lines=25):
1255 def page_dumb(strng,start=0,screen_lines=25):
1255 """Very dumb 'pager' in Python, for when nothing else works.
1256 """Very dumb 'pager' in Python, for when nothing else works.
1256
1257
1257 Only moves forward, same interface as page(), except for pager_cmd and
1258 Only moves forward, same interface as page(), except for pager_cmd and
1258 mode."""
1259 mode."""
1259
1260
1260 out_ln = strng.splitlines()[start:]
1261 out_ln = strng.splitlines()[start:]
1261 screens = chop(out_ln,screen_lines-1)
1262 screens = chop(out_ln,screen_lines-1)
1262 if len(screens) == 1:
1263 if len(screens) == 1:
1263 print >>Term.cout, os.linesep.join(screens[0])
1264 print >>Term.cout, os.linesep.join(screens[0])
1264 else:
1265 else:
1265 last_escape = ""
1266 last_escape = ""
1266 for scr in screens[0:-1]:
1267 for scr in screens[0:-1]:
1267 hunk = os.linesep.join(scr)
1268 hunk = os.linesep.join(scr)
1268 print >>Term.cout, last_escape + hunk
1269 print >>Term.cout, last_escape + hunk
1269 if not page_more():
1270 if not page_more():
1270 return
1271 return
1271 esc_list = esc_re.findall(hunk)
1272 esc_list = esc_re.findall(hunk)
1272 if len(esc_list) > 0:
1273 if len(esc_list) > 0:
1273 last_escape = esc_list[-1]
1274 last_escape = esc_list[-1]
1274 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
1275 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
1275
1276
1276 #----------------------------------------------------------------------------
1277 #----------------------------------------------------------------------------
1277 def page(strng,start=0,screen_lines=0,pager_cmd = None):
1278 def page(strng,start=0,screen_lines=0,pager_cmd = None):
1278 """Print a string, piping through a pager after a certain length.
1279 """Print a string, piping through a pager after a certain length.
1279
1280
1280 The screen_lines parameter specifies the number of *usable* lines of your
1281 The screen_lines parameter specifies the number of *usable* lines of your
1281 terminal screen (total lines minus lines you need to reserve to show other
1282 terminal screen (total lines minus lines you need to reserve to show other
1282 information).
1283 information).
1283
1284
1284 If you set screen_lines to a number <=0, page() will try to auto-determine
1285 If you set screen_lines to a number <=0, page() will try to auto-determine
1285 your screen size and will only use up to (screen_size+screen_lines) for
1286 your screen size and will only use up to (screen_size+screen_lines) for
1286 printing, paging after that. That is, if you want auto-detection but need
1287 printing, paging after that. That is, if you want auto-detection but need
1287 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
1288 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
1288 auto-detection without any lines reserved simply use screen_lines = 0.
1289 auto-detection without any lines reserved simply use screen_lines = 0.
1289
1290
1290 If a string won't fit in the allowed lines, it is sent through the
1291 If a string won't fit in the allowed lines, it is sent through the
1291 specified pager command. If none given, look for PAGER in the environment,
1292 specified pager command. If none given, look for PAGER in the environment,
1292 and ultimately default to less.
1293 and ultimately default to less.
1293
1294
1294 If no system pager works, the string is sent through a 'dumb pager'
1295 If no system pager works, the string is sent through a 'dumb pager'
1295 written in python, very simplistic.
1296 written in python, very simplistic.
1296 """
1297 """
1297
1298
1298 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
1299 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
1299 TERM = os.environ.get('TERM','dumb')
1300 TERM = os.environ.get('TERM','dumb')
1300 if TERM in ['dumb','emacs'] and os.name != 'nt':
1301 if TERM in ['dumb','emacs'] and os.name != 'nt':
1301 print strng
1302 print strng
1302 return
1303 return
1303 # chop off the topmost part of the string we don't want to see
1304 # chop off the topmost part of the string we don't want to see
1304 str_lines = strng.split(os.linesep)[start:]
1305 str_lines = strng.split(os.linesep)[start:]
1305 str_toprint = os.linesep.join(str_lines)
1306 str_toprint = os.linesep.join(str_lines)
1306 num_newlines = len(str_lines)
1307 num_newlines = len(str_lines)
1307 len_str = len(str_toprint)
1308 len_str = len(str_toprint)
1308
1309
1309 # Dumb heuristics to guesstimate number of on-screen lines the string
1310 # Dumb heuristics to guesstimate number of on-screen lines the string
1310 # takes. Very basic, but good enough for docstrings in reasonable
1311 # takes. Very basic, but good enough for docstrings in reasonable
1311 # terminals. If someone later feels like refining it, it's not hard.
1312 # terminals. If someone later feels like refining it, it's not hard.
1312 numlines = max(num_newlines,int(len_str/80)+1)
1313 numlines = max(num_newlines,int(len_str/80)+1)
1313
1314
1314 if os.name == "nt":
1315 if os.name == "nt":
1315 screen_lines_def = get_console_size(defaulty=25)[1]
1316 screen_lines_def = get_console_size(defaulty=25)[1]
1316 else:
1317 else:
1317 screen_lines_def = 25 # default value if we can't auto-determine
1318 screen_lines_def = 25 # default value if we can't auto-determine
1318
1319
1319 # auto-determine screen size
1320 # auto-determine screen size
1320 if screen_lines <= 0:
1321 if screen_lines <= 0:
1321 if TERM=='xterm':
1322 if TERM=='xterm':
1322 try:
1323 try:
1323 import curses
1324 import curses
1324 if hasattr(curses,'initscr'):
1325 if hasattr(curses,'initscr'):
1325 use_curses = 1
1326 use_curses = 1
1326 else:
1327 else:
1327 use_curses = 0
1328 use_curses = 0
1328 except ImportError:
1329 except ImportError:
1329 use_curses = 0
1330 use_curses = 0
1330 else:
1331 else:
1331 # curses causes problems on many terminals other than xterm.
1332 # curses causes problems on many terminals other than xterm.
1332 use_curses = 0
1333 use_curses = 0
1333 if use_curses:
1334 if use_curses:
1334 scr = curses.initscr()
1335 scr = curses.initscr()
1335 screen_lines_real,screen_cols = scr.getmaxyx()
1336 screen_lines_real,screen_cols = scr.getmaxyx()
1336 curses.endwin()
1337 curses.endwin()
1337 screen_lines += screen_lines_real
1338 screen_lines += screen_lines_real
1338 #print '***Screen size:',screen_lines_real,'lines x',\
1339 #print '***Screen size:',screen_lines_real,'lines x',\
1339 #screen_cols,'columns.' # dbg
1340 #screen_cols,'columns.' # dbg
1340 else:
1341 else:
1341 screen_lines += screen_lines_def
1342 screen_lines += screen_lines_def
1342
1343
1343 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1344 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1344 if numlines <= screen_lines :
1345 if numlines <= screen_lines :
1345 #print '*** normal print' # dbg
1346 #print '*** normal print' # dbg
1346 print >>Term.cout, str_toprint
1347 print >>Term.cout, str_toprint
1347 else:
1348 else:
1348 # Try to open pager and default to internal one if that fails.
1349 # Try to open pager and default to internal one if that fails.
1349 # All failure modes are tagged as 'retval=1', to match the return
1350 # All failure modes are tagged as 'retval=1', to match the return
1350 # value of a failed system command. If any intermediate attempt
1351 # value of a failed system command. If any intermediate attempt
1351 # sets retval to 1, at the end we resort to our own page_dumb() pager.
1352 # sets retval to 1, at the end we resort to our own page_dumb() pager.
1352 pager_cmd = get_pager_cmd(pager_cmd)
1353 pager_cmd = get_pager_cmd(pager_cmd)
1353 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1354 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1354 if os.name == 'nt':
1355 if os.name == 'nt':
1355 if pager_cmd.startswith('type'):
1356 if pager_cmd.startswith('type'):
1356 # The default WinXP 'type' command is failing on complex strings.
1357 # The default WinXP 'type' command is failing on complex strings.
1357 retval = 1
1358 retval = 1
1358 else:
1359 else:
1359 tmpname = tempfile.mktemp('.txt')
1360 tmpname = tempfile.mktemp('.txt')
1360 tmpfile = file(tmpname,'wt')
1361 tmpfile = file(tmpname,'wt')
1361 tmpfile.write(strng)
1362 tmpfile.write(strng)
1362 tmpfile.close()
1363 tmpfile.close()
1363 cmd = "%s < %s" % (pager_cmd,tmpname)
1364 cmd = "%s < %s" % (pager_cmd,tmpname)
1364 if os.system(cmd):
1365 if os.system(cmd):
1365 retval = 1
1366 retval = 1
1366 else:
1367 else:
1367 retval = None
1368 retval = None
1368 os.remove(tmpname)
1369 os.remove(tmpname)
1369 else:
1370 else:
1370 try:
1371 try:
1371 retval = None
1372 retval = None
1372 # if I use popen4, things hang. No idea why.
1373 # if I use popen4, things hang. No idea why.
1373 #pager,shell_out = os.popen4(pager_cmd)
1374 #pager,shell_out = os.popen4(pager_cmd)
1374 pager = os.popen(pager_cmd,'w')
1375 pager = os.popen(pager_cmd,'w')
1375 pager.write(strng)
1376 pager.write(strng)
1376 pager.close()
1377 pager.close()
1377 retval = pager.close() # success returns None
1378 retval = pager.close() # success returns None
1378 except IOError,msg: # broken pipe when user quits
1379 except IOError,msg: # broken pipe when user quits
1379 if msg.args == (32,'Broken pipe'):
1380 if msg.args == (32,'Broken pipe'):
1380 retval = None
1381 retval = None
1381 else:
1382 else:
1382 retval = 1
1383 retval = 1
1383 except OSError:
1384 except OSError:
1384 # Other strange problems, sometimes seen in Win2k/cygwin
1385 # Other strange problems, sometimes seen in Win2k/cygwin
1385 retval = 1
1386 retval = 1
1386 if retval is not None:
1387 if retval is not None:
1387 page_dumb(strng,screen_lines=screen_lines)
1388 page_dumb(strng,screen_lines=screen_lines)
1388
1389
1389 #----------------------------------------------------------------------------
1390 #----------------------------------------------------------------------------
1390 def page_file(fname,start = 0, pager_cmd = None):
1391 def page_file(fname,start = 0, pager_cmd = None):
1391 """Page a file, using an optional pager command and starting line.
1392 """Page a file, using an optional pager command and starting line.
1392 """
1393 """
1393
1394
1394 pager_cmd = get_pager_cmd(pager_cmd)
1395 pager_cmd = get_pager_cmd(pager_cmd)
1395 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1396 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1396
1397
1397 try:
1398 try:
1398 if os.environ['TERM'] in ['emacs','dumb']:
1399 if os.environ['TERM'] in ['emacs','dumb']:
1399 raise EnvironmentError
1400 raise EnvironmentError
1400 xsys(pager_cmd + ' ' + fname)
1401 xsys(pager_cmd + ' ' + fname)
1401 except:
1402 except:
1402 try:
1403 try:
1403 if start > 0:
1404 if start > 0:
1404 start -= 1
1405 start -= 1
1405 page(open(fname).read(),start)
1406 page(open(fname).read(),start)
1406 except:
1407 except:
1407 print 'Unable to show file',`fname`
1408 print 'Unable to show file',`fname`
1408
1409
1409 #----------------------------------------------------------------------------
1410 #----------------------------------------------------------------------------
1410 def snip_print(str,width = 75,print_full = 0,header = ''):
1411 def snip_print(str,width = 75,print_full = 0,header = ''):
1411 """Print a string snipping the midsection to fit in width.
1412 """Print a string snipping the midsection to fit in width.
1412
1413
1413 print_full: mode control:
1414 print_full: mode control:
1414 - 0: only snip long strings
1415 - 0: only snip long strings
1415 - 1: send to page() directly.
1416 - 1: send to page() directly.
1416 - 2: snip long strings and ask for full length viewing with page()
1417 - 2: snip long strings and ask for full length viewing with page()
1417 Return 1 if snipping was necessary, 0 otherwise."""
1418 Return 1 if snipping was necessary, 0 otherwise."""
1418
1419
1419 if print_full == 1:
1420 if print_full == 1:
1420 page(header+str)
1421 page(header+str)
1421 return 0
1422 return 0
1422
1423
1423 print header,
1424 print header,
1424 if len(str) < width:
1425 if len(str) < width:
1425 print str
1426 print str
1426 snip = 0
1427 snip = 0
1427 else:
1428 else:
1428 whalf = int((width -5)/2)
1429 whalf = int((width -5)/2)
1429 print str[:whalf] + ' <...> ' + str[-whalf:]
1430 print str[:whalf] + ' <...> ' + str[-whalf:]
1430 snip = 1
1431 snip = 1
1431 if snip and print_full == 2:
1432 if snip and print_full == 2:
1432 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
1433 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
1433 page(str)
1434 page(str)
1434 return snip
1435 return snip
1435
1436
1436 #****************************************************************************
1437 #****************************************************************************
1437 # lists, dicts and structures
1438 # lists, dicts and structures
1438
1439
1439 def belong(candidates,checklist):
1440 def belong(candidates,checklist):
1440 """Check whether a list of items appear in a given list of options.
1441 """Check whether a list of items appear in a given list of options.
1441
1442
1442 Returns a list of 1 and 0, one for each candidate given."""
1443 Returns a list of 1 and 0, one for each candidate given."""
1443
1444
1444 return [x in checklist for x in candidates]
1445 return [x in checklist for x in candidates]
1445
1446
1446 #----------------------------------------------------------------------------
1447 #----------------------------------------------------------------------------
1447 def uniq_stable(elems):
1448 def uniq_stable(elems):
1448 """uniq_stable(elems) -> list
1449 """uniq_stable(elems) -> list
1449
1450
1450 Return from an iterable, a list of all the unique elements in the input,
1451 Return from an iterable, a list of all the unique elements in the input,
1451 but maintaining the order in which they first appear.
1452 but maintaining the order in which they first appear.
1452
1453
1453 A naive solution to this problem which just makes a dictionary with the
1454 A naive solution to this problem which just makes a dictionary with the
1454 elements as keys fails to respect the stability condition, since
1455 elements as keys fails to respect the stability condition, since
1455 dictionaries are unsorted by nature.
1456 dictionaries are unsorted by nature.
1456
1457
1457 Note: All elements in the input must be valid dictionary keys for this
1458 Note: All elements in the input must be valid dictionary keys for this
1458 routine to work, as it internally uses a dictionary for efficiency
1459 routine to work, as it internally uses a dictionary for efficiency
1459 reasons."""
1460 reasons."""
1460
1461
1461 unique = []
1462 unique = []
1462 unique_dict = {}
1463 unique_dict = {}
1463 for nn in elems:
1464 for nn in elems:
1464 if nn not in unique_dict:
1465 if nn not in unique_dict:
1465 unique.append(nn)
1466 unique.append(nn)
1466 unique_dict[nn] = None
1467 unique_dict[nn] = None
1467 return unique
1468 return unique
1468
1469
1469 #----------------------------------------------------------------------------
1470 #----------------------------------------------------------------------------
1470 class NLprinter:
1471 class NLprinter:
1471 """Print an arbitrarily nested list, indicating index numbers.
1472 """Print an arbitrarily nested list, indicating index numbers.
1472
1473
1473 An instance of this class called nlprint is available and callable as a
1474 An instance of this class called nlprint is available and callable as a
1474 function.
1475 function.
1475
1476
1476 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1477 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1477 and using 'sep' to separate the index from the value. """
1478 and using 'sep' to separate the index from the value. """
1478
1479
1479 def __init__(self):
1480 def __init__(self):
1480 self.depth = 0
1481 self.depth = 0
1481
1482
1482 def __call__(self,lst,pos='',**kw):
1483 def __call__(self,lst,pos='',**kw):
1483 """Prints the nested list numbering levels."""
1484 """Prints the nested list numbering levels."""
1484 kw.setdefault('indent',' ')
1485 kw.setdefault('indent',' ')
1485 kw.setdefault('sep',': ')
1486 kw.setdefault('sep',': ')
1486 kw.setdefault('start',0)
1487 kw.setdefault('start',0)
1487 kw.setdefault('stop',len(lst))
1488 kw.setdefault('stop',len(lst))
1488 # we need to remove start and stop from kw so they don't propagate
1489 # we need to remove start and stop from kw so they don't propagate
1489 # into a recursive call for a nested list.
1490 # into a recursive call for a nested list.
1490 start = kw['start']; del kw['start']
1491 start = kw['start']; del kw['start']
1491 stop = kw['stop']; del kw['stop']
1492 stop = kw['stop']; del kw['stop']
1492 if self.depth == 0 and 'header' in kw.keys():
1493 if self.depth == 0 and 'header' in kw.keys():
1493 print kw['header']
1494 print kw['header']
1494
1495
1495 for idx in range(start,stop):
1496 for idx in range(start,stop):
1496 elem = lst[idx]
1497 elem = lst[idx]
1497 if type(elem)==type([]):
1498 if type(elem)==type([]):
1498 self.depth += 1
1499 self.depth += 1
1499 self.__call__(elem,itpl('$pos$idx,'),**kw)
1500 self.__call__(elem,itpl('$pos$idx,'),**kw)
1500 self.depth -= 1
1501 self.depth -= 1
1501 else:
1502 else:
1502 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1503 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1503
1504
1504 nlprint = NLprinter()
1505 nlprint = NLprinter()
1505 #----------------------------------------------------------------------------
1506 #----------------------------------------------------------------------------
1506 def all_belong(candidates,checklist):
1507 def all_belong(candidates,checklist):
1507 """Check whether a list of items ALL appear in a given list of options.
1508 """Check whether a list of items ALL appear in a given list of options.
1508
1509
1509 Returns a single 1 or 0 value."""
1510 Returns a single 1 or 0 value."""
1510
1511
1511 return 1-(0 in [x in checklist for x in candidates])
1512 return 1-(0 in [x in checklist for x in candidates])
1512
1513
1513 #----------------------------------------------------------------------------
1514 #----------------------------------------------------------------------------
1514 def sort_compare(lst1,lst2,inplace = 1):
1515 def sort_compare(lst1,lst2,inplace = 1):
1515 """Sort and compare two lists.
1516 """Sort and compare two lists.
1516
1517
1517 By default it does it in place, thus modifying the lists. Use inplace = 0
1518 By default it does it in place, thus modifying the lists. Use inplace = 0
1518 to avoid that (at the cost of temporary copy creation)."""
1519 to avoid that (at the cost of temporary copy creation)."""
1519 if not inplace:
1520 if not inplace:
1520 lst1 = lst1[:]
1521 lst1 = lst1[:]
1521 lst2 = lst2[:]
1522 lst2 = lst2[:]
1522 lst1.sort(); lst2.sort()
1523 lst1.sort(); lst2.sort()
1523 return lst1 == lst2
1524 return lst1 == lst2
1524
1525
1525 #----------------------------------------------------------------------------
1526 #----------------------------------------------------------------------------
1526 def mkdict(**kwargs):
1527 def mkdict(**kwargs):
1527 """Return a dict from a keyword list.
1528 """Return a dict from a keyword list.
1528
1529
1529 It's just syntactic sugar for making ditcionary creation more convenient:
1530 It's just syntactic sugar for making ditcionary creation more convenient:
1530 # the standard way
1531 # the standard way
1531 >>>data = { 'red' : 1, 'green' : 2, 'blue' : 3 }
1532 >>>data = { 'red' : 1, 'green' : 2, 'blue' : 3 }
1532 # a cleaner way
1533 # a cleaner way
1533 >>>data = dict(red=1, green=2, blue=3)
1534 >>>data = dict(red=1, green=2, blue=3)
1534
1535
1535 If you need more than this, look at the Struct() class."""
1536 If you need more than this, look at the Struct() class."""
1536
1537
1537 return kwargs
1538 return kwargs
1538
1539
1539 #----------------------------------------------------------------------------
1540 #----------------------------------------------------------------------------
1540 def list2dict(lst):
1541 def list2dict(lst):
1541 """Takes a list of (key,value) pairs and turns it into a dict."""
1542 """Takes a list of (key,value) pairs and turns it into a dict."""
1542
1543
1543 dic = {}
1544 dic = {}
1544 for k,v in lst: dic[k] = v
1545 for k,v in lst: dic[k] = v
1545 return dic
1546 return dic
1546
1547
1547 #----------------------------------------------------------------------------
1548 #----------------------------------------------------------------------------
1548 def list2dict2(lst,default=''):
1549 def list2dict2(lst,default=''):
1549 """Takes a list and turns it into a dict.
1550 """Takes a list and turns it into a dict.
1550 Much slower than list2dict, but more versatile. This version can take
1551 Much slower than list2dict, but more versatile. This version can take
1551 lists with sublists of arbitrary length (including sclars)."""
1552 lists with sublists of arbitrary length (including sclars)."""
1552
1553
1553 dic = {}
1554 dic = {}
1554 for elem in lst:
1555 for elem in lst:
1555 if type(elem) in (types.ListType,types.TupleType):
1556 if type(elem) in (types.ListType,types.TupleType):
1556 size = len(elem)
1557 size = len(elem)
1557 if size == 0:
1558 if size == 0:
1558 pass
1559 pass
1559 elif size == 1:
1560 elif size == 1:
1560 dic[elem] = default
1561 dic[elem] = default
1561 else:
1562 else:
1562 k,v = elem[0], elem[1:]
1563 k,v = elem[0], elem[1:]
1563 if len(v) == 1: v = v[0]
1564 if len(v) == 1: v = v[0]
1564 dic[k] = v
1565 dic[k] = v
1565 else:
1566 else:
1566 dic[elem] = default
1567 dic[elem] = default
1567 return dic
1568 return dic
1568
1569
1569 #----------------------------------------------------------------------------
1570 #----------------------------------------------------------------------------
1570 def flatten(seq):
1571 def flatten(seq):
1571 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1572 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1572
1573
1573 return [x for subseq in seq for x in subseq]
1574 return [x for subseq in seq for x in subseq]
1574
1575
1575 #----------------------------------------------------------------------------
1576 #----------------------------------------------------------------------------
1576 def get_slice(seq,start=0,stop=None,step=1):
1577 def get_slice(seq,start=0,stop=None,step=1):
1577 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1578 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1578 if stop == None:
1579 if stop == None:
1579 stop = len(seq)
1580 stop = len(seq)
1580 item = lambda i: seq[i]
1581 item = lambda i: seq[i]
1581 return map(item,xrange(start,stop,step))
1582 return map(item,xrange(start,stop,step))
1582
1583
1583 #----------------------------------------------------------------------------
1584 #----------------------------------------------------------------------------
1584 def chop(seq,size):
1585 def chop(seq,size):
1585 """Chop a sequence into chunks of the given size."""
1586 """Chop a sequence into chunks of the given size."""
1586 chunk = lambda i: seq[i:i+size]
1587 chunk = lambda i: seq[i:i+size]
1587 return map(chunk,xrange(0,len(seq),size))
1588 return map(chunk,xrange(0,len(seq),size))
1588
1589
1589 #----------------------------------------------------------------------------
1590 #----------------------------------------------------------------------------
1590 # with is a keyword as of python 2.5, so this function is renamed to withobj
1591 # with is a keyword as of python 2.5, so this function is renamed to withobj
1591 # from its old 'with' name.
1592 # from its old 'with' name.
1592 def with_obj(object, **args):
1593 def with_obj(object, **args):
1593 """Set multiple attributes for an object, similar to Pascal's with.
1594 """Set multiple attributes for an object, similar to Pascal's with.
1594
1595
1595 Example:
1596 Example:
1596 with_obj(jim,
1597 with_obj(jim,
1597 born = 1960,
1598 born = 1960,
1598 haircolour = 'Brown',
1599 haircolour = 'Brown',
1599 eyecolour = 'Green')
1600 eyecolour = 'Green')
1600
1601
1601 Credit: Greg Ewing, in
1602 Credit: Greg Ewing, in
1602 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1603 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1603
1604
1604 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1605 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1605 has become a keyword for Python 2.5, so we had to rename it."""
1606 has become a keyword for Python 2.5, so we had to rename it."""
1606
1607
1607 object.__dict__.update(args)
1608 object.__dict__.update(args)
1608
1609
1609 #----------------------------------------------------------------------------
1610 #----------------------------------------------------------------------------
1610 def setattr_list(obj,alist,nspace = None):
1611 def setattr_list(obj,alist,nspace = None):
1611 """Set a list of attributes for an object taken from a namespace.
1612 """Set a list of attributes for an object taken from a namespace.
1612
1613
1613 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1614 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1614 alist with their values taken from nspace, which must be a dict (something
1615 alist with their values taken from nspace, which must be a dict (something
1615 like locals() will often do) If nspace isn't given, locals() of the
1616 like locals() will often do) If nspace isn't given, locals() of the
1616 *caller* is used, so in most cases you can omit it.
1617 *caller* is used, so in most cases you can omit it.
1617
1618
1618 Note that alist can be given as a string, which will be automatically
1619 Note that alist can be given as a string, which will be automatically
1619 split into a list on whitespace. If given as a list, it must be a list of
1620 split into a list on whitespace. If given as a list, it must be a list of
1620 *strings* (the variable names themselves), not of variables."""
1621 *strings* (the variable names themselves), not of variables."""
1621
1622
1622 # this grabs the local variables from the *previous* call frame -- that is
1623 # this grabs the local variables from the *previous* call frame -- that is
1623 # the locals from the function that called setattr_list().
1624 # the locals from the function that called setattr_list().
1624 # - snipped from weave.inline()
1625 # - snipped from weave.inline()
1625 if nspace is None:
1626 if nspace is None:
1626 call_frame = sys._getframe().f_back
1627 call_frame = sys._getframe().f_back
1627 nspace = call_frame.f_locals
1628 nspace = call_frame.f_locals
1628
1629
1629 if type(alist) in StringTypes:
1630 if type(alist) in StringTypes:
1630 alist = alist.split()
1631 alist = alist.split()
1631 for attr in alist:
1632 for attr in alist:
1632 val = eval(attr,nspace)
1633 val = eval(attr,nspace)
1633 setattr(obj,attr,val)
1634 setattr(obj,attr,val)
1634
1635
1635 #----------------------------------------------------------------------------
1636 #----------------------------------------------------------------------------
1636 def getattr_list(obj,alist,*args):
1637 def getattr_list(obj,alist,*args):
1637 """getattr_list(obj,alist[, default]) -> attribute list.
1638 """getattr_list(obj,alist[, default]) -> attribute list.
1638
1639
1639 Get a list of named attributes for an object. When a default argument is
1640 Get a list of named attributes for an object. When a default argument is
1640 given, it is returned when the attribute doesn't exist; without it, an
1641 given, it is returned when the attribute doesn't exist; without it, an
1641 exception is raised in that case.
1642 exception is raised in that case.
1642
1643
1643 Note that alist can be given as a string, which will be automatically
1644 Note that alist can be given as a string, which will be automatically
1644 split into a list on whitespace. If given as a list, it must be a list of
1645 split into a list on whitespace. If given as a list, it must be a list of
1645 *strings* (the variable names themselves), not of variables."""
1646 *strings* (the variable names themselves), not of variables."""
1646
1647
1647 if type(alist) in StringTypes:
1648 if type(alist) in StringTypes:
1648 alist = alist.split()
1649 alist = alist.split()
1649 if args:
1650 if args:
1650 if len(args)==1:
1651 if len(args)==1:
1651 default = args[0]
1652 default = args[0]
1652 return map(lambda attr: getattr(obj,attr,default),alist)
1653 return map(lambda attr: getattr(obj,attr,default),alist)
1653 else:
1654 else:
1654 raise ValueError,'getattr_list() takes only one optional argument'
1655 raise ValueError,'getattr_list() takes only one optional argument'
1655 else:
1656 else:
1656 return map(lambda attr: getattr(obj,attr),alist)
1657 return map(lambda attr: getattr(obj,attr),alist)
1657
1658
1658 #----------------------------------------------------------------------------
1659 #----------------------------------------------------------------------------
1659 def map_method(method,object_list,*argseq,**kw):
1660 def map_method(method,object_list,*argseq,**kw):
1660 """map_method(method,object_list,*args,**kw) -> list
1661 """map_method(method,object_list,*args,**kw) -> list
1661
1662
1662 Return a list of the results of applying the methods to the items of the
1663 Return a list of the results of applying the methods to the items of the
1663 argument sequence(s). If more than one sequence is given, the method is
1664 argument sequence(s). If more than one sequence is given, the method is
1664 called with an argument list consisting of the corresponding item of each
1665 called with an argument list consisting of the corresponding item of each
1665 sequence. All sequences must be of the same length.
1666 sequence. All sequences must be of the same length.
1666
1667
1667 Keyword arguments are passed verbatim to all objects called.
1668 Keyword arguments are passed verbatim to all objects called.
1668
1669
1669 This is Python code, so it's not nearly as fast as the builtin map()."""
1670 This is Python code, so it's not nearly as fast as the builtin map()."""
1670
1671
1671 out_list = []
1672 out_list = []
1672 idx = 0
1673 idx = 0
1673 for object in object_list:
1674 for object in object_list:
1674 try:
1675 try:
1675 handler = getattr(object, method)
1676 handler = getattr(object, method)
1676 except AttributeError:
1677 except AttributeError:
1677 out_list.append(None)
1678 out_list.append(None)
1678 else:
1679 else:
1679 if argseq:
1680 if argseq:
1680 args = map(lambda lst:lst[idx],argseq)
1681 args = map(lambda lst:lst[idx],argseq)
1681 #print 'ob',object,'hand',handler,'ar',args # dbg
1682 #print 'ob',object,'hand',handler,'ar',args # dbg
1682 out_list.append(handler(args,**kw))
1683 out_list.append(handler(args,**kw))
1683 else:
1684 else:
1684 out_list.append(handler(**kw))
1685 out_list.append(handler(**kw))
1685 idx += 1
1686 idx += 1
1686 return out_list
1687 return out_list
1687
1688
1688 #----------------------------------------------------------------------------
1689 #----------------------------------------------------------------------------
1689 def import_fail_info(mod_name,fns=None):
1690 def import_fail_info(mod_name,fns=None):
1690 """Inform load failure for a module."""
1691 """Inform load failure for a module."""
1691
1692
1692 if fns == None:
1693 if fns == None:
1693 warn("Loading of %s failed.\n" % (mod_name,))
1694 warn("Loading of %s failed.\n" % (mod_name,))
1694 else:
1695 else:
1695 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
1696 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
1696
1697
1697 #----------------------------------------------------------------------------
1698 #----------------------------------------------------------------------------
1698 # Proposed popitem() extension, written as a method
1699 # Proposed popitem() extension, written as a method
1699
1700
1701
1700 class NotGiven: pass
1702 class NotGiven: pass
1701
1703
1702 def popkey(dct,key,default=NotGiven):
1704 def popkey(dct,key,default=NotGiven):
1703 """Return dct[key] and delete dct[key].
1705 """Return dct[key] and delete dct[key].
1704
1706
1705 If default is given, return it if dct[key] doesn't exist, otherwise raise
1707 If default is given, return it if dct[key] doesn't exist, otherwise raise
1706 KeyError. """
1708 KeyError. """
1707
1709
1708 try:
1710 try:
1709 val = dct[key]
1711 val = dct[key]
1710 except KeyError:
1712 except KeyError:
1711 if default is NotGiven:
1713 if default is NotGiven:
1712 raise
1714 raise
1713 else:
1715 else:
1714 return default
1716 return default
1715 else:
1717 else:
1716 del dct[key]
1718 del dct[key]
1717 return val
1719 return val
1720
1721 def wrap_deprecated(func, suggest = '<nothing>'):
1722 def newFunc(*args, **kwargs):
1723 warnings.warn("Call to deprecated function %s, use %s instead" %
1724 ( func.__name__, suggest),
1725 category=DeprecationWarning,
1726 stacklevel = 2)
1727 return func(*args, **kwargs)
1728 return newFunc
1729
1718 #*************************** end of file <genutils.py> **********************
1730 #*************************** end of file <genutils.py> **********************
1719
1731
General Comments 0
You need to be logged in to leave comments. Login now