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