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