##// END OF EJS Templates
Minor bug fixes and comments to address review....
Brian Granger -
Show More
@@ -1,642 +1,642 b''
1 1 """Word completion for IPython.
2 2
3 3 This module is a fork of the rlcompleter module in the Python standard
4 4 library. The original enhancements made to rlcompleter have been sent
5 5 upstream and were accepted as of Python 2.3, but we need a lot more
6 6 functionality specific to IPython, so this module will continue to live as an
7 7 IPython-specific utility.
8 8
9 9 Original rlcompleter documentation:
10 10
11 11 This requires the latest extension to the readline module (the
12 12 completes keywords, built-ins and globals in __main__; when completing
13 13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
14 14 completes its attributes.
15 15
16 16 It's very cool to do "import string" type "string.", hit the
17 17 completion key (twice), and see the list of names defined by the
18 18 string module!
19 19
20 20 Tip: to use the tab key as the completion key, call
21 21
22 22 readline.parse_and_bind("tab: complete")
23 23
24 24 Notes:
25 25
26 26 - Exceptions raised by the completer function are *ignored* (and
27 27 generally cause the completion to fail). This is a feature -- since
28 28 readline sets the tty device in raw (or cbreak) mode, printing a
29 29 traceback wouldn't work well without some complicated hoopla to save,
30 30 reset and restore the tty state.
31 31
32 32 - The evaluation of the NAME.NAME... form may cause arbitrary
33 33 application defined code to be executed if an object with a
34 34 __getattr__ hook is found. Since it is the responsibility of the
35 35 application (or the user) to enable this feature, I consider this an
36 36 acceptable risk. More complicated expressions (e.g. function calls or
37 37 indexing operations) are *not* evaluated.
38 38
39 39 - GNU readline is also used by the built-in functions input() and
40 40 raw_input(), and thus these also benefit/suffer from the completer
41 41 features. Clearly an interactive application can benefit by
42 42 specifying its own completer function and using raw_input() for all
43 43 its input.
44 44
45 45 - When the original stdin is not a tty device, GNU readline is never
46 46 used, and this module (and the readline module) are silently inactive.
47 47
48 48 """
49 49
50 50 #*****************************************************************************
51 51 #
52 52 # Since this file is essentially a minimally modified copy of the rlcompleter
53 53 # module which is part of the standard Python distribution, I assume that the
54 54 # proper procedure is to maintain its copyright as belonging to the Python
55 55 # Software Foundation (in addition to my own, for all new code).
56 56 #
57 57 # Copyright (C) 2001 Python Software Foundation, www.python.org
58 58 # Copyright (C) 2001-2006 Fernando Perez. <fperez@colorado.edu>
59 59 #
60 60 # Distributed under the terms of the BSD License. The full license is in
61 61 # the file COPYING, distributed as part of this software.
62 62 #
63 63 #*****************************************************************************
64 64
65 65 import __builtin__
66 66 import __main__
67 67 import glob
68 import itertools
68 69 import keyword
69 70 import os
70 71 import re
71 72 import shlex
72 73 import sys
73 import itertools
74 74 import types
75 75
76 76 from IPython.core.error import TryNext
77 77 from IPython.core.prefilter import ESC_MAGIC
78 78
79 79 import IPython.utils.rlineimpl as readline
80 80 from IPython.utils.ipstruct import Struct
81 81 from IPython.utils import generics
82 82
83 83 # Python 2.4 offers sets as a builtin
84 84 try:
85 85 set()
86 86 except NameError:
87 87 from sets import Set as set
88 88
89 89 from IPython.utils.genutils import debugx, dir2
90 90
91 91 __all__ = ['Completer','IPCompleter']
92 92
93 93 class Completer:
94 94 def __init__(self,namespace=None,global_namespace=None):
95 95 """Create a new completer for the command line.
96 96
97 97 Completer([namespace,global_namespace]) -> completer instance.
98 98
99 99 If unspecified, the default namespace where completions are performed
100 100 is __main__ (technically, __main__.__dict__). Namespaces should be
101 101 given as dictionaries.
102 102
103 103 An optional second namespace can be given. This allows the completer
104 104 to handle cases where both the local and global scopes need to be
105 105 distinguished.
106 106
107 107 Completer instances should be used as the completion mechanism of
108 108 readline via the set_completer() call:
109 109
110 110 readline.set_completer(Completer(my_namespace).complete)
111 111 """
112 112
113 113 # Don't bind to namespace quite yet, but flag whether the user wants a
114 114 # specific namespace or to use __main__.__dict__. This will allow us
115 115 # to bind to __main__.__dict__ at completion time, not now.
116 116 if namespace is None:
117 117 self.use_main_ns = 1
118 118 else:
119 119 self.use_main_ns = 0
120 120 self.namespace = namespace
121 121
122 122 # The global namespace, if given, can be bound directly
123 123 if global_namespace is None:
124 124 self.global_namespace = {}
125 125 else:
126 126 self.global_namespace = global_namespace
127 127
128 128 def complete(self, text, state):
129 129 """Return the next possible completion for 'text'.
130 130
131 131 This is called successively with state == 0, 1, 2, ... until it
132 132 returns None. The completion should begin with 'text'.
133 133
134 134 """
135 135 if self.use_main_ns:
136 136 self.namespace = __main__.__dict__
137 137
138 138 if state == 0:
139 139 if "." in text:
140 140 self.matches = self.attr_matches(text)
141 141 else:
142 142 self.matches = self.global_matches(text)
143 143 try:
144 144 return self.matches[state]
145 145 except IndexError:
146 146 return None
147 147
148 148 def global_matches(self, text):
149 149 """Compute matches when text is a simple name.
150 150
151 151 Return a list of all keywords, built-in functions and names currently
152 152 defined in self.namespace or self.global_namespace that match.
153 153
154 154 """
155 155 matches = []
156 156 match_append = matches.append
157 157 n = len(text)
158 158 for lst in [keyword.kwlist,
159 159 __builtin__.__dict__.keys(),
160 160 self.namespace.keys(),
161 161 self.global_namespace.keys()]:
162 162 for word in lst:
163 163 if word[:n] == text and word != "__builtins__":
164 164 match_append(word)
165 165 return matches
166 166
167 167 def attr_matches(self, text):
168 168 """Compute matches when text contains a dot.
169 169
170 170 Assuming the text is of the form NAME.NAME....[NAME], and is
171 171 evaluatable in self.namespace or self.global_namespace, it will be
172 172 evaluated and its attributes (as revealed by dir()) are used as
173 173 possible completions. (For class instances, class members are are
174 174 also considered.)
175 175
176 176 WARNING: this can still invoke arbitrary C code, if an object
177 177 with a __getattr__ hook is evaluated.
178 178
179 179 """
180 180 import re
181 181
182 182 # Another option, seems to work great. Catches things like ''.<tab>
183 183 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
184 184
185 185 if not m:
186 186 return []
187 187
188 188 expr, attr = m.group(1, 3)
189 189 try:
190 190 obj = eval(expr, self.namespace)
191 191 except:
192 192 try:
193 193 obj = eval(expr, self.global_namespace)
194 194 except:
195 195 return []
196 196
197 197 words = dir2(obj)
198 198
199 199 try:
200 200 words = generics.complete_object(obj, words)
201 201 except TryNext:
202 202 pass
203 203 # Build match list to return
204 204 n = len(attr)
205 205 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
206 206 return res
207 207
208 208 class IPCompleter(Completer):
209 209 """Extension of the completer class with IPython-specific features"""
210 210
211 211 def __init__(self,shell,namespace=None,global_namespace=None,
212 212 omit__names=0,alias_table=None):
213 213 """IPCompleter() -> completer
214 214
215 215 Return a completer object suitable for use by the readline library
216 216 via readline.set_completer().
217 217
218 218 Inputs:
219 219
220 220 - shell: a pointer to the ipython shell itself. This is needed
221 221 because this completer knows about magic functions, and those can
222 222 only be accessed via the ipython instance.
223 223
224 224 - namespace: an optional dict where completions are performed.
225 225
226 226 - global_namespace: secondary optional dict for completions, to
227 227 handle cases (such as IPython embedded inside functions) where
228 228 both Python scopes are visible.
229 229
230 230 - The optional omit__names parameter sets the completer to omit the
231 231 'magic' names (__magicname__) for python objects unless the text
232 232 to be completed explicitly starts with one or more underscores.
233 233
234 234 - If alias_table is supplied, it should be a dictionary of aliases
235 235 to complete. """
236 236
237 237 Completer.__init__(self,namespace,global_namespace)
238 238 self.magic_prefix = shell.name+'.magic_'
239 239 self.magic_escape = ESC_MAGIC
240 240 self.readline = readline
241 241 delims = self.readline.get_completer_delims()
242 242 delims = delims.replace(self.magic_escape,'')
243 243 self.readline.set_completer_delims(delims)
244 244 self.get_line_buffer = self.readline.get_line_buffer
245 245 self.get_endidx = self.readline.get_endidx
246 246 self.omit__names = omit__names
247 247 self.merge_completions = shell.readline_merge_completions
248 248 if alias_table is None:
249 249 alias_table = {}
250 250 self.alias_table = alias_table
251 251 # Regexp to split filenames with spaces in them
252 252 self.space_name_re = re.compile(r'([^\\] )')
253 253 # Hold a local ref. to glob.glob for speed
254 254 self.glob = glob.glob
255 255
256 256 # Determine if we are running on 'dumb' terminals, like (X)Emacs
257 257 # buffers, to avoid completion problems.
258 258 term = os.environ.get('TERM','xterm')
259 259 self.dumb_terminal = term in ['dumb','emacs']
260 260
261 261 # Special handling of backslashes needed in win32 platforms
262 262 if sys.platform == "win32":
263 263 self.clean_glob = self._clean_glob_win32
264 264 else:
265 265 self.clean_glob = self._clean_glob
266 266 self.matchers = [self.python_matches,
267 267 self.file_matches,
268 268 self.alias_matches,
269 269 self.python_func_kw_matches]
270 270
271 271
272 272 # Code contributed by Alex Schmolck, for ipython/emacs integration
273 273 def all_completions(self, text):
274 274 """Return all possible completions for the benefit of emacs."""
275 275
276 276 completions = []
277 277 comp_append = completions.append
278 278 try:
279 279 for i in xrange(sys.maxint):
280 280 res = self.complete(text, i)
281 281
282 282 if not res: break
283 283
284 284 comp_append(res)
285 285 #XXX workaround for ``notDefined.<tab>``
286 286 except NameError:
287 287 pass
288 288 return completions
289 289 # /end Alex Schmolck code.
290 290
291 291 def _clean_glob(self,text):
292 292 return self.glob("%s*" % text)
293 293
294 294 def _clean_glob_win32(self,text):
295 295 return [f.replace("\\","/")
296 296 for f in self.glob("%s*" % text)]
297 297
298 298 def file_matches(self, text):
299 299 """Match filenames, expanding ~USER type strings.
300 300
301 301 Most of the seemingly convoluted logic in this completer is an
302 302 attempt to handle filenames with spaces in them. And yet it's not
303 303 quite perfect, because Python's readline doesn't expose all of the
304 304 GNU readline details needed for this to be done correctly.
305 305
306 306 For a filename with a space in it, the printed completions will be
307 307 only the parts after what's already been typed (instead of the
308 308 full completions, as is normally done). I don't think with the
309 309 current (as of Python 2.3) Python readline it's possible to do
310 310 better."""
311 311
312 312 #print 'Completer->file_matches: <%s>' % text # dbg
313 313
314 314 # chars that require escaping with backslash - i.e. chars
315 315 # that readline treats incorrectly as delimiters, but we
316 316 # don't want to treat as delimiters in filename matching
317 317 # when escaped with backslash
318 318
319 319 if sys.platform == 'win32':
320 320 protectables = ' '
321 321 else:
322 322 protectables = ' ()'
323 323
324 324 if text.startswith('!'):
325 325 text = text[1:]
326 326 text_prefix = '!'
327 327 else:
328 328 text_prefix = ''
329 329
330 330 def protect_filename(s):
331 331 return "".join([(ch in protectables and '\\' + ch or ch)
332 332 for ch in s])
333 333
334 334 def single_dir_expand(matches):
335 335 "Recursively expand match lists containing a single dir."
336 336
337 337 if len(matches) == 1 and os.path.isdir(matches[0]):
338 338 # Takes care of links to directories also. Use '/'
339 339 # explicitly, even under Windows, so that name completions
340 340 # don't end up escaped.
341 341 d = matches[0]
342 342 if d[-1] in ['/','\\']:
343 343 d = d[:-1]
344 344
345 345 subdirs = os.listdir(d)
346 346 if subdirs:
347 347 matches = [ (d + '/' + p) for p in subdirs]
348 348 return single_dir_expand(matches)
349 349 else:
350 350 return matches
351 351 else:
352 352 return matches
353 353
354 354 lbuf = self.lbuf
355 355 open_quotes = 0 # track strings with open quotes
356 356 try:
357 357 lsplit = shlex.split(lbuf)[-1]
358 358 except ValueError:
359 359 # typically an unmatched ", or backslash without escaped char.
360 360 if lbuf.count('"')==1:
361 361 open_quotes = 1
362 362 lsplit = lbuf.split('"')[-1]
363 363 elif lbuf.count("'")==1:
364 364 open_quotes = 1
365 365 lsplit = lbuf.split("'")[-1]
366 366 else:
367 367 return []
368 368 except IndexError:
369 369 # tab pressed on empty line
370 370 lsplit = ""
371 371
372 372 if lsplit != protect_filename(lsplit):
373 373 # if protectables are found, do matching on the whole escaped
374 374 # name
375 375 has_protectables = 1
376 376 text0,text = text,lsplit
377 377 else:
378 378 has_protectables = 0
379 379 text = os.path.expanduser(text)
380 380
381 381 if text == "":
382 382 return [text_prefix + protect_filename(f) for f in self.glob("*")]
383 383
384 384 m0 = self.clean_glob(text.replace('\\',''))
385 385 if has_protectables:
386 386 # If we had protectables, we need to revert our changes to the
387 387 # beginning of filename so that we don't double-write the part
388 388 # of the filename we have so far
389 389 len_lsplit = len(lsplit)
390 390 matches = [text_prefix + text0 +
391 391 protect_filename(f[len_lsplit:]) for f in m0]
392 392 else:
393 393 if open_quotes:
394 394 # if we have a string with an open quote, we don't need to
395 395 # protect the names at all (and we _shouldn't_, as it
396 396 # would cause bugs when the filesystem call is made).
397 397 matches = m0
398 398 else:
399 399 matches = [text_prefix +
400 400 protect_filename(f) for f in m0]
401 401
402 402 #print 'mm',matches # dbg
403 403 return single_dir_expand(matches)
404 404
405 405 def alias_matches(self, text):
406 406 """Match internal system aliases"""
407 407 #print 'Completer->alias_matches:',text,'lb',self.lbuf # dbg
408 408
409 409 # if we are not in the first 'item', alias matching
410 410 # doesn't make sense - unless we are starting with 'sudo' command.
411 411 if ' ' in self.lbuf.lstrip() and not self.lbuf.lstrip().startswith('sudo'):
412 412 return []
413 413 text = os.path.expanduser(text)
414 414 aliases = self.alias_table.keys()
415 415 if text == "":
416 416 return aliases
417 417 else:
418 418 return [alias for alias in aliases if alias.startswith(text)]
419 419
420 420 def python_matches(self,text):
421 421 """Match attributes or global python names"""
422 422
423 423 #print 'Completer->python_matches, txt=<%s>' % text # dbg
424 424 if "." in text:
425 425 try:
426 426 matches = self.attr_matches(text)
427 427 if text.endswith('.') and self.omit__names:
428 428 if self.omit__names == 1:
429 429 # true if txt is _not_ a __ name, false otherwise:
430 430 no__name = (lambda txt:
431 431 re.match(r'.*\.__.*?__',txt) is None)
432 432 else:
433 433 # true if txt is _not_ a _ name, false otherwise:
434 434 no__name = (lambda txt:
435 435 re.match(r'.*\._.*?',txt) is None)
436 436 matches = filter(no__name, matches)
437 437 except NameError:
438 438 # catches <undefined attributes>.<tab>
439 439 matches = []
440 440 else:
441 441 matches = self.global_matches(text)
442 442 # this is so completion finds magics when automagic is on:
443 443 if (matches == [] and
444 444 not text.startswith(os.sep) and
445 445 not ' ' in self.lbuf):
446 446 matches = self.attr_matches(self.magic_prefix+text)
447 447 return matches
448 448
449 449 def _default_arguments(self, obj):
450 450 """Return the list of default arguments of obj if it is callable,
451 451 or empty list otherwise."""
452 452
453 453 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
454 454 # for classes, check for __init__,__new__
455 455 if inspect.isclass(obj):
456 456 obj = (getattr(obj,'__init__',None) or
457 457 getattr(obj,'__new__',None))
458 458 # for all others, check if they are __call__able
459 459 elif hasattr(obj, '__call__'):
460 460 obj = obj.__call__
461 461 # XXX: is there a way to handle the builtins ?
462 462 try:
463 463 args,_,_1,defaults = inspect.getargspec(obj)
464 464 if defaults:
465 465 return args[-len(defaults):]
466 466 except TypeError: pass
467 467 return []
468 468
469 469 def python_func_kw_matches(self,text):
470 470 """Match named parameters (kwargs) of the last open function"""
471 471
472 472 if "." in text: # a parameter cannot be dotted
473 473 return []
474 474 try: regexp = self.__funcParamsRegex
475 475 except AttributeError:
476 476 regexp = self.__funcParamsRegex = re.compile(r'''
477 477 '.*?' | # single quoted strings or
478 478 ".*?" | # double quoted strings or
479 479 \w+ | # identifier
480 480 \S # other characters
481 481 ''', re.VERBOSE | re.DOTALL)
482 482 # 1. find the nearest identifier that comes before an unclosed
483 483 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
484 484 tokens = regexp.findall(self.get_line_buffer())
485 485 tokens.reverse()
486 486 iterTokens = iter(tokens); openPar = 0
487 487 for token in iterTokens:
488 488 if token == ')':
489 489 openPar -= 1
490 490 elif token == '(':
491 491 openPar += 1
492 492 if openPar > 0:
493 493 # found the last unclosed parenthesis
494 494 break
495 495 else:
496 496 return []
497 497 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
498 498 ids = []
499 499 isId = re.compile(r'\w+$').match
500 500 while True:
501 501 try:
502 502 ids.append(iterTokens.next())
503 503 if not isId(ids[-1]):
504 504 ids.pop(); break
505 505 if not iterTokens.next() == '.':
506 506 break
507 507 except StopIteration:
508 508 break
509 509 # lookup the candidate callable matches either using global_matches
510 510 # or attr_matches for dotted names
511 511 if len(ids) == 1:
512 512 callableMatches = self.global_matches(ids[0])
513 513 else:
514 514 callableMatches = self.attr_matches('.'.join(ids[::-1]))
515 515 argMatches = []
516 516 for callableMatch in callableMatches:
517 517 try: namedArgs = self._default_arguments(eval(callableMatch,
518 518 self.namespace))
519 519 except: continue
520 520 for namedArg in namedArgs:
521 521 if namedArg.startswith(text):
522 522 argMatches.append("%s=" %namedArg)
523 523 return argMatches
524 524
525 525 def dispatch_custom_completer(self,text):
526 526 #print "Custom! '%s' %s" % (text, self.custom_completers) # dbg
527 527 line = self.full_lbuf
528 528 if not line.strip():
529 529 return None
530 530
531 531 event = Struct()
532 532 event.line = line
533 533 event.symbol = text
534 534 cmd = line.split(None,1)[0]
535 535 event.command = cmd
536 536 #print "\ncustom:{%s]\n" % event # dbg
537 537
538 538 # for foo etc, try also to find completer for %foo
539 539 if not cmd.startswith(self.magic_escape):
540 540 try_magic = self.custom_completers.s_matches(
541 541 self.magic_escape + cmd)
542 542 else:
543 543 try_magic = []
544 544
545 545
546 546 for c in itertools.chain(
547 547 self.custom_completers.s_matches(cmd),
548 548 try_magic,
549 549 self.custom_completers.flat_matches(self.lbuf)):
550 550 #print "try",c # dbg
551 551 try:
552 552 res = c(event)
553 553 # first, try case sensitive match
554 554 withcase = [r for r in res if r.startswith(text)]
555 555 if withcase:
556 556 return withcase
557 557 # if none, then case insensitive ones are ok too
558 558 return [r for r in res if r.lower().startswith(text.lower())]
559 559 except TryNext:
560 560 pass
561 561
562 562 return None
563 563
564 564 def complete(self, text, state,line_buffer=None):
565 565 """Return the next possible completion for 'text'.
566 566
567 567 This is called successively with state == 0, 1, 2, ... until it
568 568 returns None. The completion should begin with 'text'.
569 569
570 570 :Keywords:
571 571 - line_buffer: string
572 572 If not given, the completer attempts to obtain the current line buffer
573 573 via readline. This keyword allows clients which are requesting for
574 574 text completions in non-readline contexts to inform the completer of
575 575 the entire text.
576 576 """
577 577
578 578 #print '\n*** COMPLETE: <%s> (%s)' % (text,state) # dbg
579 579
580 580 # if there is only a tab on a line with only whitespace, instead
581 581 # of the mostly useless 'do you want to see all million
582 582 # completions' message, just do the right thing and give the user
583 583 # his tab! Incidentally, this enables pasting of tabbed text from
584 584 # an editor (as long as autoindent is off).
585 585
586 586 # It should be noted that at least pyreadline still shows
587 587 # file completions - is there a way around it?
588 588
589 589 # don't apply this on 'dumb' terminals, such as emacs buffers, so we
590 590 # don't interfere with their own tab-completion mechanism.
591 591 if line_buffer is None:
592 592 self.full_lbuf = self.get_line_buffer()
593 593 else:
594 594 self.full_lbuf = line_buffer
595 595
596 596 if not (self.dumb_terminal or self.full_lbuf.strip()):
597 597 self.readline.insert_text('\t')
598 598 return None
599 599
600 600 magic_escape = self.magic_escape
601 601 magic_prefix = self.magic_prefix
602 602
603 603 self.lbuf = self.full_lbuf[:self.get_endidx()]
604 604
605 605 try:
606 606 if text.startswith(magic_escape):
607 607 text = text.replace(magic_escape,magic_prefix)
608 608 elif text.startswith('~'):
609 609 text = os.path.expanduser(text)
610 610 if state == 0:
611 611 custom_res = self.dispatch_custom_completer(text)
612 612 if custom_res is not None:
613 613 # did custom completers produce something?
614 614 self.matches = custom_res
615 615 else:
616 616 # Extend the list of completions with the results of each
617 617 # matcher, so we return results to the user from all
618 618 # namespaces.
619 619 if self.merge_completions:
620 620 self.matches = []
621 621 for matcher in self.matchers:
622 622 self.matches.extend(matcher(text))
623 623 else:
624 624 for matcher in self.matchers:
625 625 self.matches = matcher(text)
626 626 if self.matches:
627 627 break
628 628 def uniq(alist):
629 629 set = {}
630 630 return [set.setdefault(e,e) for e in alist if e not in set]
631 631 self.matches = uniq(self.matches)
632 632 try:
633 633 ret = self.matches[state].replace(magic_prefix,magic_escape)
634 634 return ret
635 635 except IndexError:
636 636 return None
637 637 except:
638 638 #from IPython.core.ultratb import AutoFormattedTB; # dbg
639 639 #tb=AutoFormattedTB('Verbose');tb() #dbg
640 640
641 641 # If completion fails, don't annoy the user.
642 642 return None
@@ -1,306 +1,306 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 Paging capabilities for IPython.core
5 5
6 6 Authors:
7 7
8 8 * Brian Granger
9 9 * Fernando Perez
10 10
11 11 Notes
12 12 -----
13 13
14 14 For now this uses ipapi, so it can't be in IPython.utils. If we can get
15 15 rid of that dependency, we could move it there.
16 16 -----
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Copyright (C) 2008-2009 The IPython Development Team
21 21 #
22 22 # Distributed under the terms of the BSD License. The full license is in
23 23 # the file COPYING, distributed as part of this software.
24 24 #-----------------------------------------------------------------------------
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Imports
28 28 #-----------------------------------------------------------------------------
29 29
30 30 import os
31 31 import re
32 32 import sys
33 33
34 34 from IPython.core import ipapi
35 35 from IPython.core.error import TryNext
36 36 from IPython.utils.genutils import (
37 chop, Term
37 chop, Term, USE_CURSES
38 38 )
39 39
40 40 if os.name == "nt":
41 41 from IPython.utils.winconsole import get_console_size
42 42
43 43
44 44 #-----------------------------------------------------------------------------
45 45 # Classes and functions
46 46 #-----------------------------------------------------------------------------
47 47
48 48 esc_re = re.compile(r"(\x1b[^m]+m)")
49 49
50 50 def page_dumb(strng,start=0,screen_lines=25):
51 51 """Very dumb 'pager' in Python, for when nothing else works.
52 52
53 53 Only moves forward, same interface as page(), except for pager_cmd and
54 54 mode."""
55 55
56 56 out_ln = strng.splitlines()[start:]
57 57 screens = chop(out_ln,screen_lines-1)
58 58 if len(screens) == 1:
59 59 print >>Term.cout, os.linesep.join(screens[0])
60 60 else:
61 61 last_escape = ""
62 62 for scr in screens[0:-1]:
63 63 hunk = os.linesep.join(scr)
64 64 print >>Term.cout, last_escape + hunk
65 65 if not page_more():
66 66 return
67 67 esc_list = esc_re.findall(hunk)
68 68 if len(esc_list) > 0:
69 69 last_escape = esc_list[-1]
70 70 print >>Term.cout, last_escape + os.linesep.join(screens[-1])
71 71
72 72 #----------------------------------------------------------------------------
73 73 def page(strng,start=0,screen_lines=0,pager_cmd = None):
74 74 """Print a string, piping through a pager after a certain length.
75 75
76 76 The screen_lines parameter specifies the number of *usable* lines of your
77 77 terminal screen (total lines minus lines you need to reserve to show other
78 78 information).
79 79
80 80 If you set screen_lines to a number <=0, page() will try to auto-determine
81 81 your screen size and will only use up to (screen_size+screen_lines) for
82 82 printing, paging after that. That is, if you want auto-detection but need
83 83 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
84 84 auto-detection without any lines reserved simply use screen_lines = 0.
85 85
86 86 If a string won't fit in the allowed lines, it is sent through the
87 87 specified pager command. If none given, look for PAGER in the environment,
88 88 and ultimately default to less.
89 89
90 90 If no system pager works, the string is sent through a 'dumb pager'
91 91 written in python, very simplistic.
92 92 """
93 93
94 94 # Some routines may auto-compute start offsets incorrectly and pass a
95 95 # negative value. Offset to 0 for robustness.
96 96 start = max(0,start)
97 97
98 98 # first, try the hook
99 99 ip = ipapi.get()
100 100 if ip:
101 101 try:
102 102 ip.hooks.show_in_pager(strng)
103 103 return
104 104 except TryNext:
105 105 pass
106 106
107 107 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
108 108 TERM = os.environ.get('TERM','dumb')
109 109 if TERM in ['dumb','emacs'] and os.name != 'nt':
110 110 print strng
111 111 return
112 112 # chop off the topmost part of the string we don't want to see
113 113 str_lines = strng.split(os.linesep)[start:]
114 114 str_toprint = os.linesep.join(str_lines)
115 115 num_newlines = len(str_lines)
116 116 len_str = len(str_toprint)
117 117
118 118 # Dumb heuristics to guesstimate number of on-screen lines the string
119 119 # takes. Very basic, but good enough for docstrings in reasonable
120 120 # terminals. If someone later feels like refining it, it's not hard.
121 121 numlines = max(num_newlines,int(len_str/80)+1)
122 122
123 123 if os.name == "nt":
124 124 screen_lines_def = get_console_size(defaulty=25)[1]
125 125 else:
126 126 screen_lines_def = 25 # default value if we can't auto-determine
127 127
128 128 # auto-determine screen size
129 129 if screen_lines <= 0:
130 130 if TERM=='xterm':
131 131 use_curses = USE_CURSES
132 132 else:
133 133 # curses causes problems on many terminals other than xterm.
134 134 use_curses = False
135 135 if use_curses:
136 136 # There is a bug in curses, where *sometimes* it fails to properly
137 137 # initialize, and then after the endwin() call is made, the
138 138 # terminal is left in an unusable state. Rather than trying to
139 139 # check everytime for this (by requesting and comparing termios
140 140 # flags each time), we just save the initial terminal state and
141 141 # unconditionally reset it every time. It's cheaper than making
142 142 # the checks.
143 143 term_flags = termios.tcgetattr(sys.stdout)
144 144 scr = curses.initscr()
145 145 screen_lines_real,screen_cols = scr.getmaxyx()
146 146 curses.endwin()
147 147 # Restore terminal state in case endwin() didn't.
148 148 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
149 149 # Now we have what we needed: the screen size in rows/columns
150 150 screen_lines += screen_lines_real
151 151 #print '***Screen size:',screen_lines_real,'lines x',\
152 152 #screen_cols,'columns.' # dbg
153 153 else:
154 154 screen_lines += screen_lines_def
155 155
156 156 #print 'numlines',numlines,'screenlines',screen_lines # dbg
157 157 if numlines <= screen_lines :
158 158 #print '*** normal print' # dbg
159 159 print >>Term.cout, str_toprint
160 160 else:
161 161 # Try to open pager and default to internal one if that fails.
162 162 # All failure modes are tagged as 'retval=1', to match the return
163 163 # value of a failed system command. If any intermediate attempt
164 164 # sets retval to 1, at the end we resort to our own page_dumb() pager.
165 165 pager_cmd = get_pager_cmd(pager_cmd)
166 166 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
167 167 if os.name == 'nt':
168 168 if pager_cmd.startswith('type'):
169 169 # The default WinXP 'type' command is failing on complex strings.
170 170 retval = 1
171 171 else:
172 172 tmpname = tempfile.mktemp('.txt')
173 173 tmpfile = file(tmpname,'wt')
174 174 tmpfile.write(strng)
175 175 tmpfile.close()
176 176 cmd = "%s < %s" % (pager_cmd,tmpname)
177 177 if os.system(cmd):
178 178 retval = 1
179 179 else:
180 180 retval = None
181 181 os.remove(tmpname)
182 182 else:
183 183 try:
184 184 retval = None
185 185 # if I use popen4, things hang. No idea why.
186 186 #pager,shell_out = os.popen4(pager_cmd)
187 187 pager = os.popen(pager_cmd,'w')
188 188 pager.write(strng)
189 189 pager.close()
190 190 retval = pager.close() # success returns None
191 191 except IOError,msg: # broken pipe when user quits
192 192 if msg.args == (32,'Broken pipe'):
193 193 retval = None
194 194 else:
195 195 retval = 1
196 196 except OSError:
197 197 # Other strange problems, sometimes seen in Win2k/cygwin
198 198 retval = 1
199 199 if retval is not None:
200 200 page_dumb(strng,screen_lines=screen_lines)
201 201
202 202 #----------------------------------------------------------------------------
203 203 def page_file(fname,start = 0, pager_cmd = None):
204 204 """Page a file, using an optional pager command and starting line.
205 205 """
206 206
207 207 pager_cmd = get_pager_cmd(pager_cmd)
208 208 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
209 209
210 210 try:
211 211 if os.environ['TERM'] in ['emacs','dumb']:
212 212 raise EnvironmentError
213 213 xsys(pager_cmd + ' ' + fname)
214 214 except:
215 215 try:
216 216 if start > 0:
217 217 start -= 1
218 218 page(open(fname).read(),start)
219 219 except:
220 220 print 'Unable to show file',`fname`
221 221
222 222 #----------------------------------------------------------------------------
223 223 def get_pager_cmd(pager_cmd = None):
224 224 """Return a pager command.
225 225
226 226 Makes some attempts at finding an OS-correct one."""
227 227
228 228 if os.name == 'posix':
229 229 default_pager_cmd = 'less -r' # -r for color control sequences
230 230 elif os.name in ['nt','dos']:
231 231 default_pager_cmd = 'type'
232 232
233 233 if pager_cmd is None:
234 234 try:
235 235 pager_cmd = os.environ['PAGER']
236 236 except:
237 237 pager_cmd = default_pager_cmd
238 238 return pager_cmd
239 239
240 240 #-----------------------------------------------------------------------------
241 241 def get_pager_start(pager,start):
242 242 """Return the string for paging files with an offset.
243 243
244 244 This is the '+N' argument which less and more (under Unix) accept.
245 245 """
246 246
247 247 if pager in ['less','more']:
248 248 if start:
249 249 start_string = '+' + str(start)
250 250 else:
251 251 start_string = ''
252 252 else:
253 253 start_string = ''
254 254 return start_string
255 255
256 256 #----------------------------------------------------------------------------
257 257 # (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch()
258 258 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
259 259 import msvcrt
260 260 def page_more():
261 261 """ Smart pausing between pages
262 262
263 263 @return: True if need print more lines, False if quit
264 264 """
265 265 Term.cout.write('---Return to continue, q to quit--- ')
266 266 ans = msvcrt.getch()
267 267 if ans in ("q", "Q"):
268 268 result = False
269 269 else:
270 270 result = True
271 271 Term.cout.write("\b"*37 + " "*37 + "\b"*37)
272 272 return result
273 273 else:
274 274 def page_more():
275 275 ans = raw_input('---Return to continue, q to quit--- ')
276 276 if ans.lower().startswith('q'):
277 277 return False
278 278 else:
279 279 return True
280 280
281 281 #----------------------------------------------------------------------------
282 282 def snip_print(str,width = 75,print_full = 0,header = ''):
283 283 """Print a string snipping the midsection to fit in width.
284 284
285 285 print_full: mode control:
286 286 - 0: only snip long strings
287 287 - 1: send to page() directly.
288 288 - 2: snip long strings and ask for full length viewing with page()
289 289 Return 1 if snipping was necessary, 0 otherwise."""
290 290
291 291 if print_full == 1:
292 292 page(header+str)
293 293 return 0
294 294
295 295 print header,
296 296 if len(str) < width:
297 297 print str
298 298 snip = 0
299 299 else:
300 300 whalf = int((width -5)/2)
301 301 print str[:whalf] + ' <...> ' + str[-whalf:]
302 302 snip = 1
303 303 if snip and print_full == 2:
304 304 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
305 305 page(str)
306 306 return snip No newline at end of file
@@ -1,28 +1,28 b''
1 1 #!/usr/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 """IPython -- An enhanced Interactive Python
4 4
5 5 This is just the startup wrapper script, kept deliberately to a minimum.
6 6
7 7 The shell's mainloop() takes an optional argument, sys_exit (default=0). If
8 8 set to 1, it calls sys.exit() at exit time. You can use the following code in
9 9 your PYTHONSTARTUP file:
10 10
11 11 import IPython
12 12 IPython.Shell.IPShell().mainloop(sys_exit=1)
13 13
14 14 [or simply IPython.Shell.IPShell().mainloop(1) ]
15 15
16 16 and IPython will be your working environment when you start python. The final
17 17 sys.exit() call will make python exit transparently when IPython finishes, so
18 18 you don't have an extra prompt to get out of.
19 19
20 20 This is probably useful to developers who manage multiple Python versions and
21 21 don't want to have correspondingly multiple IPython versions. Note that in
22 22 this mode, there is no way to pass IPython any command-line options, as those
23 23 are trapped first by Python itself.
24 24 """
25 25
26 import IPython.core.ipapi import launch_new_instance
26 from IPython.core.ipapi import launch_new_instance
27 27
28 28 launch_new_instance()
@@ -1,101 +1,109 b''
1 1 """A Simple wx example to test IPython's event loop integration.
2 2
3 3 To run this do:
4 4
5 5 In [5]: %gui wx
6 6
7 7 In [6]: %run gui-wx.py
8 8
9 9 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
10 10
11 11 This example can only be run once in a given IPython session because when
12 12 the frame is closed, wx goes through its shutdown sequence, killing further
13 13 attempts. I am sure someone who knows wx can fix this issue.
14
15 Furthermore, once this example is run, the Wx event loop is mostly dead, so
16 even other new uses of Wx may not work correctly. If you know how to better
17 handle this, please contact the ipython developers and let us know.
18
19 Note however that we will work with the Matplotlib and Enthought developers so
20 that the main interactive uses of Wx we are aware of, namely these tools, will
21 continue to work well with IPython interactively.
14 22 """
15 23
16 24 import wx
17 25
18 26
19 27 class MyFrame(wx.Frame):
20 28 """
21 29 This is MyFrame. It just shows a few controls on a wxPanel,
22 30 and has a simple menu.
23 31 """
24 32 def __init__(self, parent, title):
25 33 wx.Frame.__init__(self, parent, -1, title,
26 34 pos=(150, 150), size=(350, 200))
27 35
28 36 # Create the menubar
29 37 menuBar = wx.MenuBar()
30 38
31 39 # and a menu
32 40 menu = wx.Menu()
33 41
34 42 # add an item to the menu, using \tKeyName automatically
35 43 # creates an accelerator, the third param is some help text
36 44 # that will show up in the statusbar
37 45 menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample")
38 46
39 47 # bind the menu event to an event handler
40 48 self.Bind(wx.EVT_MENU, self.OnTimeToClose, id=wx.ID_EXIT)
41 49
42 50 # and put the menu on the menubar
43 51 menuBar.Append(menu, "&File")
44 52 self.SetMenuBar(menuBar)
45 53
46 54 self.CreateStatusBar()
47 55
48 56 # Now create the Panel to put the other controls on.
49 57 panel = wx.Panel(self)
50 58
51 59 # and a few controls
52 60 text = wx.StaticText(panel, -1, "Hello World!")
53 61 text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))
54 62 text.SetSize(text.GetBestSize())
55 63 btn = wx.Button(panel, -1, "Close")
56 64 funbtn = wx.Button(panel, -1, "Just for fun...")
57 65
58 66 # bind the button events to handlers
59 67 self.Bind(wx.EVT_BUTTON, self.OnTimeToClose, btn)
60 68 self.Bind(wx.EVT_BUTTON, self.OnFunButton, funbtn)
61 69
62 70 # Use a sizer to layout the controls, stacked vertically and with
63 71 # a 10 pixel border around each
64 72 sizer = wx.BoxSizer(wx.VERTICAL)
65 73 sizer.Add(text, 0, wx.ALL, 10)
66 74 sizer.Add(btn, 0, wx.ALL, 10)
67 75 sizer.Add(funbtn, 0, wx.ALL, 10)
68 76 panel.SetSizer(sizer)
69 77 panel.Layout()
70 78
71 79
72 80 def OnTimeToClose(self, evt):
73 81 """Event handler for the button click."""
74 82 print "See ya later!"
75 83 self.Close()
76 84
77 85 def OnFunButton(self, evt):
78 86 """Event handler for the button click."""
79 87 print "Having fun yet?"
80 88
81 89
82 90 class MyApp(wx.App):
83 91 def OnInit(self):
84 92 frame = MyFrame(None, "Simple wxPython App")
85 93 self.SetTopWindow(frame)
86 94
87 95 print "Print statements go to this stdout window by default."
88 96
89 97 frame.Show(True)
90 98 return True
91 99
92 100 app = wx.GetApp()
93 101 if app is None:
94 102 app = MyApp(redirect=False, clearSigInt=False)
95 103
96 104 try:
97 105 from IPython.lib.inputhook import appstart_wx
98 106 appstart_wx(app)
99 107 except ImportError:
100 108 app.MainLoop()
101 109
General Comments 0
You need to be logged in to leave comments. Login now