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