##// END OF EJS Templates
fix small but critical bug for win32 system access.
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

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