##// END OF EJS Templates
use popen in genutils.getoutput
vivainio -
Show More

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

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