##// END OF EJS Templates
Jorgen Stenarson's patch (minor mods) to support network shares under win32.
fperez -
Show More

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

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