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