##// END OF EJS Templates
Fixing a few small things on Windows....
bgranger -
Show More
@@ -1,700 +1,700 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Facilities for launching processing asynchronously.
4 Facilities for launching processing asynchronously.
5 """
5 """
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2009 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 import re
19 import re
20 import sys
20 import sys
21
21
22 from IPython.core.component import Component
22 from IPython.core.component import Component
23 from IPython.external import Itpl
23 from IPython.external import Itpl
24 from IPython.utils.traitlets import Str, Int, List, Unicode
24 from IPython.utils.traitlets import Str, Int, List, Unicode
25 from IPython.kernel.twistedutil import gatherBoth, make_deferred, sleep_deferred
25 from IPython.kernel.twistedutil import gatherBoth, make_deferred, sleep_deferred
26
26
27 from twisted.internet import reactor, defer
27 from twisted.internet import reactor, defer
28 from twisted.internet.defer import inlineCallbacks
28 from twisted.internet.defer import inlineCallbacks
29 from twisted.internet.protocol import ProcessProtocol
29 from twisted.internet.protocol import ProcessProtocol
30 from twisted.internet.utils import getProcessOutput
30 from twisted.internet.utils import getProcessOutput
31 from twisted.internet.error import ProcessDone, ProcessTerminated
31 from twisted.internet.error import ProcessDone, ProcessTerminated
32 from twisted.python import log
32 from twisted.python import log
33 from twisted.python.failure import Failure
33 from twisted.python.failure import Failure
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Generic launchers
36 # Generic launchers
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39
39
40 class LauncherError(Exception):
40 class LauncherError(Exception):
41 pass
41 pass
42
42
43
43
44 class ProcessStateError(LauncherError):
44 class ProcessStateError(LauncherError):
45 pass
45 pass
46
46
47
47
48 class UnknownStatus(LauncherError):
48 class UnknownStatus(LauncherError):
49 pass
49 pass
50
50
51
51
52 class BaseLauncher(Component):
52 class BaseLauncher(Component):
53 """An asbtraction for starting, stopping and signaling a process."""
53 """An asbtraction for starting, stopping and signaling a process."""
54
54
55 # A directory for files related to the process. But, we don't cd to
55 # A directory for files related to the process. But, we don't cd to
56 # this directory,
56 # this directory,
57 working_dir = Unicode(u'')
57 working_dir = Unicode(u'')
58
58
59 def __init__(self, working_dir, parent=None, name=None, config=None):
59 def __init__(self, working_dir, parent=None, name=None, config=None):
60 super(BaseLauncher, self).__init__(parent, name, config)
60 super(BaseLauncher, self).__init__(parent, name, config)
61 self.working_dir = working_dir
61 self.working_dir = working_dir
62 self.state = 'before' # can be before, running, after
62 self.state = 'before' # can be before, running, after
63 self.stop_deferreds = []
63 self.stop_deferreds = []
64 self.start_data = None
64 self.start_data = None
65 self.stop_data = None
65 self.stop_data = None
66
66
67 @property
67 @property
68 def args(self):
68 def args(self):
69 """A list of cmd and args that will be used to start the process.
69 """A list of cmd and args that will be used to start the process.
70
70
71 This is what is passed to :func:`spawnProcess` and the first element
71 This is what is passed to :func:`spawnProcess` and the first element
72 will be the process name.
72 will be the process name.
73 """
73 """
74 return self.find_args()
74 return self.find_args()
75
75
76 def find_args(self):
76 def find_args(self):
77 """The ``.args`` property calls this to find the args list.
77 """The ``.args`` property calls this to find the args list.
78
78
79 Subcommand should implement this to construct the cmd and args.
79 Subcommand should implement this to construct the cmd and args.
80 """
80 """
81 raise NotImplementedError('find_args must be implemented in a subclass')
81 raise NotImplementedError('find_args must be implemented in a subclass')
82
82
83 @property
83 @property
84 def arg_str(self):
84 def arg_str(self):
85 """The string form of the program arguments."""
85 """The string form of the program arguments."""
86 return ' '.join(self.args)
86 return ' '.join(self.args)
87
87
88 @property
88 @property
89 def running(self):
89 def running(self):
90 """Am I running."""
90 """Am I running."""
91 if self.state == 'running':
91 if self.state == 'running':
92 return True
92 return True
93 else:
93 else:
94 return False
94 return False
95
95
96 def start(self):
96 def start(self):
97 """Start the process.
97 """Start the process.
98
98
99 This must return a deferred that fires with information about the
99 This must return a deferred that fires with information about the
100 process starting (like a pid, job id, etc.).
100 process starting (like a pid, job id, etc.).
101 """
101 """
102 return defer.fail(
102 return defer.fail(
103 Failure(NotImplementedError(
103 Failure(NotImplementedError(
104 'start must be implemented in a subclass')
104 'start must be implemented in a subclass')
105 )
105 )
106 )
106 )
107
107
108 def stop(self):
108 def stop(self):
109 """Stop the process and notify observers of stopping.
109 """Stop the process and notify observers of stopping.
110
110
111 This must return a deferred that fires with information about the
111 This must return a deferred that fires with information about the
112 processing stopping, like errors that occur while the process is
112 processing stopping, like errors that occur while the process is
113 attempting to be shut down. This deferred won't fire when the process
113 attempting to be shut down. This deferred won't fire when the process
114 actually stops. To observe the actual process stopping, see
114 actually stops. To observe the actual process stopping, see
115 :func:`observe_stop`.
115 :func:`observe_stop`.
116 """
116 """
117 return defer.fail(
117 return defer.fail(
118 Failure(NotImplementedError(
118 Failure(NotImplementedError(
119 'stop must be implemented in a subclass')
119 'stop must be implemented in a subclass')
120 )
120 )
121 )
121 )
122
122
123 def observe_stop(self):
123 def observe_stop(self):
124 """Get a deferred that will fire when the process stops.
124 """Get a deferred that will fire when the process stops.
125
125
126 The deferred will fire with data that contains information about
126 The deferred will fire with data that contains information about
127 the exit status of the process.
127 the exit status of the process.
128 """
128 """
129 if self.state=='after':
129 if self.state=='after':
130 return defer.succeed(self.stop_data)
130 return defer.succeed(self.stop_data)
131 else:
131 else:
132 d = defer.Deferred()
132 d = defer.Deferred()
133 self.stop_deferreds.append(d)
133 self.stop_deferreds.append(d)
134 return d
134 return d
135
135
136 def notify_start(self, data):
136 def notify_start(self, data):
137 """Call this to trigger startup actions.
137 """Call this to trigger startup actions.
138
138
139 This logs the process startup and sets the state to 'running'. It is
139 This logs the process startup and sets the state to 'running'. It is
140 a pass-through so it can be used as a callback.
140 a pass-through so it can be used as a callback.
141 """
141 """
142
142
143 log.msg('Process %r started: %r' % (self.args[0], data))
143 log.msg('Process %r started: %r' % (self.args[0], data))
144 self.start_data = data
144 self.start_data = data
145 self.state = 'running'
145 self.state = 'running'
146 return data
146 return data
147
147
148 def notify_stop(self, data):
148 def notify_stop(self, data):
149 """Call this to trigger process stop actions.
149 """Call this to trigger process stop actions.
150
150
151 This logs the process stopping and sets the state to 'after'. Call
151 This logs the process stopping and sets the state to 'after'. Call
152 this to trigger all the deferreds from :func:`observe_stop`."""
152 this to trigger all the deferreds from :func:`observe_stop`."""
153
153
154 log.msg('Process %r stopped: %r' % (self.args[0], data))
154 log.msg('Process %r stopped: %r' % (self.args[0], data))
155 self.stop_data = data
155 self.stop_data = data
156 self.state = 'after'
156 self.state = 'after'
157 for i in range(len(self.stop_deferreds)):
157 for i in range(len(self.stop_deferreds)):
158 d = self.stop_deferreds.pop()
158 d = self.stop_deferreds.pop()
159 d.callback(data)
159 d.callback(data)
160 return data
160 return data
161
161
162 def signal(self, sig):
162 def signal(self, sig):
163 """Signal the process.
163 """Signal the process.
164
164
165 Return a semi-meaningless deferred after signaling the process.
165 Return a semi-meaningless deferred after signaling the process.
166
166
167 Parameters
167 Parameters
168 ----------
168 ----------
169 sig : str or int
169 sig : str or int
170 'KILL', 'INT', etc., or any signal number
170 'KILL', 'INT', etc., or any signal number
171 """
171 """
172 return defer.fail(
172 return defer.fail(
173 Failure(NotImplementedError(
173 Failure(NotImplementedError(
174 'signal must be implemented in a subclass')
174 'signal must be implemented in a subclass')
175 )
175 )
176 )
176 )
177
177
178
178
179 class LocalProcessLauncherProtocol(ProcessProtocol):
179 class LocalProcessLauncherProtocol(ProcessProtocol):
180 """A ProcessProtocol to go with the LocalProcessLauncher."""
180 """A ProcessProtocol to go with the LocalProcessLauncher."""
181
181
182 def __init__(self, process_launcher):
182 def __init__(self, process_launcher):
183 self.process_launcher = process_launcher
183 self.process_launcher = process_launcher
184 self.pid = None
184 self.pid = None
185
185
186 def connectionMade(self):
186 def connectionMade(self):
187 self.pid = self.transport.pid
187 self.pid = self.transport.pid
188 self.process_launcher.notify_start(self.transport.pid)
188 self.process_launcher.notify_start(self.transport.pid)
189
189
190 def processEnded(self, status):
190 def processEnded(self, status):
191 value = status.value
191 value = status.value
192 if isinstance(value, ProcessDone):
192 if isinstance(value, ProcessDone):
193 self.process_launcher.notify_stop(
193 self.process_launcher.notify_stop(
194 {'exit_code':0,
194 {'exit_code':0,
195 'signal':None,
195 'signal':None,
196 'status':None,
196 'status':None,
197 'pid':self.pid
197 'pid':self.pid
198 }
198 }
199 )
199 )
200 elif isinstance(value, ProcessTerminated):
200 elif isinstance(value, ProcessTerminated):
201 self.process_launcher.notify_stop(
201 self.process_launcher.notify_stop(
202 {'exit_code':value.exitCode,
202 {'exit_code':value.exitCode,
203 'signal':value.signal,
203 'signal':value.signal,
204 'status':value.status,
204 'status':value.status,
205 'pid':self.pid
205 'pid':self.pid
206 }
206 }
207 )
207 )
208 else:
208 else:
209 raise UnknownStatus("Unknown exit status, this is probably a "
209 raise UnknownStatus("Unknown exit status, this is probably a "
210 "bug in Twisted")
210 "bug in Twisted")
211
211
212 def outReceived(self, data):
212 def outReceived(self, data):
213 log.msg(data)
213 log.msg(data)
214
214
215 def errReceived(self, data):
215 def errReceived(self, data):
216 log.err(data)
216 log.err(data)
217
217
218
218
219 class LocalProcessLauncher(BaseLauncher):
219 class LocalProcessLauncher(BaseLauncher):
220 """Start and stop an external process in an asynchronous manner."""
220 """Start and stop an external process in an asynchronous manner."""
221
221
222 # This is used to to construct self.args, which is passed to
222 # This is used to to construct self.args, which is passed to
223 # spawnProcess.
223 # spawnProcess.
224 cmd_and_args = List([])
224 cmd_and_args = List([])
225
225
226 def __init__(self, working_dir, parent=None, name=None, config=None):
226 def __init__(self, working_dir, parent=None, name=None, config=None):
227 super(LocalProcessLauncher, self).__init__(
227 super(LocalProcessLauncher, self).__init__(
228 working_dir, parent, name, config
228 working_dir, parent, name, config
229 )
229 )
230 self.process_protocol = None
230 self.process_protocol = None
231 self.start_deferred = None
231 self.start_deferred = None
232
232
233 def find_args(self):
233 def find_args(self):
234 return self.cmd_and_args
234 return self.cmd_and_args
235
235
236 def start(self):
236 def start(self):
237 if self.state == 'before':
237 if self.state == 'before':
238 self.process_protocol = LocalProcessLauncherProtocol(self)
238 self.process_protocol = LocalProcessLauncherProtocol(self)
239 self.start_deferred = defer.Deferred()
239 self.start_deferred = defer.Deferred()
240 self.process_transport = reactor.spawnProcess(
240 self.process_transport = reactor.spawnProcess(
241 self.process_protocol,
241 self.process_protocol,
242 str(self.args[0]),
242 str(self.args[0]),
243 [str(a) for a in self.args],
243 [str(a) for a in self.args],
244 env=os.environ
244 env=os.environ
245 )
245 )
246 return self.start_deferred
246 return self.start_deferred
247 else:
247 else:
248 s = 'The process was already started and has state: %r' % self.state
248 s = 'The process was already started and has state: %r' % self.state
249 return defer.fail(ProcessStateError(s))
249 return defer.fail(ProcessStateError(s))
250
250
251 def notify_start(self, data):
251 def notify_start(self, data):
252 super(LocalProcessLauncher, self).notify_start(data)
252 super(LocalProcessLauncher, self).notify_start(data)
253 self.start_deferred.callback(data)
253 self.start_deferred.callback(data)
254
254
255 def stop(self):
255 def stop(self):
256 return self.interrupt_then_kill()
256 return self.interrupt_then_kill()
257
257
258 @make_deferred
258 @make_deferred
259 def signal(self, sig):
259 def signal(self, sig):
260 if self.state == 'running':
260 if self.state == 'running':
261 self.process_transport.signalProcess(sig)
261 self.process_transport.signalProcess(sig)
262
262
263 @inlineCallbacks
263 @inlineCallbacks
264 def interrupt_then_kill(self, delay=2.0):
264 def interrupt_then_kill(self, delay=2.0):
265 """Send INT, wait a delay and then send KILL."""
265 """Send INT, wait a delay and then send KILL."""
266 yield self.signal('INT')
266 yield self.signal('INT')
267 yield sleep_deferred(delay)
267 yield sleep_deferred(delay)
268 yield self.signal('KILL')
268 yield self.signal('KILL')
269
269
270
270
271 class MPIExecLauncher(LocalProcessLauncher):
271 class MPIExecLauncher(LocalProcessLauncher):
272 """Launch an external process using mpiexec."""
272 """Launch an external process using mpiexec."""
273
273
274 # The mpiexec command to use in starting the process.
274 # The mpiexec command to use in starting the process.
275 mpi_cmd = List(['mpiexec'], config=True)
275 mpi_cmd = List(['mpiexec'], config=True)
276 # The command line arguments to pass to mpiexec.
276 # The command line arguments to pass to mpiexec.
277 mpi_args = List([], config=True)
277 mpi_args = List([], config=True)
278 # The program to start using mpiexec.
278 # The program to start using mpiexec.
279 program = List(['date'], config=True)
279 program = List(['date'], config=True)
280 # The command line argument to the program.
280 # The command line argument to the program.
281 program_args = List([], config=True)
281 program_args = List([], config=True)
282 # The number of instances of the program to start.
282 # The number of instances of the program to start.
283 n = Int(1, config=True)
283 n = Int(1, config=True)
284
284
285 def find_args(self):
285 def find_args(self):
286 """Build self.args using all the fields."""
286 """Build self.args using all the fields."""
287 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
287 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
288 self.program + self.program_args
288 self.program + self.program_args
289
289
290 def start(self, n):
290 def start(self, n):
291 """Start n instances of the program using mpiexec."""
291 """Start n instances of the program using mpiexec."""
292 self.n = n
292 self.n = n
293 return super(MPIExecLauncher, self).start()
293 return super(MPIExecLauncher, self).start()
294
294
295
295
296 class SSHLauncher(BaseLauncher):
296 class SSHLauncher(BaseLauncher):
297 """A minimal launcher for ssh.
297 """A minimal launcher for ssh.
298
298
299 To be useful this will probably have to be extended to use the ``sshx``
299 To be useful this will probably have to be extended to use the ``sshx``
300 idea for environment variables. There could be other things this needs
300 idea for environment variables. There could be other things this needs
301 as well.
301 as well.
302 """
302 """
303
303
304 ssh_cmd = List(['ssh'], config=True)
304 ssh_cmd = List(['ssh'], config=True)
305 ssh_args = List([], config=True)
305 ssh_args = List([], config=True)
306 program = List(['date'], config=True)
306 program = List(['date'], config=True)
307 program_args = List([], config=True)
307 program_args = List([], config=True)
308 hostname = Str('', config=True)
308 hostname = Str('', config=True)
309 user = Str(os.environ['USER'], config=True)
309 user = Str('', config=True)
310 location = Str('')
310 location = Str('')
311
311
312 def _hostname_changed(self, name, old, new):
312 def _hostname_changed(self, name, old, new):
313 self.location = '%s@%s' % (self.user, new)
313 self.location = '%s@%s' % (self.user, new)
314
314
315 def _user_changed(self, name, old, new):
315 def _user_changed(self, name, old, new):
316 self.location = '%s@%s' % (new, self.hostname)
316 self.location = '%s@%s' % (new, self.hostname)
317
317
318 def find_args(self):
318 def find_args(self):
319 return self.ssh_cmd + self.ssh_args + [self.location] + \
319 return self.ssh_cmd + self.ssh_args + [self.location] + \
320 self.program + self.program_args
320 self.program + self.program_args
321
321
322 def start(self, n, hostname=None, user=None):
322 def start(self, n, hostname=None, user=None):
323 if hostname is not None:
323 if hostname is not None:
324 self.hostname = hostname
324 self.hostname = hostname
325 if user is not None:
325 if user is not None:
326 self.user = user
326 self.user = user
327 return super(SSHLauncher, self).start()
327 return super(SSHLauncher, self).start()
328
328
329
329
330 class WindowsHPCLauncher(BaseLauncher):
330 class WindowsHPCLauncher(BaseLauncher):
331 pass
331 pass
332
332
333
333
334 class BatchSystemLauncher(BaseLauncher):
334 class BatchSystemLauncher(BaseLauncher):
335 """Launch an external process using a batch system.
335 """Launch an external process using a batch system.
336
336
337 This class is designed to work with UNIX batch systems like PBS, LSF,
337 This class is designed to work with UNIX batch systems like PBS, LSF,
338 GridEngine, etc. The overall model is that there are different commands
338 GridEngine, etc. The overall model is that there are different commands
339 like qsub, qdel, etc. that handle the starting and stopping of the process.
339 like qsub, qdel, etc. that handle the starting and stopping of the process.
340
340
341 This class also has the notion of a batch script. The ``batch_template``
341 This class also has the notion of a batch script. The ``batch_template``
342 attribute can be set to a string that is a template for the batch script.
342 attribute can be set to a string that is a template for the batch script.
343 This template is instantiated using Itpl. Thus the template can use
343 This template is instantiated using Itpl. Thus the template can use
344 ${n} fot the number of instances. Subclasses can add additional variables
344 ${n} fot the number of instances. Subclasses can add additional variables
345 to the template dict.
345 to the template dict.
346 """
346 """
347
347
348 # Subclasses must fill these in. See PBSEngineSet
348 # Subclasses must fill these in. See PBSEngineSet
349 # The name of the command line program used to submit jobs.
349 # The name of the command line program used to submit jobs.
350 submit_command = Str('', config=True)
350 submit_command = Str('', config=True)
351 # The name of the command line program used to delete jobs.
351 # The name of the command line program used to delete jobs.
352 delete_command = Str('', config=True)
352 delete_command = Str('', config=True)
353 # A regular expression used to get the job id from the output of the
353 # A regular expression used to get the job id from the output of the
354 # submit_command.
354 # submit_command.
355 job_id_regexp = Str('', config=True)
355 job_id_regexp = Str('', config=True)
356 # The string that is the batch script template itself.
356 # The string that is the batch script template itself.
357 batch_template = Str('', config=True)
357 batch_template = Str('', config=True)
358 # The filename of the instantiated batch script.
358 # The filename of the instantiated batch script.
359 batch_file_name = Unicode(u'batch_script', config=True)
359 batch_file_name = Unicode(u'batch_script', config=True)
360 # The full path to the instantiated batch script.
360 # The full path to the instantiated batch script.
361 batch_file = Unicode(u'')
361 batch_file = Unicode(u'')
362
362
363 def __init__(self, working_dir, parent=None, name=None, config=None):
363 def __init__(self, working_dir, parent=None, name=None, config=None):
364 super(BatchSystemLauncher, self).__init__(
364 super(BatchSystemLauncher, self).__init__(
365 working_dir, parent, name, config
365 working_dir, parent, name, config
366 )
366 )
367 self.batch_file = os.path.join(self.working_dir, self.batch_file_name)
367 self.batch_file = os.path.join(self.working_dir, self.batch_file_name)
368 self.context = {}
368 self.context = {}
369
369
370 def parse_job_id(self, output):
370 def parse_job_id(self, output):
371 """Take the output of the submit command and return the job id."""
371 """Take the output of the submit command and return the job id."""
372 m = re.match(self.job_id_regexp, output)
372 m = re.match(self.job_id_regexp, output)
373 if m is not None:
373 if m is not None:
374 job_id = m.group()
374 job_id = m.group()
375 else:
375 else:
376 raise LauncherError("Job id couldn't be determined: %s" % output)
376 raise LauncherError("Job id couldn't be determined: %s" % output)
377 self.job_id = job_id
377 self.job_id = job_id
378 log.msg('Job started with job id: %r' % job_id)
378 log.msg('Job started with job id: %r' % job_id)
379 return job_id
379 return job_id
380
380
381 def write_batch_script(self, n):
381 def write_batch_script(self, n):
382 """Instantiate and write the batch script to the working_dir."""
382 """Instantiate and write the batch script to the working_dir."""
383 self.context['n'] = n
383 self.context['n'] = n
384 script_as_string = Itpl.itplns(self.batch_template, self.context)
384 script_as_string = Itpl.itplns(self.batch_template, self.context)
385 log.msg('Writing instantiated batch script: %s' % self.batch_file)
385 log.msg('Writing instantiated batch script: %s' % self.batch_file)
386 f = open(self.batch_file, 'w')
386 f = open(self.batch_file, 'w')
387 f.write(script_as_string)
387 f.write(script_as_string)
388 f.close()
388 f.close()
389
389
390 @inlineCallbacks
390 @inlineCallbacks
391 def start(self, n):
391 def start(self, n):
392 """Start n copies of the process using a batch system."""
392 """Start n copies of the process using a batch system."""
393 self.write_batch_script(n)
393 self.write_batch_script(n)
394 output = yield getProcessOutput(self.submit_command,
394 output = yield getProcessOutput(self.submit_command,
395 [self.batch_file], env=os.environ)
395 [self.batch_file], env=os.environ)
396 job_id = self.parse_job_id(output)
396 job_id = self.parse_job_id(output)
397 self.notify_start(job_id)
397 self.notify_start(job_id)
398 defer.returnValue(job_id)
398 defer.returnValue(job_id)
399
399
400 @inlineCallbacks
400 @inlineCallbacks
401 def stop(self):
401 def stop(self):
402 output = yield getProcessOutput(self.delete_command,
402 output = yield getProcessOutput(self.delete_command,
403 [self.job_id], env=os.environ
403 [self.job_id], env=os.environ
404 )
404 )
405 self.notify_stop(output) # Pass the output of the kill cmd
405 self.notify_stop(output) # Pass the output of the kill cmd
406 defer.returnValue(output)
406 defer.returnValue(output)
407
407
408
408
409 class PBSLauncher(BatchSystemLauncher):
409 class PBSLauncher(BatchSystemLauncher):
410 """A BatchSystemLauncher subclass for PBS."""
410 """A BatchSystemLauncher subclass for PBS."""
411
411
412 submit_command = Str('qsub', config=True)
412 submit_command = Str('qsub', config=True)
413 delete_command = Str('qdel', config=True)
413 delete_command = Str('qdel', config=True)
414 job_id_regexp = Str('\d+', config=True)
414 job_id_regexp = Str('\d+', config=True)
415 batch_template = Str('', config=True)
415 batch_template = Str('', config=True)
416 batch_file_name = Unicode(u'pbs_batch_script', config=True)
416 batch_file_name = Unicode(u'pbs_batch_script', config=True)
417 batch_file = Unicode(u'')
417 batch_file = Unicode(u'')
418
418
419
419
420 #-----------------------------------------------------------------------------
420 #-----------------------------------------------------------------------------
421 # Controller launchers
421 # Controller launchers
422 #-----------------------------------------------------------------------------
422 #-----------------------------------------------------------------------------
423
423
424 def find_controller_cmd():
424 def find_controller_cmd():
425 """Find the command line ipcontroller program in a cross platform way."""
425 """Find the command line ipcontroller program in a cross platform way."""
426 if sys.platform == 'win32':
426 if sys.platform == 'win32':
427 # This logic is needed because the ipcontroller script doesn't
427 # This logic is needed because the ipcontroller script doesn't
428 # always get installed in the same way or in the same location.
428 # always get installed in the same way or in the same location.
429 from IPython.kernel import ipcontrollerapp
429 from IPython.kernel import ipcontrollerapp
430 script_location = ipcontrollerapp.__file__.replace('.pyc', '.py')
430 script_location = ipcontrollerapp.__file__.replace('.pyc', '.py')
431 # The -u option here turns on unbuffered output, which is required
431 # The -u option here turns on unbuffered output, which is required
432 # on Win32 to prevent wierd conflict and problems with Twisted.
432 # on Win32 to prevent wierd conflict and problems with Twisted.
433 # Also, use sys.executable to make sure we are picking up the
433 # Also, use sys.executable to make sure we are picking up the
434 # right python exe.
434 # right python exe.
435 cmd = [sys.executable, '-u', script_location]
435 cmd = [sys.executable, '-u', script_location]
436 else:
436 else:
437 # ipcontroller has to be on the PATH in this case.
437 # ipcontroller has to be on the PATH in this case.
438 cmd = ['ipcontroller']
438 cmd = ['ipcontroller']
439 return cmd
439 return cmd
440
440
441
441
442 class LocalControllerLauncher(LocalProcessLauncher):
442 class LocalControllerLauncher(LocalProcessLauncher):
443 """Launch a controller as a regular external process."""
443 """Launch a controller as a regular external process."""
444
444
445 controller_cmd = List(find_controller_cmd())
445 controller_cmd = List(find_controller_cmd())
446 # Command line arguments to ipcontroller.
446 # Command line arguments to ipcontroller.
447 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
447 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
448
448
449 def find_args(self):
449 def find_args(self):
450 return self.controller_cmd + self.controller_args
450 return self.controller_cmd + self.controller_args
451
451
452 def start(self, profile=None, cluster_dir=None):
452 def start(self, profile=None, cluster_dir=None):
453 """Start the controller by profile or cluster_dir."""
453 """Start the controller by profile or cluster_dir."""
454 if cluster_dir is not None:
454 if cluster_dir is not None:
455 self.controller_args.extend(['--cluster-dir', cluster_dir])
455 self.controller_args.extend(['--cluster-dir', cluster_dir])
456 if profile is not None:
456 if profile is not None:
457 self.controller_args.extend(['--profile', profile])
457 self.controller_args.extend(['--profile', profile])
458 log.msg("Starting LocalControllerLauncher: %r" % self.args)
458 log.msg("Starting LocalControllerLauncher: %r" % self.args)
459 return super(LocalControllerLauncher, self).start()
459 return super(LocalControllerLauncher, self).start()
460
460
461
461
462 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
462 class WindowsHPCControllerLauncher(WindowsHPCLauncher):
463 pass
463 pass
464
464
465
465
466 class MPIExecControllerLauncher(MPIExecLauncher):
466 class MPIExecControllerLauncher(MPIExecLauncher):
467 """Launch a controller using mpiexec."""
467 """Launch a controller using mpiexec."""
468
468
469 controller_cmd = List(find_controller_cmd(), config=False)
469 controller_cmd = List(find_controller_cmd(), config=False)
470 # Command line arguments to ipcontroller.
470 # Command line arguments to ipcontroller.
471 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
471 controller_args = List(['--log-to-file','--log-level', '40'], config=True)
472 n = Int(1, config=False)
472 n = Int(1, config=False)
473
473
474 def start(self, profile=None, cluster_dir=None):
474 def start(self, profile=None, cluster_dir=None):
475 """Start the controller by profile or cluster_dir."""
475 """Start the controller by profile or cluster_dir."""
476 if cluster_dir is not None:
476 if cluster_dir is not None:
477 self.controller_args.extend(['--cluster-dir', cluster_dir])
477 self.controller_args.extend(['--cluster-dir', cluster_dir])
478 if profile is not None:
478 if profile is not None:
479 self.controller_args.extend(['--profile', profile])
479 self.controller_args.extend(['--profile', profile])
480 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
480 log.msg("Starting MPIExecControllerLauncher: %r" % self.args)
481 return super(MPIExecControllerLauncher, self).start(1)
481 return super(MPIExecControllerLauncher, self).start(1)
482
482
483 def find_args(self):
483 def find_args(self):
484 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
484 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
485 self.controller_cmd + self.controller_args
485 self.controller_cmd + self.controller_args
486
486
487
487
488 class PBSControllerLauncher(PBSLauncher):
488 class PBSControllerLauncher(PBSLauncher):
489 """Launch a controller using PBS."""
489 """Launch a controller using PBS."""
490
490
491 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
491 batch_file_name = Unicode(u'pbs_batch_script_controller', config=True)
492
492
493 def start(self, profile=None, cluster_dir=None):
493 def start(self, profile=None, cluster_dir=None):
494 """Start the controller by profile or cluster_dir."""
494 """Start the controller by profile or cluster_dir."""
495 # Here we save profile and cluster_dir in the context so they
495 # Here we save profile and cluster_dir in the context so they
496 # can be used in the batch script template as ${profile} and
496 # can be used in the batch script template as ${profile} and
497 # ${cluster_dir}
497 # ${cluster_dir}
498 if cluster_dir is not None:
498 if cluster_dir is not None:
499 self.context['cluster_dir'] = cluster_dir
499 self.context['cluster_dir'] = cluster_dir
500 if profile is not None:
500 if profile is not None:
501 self.context['profile'] = profile
501 self.context['profile'] = profile
502 log.msg("Starting PBSControllerLauncher: %r" % self.args)
502 log.msg("Starting PBSControllerLauncher: %r" % self.args)
503 return super(PBSControllerLauncher, self).start(1)
503 return super(PBSControllerLauncher, self).start(1)
504
504
505
505
506 class SSHControllerLauncher(SSHLauncher):
506 class SSHControllerLauncher(SSHLauncher):
507 pass
507 pass
508
508
509
509
510 #-----------------------------------------------------------------------------
510 #-----------------------------------------------------------------------------
511 # Engine launchers
511 # Engine launchers
512 #-----------------------------------------------------------------------------
512 #-----------------------------------------------------------------------------
513
513
514
514
515 def find_engine_cmd():
515 def find_engine_cmd():
516 """Find the command line ipengine program in a cross platform way."""
516 """Find the command line ipengine program in a cross platform way."""
517 if sys.platform == 'win32':
517 if sys.platform == 'win32':
518 # This logic is needed because the ipengine script doesn't
518 # This logic is needed because the ipengine script doesn't
519 # always get installed in the same way or in the same location.
519 # always get installed in the same way or in the same location.
520 from IPython.kernel import ipengineapp
520 from IPython.kernel import ipengineapp
521 script_location = ipengineapp.__file__.replace('.pyc', '.py')
521 script_location = ipengineapp.__file__.replace('.pyc', '.py')
522 # The -u option here turns on unbuffered output, which is required
522 # The -u option here turns on unbuffered output, which is required
523 # on Win32 to prevent wierd conflict and problems with Twisted.
523 # on Win32 to prevent wierd conflict and problems with Twisted.
524 # Also, use sys.executable to make sure we are picking up the
524 # Also, use sys.executable to make sure we are picking up the
525 # right python exe.
525 # right python exe.
526 cmd = [sys.executable, '-u', script_location]
526 cmd = [sys.executable, '-u', script_location]
527 else:
527 else:
528 # ipcontroller has to be on the PATH in this case.
528 # ipcontroller has to be on the PATH in this case.
529 cmd = ['ipengine']
529 cmd = ['ipengine']
530 return cmd
530 return cmd
531
531
532
532
533 class LocalEngineLauncher(LocalProcessLauncher):
533 class LocalEngineLauncher(LocalProcessLauncher):
534 """Launch a single engine as a regular externall process."""
534 """Launch a single engine as a regular externall process."""
535
535
536 engine_cmd = List(find_engine_cmd())
536 engine_cmd = List(find_engine_cmd())
537 # Command line arguments for ipengine.
537 # Command line arguments for ipengine.
538 engine_args = List(
538 engine_args = List(
539 ['--log-to-file','--log-level', '40'], config=True
539 ['--log-to-file','--log-level', '40'], config=True
540 )
540 )
541
541
542 def find_args(self):
542 def find_args(self):
543 return self.engine_cmd + self.engine_args
543 return self.engine_cmd + self.engine_args
544
544
545 def start(self, profile=None, cluster_dir=None):
545 def start(self, profile=None, cluster_dir=None):
546 """Start the engine by profile or cluster_dir."""
546 """Start the engine by profile or cluster_dir."""
547 if cluster_dir is not None:
547 if cluster_dir is not None:
548 self.engine_args.extend(['--cluster-dir', cluster_dir])
548 self.engine_args.extend(['--cluster-dir', cluster_dir])
549 if profile is not None:
549 if profile is not None:
550 self.engine_args.extend(['--profile', profile])
550 self.engine_args.extend(['--profile', profile])
551 return super(LocalEngineLauncher, self).start()
551 return super(LocalEngineLauncher, self).start()
552
552
553
553
554 class LocalEngineSetLauncher(BaseLauncher):
554 class LocalEngineSetLauncher(BaseLauncher):
555 """Launch a set of engines as regular external processes."""
555 """Launch a set of engines as regular external processes."""
556
556
557 # Command line arguments for ipengine.
557 # Command line arguments for ipengine.
558 engine_args = List(
558 engine_args = List(
559 ['--log-to-file','--log-level', '40'], config=True
559 ['--log-to-file','--log-level', '40'], config=True
560 )
560 )
561
561
562 def __init__(self, working_dir, parent=None, name=None, config=None):
562 def __init__(self, working_dir, parent=None, name=None, config=None):
563 super(LocalEngineSetLauncher, self).__init__(
563 super(LocalEngineSetLauncher, self).__init__(
564 working_dir, parent, name, config
564 working_dir, parent, name, config
565 )
565 )
566 self.launchers = []
566 self.launchers = []
567
567
568 def start(self, n, profile=None, cluster_dir=None):
568 def start(self, n, profile=None, cluster_dir=None):
569 """Start n engines by profile or cluster_dir."""
569 """Start n engines by profile or cluster_dir."""
570 dlist = []
570 dlist = []
571 for i in range(n):
571 for i in range(n):
572 el = LocalEngineLauncher(self.working_dir, self)
572 el = LocalEngineLauncher(self.working_dir, self)
573 # Copy the engine args over to each engine launcher.
573 # Copy the engine args over to each engine launcher.
574 import copy
574 import copy
575 el.engine_args = copy.deepcopy(self.engine_args)
575 el.engine_args = copy.deepcopy(self.engine_args)
576 d = el.start(profile, cluster_dir)
576 d = el.start(profile, cluster_dir)
577 if i==0:
577 if i==0:
578 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
578 log.msg("Starting LocalEngineSetLauncher: %r" % el.args)
579 self.launchers.append(el)
579 self.launchers.append(el)
580 dlist.append(d)
580 dlist.append(d)
581 # The consumeErrors here could be dangerous
581 # The consumeErrors here could be dangerous
582 dfinal = gatherBoth(dlist, consumeErrors=True)
582 dfinal = gatherBoth(dlist, consumeErrors=True)
583 dfinal.addCallback(self.notify_start)
583 dfinal.addCallback(self.notify_start)
584 return dfinal
584 return dfinal
585
585
586 def find_args(self):
586 def find_args(self):
587 return ['engine set']
587 return ['engine set']
588
588
589 def signal(self, sig):
589 def signal(self, sig):
590 dlist = []
590 dlist = []
591 for el in self.launchers:
591 for el in self.launchers:
592 d = el.signal(sig)
592 d = el.signal(sig)
593 dlist.append(d)
593 dlist.append(d)
594 dfinal = gatherBoth(dlist, consumeErrors=True)
594 dfinal = gatherBoth(dlist, consumeErrors=True)
595 return dfinal
595 return dfinal
596
596
597 def interrupt_then_kill(self, delay=1.0):
597 def interrupt_then_kill(self, delay=1.0):
598 dlist = []
598 dlist = []
599 for el in self.launchers:
599 for el in self.launchers:
600 d = el.interrupt_then_kill(delay)
600 d = el.interrupt_then_kill(delay)
601 dlist.append(d)
601 dlist.append(d)
602 dfinal = gatherBoth(dlist, consumeErrors=True)
602 dfinal = gatherBoth(dlist, consumeErrors=True)
603 return dfinal
603 return dfinal
604
604
605 def stop(self):
605 def stop(self):
606 return self.interrupt_then_kill()
606 return self.interrupt_then_kill()
607
607
608 def observe_stop(self):
608 def observe_stop(self):
609 dlist = [el.observe_stop() for el in self.launchers]
609 dlist = [el.observe_stop() for el in self.launchers]
610 dfinal = gatherBoth(dlist, consumeErrors=False)
610 dfinal = gatherBoth(dlist, consumeErrors=False)
611 dfinal.addCallback(self.notify_stop)
611 dfinal.addCallback(self.notify_stop)
612 return dfinal
612 return dfinal
613
613
614
614
615 class MPIExecEngineSetLauncher(MPIExecLauncher):
615 class MPIExecEngineSetLauncher(MPIExecLauncher):
616
616
617 engine_cmd = List(find_engine_cmd(), config=False)
617 engine_cmd = List(find_engine_cmd(), config=False)
618 # Command line arguments for ipengine.
618 # Command line arguments for ipengine.
619 engine_args = List(
619 engine_args = List(
620 ['--log-to-file','--log-level', '40'], config=True
620 ['--log-to-file','--log-level', '40'], config=True
621 )
621 )
622 n = Int(1, config=True)
622 n = Int(1, config=True)
623
623
624 def start(self, n, profile=None, cluster_dir=None):
624 def start(self, n, profile=None, cluster_dir=None):
625 """Start n engines by profile or cluster_dir."""
625 """Start n engines by profile or cluster_dir."""
626 if cluster_dir is not None:
626 if cluster_dir is not None:
627 self.engine_args.extend(['--cluster-dir', cluster_dir])
627 self.engine_args.extend(['--cluster-dir', cluster_dir])
628 if profile is not None:
628 if profile is not None:
629 self.engine_args.extend(['--profile', profile])
629 self.engine_args.extend(['--profile', profile])
630 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
630 log.msg('Starting MPIExecEngineSetLauncher: %r' % self.args)
631 return super(MPIExecEngineSetLauncher, self).start(n)
631 return super(MPIExecEngineSetLauncher, self).start(n)
632
632
633 def find_args(self):
633 def find_args(self):
634 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
634 return self.mpi_cmd + ['-n', self.n] + self.mpi_args + \
635 self.engine_cmd + self.engine_args
635 self.engine_cmd + self.engine_args
636
636
637
637
638 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
638 class WindowsHPCEngineSetLauncher(WindowsHPCLauncher):
639 pass
639 pass
640
640
641
641
642 class PBSEngineSetLauncher(PBSLauncher):
642 class PBSEngineSetLauncher(PBSLauncher):
643
643
644 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
644 batch_file_name = Unicode(u'pbs_batch_script_engines', config=True)
645
645
646 def start(self, n, profile=None, cluster_dir=None):
646 def start(self, n, profile=None, cluster_dir=None):
647 """Start n engines by profile or cluster_dir."""
647 """Start n engines by profile or cluster_dir."""
648 if cluster_dir is not None:
648 if cluster_dir is not None:
649 self.program_args.extend(['--cluster-dir', cluster_dir])
649 self.program_args.extend(['--cluster-dir', cluster_dir])
650 if profile is not None:
650 if profile is not None:
651 self.program_args.extend(['-p', profile])
651 self.program_args.extend(['-p', profile])
652 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
652 log.msg('Starting PBSEngineSetLauncher: %r' % self.args)
653 return super(PBSEngineSetLauncher, self).start(n)
653 return super(PBSEngineSetLauncher, self).start(n)
654
654
655
655
656 class SSHEngineSetLauncher(BaseLauncher):
656 class SSHEngineSetLauncher(BaseLauncher):
657 pass
657 pass
658
658
659
659
660 #-----------------------------------------------------------------------------
660 #-----------------------------------------------------------------------------
661 # A launcher for ipcluster itself!
661 # A launcher for ipcluster itself!
662 #-----------------------------------------------------------------------------
662 #-----------------------------------------------------------------------------
663
663
664
664
665 def find_ipcluster_cmd():
665 def find_ipcluster_cmd():
666 """Find the command line ipcluster program in a cross platform way."""
666 """Find the command line ipcluster program in a cross platform way."""
667 if sys.platform == 'win32':
667 if sys.platform == 'win32':
668 # This logic is needed because the ipcluster script doesn't
668 # This logic is needed because the ipcluster script doesn't
669 # always get installed in the same way or in the same location.
669 # always get installed in the same way or in the same location.
670 from IPython.kernel import ipclusterapp
670 from IPython.kernel import ipclusterapp
671 script_location = ipclusterapp.__file__.replace('.pyc', '.py')
671 script_location = ipclusterapp.__file__.replace('.pyc', '.py')
672 # The -u option here turns on unbuffered output, which is required
672 # The -u option here turns on unbuffered output, which is required
673 # on Win32 to prevent wierd conflict and problems with Twisted.
673 # on Win32 to prevent wierd conflict and problems with Twisted.
674 # Also, use sys.executable to make sure we are picking up the
674 # Also, use sys.executable to make sure we are picking up the
675 # right python exe.
675 # right python exe.
676 cmd = [sys.executable, '-u', script_location]
676 cmd = [sys.executable, '-u', script_location]
677 else:
677 else:
678 # ipcontroller has to be on the PATH in this case.
678 # ipcontroller has to be on the PATH in this case.
679 cmd = ['ipcluster']
679 cmd = ['ipcluster']
680 return cmd
680 return cmd
681
681
682
682
683 class IPClusterLauncher(LocalProcessLauncher):
683 class IPClusterLauncher(LocalProcessLauncher):
684 """Launch the ipcluster program in an external process."""
684 """Launch the ipcluster program in an external process."""
685
685
686 ipcluster_cmd = List(find_ipcluster_cmd())
686 ipcluster_cmd = List(find_ipcluster_cmd())
687 # Command line arguments to pass to ipcluster.
687 # Command line arguments to pass to ipcluster.
688 ipcluster_args = List(
688 ipcluster_args = List(
689 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
689 ['--clean-logs', '--log-to-file', '--log-level', '40'], config=True)
690 ipcluster_subcommand = Str('start')
690 ipcluster_subcommand = Str('start')
691 ipcluster_n = Int(2)
691 ipcluster_n = Int(2)
692
692
693 def find_args(self):
693 def find_args(self):
694 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
694 return self.ipcluster_cmd + [self.ipcluster_subcommand] + \
695 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
695 ['-n', repr(self.ipcluster_n)] + self.ipcluster_args
696
696
697 def start(self):
697 def start(self):
698 log.msg("Starting ipcluster: %r" % self.args)
698 log.msg("Starting ipcluster: %r" % self.args)
699 return super(IPClusterLauncher, self).start()
699 return super(IPClusterLauncher, self).start()
700
700
@@ -1,1769 +1,1796 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """General purpose utilities.
2 """General purpose utilities.
3
3
4 This is a grab-bag of stuff I find useful in most programs I write. Some of
4 This is a grab-bag of stuff I find useful in most programs I write. Some of
5 these things are also convenient when working at the command line.
5 these things are also convenient when working at the command line.
6 """
6 """
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
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 # required modules from the Python standard library
16 # required modules from the Python standard library
17 import __main__
17 import __main__
18
18
19 import os
19 import os
20 import platform
20 import platform
21 import re
21 import re
22 import shlex
22 import shlex
23 import shutil
23 import shutil
24 import subprocess
24 import subprocess
25 import sys
25 import sys
26 import time
26 import time
27 import types
27 import types
28 import warnings
28 import warnings
29
29
30 # Curses and termios are Unix-only modules
30 # Curses and termios are Unix-only modules
31 try:
31 try:
32 import curses
32 import curses
33 # We need termios as well, so if its import happens to raise, we bail on
33 # We need termios as well, so if its import happens to raise, we bail on
34 # using curses altogether.
34 # using curses altogether.
35 import termios
35 import termios
36 except ImportError:
36 except ImportError:
37 USE_CURSES = False
37 USE_CURSES = False
38 else:
38 else:
39 # Curses on Solaris may not be complete, so we can't use it there
39 # Curses on Solaris may not be complete, so we can't use it there
40 USE_CURSES = hasattr(curses,'initscr')
40 USE_CURSES = hasattr(curses,'initscr')
41
41
42 # Other IPython utilities
42 # Other IPython utilities
43 import IPython
43 import IPython
44 from IPython.external.Itpl import itpl,printpl
44 from IPython.external.Itpl import itpl,printpl
45 from IPython.utils import platutils
45 from IPython.utils import platutils
46 from IPython.utils.generics import result_display
46 from IPython.utils.generics import result_display
47 from IPython.external.path import path
47 from IPython.external.path import path
48
48
49 try:
49 try:
50 set
50 set
51 except:
51 except:
52 from sets import Set as set
52 from sets import Set as set
53
53
54
54
55 #****************************************************************************
55 #****************************************************************************
56 # Exceptions
56 # Exceptions
57 class Error(Exception):
57 class Error(Exception):
58 """Base class for exceptions in this module."""
58 """Base class for exceptions in this module."""
59 pass
59 pass
60
60
61 #----------------------------------------------------------------------------
61 #----------------------------------------------------------------------------
62 class IOStream:
62 class IOStream:
63 def __init__(self,stream,fallback):
63 def __init__(self,stream,fallback):
64 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
64 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
65 stream = fallback
65 stream = fallback
66 self.stream = stream
66 self.stream = stream
67 self._swrite = stream.write
67 self._swrite = stream.write
68 self.flush = stream.flush
68 self.flush = stream.flush
69
69
70 def write(self,data):
70 def write(self,data):
71 try:
71 try:
72 self._swrite(data)
72 self._swrite(data)
73 except:
73 except:
74 try:
74 try:
75 # print handles some unicode issues which may trip a plain
75 # print handles some unicode issues which may trip a plain
76 # write() call. Attempt to emulate write() by using a
76 # write() call. Attempt to emulate write() by using a
77 # trailing comma
77 # trailing comma
78 print >> self.stream, data,
78 print >> self.stream, data,
79 except:
79 except:
80 # if we get here, something is seriously broken.
80 # if we get here, something is seriously broken.
81 print >> sys.stderr, \
81 print >> sys.stderr, \
82 'ERROR - failed to write data to stream:', self.stream
82 'ERROR - failed to write data to stream:', self.stream
83
83
84 def close(self):
84 def close(self):
85 pass
85 pass
86
86
87
87
88 class IOTerm:
88 class IOTerm:
89 """ Term holds the file or file-like objects for handling I/O operations.
89 """ Term holds the file or file-like objects for handling I/O operations.
90
90
91 These are normally just sys.stdin, sys.stdout and sys.stderr but for
91 These are normally just sys.stdin, sys.stdout and sys.stderr but for
92 Windows they can can replaced to allow editing the strings before they are
92 Windows they can can replaced to allow editing the strings before they are
93 displayed."""
93 displayed."""
94
94
95 # In the future, having IPython channel all its I/O operations through
95 # In the future, having IPython channel all its I/O operations through
96 # this class will make it easier to embed it into other environments which
96 # this class will make it easier to embed it into other environments which
97 # are not a normal terminal (such as a GUI-based shell)
97 # are not a normal terminal (such as a GUI-based shell)
98 def __init__(self,cin=None,cout=None,cerr=None):
98 def __init__(self,cin=None,cout=None,cerr=None):
99 self.cin = IOStream(cin,sys.stdin)
99 self.cin = IOStream(cin,sys.stdin)
100 self.cout = IOStream(cout,sys.stdout)
100 self.cout = IOStream(cout,sys.stdout)
101 self.cerr = IOStream(cerr,sys.stderr)
101 self.cerr = IOStream(cerr,sys.stderr)
102
102
103 # Global variable to be used for all I/O
103 # Global variable to be used for all I/O
104 Term = IOTerm()
104 Term = IOTerm()
105
105
106 import IPython.utils.rlineimpl as readline
106 import IPython.utils.rlineimpl as readline
107 # Remake Term to use the readline i/o facilities
107 # Remake Term to use the readline i/o facilities
108 if sys.platform == 'win32' and readline.have_readline:
108 if sys.platform == 'win32' and readline.have_readline:
109
109
110 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
110 Term = IOTerm(cout=readline._outputfile,cerr=readline._outputfile)
111
111
112
112
113 #****************************************************************************
113 #****************************************************************************
114 # Generic warning/error printer, used by everything else
114 # Generic warning/error printer, used by everything else
115 def warn(msg,level=2,exit_val=1):
115 def warn(msg,level=2,exit_val=1):
116 """Standard warning printer. Gives formatting consistency.
116 """Standard warning printer. Gives formatting consistency.
117
117
118 Output is sent to Term.cerr (sys.stderr by default).
118 Output is sent to Term.cerr (sys.stderr by default).
119
119
120 Options:
120 Options:
121
121
122 -level(2): allows finer control:
122 -level(2): allows finer control:
123 0 -> Do nothing, dummy function.
123 0 -> Do nothing, dummy function.
124 1 -> Print message.
124 1 -> Print message.
125 2 -> Print 'WARNING:' + message. (Default level).
125 2 -> Print 'WARNING:' + message. (Default level).
126 3 -> Print 'ERROR:' + message.
126 3 -> Print 'ERROR:' + message.
127 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
127 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
128
128
129 -exit_val (1): exit value returned by sys.exit() for a level 4
129 -exit_val (1): exit value returned by sys.exit() for a level 4
130 warning. Ignored for all other levels."""
130 warning. Ignored for all other levels."""
131
131
132 if level>0:
132 if level>0:
133 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
133 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
134 print >> Term.cerr, '%s%s' % (header[level],msg)
134 print >> Term.cerr, '%s%s' % (header[level],msg)
135 if level == 4:
135 if level == 4:
136 print >> Term.cerr,'Exiting.\n'
136 print >> Term.cerr,'Exiting.\n'
137 sys.exit(exit_val)
137 sys.exit(exit_val)
138
138
139 def info(msg):
139 def info(msg):
140 """Equivalent to warn(msg,level=1)."""
140 """Equivalent to warn(msg,level=1)."""
141
141
142 warn(msg,level=1)
142 warn(msg,level=1)
143
143
144 def error(msg):
144 def error(msg):
145 """Equivalent to warn(msg,level=3)."""
145 """Equivalent to warn(msg,level=3)."""
146
146
147 warn(msg,level=3)
147 warn(msg,level=3)
148
148
149 def fatal(msg,exit_val=1):
149 def fatal(msg,exit_val=1):
150 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
150 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
151
151
152 warn(msg,exit_val=exit_val,level=4)
152 warn(msg,exit_val=exit_val,level=4)
153
153
154 #---------------------------------------------------------------------------
154 #---------------------------------------------------------------------------
155 # Debugging routines
155 # Debugging routines
156 #
156 #
157 def debugx(expr,pre_msg=''):
157 def debugx(expr,pre_msg=''):
158 """Print the value of an expression from the caller's frame.
158 """Print the value of an expression from the caller's frame.
159
159
160 Takes an expression, evaluates it in the caller's frame and prints both
160 Takes an expression, evaluates it in the caller's frame and prints both
161 the given expression and the resulting value (as well as a debug mark
161 the given expression and the resulting value (as well as a debug mark
162 indicating the name of the calling function. The input must be of a form
162 indicating the name of the calling function. The input must be of a form
163 suitable for eval().
163 suitable for eval().
164
164
165 An optional message can be passed, which will be prepended to the printed
165 An optional message can be passed, which will be prepended to the printed
166 expr->value pair."""
166 expr->value pair."""
167
167
168 cf = sys._getframe(1)
168 cf = sys._getframe(1)
169 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
169 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
170 eval(expr,cf.f_globals,cf.f_locals))
170 eval(expr,cf.f_globals,cf.f_locals))
171
171
172 # deactivate it by uncommenting the following line, which makes it a no-op
172 # deactivate it by uncommenting the following line, which makes it a no-op
173 #def debugx(expr,pre_msg=''): pass
173 #def debugx(expr,pre_msg=''): pass
174
174
175 #----------------------------------------------------------------------------
175 #----------------------------------------------------------------------------
176 StringTypes = types.StringTypes
176 StringTypes = types.StringTypes
177
177
178 # Basic timing functionality
178 # Basic timing functionality
179
179
180 # If possible (Unix), use the resource module instead of time.clock()
180 # If possible (Unix), use the resource module instead of time.clock()
181 try:
181 try:
182 import resource
182 import resource
183 def clocku():
183 def clocku():
184 """clocku() -> floating point number
184 """clocku() -> floating point number
185
185
186 Return the *USER* CPU time in seconds since the start of the process.
186 Return the *USER* CPU time in seconds since the start of the process.
187 This is done via a call to resource.getrusage, so it avoids the
187 This is done via a call to resource.getrusage, so it avoids the
188 wraparound problems in time.clock()."""
188 wraparound problems in time.clock()."""
189
189
190 return resource.getrusage(resource.RUSAGE_SELF)[0]
190 return resource.getrusage(resource.RUSAGE_SELF)[0]
191
191
192 def clocks():
192 def clocks():
193 """clocks() -> floating point number
193 """clocks() -> floating point number
194
194
195 Return the *SYSTEM* CPU time in seconds since the start of the process.
195 Return the *SYSTEM* CPU time in seconds since the start of the process.
196 This is done via a call to resource.getrusage, so it avoids the
196 This is done via a call to resource.getrusage, so it avoids the
197 wraparound problems in time.clock()."""
197 wraparound problems in time.clock()."""
198
198
199 return resource.getrusage(resource.RUSAGE_SELF)[1]
199 return resource.getrusage(resource.RUSAGE_SELF)[1]
200
200
201 def clock():
201 def clock():
202 """clock() -> floating point number
202 """clock() -> floating point number
203
203
204 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
204 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
205 the process. This is done via a call to resource.getrusage, so it
205 the process. This is done via a call to resource.getrusage, so it
206 avoids the wraparound problems in time.clock()."""
206 avoids the wraparound problems in time.clock()."""
207
207
208 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
208 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
209 return u+s
209 return u+s
210
210
211 def clock2():
211 def clock2():
212 """clock2() -> (t_user,t_system)
212 """clock2() -> (t_user,t_system)
213
213
214 Similar to clock(), but return a tuple of user/system times."""
214 Similar to clock(), but return a tuple of user/system times."""
215 return resource.getrusage(resource.RUSAGE_SELF)[:2]
215 return resource.getrusage(resource.RUSAGE_SELF)[:2]
216
216
217 except ImportError:
217 except ImportError:
218 # There is no distinction of user/system time under windows, so we just use
218 # There is no distinction of user/system time under windows, so we just use
219 # time.clock() for everything...
219 # time.clock() for everything...
220 clocku = clocks = clock = time.clock
220 clocku = clocks = clock = time.clock
221 def clock2():
221 def clock2():
222 """Under windows, system CPU time can't be measured.
222 """Under windows, system CPU time can't be measured.
223
223
224 This just returns clock() and zero."""
224 This just returns clock() and zero."""
225 return time.clock(),0.0
225 return time.clock(),0.0
226
226
227 def timings_out(reps,func,*args,**kw):
227 def timings_out(reps,func,*args,**kw):
228 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
228 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
229
229
230 Execute a function reps times, return a tuple with the elapsed total
230 Execute a function reps times, return a tuple with the elapsed total
231 CPU time in seconds, the time per call and the function's output.
231 CPU time in seconds, the time per call and the function's output.
232
232
233 Under Unix, the return value is the sum of user+system time consumed by
233 Under Unix, the return value is the sum of user+system time consumed by
234 the process, computed via the resource module. This prevents problems
234 the process, computed via the resource module. This prevents problems
235 related to the wraparound effect which the time.clock() function has.
235 related to the wraparound effect which the time.clock() function has.
236
236
237 Under Windows the return value is in wall clock seconds. See the
237 Under Windows the return value is in wall clock seconds. See the
238 documentation for the time module for more details."""
238 documentation for the time module for more details."""
239
239
240 reps = int(reps)
240 reps = int(reps)
241 assert reps >=1, 'reps must be >= 1'
241 assert reps >=1, 'reps must be >= 1'
242 if reps==1:
242 if reps==1:
243 start = clock()
243 start = clock()
244 out = func(*args,**kw)
244 out = func(*args,**kw)
245 tot_time = clock()-start
245 tot_time = clock()-start
246 else:
246 else:
247 rng = xrange(reps-1) # the last time is executed separately to store output
247 rng = xrange(reps-1) # the last time is executed separately to store output
248 start = clock()
248 start = clock()
249 for dummy in rng: func(*args,**kw)
249 for dummy in rng: func(*args,**kw)
250 out = func(*args,**kw) # one last time
250 out = func(*args,**kw) # one last time
251 tot_time = clock()-start
251 tot_time = clock()-start
252 av_time = tot_time / reps
252 av_time = tot_time / reps
253 return tot_time,av_time,out
253 return tot_time,av_time,out
254
254
255 def timings(reps,func,*args,**kw):
255 def timings(reps,func,*args,**kw):
256 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
256 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
257
257
258 Execute a function reps times, return a tuple with the elapsed total CPU
258 Execute a function reps times, return a tuple with the elapsed total CPU
259 time in seconds and the time per call. These are just the first two values
259 time in seconds and the time per call. These are just the first two values
260 in timings_out()."""
260 in timings_out()."""
261
261
262 return timings_out(reps,func,*args,**kw)[0:2]
262 return timings_out(reps,func,*args,**kw)[0:2]
263
263
264 def timing(func,*args,**kw):
264 def timing(func,*args,**kw):
265 """timing(func,*args,**kw) -> t_total
265 """timing(func,*args,**kw) -> t_total
266
266
267 Execute a function once, return the elapsed total CPU time in
267 Execute a function once, return the elapsed total CPU time in
268 seconds. This is just the first value in timings_out()."""
268 seconds. This is just the first value in timings_out()."""
269
269
270 return timings_out(1,func,*args,**kw)[0]
270 return timings_out(1,func,*args,**kw)[0]
271
271
272 #****************************************************************************
272 #****************************************************************************
273 # file and system
273 # file and system
274
274
275 def arg_split(s,posix=False):
275 def arg_split(s,posix=False):
276 """Split a command line's arguments in a shell-like manner.
276 """Split a command line's arguments in a shell-like manner.
277
277
278 This is a modified version of the standard library's shlex.split()
278 This is a modified version of the standard library's shlex.split()
279 function, but with a default of posix=False for splitting, so that quotes
279 function, but with a default of posix=False for splitting, so that quotes
280 in inputs are respected."""
280 in inputs are respected."""
281
281
282 # XXX - there may be unicode-related problems here!!! I'm not sure that
282 # XXX - there may be unicode-related problems here!!! I'm not sure that
283 # shlex is truly unicode-safe, so it might be necessary to do
283 # shlex is truly unicode-safe, so it might be necessary to do
284 #
284 #
285 # s = s.encode(sys.stdin.encoding)
285 # s = s.encode(sys.stdin.encoding)
286 #
286 #
287 # first, to ensure that shlex gets a normal string. Input from anyone who
287 # first, to ensure that shlex gets a normal string. Input from anyone who
288 # knows more about unicode and shlex than I would be good to have here...
288 # knows more about unicode and shlex than I would be good to have here...
289 lex = shlex.shlex(s, posix=posix)
289 lex = shlex.shlex(s, posix=posix)
290 lex.whitespace_split = True
290 lex.whitespace_split = True
291 return list(lex)
291 return list(lex)
292
292
293 def system(cmd,verbose=0,debug=0,header=''):
293 def system(cmd,verbose=0,debug=0,header=''):
294 """Execute a system command, return its exit status.
294 """Execute a system command, return its exit status.
295
295
296 Options:
296 Options:
297
297
298 - verbose (0): print the command to be executed.
298 - verbose (0): print the command to be executed.
299
299
300 - debug (0): only print, do not actually execute.
300 - debug (0): only print, do not actually execute.
301
301
302 - header (''): Header to print on screen prior to the executed command (it
302 - header (''): Header to print on screen prior to the executed command (it
303 is only prepended to the command, no newlines are added).
303 is only prepended to the command, no newlines are added).
304
304
305 Note: a stateful version of this function is available through the
305 Note: a stateful version of this function is available through the
306 SystemExec class."""
306 SystemExec class."""
307
307
308 stat = 0
308 stat = 0
309 if verbose or debug: print header+cmd
309 if verbose or debug: print header+cmd
310 sys.stdout.flush()
310 sys.stdout.flush()
311 if not debug: stat = os.system(cmd)
311 if not debug: stat = os.system(cmd)
312 return stat
312 return stat
313
313
314 def abbrev_cwd():
314 def abbrev_cwd():
315 """ Return abbreviated version of cwd, e.g. d:mydir """
315 """ Return abbreviated version of cwd, e.g. d:mydir """
316 cwd = os.getcwd().replace('\\','/')
316 cwd = os.getcwd().replace('\\','/')
317 drivepart = ''
317 drivepart = ''
318 tail = cwd
318 tail = cwd
319 if sys.platform == 'win32':
319 if sys.platform == 'win32':
320 if len(cwd) < 4:
320 if len(cwd) < 4:
321 return cwd
321 return cwd
322 drivepart,tail = os.path.splitdrive(cwd)
322 drivepart,tail = os.path.splitdrive(cwd)
323
323
324
324
325 parts = tail.split('/')
325 parts = tail.split('/')
326 if len(parts) > 2:
326 if len(parts) > 2:
327 tail = '/'.join(parts[-2:])
327 tail = '/'.join(parts[-2:])
328
328
329 return (drivepart + (
329 return (drivepart + (
330 cwd == '/' and '/' or tail))
330 cwd == '/' and '/' or tail))
331
331
332
332
333 # This function is used by ipython in a lot of places to make system calls.
333 # This function is used by ipython in a lot of places to make system calls.
334 # We need it to be slightly different under win32, due to the vagaries of
334 # We need it to be slightly different under win32, due to the vagaries of
335 # 'network shares'. A win32 override is below.
335 # 'network shares'. A win32 override is below.
336
336
337 def shell(cmd,verbose=0,debug=0,header=''):
337 def shell(cmd,verbose=0,debug=0,header=''):
338 """Execute a command in the system shell, always return None.
338 """Execute a command in the system shell, always return None.
339
339
340 Options:
340 Options:
341
341
342 - verbose (0): print the command to be executed.
342 - verbose (0): print the command to be executed.
343
343
344 - debug (0): only print, do not actually execute.
344 - debug (0): only print, do not actually execute.
345
345
346 - header (''): Header to print on screen prior to the executed command (it
346 - header (''): Header to print on screen prior to the executed command (it
347 is only prepended to the command, no newlines are added).
347 is only prepended to the command, no newlines are added).
348
348
349 Note: this is similar to genutils.system(), but it returns None so it can
349 Note: this is similar to genutils.system(), but it returns None so it can
350 be conveniently used in interactive loops without getting the return value
350 be conveniently used in interactive loops without getting the return value
351 (typically 0) printed many times."""
351 (typically 0) printed many times."""
352
352
353 stat = 0
353 stat = 0
354 if verbose or debug: print header+cmd
354 if verbose or debug: print header+cmd
355 # flush stdout so we don't mangle python's buffering
355 # flush stdout so we don't mangle python's buffering
356 sys.stdout.flush()
356 sys.stdout.flush()
357
357
358 if not debug:
358 if not debug:
359 platutils.set_term_title("IPy " + cmd)
359 platutils.set_term_title("IPy " + cmd)
360 os.system(cmd)
360 os.system(cmd)
361 platutils.set_term_title("IPy " + abbrev_cwd())
361 platutils.set_term_title("IPy " + abbrev_cwd())
362
362
363 # override shell() for win32 to deal with network shares
363 # override shell() for win32 to deal with network shares
364 if os.name in ('nt','dos'):
364 if os.name in ('nt','dos'):
365
365
366 shell_ori = shell
366 shell_ori = shell
367
367
368 def shell(cmd,verbose=0,debug=0,header=''):
368 def shell(cmd,verbose=0,debug=0,header=''):
369 if os.getcwd().startswith(r"\\"):
369 if os.getcwd().startswith(r"\\"):
370 path = os.getcwd()
370 path = os.getcwd()
371 # change to c drive (cannot be on UNC-share when issuing os.system,
371 # change to c drive (cannot be on UNC-share when issuing os.system,
372 # as cmd.exe cannot handle UNC addresses)
372 # as cmd.exe cannot handle UNC addresses)
373 os.chdir("c:")
373 os.chdir("c:")
374 # issue pushd to the UNC-share and then run the command
374 # issue pushd to the UNC-share and then run the command
375 try:
375 try:
376 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
376 shell_ori('"pushd %s&&"'%path+cmd,verbose,debug,header)
377 finally:
377 finally:
378 os.chdir(path)
378 os.chdir(path)
379 else:
379 else:
380 shell_ori(cmd,verbose,debug,header)
380 shell_ori(cmd,verbose,debug,header)
381
381
382 shell.__doc__ = shell_ori.__doc__
382 shell.__doc__ = shell_ori.__doc__
383
383
384 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
384 def getoutput(cmd,verbose=0,debug=0,header='',split=0):
385 """Dummy substitute for perl's backquotes.
385 """Dummy substitute for perl's backquotes.
386
386
387 Executes a command and returns the output.
387 Executes a command and returns the output.
388
388
389 Accepts the same arguments as system(), plus:
389 Accepts the same arguments as system(), plus:
390
390
391 - split(0): if true, the output is returned as a list split on newlines.
391 - split(0): if true, the output is returned as a list split on newlines.
392
392
393 Note: a stateful version of this function is available through the
393 Note: a stateful version of this function is available through the
394 SystemExec class.
394 SystemExec class.
395
395
396 This is pretty much deprecated and rarely used,
396 This is pretty much deprecated and rarely used,
397 genutils.getoutputerror may be what you need.
397 genutils.getoutputerror may be what you need.
398
398
399 """
399 """
400
400
401 if verbose or debug: print header+cmd
401 if verbose or debug: print header+cmd
402 if not debug:
402 if not debug:
403 output = os.popen(cmd).read()
403 output = os.popen(cmd).read()
404 # stipping last \n is here for backwards compat.
404 # stipping last \n is here for backwards compat.
405 if output.endswith('\n'):
405 if output.endswith('\n'):
406 output = output[:-1]
406 output = output[:-1]
407 if split:
407 if split:
408 return output.split('\n')
408 return output.split('\n')
409 else:
409 else:
410 return output
410 return output
411
411
412 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
412 def getoutputerror(cmd,verbose=0,debug=0,header='',split=0):
413 """Return (standard output,standard error) of executing cmd in a shell.
413 """Return (standard output,standard error) of executing cmd in a shell.
414
414
415 Accepts the same arguments as system(), plus:
415 Accepts the same arguments as system(), plus:
416
416
417 - split(0): if true, each of stdout/err is returned as a list split on
417 - split(0): if true, each of stdout/err is returned as a list split on
418 newlines.
418 newlines.
419
419
420 Note: a stateful version of this function is available through the
420 Note: a stateful version of this function is available through the
421 SystemExec class."""
421 SystemExec class."""
422
422
423 if verbose or debug: print header+cmd
423 if verbose or debug: print header+cmd
424 if not cmd:
424 if not cmd:
425 if split:
425 if split:
426 return [],[]
426 return [],[]
427 else:
427 else:
428 return '',''
428 return '',''
429 if not debug:
429 if not debug:
430 pin,pout,perr = os.popen3(cmd)
430 pin,pout,perr = os.popen3(cmd)
431 tout = pout.read().rstrip()
431 tout = pout.read().rstrip()
432 terr = perr.read().rstrip()
432 terr = perr.read().rstrip()
433 pin.close()
433 pin.close()
434 pout.close()
434 pout.close()
435 perr.close()
435 perr.close()
436 if split:
436 if split:
437 return tout.split('\n'),terr.split('\n')
437 return tout.split('\n'),terr.split('\n')
438 else:
438 else:
439 return tout,terr
439 return tout,terr
440
440
441 # for compatibility with older naming conventions
441 # for compatibility with older naming conventions
442 xsys = system
442 xsys = system
443 bq = getoutput
443 bq = getoutput
444
444
445 class SystemExec:
445 class SystemExec:
446 """Access the system and getoutput functions through a stateful interface.
446 """Access the system and getoutput functions through a stateful interface.
447
447
448 Note: here we refer to the system and getoutput functions from this
448 Note: here we refer to the system and getoutput functions from this
449 library, not the ones from the standard python library.
449 library, not the ones from the standard python library.
450
450
451 This class offers the system and getoutput functions as methods, but the
451 This class offers the system and getoutput functions as methods, but the
452 verbose, debug and header parameters can be set for the instance (at
452 verbose, debug and header parameters can be set for the instance (at
453 creation time or later) so that they don't need to be specified on each
453 creation time or later) so that they don't need to be specified on each
454 call.
454 call.
455
455
456 For efficiency reasons, there's no way to override the parameters on a
456 For efficiency reasons, there's no way to override the parameters on a
457 per-call basis other than by setting instance attributes. If you need
457 per-call basis other than by setting instance attributes. If you need
458 local overrides, it's best to directly call system() or getoutput().
458 local overrides, it's best to directly call system() or getoutput().
459
459
460 The following names are provided as alternate options:
460 The following names are provided as alternate options:
461 - xsys: alias to system
461 - xsys: alias to system
462 - bq: alias to getoutput
462 - bq: alias to getoutput
463
463
464 An instance can then be created as:
464 An instance can then be created as:
465 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
465 >>> sysexec = SystemExec(verbose=1,debug=0,header='Calling: ')
466 """
466 """
467
467
468 def __init__(self,verbose=0,debug=0,header='',split=0):
468 def __init__(self,verbose=0,debug=0,header='',split=0):
469 """Specify the instance's values for verbose, debug and header."""
469 """Specify the instance's values for verbose, debug and header."""
470 setattr_list(self,'verbose debug header split')
470 setattr_list(self,'verbose debug header split')
471
471
472 def system(self,cmd):
472 def system(self,cmd):
473 """Stateful interface to system(), with the same keyword parameters."""
473 """Stateful interface to system(), with the same keyword parameters."""
474
474
475 system(cmd,self.verbose,self.debug,self.header)
475 system(cmd,self.verbose,self.debug,self.header)
476
476
477 def shell(self,cmd):
477 def shell(self,cmd):
478 """Stateful interface to shell(), with the same keyword parameters."""
478 """Stateful interface to shell(), with the same keyword parameters."""
479
479
480 shell(cmd,self.verbose,self.debug,self.header)
480 shell(cmd,self.verbose,self.debug,self.header)
481
481
482 xsys = system # alias
482 xsys = system # alias
483
483
484 def getoutput(self,cmd):
484 def getoutput(self,cmd):
485 """Stateful interface to getoutput()."""
485 """Stateful interface to getoutput()."""
486
486
487 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
487 return getoutput(cmd,self.verbose,self.debug,self.header,self.split)
488
488
489 def getoutputerror(self,cmd):
489 def getoutputerror(self,cmd):
490 """Stateful interface to getoutputerror()."""
490 """Stateful interface to getoutputerror()."""
491
491
492 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
492 return getoutputerror(cmd,self.verbose,self.debug,self.header,self.split)
493
493
494 bq = getoutput # alias
494 bq = getoutput # alias
495
495
496 #-----------------------------------------------------------------------------
496 #-----------------------------------------------------------------------------
497 def mutex_opts(dict,ex_op):
497 def mutex_opts(dict,ex_op):
498 """Check for presence of mutually exclusive keys in a dict.
498 """Check for presence of mutually exclusive keys in a dict.
499
499
500 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
500 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
501 for op1,op2 in ex_op:
501 for op1,op2 in ex_op:
502 if op1 in dict and op2 in dict:
502 if op1 in dict and op2 in dict:
503 raise ValueError,'\n*** ERROR in Arguments *** '\
503 raise ValueError,'\n*** ERROR in Arguments *** '\
504 'Options '+op1+' and '+op2+' are mutually exclusive.'
504 'Options '+op1+' and '+op2+' are mutually exclusive.'
505
505
506 #-----------------------------------------------------------------------------
506 #-----------------------------------------------------------------------------
507 def get_py_filename(name):
507 def get_py_filename(name):
508 """Return a valid python filename in the current directory.
508 """Return a valid python filename in the current directory.
509
509
510 If the given name is not a file, it adds '.py' and searches again.
510 If the given name is not a file, it adds '.py' and searches again.
511 Raises IOError with an informative message if the file isn't found."""
511 Raises IOError with an informative message if the file isn't found."""
512
512
513 name = os.path.expanduser(name)
513 name = os.path.expanduser(name)
514 if not os.path.isfile(name) and not name.endswith('.py'):
514 if not os.path.isfile(name) and not name.endswith('.py'):
515 name += '.py'
515 name += '.py'
516 if os.path.isfile(name):
516 if os.path.isfile(name):
517 return name
517 return name
518 else:
518 else:
519 raise IOError,'File `%s` not found.' % name
519 raise IOError,'File `%s` not found.' % name
520
520
521 #-----------------------------------------------------------------------------
521 #-----------------------------------------------------------------------------
522
522
523
523
524 def filefind(filename, path_dirs=None):
524 def filefind(filename, path_dirs=None):
525 """Find a file by looking through a sequence of paths.
525 """Find a file by looking through a sequence of paths.
526
526
527 This iterates through a sequence of paths looking for a file and returns
527 This iterates through a sequence of paths looking for a file and returns
528 the full, absolute path of the first occurence of the file. If no set of
528 the full, absolute path of the first occurence of the file. If no set of
529 path dirs is given, the filename is tested as is, after running through
529 path dirs is given, the filename is tested as is, after running through
530 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
530 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
531
531
532 filefind('myfile.txt')
532 filefind('myfile.txt')
533
533
534 will find the file in the current working dir, but::
534 will find the file in the current working dir, but::
535
535
536 filefind('~/myfile.txt')
536 filefind('~/myfile.txt')
537
537
538 Will find the file in the users home directory. This function does not
538 Will find the file in the users home directory. This function does not
539 automatically try any paths, such as the cwd or the user's home directory.
539 automatically try any paths, such as the cwd or the user's home directory.
540
540
541 Parameters
541 Parameters
542 ----------
542 ----------
543 filename : str
543 filename : str
544 The filename to look for.
544 The filename to look for.
545 path_dirs : str, None or sequence of str
545 path_dirs : str, None or sequence of str
546 The sequence of paths to look for the file in. If None, the filename
546 The sequence of paths to look for the file in. If None, the filename
547 need to be absolute or be in the cwd. If a string, the string is
547 need to be absolute or be in the cwd. If a string, the string is
548 put into a sequence and the searched. If a sequence, walk through
548 put into a sequence and the searched. If a sequence, walk through
549 each element and join with ``filename``, calling :func:`expandvars`
549 each element and join with ``filename``, calling :func:`expandvars`
550 and :func:`expanduser` before testing for existence.
550 and :func:`expanduser` before testing for existence.
551
551
552 Returns
552 Returns
553 -------
553 -------
554 Raises :exc:`IOError` or returns absolute path to file.
554 Raises :exc:`IOError` or returns absolute path to file.
555 """
555 """
556 if path_dirs is None:
556 if path_dirs is None:
557 path_dirs = ("",)
557 path_dirs = ("",)
558 elif isinstance(path_dirs, basestring):
558 elif isinstance(path_dirs, basestring):
559 path_dirs = (path_dirs,)
559 path_dirs = (path_dirs,)
560 for path in path_dirs:
560 for path in path_dirs:
561 if path == '.': path = os.getcwd()
561 if path == '.': path = os.getcwd()
562 testname = os.path.expandvars(
562 testname = os.path.expandvars(
563 os.path.expanduser(
563 os.path.expanduser(
564 os.path.join(path, filename)))
564 os.path.join(path, filename)))
565 if os.path.isfile(testname):
565 if os.path.isfile(testname):
566 return os.path.abspath(testname)
566 return os.path.abspath(testname)
567 raise IOError("File does not exist in any "
567 raise IOError("File does not exist in any "
568 "of the search paths: %r, %r" % \
568 "of the search paths: %r, %r" % \
569 (filename, path_dirs))
569 (filename, path_dirs))
570
570
571
571
572 #----------------------------------------------------------------------------
572 #----------------------------------------------------------------------------
573 def file_read(filename):
573 def file_read(filename):
574 """Read a file and close it. Returns the file source."""
574 """Read a file and close it. Returns the file source."""
575 fobj = open(filename,'r');
575 fobj = open(filename,'r');
576 source = fobj.read();
576 source = fobj.read();
577 fobj.close()
577 fobj.close()
578 return source
578 return source
579
579
580 def file_readlines(filename):
580 def file_readlines(filename):
581 """Read a file and close it. Returns the file source using readlines()."""
581 """Read a file and close it. Returns the file source using readlines()."""
582 fobj = open(filename,'r');
582 fobj = open(filename,'r');
583 lines = fobj.readlines();
583 lines = fobj.readlines();
584 fobj.close()
584 fobj.close()
585 return lines
585 return lines
586
586
587 #----------------------------------------------------------------------------
587 #----------------------------------------------------------------------------
588 def target_outdated(target,deps):
588 def target_outdated(target,deps):
589 """Determine whether a target is out of date.
589 """Determine whether a target is out of date.
590
590
591 target_outdated(target,deps) -> 1/0
591 target_outdated(target,deps) -> 1/0
592
592
593 deps: list of filenames which MUST exist.
593 deps: list of filenames which MUST exist.
594 target: single filename which may or may not exist.
594 target: single filename which may or may not exist.
595
595
596 If target doesn't exist or is older than any file listed in deps, return
596 If target doesn't exist or is older than any file listed in deps, return
597 true, otherwise return false.
597 true, otherwise return false.
598 """
598 """
599 try:
599 try:
600 target_time = os.path.getmtime(target)
600 target_time = os.path.getmtime(target)
601 except os.error:
601 except os.error:
602 return 1
602 return 1
603 for dep in deps:
603 for dep in deps:
604 dep_time = os.path.getmtime(dep)
604 dep_time = os.path.getmtime(dep)
605 if dep_time > target_time:
605 if dep_time > target_time:
606 #print "For target",target,"Dep failed:",dep # dbg
606 #print "For target",target,"Dep failed:",dep # dbg
607 #print "times (dep,tar):",dep_time,target_time # dbg
607 #print "times (dep,tar):",dep_time,target_time # dbg
608 return 1
608 return 1
609 return 0
609 return 0
610
610
611 #-----------------------------------------------------------------------------
611 #-----------------------------------------------------------------------------
612 def target_update(target,deps,cmd):
612 def target_update(target,deps,cmd):
613 """Update a target with a given command given a list of dependencies.
613 """Update a target with a given command given a list of dependencies.
614
614
615 target_update(target,deps,cmd) -> runs cmd if target is outdated.
615 target_update(target,deps,cmd) -> runs cmd if target is outdated.
616
616
617 This is just a wrapper around target_outdated() which calls the given
617 This is just a wrapper around target_outdated() which calls the given
618 command if target is outdated."""
618 command if target is outdated."""
619
619
620 if target_outdated(target,deps):
620 if target_outdated(target,deps):
621 xsys(cmd)
621 xsys(cmd)
622
622
623 #----------------------------------------------------------------------------
623 #----------------------------------------------------------------------------
624 def unquote_ends(istr):
624 def unquote_ends(istr):
625 """Remove a single pair of quotes from the endpoints of a string."""
625 """Remove a single pair of quotes from the endpoints of a string."""
626
626
627 if not istr:
627 if not istr:
628 return istr
628 return istr
629 if (istr[0]=="'" and istr[-1]=="'") or \
629 if (istr[0]=="'" and istr[-1]=="'") or \
630 (istr[0]=='"' and istr[-1]=='"'):
630 (istr[0]=='"' and istr[-1]=='"'):
631 return istr[1:-1]
631 return istr[1:-1]
632 else:
632 else:
633 return istr
633 return istr
634
634
635 #----------------------------------------------------------------------------
635 #----------------------------------------------------------------------------
636 def flag_calls(func):
636 def flag_calls(func):
637 """Wrap a function to detect and flag when it gets called.
637 """Wrap a function to detect and flag when it gets called.
638
638
639 This is a decorator which takes a function and wraps it in a function with
639 This is a decorator which takes a function and wraps it in a function with
640 a 'called' attribute. wrapper.called is initialized to False.
640 a 'called' attribute. wrapper.called is initialized to False.
641
641
642 The wrapper.called attribute is set to False right before each call to the
642 The wrapper.called attribute is set to False right before each call to the
643 wrapped function, so if the call fails it remains False. After the call
643 wrapped function, so if the call fails it remains False. After the call
644 completes, wrapper.called is set to True and the output is returned.
644 completes, wrapper.called is set to True and the output is returned.
645
645
646 Testing for truth in wrapper.called allows you to determine if a call to
646 Testing for truth in wrapper.called allows you to determine if a call to
647 func() was attempted and succeeded."""
647 func() was attempted and succeeded."""
648
648
649 def wrapper(*args,**kw):
649 def wrapper(*args,**kw):
650 wrapper.called = False
650 wrapper.called = False
651 out = func(*args,**kw)
651 out = func(*args,**kw)
652 wrapper.called = True
652 wrapper.called = True
653 return out
653 return out
654
654
655 wrapper.called = False
655 wrapper.called = False
656 wrapper.__doc__ = func.__doc__
656 wrapper.__doc__ = func.__doc__
657 return wrapper
657 return wrapper
658
658
659 #----------------------------------------------------------------------------
659 #----------------------------------------------------------------------------
660 def dhook_wrap(func,*a,**k):
660 def dhook_wrap(func,*a,**k):
661 """Wrap a function call in a sys.displayhook controller.
661 """Wrap a function call in a sys.displayhook controller.
662
662
663 Returns a wrapper around func which calls func, with all its arguments and
663 Returns a wrapper around func which calls func, with all its arguments and
664 keywords unmodified, using the default sys.displayhook. Since IPython
664 keywords unmodified, using the default sys.displayhook. Since IPython
665 modifies sys.displayhook, it breaks the behavior of certain systems that
665 modifies sys.displayhook, it breaks the behavior of certain systems that
666 rely on the default behavior, notably doctest.
666 rely on the default behavior, notably doctest.
667 """
667 """
668
668
669 def f(*a,**k):
669 def f(*a,**k):
670
670
671 dhook_s = sys.displayhook
671 dhook_s = sys.displayhook
672 sys.displayhook = sys.__displayhook__
672 sys.displayhook = sys.__displayhook__
673 try:
673 try:
674 out = func(*a,**k)
674 out = func(*a,**k)
675 finally:
675 finally:
676 sys.displayhook = dhook_s
676 sys.displayhook = dhook_s
677
677
678 return out
678 return out
679
679
680 f.__doc__ = func.__doc__
680 f.__doc__ = func.__doc__
681 return f
681 return f
682
682
683 #----------------------------------------------------------------------------
683 #----------------------------------------------------------------------------
684 def doctest_reload():
684 def doctest_reload():
685 """Properly reload doctest to reuse it interactively.
685 """Properly reload doctest to reuse it interactively.
686
686
687 This routine:
687 This routine:
688
688
689 - imports doctest but does NOT reload it (see below).
689 - imports doctest but does NOT reload it (see below).
690
690
691 - resets its global 'master' attribute to None, so that multiple uses of
691 - resets its global 'master' attribute to None, so that multiple uses of
692 the module interactively don't produce cumulative reports.
692 the module interactively don't produce cumulative reports.
693
693
694 - Monkeypatches its core test runner method to protect it from IPython's
694 - Monkeypatches its core test runner method to protect it from IPython's
695 modified displayhook. Doctest expects the default displayhook behavior
695 modified displayhook. Doctest expects the default displayhook behavior
696 deep down, so our modification breaks it completely. For this reason, a
696 deep down, so our modification breaks it completely. For this reason, a
697 hard monkeypatch seems like a reasonable solution rather than asking
697 hard monkeypatch seems like a reasonable solution rather than asking
698 users to manually use a different doctest runner when under IPython.
698 users to manually use a different doctest runner when under IPython.
699
699
700 Notes
700 Notes
701 -----
701 -----
702
702
703 This function *used to* reload doctest, but this has been disabled because
703 This function *used to* reload doctest, but this has been disabled because
704 reloading doctest unconditionally can cause massive breakage of other
704 reloading doctest unconditionally can cause massive breakage of other
705 doctest-dependent modules already in memory, such as those for IPython's
705 doctest-dependent modules already in memory, such as those for IPython's
706 own testing system. The name wasn't changed to avoid breaking people's
706 own testing system. The name wasn't changed to avoid breaking people's
707 code, but the reload call isn't actually made anymore."""
707 code, but the reload call isn't actually made anymore."""
708
708
709 import doctest
709 import doctest
710 doctest.master = None
710 doctest.master = None
711 doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
711 doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
712
712
713 #----------------------------------------------------------------------------
713 #----------------------------------------------------------------------------
714 class HomeDirError(Error):
714 class HomeDirError(Error):
715 pass
715 pass
716
716
717 def get_home_dir():
717 def get_home_dir():
718 """Return the closest possible equivalent to a 'home' directory.
718 """Return the closest possible equivalent to a 'home' directory.
719
719
720 We first try $HOME. Absent that, on NT it's $HOMEDRIVE\$HOMEPATH.
720 * On POSIX, we try $HOME.
721
721 * On Windows we try:
722 - %HOMESHARE%
723 - %HOMEDRIVE\%HOMEPATH%
724 - %USERPROFILE%
725 - Registry hack
726 * On Dos C:\
727
722 Currently only Posix and NT are implemented, a HomeDirError exception is
728 Currently only Posix and NT are implemented, a HomeDirError exception is
723 raised for all other OSes. """
729 raised for all other OSes.
730 """
724
731
725 isdir = os.path.isdir
732 isdir = os.path.isdir
726 env = os.environ
733 env = os.environ
727
734
728 # first, check py2exe distribution root directory for _ipython.
735 # first, check py2exe distribution root directory for _ipython.
729 # This overrides all. Normally does not exist.
736 # This overrides all. Normally does not exist.
730
737
731 if hasattr(sys, "frozen"): #Is frozen by py2exe
738 if hasattr(sys, "frozen"): #Is frozen by py2exe
732 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
739 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
733 root, rest = IPython.__file__.lower().split('library.zip')
740 root, rest = IPython.__file__.lower().split('library.zip')
734 else:
741 else:
735 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
742 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
736 root=os.path.abspath(root).rstrip('\\')
743 root=os.path.abspath(root).rstrip('\\')
737 if isdir(os.path.join(root, '_ipython')):
744 if isdir(os.path.join(root, '_ipython')):
738 os.environ["IPYKITROOT"] = root
745 os.environ["IPYKITROOT"] = root
739 return root.decode(sys.getfilesystemencoding())
746 return root.decode(sys.getfilesystemencoding())
740 try:
747
741 homedir = env['HOME']
748 if os.name == 'posix':
742 if not isdir(homedir):
749 # Linux, Unix, AIX, OS X
743 # in case a user stuck some string which does NOT resolve to a
750 try:
744 # valid path, it's as good as if we hadn't foud it
751 homedir = env['HOME']
745 raise KeyError
752 except KeyError:
746 return homedir.decode(sys.getfilesystemencoding())
753 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
747 except KeyError:
754 else:
748 if os.name == 'posix':
755 return homedir.decode(sys.getfilesystemencoding())
749 raise HomeDirError,'undefined $HOME, IPython can not proceed.'
756 elif os.name == 'nt':
750 elif os.name == 'nt':
757 # Now for win9x, XP, Vista, 7?
751 # For some strange reason, win9x returns 'nt' for os.name.
758 # For some strange reason all of these return 'nt' for os.name.
752 try:
759 # First look for a network home directory. This will return the UNC
753 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
760 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
754 if not isdir(homedir):
761 # is needed when running IPython on cluster where all paths have to
755 homedir = os.path.join(env['USERPROFILE'])
762 # be UNC.
756 if not isdir(homedir):
763 try:
757 raise HomeDirError
764 homedir = env['HOMESHARE']
765 except KeyError:
766 pass
767 else:
768 if isdir(homedir):
758 return homedir.decode(sys.getfilesystemencoding())
769 return homedir.decode(sys.getfilesystemencoding())
759 except KeyError:
770
760 try:
771 # Now look for a local home directory
761 # Use the registry to get the 'My Documents' folder.
772 try:
762 import _winreg as wreg
773 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
763 key = wreg.OpenKey(wreg.HKEY_CURRENT_USER,
774 except KeyError:
764 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
775 pass
765 homedir = wreg.QueryValueEx(key,'Personal')[0]
766 key.Close()
767 if not isdir(homedir):
768 e = ('Invalid "Personal" folder registry key '
769 'typically "My Documents".\n'
770 'Value: %s\n'
771 'This is not a valid directory on your system.' %
772 homedir)
773 raise HomeDirError(e)
774 return homedir.decode(sys.getfilesystemencoding())
775 except HomeDirError:
776 raise
777 except:
778 return 'C:\\'.decode(sys.getfilesystemencoding())
779 elif os.name == 'dos':
780 # Desperate, may do absurd things in classic MacOS. May work under DOS.
781 return 'C:\\'.decode(sys.getfilesystemencoding())
782 else:
776 else:
783 raise HomeDirError,'support for your operating system not implemented.'
777 if isdir(homedir):
778 return homedir.decode(sys.getfilesystemencoding())
779
780 # Now the users profile directory
781 try:
782 homedir = os.path.join(env['USERPROFILE'])
783 except KeyError:
784 pass
785 else:
786 if isdir(homedir):
787 return homedir.decode(sys.getfilesystemencoding())
788
789 # Use the registry to get the 'My Documents' folder.
790 try:
791 import _winreg as wreg
792 key = wreg.OpenKey(
793 wreg.HKEY_CURRENT_USER,
794 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
795 )
796 homedir = wreg.QueryValueEx(key,'Personal')[0]
797 key.Close()
798 except:
799 pass
800 else:
801 if isdir(homedir):
802 return homedir.decode(sys.getfilesystemencoding())
803
804 # If all else fails, raise HomeDirError
805 raise HomeDirError('No valid home directory could be found')
806 elif os.name == 'dos':
807 # Desperate, may do absurd things in classic MacOS. May work under DOS.
808 return 'C:\\'.decode(sys.getfilesystemencoding())
809 else:
810 raise HomeDirError('No valid home directory could be found for your OS')
784
811
785
812
786 def get_ipython_dir():
813 def get_ipython_dir():
787 """Get the IPython directory for this platform and user.
814 """Get the IPython directory for this platform and user.
788
815
789 This uses the logic in `get_home_dir` to find the home directory
816 This uses the logic in `get_home_dir` to find the home directory
790 and the adds .ipython to the end of the path.
817 and the adds .ipython to the end of the path.
791 """
818 """
792 ipdir_def = '.ipython'
819 ipdir_def = '.ipython'
793 home_dir = get_home_dir()
820 home_dir = get_home_dir()
794 ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
821 ipdir = os.path.abspath(os.environ.get('IPYTHONDIR',
795 os.path.join(home_dir, ipdir_def)))
822 os.path.join(home_dir, ipdir_def)))
796 return ipdir.decode(sys.getfilesystemencoding())
823 return ipdir.decode(sys.getfilesystemencoding())
797
824
798
825
799 #****************************************************************************
826 #****************************************************************************
800 # strings and text
827 # strings and text
801
828
802 class LSString(str):
829 class LSString(str):
803 """String derivative with a special access attributes.
830 """String derivative with a special access attributes.
804
831
805 These are normal strings, but with the special attributes:
832 These are normal strings, but with the special attributes:
806
833
807 .l (or .list) : value as list (split on newlines).
834 .l (or .list) : value as list (split on newlines).
808 .n (or .nlstr): original value (the string itself).
835 .n (or .nlstr): original value (the string itself).
809 .s (or .spstr): value as whitespace-separated string.
836 .s (or .spstr): value as whitespace-separated string.
810 .p (or .paths): list of path objects
837 .p (or .paths): list of path objects
811
838
812 Any values which require transformations are computed only once and
839 Any values which require transformations are computed only once and
813 cached.
840 cached.
814
841
815 Such strings are very useful to efficiently interact with the shell, which
842 Such strings are very useful to efficiently interact with the shell, which
816 typically only understands whitespace-separated options for commands."""
843 typically only understands whitespace-separated options for commands."""
817
844
818 def get_list(self):
845 def get_list(self):
819 try:
846 try:
820 return self.__list
847 return self.__list
821 except AttributeError:
848 except AttributeError:
822 self.__list = self.split('\n')
849 self.__list = self.split('\n')
823 return self.__list
850 return self.__list
824
851
825 l = list = property(get_list)
852 l = list = property(get_list)
826
853
827 def get_spstr(self):
854 def get_spstr(self):
828 try:
855 try:
829 return self.__spstr
856 return self.__spstr
830 except AttributeError:
857 except AttributeError:
831 self.__spstr = self.replace('\n',' ')
858 self.__spstr = self.replace('\n',' ')
832 return self.__spstr
859 return self.__spstr
833
860
834 s = spstr = property(get_spstr)
861 s = spstr = property(get_spstr)
835
862
836 def get_nlstr(self):
863 def get_nlstr(self):
837 return self
864 return self
838
865
839 n = nlstr = property(get_nlstr)
866 n = nlstr = property(get_nlstr)
840
867
841 def get_paths(self):
868 def get_paths(self):
842 try:
869 try:
843 return self.__paths
870 return self.__paths
844 except AttributeError:
871 except AttributeError:
845 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
872 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
846 return self.__paths
873 return self.__paths
847
874
848 p = paths = property(get_paths)
875 p = paths = property(get_paths)
849
876
850 def print_lsstring(arg):
877 def print_lsstring(arg):
851 """ Prettier (non-repr-like) and more informative printer for LSString """
878 """ Prettier (non-repr-like) and more informative printer for LSString """
852 print "LSString (.p, .n, .l, .s available). Value:"
879 print "LSString (.p, .n, .l, .s available). Value:"
853 print arg
880 print arg
854
881
855 print_lsstring = result_display.when_type(LSString)(print_lsstring)
882 print_lsstring = result_display.when_type(LSString)(print_lsstring)
856
883
857 #----------------------------------------------------------------------------
884 #----------------------------------------------------------------------------
858 class SList(list):
885 class SList(list):
859 """List derivative with a special access attributes.
886 """List derivative with a special access attributes.
860
887
861 These are normal lists, but with the special attributes:
888 These are normal lists, but with the special attributes:
862
889
863 .l (or .list) : value as list (the list itself).
890 .l (or .list) : value as list (the list itself).
864 .n (or .nlstr): value as a string, joined on newlines.
891 .n (or .nlstr): value as a string, joined on newlines.
865 .s (or .spstr): value as a string, joined on spaces.
892 .s (or .spstr): value as a string, joined on spaces.
866 .p (or .paths): list of path objects
893 .p (or .paths): list of path objects
867
894
868 Any values which require transformations are computed only once and
895 Any values which require transformations are computed only once and
869 cached."""
896 cached."""
870
897
871 def get_list(self):
898 def get_list(self):
872 return self
899 return self
873
900
874 l = list = property(get_list)
901 l = list = property(get_list)
875
902
876 def get_spstr(self):
903 def get_spstr(self):
877 try:
904 try:
878 return self.__spstr
905 return self.__spstr
879 except AttributeError:
906 except AttributeError:
880 self.__spstr = ' '.join(self)
907 self.__spstr = ' '.join(self)
881 return self.__spstr
908 return self.__spstr
882
909
883 s = spstr = property(get_spstr)
910 s = spstr = property(get_spstr)
884
911
885 def get_nlstr(self):
912 def get_nlstr(self):
886 try:
913 try:
887 return self.__nlstr
914 return self.__nlstr
888 except AttributeError:
915 except AttributeError:
889 self.__nlstr = '\n'.join(self)
916 self.__nlstr = '\n'.join(self)
890 return self.__nlstr
917 return self.__nlstr
891
918
892 n = nlstr = property(get_nlstr)
919 n = nlstr = property(get_nlstr)
893
920
894 def get_paths(self):
921 def get_paths(self):
895 try:
922 try:
896 return self.__paths
923 return self.__paths
897 except AttributeError:
924 except AttributeError:
898 self.__paths = [path(p) for p in self if os.path.exists(p)]
925 self.__paths = [path(p) for p in self if os.path.exists(p)]
899 return self.__paths
926 return self.__paths
900
927
901 p = paths = property(get_paths)
928 p = paths = property(get_paths)
902
929
903 def grep(self, pattern, prune = False, field = None):
930 def grep(self, pattern, prune = False, field = None):
904 """ Return all strings matching 'pattern' (a regex or callable)
931 """ Return all strings matching 'pattern' (a regex or callable)
905
932
906 This is case-insensitive. If prune is true, return all items
933 This is case-insensitive. If prune is true, return all items
907 NOT matching the pattern.
934 NOT matching the pattern.
908
935
909 If field is specified, the match must occur in the specified
936 If field is specified, the match must occur in the specified
910 whitespace-separated field.
937 whitespace-separated field.
911
938
912 Examples::
939 Examples::
913
940
914 a.grep( lambda x: x.startswith('C') )
941 a.grep( lambda x: x.startswith('C') )
915 a.grep('Cha.*log', prune=1)
942 a.grep('Cha.*log', prune=1)
916 a.grep('chm', field=-1)
943 a.grep('chm', field=-1)
917 """
944 """
918
945
919 def match_target(s):
946 def match_target(s):
920 if field is None:
947 if field is None:
921 return s
948 return s
922 parts = s.split()
949 parts = s.split()
923 try:
950 try:
924 tgt = parts[field]
951 tgt = parts[field]
925 return tgt
952 return tgt
926 except IndexError:
953 except IndexError:
927 return ""
954 return ""
928
955
929 if isinstance(pattern, basestring):
956 if isinstance(pattern, basestring):
930 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
957 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
931 else:
958 else:
932 pred = pattern
959 pred = pattern
933 if not prune:
960 if not prune:
934 return SList([el for el in self if pred(match_target(el))])
961 return SList([el for el in self if pred(match_target(el))])
935 else:
962 else:
936 return SList([el for el in self if not pred(match_target(el))])
963 return SList([el for el in self if not pred(match_target(el))])
937 def fields(self, *fields):
964 def fields(self, *fields):
938 """ Collect whitespace-separated fields from string list
965 """ Collect whitespace-separated fields from string list
939
966
940 Allows quick awk-like usage of string lists.
967 Allows quick awk-like usage of string lists.
941
968
942 Example data (in var a, created by 'a = !ls -l')::
969 Example data (in var a, created by 'a = !ls -l')::
943 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
970 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
944 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
971 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
945
972
946 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
973 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
947 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
974 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
948 (note the joining by space).
975 (note the joining by space).
949 a.fields(-1) is ['ChangeLog', 'IPython']
976 a.fields(-1) is ['ChangeLog', 'IPython']
950
977
951 IndexErrors are ignored.
978 IndexErrors are ignored.
952
979
953 Without args, fields() just split()'s the strings.
980 Without args, fields() just split()'s the strings.
954 """
981 """
955 if len(fields) == 0:
982 if len(fields) == 0:
956 return [el.split() for el in self]
983 return [el.split() for el in self]
957
984
958 res = SList()
985 res = SList()
959 for el in [f.split() for f in self]:
986 for el in [f.split() for f in self]:
960 lineparts = []
987 lineparts = []
961
988
962 for fd in fields:
989 for fd in fields:
963 try:
990 try:
964 lineparts.append(el[fd])
991 lineparts.append(el[fd])
965 except IndexError:
992 except IndexError:
966 pass
993 pass
967 if lineparts:
994 if lineparts:
968 res.append(" ".join(lineparts))
995 res.append(" ".join(lineparts))
969
996
970 return res
997 return res
971 def sort(self,field= None, nums = False):
998 def sort(self,field= None, nums = False):
972 """ sort by specified fields (see fields())
999 """ sort by specified fields (see fields())
973
1000
974 Example::
1001 Example::
975 a.sort(1, nums = True)
1002 a.sort(1, nums = True)
976
1003
977 Sorts a by second field, in numerical order (so that 21 > 3)
1004 Sorts a by second field, in numerical order (so that 21 > 3)
978
1005
979 """
1006 """
980
1007
981 #decorate, sort, undecorate
1008 #decorate, sort, undecorate
982 if field is not None:
1009 if field is not None:
983 dsu = [[SList([line]).fields(field), line] for line in self]
1010 dsu = [[SList([line]).fields(field), line] for line in self]
984 else:
1011 else:
985 dsu = [[line, line] for line in self]
1012 dsu = [[line, line] for line in self]
986 if nums:
1013 if nums:
987 for i in range(len(dsu)):
1014 for i in range(len(dsu)):
988 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
1015 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
989 try:
1016 try:
990 n = int(numstr)
1017 n = int(numstr)
991 except ValueError:
1018 except ValueError:
992 n = 0;
1019 n = 0;
993 dsu[i][0] = n
1020 dsu[i][0] = n
994
1021
995
1022
996 dsu.sort()
1023 dsu.sort()
997 return SList([t[1] for t in dsu])
1024 return SList([t[1] for t in dsu])
998
1025
999 def print_slist(arg):
1026 def print_slist(arg):
1000 """ Prettier (non-repr-like) and more informative printer for SList """
1027 """ Prettier (non-repr-like) and more informative printer for SList """
1001 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
1028 print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
1002 if hasattr(arg, 'hideonce') and arg.hideonce:
1029 if hasattr(arg, 'hideonce') and arg.hideonce:
1003 arg.hideonce = False
1030 arg.hideonce = False
1004 return
1031 return
1005
1032
1006 nlprint(arg)
1033 nlprint(arg)
1007
1034
1008 print_slist = result_display.when_type(SList)(print_slist)
1035 print_slist = result_display.when_type(SList)(print_slist)
1009
1036
1010
1037
1011
1038
1012 #----------------------------------------------------------------------------
1039 #----------------------------------------------------------------------------
1013 def esc_quotes(strng):
1040 def esc_quotes(strng):
1014 """Return the input string with single and double quotes escaped out"""
1041 """Return the input string with single and double quotes escaped out"""
1015
1042
1016 return strng.replace('"','\\"').replace("'","\\'")
1043 return strng.replace('"','\\"').replace("'","\\'")
1017
1044
1018 #----------------------------------------------------------------------------
1045 #----------------------------------------------------------------------------
1019 def make_quoted_expr(s):
1046 def make_quoted_expr(s):
1020 """Return string s in appropriate quotes, using raw string if possible.
1047 """Return string s in appropriate quotes, using raw string if possible.
1021
1048
1022 XXX - example removed because it caused encoding errors in documentation
1049 XXX - example removed because it caused encoding errors in documentation
1023 generation. We need a new example that doesn't contain invalid chars.
1050 generation. We need a new example that doesn't contain invalid chars.
1024
1051
1025 Note the use of raw string and padding at the end to allow trailing
1052 Note the use of raw string and padding at the end to allow trailing
1026 backslash.
1053 backslash.
1027 """
1054 """
1028
1055
1029 tail = ''
1056 tail = ''
1030 tailpadding = ''
1057 tailpadding = ''
1031 raw = ''
1058 raw = ''
1032 if "\\" in s:
1059 if "\\" in s:
1033 raw = 'r'
1060 raw = 'r'
1034 if s.endswith('\\'):
1061 if s.endswith('\\'):
1035 tail = '[:-1]'
1062 tail = '[:-1]'
1036 tailpadding = '_'
1063 tailpadding = '_'
1037 if '"' not in s:
1064 if '"' not in s:
1038 quote = '"'
1065 quote = '"'
1039 elif "'" not in s:
1066 elif "'" not in s:
1040 quote = "'"
1067 quote = "'"
1041 elif '"""' not in s and not s.endswith('"'):
1068 elif '"""' not in s and not s.endswith('"'):
1042 quote = '"""'
1069 quote = '"""'
1043 elif "'''" not in s and not s.endswith("'"):
1070 elif "'''" not in s and not s.endswith("'"):
1044 quote = "'''"
1071 quote = "'''"
1045 else:
1072 else:
1046 # give up, backslash-escaped string will do
1073 # give up, backslash-escaped string will do
1047 return '"%s"' % esc_quotes(s)
1074 return '"%s"' % esc_quotes(s)
1048 res = raw + quote + s + tailpadding + quote + tail
1075 res = raw + quote + s + tailpadding + quote + tail
1049 return res
1076 return res
1050
1077
1051
1078
1052 #----------------------------------------------------------------------------
1079 #----------------------------------------------------------------------------
1053 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
1080 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
1054 """Take multiple lines of input.
1081 """Take multiple lines of input.
1055
1082
1056 A list with each line of input as a separate element is returned when a
1083 A list with each line of input as a separate element is returned when a
1057 termination string is entered (defaults to a single '.'). Input can also
1084 termination string is entered (defaults to a single '.'). Input can also
1058 terminate via EOF (^D in Unix, ^Z-RET in Windows).
1085 terminate via EOF (^D in Unix, ^Z-RET in Windows).
1059
1086
1060 Lines of input which end in \\ are joined into single entries (and a
1087 Lines of input which end in \\ are joined into single entries (and a
1061 secondary continuation prompt is issued as long as the user terminates
1088 secondary continuation prompt is issued as long as the user terminates
1062 lines with \\). This allows entering very long strings which are still
1089 lines with \\). This allows entering very long strings which are still
1063 meant to be treated as single entities.
1090 meant to be treated as single entities.
1064 """
1091 """
1065
1092
1066 try:
1093 try:
1067 if header:
1094 if header:
1068 header += '\n'
1095 header += '\n'
1069 lines = [raw_input(header + ps1)]
1096 lines = [raw_input(header + ps1)]
1070 except EOFError:
1097 except EOFError:
1071 return []
1098 return []
1072 terminate = [terminate_str]
1099 terminate = [terminate_str]
1073 try:
1100 try:
1074 while lines[-1:] != terminate:
1101 while lines[-1:] != terminate:
1075 new_line = raw_input(ps1)
1102 new_line = raw_input(ps1)
1076 while new_line.endswith('\\'):
1103 while new_line.endswith('\\'):
1077 new_line = new_line[:-1] + raw_input(ps2)
1104 new_line = new_line[:-1] + raw_input(ps2)
1078 lines.append(new_line)
1105 lines.append(new_line)
1079
1106
1080 return lines[:-1] # don't return the termination command
1107 return lines[:-1] # don't return the termination command
1081 except EOFError:
1108 except EOFError:
1082 print
1109 print
1083 return lines
1110 return lines
1084
1111
1085 #----------------------------------------------------------------------------
1112 #----------------------------------------------------------------------------
1086 def raw_input_ext(prompt='', ps2='... '):
1113 def raw_input_ext(prompt='', ps2='... '):
1087 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
1114 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
1088
1115
1089 line = raw_input(prompt)
1116 line = raw_input(prompt)
1090 while line.endswith('\\'):
1117 while line.endswith('\\'):
1091 line = line[:-1] + raw_input(ps2)
1118 line = line[:-1] + raw_input(ps2)
1092 return line
1119 return line
1093
1120
1094 #----------------------------------------------------------------------------
1121 #----------------------------------------------------------------------------
1095 def ask_yes_no(prompt,default=None):
1122 def ask_yes_no(prompt,default=None):
1096 """Asks a question and returns a boolean (y/n) answer.
1123 """Asks a question and returns a boolean (y/n) answer.
1097
1124
1098 If default is given (one of 'y','n'), it is used if the user input is
1125 If default is given (one of 'y','n'), it is used if the user input is
1099 empty. Otherwise the question is repeated until an answer is given.
1126 empty. Otherwise the question is repeated until an answer is given.
1100
1127
1101 An EOF is treated as the default answer. If there is no default, an
1128 An EOF is treated as the default answer. If there is no default, an
1102 exception is raised to prevent infinite loops.
1129 exception is raised to prevent infinite loops.
1103
1130
1104 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1131 Valid answers are: y/yes/n/no (match is not case sensitive)."""
1105
1132
1106 answers = {'y':True,'n':False,'yes':True,'no':False}
1133 answers = {'y':True,'n':False,'yes':True,'no':False}
1107 ans = None
1134 ans = None
1108 while ans not in answers.keys():
1135 while ans not in answers.keys():
1109 try:
1136 try:
1110 ans = raw_input(prompt+' ').lower()
1137 ans = raw_input(prompt+' ').lower()
1111 if not ans: # response was an empty string
1138 if not ans: # response was an empty string
1112 ans = default
1139 ans = default
1113 except KeyboardInterrupt:
1140 except KeyboardInterrupt:
1114 pass
1141 pass
1115 except EOFError:
1142 except EOFError:
1116 if default in answers.keys():
1143 if default in answers.keys():
1117 ans = default
1144 ans = default
1118 print
1145 print
1119 else:
1146 else:
1120 raise
1147 raise
1121
1148
1122 return answers[ans]
1149 return answers[ans]
1123
1150
1124 #----------------------------------------------------------------------------
1151 #----------------------------------------------------------------------------
1125 class EvalDict:
1152 class EvalDict:
1126 """
1153 """
1127 Emulate a dict which evaluates its contents in the caller's frame.
1154 Emulate a dict which evaluates its contents in the caller's frame.
1128
1155
1129 Usage:
1156 Usage:
1130 >>> number = 19
1157 >>> number = 19
1131
1158
1132 >>> text = "python"
1159 >>> text = "python"
1133
1160
1134 >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1161 >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
1135 Python 2.1 rules!
1162 Python 2.1 rules!
1136 """
1163 """
1137
1164
1138 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1165 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
1139 # modified (shorter) version of:
1166 # modified (shorter) version of:
1140 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1167 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
1141 # Skip Montanaro (skip@pobox.com).
1168 # Skip Montanaro (skip@pobox.com).
1142
1169
1143 def __getitem__(self, name):
1170 def __getitem__(self, name):
1144 frame = sys._getframe(1)
1171 frame = sys._getframe(1)
1145 return eval(name, frame.f_globals, frame.f_locals)
1172 return eval(name, frame.f_globals, frame.f_locals)
1146
1173
1147 EvalString = EvalDict # for backwards compatibility
1174 EvalString = EvalDict # for backwards compatibility
1148 #----------------------------------------------------------------------------
1175 #----------------------------------------------------------------------------
1149 def qw(words,flat=0,sep=None,maxsplit=-1):
1176 def qw(words,flat=0,sep=None,maxsplit=-1):
1150 """Similar to Perl's qw() operator, but with some more options.
1177 """Similar to Perl's qw() operator, but with some more options.
1151
1178
1152 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1179 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
1153
1180
1154 words can also be a list itself, and with flat=1, the output will be
1181 words can also be a list itself, and with flat=1, the output will be
1155 recursively flattened.
1182 recursively flattened.
1156
1183
1157 Examples:
1184 Examples:
1158
1185
1159 >>> qw('1 2')
1186 >>> qw('1 2')
1160 ['1', '2']
1187 ['1', '2']
1161
1188
1162 >>> qw(['a b','1 2',['m n','p q']])
1189 >>> qw(['a b','1 2',['m n','p q']])
1163 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1190 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
1164
1191
1165 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1192 >>> qw(['a b','1 2',['m n','p q']],flat=1)
1166 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
1193 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
1167 """
1194 """
1168
1195
1169 if type(words) in StringTypes:
1196 if type(words) in StringTypes:
1170 return [word.strip() for word in words.split(sep,maxsplit)
1197 return [word.strip() for word in words.split(sep,maxsplit)
1171 if word and not word.isspace() ]
1198 if word and not word.isspace() ]
1172 if flat:
1199 if flat:
1173 return flatten(map(qw,words,[1]*len(words)))
1200 return flatten(map(qw,words,[1]*len(words)))
1174 return map(qw,words)
1201 return map(qw,words)
1175
1202
1176 #----------------------------------------------------------------------------
1203 #----------------------------------------------------------------------------
1177 def qwflat(words,sep=None,maxsplit=-1):
1204 def qwflat(words,sep=None,maxsplit=-1):
1178 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1205 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
1179 return qw(words,1,sep,maxsplit)
1206 return qw(words,1,sep,maxsplit)
1180
1207
1181 #----------------------------------------------------------------------------
1208 #----------------------------------------------------------------------------
1182 def qw_lol(indata):
1209 def qw_lol(indata):
1183 """qw_lol('a b') -> [['a','b']],
1210 """qw_lol('a b') -> [['a','b']],
1184 otherwise it's just a call to qw().
1211 otherwise it's just a call to qw().
1185
1212
1186 We need this to make sure the modules_some keys *always* end up as a
1213 We need this to make sure the modules_some keys *always* end up as a
1187 list of lists."""
1214 list of lists."""
1188
1215
1189 if type(indata) in StringTypes:
1216 if type(indata) in StringTypes:
1190 return [qw(indata)]
1217 return [qw(indata)]
1191 else:
1218 else:
1192 return qw(indata)
1219 return qw(indata)
1193
1220
1194 #----------------------------------------------------------------------------
1221 #----------------------------------------------------------------------------
1195 def grep(pat,list,case=1):
1222 def grep(pat,list,case=1):
1196 """Simple minded grep-like function.
1223 """Simple minded grep-like function.
1197 grep(pat,list) returns occurrences of pat in list, None on failure.
1224 grep(pat,list) returns occurrences of pat in list, None on failure.
1198
1225
1199 It only does simple string matching, with no support for regexps. Use the
1226 It only does simple string matching, with no support for regexps. Use the
1200 option case=0 for case-insensitive matching."""
1227 option case=0 for case-insensitive matching."""
1201
1228
1202 # This is pretty crude. At least it should implement copying only references
1229 # This is pretty crude. At least it should implement copying only references
1203 # to the original data in case it's big. Now it copies the data for output.
1230 # to the original data in case it's big. Now it copies the data for output.
1204 out=[]
1231 out=[]
1205 if case:
1232 if case:
1206 for term in list:
1233 for term in list:
1207 if term.find(pat)>-1: out.append(term)
1234 if term.find(pat)>-1: out.append(term)
1208 else:
1235 else:
1209 lpat=pat.lower()
1236 lpat=pat.lower()
1210 for term in list:
1237 for term in list:
1211 if term.lower().find(lpat)>-1: out.append(term)
1238 if term.lower().find(lpat)>-1: out.append(term)
1212
1239
1213 if len(out): return out
1240 if len(out): return out
1214 else: return None
1241 else: return None
1215
1242
1216 #----------------------------------------------------------------------------
1243 #----------------------------------------------------------------------------
1217 def dgrep(pat,*opts):
1244 def dgrep(pat,*opts):
1218 """Return grep() on dir()+dir(__builtins__).
1245 """Return grep() on dir()+dir(__builtins__).
1219
1246
1220 A very common use of grep() when working interactively."""
1247 A very common use of grep() when working interactively."""
1221
1248
1222 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1249 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
1223
1250
1224 #----------------------------------------------------------------------------
1251 #----------------------------------------------------------------------------
1225 def idgrep(pat):
1252 def idgrep(pat):
1226 """Case-insensitive dgrep()"""
1253 """Case-insensitive dgrep()"""
1227
1254
1228 return dgrep(pat,0)
1255 return dgrep(pat,0)
1229
1256
1230 #----------------------------------------------------------------------------
1257 #----------------------------------------------------------------------------
1231 def igrep(pat,list):
1258 def igrep(pat,list):
1232 """Synonym for case-insensitive grep."""
1259 """Synonym for case-insensitive grep."""
1233
1260
1234 return grep(pat,list,case=0)
1261 return grep(pat,list,case=0)
1235
1262
1236 #----------------------------------------------------------------------------
1263 #----------------------------------------------------------------------------
1237 def indent(str,nspaces=4,ntabs=0):
1264 def indent(str,nspaces=4,ntabs=0):
1238 """Indent a string a given number of spaces or tabstops.
1265 """Indent a string a given number of spaces or tabstops.
1239
1266
1240 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1267 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
1241 """
1268 """
1242 if str is None:
1269 if str is None:
1243 return
1270 return
1244 ind = '\t'*ntabs+' '*nspaces
1271 ind = '\t'*ntabs+' '*nspaces
1245 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1272 outstr = '%s%s' % (ind,str.replace(os.linesep,os.linesep+ind))
1246 if outstr.endswith(os.linesep+ind):
1273 if outstr.endswith(os.linesep+ind):
1247 return outstr[:-len(ind)]
1274 return outstr[:-len(ind)]
1248 else:
1275 else:
1249 return outstr
1276 return outstr
1250
1277
1251 #-----------------------------------------------------------------------------
1278 #-----------------------------------------------------------------------------
1252 def native_line_ends(filename,backup=1):
1279 def native_line_ends(filename,backup=1):
1253 """Convert (in-place) a file to line-ends native to the current OS.
1280 """Convert (in-place) a file to line-ends native to the current OS.
1254
1281
1255 If the optional backup argument is given as false, no backup of the
1282 If the optional backup argument is given as false, no backup of the
1256 original file is left. """
1283 original file is left. """
1257
1284
1258 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1285 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
1259
1286
1260 bak_filename = filename + backup_suffixes[os.name]
1287 bak_filename = filename + backup_suffixes[os.name]
1261
1288
1262 original = open(filename).read()
1289 original = open(filename).read()
1263 shutil.copy2(filename,bak_filename)
1290 shutil.copy2(filename,bak_filename)
1264 try:
1291 try:
1265 new = open(filename,'wb')
1292 new = open(filename,'wb')
1266 new.write(os.linesep.join(original.splitlines()))
1293 new.write(os.linesep.join(original.splitlines()))
1267 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1294 new.write(os.linesep) # ALWAYS put an eol at the end of the file
1268 new.close()
1295 new.close()
1269 except:
1296 except:
1270 os.rename(bak_filename,filename)
1297 os.rename(bak_filename,filename)
1271 if not backup:
1298 if not backup:
1272 try:
1299 try:
1273 os.remove(bak_filename)
1300 os.remove(bak_filename)
1274 except:
1301 except:
1275 pass
1302 pass
1276
1303
1277 #****************************************************************************
1304 #****************************************************************************
1278 # lists, dicts and structures
1305 # lists, dicts and structures
1279
1306
1280 def belong(candidates,checklist):
1307 def belong(candidates,checklist):
1281 """Check whether a list of items appear in a given list of options.
1308 """Check whether a list of items appear in a given list of options.
1282
1309
1283 Returns a list of 1 and 0, one for each candidate given."""
1310 Returns a list of 1 and 0, one for each candidate given."""
1284
1311
1285 return [x in checklist for x in candidates]
1312 return [x in checklist for x in candidates]
1286
1313
1287 #----------------------------------------------------------------------------
1314 #----------------------------------------------------------------------------
1288 def uniq_stable(elems):
1315 def uniq_stable(elems):
1289 """uniq_stable(elems) -> list
1316 """uniq_stable(elems) -> list
1290
1317
1291 Return from an iterable, a list of all the unique elements in the input,
1318 Return from an iterable, a list of all the unique elements in the input,
1292 but maintaining the order in which they first appear.
1319 but maintaining the order in which they first appear.
1293
1320
1294 A naive solution to this problem which just makes a dictionary with the
1321 A naive solution to this problem which just makes a dictionary with the
1295 elements as keys fails to respect the stability condition, since
1322 elements as keys fails to respect the stability condition, since
1296 dictionaries are unsorted by nature.
1323 dictionaries are unsorted by nature.
1297
1324
1298 Note: All elements in the input must be valid dictionary keys for this
1325 Note: All elements in the input must be valid dictionary keys for this
1299 routine to work, as it internally uses a dictionary for efficiency
1326 routine to work, as it internally uses a dictionary for efficiency
1300 reasons."""
1327 reasons."""
1301
1328
1302 unique = []
1329 unique = []
1303 unique_dict = {}
1330 unique_dict = {}
1304 for nn in elems:
1331 for nn in elems:
1305 if nn not in unique_dict:
1332 if nn not in unique_dict:
1306 unique.append(nn)
1333 unique.append(nn)
1307 unique_dict[nn] = None
1334 unique_dict[nn] = None
1308 return unique
1335 return unique
1309
1336
1310 #----------------------------------------------------------------------------
1337 #----------------------------------------------------------------------------
1311 class NLprinter:
1338 class NLprinter:
1312 """Print an arbitrarily nested list, indicating index numbers.
1339 """Print an arbitrarily nested list, indicating index numbers.
1313
1340
1314 An instance of this class called nlprint is available and callable as a
1341 An instance of this class called nlprint is available and callable as a
1315 function.
1342 function.
1316
1343
1317 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1344 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
1318 and using 'sep' to separate the index from the value. """
1345 and using 'sep' to separate the index from the value. """
1319
1346
1320 def __init__(self):
1347 def __init__(self):
1321 self.depth = 0
1348 self.depth = 0
1322
1349
1323 def __call__(self,lst,pos='',**kw):
1350 def __call__(self,lst,pos='',**kw):
1324 """Prints the nested list numbering levels."""
1351 """Prints the nested list numbering levels."""
1325 kw.setdefault('indent',' ')
1352 kw.setdefault('indent',' ')
1326 kw.setdefault('sep',': ')
1353 kw.setdefault('sep',': ')
1327 kw.setdefault('start',0)
1354 kw.setdefault('start',0)
1328 kw.setdefault('stop',len(lst))
1355 kw.setdefault('stop',len(lst))
1329 # we need to remove start and stop from kw so they don't propagate
1356 # we need to remove start and stop from kw so they don't propagate
1330 # into a recursive call for a nested list.
1357 # into a recursive call for a nested list.
1331 start = kw['start']; del kw['start']
1358 start = kw['start']; del kw['start']
1332 stop = kw['stop']; del kw['stop']
1359 stop = kw['stop']; del kw['stop']
1333 if self.depth == 0 and 'header' in kw.keys():
1360 if self.depth == 0 and 'header' in kw.keys():
1334 print kw['header']
1361 print kw['header']
1335
1362
1336 for idx in range(start,stop):
1363 for idx in range(start,stop):
1337 elem = lst[idx]
1364 elem = lst[idx]
1338 if type(elem)==type([]):
1365 if type(elem)==type([]):
1339 self.depth += 1
1366 self.depth += 1
1340 self.__call__(elem,itpl('$pos$idx,'),**kw)
1367 self.__call__(elem,itpl('$pos$idx,'),**kw)
1341 self.depth -= 1
1368 self.depth -= 1
1342 else:
1369 else:
1343 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1370 printpl(kw['indent']*self.depth+'$pos$idx$kw["sep"]$elem')
1344
1371
1345 nlprint = NLprinter()
1372 nlprint = NLprinter()
1346 #----------------------------------------------------------------------------
1373 #----------------------------------------------------------------------------
1347 def all_belong(candidates,checklist):
1374 def all_belong(candidates,checklist):
1348 """Check whether a list of items ALL appear in a given list of options.
1375 """Check whether a list of items ALL appear in a given list of options.
1349
1376
1350 Returns a single 1 or 0 value."""
1377 Returns a single 1 or 0 value."""
1351
1378
1352 return 1-(0 in [x in checklist for x in candidates])
1379 return 1-(0 in [x in checklist for x in candidates])
1353
1380
1354 #----------------------------------------------------------------------------
1381 #----------------------------------------------------------------------------
1355 def sort_compare(lst1,lst2,inplace = 1):
1382 def sort_compare(lst1,lst2,inplace = 1):
1356 """Sort and compare two lists.
1383 """Sort and compare two lists.
1357
1384
1358 By default it does it in place, thus modifying the lists. Use inplace = 0
1385 By default it does it in place, thus modifying the lists. Use inplace = 0
1359 to avoid that (at the cost of temporary copy creation)."""
1386 to avoid that (at the cost of temporary copy creation)."""
1360 if not inplace:
1387 if not inplace:
1361 lst1 = lst1[:]
1388 lst1 = lst1[:]
1362 lst2 = lst2[:]
1389 lst2 = lst2[:]
1363 lst1.sort(); lst2.sort()
1390 lst1.sort(); lst2.sort()
1364 return lst1 == lst2
1391 return lst1 == lst2
1365
1392
1366 #----------------------------------------------------------------------------
1393 #----------------------------------------------------------------------------
1367 def list2dict(lst):
1394 def list2dict(lst):
1368 """Takes a list of (key,value) pairs and turns it into a dict."""
1395 """Takes a list of (key,value) pairs and turns it into a dict."""
1369
1396
1370 dic = {}
1397 dic = {}
1371 for k,v in lst: dic[k] = v
1398 for k,v in lst: dic[k] = v
1372 return dic
1399 return dic
1373
1400
1374 #----------------------------------------------------------------------------
1401 #----------------------------------------------------------------------------
1375 def list2dict2(lst,default=''):
1402 def list2dict2(lst,default=''):
1376 """Takes a list and turns it into a dict.
1403 """Takes a list and turns it into a dict.
1377 Much slower than list2dict, but more versatile. This version can take
1404 Much slower than list2dict, but more versatile. This version can take
1378 lists with sublists of arbitrary length (including sclars)."""
1405 lists with sublists of arbitrary length (including sclars)."""
1379
1406
1380 dic = {}
1407 dic = {}
1381 for elem in lst:
1408 for elem in lst:
1382 if type(elem) in (types.ListType,types.TupleType):
1409 if type(elem) in (types.ListType,types.TupleType):
1383 size = len(elem)
1410 size = len(elem)
1384 if size == 0:
1411 if size == 0:
1385 pass
1412 pass
1386 elif size == 1:
1413 elif size == 1:
1387 dic[elem] = default
1414 dic[elem] = default
1388 else:
1415 else:
1389 k,v = elem[0], elem[1:]
1416 k,v = elem[0], elem[1:]
1390 if len(v) == 1: v = v[0]
1417 if len(v) == 1: v = v[0]
1391 dic[k] = v
1418 dic[k] = v
1392 else:
1419 else:
1393 dic[elem] = default
1420 dic[elem] = default
1394 return dic
1421 return dic
1395
1422
1396 #----------------------------------------------------------------------------
1423 #----------------------------------------------------------------------------
1397 def flatten(seq):
1424 def flatten(seq):
1398 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1425 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
1399
1426
1400 return [x for subseq in seq for x in subseq]
1427 return [x for subseq in seq for x in subseq]
1401
1428
1402 #----------------------------------------------------------------------------
1429 #----------------------------------------------------------------------------
1403 def get_slice(seq,start=0,stop=None,step=1):
1430 def get_slice(seq,start=0,stop=None,step=1):
1404 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1431 """Get a slice of a sequence with variable step. Specify start,stop,step."""
1405 if stop == None:
1432 if stop == None:
1406 stop = len(seq)
1433 stop = len(seq)
1407 item = lambda i: seq[i]
1434 item = lambda i: seq[i]
1408 return map(item,xrange(start,stop,step))
1435 return map(item,xrange(start,stop,step))
1409
1436
1410 #----------------------------------------------------------------------------
1437 #----------------------------------------------------------------------------
1411 def chop(seq,size):
1438 def chop(seq,size):
1412 """Chop a sequence into chunks of the given size."""
1439 """Chop a sequence into chunks of the given size."""
1413 chunk = lambda i: seq[i:i+size]
1440 chunk = lambda i: seq[i:i+size]
1414 return map(chunk,xrange(0,len(seq),size))
1441 return map(chunk,xrange(0,len(seq),size))
1415
1442
1416 #----------------------------------------------------------------------------
1443 #----------------------------------------------------------------------------
1417 # with is a keyword as of python 2.5, so this function is renamed to withobj
1444 # with is a keyword as of python 2.5, so this function is renamed to withobj
1418 # from its old 'with' name.
1445 # from its old 'with' name.
1419 def with_obj(object, **args):
1446 def with_obj(object, **args):
1420 """Set multiple attributes for an object, similar to Pascal's with.
1447 """Set multiple attributes for an object, similar to Pascal's with.
1421
1448
1422 Example:
1449 Example:
1423 with_obj(jim,
1450 with_obj(jim,
1424 born = 1960,
1451 born = 1960,
1425 haircolour = 'Brown',
1452 haircolour = 'Brown',
1426 eyecolour = 'Green')
1453 eyecolour = 'Green')
1427
1454
1428 Credit: Greg Ewing, in
1455 Credit: Greg Ewing, in
1429 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1456 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
1430
1457
1431 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1458 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
1432 has become a keyword for Python 2.5, so we had to rename it."""
1459 has become a keyword for Python 2.5, so we had to rename it."""
1433
1460
1434 object.__dict__.update(args)
1461 object.__dict__.update(args)
1435
1462
1436 #----------------------------------------------------------------------------
1463 #----------------------------------------------------------------------------
1437 def setattr_list(obj,alist,nspace = None):
1464 def setattr_list(obj,alist,nspace = None):
1438 """Set a list of attributes for an object taken from a namespace.
1465 """Set a list of attributes for an object taken from a namespace.
1439
1466
1440 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1467 setattr_list(obj,alist,nspace) -> sets in obj all the attributes listed in
1441 alist with their values taken from nspace, which must be a dict (something
1468 alist with their values taken from nspace, which must be a dict (something
1442 like locals() will often do) If nspace isn't given, locals() of the
1469 like locals() will often do) If nspace isn't given, locals() of the
1443 *caller* is used, so in most cases you can omit it.
1470 *caller* is used, so in most cases you can omit it.
1444
1471
1445 Note that alist can be given as a string, which will be automatically
1472 Note that alist can be given as a string, which will be automatically
1446 split into a list on whitespace. If given as a list, it must be a list of
1473 split into a list on whitespace. If given as a list, it must be a list of
1447 *strings* (the variable names themselves), not of variables."""
1474 *strings* (the variable names themselves), not of variables."""
1448
1475
1449 # this grabs the local variables from the *previous* call frame -- that is
1476 # this grabs the local variables from the *previous* call frame -- that is
1450 # the locals from the function that called setattr_list().
1477 # the locals from the function that called setattr_list().
1451 # - snipped from weave.inline()
1478 # - snipped from weave.inline()
1452 if nspace is None:
1479 if nspace is None:
1453 call_frame = sys._getframe().f_back
1480 call_frame = sys._getframe().f_back
1454 nspace = call_frame.f_locals
1481 nspace = call_frame.f_locals
1455
1482
1456 if type(alist) in StringTypes:
1483 if type(alist) in StringTypes:
1457 alist = alist.split()
1484 alist = alist.split()
1458 for attr in alist:
1485 for attr in alist:
1459 val = eval(attr,nspace)
1486 val = eval(attr,nspace)
1460 setattr(obj,attr,val)
1487 setattr(obj,attr,val)
1461
1488
1462 #----------------------------------------------------------------------------
1489 #----------------------------------------------------------------------------
1463 def getattr_list(obj,alist,*args):
1490 def getattr_list(obj,alist,*args):
1464 """getattr_list(obj,alist[, default]) -> attribute list.
1491 """getattr_list(obj,alist[, default]) -> attribute list.
1465
1492
1466 Get a list of named attributes for an object. When a default argument is
1493 Get a list of named attributes for an object. When a default argument is
1467 given, it is returned when the attribute doesn't exist; without it, an
1494 given, it is returned when the attribute doesn't exist; without it, an
1468 exception is raised in that case.
1495 exception is raised in that case.
1469
1496
1470 Note that alist can be given as a string, which will be automatically
1497 Note that alist can be given as a string, which will be automatically
1471 split into a list on whitespace. If given as a list, it must be a list of
1498 split into a list on whitespace. If given as a list, it must be a list of
1472 *strings* (the variable names themselves), not of variables."""
1499 *strings* (the variable names themselves), not of variables."""
1473
1500
1474 if type(alist) in StringTypes:
1501 if type(alist) in StringTypes:
1475 alist = alist.split()
1502 alist = alist.split()
1476 if args:
1503 if args:
1477 if len(args)==1:
1504 if len(args)==1:
1478 default = args[0]
1505 default = args[0]
1479 return map(lambda attr: getattr(obj,attr,default),alist)
1506 return map(lambda attr: getattr(obj,attr,default),alist)
1480 else:
1507 else:
1481 raise ValueError,'getattr_list() takes only one optional argument'
1508 raise ValueError,'getattr_list() takes only one optional argument'
1482 else:
1509 else:
1483 return map(lambda attr: getattr(obj,attr),alist)
1510 return map(lambda attr: getattr(obj,attr),alist)
1484
1511
1485 #----------------------------------------------------------------------------
1512 #----------------------------------------------------------------------------
1486 def map_method(method,object_list,*argseq,**kw):
1513 def map_method(method,object_list,*argseq,**kw):
1487 """map_method(method,object_list,*args,**kw) -> list
1514 """map_method(method,object_list,*args,**kw) -> list
1488
1515
1489 Return a list of the results of applying the methods to the items of the
1516 Return a list of the results of applying the methods to the items of the
1490 argument sequence(s). If more than one sequence is given, the method is
1517 argument sequence(s). If more than one sequence is given, the method is
1491 called with an argument list consisting of the corresponding item of each
1518 called with an argument list consisting of the corresponding item of each
1492 sequence. All sequences must be of the same length.
1519 sequence. All sequences must be of the same length.
1493
1520
1494 Keyword arguments are passed verbatim to all objects called.
1521 Keyword arguments are passed verbatim to all objects called.
1495
1522
1496 This is Python code, so it's not nearly as fast as the builtin map()."""
1523 This is Python code, so it's not nearly as fast as the builtin map()."""
1497
1524
1498 out_list = []
1525 out_list = []
1499 idx = 0
1526 idx = 0
1500 for object in object_list:
1527 for object in object_list:
1501 try:
1528 try:
1502 handler = getattr(object, method)
1529 handler = getattr(object, method)
1503 except AttributeError:
1530 except AttributeError:
1504 out_list.append(None)
1531 out_list.append(None)
1505 else:
1532 else:
1506 if argseq:
1533 if argseq:
1507 args = map(lambda lst:lst[idx],argseq)
1534 args = map(lambda lst:lst[idx],argseq)
1508 #print 'ob',object,'hand',handler,'ar',args # dbg
1535 #print 'ob',object,'hand',handler,'ar',args # dbg
1509 out_list.append(handler(args,**kw))
1536 out_list.append(handler(args,**kw))
1510 else:
1537 else:
1511 out_list.append(handler(**kw))
1538 out_list.append(handler(**kw))
1512 idx += 1
1539 idx += 1
1513 return out_list
1540 return out_list
1514
1541
1515 #----------------------------------------------------------------------------
1542 #----------------------------------------------------------------------------
1516 def get_class_members(cls):
1543 def get_class_members(cls):
1517 ret = dir(cls)
1544 ret = dir(cls)
1518 if hasattr(cls,'__bases__'):
1545 if hasattr(cls,'__bases__'):
1519 for base in cls.__bases__:
1546 for base in cls.__bases__:
1520 ret.extend(get_class_members(base))
1547 ret.extend(get_class_members(base))
1521 return ret
1548 return ret
1522
1549
1523 #----------------------------------------------------------------------------
1550 #----------------------------------------------------------------------------
1524 def dir2(obj):
1551 def dir2(obj):
1525 """dir2(obj) -> list of strings
1552 """dir2(obj) -> list of strings
1526
1553
1527 Extended version of the Python builtin dir(), which does a few extra
1554 Extended version of the Python builtin dir(), which does a few extra
1528 checks, and supports common objects with unusual internals that confuse
1555 checks, and supports common objects with unusual internals that confuse
1529 dir(), such as Traits and PyCrust.
1556 dir(), such as Traits and PyCrust.
1530
1557
1531 This version is guaranteed to return only a list of true strings, whereas
1558 This version is guaranteed to return only a list of true strings, whereas
1532 dir() returns anything that objects inject into themselves, even if they
1559 dir() returns anything that objects inject into themselves, even if they
1533 are later not really valid for attribute access (many extension libraries
1560 are later not really valid for attribute access (many extension libraries
1534 have such bugs).
1561 have such bugs).
1535 """
1562 """
1536
1563
1537 # Start building the attribute list via dir(), and then complete it
1564 # Start building the attribute list via dir(), and then complete it
1538 # with a few extra special-purpose calls.
1565 # with a few extra special-purpose calls.
1539 words = dir(obj)
1566 words = dir(obj)
1540
1567
1541 if hasattr(obj,'__class__'):
1568 if hasattr(obj,'__class__'):
1542 words.append('__class__')
1569 words.append('__class__')
1543 words.extend(get_class_members(obj.__class__))
1570 words.extend(get_class_members(obj.__class__))
1544 #if '__base__' in words: 1/0
1571 #if '__base__' in words: 1/0
1545
1572
1546 # Some libraries (such as traits) may introduce duplicates, we want to
1573 # Some libraries (such as traits) may introduce duplicates, we want to
1547 # track and clean this up if it happens
1574 # track and clean this up if it happens
1548 may_have_dupes = False
1575 may_have_dupes = False
1549
1576
1550 # this is the 'dir' function for objects with Enthought's traits
1577 # this is the 'dir' function for objects with Enthought's traits
1551 if hasattr(obj, 'trait_names'):
1578 if hasattr(obj, 'trait_names'):
1552 try:
1579 try:
1553 words.extend(obj.trait_names())
1580 words.extend(obj.trait_names())
1554 may_have_dupes = True
1581 may_have_dupes = True
1555 except TypeError:
1582 except TypeError:
1556 # This will happen if `obj` is a class and not an instance.
1583 # This will happen if `obj` is a class and not an instance.
1557 pass
1584 pass
1558
1585
1559 # Support for PyCrust-style _getAttributeNames magic method.
1586 # Support for PyCrust-style _getAttributeNames magic method.
1560 if hasattr(obj, '_getAttributeNames'):
1587 if hasattr(obj, '_getAttributeNames'):
1561 try:
1588 try:
1562 words.extend(obj._getAttributeNames())
1589 words.extend(obj._getAttributeNames())
1563 may_have_dupes = True
1590 may_have_dupes = True
1564 except TypeError:
1591 except TypeError:
1565 # `obj` is a class and not an instance. Ignore
1592 # `obj` is a class and not an instance. Ignore
1566 # this error.
1593 # this error.
1567 pass
1594 pass
1568
1595
1569 if may_have_dupes:
1596 if may_have_dupes:
1570 # eliminate possible duplicates, as some traits may also
1597 # eliminate possible duplicates, as some traits may also
1571 # appear as normal attributes in the dir() call.
1598 # appear as normal attributes in the dir() call.
1572 words = list(set(words))
1599 words = list(set(words))
1573 words.sort()
1600 words.sort()
1574
1601
1575 # filter out non-string attributes which may be stuffed by dir() calls
1602 # filter out non-string attributes which may be stuffed by dir() calls
1576 # and poor coding in third-party modules
1603 # and poor coding in third-party modules
1577 return [w for w in words if isinstance(w, basestring)]
1604 return [w for w in words if isinstance(w, basestring)]
1578
1605
1579 #----------------------------------------------------------------------------
1606 #----------------------------------------------------------------------------
1580 def import_fail_info(mod_name,fns=None):
1607 def import_fail_info(mod_name,fns=None):
1581 """Inform load failure for a module."""
1608 """Inform load failure for a module."""
1582
1609
1583 if fns == None:
1610 if fns == None:
1584 warn("Loading of %s failed.\n" % (mod_name,))
1611 warn("Loading of %s failed.\n" % (mod_name,))
1585 else:
1612 else:
1586 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
1613 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
1587
1614
1588 #----------------------------------------------------------------------------
1615 #----------------------------------------------------------------------------
1589 # Proposed popitem() extension, written as a method
1616 # Proposed popitem() extension, written as a method
1590
1617
1591
1618
1592 class NotGiven: pass
1619 class NotGiven: pass
1593
1620
1594 def popkey(dct,key,default=NotGiven):
1621 def popkey(dct,key,default=NotGiven):
1595 """Return dct[key] and delete dct[key].
1622 """Return dct[key] and delete dct[key].
1596
1623
1597 If default is given, return it if dct[key] doesn't exist, otherwise raise
1624 If default is given, return it if dct[key] doesn't exist, otherwise raise
1598 KeyError. """
1625 KeyError. """
1599
1626
1600 try:
1627 try:
1601 val = dct[key]
1628 val = dct[key]
1602 except KeyError:
1629 except KeyError:
1603 if default is NotGiven:
1630 if default is NotGiven:
1604 raise
1631 raise
1605 else:
1632 else:
1606 return default
1633 return default
1607 else:
1634 else:
1608 del dct[key]
1635 del dct[key]
1609 return val
1636 return val
1610
1637
1611 def wrap_deprecated(func, suggest = '<nothing>'):
1638 def wrap_deprecated(func, suggest = '<nothing>'):
1612 def newFunc(*args, **kwargs):
1639 def newFunc(*args, **kwargs):
1613 warnings.warn("Call to deprecated function %s, use %s instead" %
1640 warnings.warn("Call to deprecated function %s, use %s instead" %
1614 ( func.__name__, suggest),
1641 ( func.__name__, suggest),
1615 category=DeprecationWarning,
1642 category=DeprecationWarning,
1616 stacklevel = 2)
1643 stacklevel = 2)
1617 return func(*args, **kwargs)
1644 return func(*args, **kwargs)
1618 return newFunc
1645 return newFunc
1619
1646
1620
1647
1621 def _num_cpus_unix():
1648 def _num_cpus_unix():
1622 """Return the number of active CPUs on a Unix system."""
1649 """Return the number of active CPUs on a Unix system."""
1623 return os.sysconf("SC_NPROCESSORS_ONLN")
1650 return os.sysconf("SC_NPROCESSORS_ONLN")
1624
1651
1625
1652
1626 def _num_cpus_darwin():
1653 def _num_cpus_darwin():
1627 """Return the number of active CPUs on a Darwin system."""
1654 """Return the number of active CPUs on a Darwin system."""
1628 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
1655 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
1629 return p.stdout.read()
1656 return p.stdout.read()
1630
1657
1631
1658
1632 def _num_cpus_windows():
1659 def _num_cpus_windows():
1633 """Return the number of active CPUs on a Windows system."""
1660 """Return the number of active CPUs on a Windows system."""
1634 return os.environ.get("NUMBER_OF_PROCESSORS")
1661 return os.environ.get("NUMBER_OF_PROCESSORS")
1635
1662
1636
1663
1637 def num_cpus():
1664 def num_cpus():
1638 """Return the effective number of CPUs in the system as an integer.
1665 """Return the effective number of CPUs in the system as an integer.
1639
1666
1640 This cross-platform function makes an attempt at finding the total number of
1667 This cross-platform function makes an attempt at finding the total number of
1641 available CPUs in the system, as returned by various underlying system and
1668 available CPUs in the system, as returned by various underlying system and
1642 python calls.
1669 python calls.
1643
1670
1644 If it can't find a sensible answer, it returns 1 (though an error *may* make
1671 If it can't find a sensible answer, it returns 1 (though an error *may* make
1645 it return a large positive number that's actually incorrect).
1672 it return a large positive number that's actually incorrect).
1646 """
1673 """
1647
1674
1648 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
1675 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
1649 # for the names of the keys we needed to look up for this function. This
1676 # for the names of the keys we needed to look up for this function. This
1650 # code was inspired by their equivalent function.
1677 # code was inspired by their equivalent function.
1651
1678
1652 ncpufuncs = {'Linux':_num_cpus_unix,
1679 ncpufuncs = {'Linux':_num_cpus_unix,
1653 'Darwin':_num_cpus_darwin,
1680 'Darwin':_num_cpus_darwin,
1654 'Windows':_num_cpus_windows,
1681 'Windows':_num_cpus_windows,
1655 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
1682 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
1656 # See http://bugs.python.org/issue1082 for details.
1683 # See http://bugs.python.org/issue1082 for details.
1657 'Microsoft':_num_cpus_windows,
1684 'Microsoft':_num_cpus_windows,
1658 }
1685 }
1659
1686
1660 ncpufunc = ncpufuncs.get(platform.system(),
1687 ncpufunc = ncpufuncs.get(platform.system(),
1661 # default to unix version (Solaris, AIX, etc)
1688 # default to unix version (Solaris, AIX, etc)
1662 _num_cpus_unix)
1689 _num_cpus_unix)
1663
1690
1664 try:
1691 try:
1665 ncpus = max(1,int(ncpufunc()))
1692 ncpus = max(1,int(ncpufunc()))
1666 except:
1693 except:
1667 ncpus = 1
1694 ncpus = 1
1668 return ncpus
1695 return ncpus
1669
1696
1670 def extract_vars(*names,**kw):
1697 def extract_vars(*names,**kw):
1671 """Extract a set of variables by name from another frame.
1698 """Extract a set of variables by name from another frame.
1672
1699
1673 :Parameters:
1700 :Parameters:
1674 - `*names`: strings
1701 - `*names`: strings
1675 One or more variable names which will be extracted from the caller's
1702 One or more variable names which will be extracted from the caller's
1676 frame.
1703 frame.
1677
1704
1678 :Keywords:
1705 :Keywords:
1679 - `depth`: integer (0)
1706 - `depth`: integer (0)
1680 How many frames in the stack to walk when looking for your variables.
1707 How many frames in the stack to walk when looking for your variables.
1681
1708
1682
1709
1683 Examples:
1710 Examples:
1684
1711
1685 In [2]: def func(x):
1712 In [2]: def func(x):
1686 ...: y = 1
1713 ...: y = 1
1687 ...: print extract_vars('x','y')
1714 ...: print extract_vars('x','y')
1688 ...:
1715 ...:
1689
1716
1690 In [3]: func('hello')
1717 In [3]: func('hello')
1691 {'y': 1, 'x': 'hello'}
1718 {'y': 1, 'x': 'hello'}
1692 """
1719 """
1693
1720
1694 depth = kw.get('depth',0)
1721 depth = kw.get('depth',0)
1695
1722
1696 callerNS = sys._getframe(depth+1).f_locals
1723 callerNS = sys._getframe(depth+1).f_locals
1697 return dict((k,callerNS[k]) for k in names)
1724 return dict((k,callerNS[k]) for k in names)
1698
1725
1699
1726
1700 def extract_vars_above(*names):
1727 def extract_vars_above(*names):
1701 """Extract a set of variables by name from another frame.
1728 """Extract a set of variables by name from another frame.
1702
1729
1703 Similar to extractVars(), but with a specified depth of 1, so that names
1730 Similar to extractVars(), but with a specified depth of 1, so that names
1704 are exctracted exactly from above the caller.
1731 are exctracted exactly from above the caller.
1705
1732
1706 This is simply a convenience function so that the very common case (for us)
1733 This is simply a convenience function so that the very common case (for us)
1707 of skipping exactly 1 frame doesn't have to construct a special dict for
1734 of skipping exactly 1 frame doesn't have to construct a special dict for
1708 keyword passing."""
1735 keyword passing."""
1709
1736
1710 callerNS = sys._getframe(2).f_locals
1737 callerNS = sys._getframe(2).f_locals
1711 return dict((k,callerNS[k]) for k in names)
1738 return dict((k,callerNS[k]) for k in names)
1712
1739
1713 def shexp(s):
1740 def shexp(s):
1714 """Expand $VARS and ~names in a string, like a shell
1741 """Expand $VARS and ~names in a string, like a shell
1715
1742
1716 :Examples:
1743 :Examples:
1717
1744
1718 In [2]: os.environ['FOO']='test'
1745 In [2]: os.environ['FOO']='test'
1719
1746
1720 In [3]: shexp('variable FOO is $FOO')
1747 In [3]: shexp('variable FOO is $FOO')
1721 Out[3]: 'variable FOO is test'
1748 Out[3]: 'variable FOO is test'
1722 """
1749 """
1723 return os.path.expandvars(os.path.expanduser(s))
1750 return os.path.expandvars(os.path.expanduser(s))
1724
1751
1725
1752
1726 def list_strings(arg):
1753 def list_strings(arg):
1727 """Always return a list of strings, given a string or list of strings
1754 """Always return a list of strings, given a string or list of strings
1728 as input.
1755 as input.
1729
1756
1730 :Examples:
1757 :Examples:
1731
1758
1732 In [7]: list_strings('A single string')
1759 In [7]: list_strings('A single string')
1733 Out[7]: ['A single string']
1760 Out[7]: ['A single string']
1734
1761
1735 In [8]: list_strings(['A single string in a list'])
1762 In [8]: list_strings(['A single string in a list'])
1736 Out[8]: ['A single string in a list']
1763 Out[8]: ['A single string in a list']
1737
1764
1738 In [9]: list_strings(['A','list','of','strings'])
1765 In [9]: list_strings(['A','list','of','strings'])
1739 Out[9]: ['A', 'list', 'of', 'strings']
1766 Out[9]: ['A', 'list', 'of', 'strings']
1740 """
1767 """
1741
1768
1742 if isinstance(arg,basestring): return [arg]
1769 if isinstance(arg,basestring): return [arg]
1743 else: return arg
1770 else: return arg
1744
1771
1745
1772
1746 #----------------------------------------------------------------------------
1773 #----------------------------------------------------------------------------
1747 def marquee(txt='',width=78,mark='*'):
1774 def marquee(txt='',width=78,mark='*'):
1748 """Return the input string centered in a 'marquee'.
1775 """Return the input string centered in a 'marquee'.
1749
1776
1750 :Examples:
1777 :Examples:
1751
1778
1752 In [16]: marquee('A test',40)
1779 In [16]: marquee('A test',40)
1753 Out[16]: '**************** A test ****************'
1780 Out[16]: '**************** A test ****************'
1754
1781
1755 In [17]: marquee('A test',40,'-')
1782 In [17]: marquee('A test',40,'-')
1756 Out[17]: '---------------- A test ----------------'
1783 Out[17]: '---------------- A test ----------------'
1757
1784
1758 In [18]: marquee('A test',40,' ')
1785 In [18]: marquee('A test',40,' ')
1759 Out[18]: ' A test '
1786 Out[18]: ' A test '
1760
1787
1761 """
1788 """
1762 if not txt:
1789 if not txt:
1763 return (mark*width)[:width]
1790 return (mark*width)[:width]
1764 nmark = (width-len(txt)-2)/len(mark)/2
1791 nmark = (width-len(txt)-2)/len(mark)/2
1765 if nmark < 0: nmark =0
1792 if nmark < 0: nmark =0
1766 marks = mark*nmark
1793 marks = mark*nmark
1767 return '%s %s %s' % (marks,txt,marks)
1794 return '%s %s %s' % (marks,txt,marks)
1768
1795
1769 #*************************** end of file <genutils.py> **********************
1796 #*************************** end of file <genutils.py> **********************
@@ -1,320 +1,320 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 """
3 """
4 This module defines the things that are used in setup.py for building IPython
4 This module defines the things that are used in setup.py for building IPython
5
5
6 This includes:
6 This includes:
7
7
8 * The basic arguments to setup
8 * The basic arguments to setup
9 * Functions for finding things like packages, package data, etc.
9 * Functions for finding things like packages, package data, etc.
10 * A function for checking dependencies.
10 * A function for checking dependencies.
11 """
11 """
12
12
13 __docformat__ = "restructuredtext en"
13 __docformat__ = "restructuredtext en"
14
14
15 #-------------------------------------------------------------------------------
15 #-------------------------------------------------------------------------------
16 # Copyright (C) 2008 The IPython Development Team
16 # Copyright (C) 2008 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-------------------------------------------------------------------------------
20 #-------------------------------------------------------------------------------
21
21
22 #-------------------------------------------------------------------------------
22 #-------------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-------------------------------------------------------------------------------
24 #-------------------------------------------------------------------------------
25
25
26 import os, sys
26 import os, sys
27
27
28 from glob import glob
28 from glob import glob
29
29
30 from setupext import install_data_ext
30 from setupext import install_data_ext
31
31
32 #-------------------------------------------------------------------------------
32 #-------------------------------------------------------------------------------
33 # Useful globals and utility functions
33 # Useful globals and utility functions
34 #-------------------------------------------------------------------------------
34 #-------------------------------------------------------------------------------
35
35
36 # A few handy globals
36 # A few handy globals
37 isfile = os.path.isfile
37 isfile = os.path.isfile
38 pjoin = os.path.join
38 pjoin = os.path.join
39
39
40 def oscmd(s):
40 def oscmd(s):
41 print ">", s
41 print ">", s
42 os.system(s)
42 os.system(s)
43
43
44 # A little utility we'll need below, since glob() does NOT allow you to do
44 # A little utility we'll need below, since glob() does NOT allow you to do
45 # exclusion on multiple endings!
45 # exclusion on multiple endings!
46 def file_doesnt_endwith(test,endings):
46 def file_doesnt_endwith(test,endings):
47 """Return true if test is a file and its name does NOT end with any
47 """Return true if test is a file and its name does NOT end with any
48 of the strings listed in endings."""
48 of the strings listed in endings."""
49 if not isfile(test):
49 if not isfile(test):
50 return False
50 return False
51 for e in endings:
51 for e in endings:
52 if test.endswith(e):
52 if test.endswith(e):
53 return False
53 return False
54 return True
54 return True
55
55
56 #---------------------------------------------------------------------------
56 #---------------------------------------------------------------------------
57 # Basic project information
57 # Basic project information
58 #---------------------------------------------------------------------------
58 #---------------------------------------------------------------------------
59
59
60 # release.py contains version, authors, license, url, keywords, etc.
60 # release.py contains version, authors, license, url, keywords, etc.
61 execfile(pjoin('IPython','core','release.py'))
61 execfile(pjoin('IPython','core','release.py'))
62
62
63 # Create a dict with the basic information
63 # Create a dict with the basic information
64 # This dict is eventually passed to setup after additional keys are added.
64 # This dict is eventually passed to setup after additional keys are added.
65 setup_args = dict(
65 setup_args = dict(
66 name = name,
66 name = name,
67 version = version,
67 version = version,
68 description = description,
68 description = description,
69 long_description = long_description,
69 long_description = long_description,
70 author = author,
70 author = author,
71 author_email = author_email,
71 author_email = author_email,
72 url = url,
72 url = url,
73 download_url = download_url,
73 download_url = download_url,
74 license = license,
74 license = license,
75 platforms = platforms,
75 platforms = platforms,
76 keywords = keywords,
76 keywords = keywords,
77 cmdclass = {'install_data': install_data_ext},
77 cmdclass = {'install_data': install_data_ext},
78 )
78 )
79
79
80
80
81 #---------------------------------------------------------------------------
81 #---------------------------------------------------------------------------
82 # Find packages
82 # Find packages
83 #---------------------------------------------------------------------------
83 #---------------------------------------------------------------------------
84
84
85 def add_package(packages,pname,config=False,tests=False,scripts=False,
85 def add_package(packages,pname,config=False,tests=False,scripts=False,
86 others=None):
86 others=None):
87 """
87 """
88 Add a package to the list of packages, including certain subpackages.
88 Add a package to the list of packages, including certain subpackages.
89 """
89 """
90 packages.append('.'.join(['IPython',pname]))
90 packages.append('.'.join(['IPython',pname]))
91 if config:
91 if config:
92 packages.append('.'.join(['IPython',pname,'config']))
92 packages.append('.'.join(['IPython',pname,'config']))
93 if tests:
93 if tests:
94 packages.append('.'.join(['IPython',pname,'tests']))
94 packages.append('.'.join(['IPython',pname,'tests']))
95 if scripts:
95 if scripts:
96 packages.append('.'.join(['IPython',pname,'scripts']))
96 packages.append('.'.join(['IPython',pname,'scripts']))
97 if others is not None:
97 if others is not None:
98 for o in others:
98 for o in others:
99 packages.append('.'.join(['IPython',pname,o]))
99 packages.append('.'.join(['IPython',pname,o]))
100
100
101 def find_packages():
101 def find_packages():
102 """
102 """
103 Find all of IPython's packages.
103 Find all of IPython's packages.
104 """
104 """
105 packages = ['IPython']
105 packages = ['IPython']
106 add_package(packages, 'config', tests=True, others=['default','profile'])
106 add_package(packages, 'config', tests=True, others=['default','profile'])
107 add_package(packages, 'core', tests=True)
107 add_package(packages, 'core', tests=True)
108 add_package(packages, 'deathrow', tests=True)
108 add_package(packages, 'deathrow', tests=True)
109 add_package(packages , 'extensions')
109 add_package(packages , 'extensions')
110 add_package(packages, 'external')
110 add_package(packages, 'external')
111 add_package(packages, 'frontend', tests=True)
111 add_package(packages, 'frontend', tests=True)
112 # Don't include the cocoa frontend for now as it is not stable
112 # Don't include the cocoa frontend for now as it is not stable
113 if sys.platform == 'darwin' and False:
113 if sys.platform == 'darwin' and False:
114 add_package(packages, 'frontend.cocoa', tests=True, others=['plugin'])
114 add_package(packages, 'frontend.cocoa', tests=True, others=['plugin'])
115 add_package(packages, 'frontend.cocoa.examples')
115 add_package(packages, 'frontend.cocoa.examples')
116 add_package(packages, 'frontend.cocoa.examples.IPython1Sandbox')
116 add_package(packages, 'frontend.cocoa.examples.IPython1Sandbox')
117 add_package(packages, 'frontend.cocoa.examples.IPython1Sandbox.English.lproj')
117 add_package(packages, 'frontend.cocoa.examples.IPython1Sandbox.English.lproj')
118 add_package(packages, 'frontend.process')
118 add_package(packages, 'frontend.process')
119 add_package(packages, 'frontend.wx')
119 add_package(packages, 'frontend.wx')
120 add_package(packages, 'gui')
120 add_package(packages, 'gui')
121 add_package(packages, 'gui.wx')
121 add_package(packages, 'gui.wx')
122 add_package(packages, 'kernel', config=True, tests=True, scripts=True)
122 add_package(packages, 'kernel', config=False, tests=True, scripts=True)
123 add_package(packages, 'kernel.core', config=True, tests=True)
123 add_package(packages, 'kernel.core', config=False, tests=True)
124 add_package(packages, 'lib', tests=True)
124 add_package(packages, 'lib', tests=True)
125 add_package(packages, 'quarantine', tests=True)
125 add_package(packages, 'quarantine', tests=True)
126 add_package(packages, 'scripts')
126 add_package(packages, 'scripts')
127 add_package(packages, 'testing', tests=True)
127 add_package(packages, 'testing', tests=True)
128 add_package(packages, 'testing.plugin', tests=False)
128 add_package(packages, 'testing.plugin', tests=False)
129 add_package(packages, 'utils', tests=True)
129 add_package(packages, 'utils', tests=True)
130 return packages
130 return packages
131
131
132 #---------------------------------------------------------------------------
132 #---------------------------------------------------------------------------
133 # Find package data
133 # Find package data
134 #---------------------------------------------------------------------------
134 #---------------------------------------------------------------------------
135
135
136 def find_package_data():
136 def find_package_data():
137 """
137 """
138 Find IPython's package_data.
138 Find IPython's package_data.
139 """
139 """
140 # This is not enough for these things to appear in an sdist.
140 # This is not enough for these things to appear in an sdist.
141 # We need to muck with the MANIFEST to get this to work
141 # We need to muck with the MANIFEST to get this to work
142 package_data = {
142 package_data = {
143 'IPython.config.userconfig' : ['*'],
143 'IPython.config.userconfig' : ['*'],
144 'IPython.testing' : ['*.txt']
144 'IPython.testing' : ['*.txt']
145 }
145 }
146 return package_data
146 return package_data
147
147
148
148
149 #---------------------------------------------------------------------------
149 #---------------------------------------------------------------------------
150 # Find data files
150 # Find data files
151 #---------------------------------------------------------------------------
151 #---------------------------------------------------------------------------
152
152
153 def make_dir_struct(tag,base,out_base):
153 def make_dir_struct(tag,base,out_base):
154 """Make the directory structure of all files below a starting dir.
154 """Make the directory structure of all files below a starting dir.
155
155
156 This is just a convenience routine to help build a nested directory
156 This is just a convenience routine to help build a nested directory
157 hierarchy because distutils is too stupid to do this by itself.
157 hierarchy because distutils is too stupid to do this by itself.
158
158
159 XXX - this needs a proper docstring!
159 XXX - this needs a proper docstring!
160 """
160 """
161
161
162 # we'll use these a lot below
162 # we'll use these a lot below
163 lbase = len(base)
163 lbase = len(base)
164 pathsep = os.path.sep
164 pathsep = os.path.sep
165 lpathsep = len(pathsep)
165 lpathsep = len(pathsep)
166
166
167 out = []
167 out = []
168 for (dirpath,dirnames,filenames) in os.walk(base):
168 for (dirpath,dirnames,filenames) in os.walk(base):
169 # we need to strip out the dirpath from the base to map it to the
169 # we need to strip out the dirpath from the base to map it to the
170 # output (installation) path. This requires possibly stripping the
170 # output (installation) path. This requires possibly stripping the
171 # path separator, because otherwise pjoin will not work correctly
171 # path separator, because otherwise pjoin will not work correctly
172 # (pjoin('foo/','/bar') returns '/bar').
172 # (pjoin('foo/','/bar') returns '/bar').
173
173
174 dp_eff = dirpath[lbase:]
174 dp_eff = dirpath[lbase:]
175 if dp_eff.startswith(pathsep):
175 if dp_eff.startswith(pathsep):
176 dp_eff = dp_eff[lpathsep:]
176 dp_eff = dp_eff[lpathsep:]
177 # The output path must be anchored at the out_base marker
177 # The output path must be anchored at the out_base marker
178 out_path = pjoin(out_base,dp_eff)
178 out_path = pjoin(out_base,dp_eff)
179 # Now we can generate the final filenames. Since os.walk only produces
179 # Now we can generate the final filenames. Since os.walk only produces
180 # filenames, we must join back with the dirpath to get full valid file
180 # filenames, we must join back with the dirpath to get full valid file
181 # paths:
181 # paths:
182 pfiles = [pjoin(dirpath,f) for f in filenames]
182 pfiles = [pjoin(dirpath,f) for f in filenames]
183 # Finally, generate the entry we need, which is a triple of (tag,output
183 # Finally, generate the entry we need, which is a triple of (tag,output
184 # path, files) for use as a data_files parameter in install_data.
184 # path, files) for use as a data_files parameter in install_data.
185 out.append((tag,out_path,pfiles))
185 out.append((tag,out_path,pfiles))
186
186
187 return out
187 return out
188
188
189
189
190 def find_data_files():
190 def find_data_files():
191 """
191 """
192 Find IPython's data_files.
192 Find IPython's data_files.
193
193
194 Most of these are docs.
194 Most of these are docs.
195 """
195 """
196
196
197 docdirbase = pjoin('share', 'doc', 'ipython')
197 docdirbase = pjoin('share', 'doc', 'ipython')
198 manpagebase = pjoin('share', 'man', 'man1')
198 manpagebase = pjoin('share', 'man', 'man1')
199
199
200 # Simple file lists can be made by hand
200 # Simple file lists can be made by hand
201 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
201 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
202 igridhelpfiles = filter(isfile, glob(pjoin('IPython','extensions','igrid_help.*')))
202 igridhelpfiles = filter(isfile, glob(pjoin('IPython','extensions','igrid_help.*')))
203
203
204 # For nested structures, use the utility above
204 # For nested structures, use the utility above
205 example_files = make_dir_struct(
205 example_files = make_dir_struct(
206 'data',
206 'data',
207 pjoin('docs','examples'),
207 pjoin('docs','examples'),
208 pjoin(docdirbase,'examples')
208 pjoin(docdirbase,'examples')
209 )
209 )
210 manual_files = make_dir_struct(
210 manual_files = make_dir_struct(
211 'data',
211 'data',
212 pjoin('docs','dist'),
212 pjoin('docs','dist'),
213 pjoin(docdirbase,'manual')
213 pjoin(docdirbase,'manual')
214 )
214 )
215
215
216 # And assemble the entire output list
216 # And assemble the entire output list
217 data_files = [ ('data',manpagebase, manpages),
217 data_files = [ ('data',manpagebase, manpages),
218 ('data',pjoin(docdirbase,'extensions'),igridhelpfiles),
218 ('data',pjoin(docdirbase,'extensions'),igridhelpfiles),
219 ] + manual_files + example_files
219 ] + manual_files + example_files
220
220
221 ## import pprint # dbg
221 ## import pprint # dbg
222 ## print '*'*80
222 ## print '*'*80
223 ## print 'data files'
223 ## print 'data files'
224 ## pprint.pprint(data_files)
224 ## pprint.pprint(data_files)
225 ## print '*'*80
225 ## print '*'*80
226
226
227 return data_files
227 return data_files
228
228
229
229
230 def make_man_update_target(manpage):
230 def make_man_update_target(manpage):
231 """Return a target_update-compliant tuple for the given manpage.
231 """Return a target_update-compliant tuple for the given manpage.
232
232
233 Parameters
233 Parameters
234 ----------
234 ----------
235 manpage : string
235 manpage : string
236 Name of the manpage, must include the section number (trailing number).
236 Name of the manpage, must include the section number (trailing number).
237
237
238 Example
238 Example
239 -------
239 -------
240
240
241 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
241 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
242 ('docs/man/ipython.1.gz',
242 ('docs/man/ipython.1.gz',
243 ['docs/man/ipython.1'],
243 ['docs/man/ipython.1'],
244 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
244 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
245 """
245 """
246 man_dir = pjoin('docs', 'man')
246 man_dir = pjoin('docs', 'man')
247 manpage_gz = manpage + '.gz'
247 manpage_gz = manpage + '.gz'
248 manpath = pjoin(man_dir, manpage)
248 manpath = pjoin(man_dir, manpage)
249 manpath_gz = pjoin(man_dir, manpage_gz)
249 manpath_gz = pjoin(man_dir, manpage_gz)
250 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
250 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
251 locals() )
251 locals() )
252 return (manpath_gz, [manpath], gz_cmd)
252 return (manpath_gz, [manpath], gz_cmd)
253
253
254 #---------------------------------------------------------------------------
254 #---------------------------------------------------------------------------
255 # Find scripts
255 # Find scripts
256 #---------------------------------------------------------------------------
256 #---------------------------------------------------------------------------
257
257
258 def find_scripts():
258 def find_scripts():
259 """
259 """
260 Find IPython's scripts.
260 Find IPython's scripts.
261 """
261 """
262 kernel_scripts = pjoin('IPython','kernel','scripts')
262 kernel_scripts = pjoin('IPython','kernel','scripts')
263 main_scripts = pjoin('IPython','scripts')
263 main_scripts = pjoin('IPython','scripts')
264 scripts = [pjoin(kernel_scripts, 'ipengine'),
264 scripts = [pjoin(kernel_scripts, 'ipengine'),
265 pjoin(kernel_scripts, 'ipcontroller'),
265 pjoin(kernel_scripts, 'ipcontroller'),
266 pjoin(kernel_scripts, 'ipcluster'),
266 pjoin(kernel_scripts, 'ipcluster'),
267 pjoin(main_scripts, 'ipython'),
267 pjoin(main_scripts, 'ipython'),
268 pjoin(main_scripts, 'ipythonx'),
268 pjoin(main_scripts, 'ipythonx'),
269 pjoin(main_scripts, 'ipython-wx'),
269 pjoin(main_scripts, 'ipython-wx'),
270 pjoin(main_scripts, 'pycolor'),
270 pjoin(main_scripts, 'pycolor'),
271 pjoin(main_scripts, 'irunner'),
271 pjoin(main_scripts, 'irunner'),
272 pjoin(main_scripts, 'iptest')
272 pjoin(main_scripts, 'iptest')
273 ]
273 ]
274
274
275 # Script to be run by the windows binary installer after the default setup
275 # Script to be run by the windows binary installer after the default setup
276 # routine, to add shortcuts and similar windows-only things. Windows
276 # routine, to add shortcuts and similar windows-only things. Windows
277 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
277 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
278 # doesn't find them.
278 # doesn't find them.
279 if 'bdist_wininst' in sys.argv:
279 if 'bdist_wininst' in sys.argv:
280 if len(sys.argv) > 2 and ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
280 if len(sys.argv) > 2 and ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
281 print >> sys.stderr,"ERROR: bdist_wininst must be run alone. Exiting."
281 print >> sys.stderr,"ERROR: bdist_wininst must be run alone. Exiting."
282 sys.exit(1)
282 sys.exit(1)
283 scripts.append(pjoin('scripts','ipython_win_post_install.py'))
283 scripts.append(pjoin('scripts','ipython_win_post_install.py'))
284
284
285 return scripts
285 return scripts
286
286
287 #---------------------------------------------------------------------------
287 #---------------------------------------------------------------------------
288 # Verify all dependencies
288 # Verify all dependencies
289 #---------------------------------------------------------------------------
289 #---------------------------------------------------------------------------
290
290
291 def check_for_dependencies():
291 def check_for_dependencies():
292 """Check for IPython's dependencies.
292 """Check for IPython's dependencies.
293
293
294 This function should NOT be called if running under setuptools!
294 This function should NOT be called if running under setuptools!
295 """
295 """
296 from setupext.setupext import (
296 from setupext.setupext import (
297 print_line, print_raw, print_status, print_message,
297 print_line, print_raw, print_status, print_message,
298 check_for_zopeinterface, check_for_twisted,
298 check_for_zopeinterface, check_for_twisted,
299 check_for_foolscap, check_for_pyopenssl,
299 check_for_foolscap, check_for_pyopenssl,
300 check_for_sphinx, check_for_pygments,
300 check_for_sphinx, check_for_pygments,
301 check_for_nose, check_for_pexpect
301 check_for_nose, check_for_pexpect
302 )
302 )
303 print_line()
303 print_line()
304 print_raw("BUILDING IPYTHON")
304 print_raw("BUILDING IPYTHON")
305 print_status('python', sys.version)
305 print_status('python', sys.version)
306 print_status('platform', sys.platform)
306 print_status('platform', sys.platform)
307 if sys.platform == 'win32':
307 if sys.platform == 'win32':
308 print_status('Windows version', sys.getwindowsversion())
308 print_status('Windows version', sys.getwindowsversion())
309
309
310 print_raw("")
310 print_raw("")
311 print_raw("OPTIONAL DEPENDENCIES")
311 print_raw("OPTIONAL DEPENDENCIES")
312
312
313 check_for_zopeinterface()
313 check_for_zopeinterface()
314 check_for_twisted()
314 check_for_twisted()
315 check_for_foolscap()
315 check_for_foolscap()
316 check_for_pyopenssl()
316 check_for_pyopenssl()
317 check_for_sphinx()
317 check_for_sphinx()
318 check_for_pygments()
318 check_for_pygments()
319 check_for_nose()
319 check_for_nose()
320 check_for_pexpect()
320 check_for_pexpect()
General Comments 0
You need to be logged in to leave comments. Login now