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