##// END OF EJS Templates
fix small but critical bug for win32 system access.
fperez -
Show More

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

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