##// END OF EJS Templates
All security related files (*.furl and *.pem) are now put in a default...
Brian Granger -
Show More
@@ -1,104 +1,106 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """This is the official entry point to IPython's configuration system. """
3 """This is the official entry point to IPython's configuration system. """
4
4
5 __docformat__ = "restructuredtext en"
5 __docformat__ = "restructuredtext en"
6
6
7 #-------------------------------------------------------------------------------
7 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-------------------------------------------------------------------------------
12 #-------------------------------------------------------------------------------
13
13
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 import os
18 import os
19 from os.path import join as pjoin
20
19 from IPython.genutils import get_home_dir, get_ipython_dir
21 from IPython.genutils import get_home_dir, get_ipython_dir
20 from IPython.external.configobj import ConfigObj
22 from IPython.external.configobj import ConfigObj
21
23
22 # Traitlets config imports
24 # Traitlets config imports
23 from IPython.config import traitlets
25 from IPython.config import traitlets
24 from IPython.config.config import *
26 from IPython.config.config import *
25 from traitlets import *
27 from traitlets import *
26
28
27 class ConfigObjManager(object):
29 class ConfigObjManager(object):
28
30
29 def __init__(self, configObj, filename):
31 def __init__(self, configObj, filename):
30 self.current = configObj
32 self.current = configObj
31 self.current.indent_type = ' '
33 self.current.indent_type = ' '
32 self.filename = filename
34 self.filename = filename
33 # self.write_default_config_file()
35 # self.write_default_config_file()
34
36
35 def get_config_obj(self):
37 def get_config_obj(self):
36 return self.current
38 return self.current
37
39
38 def update_config_obj(self, newConfig):
40 def update_config_obj(self, newConfig):
39 self.current.merge(newConfig)
41 self.current.merge(newConfig)
40
42
41 def update_config_obj_from_file(self, filename):
43 def update_config_obj_from_file(self, filename):
42 newConfig = ConfigObj(filename, file_error=False)
44 newConfig = ConfigObj(filename, file_error=False)
43 self.current.merge(newConfig)
45 self.current.merge(newConfig)
44
46
45 def update_config_obj_from_default_file(self, ipythondir=None):
47 def update_config_obj_from_default_file(self, ipythondir=None):
46 fname = self.resolve_file_path(self.filename, ipythondir)
48 fname = self.resolve_file_path(self.filename, ipythondir)
47 self.update_config_obj_from_file(fname)
49 self.update_config_obj_from_file(fname)
48
50
49 def write_config_obj_to_file(self, filename):
51 def write_config_obj_to_file(self, filename):
50 f = open(filename, 'w')
52 f = open(filename, 'w')
51 self.current.write(f)
53 self.current.write(f)
52 f.close()
54 f.close()
53
55
54 def write_default_config_file(self):
56 def write_default_config_file(self):
55 ipdir = get_ipython_dir()
57 ipdir = get_ipython_dir()
56 fname = ipdir + '/' + self.filename
58 fname = pjoin(ipdir, self.filename)
57 if not os.path.isfile(fname):
59 if not os.path.isfile(fname):
58 print "Writing the configuration file to: " + fname
60 print "Writing the configuration file to: " + fname
59 self.write_config_obj_to_file(fname)
61 self.write_config_obj_to_file(fname)
60
62
61 def _import(self, key):
63 def _import(self, key):
62 package = '.'.join(key.split('.')[0:-1])
64 package = '.'.join(key.split('.')[0:-1])
63 obj = key.split('.')[-1]
65 obj = key.split('.')[-1]
64 execString = 'from %s import %s' % (package, obj)
66 execString = 'from %s import %s' % (package, obj)
65 exec execString
67 exec execString
66 exec 'temp = %s' % obj
68 exec 'temp = %s' % obj
67 return temp
69 return temp
68
70
69 def resolve_file_path(self, filename, ipythondir = None):
71 def resolve_file_path(self, filename, ipythondir = None):
70 """Resolve filenames into absolute paths.
72 """Resolve filenames into absolute paths.
71
73
72 This function looks in the following directories in order:
74 This function looks in the following directories in order:
73
75
74 1. In the current working directory or by absolute path with ~ expanded
76 1. In the current working directory or by absolute path with ~ expanded
75 2. In ipythondir if that is set
77 2. In ipythondir if that is set
76 3. In the IPYTHONDIR environment variable if it exists
78 3. In the IPYTHONDIR environment variable if it exists
77 4. In the ~/.ipython directory
79 4. In the ~/.ipython directory
78
80
79 Note: The IPYTHONDIR is also used by the trunk version of IPython so
81 Note: The IPYTHONDIR is also used by the trunk version of IPython so
80 changing it will also affect it was well.
82 changing it will also affect it was well.
81 """
83 """
82
84
83 # In cwd or by absolute path with ~ expanded
85 # In cwd or by absolute path with ~ expanded
84 trythis = os.path.expanduser(filename)
86 trythis = os.path.expanduser(filename)
85 if os.path.isfile(trythis):
87 if os.path.isfile(trythis):
86 return trythis
88 return trythis
87
89
88 # In ipythondir if it is set
90 # In ipythondir if it is set
89 if ipythondir is not None:
91 if ipythondir is not None:
90 trythis = ipythondir + '/' + filename
92 trythis = pjoin(ipythondir, filename)
91 if os.path.isfile(trythis):
93 if os.path.isfile(trythis):
92 return trythis
94 return trythis
93
95
94 trythis = get_ipython_dir() + '/' + filename
96 trythis = pjoin(get_ipython_dir(), filename)
95 if os.path.isfile(trythis):
97 if os.path.isfile(trythis):
96 return trythis
98 return trythis
97
99
98 return None
100 return None
99
101
100
102
101
103
102
104
103
105
104
106
@@ -1,2148 +1,2164 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 2998 2008-01-31 10:06:04Z vivainio $"""
8 $Id: genutils.py 2998 2008-01-31 10:06:04Z vivainio $"""
9
9
10 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #*****************************************************************************
15 #*****************************************************************************
16
16
17 from IPython import Release
17 from IPython import Release
18 __author__ = '%s <%s>' % Release.authors['Fernando']
18 __author__ = '%s <%s>' % Release.authors['Fernando']
19 __license__ = Release.license
19 __license__ = Release.license
20
20
21 #****************************************************************************
21 #****************************************************************************
22 # required modules from the Python standard library
22 # required modules from the Python standard library
23 import __main__
23 import __main__
24 import commands
24 import commands
25 try:
25 try:
26 import doctest
26 import doctest
27 except ImportError:
27 except ImportError:
28 pass
28 pass
29 import os
29 import os
30 import platform
30 import platform
31 import re
31 import re
32 import shlex
32 import shlex
33 import shutil
33 import shutil
34 import subprocess
34 import subprocess
35 import sys
35 import sys
36 import tempfile
36 import tempfile
37 import time
37 import time
38 import types
38 import types
39 import warnings
39 import warnings
40
40
41 # Curses and termios are Unix-only modules
41 # Curses and termios are Unix-only modules
42 try:
42 try:
43 import curses
43 import curses
44 # We need termios as well, so if its import happens to raise, we bail on
44 # We need termios as well, so if its import happens to raise, we bail on
45 # using curses altogether.
45 # using curses altogether.
46 import termios
46 import termios
47 except ImportError:
47 except ImportError:
48 USE_CURSES = False
48 USE_CURSES = False
49 else:
49 else:
50 # Curses on Solaris may not be complete, so we can't use it there
50 # Curses on Solaris may not be complete, so we can't use it there
51 USE_CURSES = hasattr(curses,'initscr')
51 USE_CURSES = hasattr(curses,'initscr')
52
52
53 # Other IPython utilities
53 # Other IPython utilities
54 import IPython
54 import IPython
55 from IPython.Itpl import Itpl,itpl,printpl
55 from IPython.Itpl import Itpl,itpl,printpl
56 from IPython import DPyGetOpt, platutils
56 from IPython import DPyGetOpt, platutils
57 from IPython.generics import result_display
57 from IPython.generics import result_display
58 import IPython.ipapi
58 import IPython.ipapi
59 from IPython.external.path import path
59 from IPython.external.path import path
60 if os.name == "nt":
60 if os.name == "nt":
61 from IPython.winconsole import get_console_size
61 from IPython.winconsole import get_console_size
62
62
63 try:
63 try:
64 set
64 set
65 except:
65 except:
66 from sets import Set as set
66 from sets import Set as set
67
67
68
68
69 #****************************************************************************
69 #****************************************************************************
70 # Exceptions
70 # Exceptions
71 class Error(Exception):
71 class Error(Exception):
72 """Base class for exceptions in this module."""
72 """Base class for exceptions in this module."""
73 pass
73 pass
74
74
75 #----------------------------------------------------------------------------
75 #----------------------------------------------------------------------------
76 class IOStream:
76 class IOStream:
77 def __init__(self,stream,fallback):
77 def __init__(self,stream,fallback):
78 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
78 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
79 stream = fallback
79 stream = fallback
80 self.stream = stream
80 self.stream = stream
81 self._swrite = stream.write
81 self._swrite = stream.write
82 self.flush = stream.flush
82 self.flush = stream.flush
83
83
84 def write(self,data):
84 def write(self,data):
85 try:
85 try:
86 self._swrite(data)
86 self._swrite(data)
87 except:
87 except:
88 try:
88 try:
89 # print handles some unicode issues which may trip a plain
89 # print handles some unicode issues which may trip a plain
90 # write() call. Attempt to emulate write() by using a
90 # write() call. Attempt to emulate write() by using a
91 # trailing comma
91 # trailing comma
92 print >> self.stream, data,
92 print >> self.stream, data,
93 except:
93 except:
94 # if we get here, something is seriously broken.
94 # if we get here, something is seriously broken.
95 print >> sys.stderr, \
95 print >> sys.stderr, \
96 'ERROR - failed to write data to stream:', self.stream
96 'ERROR - failed to write data to stream:', self.stream
97
97
98 def close(self):
98 def close(self):
99 pass
99 pass
100
100
101
101
102 class IOTerm:
102 class IOTerm:
103 """ Term holds the file or file-like objects for handling I/O operations.
103 """ Term holds the file or file-like objects for handling I/O operations.
104
104
105 These are normally just sys.stdin, sys.stdout and sys.stderr but for
105 These are normally just sys.stdin, sys.stdout and sys.stderr but for
106 Windows they can can replaced to allow editing the strings before they are
106 Windows they can can replaced to allow editing the strings before they are
107 displayed."""
107 displayed."""
108
108
109 # In the future, having IPython channel all its I/O operations through
109 # In the future, having IPython channel all its I/O operations through
110 # this class will make it easier to embed it into other environments which
110 # this class will make it easier to embed it into other environments which
111 # are not a normal terminal (such as a GUI-based shell)
111 # are not a normal terminal (such as a GUI-based shell)
112 def __init__(self,cin=None,cout=None,cerr=None):
112 def __init__(self,cin=None,cout=None,cerr=None):
113 self.cin = IOStream(cin,sys.stdin)
113 self.cin = IOStream(cin,sys.stdin)
114 self.cout = IOStream(cout,sys.stdout)
114 self.cout = IOStream(cout,sys.stdout)
115 self.cerr = IOStream(cerr,sys.stderr)
115 self.cerr = IOStream(cerr,sys.stderr)
116
116
117 # Global variable to be used for all I/O
117 # Global variable to be used for all I/O
118 Term = IOTerm()
118 Term = IOTerm()
119
119
120 import IPython.rlineimpl as readline
120 import IPython.rlineimpl as readline
121 # Remake Term to use the readline i/o facilities
121 # Remake Term to use the readline i/o facilities
122 if sys.platform == 'win32' and readline.have_readline:
122 if sys.platform == 'win32' and readline.have_readline:
123
123
124 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
124 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
125
125
126
126
127 #****************************************************************************
127 #****************************************************************************
128 # Generic warning/error printer, used by everything else
128 # Generic warning/error printer, used by everything else
129 def warn(msg,level=2,exit_val=1):
129 def warn(msg,level=2,exit_val=1):
130 """Standard warning printer. Gives formatting consistency.
130 """Standard warning printer. Gives formatting consistency.
131
131
132 Output is sent to Term.cerr (sys.stderr by default).
132 Output is sent to Term.cerr (sys.stderr by default).
133
133
134 Options:
134 Options:
135
135
136 -level(2): allows finer control:
136 -level(2): allows finer control:
137 0 -> Do nothing, dummy function.
137 0 -> Do nothing, dummy function.
138 1 -> Print message.
138 1 -> Print message.
139 2 -> Print 'WARNING:' + message. (Default level).
139 2 -> Print 'WARNING:' + message. (Default level).
140 3 -> Print 'ERROR:' + message.
140 3 -> Print 'ERROR:' + message.
141 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
141 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
142
142
143 -exit_val (1): exit value returned by sys.exit() for a level 4
143 -exit_val (1): exit value returned by sys.exit() for a level 4
144 warning. Ignored for all other levels."""
144 warning. Ignored for all other levels."""
145
145
146 if level>0:
146 if level>0:
147 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
147 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
148 print >> Term.cerr, '%s%s' % (header[level],msg)
148 print >> Term.cerr, '%s%s' % (header[level],msg)
149 if level == 4:
149 if level == 4:
150 print >> Term.cerr,'Exiting.\n'
150 print >> Term.cerr,'Exiting.\n'
151 sys.exit(exit_val)
151 sys.exit(exit_val)
152
152
153 def info(msg):
153 def info(msg):
154 """Equivalent to warn(msg,level=1)."""
154 """Equivalent to warn(msg,level=1)."""
155
155
156 warn(msg,level=1)
156 warn(msg,level=1)
157
157
158 def error(msg):
158 def error(msg):
159 """Equivalent to warn(msg,level=3)."""
159 """Equivalent to warn(msg,level=3)."""
160
160
161 warn(msg,level=3)
161 warn(msg,level=3)
162
162
163 def fatal(msg,exit_val=1):
163 def fatal(msg,exit_val=1):
164 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
164 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
165
165
166 warn(msg,exit_val=exit_val,level=4)
166 warn(msg,exit_val=exit_val,level=4)
167
167
168 #---------------------------------------------------------------------------
168 #---------------------------------------------------------------------------
169 # Debugging routines
169 # Debugging routines
170 #
170 #
171 def debugx(expr,pre_msg=''):
171 def debugx(expr,pre_msg=''):
172 """Print the value of an expression from the caller's frame.
172 """Print the value of an expression from the caller's frame.
173
173
174 Takes an expression, evaluates it in the caller's frame and prints both
174 Takes an expression, evaluates it in the caller's frame and prints both
175 the given expression and the resulting value (as well as a debug mark
175 the given expression and the resulting value (as well as a debug mark
176 indicating the name of the calling function. The input must be of a form
176 indicating the name of the calling function. The input must be of a form
177 suitable for eval().
177 suitable for eval().
178
178
179 An optional message can be passed, which will be prepended to the printed
179 An optional message can be passed, which will be prepended to the printed
180 expr->value pair."""
180 expr->value pair."""
181
181
182 cf = sys._getframe(1)
182 cf = sys._getframe(1)
183 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
183 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
184 eval(expr,cf.f_globals,cf.f_locals))
184 eval(expr,cf.f_globals,cf.f_locals))
185
185
186 # deactivate it by uncommenting the following line, which makes it a no-op
186 # deactivate it by uncommenting the following line, which makes it a no-op
187 #def debugx(expr,pre_msg=''): pass
187 #def debugx(expr,pre_msg=''): pass
188
188
189 #----------------------------------------------------------------------------
189 #----------------------------------------------------------------------------
190 StringTypes = types.StringTypes
190 StringTypes = types.StringTypes
191
191
192 # Basic timing functionality
192 # Basic timing functionality
193
193
194 # If possible (Unix), use the resource module instead of time.clock()
194 # If possible (Unix), use the resource module instead of time.clock()
195 try:
195 try:
196 import resource
196 import resource
197 def clocku():
197 def clocku():
198 """clocku() -> floating point number
198 """clocku() -> floating point number
199
199
200 Return the *USER* CPU time in seconds since the start of the process.
200 Return the *USER* CPU time in seconds since the start of the process.
201 This is done via a call to resource.getrusage, so it avoids the
201 This is done via a call to resource.getrusage, so it avoids the
202 wraparound problems in time.clock()."""
202 wraparound problems in time.clock()."""
203
203
204 return resource.getrusage(resource.RUSAGE_SELF)[0]
204 return resource.getrusage(resource.RUSAGE_SELF)[0]
205
205
206 def clocks():
206 def clocks():
207 """clocks() -> floating point number
207 """clocks() -> floating point number
208
208
209 Return the *SYSTEM* CPU time in seconds since the start of the process.
209 Return the *SYSTEM* CPU time in seconds since the start of the process.
210 This is done via a call to resource.getrusage, so it avoids the
210 This is done via a call to resource.getrusage, so it avoids the
211 wraparound problems in time.clock()."""
211 wraparound problems in time.clock()."""
212
212
213 return resource.getrusage(resource.RUSAGE_SELF)[1]
213 return resource.getrusage(resource.RUSAGE_SELF)[1]
214
214
215 def clock():
215 def clock():
216 """clock() -> floating point number
216 """clock() -> floating point number
217
217
218 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
218 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
219 the process. This is done via a call to resource.getrusage, so it
219 the process. This is done via a call to resource.getrusage, so it
220 avoids the wraparound problems in time.clock()."""
220 avoids the wraparound problems in time.clock()."""
221
221
222 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
222 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
223 return u+s
223 return u+s
224
224
225 def clock2():
225 def clock2():
226 """clock2() -> (t_user,t_system)
226 """clock2() -> (t_user,t_system)
227
227
228 Similar to clock(), but return a tuple of user/system times."""
228 Similar to clock(), but return a tuple of user/system times."""
229 return resource.getrusage(resource.RUSAGE_SELF)[:2]
229 return resource.getrusage(resource.RUSAGE_SELF)[:2]
230
230
231 except ImportError:
231 except ImportError:
232 # There is no distinction of user/system time under windows, so we just use
232 # There is no distinction of user/system time under windows, so we just use
233 # time.clock() for everything...
233 # time.clock() for everything...
234 clocku = clocks = clock = time.clock
234 clocku = clocks = clock = time.clock
235 def clock2():
235 def clock2():
236 """Under windows, system CPU time can't be measured.
236 """Under windows, system CPU time can't be measured.
237
237
238 This just returns clock() and zero."""
238 This just returns clock() and zero."""
239 return time.clock(),0.0
239 return time.clock(),0.0
240
240
241 def timings_out(reps,func,*args,**kw):
241 def timings_out(reps,func,*args,**kw):
242 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
242 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
243
243
244 Execute a function reps times, return a tuple with the elapsed total
244 Execute a function reps times, return a tuple with the elapsed total
245 CPU time in seconds, the time per call and the function's output.
245 CPU time in seconds, the time per call and the function's output.
246
246
247 Under Unix, the return value is the sum of user+system time consumed by
247 Under Unix, the return value is the sum of user+system time consumed by
248 the process, computed via the resource module. This prevents problems
248 the process, computed via the resource module. This prevents problems
249 related to the wraparound effect which the time.clock() function has.
249 related to the wraparound effect which the time.clock() function has.
250
250
251 Under Windows the return value is in wall clock seconds. See the
251 Under Windows the return value is in wall clock seconds. See the
252 documentation for the time module for more details."""
252 documentation for the time module for more details."""
253
253
254 reps = int(reps)
254 reps = int(reps)
255 assert reps >=1, 'reps must be >= 1'
255 assert reps >=1, 'reps must be >= 1'
256 if reps==1:
256 if reps==1:
257 start = clock()
257 start = clock()
258 out = func(*args,**kw)
258 out = func(*args,**kw)
259 tot_time = clock()-start
259 tot_time = clock()-start
260 else:
260 else:
261 rng = xrange(reps-1) # the last time is executed separately to store output
261 rng = xrange(reps-1) # the last time is executed separately to store output
262 start = clock()
262 start = clock()
263 for dummy in rng: func(*args,**kw)
263 for dummy in rng: func(*args,**kw)
264 out = func(*args,**kw) # one last time
264 out = func(*args,**kw) # one last time
265 tot_time = clock()-start
265 tot_time = clock()-start
266 av_time = tot_time / reps
266 av_time = tot_time / reps
267 return tot_time,av_time,out
267 return tot_time,av_time,out
268
268
269 def timings(reps,func,*args,**kw):
269 def timings(reps,func,*args,**kw):
270 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
270 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
271
271
272 Execute a function reps times, return a tuple with the elapsed total CPU
272 Execute a function reps times, return a tuple with the elapsed total CPU
273 time in seconds and the time per call. These are just the first two values
273 time in seconds and the time per call. These are just the first two values
274 in timings_out()."""
274 in timings_out()."""
275
275
276 return timings_out(reps,func,*args,**kw)[0:2]
276 return timings_out(reps,func,*args,**kw)[0:2]
277
277
278 def timing(func,*args,**kw):
278 def timing(func,*args,**kw):
279 """timing(func,*args,**kw) -> t_total
279 """timing(func,*args,**kw) -> t_total
280
280
281 Execute a function once, return the elapsed total CPU time in
281 Execute a function once, return the elapsed total CPU time in
282 seconds. This is just the first value in timings_out()."""
282 seconds. This is just the first value in timings_out()."""
283
283
284 return timings_out(1,func,*args,**kw)[0]
284 return timings_out(1,func,*args,**kw)[0]
285
285
286 #****************************************************************************
286 #****************************************************************************
287 # file and system
287 # file and system
288
288
289 def arg_split(s,posix=False):
289 def arg_split(s,posix=False):
290 """Split a command line's arguments in a shell-like manner.
290 """Split a command line's arguments in a shell-like manner.
291
291
292 This is a modified version of the standard library's shlex.split()
292 This is a modified version of the standard library's shlex.split()
293 function, but with a default of posix=False for splitting, so that quotes
293 function, but with a default of posix=False for splitting, so that quotes
294 in inputs are respected."""
294 in inputs are respected."""
295
295
296 # XXX - there may be unicode-related problems here!!! I'm not sure that
296 # XXX - there may be unicode-related problems here!!! I'm not sure that
297 # shlex is truly unicode-safe, so it might be necessary to do
297 # shlex is truly unicode-safe, so it might be necessary to do
298 #
298 #
299 # s = s.encode(sys.stdin.encoding)
299 # s = s.encode(sys.stdin.encoding)
300 #
300 #
301 # first, to ensure that shlex gets a normal string. Input from anyone who
301 # first, to ensure that shlex gets a normal string. Input from anyone who
302 # knows more about unicode and shlex than I would be good to have here...
302 # knows more about unicode and shlex than I would be good to have here...
303 lex = shlex.shlex(s, posix=posix)
303 lex = shlex.shlex(s, posix=posix)
304 lex.whitespace_split = True
304 lex.whitespace_split = True
305 return list(lex)
305 return list(lex)
306
306
307 def system(cmd,verbose=0,debug=0,header=''):
307 def system(cmd,verbose=0,debug=0,header=''):
308 """Execute a system command, return its exit status.
308 """Execute a system command, return its exit status.
309
309
310 Options:
310 Options:
311
311
312 - verbose (0): print the command to be executed.
312 - verbose (0): print the command to be executed.
313
313
314 - debug (0): only print, do not actually execute.
314 - debug (0): only print, do not actually execute.
315
315
316 - header (''): Header to print on screen prior to the executed command (it
316 - header (''): Header to print on screen prior to the executed command (it
317 is only prepended to the command, no newlines are added).
317 is only prepended to the command, no newlines are added).
318
318
319 Note: a stateful version of this function is available through the
319 Note: a stateful version of this function is available through the
320 SystemExec class."""
320 SystemExec class."""
321
321
322 stat = 0
322 stat = 0
323 if verbose or debug: print header+cmd
323 if verbose or debug: print header+cmd
324 sys.stdout.flush()
324 sys.stdout.flush()
325 if not debug: stat = os.system(cmd)
325 if not debug: stat = os.system(cmd)
326 return stat
326 return stat
327
327
328 def abbrev_cwd():
328 def abbrev_cwd():
329 """ Return abbreviated version of cwd, e.g. d:mydir """
329 """ Return abbreviated version of cwd, e.g. d:mydir """
330 cwd = os.getcwd().replace('\\','/')
330 cwd = os.getcwd().replace('\\','/')
331 drivepart = ''
331 drivepart = ''
332 tail = cwd
332 tail = cwd
333 if sys.platform == 'win32':
333 if sys.platform == 'win32':
334 if len(cwd) < 4:
334 if len(cwd) < 4:
335 return cwd
335 return cwd
336 drivepart,tail = os.path.splitdrive(cwd)
336 drivepart,tail = os.path.splitdrive(cwd)
337
337
338
338
339 parts = tail.split('/')
339 parts = tail.split('/')
340 if len(parts) > 2:
340 if len(parts) > 2:
341 tail = '/'.join(parts[-2:])
341 tail = '/'.join(parts[-2:])
342
342
343 return (drivepart + (
343 return (drivepart + (
344 cwd == '/' and '/' or tail))
344 cwd == '/' and '/' or tail))
345
345
346
346
347 # This function is used by ipython in a lot of places to make system calls.
347 # This function is used by ipython in a lot of places to make system calls.
348 # We need it to be slightly different under win32, due to the vagaries of
348 # We need it to be slightly different under win32, due to the vagaries of
349 # 'network shares'. A win32 override is below.
349 # 'network shares'. A win32 override is below.
350
350
351 def shell(cmd,verbose=0,debug=0,header=''):
351 def shell(cmd,verbose=0,debug=0,header=''):
352 """Execute a command in the system shell, always return None.
352 """Execute a command in the system shell, always return None.
353
353
354 Options:
354 Options:
355
355
356 - verbose (0): print the command to be executed.
356 - verbose (0): print the command to be executed.
357
357
358 - debug (0): only print, do not actually execute.
358 - debug (0): only print, do not actually execute.
359
359
360 - header (''): Header to print on screen prior to the executed command (it
360 - header (''): Header to print on screen prior to the executed command (it
361 is only prepended to the command, no newlines are added).
361 is only prepended to the command, no newlines are added).
362
362
363 Note: this is similar to genutils.system(), but it returns None so it can
363 Note: this is similar to genutils.system(), but it returns None so it can
364 be conveniently used in interactive loops without getting the return value
364 be conveniently used in interactive loops without getting the return value
365 (typically 0) printed many times."""
365 (typically 0) printed many times."""
366
366
367 stat = 0
367 stat = 0
368 if verbose or debug: print header+cmd
368 if verbose or debug: print header+cmd
369 # flush stdout so we don't mangle python's buffering
369 # flush stdout so we don't mangle python's buffering
370 sys.stdout.flush()
370 sys.stdout.flush()
371
371
372 if not debug:
372 if not debug:
373 platutils.set_term_title("IPy " + cmd)
373 platutils.set_term_title("IPy " + cmd)
374 os.system(cmd)
374 os.system(cmd)
375 platutils.set_term_title("IPy " + abbrev_cwd())
375 platutils.set_term_title("IPy " + abbrev_cwd())
376
376
377 # override shell() for win32 to deal with network shares
377 # override shell() for win32 to deal with network shares
378 if os.name in ('nt','dos'):
378 if os.name in ('nt','dos'):
379
379
380 shell_ori = shell
380 shell_ori = shell
381
381
382 def shell(cmd,verbose=0,debug=0,header=''):
382 def shell(cmd,verbose=0,debug=0,header=''):
383 if os.getcwd().startswith(r"\\"):
383 if os.getcwd().startswith(r"\\"):
384 path = os.getcwd()
384 path = os.getcwd()
385 # change to c drive (cannot be on UNC-share when issuing os.system,
385 # change to c drive (cannot be on UNC-share when issuing os.system,
386 # as cmd.exe cannot handle UNC addresses)
386 # as cmd.exe cannot handle UNC addresses)
387 os.chdir("c:")
387 os.chdir("c:")
388 # issue pushd to the UNC-share and then run the command
388 # issue pushd to the UNC-share and then run the command
389 try:
389 try:
390 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
390 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
391 finally:
391 finally:
392 os.chdir(path)
392 os.chdir(path)
393 else:
393 else:
394 shell_ori(cmd,verbose,debug,header)
394 shell_ori(cmd,verbose,debug,header)
395
395
396 shell.__doc__ = shell_ori.__doc__
396 shell.__doc__ = shell_ori.__doc__
397
397
398 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
398 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
399 """Dummy substitute for perl's backquotes.
399 """Dummy substitute for perl's backquotes.
400
400
401 Executes a command and returns the output.
401 Executes a command and returns the output.
402
402
403 Accepts the same arguments as system(), plus:
403 Accepts the same arguments as system(), plus:
404
404
405 - split(0): if true, the output is returned as a list split on newlines.
405 - split(0): if true, the output is returned as a list split on newlines.
406
406
407 Note: a stateful version of this function is available through the
407 Note: a stateful version of this function is available through the
408 SystemExec class.
408 SystemExec class.
409
409
410 This is pretty much deprecated and rarely used,
410 This is pretty much deprecated and rarely used,
411 genutils.getoutputerror may be what you need.
411 genutils.getoutputerror may be what you need.
412
412
413 """
413 """
414
414
415 if verbose or debug: print header+cmd
415 if verbose or debug: print header+cmd
416 if not debug:
416 if not debug:
417 output = os.popen(cmd).read()
417 output = os.popen(cmd).read()
418 # stipping last \n is here for backwards compat.
418 # stipping last \n is here for backwards compat.
419 if output.endswith('\n'):
419 if output.endswith('\n'):
420 output = output[:-1]
420 output = output[:-1]
421 if split:
421 if split:
422 return output.split('\n')
422 return output.split('\n')
423 else:
423 else:
424 return output
424 return output
425
425
426 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
426 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
427 """Return (standard output,standard error) of executing cmd in a shell.
427 """Return (standard output,standard error) of executing cmd in a shell.
428
428
429 Accepts the same arguments as system(), plus:
429 Accepts the same arguments as system(), plus:
430
430
431 - split(0): if true, each of stdout/err is returned as a list split on
431 - split(0): if true, each of stdout/err is returned as a list split on
432 newlines.
432 newlines.
433
433
434 Note: a stateful version of this function is available through the
434 Note: a stateful version of this function is available through the
435 SystemExec class."""
435 SystemExec class."""
436
436
437 if verbose or debug: print header+cmd
437 if verbose or debug: print header+cmd
438 if not cmd:
438 if not cmd:
439 if split:
439 if split:
440 return [],[]
440 return [],[]
441 else:
441 else:
442 return '',''
442 return '',''
443 if not debug:
443 if not debug:
444 pin,pout,perr = os.popen3(cmd)
444 pin,pout,perr = os.popen3(cmd)
445 tout = pout.read().rstrip()
445 tout = pout.read().rstrip()
446 terr = perr.read().rstrip()
446 terr = perr.read().rstrip()
447 pin.close()
447 pin.close()
448 pout.close()
448 pout.close()
449 perr.close()
449 perr.close()
450 if split:
450 if split:
451 return tout.split('\n'),terr.split('\n')
451 return tout.split('\n'),terr.split('\n')
452 else:
452 else:
453 return tout,terr
453 return tout,terr
454
454
455 # for compatibility with older naming conventions
455 # for compatibility with older naming conventions
456 xsys = system
456 xsys = system
457 bq = getoutput
457 bq = getoutput
458
458
459 class SystemExec:
459 class SystemExec:
460 """Access the system and getoutput functions through a stateful interface.
460 """Access the system and getoutput functions through a stateful interface.
461
461
462 Note: here we refer to the system and getoutput functions from this
462 Note: here we refer to the system and getoutput functions from this
463 library, not the ones from the standard python library.
463 library, not the ones from the standard python library.
464
464
465 This class offers the system and getoutput functions as methods, but the
465 This class offers the system and getoutput functions as methods, but the
466 verbose, debug and header parameters can be set for the instance (at
466 verbose, debug and header parameters can be set for the instance (at
467 creation time or later) so that they don't need to be specified on each
467 creation time or later) so that they don't need to be specified on each
468 call.
468 call.
469
469
470 For efficiency reasons, there's no way to override the parameters on a
470 For efficiency reasons, there's no way to override the parameters on a
471 per-call basis other than by setting instance attributes. If you need
471 per-call basis other than by setting instance attributes. If you need
472 local overrides, it's best to directly call system() or getoutput().
472 local overrides, it's best to directly call system() or getoutput().
473
473
474 The following names are provided as alternate options:
474 The following names are provided as alternate options:
475 - xsys: alias to system
475 - xsys: alias to system
476 - bq: alias to getoutput
476 - bq: alias to getoutput
477
477
478 An instance can then be created as:
478 An instance can then be created as:
479 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
479 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
480 """
480 """
481
481
482 def __init__(self,verbose=0,debug=0,header='',split=0):
482 def __init__(self,verbose=0,debug=0,header='',split=0):
483 """Specify the instance's values for verbose, debug and header."""
483 """Specify the instance's values for verbose, debug and header."""
484 setattr_list(self,'verbose debug header split')
484 setattr_list(self,'verbose debug header split')
485
485
486 def system(self,cmd):
486 def system(self,cmd):
487 """Stateful interface to system(), with the same keyword parameters."""
487 """Stateful interface to system(), with the same keyword parameters."""
488
488
489 system(cmd,self.verbose,self.debug,self.header)
489 system(cmd,self.verbose,self.debug,self.header)
490
490
491 def shell(self,cmd):
491 def shell(self,cmd):
492 """Stateful interface to shell(), with the same keyword parameters."""
492 """Stateful interface to shell(), with the same keyword parameters."""
493
493
494 shell(cmd,self.verbose,self.debug,self.header)
494 shell(cmd,self.verbose,self.debug,self.header)
495
495
496 xsys = system # alias
496 xsys = system # alias
497
497
498 def getoutput(self,cmd):
498 def getoutput(self,cmd):
499 """Stateful interface to getoutput()."""
499 """Stateful interface to getoutput()."""
500
500
501 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
501 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
502
502
503 def getoutputerror(self,cmd):
503 def getoutputerror(self,cmd):
504 """Stateful interface to getoutputerror()."""
504 """Stateful interface to getoutputerror()."""
505
505
506 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
506 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
507
507
508 bq = getoutput # alias
508 bq = getoutput # alias
509
509
510 #-----------------------------------------------------------------------------
510 #-----------------------------------------------------------------------------
511 def mutex_opts(dict,ex_op):
511 def mutex_opts(dict,ex_op):
512 """Check for presence of mutually exclusive keys in a dict.
512 """Check for presence of mutually exclusive keys in a dict.
513
513
514 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
514 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
515 for op1,op2 in ex_op:
515 for op1,op2 in ex_op:
516 if op1 in dict and op2 in dict:
516 if op1 in dict and op2 in dict:
517 raise ValueError,'\n*** ERROR in Arguments *** '\
517 raise ValueError,'\n*** ERROR in Arguments *** '\
518 'Options '+op1+' and '+op2+' are mutually exclusive.'
518 'Options '+op1+' and '+op2+' are mutually exclusive.'
519
519
520 #-----------------------------------------------------------------------------
520 #-----------------------------------------------------------------------------
521 def get_py_filename(name):
521 def get_py_filename(name):
522 """Return a valid python filename in the current directory.
522 """Return a valid python filename in the current directory.
523
523
524 If the given name is not a file, it adds '.py' and searches again.
524 If the given name is not a file, it adds '.py' and searches again.
525 Raises IOError with an informative message if the file isn't found."""
525 Raises IOError with an informative message if the file isn't found."""
526
526
527 name = os.path.expanduser(name)
527 name = os.path.expanduser(name)
528 if not os.path.isfile(name) and not name.endswith('.py'):
528 if not os.path.isfile(name) and not name.endswith('.py'):
529 name += '.py'
529 name += '.py'
530 if os.path.isfile(name):
530 if os.path.isfile(name):
531 return name
531 return name
532 else:
532 else:
533 raise IOError,'File `%s` not found.' % name
533 raise IOError,'File `%s` not found.' % name
534
534
535 #-----------------------------------------------------------------------------
535 #-----------------------------------------------------------------------------
536 def filefind(fname,alt_dirs = None):
536 def filefind(fname,alt_dirs = None):
537 """Return the given filename either in the current directory, if it
537 """Return the given filename either in the current directory, if it
538 exists, or in a specified list of directories.
538 exists, or in a specified list of directories.
539
539
540 ~ expansion is done on all file and directory names.
540 ~ expansion is done on all file and directory names.
541
541
542 Upon an unsuccessful search, raise an IOError exception."""
542 Upon an unsuccessful search, raise an IOError exception."""
543
543
544 if alt_dirs is None:
544 if alt_dirs is None:
545 try:
545 try:
546 alt_dirs = get_home_dir()
546 alt_dirs = get_home_dir()
547 except HomeDirError:
547 except HomeDirError:
548 alt_dirs = os.getcwd()
548 alt_dirs = os.getcwd()
549 search = [fname] + list_strings(alt_dirs)
549 search = [fname] + list_strings(alt_dirs)
550 search = map(os.path.expanduser,search)
550 search = map(os.path.expanduser,search)
551 #print 'search list for',fname,'list:',search # dbg
551 #print 'search list for',fname,'list:',search # dbg
552 fname = search[0]
552 fname = search[0]
553 if os.path.isfile(fname):
553 if os.path.isfile(fname):
554 return fname
554 return fname
555 for direc in search[1:]:
555 for direc in search[1:]:
556 testname = os.path.join(direc,fname)
556 testname = os.path.join(direc,fname)
557 #print 'testname',testname # dbg
557 #print 'testname',testname # dbg
558 if os.path.isfile(testname):
558 if os.path.isfile(testname):
559 return testname
559 return testname
560 raise IOError,'File' + `fname` + \
560 raise IOError,'File' + `fname` + \
561 ' not found in current or supplied directories:' + `alt_dirs`
561 ' not found in current or supplied directories:' + `alt_dirs`
562
562
563 #----------------------------------------------------------------------------
563 #----------------------------------------------------------------------------
564 def file_read(filename):
564 def file_read(filename):
565 """Read a file and close it. Returns the file source."""
565 """Read a file and close it. Returns the file source."""
566 fobj = open(filename,'r');
566 fobj = open(filename,'r');
567 source = fobj.read();
567 source = fobj.read();
568 fobj.close()
568 fobj.close()
569 return source
569 return source
570
570
571 def file_readlines(filename):
571 def file_readlines(filename):
572 """Read a file and close it. Returns the file source using readlines()."""
572 """Read a file and close it. Returns the file source using readlines()."""
573 fobj = open(filename,'r');
573 fobj = open(filename,'r');
574 lines = fobj.readlines();
574 lines = fobj.readlines();
575 fobj.close()
575 fobj.close()
576 return lines
576 return lines
577
577
578 #----------------------------------------------------------------------------
578 #----------------------------------------------------------------------------
579 def target_outdated(target,deps):
579 def target_outdated(target,deps):
580 """Determine whether a target is out of date.
580 """Determine whether a target is out of date.
581
581
582 target_outdated(target,deps) -> 1/0
582 target_outdated(target,deps) -> 1/0
583
583
584 deps: list of filenames which MUST exist.
584 deps: list of filenames which MUST exist.
585 target: single filename which may or may not exist.
585 target: single filename which may or may not exist.
586
586
587 If target doesn't exist or is older than any file listed in deps, return
587 If target doesn't exist or is older than any file listed in deps, return
588 true, otherwise return false.
588 true, otherwise return false.
589 """
589 """
590 try:
590 try:
591 target_time = os.path.getmtime(target)
591 target_time = os.path.getmtime(target)
592 except os.error:
592 except os.error:
593 return 1
593 return 1
594 for dep in deps:
594 for dep in deps:
595 dep_time = os.path.getmtime(dep)
595 dep_time = os.path.getmtime(dep)
596 if dep_time > target_time:
596 if dep_time > target_time:
597 #print "For target",target,"Dep failed:",dep # dbg
597 #print "For target",target,"Dep failed:",dep # dbg
598 #print "times (dep,tar):",dep_time,target_time # dbg
598 #print "times (dep,tar):",dep_time,target_time # dbg
599 return 1
599 return 1
600 return 0
600 return 0
601
601
602 #-----------------------------------------------------------------------------
602 #-----------------------------------------------------------------------------
603 def target_update(target,deps,cmd):
603 def target_update(target,deps,cmd):
604 """Update a target with a given command given a list of dependencies.
604 """Update a target with a given command given a list of dependencies.
605
605
606 target_update(target,deps,cmd) -> runs cmd if target is outdated.
606 target_update(target,deps,cmd) -> runs cmd if target is outdated.
607
607
608 This is just a wrapper around target_outdated() which calls the given
608 This is just a wrapper around target_outdated() which calls the given
609 command if target is outdated."""
609 command if target is outdated."""
610
610
611 if target_outdated(target,deps):
611 if target_outdated(target,deps):
612 xsys(cmd)
612 xsys(cmd)
613
613
614 #----------------------------------------------------------------------------
614 #----------------------------------------------------------------------------
615 def unquote_ends(istr):
615 def unquote_ends(istr):
616 """Remove a single pair of quotes from the endpoints of a string."""
616 """Remove a single pair of quotes from the endpoints of a string."""
617
617
618 if not istr:
618 if not istr:
619 return istr
619 return istr
620 if (istr[0]=="'" and istr[-1]=="'") or \
620 if (istr[0]=="'" and istr[-1]=="'") or \
621 (istr[0]=='"' and istr[-1]=='"'):
621 (istr[0]=='"' and istr[-1]=='"'):
622 return istr[1:-1]
622 return istr[1:-1]
623 else:
623 else:
624 return istr
624 return istr
625
625
626 #----------------------------------------------------------------------------
626 #----------------------------------------------------------------------------
627 def process_cmdline(argv,names=[],defaults={},usage=''):
627 def process_cmdline(argv,names=[],defaults={},usage=''):
628 """ Process command-line options and arguments.
628 """ Process command-line options and arguments.
629
629
630 Arguments:
630 Arguments:
631
631
632 - argv: list of arguments, typically sys.argv.
632 - argv: list of arguments, typically sys.argv.
633
633
634 - names: list of option names. See DPyGetOpt docs for details on options
634 - names: list of option names. See DPyGetOpt docs for details on options
635 syntax.
635 syntax.
636
636
637 - defaults: dict of default values.
637 - defaults: dict of default values.
638
638
639 - usage: optional usage notice to print if a wrong argument is passed.
639 - usage: optional usage notice to print if a wrong argument is passed.
640
640
641 Return a dict of options and a list of free arguments."""
641 Return a dict of options and a list of free arguments."""
642
642
643 getopt = DPyGetOpt.DPyGetOpt()
643 getopt = DPyGetOpt.DPyGetOpt()
644 getopt.setIgnoreCase(0)
644 getopt.setIgnoreCase(0)
645 getopt.parseConfiguration(names)
645 getopt.parseConfiguration(names)
646
646
647 try:
647 try:
648 getopt.processArguments(argv)
648 getopt.processArguments(argv)
649 except DPyGetOpt.ArgumentError, exc:
649 except DPyGetOpt.ArgumentError, exc:
650 print usage
650 print usage
651 warn('"%s"' % exc,level=4)
651 warn('"%s"' % exc,level=4)
652
652
653 defaults.update(getopt.optionValues)
653 defaults.update(getopt.optionValues)
654 args = getopt.freeValues
654 args = getopt.freeValues
655
655
656 return defaults,args
656 return defaults,args
657
657
658 #----------------------------------------------------------------------------
658 #----------------------------------------------------------------------------
659 def optstr2types(ostr):
659 def optstr2types(ostr):
660 """Convert a string of option names to a dict of type mappings.
660 """Convert a string of option names to a dict of type mappings.
661
661
662 optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
662 optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'}
663
663
664 This is used to get the types of all the options in a string formatted
664 This is used to get the types of all the options in a string formatted
665 with the conventions of DPyGetOpt. The 'type' None is used for options
665 with the conventions of DPyGetOpt. The 'type' None is used for options
666 which are strings (they need no further conversion). This function's main
666 which are strings (they need no further conversion). This function's main
667 use is to get a typemap for use with read_dict().
667 use is to get a typemap for use with read_dict().
668 """
668 """
669
669
670 typeconv = {None:'',int:'',float:''}
670 typeconv = {None:'',int:'',float:''}
671 typemap = {'s':None,'i':int,'f':float}
671 typemap = {'s':None,'i':int,'f':float}
672 opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
672 opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)')
673
673
674 for w in ostr.split():
674 for w in ostr.split():
675 oname,alias,otype = opt_re.match(w).groups()
675 oname,alias,otype = opt_re.match(w).groups()
676 if otype == '' or alias == '!': # simple switches are integers too
676 if otype == '' or alias == '!': # simple switches are integers too
677 otype = 'i'
677 otype = 'i'
678 typeconv[typemap[otype]] += oname + ' '
678 typeconv[typemap[otype]] += oname + ' '
679 return typeconv
679 return typeconv
680
680
681 #----------------------------------------------------------------------------
681 #----------------------------------------------------------------------------
682 def read_dict(filename,type_conv=None,**opt):
682 def read_dict(filename,type_conv=None,**opt):
683 r"""Read a dictionary of key=value pairs from an input file, optionally
683 r"""Read a dictionary of key=value pairs from an input file, optionally
684 performing conversions on the resulting values.
684 performing conversions on the resulting values.
685
685
686 read_dict(filename,type_conv,**opt) -> dict
686 read_dict(filename,type_conv,**opt) -> dict
687
687
688 Only one value per line is accepted, the format should be
688 Only one value per line is accepted, the format should be
689 # optional comments are ignored
689 # optional comments are ignored
690 key value\n
690 key value\n
691
691
692 Args:
692 Args:
693
693
694 - type_conv: A dictionary specifying which keys need to be converted to
694 - type_conv: A dictionary specifying which keys need to be converted to
695 which types. By default all keys are read as strings. This dictionary
695 which types. By default all keys are read as strings. This dictionary
696 should have as its keys valid conversion functions for strings
696 should have as its keys valid conversion functions for strings
697 (int,long,float,complex, or your own). The value for each key
697 (int,long,float,complex, or your own). The value for each key
698 (converter) should be a whitespace separated string containing the names
698 (converter) should be a whitespace separated string containing the names
699 of all the entries in the file to be converted using that function. For
699 of all the entries in the file to be converted using that function. For
700 keys to be left alone, use None as the conversion function (only needed
700 keys to be left alone, use None as the conversion function (only needed
701 with purge=1, see below).
701 with purge=1, see below).
702
702
703 - opt: dictionary with extra options as below (default in parens)
703 - opt: dictionary with extra options as below (default in parens)
704
704
705 purge(0): if set to 1, all keys *not* listed in type_conv are purged out
705 purge(0): if set to 1, all keys *not* listed in type_conv are purged out
706 of the dictionary to be returned. If purge is going to be used, the
706 of the dictionary to be returned. If purge is going to be used, the
707 set of keys to be left as strings also has to be explicitly specified
707 set of keys to be left as strings also has to be explicitly specified
708 using the (non-existent) conversion function None.
708 using the (non-existent) conversion function None.
709
709
710 fs(None): field separator. This is the key/value separator to be used
710 fs(None): field separator. This is the key/value separator to be used
711 when parsing the file. The None default means any whitespace [behavior
711 when parsing the file. The None default means any whitespace [behavior
712 of string.split()].
712 of string.split()].
713
713
714 strip(0): if 1, strip string values of leading/trailinig whitespace.
714 strip(0): if 1, strip string values of leading/trailinig whitespace.
715
715
716 warn(1): warning level if requested keys are not found in file.
716 warn(1): warning level if requested keys are not found in file.
717 - 0: silently ignore.
717 - 0: silently ignore.
718 - 1: inform but proceed.
718 - 1: inform but proceed.
719 - 2: raise KeyError exception.
719 - 2: raise KeyError exception.
720
720
721 no_empty(0): if 1, remove keys with whitespace strings as a value.
721 no_empty(0): if 1, remove keys with whitespace strings as a value.
722
722
723 unique([]): list of keys (or space separated string) which can't be
723 unique([]): list of keys (or space separated string) which can't be
724 repeated. If one such key is found in the file, each new instance
724 repeated. If one such key is found in the file, each new instance
725 overwrites the previous one. For keys not listed here, the behavior is
725 overwrites the previous one. For keys not listed here, the behavior is
726 to make a list of all appearances.
726 to make a list of all appearances.
727
727
728 Example:
728 Example:
729
729
730 If the input file test.ini contains (we put it in a string to keep the test
730 If the input file test.ini contains (we put it in a string to keep the test
731 self-contained):
731 self-contained):
732
732
733 >>> test_ini = '''\
733 >>> test_ini = '''\
734 ... i 3
734 ... i 3
735 ... x 4.5
735 ... x 4.5
736 ... y 5.5
736 ... y 5.5
737 ... s hi ho'''
737 ... s hi ho'''
738
738
739 Then we can use it as follows:
739 Then we can use it as follows:
740 >>> type_conv={int:'i',float:'x',None:'s'}
740 >>> type_conv={int:'i',float:'x',None:'s'}
741
741
742 >>> d = read_dict(test_ini)
742 >>> d = read_dict(test_ini)
743
743
744 >>> sorted(d.items())
744 >>> sorted(d.items())
745 [('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')]
745 [('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')]
746
746
747 >>> d = read_dict(test_ini,type_conv)
747 >>> d = read_dict(test_ini,type_conv)
748
748
749 >>> sorted(d.items())
749 >>> sorted(d.items())
750 [('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')]
750 [('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')]
751
751
752 >>> d = read_dict(test_ini,type_conv,purge=True)
752 >>> d = read_dict(test_ini,type_conv,purge=True)
753
753
754 >>> sorted(d.items())
754 >>> sorted(d.items())
755 [('i', 3), ('s', 'hi ho'), ('x', 4.5)]
755 [('i', 3), ('s', 'hi ho'), ('x', 4.5)]
756 """
756 """
757
757
758 # starting config
758 # starting config
759 opt.setdefault('purge',0)
759 opt.setdefault('purge',0)
760 opt.setdefault('fs',None) # field sep defaults to any whitespace
760 opt.setdefault('fs',None) # field sep defaults to any whitespace
761 opt.setdefault('strip',0)
761 opt.setdefault('strip',0)
762 opt.setdefault('warn',1)
762 opt.setdefault('warn',1)
763 opt.setdefault('no_empty',0)
763 opt.setdefault('no_empty',0)
764 opt.setdefault('unique','')
764 opt.setdefault('unique','')
765 if type(opt['unique']) in StringTypes:
765 if type(opt['unique']) in StringTypes:
766 unique_keys = qw(opt['unique'])
766 unique_keys = qw(opt['unique'])
767 elif type(opt['unique']) in (types.TupleType,types.ListType):
767 elif type(opt['unique']) in (types.TupleType,types.ListType):
768 unique_keys = opt['unique']
768 unique_keys = opt['unique']
769 else:
769 else:
770 raise ValueError, 'Unique keys must be given as a string, List or Tuple'
770 raise ValueError, 'Unique keys must be given as a string, List or Tuple'
771
771
772 dict = {}
772 dict = {}
773
773
774 # first read in table of values as strings
774 # first read in table of values as strings
775 if '\n' in filename:
775 if '\n' in filename:
776 lines = filename.splitlines()
776 lines = filename.splitlines()
777 file = None
777 file = None
778 else:
778 else:
779 file = open(filename,'r')
779 file = open(filename,'r')
780 lines = file.readlines()
780 lines = file.readlines()
781 for line in lines:
781 for line in lines:
782 line = line.strip()
782 line = line.strip()
783 if len(line) and line[0]=='#': continue
783 if len(line) and line[0]=='#': continue
784 if len(line)>0:
784 if len(line)>0:
785 lsplit = line.split(opt['fs'],1)
785 lsplit = line.split(opt['fs'],1)
786 try:
786 try:
787 key,val = lsplit
787 key,val = lsplit
788 except ValueError:
788 except ValueError:
789 key,val = lsplit[0],''
789 key,val = lsplit[0],''
790 key = key.strip()
790 key = key.strip()
791 if opt['strip']: val = val.strip()
791 if opt['strip']: val = val.strip()
792 if val == "''" or val == '""': val = ''
792 if val == "''" or val == '""': val = ''
793 if opt['no_empty'] and (val=='' or val.isspace()):
793 if opt['no_empty'] and (val=='' or val.isspace()):
794 continue
794 continue
795 # if a key is found more than once in the file, build a list
795 # if a key is found more than once in the file, build a list
796 # unless it's in the 'unique' list. In that case, last found in file
796 # unless it's in the 'unique' list. In that case, last found in file
797 # takes precedence. User beware.
797 # takes precedence. User beware.
798 try:
798 try:
799 if dict[key] and key in unique_keys:
799 if dict[key] and key in unique_keys:
800 dict[key] = val
800 dict[key] = val
801 elif type(dict[key]) is types.ListType:
801 elif type(dict[key]) is types.ListType:
802 dict[key].append(val)
802 dict[key].append(val)
803 else:
803 else:
804 dict[key] = [dict[key],val]
804 dict[key] = [dict[key],val]
805 except KeyError:
805 except KeyError:
806 dict[key] = val
806 dict[key] = val
807 # purge if requested
807 # purge if requested
808 if opt['purge']:
808 if opt['purge']:
809 accepted_keys = qwflat(type_conv.values())
809 accepted_keys = qwflat(type_conv.values())
810 for key in dict.keys():
810 for key in dict.keys():
811 if key in accepted_keys: continue
811 if key in accepted_keys: continue
812 del(dict[key])
812 del(dict[key])
813 # now convert if requested
813 # now convert if requested
814 if type_conv==None: return dict
814 if type_conv==None: return dict
815 conversions = type_conv.keys()
815 conversions = type_conv.keys()
816 try: conversions.remove(None)
816 try: conversions.remove(None)
817 except: pass
817 except: pass
818 for convert in conversions:
818 for convert in conversions:
819 for val in qw(type_conv[convert]):
819 for val in qw(type_conv[convert]):
820 try:
820 try:
821 dict[val] = convert(dict[val])
821 dict[val] = convert(dict[val])
822 except KeyError,e:
822 except KeyError,e:
823 if opt['warn'] == 0:
823 if opt['warn'] == 0:
824 pass
824 pass
825 elif opt['warn'] == 1:
825 elif opt['warn'] == 1:
826 print >>sys.stderr, 'Warning: key',val,\
826 print >>sys.stderr, 'Warning: key',val,\
827 'not found in file',filename
827 'not found in file',filename
828 elif opt['warn'] == 2:
828 elif opt['warn'] == 2:
829 raise KeyError,e
829 raise KeyError,e
830 else:
830 else:
831 raise ValueError,'Warning level must be 0,1 or 2'
831 raise ValueError,'Warning level must be 0,1 or 2'
832
832
833 return dict
833 return dict
834
834
835 #----------------------------------------------------------------------------
835 #----------------------------------------------------------------------------
836 def flag_calls(func):
836 def flag_calls(func):
837 """Wrap a function to detect and flag when it gets called.
837 """Wrap a function to detect and flag when it gets called.
838
838
839 This is a decorator which takes a function and wraps it in a function with
839 This is a decorator which takes a function and wraps it in a function with
840 a 'called' attribute. wrapper.called is initialized to False.
840 a 'called' attribute. wrapper.called is initialized to False.
841
841
842 The wrapper.called attribute is set to False right before each call to the
842 The wrapper.called attribute is set to False right before each call to the
843 wrapped function, so if the call fails it remains False. After the call
843 wrapped function, so if the call fails it remains False. After the call
844 completes, wrapper.called is set to True and the output is returned.
844 completes, wrapper.called is set to True and the output is returned.
845
845
846 Testing for truth in wrapper.called allows you to determine if a call to
846 Testing for truth in wrapper.called allows you to determine if a call to
847 func() was attempted and succeeded."""
847 func() was attempted and succeeded."""
848
848
849 def wrapper(*args,**kw):
849 def wrapper(*args,**kw):
850 wrapper.called = False
850 wrapper.called = False
851 out = func(*args,**kw)
851 out = func(*args,**kw)
852 wrapper.called = True
852 wrapper.called = True
853 return out
853 return out
854
854
855 wrapper.called = False
855 wrapper.called = False
856 wrapper.__doc__ = func.__doc__
856 wrapper.__doc__ = func.__doc__
857 return wrapper
857 return wrapper
858
858
859 #----------------------------------------------------------------------------
859 #----------------------------------------------------------------------------
860 def dhook_wrap(func,*a,**k):
860 def dhook_wrap(func,*a,**k):
861 """Wrap a function call in a sys.displayhook controller.
861 """Wrap a function call in a sys.displayhook controller.
862
862
863 Returns a wrapper around func which calls func, with all its arguments and
863 Returns a wrapper around func which calls func, with all its arguments and
864 keywords unmodified, using the default sys.displayhook. Since IPython
864 keywords unmodified, using the default sys.displayhook. Since IPython
865 modifies sys.displayhook, it breaks the behavior of certain systems that
865 modifies sys.displayhook, it breaks the behavior of certain systems that
866 rely on the default behavior, notably doctest.
866 rely on the default behavior, notably doctest.
867 """
867 """
868
868
869 def f(*a,**k):
869 def f(*a,**k):
870
870
871 dhook_s = sys.displayhook
871 dhook_s = sys.displayhook
872 sys.displayhook = sys.__displayhook__
872 sys.displayhook = sys.__displayhook__
873 try:
873 try:
874 out = func(*a,**k)
874 out = func(*a,**k)
875 finally:
875 finally:
876 sys.displayhook = dhook_s
876 sys.displayhook = dhook_s
877
877
878 return out
878 return out
879
879
880 f.__doc__ = func.__doc__
880 f.__doc__ = func.__doc__
881 return f
881 return f
882
882
883 #----------------------------------------------------------------------------
883 #----------------------------------------------------------------------------
884 def doctest_reload():
884 def doctest_reload():
885 """Properly reload doctest to reuse it interactively.
885 """Properly reload doctest to reuse it interactively.
886
886
887 This routine:
887 This routine:
888
888
889 - reloads doctest
889 - reloads doctest
890
890
891 - resets its global 'master' attribute to None, so that multiple uses of
891 - resets its global 'master' attribute to None, so that multiple uses of
892 the module interactively don't produce cumulative reports.
892 the module interactively don't produce cumulative reports.
893
893
894 - Monkeypatches its core test runner method to protect it from IPython's
894 - Monkeypatches its core test runner method to protect it from IPython's
895 modified displayhook. Doctest expects the default displayhook behavior
895 modified displayhook. Doctest expects the default displayhook behavior
896 deep down, so our modification breaks it completely. For this reason, a
896 deep down, so our modification breaks it completely. For this reason, a
897 hard monkeypatch seems like a reasonable solution rather than asking
897 hard monkeypatch seems like a reasonable solution rather than asking
898 users to manually use a different doctest runner when under IPython."""
898 users to manually use a different doctest runner when under IPython."""
899
899
900 import doctest
900 import doctest
901 reload(doctest)
901 reload(doctest)
902 doctest.master=None
902 doctest.master=None
903
903
904 try:
904 try:
905 doctest.DocTestRunner
905 doctest.DocTestRunner
906 except AttributeError:
906 except AttributeError:
907 # This is only for python 2.3 compatibility, remove once we move to
907 # This is only for python 2.3 compatibility, remove once we move to
908 # 2.4 only.
908 # 2.4 only.
909 pass
909 pass
910 else:
910 else:
911 doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
911 doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
912
912
913 #----------------------------------------------------------------------------
913 #----------------------------------------------------------------------------
914 class HomeDirError(Error):
914 class HomeDirError(Error):
915 pass
915 pass
916
916
917 def get_home_dir():
917 def get_home_dir():
918 """Return the closest possible equivalent to a 'home' directory.
918 """Return the closest possible equivalent to a 'home' directory.
919
919
920 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
920 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
921
921
922 Currently only Posix and NT are implemented, a HomeDirError exception is
922 Currently only Posix and NT are implemented, a HomeDirError exception is
923 raised for all other OSes. """
923 raised for all other OSes. """
924
924
925 isdir = os.path.isdir
925 isdir = os.path.isdir
926 env = os.environ
926 env = os.environ
927
927
928 # first, check py2exe distribution root directory for _ipython.
928 # first, check py2exe distribution root directory for _ipython.
929 # This overrides all. Normally does not exist.
929 # This overrides all. Normally does not exist.
930
930
931 if '\\library.zip\\' in IPython.__file__.lower():
931 if '\\library.zip\\' in IPython.__file__.lower():
932 root, rest = IPython.__file__.lower().split('library.zip')
932 root, rest = IPython.__file__.lower().split('library.zip')
933 if isdir(root + '_ipython'):
933 if isdir(root + '_ipython'):
934 os.environ["IPYKITROOT"] = root.rstrip('\\')
934 os.environ["IPYKITROOT"] = root.rstrip('\\')
935 return root
935 return root
936
936
937 try:
937 try:
938 homedir = env['HOME']
938 homedir = env['HOME']
939 if not isdir(homedir):
939 if not isdir(homedir):
940 # in case a user stuck some string which does NOT resolve to a
940 # in case a user stuck some string which does NOT resolve to a
941 # valid path, it's as good as if we hadn't foud it
941 # valid path, it's as good as if we hadn't foud it
942 raise KeyError
942 raise KeyError
943 return homedir
943 return homedir
944 except KeyError:
944 except KeyError:
945 if os.name == 'posix':
945 if os.name == 'posix':
946 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
946 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
947 elif os.name == 'nt':
947 elif os.name == 'nt':
948 # For some strange reason, win9x returns 'nt' for os.name.
948 # For some strange reason, win9x returns 'nt' for os.name.
949 try:
949 try:
950 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
950 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
951 if not isdir(homedir):
951 if not isdir(homedir):
952 homedir = os.path.join(env['USERPROFILE'])
952 homedir = os.path.join(env['USERPROFILE'])
953 if not isdir(homedir):
953 if not isdir(homedir):
954 raise HomeDirError
954 raise HomeDirError
955 return homedir
955 return homedir
956 except:
956 except:
957 try:
957 try:
958 # Use the registry to get the 'My Documents' folder.
958 # Use the registry to get the 'My Documents' folder.
959 import _winreg as wreg
959 import _winreg as wreg
960 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
960 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
961 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
961 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
962 homedir = wreg.QueryValueEx(key,'Personal')[0]
962 homedir = wreg.QueryValueEx(key,'Personal')[0]
963 key.Close()
963 key.Close()
964 if not isdir(homedir):
964 if not isdir(homedir):
965 e = ('Invalid "Personal" folder registry key '
965 e = ('Invalid "Personal" folder registry key '
966 'typically "My Documents".\n'
966 'typically "My Documents".\n'
967 'Value: %s\n'
967 'Value: %s\n'
968 'This is not a valid directory on your system.' %
968 'This is not a valid directory on your system.' %
969 homedir)
969 homedir)
970 raise HomeDirError(e)
970 raise HomeDirError(e)
971 return homedir
971 return homedir
972 except HomeDirError:
972 except HomeDirError:
973 raise
973 raise
974 except:
974 except:
975 return 'C:\\'
975 return 'C:\\'
976 elif os.name == 'dos':
976 elif os.name == 'dos':
977 # Desperate, may do absurd things in classic MacOS. May work under DOS.
977 # Desperate, may do absurd things in classic MacOS. May work under DOS.
978 return 'C:\\'
978 return 'C:\\'
979 else:
979 else:
980 raise HomeDirError,'support for your operating system not implemented.'
980 raise HomeDirError,'support for your operating system not implemented.'
981
981
982
982
983 def get_ipython_dir():
983 def get_ipython_dir():
984 """Get the IPython directory for this platform and user.
984 """Get the IPython directory for this platform and user.
985
985
986 This uses the logic in `get_home_dir` to find the home directory
986 This uses the logic in `get_home_dir` to find the home directory
987 and the adds either .ipython or _ipython to the end of the path.
987 and the adds either .ipython or _ipython to the end of the path.
988 """
988 """
989 if os.name == 'posix':
989 if os.name == 'posix':
990 ipdir_def = '.ipython'
990 ipdir_def = '.ipython'
991 else:
991 else:
992 ipdir_def = '_ipython'
992 ipdir_def = '_ipython'
993 home_dir = get_home_dir()
993 home_dir = get_home_dir()
994 ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
994 ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
995 os.path.join(home_dir,ipdir_def)))
995 os.path.join(home_dir,ipdir_def)))
996 return ipdir
996 return ipdir
997
997
998 def get_security_dir():
999 """Get the IPython security directory.
1000
1001 This directory is the default location for all security related files,
1002 including SSL/TLS certificates and FURL files.
1003
1004 If the directory does not exist, it is created with 0700 permissions.
1005 If it exists, permissions are set to 0700.
1006 """
1007 security_dir = os.path.join(get_ipython_dir(), 'security')
1008 if not os.path.isdir(security_dir):
1009 os.mkdir(security_dir, 0700)
1010 else:
1011 os.chmod(security_dir, 0700)
1012 return security_dir
1013
998 #****************************************************************************
1014 #****************************************************************************
999 # strings and text
1015 # strings and text
1000
1016
1001 class LSString(str):
1017 class LSString(str):
1002 """String derivative with a special access attributes.
1018 """String derivative with a special access attributes.
1003
1019
1004 These are normal strings, but with the special attributes:
1020 These are normal strings, but with the special attributes:
1005
1021
1006 .l (or .list) : value as list (split on newlines).
1022 .l (or .list) : value as list (split on newlines).
1007 .n (or .nlstr): original value (the string itself).
1023 .n (or .nlstr): original value (the string itself).
1008 .s (or .spstr): value as whitespace-separated string.
1024 .s (or .spstr): value as whitespace-separated string.
1009 .p (or .paths): list of path objects
1025 .p (or .paths): list of path objects
1010
1026
1011 Any values which require transformations are computed only once and
1027 Any values which require transformations are computed only once and
1012 cached.
1028 cached.
1013
1029
1014 Such strings are very useful to efficiently interact with the shell, which
1030 Such strings are very useful to efficiently interact with the shell, which
1015 typically only understands whitespace-separated options for commands."""
1031 typically only understands whitespace-separated options for commands."""
1016
1032
1017 def get_list(self):
1033 def get_list(self):
1018 try:
1034 try:
1019 return self.__list
1035 return self.__list
1020 except AttributeError:
1036 except AttributeError:
1021 self.__list = self.split('\n')
1037 self.__list = self.split('\n')
1022 return self.__list
1038 return self.__list
1023
1039
1024 l = list = property(get_list)
1040 l = list = property(get_list)
1025
1041
1026 def get_spstr(self):
1042 def get_spstr(self):
1027 try:
1043 try:
1028 return self.__spstr
1044 return self.__spstr
1029 except AttributeError:
1045 except AttributeError:
1030 self.__spstr = self.replace('\n',' ')
1046 self.__spstr = self.replace('\n',' ')
1031 return self.__spstr
1047 return self.__spstr
1032
1048
1033 s = spstr = property(get_spstr)
1049 s = spstr = property(get_spstr)
1034
1050
1035 def get_nlstr(self):
1051 def get_nlstr(self):
1036 return self
1052 return self
1037
1053
1038 n = nlstr = property(get_nlstr)
1054 n = nlstr = property(get_nlstr)
1039
1055
1040 def get_paths(self):
1056 def get_paths(self):
1041 try:
1057 try:
1042 return self.__paths
1058 return self.__paths
1043 except AttributeError:
1059 except AttributeError:
1044 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
1060 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
1045 return self.__paths
1061 return self.__paths
1046
1062
1047 p = paths = property(get_paths)
1063 p = paths = property(get_paths)
1048
1064
1049 def print_lsstring(arg):
1065 def print_lsstring(arg):
1050 """ Prettier (non-repr-like) and more informative printer for LSString """
1066 """ Prettier (non-repr-like) and more informative printer for LSString """
1051 print "LSString (.p, .n, .l, .s available). Value:"
1067 print "LSString (.p, .n, .l, .s available). Value:"
1052 print arg
1068 print arg
1053
1069
1054 print_lsstring = result_display.when_type(LSString)(print_lsstring)
1070 print_lsstring = result_display.when_type(LSString)(print_lsstring)
1055
1071
1056 #----------------------------------------------------------------------------
1072 #----------------------------------------------------------------------------
1057 class SList(list):
1073 class SList(list):
1058 """List derivative with a special access attributes.
1074 """List derivative with a special access attributes.
1059
1075
1060 These are normal lists, but with the special attributes:
1076 These are normal lists, but with the special attributes:
1061
1077
1062 .l (or .list) : value as list (the list itself).
1078 .l (or .list) : value as list (the list itself).
1063 .n (or .nlstr): value as a string, joined on newlines.
1079 .n (or .nlstr): value as a string, joined on newlines.
1064 .s (or .spstr): value as a string, joined on spaces.
1080 .s (or .spstr): value as a string, joined on spaces.
1065 .p (or .paths): list of path objects
1081 .p (or .paths): list of path objects
1066
1082
1067 Any values which require transformations are computed only once and
1083 Any values which require transformations are computed only once and
1068 cached."""
1084 cached."""
1069
1085
1070 def get_list(self):
1086 def get_list(self):
1071 return self
1087 return self
1072
1088
1073 l = list = property(get_list)
1089 l = list = property(get_list)
1074
1090
1075 def get_spstr(self):
1091 def get_spstr(self):
1076 try:
1092 try:
1077 return self.__spstr
1093 return self.__spstr
1078 except AttributeError:
1094 except AttributeError:
1079 self.__spstr = ' '.join(self)
1095 self.__spstr = ' '.join(self)
1080 return self.__spstr
1096 return self.__spstr
1081
1097
1082 s = spstr = property(get_spstr)
1098 s = spstr = property(get_spstr)
1083
1099
1084 def get_nlstr(self):
1100 def get_nlstr(self):
1085 try:
1101 try:
1086 return self.__nlstr
1102 return self.__nlstr
1087 except AttributeError:
1103 except AttributeError:
1088 self.__nlstr = '\n'.join(self)
1104 self.__nlstr = '\n'.join(self)
1089 return self.__nlstr
1105 return self.__nlstr
1090
1106
1091 n = nlstr = property(get_nlstr)
1107 n = nlstr = property(get_nlstr)
1092
1108
1093 def get_paths(self):
1109 def get_paths(self):
1094 try:
1110 try:
1095 return self.__paths
1111 return self.__paths
1096 except AttributeError:
1112 except AttributeError:
1097 self.__paths = [path(p) for p in self if os.path.exists(p)]
1113 self.__paths = [path(p) for p in self if os.path.exists(p)]
1098 return self.__paths
1114 return self.__paths
1099
1115
1100 p = paths = property(get_paths)
1116 p = paths = property(get_paths)
1101
1117
1102 def grep(self, pattern, prune = False, field = None):
1118 def grep(self, pattern, prune = False, field = None):
1103 """ Return all strings matching 'pattern' (a regex or callable)
1119 """ Return all strings matching 'pattern' (a regex or callable)
1104
1120
1105 This is case-insensitive. If prune is true, return all items
1121 This is case-insensitive. If prune is true, return all items
1106 NOT matching the pattern.
1122 NOT matching the pattern.
1107
1123
1108 If field is specified, the match must occur in the specified
1124 If field is specified, the match must occur in the specified
1109 whitespace-separated field.
1125 whitespace-separated field.
1110
1126
1111 Examples::
1127 Examples::
1112
1128
1113 a.grep( lambda x: x.startswith('C') )
1129 a.grep( lambda x: x.startswith('C') )
1114 a.grep('Cha.*log', prune=1)
1130 a.grep('Cha.*log', prune=1)
1115 a.grep('chm', field=-1)
1131 a.grep('chm', field=-1)
1116 """
1132 """
1117
1133
1118 def match_target(s):
1134 def match_target(s):
1119 if field is None:
1135 if field is None:
1120 return s
1136 return s
1121 parts = s.split()
1137 parts = s.split()
1122 try:
1138 try:
1123 tgt = parts[field]
1139 tgt = parts[field]
1124 return tgt
1140 return tgt
1125 except IndexError:
1141 except IndexError:
1126 return ""
1142 return ""
1127
1143
1128 if isinstance(pattern, basestring):
1144 if isinstance(pattern, basestring):
1129 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
1145 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
1130 else:
1146 else:
1131 pred = pattern
1147 pred = pattern
1132 if not prune:
1148 if not prune:
1133 return SList([el for el in self if pred(match_target(el))])
1149 return SList([el for el in self if pred(match_target(el))])
1134 else:
1150 else:
1135 return SList([el for el in self if not pred(match_target(el))])
1151 return SList([el for el in self if not pred(match_target(el))])
1136 def fields(self, *fields):
1152 def fields(self, *fields):
1137 """ Collect whitespace-separated fields from string list
1153 """ Collect whitespace-separated fields from string list
1138
1154
1139 Allows quick awk-like usage of string lists.
1155 Allows quick awk-like usage of string lists.
1140
1156
1141 Example data (in var a, created by 'a = !ls -l')::
1157 Example data (in var a, created by 'a = !ls -l')::
1142 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
1158 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
1143 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
1159 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
1144
1160
1145 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
1161 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
1146 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
1162 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
1147 (note the joining by space).
1163 (note the joining by space).
1148 a.fields(-1) is ['ChangeLog', 'IPython']
1164 a.fields(-1) is ['ChangeLog', 'IPython']
1149
1165
1150 IndexErrors are ignored.
1166 IndexErrors are ignored.
1151
1167
1152 Without args, fields() just split()'s the strings.
1168 Without args, fields() just split()'s the strings.
1153 """
1169 """
1154 if len(fields) == 0:
1170 if len(fields) == 0:
1155 return [el.split() for el in self]
1171 return [el.split() for el in self]
1156
1172
1157 res = SList()
1173 res = SList()
1158 for el in [f.split() for f in self]:
1174 for el in [f.split() for f in self]:
1159 lineparts = []
1175 lineparts = []
1160
1176
1161 for fd in fields:
1177 for fd in fields:
1162 try:
1178 try:
1163 lineparts.append(el[fd])
1179 lineparts.append(el[fd])
1164 except IndexError:
1180 except IndexError:
1165 pass
1181 pass
1166 if lineparts:
1182 if lineparts:
1167 res.append(" ".join(lineparts))
1183 res.append(" ".join(lineparts))
1168
1184
1169 return res
1185 return res
1170 def sort(self,field= None, nums = False):
1186 def sort(self,field= None, nums = False):
1171 """ sort by specified fields (see fields())
1187 """ sort by specified fields (see fields())
1172
1188
1173 Example::
1189 Example::
1174 a.sort(1, nums = True)
1190 a.sort(1, nums = True)
1175
1191
1176 Sorts a by second field, in numerical order (so that 21 > 3)
1192 Sorts a by second field, in numerical order (so that 21 > 3)
1177
1193
1178 """
1194 """
1179
1195
1180 #decorate, sort, undecorate
1196 #decorate, sort, undecorate
1181 if field is not None:
1197 if field is not None:
1182 dsu = [[SList([line]).fields(field), line] for line in self]
1198 dsu = [[SList([line]).fields(field), line] for line in self]
1183 else:
1199 else:
1184 dsu = [[line, line] for line in self]
1200 dsu = [[line, line] for line in self]
1185 if nums:
1201 if nums:
1186 for i in range(len(dsu)):
1202 for i in range(len(dsu)):
1187 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
1203 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
1188 try:
1204 try:
1189 n = int(numstr)
1205 n = int(numstr)
1190 except ValueError:
1206 except ValueError:
1191 n = 0;
1207 n = 0;
1192 dsu[i][0] = n
1208 dsu[i][0] = n
1193
1209
1194
1210
1195 dsu.sort()
1211 dsu.sort()
1196 return SList([t[1] for t in dsu])
1212 return SList([t[1] for t in dsu])
1197
1213
1198 def print_slist(arg):
1214 def print_slist(arg):
1199 """ Prettier (non-repr-like) and more informative printer for SList """
1215 """ Prettier (non-repr-like) and more informative printer for SList """
1200 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
1216 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
1201 if hasattr(arg, 'hideonce') and arg.hideonce:
1217 if hasattr(arg, 'hideonce') and arg.hideonce:
1202 arg.hideonce = False
1218 arg.hideonce = False
1203 return
1219 return
1204
1220
1205 nlprint(arg)
1221 nlprint(arg)
1206
1222
1207 print_slist = result_display.when_type(SList)(print_slist)
1223 print_slist = result_display.when_type(SList)(print_slist)
1208
1224
1209
1225
1210
1226
1211 #----------------------------------------------------------------------------
1227 #----------------------------------------------------------------------------
1212 def esc_quotes(strng):
1228 def esc_quotes(strng):
1213 """Return the input string with single and double quotes escaped out"""
1229 """Return the input string with single and double quotes escaped out"""
1214
1230
1215 return strng.replace('"','\\"').replace("'","\\'")
1231 return strng.replace('"','\\"').replace("'","\\'")
1216
1232
1217 #----------------------------------------------------------------------------
1233 #----------------------------------------------------------------------------
1218 def make_quoted_expr(s):
1234 def make_quoted_expr(s):
1219 """Return string s in appropriate quotes, using raw string if possible.
1235 """Return string s in appropriate quotes, using raw string if possible.
1220
1236
1221 Effectively this turns string: cd \ao\ao\
1237 Effectively this turns string: cd \ao\ao\
1222 to: r"cd \ao\ao\_"[:-1]
1238 to: r"cd \ao\ao\_"[:-1]
1223
1239
1224 Note the use of raw string and padding at the end to allow trailing backslash.
1240 Note the use of raw string and padding at the end to allow trailing backslash.
1225
1241
1226 """
1242 """
1227
1243
1228 tail = ''
1244 tail = ''
1229 tailpadding = ''
1245 tailpadding = ''
1230 raw = ''
1246 raw = ''
1231 if "\\" in s:
1247 if "\\" in s:
1232 raw = 'r'
1248 raw = 'r'
1233 if s.endswith('\\'):
1249 if s.endswith('\\'):
1234 tail = '[:-1]'
1250 tail = '[:-1]'
1235 tailpadding = '_'
1251 tailpadding = '_'
1236 if '"' not in s:
1252 if '"' not in s:
1237 quote = '"'
1253 quote = '"'
1238 elif "'" not in s:
1254 elif "'" not in s:
1239 quote = "'"
1255 quote = "'"
1240 elif '"""' not in s and not s.endswith('"'):
1256 elif '"""' not in s and not s.endswith('"'):
1241 quote = '"""'
1257 quote = '"""'
1242 elif "'''" not in s and not s.endswith("'"):
1258 elif "'''" not in s and not s.endswith("'"):
1243 quote = "'''"
1259 quote = "'''"
1244 else:
1260 else:
1245 # give up, backslash-escaped string will do
1261 # give up, backslash-escaped string will do
1246 return '"%s"' % esc_quotes(s)
1262 return '"%s"' % esc_quotes(s)
1247 res = raw + quote + s + tailpadding + quote + tail
1263 res = raw + quote + s + tailpadding + quote + tail
1248 return res
1264 return res
1249
1265
1250
1266
1251 #----------------------------------------------------------------------------
1267 #----------------------------------------------------------------------------
1252 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
1268 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
1253 """Take multiple lines of input.
1269 """Take multiple lines of input.
1254
1270
1255 A list with each line of input as a separate element is returned when a
1271 A list with each line of input as a separate element is returned when a
1256 termination string is entered (defaults to a single '.'). Input can also
1272 termination string is entered (defaults to a single '.'). Input can also
1257 terminate via EOF (^D in Unix, ^Z-RET in Windows).
1273 terminate via EOF (^D in Unix, ^Z-RET in Windows).
1258
1274
1259 Lines of input which end in \\ are joined into single entries (and a
1275 Lines of input which end in \\ are joined into single entries (and a
1260 secondary continuation prompt is issued as long as the user terminates
1276 secondary continuation prompt is issued as long as the user terminates
1261 lines with \\). This allows entering very long strings which are still
1277 lines with \\). This allows entering very long strings which are still
1262 meant to be treated as single entities.
1278 meant to be treated as single entities.
1263 """
1279 """
1264
1280
1265 try:
1281 try:
1266 if header:
1282 if header:
1267 header += '\n'
1283 header += '\n'
1268 lines = [raw_input(header + ps1)]
1284 lines = [raw_input(header + ps1)]
1269 except EOFError:
1285 except EOFError:
1270 return []
1286 return []
1271 terminate = [terminate_str]
1287 terminate = [terminate_str]
1272 try:
1288 try:
1273 while lines[-1:] != terminate:
1289 while lines[-1:] != terminate:
1274 new_line = raw_input(ps1)
1290 new_line = raw_input(ps1)
1275 while new_line.endswith('\\'):
1291 while new_line.endswith('\\'):
1276 new_line = new_line[:-1] + raw_input(ps2)
1292 new_line = new_line[:-1] + raw_input(ps2)
1277 lines.append(new_line)
1293 lines.append(new_line)
1278
1294
1279 return lines[:-1] # don't return the termination command
1295 return lines[:-1] # don't return the termination command
1280 except EOFError:
1296 except EOFError:
1281 print
1297 print
1282 return lines
1298 return lines
1283
1299
1284 #----------------------------------------------------------------------------
1300 #----------------------------------------------------------------------------
1285 def raw_input_ext(prompt='', ps2='... '):
1301 def raw_input_ext(prompt='', ps2='... '):
1286 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
1302 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
1287
1303
1288 line = raw_input(prompt)
1304 line = raw_input(prompt)
1289 while line.endswith('\\'):
1305 while line.endswith('\\'):
1290 line = line[:-1] + raw_input(ps2)
1306 line = line[:-1] + raw_input(ps2)
1291 return line
1307 return line
1292
1308
1293 #----------------------------------------------------------------------------
1309 #----------------------------------------------------------------------------
1294 def ask_yes_no(prompt,default=None):
1310 def ask_yes_no(prompt,default=None):
1295 """Asks a question and returns a boolean (y/n) answer.
1311 """Asks a question and returns a boolean (y/n) answer.
1296
1312
1297 If default is given (one of 'y','n'), it is used if the user input is
1313 If default is given (one of 'y','n'), it is used if the user input is
1298 empty. Otherwise the question is repeated until an answer is given.
1314 empty. Otherwise the question is repeated until an answer is given.
1299
1315
1300 An EOF is treated as the default answer. If there is no default, an
1316 An EOF is treated as the default answer. If there is no default, an
1301 exception is raised to prevent infinite loops.
1317 exception is raised to prevent infinite loops.
1302
1318
1303 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1319 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1304
1320
1305 answers = {'y':True,'n':False,'yes':True,'no':False}
1321 answers = {'y':True,'n':False,'yes':True,'no':False}
1306 ans = None
1322 ans = None
1307 while ans not in answers.keys():
1323 while ans not in answers.keys():
1308 try:
1324 try:
1309 ans = raw_input(prompt+' ').lower()
1325 ans = raw_input(prompt+' ').lower()
1310 if not ans: # response was an empty string
1326 if not ans: # response was an empty string
1311 ans = default
1327 ans = default
1312 except KeyboardInterrupt:
1328 except KeyboardInterrupt:
1313 pass
1329 pass
1314 except EOFError:
1330 except EOFError:
1315 if default in answers.keys():
1331 if default in answers.keys():
1316 ans = default
1332 ans = default
1317 print
1333 print
1318 else:
1334 else:
1319 raise
1335 raise
1320
1336
1321 return answers[ans]
1337 return answers[ans]
1322
1338
1323 #----------------------------------------------------------------------------
1339 #----------------------------------------------------------------------------
1324 def marquee(txt='',width=78,mark='*'):
1340 def marquee(txt='',width=78,mark='*'):
1325 """Return the input string centered in a 'marquee'."""
1341 """Return the input string centered in a 'marquee'."""
1326 if not txt:
1342 if not txt:
1327 return (mark*width)[:width]
1343 return (mark*width)[:width]
1328 nmark = (width-len(txt)-2)/len(mark)/2
1344 nmark = (width-len(txt)-2)/len(mark)/2
1329 if nmark < 0: nmark =0
1345 if nmark < 0: nmark =0
1330 marks = mark*nmark
1346 marks = mark*nmark
1331 return '%s %s %s' % (marks,txt,marks)
1347 return '%s %s %s' % (marks,txt,marks)
1332
1348
1333 #----------------------------------------------------------------------------
1349 #----------------------------------------------------------------------------
1334 class EvalDict:
1350 class EvalDict:
1335 """
1351 """
1336 Emulate a dict which evaluates its contents in the caller's frame.
1352 Emulate a dict which evaluates its contents in the caller's frame.
1337
1353
1338 Usage:
1354 Usage:
1339 >>> number = 19
1355 >>> number = 19
1340
1356
1341 >>> text = "python"
1357 >>> text = "python"
1342
1358
1343 >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1359 >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1344 Python 2.1 rules!
1360 Python 2.1 rules!
1345 """
1361 """
1346
1362
1347 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1363 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1348 # modified (shorter) version of:
1364 # modified (shorter) version of:
1349 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1365 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1350 # Skip Montanaro (skip@pobox.com).
1366 # Skip Montanaro (skip@pobox.com).
1351
1367
1352 def __getitem__(self, name):
1368 def __getitem__(self, name):
1353 frame = sys._getframe(1)
1369 frame = sys._getframe(1)
1354 return eval(name, frame.f_globals, frame.f_locals)
1370 return eval(name, frame.f_globals, frame.f_locals)
1355
1371
1356 EvalString = EvalDict # for backwards compatibility
1372 EvalString = EvalDict # for backwards compatibility
1357 #----------------------------------------------------------------------------
1373 #----------------------------------------------------------------------------
1358 def qw(words,flat=0,sep=None,maxsplit=-1):
1374 def qw(words,flat=0,sep=None,maxsplit=-1):
1359 """Similar to Perl's qw() operator, but with some more options.
1375 """Similar to Perl's qw() operator, but with some more options.
1360
1376
1361 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1377 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1362
1378
1363 words can also be a list itself, and with flat=1, the output will be
1379 words can also be a list itself, and with flat=1, the output will be
1364 recursively flattened.
1380 recursively flattened.
1365
1381
1366 Examples:
1382 Examples:
1367
1383
1368 >>> qw('1 2')
1384 >>> qw('1 2')
1369 ['1', '2']
1385 ['1', '2']
1370
1386
1371 >>> qw(['a b','1 2',['m n','p q']])
1387 >>> qw(['a b','1 2',['m n','p q']])
1372 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1388 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1373
1389
1374 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1390 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1375 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
1391 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
1376 """
1392 """
1377
1393
1378 if type(words) in StringTypes:
1394 if type(words) in StringTypes:
1379 return [word.strip() for word in words.split(sep,maxsplit)
1395 return [word.strip() for word in words.split(sep,maxsplit)
1380 if word and not word.isspace() ]
1396 if word and not word.isspace() ]
1381 if flat:
1397 if flat:
1382 return flatten(map(qw,words,[1]*len(words)))
1398 return flatten(map(qw,words,[1]*len(words)))
1383 return map(qw,words)
1399 return map(qw,words)
1384
1400
1385 #----------------------------------------------------------------------------
1401 #----------------------------------------------------------------------------
1386 def qwflat(words,sep=None,maxsplit=-1):
1402 def qwflat(words,sep=None,maxsplit=-1):
1387 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1403 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1388 return qw(words,1,sep,maxsplit)
1404 return qw(words,1,sep,maxsplit)
1389
1405
1390 #----------------------------------------------------------------------------
1406 #----------------------------------------------------------------------------
1391 def qw_lol(indata):
1407 def qw_lol(indata):
1392 """qw_lol('a b') -> [['a','b']],
1408 """qw_lol('a b') -> [['a','b']],
1393 otherwise it's just a call to qw().
1409 otherwise it's just a call to qw().
1394
1410
1395 We need this to make sure the modules_some keys *always* end up as a
1411 We need this to make sure the modules_some keys *always* end up as a
1396 list of lists."""
1412 list of lists."""
1397
1413
1398 if type(indata) in StringTypes:
1414 if type(indata) in StringTypes:
1399 return [qw(indata)]
1415 return [qw(indata)]
1400 else:
1416 else:
1401 return qw(indata)
1417 return qw(indata)
1402
1418
1403 #-----------------------------------------------------------------------------
1419 #-----------------------------------------------------------------------------
1404 def list_strings(arg):
1420 def list_strings(arg):
1405 """Always return a list of strings, given a string or list of strings
1421 """Always return a list of strings, given a string or list of strings
1406 as input."""
1422 as input."""
1407
1423
1408 if type(arg) in StringTypes: return [arg]
1424 if type(arg) in StringTypes: return [arg]
1409 else: return arg
1425 else: return arg
1410
1426
1411 #----------------------------------------------------------------------------
1427 #----------------------------------------------------------------------------
1412 def grep(pat,list,case=1):
1428 def grep(pat,list,case=1):
1413 """Simple minded grep-like function.
1429 """Simple minded grep-like function.
1414 grep(pat,list) returns occurrences of pat in list, None on failure.
1430 grep(pat,list) returns occurrences of pat in list, None on failure.
1415
1431
1416 It only does simple string matching, with no support for regexps. Use the
1432 It only does simple string matching, with no support for regexps. Use the
1417 option case=0 for case-insensitive matching."""
1433 option case=0 for case-insensitive matching."""
1418
1434
1419 # This is pretty crude. At least it should implement copying only references
1435 # This is pretty crude. At least it should implement copying only references
1420 # to the original data in case it's big. Now it copies the data for output.
1436 # to the original data in case it's big. Now it copies the data for output.
1421 out=[]
1437 out=[]
1422 if case:
1438 if case:
1423 for term in list:
1439 for term in list:
1424 if term.find(pat)>-1: out.append(term)
1440 if term.find(pat)>-1: out.append(term)
1425 else:
1441 else:
1426 lpat=pat.lower()
1442 lpat=pat.lower()
1427 for term in list:
1443 for term in list:
1428 if term.lower().find(lpat)>-1: out.append(term)
1444 if term.lower().find(lpat)>-1: out.append(term)
1429
1445
1430 if len(out): return out
1446 if len(out): return out
1431 else: return None
1447 else: return None
1432
1448
1433 #----------------------------------------------------------------------------
1449 #----------------------------------------------------------------------------
1434 def dgrep(pat,*opts):
1450 def dgrep(pat,*opts):
1435 """Return grep() on dir()+dir(__builtins__).
1451 """Return grep() on dir()+dir(__builtins__).
1436
1452
1437 A very common use of grep() when working interactively."""
1453 A very common use of grep() when working interactively."""
1438
1454
1439 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1455 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1440
1456
1441 #----------------------------------------------------------------------------
1457 #----------------------------------------------------------------------------
1442 def idgrep(pat):
1458 def idgrep(pat):
1443 """Case-insensitive dgrep()"""
1459 """Case-insensitive dgrep()"""
1444
1460
1445 return dgrep(pat,0)
1461 return dgrep(pat,0)
1446
1462
1447 #----------------------------------------------------------------------------
1463 #----------------------------------------------------------------------------
1448 def igrep(pat,list):
1464 def igrep(pat,list):
1449 """Synonym for case-insensitive grep."""
1465 """Synonym for case-insensitive grep."""
1450
1466
1451 return grep(pat,list,case=0)
1467 return grep(pat,list,case=0)
1452
1468
1453 #----------------------------------------------------------------------------
1469 #----------------------------------------------------------------------------
1454 def indent(str,nspaces=4,ntabs=0):
1470 def indent(str,nspaces=4,ntabs=0):
1455 """Indent a string a given number of spaces or tabstops.
1471 """Indent a string a given number of spaces or tabstops.
1456
1472
1457 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1473 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1458 """
1474 """
1459 if str is None:
1475 if str is None:
1460 return
1476 return
1461 ind = '\t'*ntabs+' '*nspaces
1477 ind = '\t'*ntabs+' '*nspaces
1462 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1478 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1463 if outstr.endswith(os.linesep+ind):
1479 if outstr.endswith(os.linesep+ind):
1464 return outstr[:-len(ind)]
1480 return outstr[:-len(ind)]
1465 else:
1481 else:
1466 return outstr
1482 return outstr
1467
1483
1468 #-----------------------------------------------------------------------------
1484 #-----------------------------------------------------------------------------
1469 def native_line_ends(filename,backup=1):
1485 def native_line_ends(filename,backup=1):
1470 """Convert (in-place) a file to line-ends native to the current OS.
1486 """Convert (in-place) a file to line-ends native to the current OS.
1471
1487
1472 If the optional backup argument is given as false, no backup of the
1488 If the optional backup argument is given as false, no backup of the
1473 original file is left. """
1489 original file is left. """
1474
1490
1475 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1491 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1476
1492
1477 bak_filename = filename + backup_suffixes[os.name]
1493 bak_filename = filename + backup_suffixes[os.name]
1478
1494
1479 original = open(filename).read()
1495 original = open(filename).read()
1480 shutil.copy2(filename,bak_filename)
1496 shutil.copy2(filename,bak_filename)
1481 try:
1497 try:
1482 new = open(filename,'wb')
1498 new = open(filename,'wb')
1483 new.write(os.linesep.join(original.splitlines()))
1499 new.write(os.linesep.join(original.splitlines()))
1484 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1500 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1485 new.close()
1501 new.close()
1486 except:
1502 except:
1487 os.rename(bak_filename,filename)
1503 os.rename(bak_filename,filename)
1488 if not backup:
1504 if not backup:
1489 try:
1505 try:
1490 os.remove(bak_filename)
1506 os.remove(bak_filename)
1491 except:
1507 except:
1492 pass
1508 pass
1493
1509
1494 #----------------------------------------------------------------------------
1510 #----------------------------------------------------------------------------
1495 def get_pager_cmd(pager_cmd = None):
1511 def get_pager_cmd(pager_cmd = None):
1496 """Return a pager command.
1512 """Return a pager command.
1497
1513
1498 Makes some attempts at finding an OS-correct one."""
1514 Makes some attempts at finding an OS-correct one."""
1499
1515
1500 if os.name == 'posix':
1516 if os.name == 'posix':
1501 default_pager_cmd = 'less -r' # -r for color control sequences
1517 default_pager_cmd = 'less -r' # -r for color control sequences
1502 elif os.name in ['nt','dos']:
1518 elif os.name in ['nt','dos']:
1503 default_pager_cmd = 'type'
1519 default_pager_cmd = 'type'
1504
1520
1505 if pager_cmd is None:
1521 if pager_cmd is None:
1506 try:
1522 try:
1507 pager_cmd = os.environ['PAGER']
1523 pager_cmd = os.environ['PAGER']
1508 except:
1524 except:
1509 pager_cmd = default_pager_cmd
1525 pager_cmd = default_pager_cmd
1510 return pager_cmd
1526 return pager_cmd
1511
1527
1512 #-----------------------------------------------------------------------------
1528 #-----------------------------------------------------------------------------
1513 def get_pager_start(pager,start):
1529 def get_pager_start(pager,start):
1514 """Return the string for paging files with an offset.
1530 """Return the string for paging files with an offset.
1515
1531
1516 This is the '+N' argument which less and more (under Unix) accept.
1532 This is the '+N' argument which less and more (under Unix) accept.
1517 """
1533 """
1518
1534
1519 if pager in ['less','more']:
1535 if pager in ['less','more']:
1520 if start:
1536 if start:
1521 start_string = '+' + str(start)
1537 start_string = '+' + str(start)
1522 else:
1538 else:
1523 start_string = ''
1539 start_string = ''
1524 else:
1540 else:
1525 start_string = ''
1541 start_string = ''
1526 return start_string
1542 return start_string
1527
1543
1528 #----------------------------------------------------------------------------
1544 #----------------------------------------------------------------------------
1529 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
1545 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
1530 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
1546 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
1531 import msvcrt
1547 import msvcrt
1532 def page_more():
1548 def page_more():
1533 """ Smart pausing between pages
1549 """ Smart pausing between pages
1534
1550
1535 @return: True if need print more lines, False if quit
1551 @return: True if need print more lines, False if quit
1536 """
1552 """
1537 Term.cout.write('---Return to continue, q to quit--- ')
1553 Term.cout.write('---Return to continue, q to quit--- ')
1538 ans = msvcrt.getch()
1554 ans = msvcrt.getch()
1539 if ans in ("q", "Q"):
1555 if ans in ("q", "Q"):
1540 result = False
1556 result = False
1541 else:
1557 else:
1542 result = True
1558 result = True
1543 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
1559 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
1544 return result
1560 return result
1545 else:
1561 else:
1546 def page_more():
1562 def page_more():
1547 ans = raw_input('---Return to continue, q to quit--- ')
1563 ans = raw_input('---Return to continue, q to quit--- ')
1548 if ans.lower().startswith('q'):
1564 if ans.lower().startswith('q'):
1549 return False
1565 return False
1550 else:
1566 else:
1551 return True
1567 return True
1552
1568
1553 esc_re = re.compile(r"(\x1b[^m]+m)")
1569 esc_re = re.compile(r"(\x1b[^m]+m)")
1554
1570
1555 def page_dumb(strng,start=0,screen_lines=25):
1571 def page_dumb(strng,start=0,screen_lines=25):
1556 """Very dumb 'pager' in Python, for when nothing else works.
1572 """Very dumb 'pager' in Python, for when nothing else works.
1557
1573
1558 Only moves forward, same interface as page(), except for pager_cmd and
1574 Only moves forward, same interface as page(), except for pager_cmd and
1559 mode."""
1575 mode."""
1560
1576
1561 out_ln = strng.splitlines()[start:]
1577 out_ln = strng.splitlines()[start:]
1562 screens = chop(out_ln,screen_lines-1)
1578 screens = chop(out_ln,screen_lines-1)
1563 if len(screens) == 1:
1579 if len(screens) == 1:
1564 print >>Term.cout, os.linesep.join(screens[0])
1580 print >>Term.cout, os.linesep.join(screens[0])
1565 else:
1581 else:
1566 last_escape = ""
1582 last_escape = ""
1567 for scr in screens[0:-1]:
1583 for scr in screens[0:-1]:
1568 hunk = os.linesep.join(scr)
1584 hunk = os.linesep.join(scr)
1569 print >>Term.cout, last_escape + hunk
1585 print >>Term.cout, last_escape + hunk
1570 if not page_more():
1586 if not page_more():
1571 return
1587 return
1572 esc_list = esc_re.findall(hunk)
1588 esc_list = esc_re.findall(hunk)
1573 if len(esc_list) > 0:
1589 if len(esc_list) > 0:
1574 last_escape = esc_list[-1]
1590 last_escape = esc_list[-1]
1575 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
1591 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
1576
1592
1577 #----------------------------------------------------------------------------
1593 #----------------------------------------------------------------------------
1578 def page(strng,start=0,screen_lines=0,pager_cmd = None):
1594 def page(strng,start=0,screen_lines=0,pager_cmd = None):
1579 """Print a string, piping through a pager after a certain length.
1595 """Print a string, piping through a pager after a certain length.
1580
1596
1581 The screen_lines parameter specifies the number of *usable* lines of your
1597 The screen_lines parameter specifies the number of *usable* lines of your
1582 terminal screen (total lines minus lines you need to reserve to show other
1598 terminal screen (total lines minus lines you need to reserve to show other
1583 information).
1599 information).
1584
1600
1585 If you set screen_lines to a number <=0, page() will try to auto-determine
1601 If you set screen_lines to a number <=0, page() will try to auto-determine
1586 your screen size and will only use up to (screen_size+screen_lines) for
1602 your screen size and will only use up to (screen_size+screen_lines) for
1587 printing, paging after that. That is, if you want auto-detection but need
1603 printing, paging after that. That is, if you want auto-detection but need
1588 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
1604 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
1589 auto-detection without any lines reserved simply use screen_lines = 0.
1605 auto-detection without any lines reserved simply use screen_lines = 0.
1590
1606
1591 If a string won't fit in the allowed lines, it is sent through the
1607 If a string won't fit in the allowed lines, it is sent through the
1592 specified pager command. If none given, look for PAGER in the environment,
1608 specified pager command. If none given, look for PAGER in the environment,
1593 and ultimately default to less.
1609 and ultimately default to less.
1594
1610
1595 If no system pager works, the string is sent through a 'dumb pager'
1611 If no system pager works, the string is sent through a 'dumb pager'
1596 written in python, very simplistic.
1612 written in python, very simplistic.
1597 """
1613 """
1598
1614
1599 # Some routines may auto-compute start offsets incorrectly and pass a
1615 # Some routines may auto-compute start offsets incorrectly and pass a
1600 # negative value. Offset to 0 for robustness.
1616 # negative value. Offset to 0 for robustness.
1601 start = max(0,start)
1617 start = max(0,start)
1602
1618
1603 # first, try the hook
1619 # first, try the hook
1604 ip = IPython.ipapi.get()
1620 ip = IPython.ipapi.get()
1605 if ip:
1621 if ip:
1606 try:
1622 try:
1607 ip.IP.hooks.show_in_pager(strng)
1623 ip.IP.hooks.show_in_pager(strng)
1608 return
1624 return
1609 except IPython.ipapi.TryNext:
1625 except IPython.ipapi.TryNext:
1610 pass
1626 pass
1611
1627
1612 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
1628 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
1613 TERM = os.environ.get('TERM','dumb')
1629 TERM = os.environ.get('TERM','dumb')
1614 if TERM in ['dumb','emacs'] and os.name != 'nt':
1630 if TERM in ['dumb','emacs'] and os.name != 'nt':
1615 print strng
1631 print strng
1616 return
1632 return
1617 # chop off the topmost part of the string we don't want to see
1633 # chop off the topmost part of the string we don't want to see
1618 str_lines = strng.split(os.linesep)[start:]
1634 str_lines = strng.split(os.linesep)[start:]
1619 str_toprint = os.linesep.join(str_lines)
1635 str_toprint = os.linesep.join(str_lines)
1620 num_newlines = len(str_lines)
1636 num_newlines = len(str_lines)
1621 len_str = len(str_toprint)
1637 len_str = len(str_toprint)
1622
1638
1623 # Dumb heuristics to guesstimate number of on-screen lines the string
1639 # Dumb heuristics to guesstimate number of on-screen lines the string
1624 # takes. Very basic, but good enough for docstrings in reasonable
1640 # takes. Very basic, but good enough for docstrings in reasonable
1625 # terminals. If someone later feels like refining it, it's not hard.
1641 # terminals. If someone later feels like refining it, it's not hard.
1626 numlines = max(num_newlines,int(len_str/80)+1)
1642 numlines = max(num_newlines,int(len_str/80)+1)
1627
1643
1628 if os.name == "nt":
1644 if os.name == "nt":
1629 screen_lines_def = get_console_size(defaulty=25)[1]
1645 screen_lines_def = get_console_size(defaulty=25)[1]
1630 else:
1646 else:
1631 screen_lines_def = 25 # default value if we can't auto-determine
1647 screen_lines_def = 25 # default value if we can't auto-determine
1632
1648
1633 # auto-determine screen size
1649 # auto-determine screen size
1634 if screen_lines <= 0:
1650 if screen_lines <= 0:
1635 if TERM=='xterm':
1651 if TERM=='xterm':
1636 use_curses = USE_CURSES
1652 use_curses = USE_CURSES
1637 else:
1653 else:
1638 # curses causes problems on many terminals other than xterm.
1654 # curses causes problems on many terminals other than xterm.
1639 use_curses = False
1655 use_curses = False
1640 if use_curses:
1656 if use_curses:
1641 # There is a bug in curses, where *sometimes* it fails to properly
1657 # There is a bug in curses, where *sometimes* it fails to properly
1642 # initialize, and then after the endwin() call is made, the
1658 # initialize, and then after the endwin() call is made, the
1643 # terminal is left in an unusable state. Rather than trying to
1659 # terminal is left in an unusable state. Rather than trying to
1644 # check everytime for this (by requesting and comparing termios
1660 # check everytime for this (by requesting and comparing termios
1645 # flags each time), we just save the initial terminal state and
1661 # flags each time), we just save the initial terminal state and
1646 # unconditionally reset it every time. It's cheaper than making
1662 # unconditionally reset it every time. It's cheaper than making
1647 # the checks.
1663 # the checks.
1648 term_flags = termios.tcgetattr(sys.stdout)
1664 term_flags = termios.tcgetattr(sys.stdout)
1649 scr = curses.initscr()
1665 scr = curses.initscr()
1650 screen_lines_real,screen_cols = scr.getmaxyx()
1666 screen_lines_real,screen_cols = scr.getmaxyx()
1651 curses.endwin()
1667 curses.endwin()
1652 # Restore terminal state in case endwin() didn't.
1668 # Restore terminal state in case endwin() didn't.
1653 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
1669 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
1654 # Now we have what we needed: the screen size in rows/columns
1670 # Now we have what we needed: the screen size in rows/columns
1655 screen_lines += screen_lines_real
1671 screen_lines += screen_lines_real
1656 #print '***Screen size:',screen_lines_real,'lines x',\
1672 #print '***Screen size:',screen_lines_real,'lines x',\
1657 #screen_cols,'columns.' # dbg
1673 #screen_cols,'columns.' # dbg
1658 else:
1674 else:
1659 screen_lines += screen_lines_def
1675 screen_lines += screen_lines_def
1660
1676
1661 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1677 #print 'numlines',numlines,'screenlines',screen_lines # dbg
1662 if numlines <= screen_lines :
1678 if numlines <= screen_lines :
1663 #print '*** normal print' # dbg
1679 #print '*** normal print' # dbg
1664 print >>Term.cout, str_toprint
1680 print >>Term.cout, str_toprint
1665 else:
1681 else:
1666 # Try to open pager and default to internal one if that fails.
1682 # Try to open pager and default to internal one if that fails.
1667 # All failure modes are tagged as 'retval=1', to match the return
1683 # All failure modes are tagged as 'retval=1', to match the return
1668 # value of a failed system command. If any intermediate attempt
1684 # value of a failed system command. If any intermediate attempt
1669 # sets retval to 1, at the end we resort to our own page_dumb() pager.
1685 # sets retval to 1, at the end we resort to our own page_dumb() pager.
1670 pager_cmd = get_pager_cmd(pager_cmd)
1686 pager_cmd = get_pager_cmd(pager_cmd)
1671 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1687 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1672 if os.name == 'nt':
1688 if os.name == 'nt':
1673 if pager_cmd.startswith('type'):
1689 if pager_cmd.startswith('type'):
1674 # The default WinXP 'type' command is failing on complex strings.
1690 # The default WinXP 'type' command is failing on complex strings.
1675 retval = 1
1691 retval = 1
1676 else:
1692 else:
1677 tmpname = tempfile.mktemp('.txt')
1693 tmpname = tempfile.mktemp('.txt')
1678 tmpfile = file(tmpname,'wt')
1694 tmpfile = file(tmpname,'wt')
1679 tmpfile.write(strng)
1695 tmpfile.write(strng)
1680 tmpfile.close()
1696 tmpfile.close()
1681 cmd = "%s < %s" % (pager_cmd,tmpname)
1697 cmd = "%s < %s" % (pager_cmd,tmpname)
1682 if os.system(cmd):
1698 if os.system(cmd):
1683 retval = 1
1699 retval = 1
1684 else:
1700 else:
1685 retval = None
1701 retval = None
1686 os.remove(tmpname)
1702 os.remove(tmpname)
1687 else:
1703 else:
1688 try:
1704 try:
1689 retval = None
1705 retval = None
1690 # if I use popen4, things hang. No idea why.
1706 # if I use popen4, things hang. No idea why.
1691 #pager,shell_out = os.popen4(pager_cmd)
1707 #pager,shell_out = os.popen4(pager_cmd)
1692 pager = os.popen(pager_cmd,'w')
1708 pager = os.popen(pager_cmd,'w')
1693 pager.write(strng)
1709 pager.write(strng)
1694 pager.close()
1710 pager.close()
1695 retval = pager.close() # success returns None
1711 retval = pager.close() # success returns None
1696 except IOError,msg: # broken pipe when user quits
1712 except IOError,msg: # broken pipe when user quits
1697 if msg.args == (32,'Broken pipe'):
1713 if msg.args == (32,'Broken pipe'):
1698 retval = None
1714 retval = None
1699 else:
1715 else:
1700 retval = 1
1716 retval = 1
1701 except OSError:
1717 except OSError:
1702 # Other strange problems, sometimes seen in Win2k/cygwin
1718 # Other strange problems, sometimes seen in Win2k/cygwin
1703 retval = 1
1719 retval = 1
1704 if retval is not None:
1720 if retval is not None:
1705 page_dumb(strng,screen_lines=screen_lines)
1721 page_dumb(strng,screen_lines=screen_lines)
1706
1722
1707 #----------------------------------------------------------------------------
1723 #----------------------------------------------------------------------------
1708 def page_file(fname,start = 0, pager_cmd = None):
1724 def page_file(fname,start = 0, pager_cmd = None):
1709 """Page a file, using an optional pager command and starting line.
1725 """Page a file, using an optional pager command and starting line.
1710 """
1726 """
1711
1727
1712 pager_cmd = get_pager_cmd(pager_cmd)
1728 pager_cmd = get_pager_cmd(pager_cmd)
1713 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1729 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
1714
1730
1715 try:
1731 try:
1716 if os.environ['TERM'] in ['emacs','dumb']:
1732 if os.environ['TERM'] in ['emacs','dumb']:
1717 raise EnvironmentError
1733 raise EnvironmentError
1718 xsys(pager_cmd + ' ' + fname)
1734 xsys(pager_cmd + ' ' + fname)
1719 except:
1735 except:
1720 try:
1736 try:
1721 if start > 0:
1737 if start > 0:
1722 start -= 1
1738 start -= 1
1723 page(open(fname).read(),start)
1739 page(open(fname).read(),start)
1724 except:
1740 except:
1725 print 'Unable to show file',`fname`
1741 print 'Unable to show file',`fname`
1726
1742
1727
1743
1728 #----------------------------------------------------------------------------
1744 #----------------------------------------------------------------------------
1729 def snip_print(str,width = 75,print_full = 0,header = ''):
1745 def snip_print(str,width = 75,print_full = 0,header = ''):
1730 """Print a string snipping the midsection to fit in width.
1746 """Print a string snipping the midsection to fit in width.
1731
1747
1732 print_full: mode control:
1748 print_full: mode control:
1733 - 0: only snip long strings
1749 - 0: only snip long strings
1734 - 1: send to page() directly.
1750 - 1: send to page() directly.
1735 - 2: snip long strings and ask for full length viewing with page()
1751 - 2: snip long strings and ask for full length viewing with page()
1736 Return 1 if snipping was necessary, 0 otherwise."""
1752 Return 1 if snipping was necessary, 0 otherwise."""
1737
1753
1738 if print_full == 1:
1754 if print_full == 1:
1739 page(header+str)
1755 page(header+str)
1740 return 0
1756 return 0
1741
1757
1742 print header,
1758 print header,
1743 if len(str) < width:
1759 if len(str) < width:
1744 print str
1760 print str
1745 snip = 0
1761 snip = 0
1746 else:
1762 else:
1747 whalf = int((width -5)/2)
1763 whalf = int((width -5)/2)
1748 print str[:whalf] + ' <...> ' + str[-whalf:]
1764 print str[:whalf] + ' <...> ' + str[-whalf:]
1749 snip = 1
1765 snip = 1
1750 if snip and print_full == 2:
1766 if snip and print_full == 2:
1751 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
1767 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
1752 page(str)
1768 page(str)
1753 return snip
1769 return snip
1754
1770
1755 #****************************************************************************
1771 #****************************************************************************
1756 # lists, dicts and structures
1772 # lists, dicts and structures
1757
1773
1758 def belong(candidates,checklist):
1774 def belong(candidates,checklist):
1759 """Check whether a list of items appear in a given list of options.
1775 """Check whether a list of items appear in a given list of options.
1760
1776
1761 Returns a list of 1 and 0, one for each candidate given."""
1777 Returns a list of 1 and 0, one for each candidate given."""
1762
1778
1763 return [x in checklist for x in candidates]
1779 return [x in checklist for x in candidates]
1764
1780
1765 #----------------------------------------------------------------------------
1781 #----------------------------------------------------------------------------
1766 def uniq_stable(elems):
1782 def uniq_stable(elems):
1767 """uniq_stable(elems) -> list
1783 """uniq_stable(elems) -> list
1768
1784
1769 Return from an iterable, a list of all the unique elements in the input,
1785 Return from an iterable, a list of all the unique elements in the input,
1770 but maintaining the order in which they first appear.
1786 but maintaining the order in which they first appear.
1771
1787
1772 A naive solution to this problem which just makes a dictionary with the
1788 A naive solution to this problem which just makes a dictionary with the
1773 elements as keys fails to respect the stability condition, since
1789 elements as keys fails to respect the stability condition, since
1774 dictionaries are unsorted by nature.
1790 dictionaries are unsorted by nature.
1775
1791
1776 Note: All elements in the input must be valid dictionary keys for this
1792 Note: All elements in the input must be valid dictionary keys for this
1777 routine to work, as it internally uses a dictionary for efficiency
1793 routine to work, as it internally uses a dictionary for efficiency
1778 reasons."""
1794 reasons."""
1779
1795
1780 unique = []
1796 unique = []
1781 unique_dict = {}
1797 unique_dict = {}
1782 for nn in elems:
1798 for nn in elems:
1783 if nn not in unique_dict:
1799 if nn not in unique_dict:
1784 unique.append(nn)
1800 unique.append(nn)
1785 unique_dict[nn] = None
1801 unique_dict[nn] = None
1786 return unique
1802 return unique
1787
1803
1788 #----------------------------------------------------------------------------
1804 #----------------------------------------------------------------------------
1789 class NLprinter:
1805 class NLprinter:
1790 """Print an arbitrarily nested list, indicating index numbers.
1806 """Print an arbitrarily nested list, indicating index numbers.
1791
1807
1792 An instance of this class called nlprint is available and callable as a
1808 An instance of this class called nlprint is available and callable as a
1793 function.
1809 function.
1794
1810
1795 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1811 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1796 and using 'sep' to separate the index from the value. """
1812 and using 'sep' to separate the index from the value. """
1797
1813
1798 def __init__(self):
1814 def __init__(self):
1799 self.depth = 0
1815 self.depth = 0
1800
1816
1801 def __call__(self,lst,pos='',**kw):
1817 def __call__(self,lst,pos='',**kw):
1802 """Prints the nested list numbering levels."""
1818 """Prints the nested list numbering levels."""
1803 kw.setdefault('indent',' ')
1819 kw.setdefault('indent',' ')
1804 kw.setdefault('sep',': ')
1820 kw.setdefault('sep',': ')
1805 kw.setdefault('start',0)
1821 kw.setdefault('start',0)
1806 kw.setdefault('stop',len(lst))
1822 kw.setdefault('stop',len(lst))
1807 # we need to remove start and stop from kw so they don't propagate
1823 # we need to remove start and stop from kw so they don't propagate
1808 # into a recursive call for a nested list.
1824 # into a recursive call for a nested list.
1809 start = kw['start']; del kw['start']
1825 start = kw['start']; del kw['start']
1810 stop = kw['stop']; del kw['stop']
1826 stop = kw['stop']; del kw['stop']
1811 if self.depth == 0 and 'header' in kw.keys():
1827 if self.depth == 0 and 'header' in kw.keys():
1812 print kw['header']
1828 print kw['header']
1813
1829
1814 for idx in range(start,stop):
1830 for idx in range(start,stop):
1815 elem = lst[idx]
1831 elem = lst[idx]
1816 if type(elem)==type([]):
1832 if type(elem)==type([]):
1817 self.depth += 1
1833 self.depth += 1
1818 self.__call__(elem,itpl('$pos$idx,'),**kw)
1834 self.__call__(elem,itpl('$pos$idx,'),**kw)
1819 self.depth -= 1
1835 self.depth -= 1
1820 else:
1836 else:
1821 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1837 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1822
1838
1823 nlprint = NLprinter()
1839 nlprint = NLprinter()
1824 #----------------------------------------------------------------------------
1840 #----------------------------------------------------------------------------
1825 def all_belong(candidates,checklist):
1841 def all_belong(candidates,checklist):
1826 """Check whether a list of items ALL appear in a given list of options.
1842 """Check whether a list of items ALL appear in a given list of options.
1827
1843
1828 Returns a single 1 or 0 value."""
1844 Returns a single 1 or 0 value."""
1829
1845
1830 return 1-(0 in [x in checklist for x in candidates])
1846 return 1-(0 in [x in checklist for x in candidates])
1831
1847
1832 #----------------------------------------------------------------------------
1848 #----------------------------------------------------------------------------
1833 def sort_compare(lst1,lst2,inplace = 1):
1849 def sort_compare(lst1,lst2,inplace = 1):
1834 """Sort and compare two lists.
1850 """Sort and compare two lists.
1835
1851
1836 By default it does it in place, thus modifying the lists. Use inplace = 0
1852 By default it does it in place, thus modifying the lists. Use inplace = 0
1837 to avoid that (at the cost of temporary copy creation)."""
1853 to avoid that (at the cost of temporary copy creation)."""
1838 if not inplace:
1854 if not inplace:
1839 lst1 = lst1[:]
1855 lst1 = lst1[:]
1840 lst2 = lst2[:]
1856 lst2 = lst2[:]
1841 lst1.sort(); lst2.sort()
1857 lst1.sort(); lst2.sort()
1842 return lst1 == lst2
1858 return lst1 == lst2
1843
1859
1844 #----------------------------------------------------------------------------
1860 #----------------------------------------------------------------------------
1845 def list2dict(lst):
1861 def list2dict(lst):
1846 """Takes a list of (key,value) pairs and turns it into a dict."""
1862 """Takes a list of (key,value) pairs and turns it into a dict."""
1847
1863
1848 dic = {}
1864 dic = {}
1849 for k,v in lst: dic[k] = v
1865 for k,v in lst: dic[k] = v
1850 return dic
1866 return dic
1851
1867
1852 #----------------------------------------------------------------------------
1868 #----------------------------------------------------------------------------
1853 def list2dict2(lst,default=''):
1869 def list2dict2(lst,default=''):
1854 """Takes a list and turns it into a dict.
1870 """Takes a list and turns it into a dict.
1855 Much slower than list2dict, but more versatile. This version can take
1871 Much slower than list2dict, but more versatile. This version can take
1856 lists with sublists of arbitrary length (including sclars)."""
1872 lists with sublists of arbitrary length (including sclars)."""
1857
1873
1858 dic = {}
1874 dic = {}
1859 for elem in lst:
1875 for elem in lst:
1860 if type(elem) in (types.ListType,types.TupleType):
1876 if type(elem) in (types.ListType,types.TupleType):
1861 size = len(elem)
1877 size = len(elem)
1862 if size == 0:
1878 if size == 0:
1863 pass
1879 pass
1864 elif size == 1:
1880 elif size == 1:
1865 dic[elem] = default
1881 dic[elem] = default
1866 else:
1882 else:
1867 k,v = elem[0], elem[1:]
1883 k,v = elem[0], elem[1:]
1868 if len(v) == 1: v = v[0]
1884 if len(v) == 1: v = v[0]
1869 dic[k] = v
1885 dic[k] = v
1870 else:
1886 else:
1871 dic[elem] = default
1887 dic[elem] = default
1872 return dic
1888 return dic
1873
1889
1874 #----------------------------------------------------------------------------
1890 #----------------------------------------------------------------------------
1875 def flatten(seq):
1891 def flatten(seq):
1876 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1892 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1877
1893
1878 return [x for subseq in seq for x in subseq]
1894 return [x for subseq in seq for x in subseq]
1879
1895
1880 #----------------------------------------------------------------------------
1896 #----------------------------------------------------------------------------
1881 def get_slice(seq,start=0,stop=None,step=1):
1897 def get_slice(seq,start=0,stop=None,step=1):
1882 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1898 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1883 if stop == None:
1899 if stop == None:
1884 stop = len(seq)
1900 stop = len(seq)
1885 item = lambda i: seq[i]
1901 item = lambda i: seq[i]
1886 return map(item,xrange(start,stop,step))
1902 return map(item,xrange(start,stop,step))
1887
1903
1888 #----------------------------------------------------------------------------
1904 #----------------------------------------------------------------------------
1889 def chop(seq,size):
1905 def chop(seq,size):
1890 """Chop a sequence into chunks of the given size."""
1906 """Chop a sequence into chunks of the given size."""
1891 chunk = lambda i: seq[i:i+size]
1907 chunk = lambda i: seq[i:i+size]
1892 return map(chunk,xrange(0,len(seq),size))
1908 return map(chunk,xrange(0,len(seq),size))
1893
1909
1894 #----------------------------------------------------------------------------
1910 #----------------------------------------------------------------------------
1895 # with is a keyword as of python 2.5, so this function is renamed to withobj
1911 # with is a keyword as of python 2.5, so this function is renamed to withobj
1896 # from its old 'with' name.
1912 # from its old 'with' name.
1897 def with_obj(object, **args):
1913 def with_obj(object, **args):
1898 """Set multiple attributes for an object, similar to Pascal's with.
1914 """Set multiple attributes for an object, similar to Pascal's with.
1899
1915
1900 Example:
1916 Example:
1901 with_obj(jim,
1917 with_obj(jim,
1902 born = 1960,
1918 born = 1960,
1903 haircolour = 'Brown',
1919 haircolour = 'Brown',
1904 eyecolour = 'Green')
1920 eyecolour = 'Green')
1905
1921
1906 Credit: Greg Ewing, in
1922 Credit: Greg Ewing, in
1907 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1923 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1908
1924
1909 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1925 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1910 has become a keyword for Python 2.5, so we had to rename it."""
1926 has become a keyword for Python 2.5, so we had to rename it."""
1911
1927
1912 object.__dict__.update(args)
1928 object.__dict__.update(args)
1913
1929
1914 #----------------------------------------------------------------------------
1930 #----------------------------------------------------------------------------
1915 def setattr_list(obj,alist,nspace = None):
1931 def setattr_list(obj,alist,nspace = None):
1916 """Set a list of attributes for an object taken from a namespace.
1932 """Set a list of attributes for an object taken from a namespace.
1917
1933
1918 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1934 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1919 alist with their values taken from nspace, which must be a dict (something
1935 alist with their values taken from nspace, which must be a dict (something
1920 like locals() will often do) If nspace isn't given, locals() of the
1936 like locals() will often do) If nspace isn't given, locals() of the
1921 *caller* is used, so in most cases you can omit it.
1937 *caller* is used, so in most cases you can omit it.
1922
1938
1923 Note that alist can be given as a string, which will be automatically
1939 Note that alist can be given as a string, which will be automatically
1924 split into a list on whitespace. If given as a list, it must be a list of
1940 split into a list on whitespace. If given as a list, it must be a list of
1925 *strings* (the variable names themselves), not of variables."""
1941 *strings* (the variable names themselves), not of variables."""
1926
1942
1927 # this grabs the local variables from the *previous* call frame -- that is
1943 # this grabs the local variables from the *previous* call frame -- that is
1928 # the locals from the function that called setattr_list().
1944 # the locals from the function that called setattr_list().
1929 # - snipped from weave.inline()
1945 # - snipped from weave.inline()
1930 if nspace is None:
1946 if nspace is None:
1931 call_frame = sys._getframe().f_back
1947 call_frame = sys._getframe().f_back
1932 nspace = call_frame.f_locals
1948 nspace = call_frame.f_locals
1933
1949
1934 if type(alist) in StringTypes:
1950 if type(alist) in StringTypes:
1935 alist = alist.split()
1951 alist = alist.split()
1936 for attr in alist:
1952 for attr in alist:
1937 val = eval(attr,nspace)
1953 val = eval(attr,nspace)
1938 setattr(obj,attr,val)
1954 setattr(obj,attr,val)
1939
1955
1940 #----------------------------------------------------------------------------
1956 #----------------------------------------------------------------------------
1941 def getattr_list(obj,alist,*args):
1957 def getattr_list(obj,alist,*args):
1942 """getattr_list(obj,alist[, default]) -> attribute list.
1958 """getattr_list(obj,alist[, default]) -> attribute list.
1943
1959
1944 Get a list of named attributes for an object. When a default argument is
1960 Get a list of named attributes for an object. When a default argument is
1945 given, it is returned when the attribute doesn't exist; without it, an
1961 given, it is returned when the attribute doesn't exist; without it, an
1946 exception is raised in that case.
1962 exception is raised in that case.
1947
1963
1948 Note that alist can be given as a string, which will be automatically
1964 Note that alist can be given as a string, which will be automatically
1949 split into a list on whitespace. If given as a list, it must be a list of
1965 split into a list on whitespace. If given as a list, it must be a list of
1950 *strings* (the variable names themselves), not of variables."""
1966 *strings* (the variable names themselves), not of variables."""
1951
1967
1952 if type(alist) in StringTypes:
1968 if type(alist) in StringTypes:
1953 alist = alist.split()
1969 alist = alist.split()
1954 if args:
1970 if args:
1955 if len(args)==1:
1971 if len(args)==1:
1956 default = args[0]
1972 default = args[0]
1957 return map(lambda attr: getattr(obj,attr,default),alist)
1973 return map(lambda attr: getattr(obj,attr,default),alist)
1958 else:
1974 else:
1959 raise ValueError,'getattr_list() takes only one optional argument'
1975 raise ValueError,'getattr_list() takes only one optional argument'
1960 else:
1976 else:
1961 return map(lambda attr: getattr(obj,attr),alist)
1977 return map(lambda attr: getattr(obj,attr),alist)
1962
1978
1963 #----------------------------------------------------------------------------
1979 #----------------------------------------------------------------------------
1964 def map_method(method,object_list,*argseq,**kw):
1980 def map_method(method,object_list,*argseq,**kw):
1965 """map_method(method,object_list,*args,**kw) -> list
1981 """map_method(method,object_list,*args,**kw) -> list
1966
1982
1967 Return a list of the results of applying the methods to the items of the
1983 Return a list of the results of applying the methods to the items of the
1968 argument sequence(s). If more than one sequence is given, the method is
1984 argument sequence(s). If more than one sequence is given, the method is
1969 called with an argument list consisting of the corresponding item of each
1985 called with an argument list consisting of the corresponding item of each
1970 sequence. All sequences must be of the same length.
1986 sequence. All sequences must be of the same length.
1971
1987
1972 Keyword arguments are passed verbatim to all objects called.
1988 Keyword arguments are passed verbatim to all objects called.
1973
1989
1974 This is Python code, so it's not nearly as fast as the builtin map()."""
1990 This is Python code, so it's not nearly as fast as the builtin map()."""
1975
1991
1976 out_list = []
1992 out_list = []
1977 idx = 0
1993 idx = 0
1978 for object in object_list:
1994 for object in object_list:
1979 try:
1995 try:
1980 handler = getattr(object, method)
1996 handler = getattr(object, method)
1981 except AttributeError:
1997 except AttributeError:
1982 out_list.append(None)
1998 out_list.append(None)
1983 else:
1999 else:
1984 if argseq:
2000 if argseq:
1985 args = map(lambda lst:lst[idx],argseq)
2001 args = map(lambda lst:lst[idx],argseq)
1986 #print 'ob',object,'hand',handler,'ar',args # dbg
2002 #print 'ob',object,'hand',handler,'ar',args # dbg
1987 out_list.append(handler(args,**kw))
2003 out_list.append(handler(args,**kw))
1988 else:
2004 else:
1989 out_list.append(handler(**kw))
2005 out_list.append(handler(**kw))
1990 idx += 1
2006 idx += 1
1991 return out_list
2007 return out_list
1992
2008
1993 #----------------------------------------------------------------------------
2009 #----------------------------------------------------------------------------
1994 def get_class_members(cls):
2010 def get_class_members(cls):
1995 ret = dir(cls)
2011 ret = dir(cls)
1996 if hasattr(cls,'__bases__'):
2012 if hasattr(cls,'__bases__'):
1997 for base in cls.__bases__:
2013 for base in cls.__bases__:
1998 ret.extend(get_class_members(base))
2014 ret.extend(get_class_members(base))
1999 return ret
2015 return ret
2000
2016
2001 #----------------------------------------------------------------------------
2017 #----------------------------------------------------------------------------
2002 def dir2(obj):
2018 def dir2(obj):
2003 """dir2(obj) -> list of strings
2019 """dir2(obj) -> list of strings
2004
2020
2005 Extended version of the Python builtin dir(), which does a few extra
2021 Extended version of the Python builtin dir(), which does a few extra
2006 checks, and supports common objects with unusual internals that confuse
2022 checks, and supports common objects with unusual internals that confuse
2007 dir(), such as Traits and PyCrust.
2023 dir(), such as Traits and PyCrust.
2008
2024
2009 This version is guaranteed to return only a list of true strings, whereas
2025 This version is guaranteed to return only a list of true strings, whereas
2010 dir() returns anything that objects inject into themselves, even if they
2026 dir() returns anything that objects inject into themselves, even if they
2011 are later not really valid for attribute access (many extension libraries
2027 are later not really valid for attribute access (many extension libraries
2012 have such bugs).
2028 have such bugs).
2013 """
2029 """
2014
2030
2015 # Start building the attribute list via dir(), and then complete it
2031 # Start building the attribute list via dir(), and then complete it
2016 # with a few extra special-purpose calls.
2032 # with a few extra special-purpose calls.
2017 words = dir(obj)
2033 words = dir(obj)
2018
2034
2019 if hasattr(obj,'__class__'):
2035 if hasattr(obj,'__class__'):
2020 words.append('__class__')
2036 words.append('__class__')
2021 words.extend(get_class_members(obj.__class__))
2037 words.extend(get_class_members(obj.__class__))
2022 #if '__base__' in words: 1/0
2038 #if '__base__' in words: 1/0
2023
2039
2024 # Some libraries (such as traits) may introduce duplicates, we want to
2040 # Some libraries (such as traits) may introduce duplicates, we want to
2025 # track and clean this up if it happens
2041 # track and clean this up if it happens
2026 may_have_dupes = False
2042 may_have_dupes = False
2027
2043
2028 # this is the 'dir' function for objects with Enthought's traits
2044 # this is the 'dir' function for objects with Enthought's traits
2029 if hasattr(obj, 'trait_names'):
2045 if hasattr(obj, 'trait_names'):
2030 try:
2046 try:
2031 words.extend(obj.trait_names())
2047 words.extend(obj.trait_names())
2032 may_have_dupes = True
2048 may_have_dupes = True
2033 except TypeError:
2049 except TypeError:
2034 # This will happen if `obj` is a class and not an instance.
2050 # This will happen if `obj` is a class and not an instance.
2035 pass
2051 pass
2036
2052
2037 # Support for PyCrust-style _getAttributeNames magic method.
2053 # Support for PyCrust-style _getAttributeNames magic method.
2038 if hasattr(obj, '_getAttributeNames'):
2054 if hasattr(obj, '_getAttributeNames'):
2039 try:
2055 try:
2040 words.extend(obj._getAttributeNames())
2056 words.extend(obj._getAttributeNames())
2041 may_have_dupes = True
2057 may_have_dupes = True
2042 except TypeError:
2058 except TypeError:
2043 # `obj` is a class and not an instance. Ignore
2059 # `obj` is a class and not an instance. Ignore
2044 # this error.
2060 # this error.
2045 pass
2061 pass
2046
2062
2047 if may_have_dupes:
2063 if may_have_dupes:
2048 # eliminate possible duplicates, as some traits may also
2064 # eliminate possible duplicates, as some traits may also
2049 # appear as normal attributes in the dir() call.
2065 # appear as normal attributes in the dir() call.
2050 words = list(set(words))
2066 words = list(set(words))
2051 words.sort()
2067 words.sort()
2052
2068
2053 # filter out non-string attributes which may be stuffed by dir() calls
2069 # filter out non-string attributes which may be stuffed by dir() calls
2054 # and poor coding in third-party modules
2070 # and poor coding in third-party modules
2055 return [w for w in words if isinstance(w, basestring)]
2071 return [w for w in words if isinstance(w, basestring)]
2056
2072
2057 #----------------------------------------------------------------------------
2073 #----------------------------------------------------------------------------
2058 def import_fail_info(mod_name,fns=None):
2074 def import_fail_info(mod_name,fns=None):
2059 """Inform load failure for a module."""
2075 """Inform load failure for a module."""
2060
2076
2061 if fns == None:
2077 if fns == None:
2062 warn("Loading of %s failed.\n" % (mod_name,))
2078 warn("Loading of %s failed.\n" % (mod_name,))
2063 else:
2079 else:
2064 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
2080 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
2065
2081
2066 #----------------------------------------------------------------------------
2082 #----------------------------------------------------------------------------
2067 # Proposed popitem() extension, written as a method
2083 # Proposed popitem() extension, written as a method
2068
2084
2069
2085
2070 class NotGiven: pass
2086 class NotGiven: pass
2071
2087
2072 def popkey(dct,key,default=NotGiven):
2088 def popkey(dct,key,default=NotGiven):
2073 """Return dct[key] and delete dct[key].
2089 """Return dct[key] and delete dct[key].
2074
2090
2075 If default is given, return it if dct[key] doesn't exist, otherwise raise
2091 If default is given, return it if dct[key] doesn't exist, otherwise raise
2076 KeyError. """
2092 KeyError. """
2077
2093
2078 try:
2094 try:
2079 val = dct[key]
2095 val = dct[key]
2080 except KeyError:
2096 except KeyError:
2081 if default is NotGiven:
2097 if default is NotGiven:
2082 raise
2098 raise
2083 else:
2099 else:
2084 return default
2100 return default
2085 else:
2101 else:
2086 del dct[key]
2102 del dct[key]
2087 return val
2103 return val
2088
2104
2089 def wrap_deprecated(func, suggest = '<nothing>'):
2105 def wrap_deprecated(func, suggest = '<nothing>'):
2090 def newFunc(*args, **kwargs):
2106 def newFunc(*args, **kwargs):
2091 warnings.warn("Call to deprecated function %s, use %s instead" %
2107 warnings.warn("Call to deprecated function %s, use %s instead" %
2092 ( func.__name__, suggest),
2108 ( func.__name__, suggest),
2093 category=DeprecationWarning,
2109 category=DeprecationWarning,
2094 stacklevel = 2)
2110 stacklevel = 2)
2095 return func(*args, **kwargs)
2111 return func(*args, **kwargs)
2096 return newFunc
2112 return newFunc
2097
2113
2098
2114
2099 def _num_cpus_unix():
2115 def _num_cpus_unix():
2100 """Return the number of active CPUs on a Unix system."""
2116 """Return the number of active CPUs on a Unix system."""
2101 return os.sysconf("SC_NPROCESSORS_ONLN")
2117 return os.sysconf("SC_NPROCESSORS_ONLN")
2102
2118
2103
2119
2104 def _num_cpus_darwin():
2120 def _num_cpus_darwin():
2105 """Return the number of active CPUs on a Darwin system."""
2121 """Return the number of active CPUs on a Darwin system."""
2106 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
2122 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
2107 return p.stdout.read()
2123 return p.stdout.read()
2108
2124
2109
2125
2110 def _num_cpus_windows():
2126 def _num_cpus_windows():
2111 """Return the number of active CPUs on a Windows system."""
2127 """Return the number of active CPUs on a Windows system."""
2112 return os.environ.get("NUMBER_OF_PROCESSORS")
2128 return os.environ.get("NUMBER_OF_PROCESSORS")
2113
2129
2114
2130
2115 def num_cpus():
2131 def num_cpus():
2116 """Return the effective number of CPUs in the system as an integer.
2132 """Return the effective number of CPUs in the system as an integer.
2117
2133
2118 This cross-platform function makes an attempt at finding the total number of
2134 This cross-platform function makes an attempt at finding the total number of
2119 available CPUs in the system, as returned by various underlying system and
2135 available CPUs in the system, as returned by various underlying system and
2120 python calls.
2136 python calls.
2121
2137
2122 If it can't find a sensible answer, it returns 1 (though an error *may* make
2138 If it can't find a sensible answer, it returns 1 (though an error *may* make
2123 it return a large positive number that's actually incorrect).
2139 it return a large positive number that's actually incorrect).
2124 """
2140 """
2125
2141
2126 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
2142 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
2127 # for the names of the keys we needed to look up for this function. This
2143 # for the names of the keys we needed to look up for this function. This
2128 # code was inspired by their equivalent function.
2144 # code was inspired by their equivalent function.
2129
2145
2130 ncpufuncs = {'Linux':_num_cpus_unix,
2146 ncpufuncs = {'Linux':_num_cpus_unix,
2131 'Darwin':_num_cpus_darwin,
2147 'Darwin':_num_cpus_darwin,
2132 'Windows':_num_cpus_windows,
2148 'Windows':_num_cpus_windows,
2133 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
2149 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
2134 # See http://bugs.python.org/issue1082 for details.
2150 # See http://bugs.python.org/issue1082 for details.
2135 'Microsoft':_num_cpus_windows,
2151 'Microsoft':_num_cpus_windows,
2136 }
2152 }
2137
2153
2138 ncpufunc = ncpufuncs.get(platform.system(),
2154 ncpufunc = ncpufuncs.get(platform.system(),
2139 # default to unix version (Solaris, AIX, etc)
2155 # default to unix version (Solaris, AIX, etc)
2140 _num_cpus_unix)
2156 _num_cpus_unix)
2141
2157
2142 try:
2158 try:
2143 ncpus = max(1,int(ncpufunc()))
2159 ncpus = max(1,int(ncpufunc()))
2144 except:
2160 except:
2145 ncpus = 1
2161 ncpus = 1
2146 return ncpus
2162 return ncpus
2147
2163
2148 #*************************** end of file <genutils.py> **********************
2164 #*************************** end of file <genutils.py> **********************
@@ -1,125 +1,123 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """Default kernel configuration."""
3 """Default kernel configuration."""
4
4
5 __docformat__ = "restructuredtext en"
5 __docformat__ = "restructuredtext en"
6
6
7 #-------------------------------------------------------------------------------
7 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008 The IPython Development Team
9 #
9 #
10 # Distributed under the terms of the BSD License. The full license is in
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
11 # the file COPYING, distributed as part of this software.
12 #-------------------------------------------------------------------------------
12 #-------------------------------------------------------------------------------
13
13
14 #-------------------------------------------------------------------------------
14 #-------------------------------------------------------------------------------
15 # Imports
15 # Imports
16 #-------------------------------------------------------------------------------
16 #-------------------------------------------------------------------------------
17
17
18 from os.path import join as pjoin
19
18 from IPython.external.configobj import ConfigObj
20 from IPython.external.configobj import ConfigObj
19 from IPython.config.api import ConfigObjManager
21 from IPython.config.api import ConfigObjManager
20 from IPython.genutils import get_ipython_dir
22 from IPython.genutils import get_ipython_dir, get_security_dir
21
23
22 default_kernel_config = ConfigObj()
24 default_kernel_config = ConfigObj()
23
25
24 try:
26 security_dir = get_security_dir()
25 ipython_dir = get_ipython_dir() + '/'
26 except:
27 # This will defaults to the cwd
28 ipython_dir = ''
29
27
30 #-------------------------------------------------------------------------------
28 #-------------------------------------------------------------------------------
31 # Engine Configuration
29 # Engine Configuration
32 #-------------------------------------------------------------------------------
30 #-------------------------------------------------------------------------------
33
31
34 engine_config = dict(
32 engine_config = dict(
35 logfile = '', # Empty means log to stdout
33 logfile = '', # Empty means log to stdout
36 furl_file = ipython_dir + 'ipcontroller-engine.furl'
34 furl_file = pjoin(security_dir, 'ipcontroller-engine.furl')
37 )
35 )
38
36
39 #-------------------------------------------------------------------------------
37 #-------------------------------------------------------------------------------
40 # MPI Configuration
38 # MPI Configuration
41 #-------------------------------------------------------------------------------
39 #-------------------------------------------------------------------------------
42
40
43 mpi_config = dict(
41 mpi_config = dict(
44 mpi4py = """from mpi4py import MPI as mpi
42 mpi4py = """from mpi4py import MPI as mpi
45 mpi.size = mpi.COMM_WORLD.Get_size()
43 mpi.size = mpi.COMM_WORLD.Get_size()
46 mpi.rank = mpi.COMM_WORLD.Get_rank()
44 mpi.rank = mpi.COMM_WORLD.Get_rank()
47 """,
45 """,
48 pytrilinos = """from PyTrilinos import Epetra
46 pytrilinos = """from PyTrilinos import Epetra
49 class SimpleStruct:
47 class SimpleStruct:
50 pass
48 pass
51 mpi = SimpleStruct()
49 mpi = SimpleStruct()
52 mpi.rank = 0
50 mpi.rank = 0
53 mpi.size = 0
51 mpi.size = 0
54 """,
52 """,
55 default = ''
53 default = ''
56 )
54 )
57
55
58 #-------------------------------------------------------------------------------
56 #-------------------------------------------------------------------------------
59 # Controller Configuration
57 # Controller Configuration
60 #-------------------------------------------------------------------------------
58 #-------------------------------------------------------------------------------
61
59
62 controller_config = dict(
60 controller_config = dict(
63
61
64 logfile = '', # Empty means log to stdout
62 logfile = '', # Empty means log to stdout
65 import_statement = '',
63 import_statement = '',
66
64
67 engine_tub = dict(
65 engine_tub = dict(
68 ip = '', # Empty string means all interfaces
66 ip = '', # Empty string means all interfaces
69 port = 0, # 0 means pick a port for me
67 port = 0, # 0 means pick a port for me
70 location = '', # Empty string means try to set automatically
68 location = '', # Empty string means try to set automatically
71 secure = True,
69 secure = True,
72 cert_file = ipython_dir + 'ipcontroller-engine.pem',
70 cert_file = pjoin(security_dir, 'ipcontroller-engine.pem'),
73 ),
71 ),
74 engine_fc_interface = 'IPython.kernel.enginefc.IFCControllerBase',
72 engine_fc_interface = 'IPython.kernel.enginefc.IFCControllerBase',
75 engine_furl_file = ipython_dir + 'ipcontroller-engine.furl',
73 engine_furl_file = pjoin(security_dir, 'ipcontroller-engine.furl'),
76
74
77 controller_interfaces = dict(
75 controller_interfaces = dict(
78 # multiengine = dict(
76 # multiengine = dict(
79 # controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
77 # controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
80 # fc_interface = 'IPython.kernel.multienginefc.IFCMultiEngine',
78 # fc_interface = 'IPython.kernel.multienginefc.IFCMultiEngine',
81 # furl_file = 'ipcontroller-mec.furl'
79 # furl_file = 'ipcontroller-mec.furl'
82 # ),
80 # ),
83 task = dict(
81 task = dict(
84 controller_interface = 'IPython.kernel.task.ITaskController',
82 controller_interface = 'IPython.kernel.task.ITaskController',
85 fc_interface = 'IPython.kernel.taskfc.IFCTaskController',
83 fc_interface = 'IPython.kernel.taskfc.IFCTaskController',
86 furl_file = ipython_dir + 'ipcontroller-tc.furl'
84 furl_file = pjoin(security_dir, 'ipcontroller-tc.furl')
87 ),
85 ),
88 multiengine = dict(
86 multiengine = dict(
89 controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
87 controller_interface = 'IPython.kernel.multiengine.IMultiEngine',
90 fc_interface = 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine',
88 fc_interface = 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine',
91 furl_file = ipython_dir + 'ipcontroller-mec.furl'
89 furl_file = pjoin(security_dir, 'ipcontroller-mec.furl')
92 )
90 )
93 ),
91 ),
94
92
95 client_tub = dict(
93 client_tub = dict(
96 ip = '', # Empty string means all interfaces
94 ip = '', # Empty string means all interfaces
97 port = 0, # 0 means pick a port for me
95 port = 0, # 0 means pick a port for me
98 location = '', # Empty string means try to set automatically
96 location = '', # Empty string means try to set automatically
99 secure = True,
97 secure = True,
100 cert_file = ipython_dir + 'ipcontroller-client.pem'
98 cert_file = pjoin(security_dir, 'ipcontroller-client.pem')
101 )
99 )
102 )
100 )
103
101
104 #-------------------------------------------------------------------------------
102 #-------------------------------------------------------------------------------
105 # Client Configuration
103 # Client Configuration
106 #-------------------------------------------------------------------------------
104 #-------------------------------------------------------------------------------
107
105
108 client_config = dict(
106 client_config = dict(
109 client_interfaces = dict(
107 client_interfaces = dict(
110 task = dict(
108 task = dict(
111 furl_file = ipython_dir + 'ipcontroller-tc.furl'
109 furl_file = pjoin(security_dir, 'ipcontroller-tc.furl')
112 ),
110 ),
113 multiengine = dict(
111 multiengine = dict(
114 furl_file = ipython_dir + 'ipcontroller-mec.furl'
112 furl_file = pjoin(security_dir, 'ipcontroller-mec.furl')
115 )
113 )
116 )
114 )
117 )
115 )
118
116
119 default_kernel_config['engine'] = engine_config
117 default_kernel_config['engine'] = engine_config
120 default_kernel_config['mpi'] = mpi_config
118 default_kernel_config['mpi'] = mpi_config
121 default_kernel_config['controller'] = controller_config
119 default_kernel_config['controller'] = controller_config
122 default_kernel_config['client'] = client_config
120 default_kernel_config['client'] = client_config
123
121
124
122
125 config_manager = ConfigObjManager(default_kernel_config, 'IPython.kernel.ini') No newline at end of file
123 config_manager = ConfigObjManager(default_kernel_config, 'IPython.kernel.ini')
@@ -1,171 +1,172 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3
3
4 """Start the IPython Engine."""
4 """Start the IPython Engine."""
5
5
6 __docformat__ = "restructuredtext en"
6 __docformat__ = "restructuredtext en"
7
7
8 #-------------------------------------------------------------------------------
8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-------------------------------------------------------------------------------
13 #-------------------------------------------------------------------------------
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-------------------------------------------------------------------------------
17 #-------------------------------------------------------------------------------
18
18
19 # Python looks for an empty string at the beginning of sys.path to enable
19 # Python looks for an empty string at the beginning of sys.path to enable
20 # importing from the cwd.
20 # importing from the cwd.
21 import sys
21 import sys
22 sys.path.insert(0, '')
22 sys.path.insert(0, '')
23
23
24 import sys, os
24 import sys, os
25 from optparse import OptionParser
25 from optparse import OptionParser
26
26
27 from twisted.application import service
27 from twisted.application import service
28 from twisted.internet import reactor
28 from twisted.internet import reactor
29 from twisted.python import log
29 from twisted.python import log
30
30
31 from IPython.kernel.fcutil import Tub, UnauthenticatedTub
31 from IPython.kernel.fcutil import Tub, UnauthenticatedTub
32
32
33 from IPython.kernel.core.config import config_manager as core_config_manager
33 from IPython.kernel.core.config import config_manager as core_config_manager
34 from IPython.config.cutils import import_item
34 from IPython.config.cutils import import_item
35 from IPython.kernel.engineservice import EngineService
35 from IPython.kernel.engineservice import EngineService
36 from IPython.kernel.config import config_manager as kernel_config_manager
36 from IPython.kernel.config import config_manager as kernel_config_manager
37 from IPython.kernel.engineconnector import EngineConnector
37 from IPython.kernel.engineconnector import EngineConnector
38
38
39
39
40 #-------------------------------------------------------------------------------
40 #-------------------------------------------------------------------------------
41 # Code
41 # Code
42 #-------------------------------------------------------------------------------
42 #-------------------------------------------------------------------------------
43
43
44 def start_engine():
44 def start_engine():
45 """
45 """
46 Start the engine, by creating it and starting the Twisted reactor.
46 Start the engine, by creating it and starting the Twisted reactor.
47
47
48 This method does:
48 This method does:
49
49
50 * If it exists, runs the `mpi_import_statement` to call `MPI_Init`
50 * If it exists, runs the `mpi_import_statement` to call `MPI_Init`
51 * Starts the engine logging
51 * Starts the engine logging
52 * Creates an IPython shell and wraps it in an `EngineService`
52 * Creates an IPython shell and wraps it in an `EngineService`
53 * Creates a `foolscap.Tub` to use in connecting to a controller.
53 * Creates a `foolscap.Tub` to use in connecting to a controller.
54 * Uses the tub and the `EngineService` along with a Foolscap URL
54 * Uses the tub and the `EngineService` along with a Foolscap URL
55 (or FURL) to connect to the controller and register the engine
55 (or FURL) to connect to the controller and register the engine
56 with the controller
56 with the controller
57 """
57 """
58 kernel_config = kernel_config_manager.get_config_obj()
58 kernel_config = kernel_config_manager.get_config_obj()
59 core_config = core_config_manager.get_config_obj()
59 core_config = core_config_manager.get_config_obj()
60
60
61
61
62 # Execute the mpi import statement that needs to call MPI_Init
62 # Execute the mpi import statement that needs to call MPI_Init
63 global mpi
63 global mpi
64 mpikey = kernel_config['mpi']['default']
64 mpikey = kernel_config['mpi']['default']
65 mpi_import_statement = kernel_config['mpi'].get(mpikey, None)
65 mpi_import_statement = kernel_config['mpi'].get(mpikey, None)
66 if mpi_import_statement is not None:
66 if mpi_import_statement is not None:
67 try:
67 try:
68 exec mpi_import_statement in globals()
68 exec mpi_import_statement in globals()
69 except:
69 except:
70 mpi = None
70 mpi = None
71 else:
71 else:
72 mpi = None
72 mpi = None
73
73
74 # Start logging
74 # Start logging
75 logfile = kernel_config['engine']['logfile']
75 logfile = kernel_config['engine']['logfile']
76 if logfile:
76 if logfile:
77 logfile = logfile + str(os.getpid()) + '.log'
77 logfile = logfile + str(os.getpid()) + '.log'
78 try:
78 try:
79 openLogFile = open(logfile, 'w')
79 openLogFile = open(logfile, 'w')
80 except:
80 except:
81 openLogFile = sys.stdout
81 openLogFile = sys.stdout
82 else:
82 else:
83 openLogFile = sys.stdout
83 openLogFile = sys.stdout
84 log.startLogging(openLogFile)
84 log.startLogging(openLogFile)
85
85
86 # Create the underlying shell class and EngineService
86 # Create the underlying shell class and EngineService
87 shell_class = import_item(core_config['shell']['shell_class'])
87 shell_class = import_item(core_config['shell']['shell_class'])
88 engine_service = EngineService(shell_class, mpi=mpi)
88 engine_service = EngineService(shell_class, mpi=mpi)
89 shell_import_statement = core_config['shell']['import_statement']
89 shell_import_statement = core_config['shell']['import_statement']
90 if shell_import_statement:
90 if shell_import_statement:
91 try:
91 try:
92 engine_service.execute(shell_import_statement)
92 engine_service.execute(shell_import_statement)
93 except:
93 except:
94 log.msg("Error running import_statement: %s" % sis)
94 log.msg("Error running import_statement: %s" % sis)
95
95
96 # Create the service hierarchy
96 # Create the service hierarchy
97 main_service = service.MultiService()
97 main_service = service.MultiService()
98 engine_service.setServiceParent(main_service)
98 engine_service.setServiceParent(main_service)
99 tub_service = Tub()
99 tub_service = Tub()
100 tub_service.setServiceParent(main_service)
100 tub_service.setServiceParent(main_service)
101 # This needs to be called before the connection is initiated
101 # This needs to be called before the connection is initiated
102 main_service.startService()
102 main_service.startService()
103
103
104 # This initiates the connection to the controller and calls
104 # This initiates the connection to the controller and calls
105 # register_engine to tell the controller we are ready to do work
105 # register_engine to tell the controller we are ready to do work
106 engine_connector = EngineConnector(tub_service)
106 engine_connector = EngineConnector(tub_service)
107 furl_file = kernel_config['engine']['furl_file']
107 furl_file = kernel_config['engine']['furl_file']
108 log.msg("Using furl file: %s" % furl_file)
108 d = engine_connector.connect_to_controller(engine_service, furl_file)
109 d = engine_connector.connect_to_controller(engine_service, furl_file)
109 d.addErrback(lambda _: reactor.stop())
110 d.addErrback(lambda _: reactor.stop())
110
111
111 reactor.run()
112 reactor.run()
112
113
113
114
114 def init_config():
115 def init_config():
115 """
116 """
116 Initialize the configuration using default and command line options.
117 Initialize the configuration using default and command line options.
117 """
118 """
118
119
119 parser = OptionParser()
120 parser = OptionParser()
120
121
121 parser.add_option(
122 parser.add_option(
122 "--furl-file",
123 "--furl-file",
123 type="string",
124 type="string",
124 dest="furl_file",
125 dest="furl_file",
125 help="The filename containing the FURL of the controller"
126 help="The filename containing the FURL of the controller"
126 )
127 )
127 parser.add_option(
128 parser.add_option(
128 "--mpi",
129 "--mpi",
129 type="string",
130 type="string",
130 dest="mpi",
131 dest="mpi",
131 help="How to enable MPI (mpi4py, pytrilinos, or empty string to disable)"
132 help="How to enable MPI (mpi4py, pytrilinos, or empty string to disable)"
132 )
133 )
133 parser.add_option(
134 parser.add_option(
134 "-l",
135 "-l",
135 "--logfile",
136 "--logfile",
136 type="string",
137 type="string",
137 dest="logfile",
138 dest="logfile",
138 help="log file name (default is stdout)"
139 help="log file name (default is stdout)"
139 )
140 )
140 parser.add_option(
141 parser.add_option(
141 "--ipythondir",
142 "--ipythondir",
142 type="string",
143 type="string",
143 dest="ipythondir",
144 dest="ipythondir",
144 help="look for config files and profiles in this directory"
145 help="look for config files and profiles in this directory"
145 )
146 )
146
147
147 (options, args) = parser.parse_args()
148 (options, args) = parser.parse_args()
148
149
149 kernel_config_manager.update_config_obj_from_default_file(options.ipythondir)
150 kernel_config_manager.update_config_obj_from_default_file(options.ipythondir)
150 core_config_manager.update_config_obj_from_default_file(options.ipythondir)
151 core_config_manager.update_config_obj_from_default_file(options.ipythondir)
151
152
152 kernel_config = kernel_config_manager.get_config_obj()
153 kernel_config = kernel_config_manager.get_config_obj()
153 # Now override with command line options
154 # Now override with command line options
154 if options.furl_file is not None:
155 if options.furl_file is not None:
155 kernel_config['engine']['furl_file'] = options.furl_file
156 kernel_config['engine']['furl_file'] = options.furl_file
156 if options.logfile is not None:
157 if options.logfile is not None:
157 kernel_config['engine']['logfile'] = options.logfile
158 kernel_config['engine']['logfile'] = options.logfile
158 if options.mpi is not None:
159 if options.mpi is not None:
159 kernel_config['mpi']['default'] = options.mpi
160 kernel_config['mpi']['default'] = options.mpi
160
161
161
162
162 def main():
163 def main():
163 """
164 """
164 After creating the configuration information, start the engine.
165 After creating the configuration information, start the engine.
165 """
166 """
166 init_config()
167 init_config()
167 start_engine()
168 start_engine()
168
169
169
170
170 if __name__ == "__main__":
171 if __name__ == "__main__":
171 main() No newline at end of file
172 main()
General Comments 0
You need to be logged in to leave comments. Login now