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