##// END OF EJS Templates
More work addressing review comments for Fernando's branch....
Brian Granger -
Show More
@@ -1,2558 +1,2558 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Main IPython Component
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
8 8 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
9 9 # Copyright (C) 2008-2009 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from __future__ import with_statement
20 20 from __future__ import absolute_import
21 21
22 22 import __builtin__
23 23 import bdb
24 24 import codeop
25 25 import exceptions
26 26 import new
27 27 import os
28 28 import re
29 29 import string
30 30 import sys
31 31 import tempfile
32 32 from contextlib import nested
33 33
34 34 from IPython.core import debugger, oinspect
35 35 from IPython.core import history as ipcorehist
36 36 from IPython.core import prefilter
37 37 from IPython.core import shadowns
38 38 from IPython.core import ultratb
39 39 from IPython.core.alias import AliasManager
40 40 from IPython.core.builtin_trap import BuiltinTrap
41 41 from IPython.core.component import Component
42 42 from IPython.core.display_trap import DisplayTrap
43 43 from IPython.core.error import TryNext, UsageError
44 44 from IPython.core.fakemodule import FakeModule, init_fakemod_dict
45 45 from IPython.core.logger import Logger
46 46 from IPython.core.magic import Magic
47 47 from IPython.core.prefilter import PrefilterManager
48 48 from IPython.core.prompts import CachedOutput
49 49 from IPython.core.usage import interactive_usage, default_banner
50 50 import IPython.core.hooks
51 51 from IPython.external.Itpl import ItplNS
52 52 from IPython.lib.inputhook import enable_gui
53 53 from IPython.lib.backgroundjobs import BackgroundJobManager
54 54 from IPython.lib.pylabtools import pylab_activate
55 55 from IPython.utils import PyColorize
56 56 from IPython.utils import pickleshare
57 57 from IPython.utils.doctestreload import doctest_reload
58 58 from IPython.utils.ipstruct import Struct
59 59 from IPython.utils.io import Term, ask_yes_no
60 60 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
61 61 from IPython.utils.process import (
62 62 abbrev_cwd,
63 63 getoutput,
64 64 getoutputerror
65 65 )
66 66 # import IPython.utils.rlineimpl as readline
67 67 from IPython.utils.strdispatch import StrDispatch
68 68 from IPython.utils.syspathcontext import prepended_to_syspath
69 69 from IPython.utils.terminal import toggle_set_term_title, set_term_title
70 70 from IPython.utils.warn import warn, error, fatal
71 71 from IPython.utils.traitlets import (
72 72 Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode
73 73 )
74 74
75 75 # from IPython.utils import growl
76 76 # growl.start("IPython")
77 77
78 78 #-----------------------------------------------------------------------------
79 79 # Globals
80 80 #-----------------------------------------------------------------------------
81 81
82 82 # store the builtin raw_input globally, and use this always, in case user code
83 83 # overwrites it (like wx.py.PyShell does)
84 84 raw_input_original = raw_input
85 85
86 86 # compiled regexps for autoindent management
87 87 dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass')
88 88
89 89 #-----------------------------------------------------------------------------
90 90 # Utilities
91 91 #-----------------------------------------------------------------------------
92 92
93 93 ini_spaces_re = re.compile(r'^(\s+)')
94 94
95 95
96 96 def num_ini_spaces(strng):
97 97 """Return the number of initial spaces in a string"""
98 98
99 99 ini_spaces = ini_spaces_re.match(strng)
100 100 if ini_spaces:
101 101 return ini_spaces.end()
102 102 else:
103 103 return 0
104 104
105 105
106 106 def softspace(file, newvalue):
107 107 """Copied from code.py, to remove the dependency"""
108 108
109 109 oldvalue = 0
110 110 try:
111 111 oldvalue = file.softspace
112 112 except AttributeError:
113 113 pass
114 114 try:
115 115 file.softspace = newvalue
116 116 except (AttributeError, TypeError):
117 117 # "attribute-less object" or "read-only attributes"
118 118 pass
119 119 return oldvalue
120 120
121 121
122 122 def no_op(*a, **kw): pass
123 123
124 124 class SpaceInInput(exceptions.Exception): pass
125 125
126 126 class Bunch: pass
127 127
128 128 class InputList(list):
129 129 """Class to store user input.
130 130
131 131 It's basically a list, but slices return a string instead of a list, thus
132 132 allowing things like (assuming 'In' is an instance):
133 133
134 134 exec In[4:7]
135 135
136 136 or
137 137
138 138 exec In[5:9] + In[14] + In[21:25]"""
139 139
140 140 def __getslice__(self,i,j):
141 141 return ''.join(list.__getslice__(self,i,j))
142 142
143 143
144 144 class SyntaxTB(ultratb.ListTB):
145 145 """Extension which holds some state: the last exception value"""
146 146
147 147 def __init__(self,color_scheme = 'NoColor'):
148 148 ultratb.ListTB.__init__(self,color_scheme)
149 149 self.last_syntax_error = None
150 150
151 151 def __call__(self, etype, value, elist):
152 152 self.last_syntax_error = value
153 153 ultratb.ListTB.__call__(self,etype,value,elist)
154 154
155 155 def clear_err_state(self):
156 156 """Return the current error state and clear it"""
157 157 e = self.last_syntax_error
158 158 self.last_syntax_error = None
159 159 return e
160 160
161 161
162 162 def get_default_editor():
163 163 try:
164 164 ed = os.environ['EDITOR']
165 165 except KeyError:
166 166 if os.name == 'posix':
167 167 ed = 'vi' # the only one guaranteed to be there!
168 168 else:
169 169 ed = 'notepad' # same in Windows!
170 170 return ed
171 171
172 172
173 173 def get_default_colors():
174 174 if sys.platform=='darwin':
175 175 return "LightBG"
176 176 elif os.name=='nt':
177 177 return 'Linux'
178 178 else:
179 179 return 'Linux'
180 180
181 181
182 182 class SeparateStr(Str):
183 183 """A Str subclass to validate separate_in, separate_out, etc.
184 184
185 185 This is a Str based traitlet that converts '0'->'' and '\\n'->'\n'.
186 186 """
187 187
188 188 def validate(self, obj, value):
189 189 if value == '0': value = ''
190 190 value = value.replace('\\n','\n')
191 191 return super(SeparateStr, self).validate(obj, value)
192 192
193 193
194 def make_user_namespaces(user_ns=None, user_global_ns=None):
195 """Return a valid local and global user interactive namespaces.
196
197 This builds a dict with the minimal information needed to operate as a
198 valid IPython user namespace, which you can pass to the various
199 embedding classes in ipython. The default implementation returns the
200 same dict for both the locals and the globals to allow functions to
201 refer to variables in the namespace. Customized implementations can
202 return different dicts. The locals dictionary can actually be anything
203 following the basic mapping protocol of a dict, but the globals dict
204 must be a true dict, not even a subclass. It is recommended that any
205 custom object for the locals namespace synchronize with the globals
206 dict somehow.
207
208 Raises TypeError if the provided globals namespace is not a true dict.
209
210 Parameters
211 ----------
212 user_ns : dict-like, optional
213 The current user namespace. The items in this namespace should
214 be included in the output. If None, an appropriate blank
215 namespace should be created.
216 user_global_ns : dict, optional
217 The current user global namespace. The items in this namespace
218 should be included in the output. If None, an appropriate
219 blank namespace should be created.
220
221 Returns
222 -------
223 A pair of dictionary-like object to be used as the local namespace
224 of the interpreter and a dict to be used as the global namespace.
225 """
226
227
228 # We must ensure that __builtin__ (without the final 's') is always
229 # available and pointing to the __builtin__ *module*. For more details:
230 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
231
232 if user_ns is None:
233 # Set __name__ to __main__ to better match the behavior of the
234 # normal interpreter.
235 user_ns = {'__name__' :'__main__',
236 '__builtin__' : __builtin__,
237 '__builtins__' : __builtin__,
238 }
239 else:
240 user_ns.setdefault('__name__','__main__')
241 user_ns.setdefault('__builtin__',__builtin__)
242 user_ns.setdefault('__builtins__',__builtin__)
243
244 if user_global_ns is None:
245 user_global_ns = user_ns
246 if type(user_global_ns) is not dict:
247 raise TypeError("user_global_ns must be a true dict; got %r"
248 % type(user_global_ns))
249
250 return user_ns, user_global_ns
251
252 194 #-----------------------------------------------------------------------------
253 195 # Main IPython class
254 196 #-----------------------------------------------------------------------------
255 197
256 198
257 199 class InteractiveShell(Component, Magic):
258 200 """An enhanced, interactive shell for Python."""
259 201
260 202 autocall = Enum((0,1,2), default_value=1, config=True)
261 203 autoedit_syntax = CBool(False, config=True)
262 204 autoindent = CBool(True, config=True)
263 205 automagic = CBool(True, config=True)
264 206 banner = Str('')
265 207 banner1 = Str(default_banner, config=True)
266 208 banner2 = Str('', config=True)
267 209 cache_size = Int(1000, config=True)
268 210 color_info = CBool(True, config=True)
269 211 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
270 212 default_value=get_default_colors(), config=True)
271 213 confirm_exit = CBool(True, config=True)
272 214 debug = CBool(False, config=True)
273 215 deep_reload = CBool(False, config=True)
274 216 # This display_banner only controls whether or not self.show_banner()
275 217 # is called when mainloop/interact are called. The default is False
276 218 # because for the terminal based application, the banner behavior
277 219 # is controlled by Global.display_banner, which IPythonApp looks at
278 220 # to determine if *it* should call show_banner() by hand or not.
279 221 display_banner = CBool(False) # This isn't configurable!
280 222 embedded = CBool(False)
281 223 embedded_active = CBool(False)
282 224 editor = Str(get_default_editor(), config=True)
283 225 filename = Str("<ipython console>")
284 226 ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__
285 227 logstart = CBool(False, config=True)
286 228 logfile = Str('', config=True)
287 229 logappend = Str('', config=True)
288 230 object_info_string_level = Enum((0,1,2), default_value=0,
289 231 config=True)
290 232 pager = Str('less', config=True)
291 233 pdb = CBool(False, config=True)
292 234 pprint = CBool(True, config=True)
293 235 profile = Str('', config=True)
294 236 prompt_in1 = Str('In [\\#]: ', config=True)
295 237 prompt_in2 = Str(' .\\D.: ', config=True)
296 238 prompt_out = Str('Out[\\#]: ', config=True)
297 239 prompts_pad_left = CBool(True, config=True)
298 240 quiet = CBool(False, config=True)
299 241
300 242 readline_use = CBool(True, config=True)
301 243 readline_merge_completions = CBool(True, config=True)
302 244 readline_omit__names = Enum((0,1,2), default_value=0, config=True)
303 245 readline_remove_delims = Str('-/~', config=True)
304 246 readline_parse_and_bind = List([
305 247 'tab: complete',
306 248 '"\C-l": possible-completions',
307 249 'set show-all-if-ambiguous on',
308 250 '"\C-o": tab-insert',
309 251 '"\M-i": " "',
310 252 '"\M-o": "\d\d\d\d"',
311 253 '"\M-I": "\d\d\d\d"',
312 254 '"\C-r": reverse-search-history',
313 255 '"\C-s": forward-search-history',
314 256 '"\C-p": history-search-backward',
315 257 '"\C-n": history-search-forward',
316 258 '"\e[A": history-search-backward',
317 259 '"\e[B": history-search-forward',
318 260 '"\C-k": kill-line',
319 261 '"\C-u": unix-line-discard',
320 262 ], allow_none=False, config=True)
321 263
322 264 screen_length = Int(0, config=True)
323 265
324 266 # Use custom TraitletTypes that convert '0'->'' and '\\n'->'\n'
325 267 separate_in = SeparateStr('\n', config=True)
326 268 separate_out = SeparateStr('', config=True)
327 269 separate_out2 = SeparateStr('', config=True)
328 270
329 271 system_header = Str('IPython system call: ', config=True)
330 272 system_verbose = CBool(False, config=True)
331 273 term_title = CBool(False, config=True)
332 274 wildcards_case_sensitive = CBool(True, config=True)
333 275 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
334 276 default_value='Context', config=True)
335 277
336 278 autoexec = List(allow_none=False)
337 279
338 280 # class attribute to indicate whether the class supports threads or not.
339 281 # Subclasses with thread support should override this as needed.
340 282 isthreaded = False
341 283
342 284 def __init__(self, parent=None, config=None, ipython_dir=None, usage=None,
343 285 user_ns=None, user_global_ns=None,
344 286 banner1=None, banner2=None, display_banner=None,
345 287 custom_exceptions=((),None)):
346 288
347 289 # This is where traitlets with a config_key argument are updated
348 290 # from the values on config.
349 291 super(InteractiveShell, self).__init__(parent, config=config)
350 292
351 293 # These are relatively independent and stateless
352 294 self.init_ipython_dir(ipython_dir)
353 295 self.init_instance_attrs()
354 296 self.init_term_title()
355 297 self.init_usage(usage)
356 298 self.init_banner(banner1, banner2, display_banner)
357 299
358 300 # Create namespaces (user_ns, user_global_ns, etc.)
359 301 self.init_create_namespaces(user_ns, user_global_ns)
360 302 # This has to be done after init_create_namespaces because it uses
361 303 # something in self.user_ns, but before init_sys_modules, which
362 304 # is the first thing to modify sys.
363 305 self.save_sys_module_state()
364 306 self.init_sys_modules()
365 307
366 308 self.init_history()
367 309 self.init_encoding()
368 310 self.init_prefilter()
369 311
370 312 Magic.__init__(self, self)
371 313
372 314 self.init_syntax_highlighting()
373 315 self.init_hooks()
374 316 self.init_pushd_popd_magic()
375 317 self.init_traceback_handlers(custom_exceptions)
376 318 self.init_user_ns()
377 319 self.init_logger()
378 320 self.init_alias()
379 321 self.init_builtins()
380 322
381 323 # pre_config_initialization
382 324 self.init_shadow_hist()
383 325
384 326 # The next section should contain averything that was in ipmaker.
385 327 self.init_logstart()
386 328
387 329 # The following was in post_config_initialization
388 330 self.init_inspector()
389 331 self.init_readline()
390 332 self.init_prompts()
391 333 self.init_displayhook()
392 334 self.init_reload_doctest()
393 335 self.init_magics()
394 336 self.init_pdb()
395 337 self.hooks.late_startup_hook()
396 338
397 339 def get_ipython(self):
398 340 """Return the currently running IPython instance."""
399 341 return self
400 342
401 343 #-------------------------------------------------------------------------
402 344 # Traitlet changed handlers
403 345 #-------------------------------------------------------------------------
404 346
405 347 def _banner1_changed(self):
406 348 self.compute_banner()
407 349
408 350 def _banner2_changed(self):
409 351 self.compute_banner()
410 352
411 353 def _ipython_dir_changed(self, name, new):
412 354 if not os.path.isdir(new):
413 355 os.makedirs(new, mode = 0777)
414 356 if not os.path.isdir(self.ipython_extension_dir):
415 357 os.makedirs(self.ipython_extension_dir, mode = 0777)
416 358
417 359 @property
418 360 def ipython_extension_dir(self):
419 361 return os.path.join(self.ipython_dir, 'extensions')
420 362
421 363 @property
422 364 def usable_screen_length(self):
423 365 if self.screen_length == 0:
424 366 return 0
425 367 else:
426 368 num_lines_bot = self.separate_in.count('\n')+1
427 369 return self.screen_length - num_lines_bot
428 370
429 371 def _term_title_changed(self, name, new_value):
430 372 self.init_term_title()
431 373
432 374 def set_autoindent(self,value=None):
433 375 """Set the autoindent flag, checking for readline support.
434 376
435 377 If called with no arguments, it acts as a toggle."""
436 378
437 379 if not self.has_readline:
438 380 if os.name == 'posix':
439 381 warn("The auto-indent feature requires the readline library")
440 382 self.autoindent = 0
441 383 return
442 384 if value is None:
443 385 self.autoindent = not self.autoindent
444 386 else:
445 387 self.autoindent = value
446 388
447 389 #-------------------------------------------------------------------------
448 390 # init_* methods called by __init__
449 391 #-------------------------------------------------------------------------
450 392
451 393 def init_ipython_dir(self, ipython_dir):
452 394 if ipython_dir is not None:
453 395 self.ipython_dir = ipython_dir
454 396 self.config.Global.ipython_dir = self.ipython_dir
455 397 return
456 398
457 399 if hasattr(self.config.Global, 'ipython_dir'):
458 400 self.ipython_dir = self.config.Global.ipython_dir
459 401 else:
460 402 self.ipython_dir = get_ipython_dir()
461 403
462 404 # All children can just read this
463 405 self.config.Global.ipython_dir = self.ipython_dir
464 406
465 407 def init_instance_attrs(self):
466 408 self.jobs = BackgroundJobManager()
467 409 self.more = False
468 410
469 411 # command compiler
470 412 self.compile = codeop.CommandCompiler()
471 413
472 414 # User input buffer
473 415 self.buffer = []
474 416
475 417 # Make an empty namespace, which extension writers can rely on both
476 418 # existing and NEVER being used by ipython itself. This gives them a
477 419 # convenient location for storing additional information and state
478 420 # their extensions may require, without fear of collisions with other
479 421 # ipython names that may develop later.
480 422 self.meta = Struct()
481 423
482 424 # Object variable to store code object waiting execution. This is
483 425 # used mainly by the multithreaded shells, but it can come in handy in
484 426 # other situations. No need to use a Queue here, since it's a single
485 427 # item which gets cleared once run.
486 428 self.code_to_run = None
487 429
488 430 # Flag to mark unconditional exit
489 431 self.exit_now = False
490 432
491 433 # Temporary files used for various purposes. Deleted at exit.
492 434 self.tempfiles = []
493 435
494 436 # Keep track of readline usage (later set by init_readline)
495 437 self.has_readline = False
496 438
497 439 # keep track of where we started running (mainly for crash post-mortem)
498 440 # This is not being used anywhere currently.
499 441 self.starting_dir = os.getcwd()
500 442
501 443 # Indentation management
502 444 self.indent_current_nsp = 0
503 445
504 446 def init_term_title(self):
505 447 # Enable or disable the terminal title.
506 448 if self.term_title:
507 449 toggle_set_term_title(True)
508 450 set_term_title('IPython: ' + abbrev_cwd())
509 451 else:
510 452 toggle_set_term_title(False)
511 453
512 454 def init_usage(self, usage=None):
513 455 if usage is None:
514 456 self.usage = interactive_usage
515 457 else:
516 458 self.usage = usage
517 459
518 460 def init_encoding(self):
519 461 # Get system encoding at startup time. Certain terminals (like Emacs
520 462 # under Win32 have it set to None, and we need to have a known valid
521 463 # encoding to use in the raw_input() method
522 464 try:
523 465 self.stdin_encoding = sys.stdin.encoding or 'ascii'
524 466 except AttributeError:
525 467 self.stdin_encoding = 'ascii'
526 468
527 469 def init_syntax_highlighting(self):
528 470 # Python source parser/formatter for syntax highlighting
529 471 pyformat = PyColorize.Parser().format
530 472 self.pycolorize = lambda src: pyformat(src,'str',self.colors)
531 473
532 474 def init_pushd_popd_magic(self):
533 475 # for pushd/popd management
534 476 try:
535 477 self.home_dir = get_home_dir()
536 478 except HomeDirError, msg:
537 479 fatal(msg)
538 480
539 481 self.dir_stack = []
540 482
541 483 def init_logger(self):
542 484 self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate')
543 485 # local shortcut, this is used a LOT
544 486 self.log = self.logger.log
545 487
546 488 def init_logstart(self):
547 489 if self.logappend:
548 490 self.magic_logstart(self.logappend + ' append')
549 491 elif self.logfile:
550 492 self.magic_logstart(self.logfile)
551 493 elif self.logstart:
552 494 self.magic_logstart()
553 495
554 496 def init_builtins(self):
555 497 self.builtin_trap = BuiltinTrap(self)
556 498
557 499 def init_inspector(self):
558 500 # Object inspector
559 501 self.inspector = oinspect.Inspector(oinspect.InspectColors,
560 502 PyColorize.ANSICodeColors,
561 503 'NoColor',
562 504 self.object_info_string_level)
563 505
564 506 def init_prompts(self):
565 507 # Initialize cache, set in/out prompts and printing system
566 508 self.outputcache = CachedOutput(self,
567 509 self.cache_size,
568 510 self.pprint,
569 511 input_sep = self.separate_in,
570 512 output_sep = self.separate_out,
571 513 output_sep2 = self.separate_out2,
572 514 ps1 = self.prompt_in1,
573 515 ps2 = self.prompt_in2,
574 516 ps_out = self.prompt_out,
575 517 pad_left = self.prompts_pad_left)
576 518
577 519 # user may have over-ridden the default print hook:
578 520 try:
579 521 self.outputcache.__class__.display = self.hooks.display
580 522 except AttributeError:
581 523 pass
582 524
583 525 def init_displayhook(self):
584 526 self.display_trap = DisplayTrap(self, self.outputcache)
585 527
586 528 def init_reload_doctest(self):
587 529 # Do a proper resetting of doctest, including the necessary displayhook
588 530 # monkeypatching
589 531 try:
590 532 doctest_reload()
591 533 except ImportError:
592 534 warn("doctest module does not exist.")
593 535
594 536 #-------------------------------------------------------------------------
595 537 # Things related to the banner
596 538 #-------------------------------------------------------------------------
597 539
598 540 def init_banner(self, banner1, banner2, display_banner):
599 541 if banner1 is not None:
600 542 self.banner1 = banner1
601 543 if banner2 is not None:
602 544 self.banner2 = banner2
603 545 if display_banner is not None:
604 546 self.display_banner = display_banner
605 547 self.compute_banner()
606 548
607 549 def show_banner(self, banner=None):
608 550 if banner is None:
609 551 banner = self.banner
610 552 self.write(banner)
611 553
612 554 def compute_banner(self):
613 555 self.banner = self.banner1 + '\n'
614 556 if self.profile:
615 557 self.banner += '\nIPython profile: %s\n' % self.profile
616 558 if self.banner2:
617 559 self.banner += '\n' + self.banner2 + '\n'
618 560
619 561 #-------------------------------------------------------------------------
620 562 # Things related to injections into the sys module
621 563 #-------------------------------------------------------------------------
622 564
623 565 def save_sys_module_state(self):
624 566 """Save the state of hooks in the sys module.
625 567
626 568 This has to be called after self.user_ns is created.
627 569 """
628 570 self._orig_sys_module_state = {}
629 571 self._orig_sys_module_state['stdin'] = sys.stdin
630 572 self._orig_sys_module_state['stdout'] = sys.stdout
631 573 self._orig_sys_module_state['stderr'] = sys.stderr
632 574 self._orig_sys_module_state['excepthook'] = sys.excepthook
633 575 try:
634 576 self._orig_sys_modules_main_name = self.user_ns['__name__']
635 577 except KeyError:
636 578 pass
637 579
638 580 def restore_sys_module_state(self):
639 581 """Restore the state of the sys module."""
640 582 try:
641 583 for k, v in self._orig_sys_module_state.items():
642 584 setattr(sys, k, v)
643 585 except AttributeError:
644 586 pass
645 587 try:
646 588 delattr(sys, 'ipcompleter')
647 589 except AttributeError:
648 590 pass
649 591 # Reset what what done in self.init_sys_modules
650 592 try:
651 593 sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name
652 594 except (AttributeError, KeyError):
653 595 pass
654 596
655 597 #-------------------------------------------------------------------------
656 598 # Things related to hooks
657 599 #-------------------------------------------------------------------------
658 600
659 601 def init_hooks(self):
660 602 # hooks holds pointers used for user-side customizations
661 603 self.hooks = Struct()
662 604
663 605 self.strdispatchers = {}
664 606
665 607 # Set all default hooks, defined in the IPython.hooks module.
666 608 hooks = IPython.core.hooks
667 609 for hook_name in hooks.__all__:
668 610 # default hooks have priority 100, i.e. low; user hooks should have
669 611 # 0-100 priority
670 612 self.set_hook(hook_name,getattr(hooks,hook_name), 100)
671 613
672 614 def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None):
673 615 """set_hook(name,hook) -> sets an internal IPython hook.
674 616
675 617 IPython exposes some of its internal API as user-modifiable hooks. By
676 618 adding your function to one of these hooks, you can modify IPython's
677 619 behavior to call at runtime your own routines."""
678 620
679 621 # At some point in the future, this should validate the hook before it
680 622 # accepts it. Probably at least check that the hook takes the number
681 623 # of args it's supposed to.
682 624
683 625 f = new.instancemethod(hook,self,self.__class__)
684 626
685 627 # check if the hook is for strdispatcher first
686 628 if str_key is not None:
687 629 sdp = self.strdispatchers.get(name, StrDispatch())
688 630 sdp.add_s(str_key, f, priority )
689 631 self.strdispatchers[name] = sdp
690 632 return
691 633 if re_key is not None:
692 634 sdp = self.strdispatchers.get(name, StrDispatch())
693 635 sdp.add_re(re.compile(re_key), f, priority )
694 636 self.strdispatchers[name] = sdp
695 637 return
696 638
697 639 dp = getattr(self.hooks, name, None)
698 640 if name not in IPython.core.hooks.__all__:
699 641 print "Warning! Hook '%s' is not one of %s" % (name, IPython.core.hooks.__all__ )
700 642 if not dp:
701 643 dp = IPython.core.hooks.CommandChainDispatcher()
702 644
703 645 try:
704 646 dp.add(f,priority)
705 647 except AttributeError:
706 648 # it was not commandchain, plain old func - replace
707 649 dp = f
708 650
709 651 setattr(self.hooks,name, dp)
710 652
711 653 #-------------------------------------------------------------------------
712 654 # Things related to the "main" module
713 655 #-------------------------------------------------------------------------
714 656
715 657 def new_main_mod(self,ns=None):
716 658 """Return a new 'main' module object for user code execution.
717 659 """
718 660 main_mod = self._user_main_module
719 661 init_fakemod_dict(main_mod,ns)
720 662 return main_mod
721 663
722 664 def cache_main_mod(self,ns,fname):
723 665 """Cache a main module's namespace.
724 666
725 667 When scripts are executed via %run, we must keep a reference to the
726 668 namespace of their __main__ module (a FakeModule instance) around so
727 669 that Python doesn't clear it, rendering objects defined therein
728 670 useless.
729 671
730 672 This method keeps said reference in a private dict, keyed by the
731 673 absolute path of the module object (which corresponds to the script
732 674 path). This way, for multiple executions of the same script we only
733 675 keep one copy of the namespace (the last one), thus preventing memory
734 676 leaks from old references while allowing the objects from the last
735 677 execution to be accessible.
736 678
737 679 Note: we can not allow the actual FakeModule instances to be deleted,
738 680 because of how Python tears down modules (it hard-sets all their
739 681 references to None without regard for reference counts). This method
740 682 must therefore make a *copy* of the given namespace, to allow the
741 683 original module's __dict__ to be cleared and reused.
742 684
743 685
744 686 Parameters
745 687 ----------
746 688 ns : a namespace (a dict, typically)
747 689
748 690 fname : str
749 691 Filename associated with the namespace.
750 692
751 693 Examples
752 694 --------
753 695
754 696 In [10]: import IPython
755 697
756 698 In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
757 699
758 700 In [12]: IPython.__file__ in _ip._main_ns_cache
759 701 Out[12]: True
760 702 """
761 703 self._main_ns_cache[os.path.abspath(fname)] = ns.copy()
762 704
763 705 def clear_main_mod_cache(self):
764 706 """Clear the cache of main modules.
765 707
766 708 Mainly for use by utilities like %reset.
767 709
768 710 Examples
769 711 --------
770 712
771 713 In [15]: import IPython
772 714
773 715 In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__)
774 716
775 717 In [17]: len(_ip._main_ns_cache) > 0
776 718 Out[17]: True
777 719
778 720 In [18]: _ip.clear_main_mod_cache()
779 721
780 722 In [19]: len(_ip._main_ns_cache) == 0
781 723 Out[19]: True
782 724 """
783 725 self._main_ns_cache.clear()
784 726
785 727 #-------------------------------------------------------------------------
786 728 # Things related to debugging
787 729 #-------------------------------------------------------------------------
788 730
789 731 def init_pdb(self):
790 732 # Set calling of pdb on exceptions
791 733 # self.call_pdb is a property
792 734 self.call_pdb = self.pdb
793 735
794 736 def _get_call_pdb(self):
795 737 return self._call_pdb
796 738
797 739 def _set_call_pdb(self,val):
798 740
799 741 if val not in (0,1,False,True):
800 742 raise ValueError,'new call_pdb value must be boolean'
801 743
802 744 # store value in instance
803 745 self._call_pdb = val
804 746
805 747 # notify the actual exception handlers
806 748 self.InteractiveTB.call_pdb = val
807 749 if self.isthreaded:
808 750 try:
809 751 self.sys_excepthook.call_pdb = val
810 752 except:
811 753 warn('Failed to activate pdb for threaded exception handler')
812 754
813 755 call_pdb = property(_get_call_pdb,_set_call_pdb,None,
814 756 'Control auto-activation of pdb at exceptions')
815 757
816 758 def debugger(self,force=False):
817 759 """Call the pydb/pdb debugger.
818 760
819 761 Keywords:
820 762
821 763 - force(False): by default, this routine checks the instance call_pdb
822 764 flag and does not actually invoke the debugger if the flag is false.
823 765 The 'force' option forces the debugger to activate even if the flag
824 766 is false.
825 767 """
826 768
827 769 if not (force or self.call_pdb):
828 770 return
829 771
830 772 if not hasattr(sys,'last_traceback'):
831 773 error('No traceback has been produced, nothing to debug.')
832 774 return
833 775
834 776 # use pydb if available
835 777 if debugger.has_pydb:
836 778 from pydb import pm
837 779 else:
838 780 # fallback to our internal debugger
839 781 pm = lambda : self.InteractiveTB.debugger(force=True)
840 782 self.history_saving_wrapper(pm)()
841 783
842 784 #-------------------------------------------------------------------------
843 785 # Things related to IPython's various namespaces
844 786 #-------------------------------------------------------------------------
845 787
846 788 def init_create_namespaces(self, user_ns=None, user_global_ns=None):
847 789 # Create the namespace where the user will operate. user_ns is
848 790 # normally the only one used, and it is passed to the exec calls as
849 791 # the locals argument. But we do carry a user_global_ns namespace
850 792 # given as the exec 'globals' argument, This is useful in embedding
851 793 # situations where the ipython shell opens in a context where the
852 794 # distinction between locals and globals is meaningful. For
853 795 # non-embedded contexts, it is just the same object as the user_ns dict.
854 796
855 797 # FIXME. For some strange reason, __builtins__ is showing up at user
856 798 # level as a dict instead of a module. This is a manual fix, but I
857 799 # should really track down where the problem is coming from. Alex
858 800 # Schmolck reported this problem first.
859 801
860 802 # A useful post by Alex Martelli on this topic:
861 803 # Re: inconsistent value from __builtins__
862 804 # Von: Alex Martelli <aleaxit@yahoo.com>
863 805 # Datum: Freitag 01 Oktober 2004 04:45:34 nachmittags/abends
864 806 # Gruppen: comp.lang.python
865 807
866 808 # Michael Hohn <hohn@hooknose.lbl.gov> wrote:
867 809 # > >>> print type(builtin_check.get_global_binding('__builtins__'))
868 810 # > <type 'dict'>
869 811 # > >>> print type(__builtins__)
870 812 # > <type 'module'>
871 813 # > Is this difference in return value intentional?
872 814
873 815 # Well, it's documented that '__builtins__' can be either a dictionary
874 816 # or a module, and it's been that way for a long time. Whether it's
875 817 # intentional (or sensible), I don't know. In any case, the idea is
876 818 # that if you need to access the built-in namespace directly, you
877 819 # should start with "import __builtin__" (note, no 's') which will
878 820 # definitely give you a module. Yeah, it's somewhat confusing:-(.
879 821
880 822 # These routines return properly built dicts as needed by the rest of
881 823 # the code, and can also be used by extension writers to generate
882 824 # properly initialized namespaces.
883 user_ns, user_global_ns = make_user_namespaces(user_ns, user_global_ns)
825 user_ns, user_global_ns = self.make_user_namespaces(user_ns, user_global_ns)
884 826
885 827 # Assign namespaces
886 828 # This is the namespace where all normal user variables live
887 829 self.user_ns = user_ns
888 830 self.user_global_ns = user_global_ns
889 831
890 832 # An auxiliary namespace that checks what parts of the user_ns were
891 833 # loaded at startup, so we can list later only variables defined in
892 834 # actual interactive use. Since it is always a subset of user_ns, it
893 835 # doesn't need to be separately tracked in the ns_table.
894 836 self.user_config_ns = {}
895 837
896 838 # A namespace to keep track of internal data structures to prevent
897 839 # them from cluttering user-visible stuff. Will be updated later
898 840 self.internal_ns = {}
899 841
900 842 # Now that FakeModule produces a real module, we've run into a nasty
901 843 # problem: after script execution (via %run), the module where the user
902 844 # code ran is deleted. Now that this object is a true module (needed
903 845 # so docetst and other tools work correctly), the Python module
904 846 # teardown mechanism runs over it, and sets to None every variable
905 847 # present in that module. Top-level references to objects from the
906 848 # script survive, because the user_ns is updated with them. However,
907 849 # calling functions defined in the script that use other things from
908 850 # the script will fail, because the function's closure had references
909 851 # to the original objects, which are now all None. So we must protect
910 852 # these modules from deletion by keeping a cache.
911 853 #
912 854 # To avoid keeping stale modules around (we only need the one from the
913 855 # last run), we use a dict keyed with the full path to the script, so
914 856 # only the last version of the module is held in the cache. Note,
915 857 # however, that we must cache the module *namespace contents* (their
916 858 # __dict__). Because if we try to cache the actual modules, old ones
917 859 # (uncached) could be destroyed while still holding references (such as
918 860 # those held by GUI objects that tend to be long-lived)>
919 861 #
920 862 # The %reset command will flush this cache. See the cache_main_mod()
921 863 # and clear_main_mod_cache() methods for details on use.
922 864
923 865 # This is the cache used for 'main' namespaces
924 866 self._main_ns_cache = {}
925 867 # And this is the single instance of FakeModule whose __dict__ we keep
926 868 # copying and clearing for reuse on each %run
927 869 self._user_main_module = FakeModule()
928 870
929 871 # A table holding all the namespaces IPython deals with, so that
930 872 # introspection facilities can search easily.
931 873 self.ns_table = {'user':user_ns,
932 874 'user_global':user_global_ns,
933 875 'internal':self.internal_ns,
934 876 'builtin':__builtin__.__dict__
935 877 }
936 878
937 879 # Similarly, track all namespaces where references can be held and that
938 880 # we can safely clear (so it can NOT include builtin). This one can be
939 881 # a simple list.
940 882 self.ns_refs_table = [ user_ns, user_global_ns, self.user_config_ns,
941 883 self.internal_ns, self._main_ns_cache ]
942 884
885 def make_user_namespaces(self, user_ns=None, user_global_ns=None):
886 """Return a valid local and global user interactive namespaces.
887
888 This builds a dict with the minimal information needed to operate as a
889 valid IPython user namespace, which you can pass to the various
890 embedding classes in ipython. The default implementation returns the
891 same dict for both the locals and the globals to allow functions to
892 refer to variables in the namespace. Customized implementations can
893 return different dicts. The locals dictionary can actually be anything
894 following the basic mapping protocol of a dict, but the globals dict
895 must be a true dict, not even a subclass. It is recommended that any
896 custom object for the locals namespace synchronize with the globals
897 dict somehow.
898
899 Raises TypeError if the provided globals namespace is not a true dict.
900
901 Parameters
902 ----------
903 user_ns : dict-like, optional
904 The current user namespace. The items in this namespace should
905 be included in the output. If None, an appropriate blank
906 namespace should be created.
907 user_global_ns : dict, optional
908 The current user global namespace. The items in this namespace
909 should be included in the output. If None, an appropriate
910 blank namespace should be created.
911
912 Returns
913 -------
914 A pair of dictionary-like object to be used as the local namespace
915 of the interpreter and a dict to be used as the global namespace.
916 """
917
918
919 # We must ensure that __builtin__ (without the final 's') is always
920 # available and pointing to the __builtin__ *module*. For more details:
921 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
922
923 if user_ns is None:
924 # Set __name__ to __main__ to better match the behavior of the
925 # normal interpreter.
926 user_ns = {'__name__' :'__main__',
927 '__builtin__' : __builtin__,
928 '__builtins__' : __builtin__,
929 }
930 else:
931 user_ns.setdefault('__name__','__main__')
932 user_ns.setdefault('__builtin__',__builtin__)
933 user_ns.setdefault('__builtins__',__builtin__)
934
935 if user_global_ns is None:
936 user_global_ns = user_ns
937 if type(user_global_ns) is not dict:
938 raise TypeError("user_global_ns must be a true dict; got %r"
939 % type(user_global_ns))
940
941 return user_ns, user_global_ns
942
943 943 def init_sys_modules(self):
944 944 # We need to insert into sys.modules something that looks like a
945 945 # module but which accesses the IPython namespace, for shelve and
946 946 # pickle to work interactively. Normally they rely on getting
947 947 # everything out of __main__, but for embedding purposes each IPython
948 948 # instance has its own private namespace, so we can't go shoving
949 949 # everything into __main__.
950 950
951 951 # note, however, that we should only do this for non-embedded
952 952 # ipythons, which really mimic the __main__.__dict__ with their own
953 953 # namespace. Embedded instances, on the other hand, should not do
954 954 # this because they need to manage the user local/global namespaces
955 955 # only, but they live within a 'normal' __main__ (meaning, they
956 956 # shouldn't overtake the execution environment of the script they're
957 957 # embedded in).
958 958
959 959 # This is overridden in the InteractiveShellEmbed subclass to a no-op.
960 960
961 961 try:
962 962 main_name = self.user_ns['__name__']
963 963 except KeyError:
964 964 raise KeyError('user_ns dictionary MUST have a "__name__" key')
965 965 else:
966 966 sys.modules[main_name] = FakeModule(self.user_ns)
967 967
968 968 def init_user_ns(self):
969 969 """Initialize all user-visible namespaces to their minimum defaults.
970 970
971 971 Certain history lists are also initialized here, as they effectively
972 972 act as user namespaces.
973 973
974 974 Notes
975 975 -----
976 976 All data structures here are only filled in, they are NOT reset by this
977 977 method. If they were not empty before, data will simply be added to
978 978 therm.
979 979 """
980 980 # This function works in two parts: first we put a few things in
981 981 # user_ns, and we sync that contents into user_config_ns so that these
982 982 # initial variables aren't shown by %who. After the sync, we add the
983 983 # rest of what we *do* want the user to see with %who even on a new
984 984 # session (probably nothing, so theye really only see their own stuff)
985 985
986 986 # The user dict must *always* have a __builtin__ reference to the
987 987 # Python standard __builtin__ namespace, which must be imported.
988 988 # This is so that certain operations in prompt evaluation can be
989 989 # reliably executed with builtins. Note that we can NOT use
990 990 # __builtins__ (note the 's'), because that can either be a dict or a
991 991 # module, and can even mutate at runtime, depending on the context
992 992 # (Python makes no guarantees on it). In contrast, __builtin__ is
993 993 # always a module object, though it must be explicitly imported.
994 994
995 995 # For more details:
996 996 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
997 997 ns = dict(__builtin__ = __builtin__)
998 998
999 999 # Put 'help' in the user namespace
1000 1000 try:
1001 1001 from site import _Helper
1002 1002 ns['help'] = _Helper()
1003 1003 except ImportError:
1004 1004 warn('help() not available - check site.py')
1005 1005
1006 1006 # make global variables for user access to the histories
1007 1007 ns['_ih'] = self.input_hist
1008 1008 ns['_oh'] = self.output_hist
1009 1009 ns['_dh'] = self.dir_hist
1010 1010
1011 1011 ns['_sh'] = shadowns
1012 1012
1013 1013 # user aliases to input and output histories. These shouldn't show up
1014 1014 # in %who, as they can have very large reprs.
1015 1015 ns['In'] = self.input_hist
1016 1016 ns['Out'] = self.output_hist
1017 1017
1018 1018 # Store myself as the public api!!!
1019 1019 ns['get_ipython'] = self.get_ipython
1020 1020
1021 1021 # Sync what we've added so far to user_config_ns so these aren't seen
1022 1022 # by %who
1023 1023 self.user_config_ns.update(ns)
1024 1024
1025 1025 # Anything put into ns now would show up in %who. Think twice before
1026 1026 # putting anything here, as we really want %who to show the user their
1027 1027 # stuff, not our variables.
1028 1028
1029 1029 # Finally, update the real user's namespace
1030 1030 self.user_ns.update(ns)
1031 1031
1032 1032
1033 1033 def reset(self):
1034 1034 """Clear all internal namespaces.
1035 1035
1036 1036 Note that this is much more aggressive than %reset, since it clears
1037 1037 fully all namespaces, as well as all input/output lists.
1038 1038 """
1039 1039 for ns in self.ns_refs_table:
1040 1040 ns.clear()
1041 1041
1042 1042 self.alias_manager.clear_aliases()
1043 1043
1044 1044 # Clear input and output histories
1045 1045 self.input_hist[:] = []
1046 1046 self.input_hist_raw[:] = []
1047 1047 self.output_hist.clear()
1048 1048
1049 1049 # Restore the user namespaces to minimal usability
1050 1050 self.init_user_ns()
1051 1051
1052 1052 # Restore the default and user aliases
1053 1053 self.alias_manager.init_aliases()
1054 1054
1055 1055 def push(self, variables, interactive=True):
1056 1056 """Inject a group of variables into the IPython user namespace.
1057 1057
1058 1058 Parameters
1059 1059 ----------
1060 1060 variables : dict, str or list/tuple of str
1061 1061 The variables to inject into the user's namespace. If a dict,
1062 1062 a simple update is done. If a str, the string is assumed to
1063 1063 have variable names separated by spaces. A list/tuple of str
1064 1064 can also be used to give the variable names. If just the variable
1065 1065 names are give (list/tuple/str) then the variable values looked
1066 1066 up in the callers frame.
1067 1067 interactive : bool
1068 1068 If True (default), the variables will be listed with the ``who``
1069 1069 magic.
1070 1070 """
1071 1071 vdict = None
1072 1072
1073 1073 # We need a dict of name/value pairs to do namespace updates.
1074 1074 if isinstance(variables, dict):
1075 1075 vdict = variables
1076 1076 elif isinstance(variables, (basestring, list, tuple)):
1077 1077 if isinstance(variables, basestring):
1078 1078 vlist = variables.split()
1079 1079 else:
1080 1080 vlist = variables
1081 1081 vdict = {}
1082 1082 cf = sys._getframe(1)
1083 1083 for name in vlist:
1084 1084 try:
1085 1085 vdict[name] = eval(name, cf.f_globals, cf.f_locals)
1086 1086 except:
1087 1087 print ('Could not get variable %s from %s' %
1088 1088 (name,cf.f_code.co_name))
1089 1089 else:
1090 1090 raise ValueError('variables must be a dict/str/list/tuple')
1091 1091
1092 1092 # Propagate variables to user namespace
1093 1093 self.user_ns.update(vdict)
1094 1094
1095 1095 # And configure interactive visibility
1096 1096 config_ns = self.user_config_ns
1097 1097 if interactive:
1098 1098 for name, val in vdict.iteritems():
1099 1099 config_ns.pop(name, None)
1100 1100 else:
1101 1101 for name,val in vdict.iteritems():
1102 1102 config_ns[name] = val
1103 1103
1104 1104 #-------------------------------------------------------------------------
1105 1105 # Things related to history management
1106 1106 #-------------------------------------------------------------------------
1107 1107
1108 1108 def init_history(self):
1109 1109 # List of input with multi-line handling.
1110 1110 self.input_hist = InputList()
1111 1111 # This one will hold the 'raw' input history, without any
1112 1112 # pre-processing. This will allow users to retrieve the input just as
1113 1113 # it was exactly typed in by the user, with %hist -r.
1114 1114 self.input_hist_raw = InputList()
1115 1115
1116 1116 # list of visited directories
1117 1117 try:
1118 1118 self.dir_hist = [os.getcwd()]
1119 1119 except OSError:
1120 1120 self.dir_hist = []
1121 1121
1122 1122 # dict of output history
1123 1123 self.output_hist = {}
1124 1124
1125 1125 # Now the history file
1126 1126 if self.profile:
1127 1127 histfname = 'history-%s' % self.profile
1128 1128 else:
1129 1129 histfname = 'history'
1130 1130 self.histfile = os.path.join(self.ipython_dir, histfname)
1131 1131
1132 1132 # Fill the history zero entry, user counter starts at 1
1133 1133 self.input_hist.append('\n')
1134 1134 self.input_hist_raw.append('\n')
1135 1135
1136 1136 def init_shadow_hist(self):
1137 1137 try:
1138 1138 self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db")
1139 1139 except exceptions.UnicodeDecodeError:
1140 1140 print "Your ipython_dir can't be decoded to unicode!"
1141 1141 print "Please set HOME environment variable to something that"
1142 1142 print r"only has ASCII characters, e.g. c:\home"
1143 1143 print "Now it is", self.ipython_dir
1144 1144 sys.exit()
1145 1145 self.shadowhist = ipcorehist.ShadowHist(self.db)
1146 1146
1147 1147 def savehist(self):
1148 1148 """Save input history to a file (via readline library)."""
1149 1149
1150 1150 try:
1151 1151 self.readline.write_history_file(self.histfile)
1152 1152 except:
1153 1153 print 'Unable to save IPython command history to file: ' + \
1154 1154 `self.histfile`
1155 1155
1156 1156 def reloadhist(self):
1157 1157 """Reload the input history from disk file."""
1158 1158
1159 1159 try:
1160 1160 self.readline.clear_history()
1161 1161 self.readline.read_history_file(self.shell.histfile)
1162 1162 except AttributeError:
1163 1163 pass
1164 1164
1165 1165 def history_saving_wrapper(self, func):
1166 1166 """ Wrap func for readline history saving
1167 1167
1168 1168 Convert func into callable that saves & restores
1169 1169 history around the call """
1170 1170
1171 1171 if self.has_readline:
1172 1172 from IPython.utils import rlineimpl as readline
1173 1173 else:
1174 1174 return func
1175 1175
1176 1176 def wrapper():
1177 1177 self.savehist()
1178 1178 try:
1179 1179 func()
1180 1180 finally:
1181 1181 readline.read_history_file(self.histfile)
1182 1182 return wrapper
1183 1183
1184 1184 #-------------------------------------------------------------------------
1185 1185 # Things related to exception handling and tracebacks (not debugging)
1186 1186 #-------------------------------------------------------------------------
1187 1187
1188 1188 def init_traceback_handlers(self, custom_exceptions):
1189 1189 # Syntax error handler.
1190 1190 self.SyntaxTB = SyntaxTB(color_scheme='NoColor')
1191 1191
1192 1192 # The interactive one is initialized with an offset, meaning we always
1193 1193 # want to remove the topmost item in the traceback, which is our own
1194 1194 # internal code. Valid modes: ['Plain','Context','Verbose']
1195 1195 self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain',
1196 1196 color_scheme='NoColor',
1197 1197 tb_offset = 1)
1198 1198
1199 1199 # The instance will store a pointer to the system-wide exception hook,
1200 1200 # so that runtime code (such as magics) can access it. This is because
1201 1201 # during the read-eval loop, it may get temporarily overwritten.
1202 1202 self.sys_excepthook = sys.excepthook
1203 1203
1204 1204 # and add any custom exception handlers the user may have specified
1205 1205 self.set_custom_exc(*custom_exceptions)
1206 1206
1207 1207 # Set the exception mode
1208 1208 self.InteractiveTB.set_mode(mode=self.xmode)
1209 1209
1210 1210 def set_custom_exc(self,exc_tuple,handler):
1211 1211 """set_custom_exc(exc_tuple,handler)
1212 1212
1213 1213 Set a custom exception handler, which will be called if any of the
1214 1214 exceptions in exc_tuple occur in the mainloop (specifically, in the
1215 1215 runcode() method.
1216 1216
1217 1217 Inputs:
1218 1218
1219 1219 - exc_tuple: a *tuple* of valid exceptions to call the defined
1220 1220 handler for. It is very important that you use a tuple, and NOT A
1221 1221 LIST here, because of the way Python's except statement works. If
1222 1222 you only want to trap a single exception, use a singleton tuple:
1223 1223
1224 1224 exc_tuple == (MyCustomException,)
1225 1225
1226 1226 - handler: this must be defined as a function with the following
1227 1227 basic interface: def my_handler(self,etype,value,tb).
1228 1228
1229 1229 This will be made into an instance method (via new.instancemethod)
1230 1230 of IPython itself, and it will be called if any of the exceptions
1231 1231 listed in the exc_tuple are caught. If the handler is None, an
1232 1232 internal basic one is used, which just prints basic info.
1233 1233
1234 1234 WARNING: by putting in your own exception handler into IPython's main
1235 1235 execution loop, you run a very good chance of nasty crashes. This
1236 1236 facility should only be used if you really know what you are doing."""
1237 1237
1238 1238 assert type(exc_tuple)==type(()) , \
1239 1239 "The custom exceptions must be given AS A TUPLE."
1240 1240
1241 1241 def dummy_handler(self,etype,value,tb):
1242 1242 print '*** Simple custom exception handler ***'
1243 1243 print 'Exception type :',etype
1244 1244 print 'Exception value:',value
1245 1245 print 'Traceback :',tb
1246 1246 print 'Source code :','\n'.join(self.buffer)
1247 1247
1248 1248 if handler is None: handler = dummy_handler
1249 1249
1250 1250 self.CustomTB = new.instancemethod(handler,self,self.__class__)
1251 1251 self.custom_exceptions = exc_tuple
1252 1252
1253 1253 def excepthook(self, etype, value, tb):
1254 1254 """One more defense for GUI apps that call sys.excepthook.
1255 1255
1256 1256 GUI frameworks like wxPython trap exceptions and call
1257 1257 sys.excepthook themselves. I guess this is a feature that
1258 1258 enables them to keep running after exceptions that would
1259 1259 otherwise kill their mainloop. This is a bother for IPython
1260 1260 which excepts to catch all of the program exceptions with a try:
1261 1261 except: statement.
1262 1262
1263 1263 Normally, IPython sets sys.excepthook to a CrashHandler instance, so if
1264 1264 any app directly invokes sys.excepthook, it will look to the user like
1265 1265 IPython crashed. In order to work around this, we can disable the
1266 1266 CrashHandler and replace it with this excepthook instead, which prints a
1267 1267 regular traceback using our InteractiveTB. In this fashion, apps which
1268 1268 call sys.excepthook will generate a regular-looking exception from
1269 1269 IPython, and the CrashHandler will only be triggered by real IPython
1270 1270 crashes.
1271 1271
1272 1272 This hook should be used sparingly, only in places which are not likely
1273 1273 to be true IPython errors.
1274 1274 """
1275 1275 self.showtraceback((etype,value,tb),tb_offset=0)
1276 1276
1277 1277 def showtraceback(self,exc_tuple = None,filename=None,tb_offset=None,
1278 1278 exception_only=False):
1279 1279 """Display the exception that just occurred.
1280 1280
1281 1281 If nothing is known about the exception, this is the method which
1282 1282 should be used throughout the code for presenting user tracebacks,
1283 1283 rather than directly invoking the InteractiveTB object.
1284 1284
1285 1285 A specific showsyntaxerror() also exists, but this method can take
1286 1286 care of calling it if needed, so unless you are explicitly catching a
1287 1287 SyntaxError exception, don't try to analyze the stack manually and
1288 1288 simply call this method."""
1289 1289
1290 1290 try:
1291 1291 if exc_tuple is None:
1292 1292 etype, value, tb = sys.exc_info()
1293 1293 else:
1294 1294 etype, value, tb = exc_tuple
1295 1295
1296 1296 if etype is None:
1297 1297 if hasattr(sys, 'last_type'):
1298 1298 etype, value, tb = sys.last_type, sys.last_value, \
1299 1299 sys.last_traceback
1300 1300 else:
1301 1301 self.write('No traceback available to show.\n')
1302 1302 return
1303 1303
1304 1304 if etype is SyntaxError:
1305 1305 # Though this won't be called by syntax errors in the input
1306 1306 # line, there may be SyntaxError cases whith imported code.
1307 1307 self.showsyntaxerror(filename)
1308 1308 elif etype is UsageError:
1309 1309 print "UsageError:", value
1310 1310 else:
1311 1311 # WARNING: these variables are somewhat deprecated and not
1312 1312 # necessarily safe to use in a threaded environment, but tools
1313 1313 # like pdb depend on their existence, so let's set them. If we
1314 1314 # find problems in the field, we'll need to revisit their use.
1315 1315 sys.last_type = etype
1316 1316 sys.last_value = value
1317 1317 sys.last_traceback = tb
1318 1318
1319 1319 if etype in self.custom_exceptions:
1320 1320 self.CustomTB(etype,value,tb)
1321 1321 else:
1322 1322 if exception_only:
1323 1323 m = ('An exception has occurred, use %tb to see the '
1324 1324 'full traceback.')
1325 1325 print m
1326 1326 self.InteractiveTB.show_exception_only(etype, value)
1327 1327 else:
1328 1328 self.InteractiveTB(etype,value,tb,tb_offset=tb_offset)
1329 1329 if self.InteractiveTB.call_pdb:
1330 1330 # pdb mucks up readline, fix it back
1331 1331 self.set_completer()
1332 1332
1333 1333 except KeyboardInterrupt:
1334 1334 self.write("\nKeyboardInterrupt\n")
1335 1335
1336 1336
1337 1337 def showsyntaxerror(self, filename=None):
1338 1338 """Display the syntax error that just occurred.
1339 1339
1340 1340 This doesn't display a stack trace because there isn't one.
1341 1341
1342 1342 If a filename is given, it is stuffed in the exception instead
1343 1343 of what was there before (because Python's parser always uses
1344 1344 "<string>" when reading from a string).
1345 1345 """
1346 1346 etype, value, last_traceback = sys.exc_info()
1347 1347
1348 1348 # See note about these variables in showtraceback() above
1349 1349 sys.last_type = etype
1350 1350 sys.last_value = value
1351 1351 sys.last_traceback = last_traceback
1352 1352
1353 1353 if filename and etype is SyntaxError:
1354 1354 # Work hard to stuff the correct filename in the exception
1355 1355 try:
1356 1356 msg, (dummy_filename, lineno, offset, line) = value
1357 1357 except:
1358 1358 # Not the format we expect; leave it alone
1359 1359 pass
1360 1360 else:
1361 1361 # Stuff in the right filename
1362 1362 try:
1363 1363 # Assume SyntaxError is a class exception
1364 1364 value = SyntaxError(msg, (filename, lineno, offset, line))
1365 1365 except:
1366 1366 # If that failed, assume SyntaxError is a string
1367 1367 value = msg, (filename, lineno, offset, line)
1368 1368 self.SyntaxTB(etype,value,[])
1369 1369
1370 1370 def edit_syntax_error(self):
1371 1371 """The bottom half of the syntax error handler called in the main loop.
1372 1372
1373 1373 Loop until syntax error is fixed or user cancels.
1374 1374 """
1375 1375
1376 1376 while self.SyntaxTB.last_syntax_error:
1377 1377 # copy and clear last_syntax_error
1378 1378 err = self.SyntaxTB.clear_err_state()
1379 1379 if not self._should_recompile(err):
1380 1380 return
1381 1381 try:
1382 1382 # may set last_syntax_error again if a SyntaxError is raised
1383 1383 self.safe_execfile(err.filename,self.user_ns)
1384 1384 except:
1385 1385 self.showtraceback()
1386 1386 else:
1387 1387 try:
1388 1388 f = file(err.filename)
1389 1389 try:
1390 1390 # This should be inside a display_trap block and I
1391 1391 # think it is.
1392 1392 sys.displayhook(f.read())
1393 1393 finally:
1394 1394 f.close()
1395 1395 except:
1396 1396 self.showtraceback()
1397 1397
1398 1398 def _should_recompile(self,e):
1399 1399 """Utility routine for edit_syntax_error"""
1400 1400
1401 1401 if e.filename in ('<ipython console>','<input>','<string>',
1402 1402 '<console>','<BackgroundJob compilation>',
1403 1403 None):
1404 1404
1405 1405 return False
1406 1406 try:
1407 1407 if (self.autoedit_syntax and
1408 1408 not self.ask_yes_no('Return to editor to correct syntax error? '
1409 1409 '[Y/n] ','y')):
1410 1410 return False
1411 1411 except EOFError:
1412 1412 return False
1413 1413
1414 1414 def int0(x):
1415 1415 try:
1416 1416 return int(x)
1417 1417 except TypeError:
1418 1418 return 0
1419 1419 # always pass integer line and offset values to editor hook
1420 1420 try:
1421 1421 self.hooks.fix_error_editor(e.filename,
1422 1422 int0(e.lineno),int0(e.offset),e.msg)
1423 1423 except TryNext:
1424 1424 warn('Could not open editor')
1425 1425 return False
1426 1426 return True
1427 1427
1428 1428 #-------------------------------------------------------------------------
1429 1429 # Things related to tab completion
1430 1430 #-------------------------------------------------------------------------
1431 1431
1432 1432 def complete(self, text):
1433 1433 """Return a sorted list of all possible completions on text.
1434 1434
1435 1435 Inputs:
1436 1436
1437 1437 - text: a string of text to be completed on.
1438 1438
1439 1439 This is a wrapper around the completion mechanism, similar to what
1440 1440 readline does at the command line when the TAB key is hit. By
1441 1441 exposing it as a method, it can be used by other non-readline
1442 1442 environments (such as GUIs) for text completion.
1443 1443
1444 1444 Simple usage example:
1445 1445
1446 1446 In [7]: x = 'hello'
1447 1447
1448 1448 In [8]: x
1449 1449 Out[8]: 'hello'
1450 1450
1451 1451 In [9]: print x
1452 1452 hello
1453 1453
1454 1454 In [10]: _ip.complete('x.l')
1455 1455 Out[10]: ['x.ljust', 'x.lower', 'x.lstrip']
1456 1456 """
1457 1457
1458 1458 # Inject names into __builtin__ so we can complete on the added names.
1459 1459 with self.builtin_trap:
1460 1460 complete = self.Completer.complete
1461 1461 state = 0
1462 1462 # use a dict so we get unique keys, since ipyhton's multiple
1463 1463 # completers can return duplicates. When we make 2.4 a requirement,
1464 1464 # start using sets instead, which are faster.
1465 1465 comps = {}
1466 1466 while True:
1467 1467 newcomp = complete(text,state,line_buffer=text)
1468 1468 if newcomp is None:
1469 1469 break
1470 1470 comps[newcomp] = 1
1471 1471 state += 1
1472 1472 outcomps = comps.keys()
1473 1473 outcomps.sort()
1474 1474 #print "T:",text,"OC:",outcomps # dbg
1475 1475 #print "vars:",self.user_ns.keys()
1476 1476 return outcomps
1477 1477
1478 1478 def set_custom_completer(self,completer,pos=0):
1479 1479 """Adds a new custom completer function.
1480 1480
1481 1481 The position argument (defaults to 0) is the index in the completers
1482 1482 list where you want the completer to be inserted."""
1483 1483
1484 1484 newcomp = new.instancemethod(completer,self.Completer,
1485 1485 self.Completer.__class__)
1486 1486 self.Completer.matchers.insert(pos,newcomp)
1487 1487
1488 1488 def set_completer(self):
1489 1489 """Reset readline's completer to be our own."""
1490 1490 self.readline.set_completer(self.Completer.complete)
1491 1491
1492 1492 def set_completer_frame(self, frame=None):
1493 1493 """Set the frame of the completer."""
1494 1494 if frame:
1495 1495 self.Completer.namespace = frame.f_locals
1496 1496 self.Completer.global_namespace = frame.f_globals
1497 1497 else:
1498 1498 self.Completer.namespace = self.user_ns
1499 1499 self.Completer.global_namespace = self.user_global_ns
1500 1500
1501 1501 #-------------------------------------------------------------------------
1502 1502 # Things related to readline
1503 1503 #-------------------------------------------------------------------------
1504 1504
1505 1505 def init_readline(self):
1506 1506 """Command history completion/saving/reloading."""
1507 1507
1508 1508 if self.readline_use:
1509 1509 import IPython.utils.rlineimpl as readline
1510 1510
1511 1511 self.rl_next_input = None
1512 1512 self.rl_do_indent = False
1513 1513
1514 1514 if not self.readline_use or not readline.have_readline:
1515 1515 self.has_readline = False
1516 1516 self.readline = None
1517 1517 # Set a number of methods that depend on readline to be no-op
1518 1518 self.savehist = no_op
1519 1519 self.reloadhist = no_op
1520 1520 self.set_completer = no_op
1521 1521 self.set_custom_completer = no_op
1522 1522 self.set_completer_frame = no_op
1523 1523 warn('Readline services not available or not loaded.')
1524 1524 else:
1525 1525 self.has_readline = True
1526 1526 self.readline = readline
1527 1527 sys.modules['readline'] = readline
1528 1528 import atexit
1529 1529 from IPython.core.completer import IPCompleter
1530 1530 self.Completer = IPCompleter(self,
1531 1531 self.user_ns,
1532 1532 self.user_global_ns,
1533 1533 self.readline_omit__names,
1534 1534 self.alias_manager.alias_table)
1535 1535 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1536 1536 self.strdispatchers['complete_command'] = sdisp
1537 1537 self.Completer.custom_completers = sdisp
1538 1538 # Platform-specific configuration
1539 1539 if os.name == 'nt':
1540 1540 self.readline_startup_hook = readline.set_pre_input_hook
1541 1541 else:
1542 1542 self.readline_startup_hook = readline.set_startup_hook
1543 1543
1544 1544 # Load user's initrc file (readline config)
1545 1545 # Or if libedit is used, load editrc.
1546 1546 inputrc_name = os.environ.get('INPUTRC')
1547 1547 if inputrc_name is None:
1548 1548 home_dir = get_home_dir()
1549 1549 if home_dir is not None:
1550 1550 inputrc_name = '.inputrc'
1551 1551 if readline.uses_libedit:
1552 1552 inputrc_name = '.editrc'
1553 1553 inputrc_name = os.path.join(home_dir, inputrc_name)
1554 1554 if os.path.isfile(inputrc_name):
1555 1555 try:
1556 1556 readline.read_init_file(inputrc_name)
1557 1557 except:
1558 1558 warn('Problems reading readline initialization file <%s>'
1559 1559 % inputrc_name)
1560 1560
1561 1561 # save this in sys so embedded copies can restore it properly
1562 1562 sys.ipcompleter = self.Completer.complete
1563 1563 self.set_completer()
1564 1564
1565 1565 # Configure readline according to user's prefs
1566 1566 # This is only done if GNU readline is being used. If libedit
1567 1567 # is being used (as on Leopard) the readline config is
1568 1568 # not run as the syntax for libedit is different.
1569 1569 if not readline.uses_libedit:
1570 1570 for rlcommand in self.readline_parse_and_bind:
1571 1571 #print "loading rl:",rlcommand # dbg
1572 1572 readline.parse_and_bind(rlcommand)
1573 1573
1574 1574 # Remove some chars from the delimiters list. If we encounter
1575 1575 # unicode chars, discard them.
1576 1576 delims = readline.get_completer_delims().encode("ascii", "ignore")
1577 1577 delims = delims.translate(string._idmap,
1578 1578 self.readline_remove_delims)
1579 1579 readline.set_completer_delims(delims)
1580 1580 # otherwise we end up with a monster history after a while:
1581 1581 readline.set_history_length(1000)
1582 1582 try:
1583 1583 #print '*** Reading readline history' # dbg
1584 1584 readline.read_history_file(self.histfile)
1585 1585 except IOError:
1586 1586 pass # It doesn't exist yet.
1587 1587
1588 1588 atexit.register(self.atexit_operations)
1589 1589 del atexit
1590 1590
1591 1591 # Configure auto-indent for all platforms
1592 1592 self.set_autoindent(self.autoindent)
1593 1593
1594 1594 def set_next_input(self, s):
1595 1595 """ Sets the 'default' input string for the next command line.
1596 1596
1597 1597 Requires readline.
1598 1598
1599 1599 Example:
1600 1600
1601 1601 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1602 1602 [D:\ipython]|2> Hello Word_ # cursor is here
1603 1603 """
1604 1604
1605 1605 self.rl_next_input = s
1606 1606
1607 1607 def pre_readline(self):
1608 1608 """readline hook to be used at the start of each line.
1609 1609
1610 1610 Currently it handles auto-indent only."""
1611 1611
1612 1612 #debugx('self.indent_current_nsp','pre_readline:')
1613 1613
1614 1614 if self.rl_do_indent:
1615 1615 self.readline.insert_text(self._indent_current_str())
1616 1616 if self.rl_next_input is not None:
1617 1617 self.readline.insert_text(self.rl_next_input)
1618 1618 self.rl_next_input = None
1619 1619
1620 1620 def _indent_current_str(self):
1621 1621 """return the current level of indentation as a string"""
1622 1622 return self.indent_current_nsp * ' '
1623 1623
1624 1624 #-------------------------------------------------------------------------
1625 1625 # Things related to magics
1626 1626 #-------------------------------------------------------------------------
1627 1627
1628 1628 def init_magics(self):
1629 1629 # Set user colors (don't do it in the constructor above so that it
1630 1630 # doesn't crash if colors option is invalid)
1631 1631 self.magic_colors(self.colors)
1632 1632 # History was moved to a separate module
1633 1633 from . import history
1634 1634 history.init_ipython(self)
1635 1635
1636 1636 def magic(self,arg_s):
1637 1637 """Call a magic function by name.
1638 1638
1639 1639 Input: a string containing the name of the magic function to call and any
1640 1640 additional arguments to be passed to the magic.
1641 1641
1642 1642 magic('name -opt foo bar') is equivalent to typing at the ipython
1643 1643 prompt:
1644 1644
1645 1645 In[1]: %name -opt foo bar
1646 1646
1647 1647 To call a magic without arguments, simply use magic('name').
1648 1648
1649 1649 This provides a proper Python function to call IPython's magics in any
1650 1650 valid Python code you can type at the interpreter, including loops and
1651 1651 compound statements.
1652 1652 """
1653 1653 args = arg_s.split(' ',1)
1654 1654 magic_name = args[0]
1655 1655 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1656 1656
1657 1657 try:
1658 1658 magic_args = args[1]
1659 1659 except IndexError:
1660 1660 magic_args = ''
1661 1661 fn = getattr(self,'magic_'+magic_name,None)
1662 1662 if fn is None:
1663 1663 error("Magic function `%s` not found." % magic_name)
1664 1664 else:
1665 1665 magic_args = self.var_expand(magic_args,1)
1666 1666 with nested(self.builtin_trap,):
1667 1667 result = fn(magic_args)
1668 1668 return result
1669 1669
1670 1670 def define_magic(self, magicname, func):
1671 1671 """Expose own function as magic function for ipython
1672 1672
1673 1673 def foo_impl(self,parameter_s=''):
1674 1674 'My very own magic!. (Use docstrings, IPython reads them).'
1675 1675 print 'Magic function. Passed parameter is between < >:'
1676 1676 print '<%s>' % parameter_s
1677 1677 print 'The self object is:',self
1678 1678
1679 1679 self.define_magic('foo',foo_impl)
1680 1680 """
1681 1681
1682 1682 import new
1683 1683 im = new.instancemethod(func,self, self.__class__)
1684 1684 old = getattr(self, "magic_" + magicname, None)
1685 1685 setattr(self, "magic_" + magicname, im)
1686 1686 return old
1687 1687
1688 1688 #-------------------------------------------------------------------------
1689 1689 # Things related to macros
1690 1690 #-------------------------------------------------------------------------
1691 1691
1692 1692 def define_macro(self, name, themacro):
1693 1693 """Define a new macro
1694 1694
1695 1695 Parameters
1696 1696 ----------
1697 1697 name : str
1698 1698 The name of the macro.
1699 1699 themacro : str or Macro
1700 1700 The action to do upon invoking the macro. If a string, a new
1701 1701 Macro object is created by passing the string to it.
1702 1702 """
1703 1703
1704 1704 from IPython.core import macro
1705 1705
1706 1706 if isinstance(themacro, basestring):
1707 1707 themacro = macro.Macro(themacro)
1708 1708 if not isinstance(themacro, macro.Macro):
1709 1709 raise ValueError('A macro must be a string or a Macro instance.')
1710 1710 self.user_ns[name] = themacro
1711 1711
1712 1712 #-------------------------------------------------------------------------
1713 1713 # Things related to the running of system commands
1714 1714 #-------------------------------------------------------------------------
1715 1715
1716 1716 def system(self, cmd):
1717 1717 """Make a system call, using IPython."""
1718 1718 return self.hooks.shell_hook(self.var_expand(cmd, depth=2))
1719 1719
1720 1720 #-------------------------------------------------------------------------
1721 1721 # Things related to aliases
1722 1722 #-------------------------------------------------------------------------
1723 1723
1724 1724 def init_alias(self):
1725 1725 self.alias_manager = AliasManager(self, config=self.config)
1726 1726 self.ns_table['alias'] = self.alias_manager.alias_table,
1727 1727
1728 1728 #-------------------------------------------------------------------------
1729 1729 # Things related to the running of code
1730 1730 #-------------------------------------------------------------------------
1731 1731
1732 1732 def ex(self, cmd):
1733 1733 """Execute a normal python statement in user namespace."""
1734 1734 with nested(self.builtin_trap,):
1735 1735 exec cmd in self.user_global_ns, self.user_ns
1736 1736
1737 1737 def ev(self, expr):
1738 1738 """Evaluate python expression expr in user namespace.
1739 1739
1740 1740 Returns the result of evaluation
1741 1741 """
1742 1742 with nested(self.builtin_trap,):
1743 1743 return eval(expr, self.user_global_ns, self.user_ns)
1744 1744
1745 1745 def mainloop(self, display_banner=None):
1746 1746 """Start the mainloop.
1747 1747
1748 1748 If an optional banner argument is given, it will override the
1749 1749 internally created default banner.
1750 1750 """
1751 1751
1752 1752 with nested(self.builtin_trap, self.display_trap):
1753 1753
1754 1754 # if you run stuff with -c <cmd>, raw hist is not updated
1755 1755 # ensure that it's in sync
1756 1756 if len(self.input_hist) != len (self.input_hist_raw):
1757 1757 self.input_hist_raw = InputList(self.input_hist)
1758 1758
1759 1759 while 1:
1760 1760 try:
1761 1761 self.interact(display_banner=display_banner)
1762 1762 #self.interact_with_readline()
1763 1763 # XXX for testing of a readline-decoupled repl loop, call
1764 1764 # interact_with_readline above
1765 1765 break
1766 1766 except KeyboardInterrupt:
1767 1767 # this should not be necessary, but KeyboardInterrupt
1768 1768 # handling seems rather unpredictable...
1769 1769 self.write("\nKeyboardInterrupt in interact()\n")
1770 1770
1771 1771 def interact_prompt(self):
1772 1772 """ Print the prompt (in read-eval-print loop)
1773 1773
1774 1774 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1775 1775 used in standard IPython flow.
1776 1776 """
1777 1777 if self.more:
1778 1778 try:
1779 1779 prompt = self.hooks.generate_prompt(True)
1780 1780 except:
1781 1781 self.showtraceback()
1782 1782 if self.autoindent:
1783 1783 self.rl_do_indent = True
1784 1784
1785 1785 else:
1786 1786 try:
1787 1787 prompt = self.hooks.generate_prompt(False)
1788 1788 except:
1789 1789 self.showtraceback()
1790 1790 self.write(prompt)
1791 1791
1792 1792 def interact_handle_input(self,line):
1793 1793 """ Handle the input line (in read-eval-print loop)
1794 1794
1795 1795 Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
1796 1796 used in standard IPython flow.
1797 1797 """
1798 1798 if line.lstrip() == line:
1799 1799 self.shadowhist.add(line.strip())
1800 1800 lineout = self.prefilter_manager.prefilter_lines(line,self.more)
1801 1801
1802 1802 if line.strip():
1803 1803 if self.more:
1804 1804 self.input_hist_raw[-1] += '%s\n' % line
1805 1805 else:
1806 1806 self.input_hist_raw.append('%s\n' % line)
1807 1807
1808 1808
1809 1809 self.more = self.push_line(lineout)
1810 1810 if (self.SyntaxTB.last_syntax_error and
1811 1811 self.autoedit_syntax):
1812 1812 self.edit_syntax_error()
1813 1813
1814 1814 def interact_with_readline(self):
1815 1815 """ Demo of using interact_handle_input, interact_prompt
1816 1816
1817 1817 This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI),
1818 1818 it should work like this.
1819 1819 """
1820 1820 self.readline_startup_hook(self.pre_readline)
1821 1821 while not self.exit_now:
1822 1822 self.interact_prompt()
1823 1823 if self.more:
1824 1824 self.rl_do_indent = True
1825 1825 else:
1826 1826 self.rl_do_indent = False
1827 1827 line = raw_input_original().decode(self.stdin_encoding)
1828 1828 self.interact_handle_input(line)
1829 1829
1830 1830 def interact(self, display_banner=None):
1831 1831 """Closely emulate the interactive Python console."""
1832 1832
1833 1833 # batch run -> do not interact
1834 1834 if self.exit_now:
1835 1835 return
1836 1836
1837 1837 if display_banner is None:
1838 1838 display_banner = self.display_banner
1839 1839 if display_banner:
1840 1840 self.show_banner()
1841 1841
1842 1842 more = 0
1843 1843
1844 1844 # Mark activity in the builtins
1845 1845 __builtin__.__dict__['__IPYTHON__active'] += 1
1846 1846
1847 1847 if self.has_readline:
1848 1848 self.readline_startup_hook(self.pre_readline)
1849 1849 # exit_now is set by a call to %Exit or %Quit, through the
1850 1850 # ask_exit callback.
1851 1851
1852 1852 while not self.exit_now:
1853 1853 self.hooks.pre_prompt_hook()
1854 1854 if more:
1855 1855 try:
1856 1856 prompt = self.hooks.generate_prompt(True)
1857 1857 except:
1858 1858 self.showtraceback()
1859 1859 if self.autoindent:
1860 1860 self.rl_do_indent = True
1861 1861
1862 1862 else:
1863 1863 try:
1864 1864 prompt = self.hooks.generate_prompt(False)
1865 1865 except:
1866 1866 self.showtraceback()
1867 1867 try:
1868 1868 line = self.raw_input(prompt, more)
1869 1869 if self.exit_now:
1870 1870 # quick exit on sys.std[in|out] close
1871 1871 break
1872 1872 if self.autoindent:
1873 1873 self.rl_do_indent = False
1874 1874
1875 1875 except KeyboardInterrupt:
1876 1876 #double-guard against keyboardinterrupts during kbdint handling
1877 1877 try:
1878 1878 self.write('\nKeyboardInterrupt\n')
1879 1879 self.resetbuffer()
1880 1880 # keep cache in sync with the prompt counter:
1881 1881 self.outputcache.prompt_count -= 1
1882 1882
1883 1883 if self.autoindent:
1884 1884 self.indent_current_nsp = 0
1885 1885 more = 0
1886 1886 except KeyboardInterrupt:
1887 1887 pass
1888 1888 except EOFError:
1889 1889 if self.autoindent:
1890 1890 self.rl_do_indent = False
1891 1891 if self.has_readline:
1892 1892 self.readline_startup_hook(None)
1893 1893 self.write('\n')
1894 1894 self.exit()
1895 1895 except bdb.BdbQuit:
1896 1896 warn('The Python debugger has exited with a BdbQuit exception.\n'
1897 1897 'Because of how pdb handles the stack, it is impossible\n'
1898 1898 'for IPython to properly format this particular exception.\n'
1899 1899 'IPython will resume normal operation.')
1900 1900 except:
1901 1901 # exceptions here are VERY RARE, but they can be triggered
1902 1902 # asynchronously by signal handlers, for example.
1903 1903 self.showtraceback()
1904 1904 else:
1905 1905 more = self.push_line(line)
1906 1906 if (self.SyntaxTB.last_syntax_error and
1907 1907 self.autoedit_syntax):
1908 1908 self.edit_syntax_error()
1909 1909
1910 1910 # We are off again...
1911 1911 __builtin__.__dict__['__IPYTHON__active'] -= 1
1912 1912
1913 1913 # Turn off the exit flag, so the mainloop can be restarted if desired
1914 1914 self.exit_now = False
1915 1915
1916 1916 def safe_execfile(self, fname, *where, **kw):
1917 1917 """A safe version of the builtin execfile().
1918 1918
1919 1919 This version will never throw an exception, but instead print
1920 1920 helpful error messages to the screen. This only works on pure
1921 1921 Python files with the .py extension.
1922 1922
1923 1923 Parameters
1924 1924 ----------
1925 1925 fname : string
1926 1926 The name of the file to be executed.
1927 1927 where : tuple
1928 1928 One or two namespaces, passed to execfile() as (globals,locals).
1929 1929 If only one is given, it is passed as both.
1930 1930 exit_ignore : bool (False)
1931 1931 If True, then silence SystemExit for non-zero status (it is always
1932 1932 silenced for zero status, as it is so common).
1933 1933 """
1934 1934 kw.setdefault('exit_ignore', False)
1935 1935
1936 1936 fname = os.path.abspath(os.path.expanduser(fname))
1937 1937
1938 1938 # Make sure we have a .py file
1939 1939 if not fname.endswith('.py'):
1940 1940 warn('File must end with .py to be run using execfile: <%s>' % fname)
1941 1941
1942 1942 # Make sure we can open the file
1943 1943 try:
1944 1944 with open(fname) as thefile:
1945 1945 pass
1946 1946 except:
1947 1947 warn('Could not open file <%s> for safe execution.' % fname)
1948 1948 return
1949 1949
1950 1950 # Find things also in current directory. This is needed to mimic the
1951 1951 # behavior of running a script from the system command line, where
1952 1952 # Python inserts the script's directory into sys.path
1953 1953 dname = os.path.dirname(fname)
1954 1954
1955 1955 with prepended_to_syspath(dname):
1956 1956 try:
1957 1957 execfile(fname,*where)
1958 1958 except SystemExit, status:
1959 1959 # If the call was made with 0 or None exit status (sys.exit(0)
1960 1960 # or sys.exit() ), don't bother showing a traceback, as both of
1961 1961 # these are considered normal by the OS:
1962 1962 # > python -c'import sys;sys.exit(0)'; echo $?
1963 1963 # 0
1964 1964 # > python -c'import sys;sys.exit()'; echo $?
1965 1965 # 0
1966 1966 # For other exit status, we show the exception unless
1967 1967 # explicitly silenced, but only in short form.
1968 1968 if status.code not in (0, None) and not kw['exit_ignore']:
1969 1969 self.showtraceback(exception_only=True)
1970 1970 except:
1971 1971 self.showtraceback()
1972 1972
1973 1973 def safe_execfile_ipy(self, fname):
1974 1974 """Like safe_execfile, but for .ipy files with IPython syntax.
1975 1975
1976 1976 Parameters
1977 1977 ----------
1978 1978 fname : str
1979 1979 The name of the file to execute. The filename must have a
1980 1980 .ipy extension.
1981 1981 """
1982 1982 fname = os.path.abspath(os.path.expanduser(fname))
1983 1983
1984 1984 # Make sure we have a .py file
1985 1985 if not fname.endswith('.ipy'):
1986 1986 warn('File must end with .py to be run using execfile: <%s>' % fname)
1987 1987
1988 1988 # Make sure we can open the file
1989 1989 try:
1990 1990 with open(fname) as thefile:
1991 1991 pass
1992 1992 except:
1993 1993 warn('Could not open file <%s> for safe execution.' % fname)
1994 1994 return
1995 1995
1996 1996 # Find things also in current directory. This is needed to mimic the
1997 1997 # behavior of running a script from the system command line, where
1998 1998 # Python inserts the script's directory into sys.path
1999 1999 dname = os.path.dirname(fname)
2000 2000
2001 2001 with prepended_to_syspath(dname):
2002 2002 try:
2003 2003 with open(fname) as thefile:
2004 2004 script = thefile.read()
2005 2005 # self.runlines currently captures all exceptions
2006 2006 # raise in user code. It would be nice if there were
2007 2007 # versions of runlines, execfile that did raise, so
2008 2008 # we could catch the errors.
2009 2009 self.runlines(script, clean=True)
2010 2010 except:
2011 2011 self.showtraceback()
2012 2012 warn('Unknown failure executing file: <%s>' % fname)
2013 2013
2014 2014 def _is_secondary_block_start(self, s):
2015 2015 if not s.endswith(':'):
2016 2016 return False
2017 2017 if (s.startswith('elif') or
2018 2018 s.startswith('else') or
2019 2019 s.startswith('except') or
2020 2020 s.startswith('finally')):
2021 2021 return True
2022 2022
2023 2023 def cleanup_ipy_script(self, script):
2024 2024 """Make a script safe for self.runlines()
2025 2025
2026 2026 Currently, IPython is lines based, with blocks being detected by
2027 2027 empty lines. This is a problem for block based scripts that may
2028 2028 not have empty lines after blocks. This script adds those empty
2029 2029 lines to make scripts safe for running in the current line based
2030 2030 IPython.
2031 2031 """
2032 2032 res = []
2033 2033 lines = script.splitlines()
2034 2034 level = 0
2035 2035
2036 2036 for l in lines:
2037 2037 lstripped = l.lstrip()
2038 2038 stripped = l.strip()
2039 2039 if not stripped:
2040 2040 continue
2041 2041 newlevel = len(l) - len(lstripped)
2042 2042 if level > 0 and newlevel == 0 and \
2043 2043 not self._is_secondary_block_start(stripped):
2044 2044 # add empty line
2045 2045 res.append('')
2046 2046 res.append(l)
2047 2047 level = newlevel
2048 2048
2049 2049 return '\n'.join(res) + '\n'
2050 2050
2051 2051 def runlines(self, lines, clean=False):
2052 2052 """Run a string of one or more lines of source.
2053 2053
2054 2054 This method is capable of running a string containing multiple source
2055 2055 lines, as if they had been entered at the IPython prompt. Since it
2056 2056 exposes IPython's processing machinery, the given strings can contain
2057 2057 magic calls (%magic), special shell access (!cmd), etc.
2058 2058 """
2059 2059
2060 2060 if isinstance(lines, (list, tuple)):
2061 2061 lines = '\n'.join(lines)
2062 2062
2063 2063 if clean:
2064 2064 lines = self.cleanup_ipy_script(lines)
2065 2065
2066 2066 # We must start with a clean buffer, in case this is run from an
2067 2067 # interactive IPython session (via a magic, for example).
2068 2068 self.resetbuffer()
2069 2069 lines = lines.splitlines()
2070 2070 more = 0
2071 2071
2072 2072 with nested(self.builtin_trap, self.display_trap):
2073 2073 for line in lines:
2074 2074 # skip blank lines so we don't mess up the prompt counter, but do
2075 2075 # NOT skip even a blank line if we are in a code block (more is
2076 2076 # true)
2077 2077
2078 2078 if line or more:
2079 2079 # push to raw history, so hist line numbers stay in sync
2080 2080 self.input_hist_raw.append("# " + line + "\n")
2081 2081 prefiltered = self.prefilter_manager.prefilter_lines(line,more)
2082 2082 more = self.push_line(prefiltered)
2083 2083 # IPython's runsource returns None if there was an error
2084 2084 # compiling the code. This allows us to stop processing right
2085 2085 # away, so the user gets the error message at the right place.
2086 2086 if more is None:
2087 2087 break
2088 2088 else:
2089 2089 self.input_hist_raw.append("\n")
2090 2090 # final newline in case the input didn't have it, so that the code
2091 2091 # actually does get executed
2092 2092 if more:
2093 2093 self.push_line('\n')
2094 2094
2095 2095 def runsource(self, source, filename='<input>', symbol='single'):
2096 2096 """Compile and run some source in the interpreter.
2097 2097
2098 2098 Arguments are as for compile_command().
2099 2099
2100 2100 One several things can happen:
2101 2101
2102 2102 1) The input is incorrect; compile_command() raised an
2103 2103 exception (SyntaxError or OverflowError). A syntax traceback
2104 2104 will be printed by calling the showsyntaxerror() method.
2105 2105
2106 2106 2) The input is incomplete, and more input is required;
2107 2107 compile_command() returned None. Nothing happens.
2108 2108
2109 2109 3) The input is complete; compile_command() returned a code
2110 2110 object. The code is executed by calling self.runcode() (which
2111 2111 also handles run-time exceptions, except for SystemExit).
2112 2112
2113 2113 The return value is:
2114 2114
2115 2115 - True in case 2
2116 2116
2117 2117 - False in the other cases, unless an exception is raised, where
2118 2118 None is returned instead. This can be used by external callers to
2119 2119 know whether to continue feeding input or not.
2120 2120
2121 2121 The return value can be used to decide whether to use sys.ps1 or
2122 2122 sys.ps2 to prompt the next line."""
2123 2123
2124 2124 # if the source code has leading blanks, add 'if 1:\n' to it
2125 2125 # this allows execution of indented pasted code. It is tempting
2126 2126 # to add '\n' at the end of source to run commands like ' a=1'
2127 2127 # directly, but this fails for more complicated scenarios
2128 2128 source=source.encode(self.stdin_encoding)
2129 2129 if source[:1] in [' ', '\t']:
2130 2130 source = 'if 1:\n%s' % source
2131 2131
2132 2132 try:
2133 2133 code = self.compile(source,filename,symbol)
2134 2134 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
2135 2135 # Case 1
2136 2136 self.showsyntaxerror(filename)
2137 2137 return None
2138 2138
2139 2139 if code is None:
2140 2140 # Case 2
2141 2141 return True
2142 2142
2143 2143 # Case 3
2144 2144 # We store the code object so that threaded shells and
2145 2145 # custom exception handlers can access all this info if needed.
2146 2146 # The source corresponding to this can be obtained from the
2147 2147 # buffer attribute as '\n'.join(self.buffer).
2148 2148 self.code_to_run = code
2149 2149 # now actually execute the code object
2150 2150 if self.runcode(code) == 0:
2151 2151 return False
2152 2152 else:
2153 2153 return None
2154 2154
2155 2155 def runcode(self,code_obj):
2156 2156 """Execute a code object.
2157 2157
2158 2158 When an exception occurs, self.showtraceback() is called to display a
2159 2159 traceback.
2160 2160
2161 2161 Return value: a flag indicating whether the code to be run completed
2162 2162 successfully:
2163 2163
2164 2164 - 0: successful execution.
2165 2165 - 1: an error occurred.
2166 2166 """
2167 2167
2168 2168 # Set our own excepthook in case the user code tries to call it
2169 2169 # directly, so that the IPython crash handler doesn't get triggered
2170 2170 old_excepthook,sys.excepthook = sys.excepthook, self.excepthook
2171 2171
2172 2172 # we save the original sys.excepthook in the instance, in case config
2173 2173 # code (such as magics) needs access to it.
2174 2174 self.sys_excepthook = old_excepthook
2175 2175 outflag = 1 # happens in more places, so it's easier as default
2176 2176 try:
2177 2177 try:
2178 2178 self.hooks.pre_runcode_hook()
2179 2179 exec code_obj in self.user_global_ns, self.user_ns
2180 2180 finally:
2181 2181 # Reset our crash handler in place
2182 2182 sys.excepthook = old_excepthook
2183 2183 except SystemExit:
2184 2184 self.resetbuffer()
2185 2185 self.showtraceback(exception_only=True)
2186 2186 warn("To exit: use any of 'exit', 'quit', %Exit or Ctrl-D.", level=1)
2187 2187 except self.custom_exceptions:
2188 2188 etype,value,tb = sys.exc_info()
2189 2189 self.CustomTB(etype,value,tb)
2190 2190 except:
2191 2191 self.showtraceback()
2192 2192 else:
2193 2193 outflag = 0
2194 2194 if softspace(sys.stdout, 0):
2195 2195 print
2196 2196 # Flush out code object which has been run (and source)
2197 2197 self.code_to_run = None
2198 2198 return outflag
2199 2199
2200 2200 def push_line(self, line):
2201 2201 """Push a line to the interpreter.
2202 2202
2203 2203 The line should not have a trailing newline; it may have
2204 2204 internal newlines. The line is appended to a buffer and the
2205 2205 interpreter's runsource() method is called with the
2206 2206 concatenated contents of the buffer as source. If this
2207 2207 indicates that the command was executed or invalid, the buffer
2208 2208 is reset; otherwise, the command is incomplete, and the buffer
2209 2209 is left as it was after the line was appended. The return
2210 2210 value is 1 if more input is required, 0 if the line was dealt
2211 2211 with in some way (this is the same as runsource()).
2212 2212 """
2213 2213
2214 2214 # autoindent management should be done here, and not in the
2215 2215 # interactive loop, since that one is only seen by keyboard input. We
2216 2216 # need this done correctly even for code run via runlines (which uses
2217 2217 # push).
2218 2218
2219 2219 #print 'push line: <%s>' % line # dbg
2220 2220 for subline in line.splitlines():
2221 2221 self._autoindent_update(subline)
2222 2222 self.buffer.append(line)
2223 2223 more = self.runsource('\n'.join(self.buffer), self.filename)
2224 2224 if not more:
2225 2225 self.resetbuffer()
2226 2226 return more
2227 2227
2228 2228 def _autoindent_update(self,line):
2229 2229 """Keep track of the indent level."""
2230 2230
2231 2231 #debugx('line')
2232 2232 #debugx('self.indent_current_nsp')
2233 2233 if self.autoindent:
2234 2234 if line:
2235 2235 inisp = num_ini_spaces(line)
2236 2236 if inisp < self.indent_current_nsp:
2237 2237 self.indent_current_nsp = inisp
2238 2238
2239 2239 if line[-1] == ':':
2240 2240 self.indent_current_nsp += 4
2241 2241 elif dedent_re.match(line):
2242 2242 self.indent_current_nsp -= 4
2243 2243 else:
2244 2244 self.indent_current_nsp = 0
2245 2245
2246 2246 def resetbuffer(self):
2247 2247 """Reset the input buffer."""
2248 2248 self.buffer[:] = []
2249 2249
2250 2250 def raw_input(self,prompt='',continue_prompt=False):
2251 2251 """Write a prompt and read a line.
2252 2252
2253 2253 The returned line does not include the trailing newline.
2254 2254 When the user enters the EOF key sequence, EOFError is raised.
2255 2255
2256 2256 Optional inputs:
2257 2257
2258 2258 - prompt(''): a string to be printed to prompt the user.
2259 2259
2260 2260 - continue_prompt(False): whether this line is the first one or a
2261 2261 continuation in a sequence of inputs.
2262 2262 """
2263 2263 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
2264 2264
2265 2265 # Code run by the user may have modified the readline completer state.
2266 2266 # We must ensure that our completer is back in place.
2267 2267
2268 2268 if self.has_readline:
2269 2269 self.set_completer()
2270 2270
2271 2271 try:
2272 2272 line = raw_input_original(prompt).decode(self.stdin_encoding)
2273 2273 except ValueError:
2274 2274 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
2275 2275 " or sys.stdout.close()!\nExiting IPython!")
2276 2276 self.ask_exit()
2277 2277 return ""
2278 2278
2279 2279 # Try to be reasonably smart about not re-indenting pasted input more
2280 2280 # than necessary. We do this by trimming out the auto-indent initial
2281 2281 # spaces, if the user's actual input started itself with whitespace.
2282 2282 #debugx('self.buffer[-1]')
2283 2283
2284 2284 if self.autoindent:
2285 2285 if num_ini_spaces(line) > self.indent_current_nsp:
2286 2286 line = line[self.indent_current_nsp:]
2287 2287 self.indent_current_nsp = 0
2288 2288
2289 2289 # store the unfiltered input before the user has any chance to modify
2290 2290 # it.
2291 2291 if line.strip():
2292 2292 if continue_prompt:
2293 2293 self.input_hist_raw[-1] += '%s\n' % line
2294 2294 if self.has_readline and self.readline_use:
2295 2295 try:
2296 2296 histlen = self.readline.get_current_history_length()
2297 2297 if histlen > 1:
2298 2298 newhist = self.input_hist_raw[-1].rstrip()
2299 2299 self.readline.remove_history_item(histlen-1)
2300 2300 self.readline.replace_history_item(histlen-2,
2301 2301 newhist.encode(self.stdin_encoding))
2302 2302 except AttributeError:
2303 2303 pass # re{move,place}_history_item are new in 2.4.
2304 2304 else:
2305 2305 self.input_hist_raw.append('%s\n' % line)
2306 2306 # only entries starting at first column go to shadow history
2307 2307 if line.lstrip() == line:
2308 2308 self.shadowhist.add(line.strip())
2309 2309 elif not continue_prompt:
2310 2310 self.input_hist_raw.append('\n')
2311 2311 try:
2312 2312 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
2313 2313 except:
2314 2314 # blanket except, in case a user-defined prefilter crashes, so it
2315 2315 # can't take all of ipython with it.
2316 2316 self.showtraceback()
2317 2317 return ''
2318 2318 else:
2319 2319 return lineout
2320 2320
2321 2321 #-------------------------------------------------------------------------
2322 2322 # Working with components
2323 2323 #-------------------------------------------------------------------------
2324 2324
2325 2325 def get_component(self, name=None, klass=None):
2326 2326 """Fetch a component by name and klass in my tree."""
2327 2327 c = Component.get_instances(root=self, name=name, klass=klass)
2328 2328 if len(c) == 0:
2329 2329 return None
2330 2330 if len(c) == 1:
2331 2331 return c[0]
2332 2332 else:
2333 2333 return c
2334 2334
2335 2335 #-------------------------------------------------------------------------
2336 2336 # IPython extensions
2337 2337 #-------------------------------------------------------------------------
2338 2338
2339 2339 def load_extension(self, module_str):
2340 2340 """Load an IPython extension by its module name.
2341 2341
2342 2342 An IPython extension is an importable Python module that has
2343 2343 a function with the signature::
2344 2344
2345 2345 def load_ipython_extension(ipython):
2346 2346 # Do things with ipython
2347 2347
2348 2348 This function is called after your extension is imported and the
2349 2349 currently active :class:`InteractiveShell` instance is passed as
2350 2350 the only argument. You can do anything you want with IPython at
2351 2351 that point, including defining new magic and aliases, adding new
2352 2352 components, etc.
2353 2353
2354 2354 The :func:`load_ipython_extension` will be called again is you
2355 2355 load or reload the extension again. It is up to the extension
2356 2356 author to add code to manage that.
2357 2357
2358 2358 You can put your extension modules anywhere you want, as long as
2359 2359 they can be imported by Python's standard import mechanism. However,
2360 2360 to make it easy to write extensions, you can also put your extensions
2361 2361 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
2362 2362 is added to ``sys.path`` automatically.
2363 2363 """
2364 2364 from IPython.utils.syspathcontext import prepended_to_syspath
2365 2365
2366 2366 if module_str not in sys.modules:
2367 2367 with prepended_to_syspath(self.ipython_extension_dir):
2368 2368 __import__(module_str)
2369 2369 mod = sys.modules[module_str]
2370 2370 return self._call_load_ipython_extension(mod)
2371 2371
2372 2372 def unload_extension(self, module_str):
2373 2373 """Unload an IPython extension by its module name.
2374 2374
2375 2375 This function looks up the extension's name in ``sys.modules`` and
2376 2376 simply calls ``mod.unload_ipython_extension(self)``.
2377 2377 """
2378 2378 if module_str in sys.modules:
2379 2379 mod = sys.modules[module_str]
2380 2380 self._call_unload_ipython_extension(mod)
2381 2381
2382 2382 def reload_extension(self, module_str):
2383 2383 """Reload an IPython extension by calling reload.
2384 2384
2385 2385 If the module has not been loaded before,
2386 2386 :meth:`InteractiveShell.load_extension` is called. Otherwise
2387 2387 :func:`reload` is called and then the :func:`load_ipython_extension`
2388 2388 function of the module, if it exists is called.
2389 2389 """
2390 2390 from IPython.utils.syspathcontext import prepended_to_syspath
2391 2391
2392 2392 with prepended_to_syspath(self.ipython_extension_dir):
2393 2393 if module_str in sys.modules:
2394 2394 mod = sys.modules[module_str]
2395 2395 reload(mod)
2396 2396 self._call_load_ipython_extension(mod)
2397 2397 else:
2398 2398 self.load_extension(module_str)
2399 2399
2400 2400 def _call_load_ipython_extension(self, mod):
2401 2401 if hasattr(mod, 'load_ipython_extension'):
2402 2402 return mod.load_ipython_extension(self)
2403 2403
2404 2404 def _call_unload_ipython_extension(self, mod):
2405 2405 if hasattr(mod, 'unload_ipython_extension'):
2406 2406 return mod.unload_ipython_extension(self)
2407 2407
2408 2408 #-------------------------------------------------------------------------
2409 2409 # Things related to the prefilter
2410 2410 #-------------------------------------------------------------------------
2411 2411
2412 2412 def init_prefilter(self):
2413 2413 self.prefilter_manager = PrefilterManager(self, config=self.config)
2414 2414 # Ultimately this will be refactored in the new interpreter code, but
2415 2415 # for now, we should expose the main prefilter method (there's legacy
2416 2416 # code out there that may rely on this).
2417 2417 self.prefilter = self.prefilter_manager.prefilter_lines
2418 2418
2419 2419 #-------------------------------------------------------------------------
2420 2420 # Utilities
2421 2421 #-------------------------------------------------------------------------
2422 2422
2423 2423 def getoutput(self, cmd):
2424 2424 return getoutput(self.var_expand(cmd,depth=2),
2425 2425 header=self.system_header,
2426 2426 verbose=self.system_verbose)
2427 2427
2428 2428 def getoutputerror(self, cmd):
2429 2429 return getoutputerror(self.var_expand(cmd,depth=2),
2430 2430 header=self.system_header,
2431 2431 verbose=self.system_verbose)
2432 2432
2433 2433 def var_expand(self,cmd,depth=0):
2434 2434 """Expand python variables in a string.
2435 2435
2436 2436 The depth argument indicates how many frames above the caller should
2437 2437 be walked to look for the local namespace where to expand variables.
2438 2438
2439 2439 The global namespace for expansion is always the user's interactive
2440 2440 namespace.
2441 2441 """
2442 2442
2443 2443 return str(ItplNS(cmd,
2444 2444 self.user_ns, # globals
2445 2445 # Skip our own frame in searching for locals:
2446 2446 sys._getframe(depth+1).f_locals # locals
2447 2447 ))
2448 2448
2449 2449 def mktempfile(self,data=None):
2450 2450 """Make a new tempfile and return its filename.
2451 2451
2452 2452 This makes a call to tempfile.mktemp, but it registers the created
2453 2453 filename internally so ipython cleans it up at exit time.
2454 2454
2455 2455 Optional inputs:
2456 2456
2457 2457 - data(None): if data is given, it gets written out to the temp file
2458 2458 immediately, and the file is closed again."""
2459 2459
2460 2460 filename = tempfile.mktemp('.py','ipython_edit_')
2461 2461 self.tempfiles.append(filename)
2462 2462
2463 2463 if data:
2464 2464 tmp_file = open(filename,'w')
2465 2465 tmp_file.write(data)
2466 2466 tmp_file.close()
2467 2467 return filename
2468 2468
2469 2469 def write(self,data):
2470 2470 """Write a string to the default output"""
2471 2471 Term.cout.write(data)
2472 2472
2473 2473 def write_err(self,data):
2474 2474 """Write a string to the default error output"""
2475 2475 Term.cerr.write(data)
2476 2476
2477 2477 def ask_yes_no(self,prompt,default=True):
2478 2478 if self.quiet:
2479 2479 return True
2480 2480 return ask_yes_no(prompt,default)
2481 2481
2482 2482 #-------------------------------------------------------------------------
2483 2483 # Things related to GUI support and pylab
2484 2484 #-------------------------------------------------------------------------
2485 2485
2486 2486 def enable_pylab(self, gui=None):
2487 2487 """Activate pylab support at runtime.
2488 2488
2489 2489 This turns on support for matplotlib, preloads into the interactive
2490 2490 namespace all of numpy and pylab, and configures IPython to correcdtly
2491 2491 interact with the GUI event loop. The GUI backend to be used can be
2492 2492 optionally selected with the optional :param:`gui` argument.
2493 2493
2494 2494 Parameters
2495 2495 ----------
2496 2496 gui : optional, string
2497 2497
2498 2498 If given, dictates the choice of matplotlib GUI backend to use
2499 2499 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
2500 2500 'gtk'), otherwise we use the default chosen by matplotlib (as
2501 2501 dictated by the matplotlib build-time options plus the user's
2502 2502 matplotlibrc configuration file).
2503 2503 """
2504 2504 # We want to prevent the loading of pylab to pollute the user's
2505 2505 # namespace as shown by the %who* magics, so we execute the activation
2506 2506 # code in an empty namespace, and we update *both* user_ns and
2507 2507 # user_config_ns with this information.
2508 2508 ns = {}
2509 2509 gui = pylab_activate(ns, gui)
2510 2510 self.user_ns.update(ns)
2511 2511 self.user_config_ns.update(ns)
2512 2512 # Now we must activate the gui pylab wants to use, and fix %run to take
2513 2513 # plot updates into account
2514 2514 enable_gui(gui)
2515 2515 self.magic_run = self._pylab_magic_run
2516 2516
2517 2517 #-------------------------------------------------------------------------
2518 2518 # Things related to IPython exiting
2519 2519 #-------------------------------------------------------------------------
2520 2520
2521 2521 def ask_exit(self):
2522 2522 """ Ask the shell to exit. Can be overiden and used as a callback. """
2523 2523 self.exit_now = True
2524 2524
2525 2525 def exit(self):
2526 2526 """Handle interactive exit.
2527 2527
2528 2528 This method calls the ask_exit callback."""
2529 2529 if self.confirm_exit:
2530 2530 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
2531 2531 self.ask_exit()
2532 2532 else:
2533 2533 self.ask_exit()
2534 2534
2535 2535 def atexit_operations(self):
2536 2536 """This will be executed at the time of exit.
2537 2537
2538 2538 Saving of persistent data should be performed here.
2539 2539 """
2540 2540 self.savehist()
2541 2541
2542 2542 # Cleanup all tempfiles left around
2543 2543 for tfile in self.tempfiles:
2544 2544 try:
2545 2545 os.unlink(tfile)
2546 2546 except OSError:
2547 2547 pass
2548 2548
2549 2549 # Clear all user namespaces to release all references cleanly.
2550 2550 self.reset()
2551 2551
2552 2552 # Run user hooks
2553 2553 self.hooks.shutdown_hook()
2554 2554
2555 2555 def cleanup(self):
2556 2556 self.restore_sys_module_state()
2557 2557
2558 2558
@@ -1,167 +1,166 b''
1 1 """Use pretty.py for configurable pretty-printing.
2 2
3 3 To enable this extension in your configuration
4 4 file, add the following to :file:`ipython_config.py`::
5 5
6 6 c.Global.extensions = ['IPython.extensions.pretty']
7 7 def dict_pprinter(obj, p, cycle):
8 8 return p.text("<dict>")
9 9 c.PrettyResultDisplay.verbose = True
10 10 c.PrettyResultDisplay.defaults_for_type = [
11 11 (dict, dict_pprinter)
12 12 ]
13 13 c.PrettyResultDisplay.defaults_for_type_by_name = [
14 14 ('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')
15 15 ]
16 16
17 17 This extension can also be loaded by using the ``%load_ext`` magic::
18 18
19 19 %load_ext IPython.extensions.pretty
20 20
21 21 If this extension is enabled, you can always add additional pretty printers
22 22 by doing::
23 23
24 24 ip = get_ipython()
25 25 prd = ip.get_component('pretty_result_display')
26 26 import numpy
27 27 from IPython.extensions.pretty import dtype_pprinter
28 28 prd.for_type(numpy.dtype, dtype_pprinter)
29 29
30 30 # If you don't want to have numpy imported until it needs to be:
31 31 prd.for_type_by_name('numpy', 'dtype', dtype_pprinter)
32 32 """
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Imports
36 36 #-----------------------------------------------------------------------------
37 37
38 38 from IPython.core.error import TryNext
39 39 from IPython.external import pretty
40 40 from IPython.core.component import Component
41 41 from IPython.utils.traitlets import Bool, List
42 42 from IPython.utils.io import Term
43 43 from IPython.utils.autoattr import auto_attr
44 44 from IPython.utils.importstring import import_item
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Code
48 48 #-----------------------------------------------------------------------------
49 49
50 50
51 51 _loaded = False
52 52
53 53
54 54 class PrettyResultDisplay(Component):
55 55 """A component for pretty printing on steroids."""
56 56
57 57 verbose = Bool(False, config=True)
58 58
59 59 # A list of (type, func_name), like
60 60 # [(dict, 'my_dict_printer')]
61 61 # The final argument can also be a callable
62 62 defaults_for_type = List(default_value=[], config=True)
63 63
64 64 # A list of (module_name, type_name, func_name), like
65 65 # [('numpy', 'dtype', 'IPython.extensions.pretty.dtype_pprinter')]
66 66 # The final argument can also be a callable
67 67 defaults_for_type_by_name = List(default_value=[], config=True)
68 68
69 69 def __init__(self, parent, name=None, config=None):
70 70 super(PrettyResultDisplay, self).__init__(parent, name=name, config=config)
71 71 self._setup_defaults()
72 72
73 73 def _setup_defaults(self):
74 74 """Initialize the default pretty printers."""
75 75 for typ, func_name in self.defaults_for_type:
76 76 func = self._resolve_func_name(func_name)
77 77 self.for_type(typ, func)
78 78 for type_module, type_name, func_name in self.defaults_for_type_by_name:
79 79 func = self._resolve_func_name(func_name)
80 80 self.for_type_by_name(type_module, type_name, func)
81 81
82 82 def _resolve_func_name(self, func_name):
83 83 if callable(func_name):
84 84 return func_name
85 85 elif isinstance(func_name, basestring):
86 86 return import_item(func_name)
87 87 else:
88 88 raise TypeError('func_name must be a str or callable, got: %r' % func_name)
89 89
90 90 # Access other components like this rather than by a regular attribute.
91 91 # This won't lookup the InteractiveShell object until it is used and
92 92 # then it is cached. This is both efficient and couples this class
93 93 # more loosely to InteractiveShell.
94 94 @auto_attr
95 95 def shell(self):
96 96 return Component.get_instances(
97 97 root=self.root,
98 98 klass='IPython.core.iplib.InteractiveShell')[0]
99 99
100 100 def __call__(self, otherself, arg):
101 101 """Uber-pretty-printing display hook.
102 102
103 103 Called for displaying the result to the user.
104 104 """
105 105
106 106 if self.shell.pprint:
107 107 out = pretty.pretty(arg, verbose=self.verbose)
108 108 if '\n' in out:
109 109 # So that multi-line strings line up with the left column of
110 110 # the screen, instead of having the output prompt mess up
111 111 # their first line.
112 112 Term.cout.write('\n')
113 113 print >>Term.cout, out
114 114 else:
115 115 raise TryNext
116 116
117 117 def for_type(self, typ, func):
118 118 """Add a pretty printer for a type."""
119 119 return pretty.for_type(typ, func)
120 120
121 121 def for_type_by_name(self, type_module, type_name, func):
122 122 """Add a pretty printer for a type by its name and module name."""
123 123 return pretty.for_type_by_name(type_module, type_name, func)
124 124
125 125
126 126 #-----------------------------------------------------------------------------
127 127 # Initialization code for the extension
128 128 #-----------------------------------------------------------------------------
129 129
130 130
131 def load_ipython_extension(ip=None):
131 def load_ipython_extension(ip):
132 132 """Load the extension in IPython as a hook."""
133 if ip is None: ip = get_ipython()
134 133 global _loaded
135 134 if not _loaded:
136 135 prd = PrettyResultDisplay(ip, name='pretty_result_display')
137 136 ip.set_hook('result_display', prd, priority=99)
138 137 _loaded = True
139 138 return prd
140 139
141 140 def unload_ipython_extension(ip):
142 141 """Unload the extension."""
143 142 # The hook system does not have a way to remove a hook so this is a pass
144 143 pass
145 144
146 145
147 146 #-----------------------------------------------------------------------------
148 147 # Example pretty printers
149 148 #-----------------------------------------------------------------------------
150 149
151 150
152 151 def dtype_pprinter(obj, p, cycle):
153 152 """ A pretty-printer for numpy dtype objects.
154 153 """
155 154 if cycle:
156 155 return p.text('dtype(...)')
157 156 if hasattr(obj, 'fields'):
158 157 if obj.fields is None:
159 158 p.text(repr(obj))
160 159 else:
161 160 p.begin_group(7, 'dtype([')
162 161 for i, field in enumerate(obj.descr):
163 162 if i > 0:
164 163 p.text(',')
165 164 p.breakable()
166 165 p.pretty(field)
167 166 p.end_group(7, '])')
@@ -1,372 +1,373 b''
1 1 """
2 2 Base front end class for all line-oriented frontends, rather than
3 3 block-oriented.
4 4
5 5 Currently this focuses on synchronous frontends.
6 6 """
7 7 __docformat__ = "restructuredtext en"
8 8
9 9 #-------------------------------------------------------------------------------
10 10 # Copyright (C) 2008 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-------------------------------------------------------------------------------
15 15
16 16 #-------------------------------------------------------------------------------
17 17 # Imports
18 18 #-------------------------------------------------------------------------------
19 19 import re
20 20
21 21 import sys
22 22 import codeop
23 23
24 24 from frontendbase import FrontEndBase
25 25 from IPython.kernel.core.interpreter import Interpreter
26 26
27 27 def common_prefix(strings):
28 28 """ Given a list of strings, return the common prefix between all
29 29 these strings.
30 30 """
31 31 ref = strings[0]
32 32 prefix = ''
33 33 for size in range(len(ref)):
34 34 test_prefix = ref[:size+1]
35 35 for string in strings[1:]:
36 36 if not string.startswith(test_prefix):
37 37 return prefix
38 38 prefix = test_prefix
39 39
40 40 return prefix
41 41
42 #-------------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 43 # Base class for the line-oriented front ends
44 #-------------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45 46 class LineFrontEndBase(FrontEndBase):
46 47 """ Concrete implementation of the FrontEndBase class. This is meant
47 48 to be the base class behind all the frontend that are line-oriented,
48 49 rather than block-oriented.
49 50 """
50 51
51 52 # We need to keep the prompt number, to be able to increment
52 53 # it when there is an exception.
53 54 prompt_number = 1
54 55
55 56 # We keep a reference to the last result: it helps testing and
56 57 # programatic control of the frontend.
57 58 last_result = dict(number=0)
58 59
59 60 # The last prompt displayed. Useful for continuation prompts.
60 61 last_prompt = ''
61 62
62 63 # The input buffer being edited
63 64 input_buffer = ''
64 65
65 66 # Set to true for debug output
66 67 debug = False
67 68
68 69 # A banner to print at startup
69 70 banner = None
70 71
71 72 #--------------------------------------------------------------------------
72 73 # FrontEndBase interface
73 74 #--------------------------------------------------------------------------
74 75
75 76 def __init__(self, shell=None, history=None, banner=None, *args, **kwargs):
76 77 if shell is None:
77 78 shell = Interpreter()
78 79 FrontEndBase.__init__(self, shell=shell, history=history)
79 80
80 81 if banner is not None:
81 82 self.banner = banner
82 83
83 84 def start(self):
84 85 """ Put the frontend in a state where it is ready for user
85 86 interaction.
86 87 """
87 88 if self.banner is not None:
88 89 self.write(self.banner, refresh=False)
89 90
90 91 self.new_prompt(self.input_prompt_template.substitute(number=1))
91 92
92 93
93 94 def complete(self, line):
94 95 """Complete line in engine's user_ns
95 96
96 97 Parameters
97 98 ----------
98 99 line : string
99 100
100 101 Returns
101 102 -------
102 103 The replacement for the line and the list of possible completions.
103 104 """
104 105 completions = self.shell.complete(line)
105 106 complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
106 107 if completions:
107 108 prefix = common_prefix(completions)
108 109 residual = complete_sep.split(line)[:-1]
109 110 line = line[:-len(residual)] + prefix
110 111 return line, completions
111 112
112 113
113 114 def render_result(self, result):
114 115 """ Frontend-specific rendering of the result of a calculation
115 116 that has been sent to an engine.
116 117 """
117 118 if 'stdout' in result and result['stdout']:
118 119 self.write('\n' + result['stdout'])
119 120 if 'display' in result and result['display']:
120 121 self.write("%s%s\n" % (
121 122 self.output_prompt_template.substitute(
122 123 number=result['number']),
123 124 result['display']['pprint']
124 125 ) )
125 126
126 127
127 128 def render_error(self, failure):
128 129 """ Frontend-specific rendering of error.
129 130 """
130 131 self.write('\n\n'+str(failure)+'\n\n')
131 132 return failure
132 133
133 134
134 135 def is_complete(self, string):
135 136 """ Check if a string forms a complete, executable set of
136 137 commands.
137 138
138 139 For the line-oriented frontend, multi-line code is not executed
139 140 as soon as it is complete: the users has to enter two line
140 141 returns.
141 142 """
142 143 if string in ('', '\n'):
143 144 # Prefiltering, eg through ipython0, may return an empty
144 145 # string although some operations have been accomplished. We
145 146 # thus want to consider an empty string as a complete
146 147 # statement.
147 148 return True
148 149 elif ( len(self.input_buffer.split('\n'))>2
149 150 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
150 151 return False
151 152 else:
152 153 self.capture_output()
153 154 try:
154 155 # Add line returns here, to make sure that the statement is
155 156 # complete (except if '\' was used).
156 157 # This should probably be done in a different place (like
157 158 # maybe 'prefilter_input' method? For now, this works.
158 159 clean_string = string.rstrip('\n')
159 160 if not clean_string.endswith('\\'): clean_string +='\n\n'
160 161 is_complete = codeop.compile_command(clean_string,
161 162 "<string>", "exec")
162 163 self.release_output()
163 164 except Exception, e:
164 165 # XXX: Hack: return True so that the
165 166 # code gets executed and the error captured.
166 167 is_complete = True
167 168 return is_complete
168 169
169 170
170 171 def write(self, string, refresh=True):
171 172 """ Write some characters to the display.
172 173
173 174 Subclass should overide this method.
174 175
175 176 The refresh keyword argument is used in frontends with an
176 177 event loop, to choose whether the write should trigget an UI
177 178 refresh, and thus be syncrhonous, or not.
178 179 """
179 180 print >>sys.__stderr__, string
180 181
181 182
182 183 def execute(self, python_string, raw_string=None):
183 184 """ Stores the raw_string in the history, and sends the
184 185 python string to the interpreter.
185 186 """
186 187 if raw_string is None:
187 188 raw_string = python_string
188 189 # Create a false result, in case there is an exception
189 190 self.last_result = dict(number=self.prompt_number)
190 191
191 192 try:
192 193 try:
193 194 self.history.input_cache[-1] = raw_string.rstrip()
194 195 result = self.shell.execute(python_string)
195 196 self.last_result = result
196 197 self.render_result(result)
197 198 except:
198 199 self.show_traceback()
199 200 finally:
200 201 self.after_execute()
201 202
202 203
203 204 #--------------------------------------------------------------------------
204 205 # LineFrontEndBase interface
205 206 #--------------------------------------------------------------------------
206 207
207 208 def prefilter_input(self, string):
208 209 """ Prefilter the input to turn it in valid python.
209 210 """
210 211 string = string.replace('\r\n', '\n')
211 212 string = string.replace('\t', 4*' ')
212 213 # Clean the trailing whitespace
213 214 string = '\n'.join(l.rstrip() for l in string.split('\n'))
214 215 return string
215 216
216 217
217 218 def after_execute(self):
218 219 """ All the operations required after an execution to put the
219 220 terminal back in a shape where it is usable.
220 221 """
221 222 self.prompt_number += 1
222 223 self.new_prompt(self.input_prompt_template.substitute(
223 224 number=(self.last_result['number'] + 1)))
224 225 # Start a new empty history entry
225 226 self._add_history(None, '')
226 227 self.history_cursor = len(self.history.input_cache) - 1
227 228
228 229
229 230 def complete_current_input(self):
230 231 """ Do code completion on current line.
231 232 """
232 233 if self.debug:
233 234 print >>sys.__stdout__, "complete_current_input",
234 235 line = self.input_buffer
235 236 new_line, completions = self.complete(line)
236 237 if len(completions)>1:
237 238 self.write_completion(completions, new_line=new_line)
238 239 elif not line == new_line:
239 240 self.input_buffer = new_line
240 241 if self.debug:
241 242 print >>sys.__stdout__, 'line', line
242 243 print >>sys.__stdout__, 'new_line', new_line
243 244 print >>sys.__stdout__, completions
244 245
245 246
246 247 def get_line_width(self):
247 248 """ Return the width of the line in characters.
248 249 """
249 250 return 80
250 251
251 252
252 253 def write_completion(self, possibilities, new_line=None):
253 254 """ Write the list of possible completions.
254 255
255 256 new_line is the completed input line that should be displayed
256 257 after the completion are writen. If None, the input_buffer
257 258 before the completion is used.
258 259 """
259 260 if new_line is None:
260 261 new_line = self.input_buffer
261 262
262 263 self.write('\n')
263 264 max_len = len(max(possibilities, key=len)) + 1
264 265
265 266 # Now we check how much symbol we can put on a line...
266 267 chars_per_line = self.get_line_width()
267 268 symbols_per_line = max(1, chars_per_line/max_len)
268 269
269 270 pos = 1
270 271 completion_string = []
271 272 for symbol in possibilities:
272 273 if pos < symbols_per_line:
273 274 completion_string.append(symbol.ljust(max_len))
274 275 pos += 1
275 276 else:
276 277 completion_string.append(symbol.rstrip() + '\n')
277 278 pos = 1
278 279 self.write(''.join(completion_string))
279 280 self.new_prompt(self.input_prompt_template.substitute(
280 281 number=self.last_result['number'] + 1))
281 282 self.input_buffer = new_line
282 283
283 284
284 285 def new_prompt(self, prompt):
285 286 """ Prints a prompt and starts a new editing buffer.
286 287
287 288 Subclasses should use this method to make sure that the
288 289 terminal is put in a state favorable for a new line
289 290 input.
290 291 """
291 292 self.input_buffer = ''
292 293 self.write(prompt)
293 294
294 295
295 296 def continuation_prompt(self):
296 297 """Returns the current continuation prompt.
297 298 """
298 299 return ("."*(len(self.last_prompt)-2) + ': ')
299 300
300 301
301 302 def execute_command(self, command, hidden=False):
302 303 """ Execute a command, not only in the model, but also in the
303 304 view, if any.
304 305 """
305 306 return self.shell.execute(command)
306 307
307 308 #--------------------------------------------------------------------------
308 309 # Private API
309 310 #--------------------------------------------------------------------------
310 311
311 312 def _on_enter(self, new_line_pos=0):
312 313 """ Called when the return key is pressed in a line editing
313 314 buffer.
314 315
315 316 Parameters
316 317 ----------
317 318 new_line_pos : integer, optional
318 319 Position of the new line to add, starting from the
319 320 end (0 adds a new line after the last line, -1 before
320 321 the last line...)
321 322
322 323 Returns
323 324 -------
324 325 True if execution is triggered
325 326 """
326 327 current_buffer = self.input_buffer
327 328 # XXX: This string replace is ugly, but there should be no way it
328 329 # fails.
329 330 prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
330 331 '', current_buffer).replace('\n' + self.continuation_prompt(),
331 332 '\n')
332 333 cleaned_buffer = self.prefilter_input(prompt_less_buffer)
333 334 if self.is_complete(cleaned_buffer):
334 335 self.execute(cleaned_buffer, raw_string=current_buffer)
335 336 return True
336 337 else:
337 338 # Start a new line.
338 339 new_line_pos = -new_line_pos
339 340 lines = current_buffer.split('\n')[:-1]
340 341 prompt_less_lines = prompt_less_buffer.split('\n')
341 342 # Create the new line, with the continuation prompt, and the
342 343 # same amount of indent than the line above it.
343 344 new_line = self.continuation_prompt() + \
344 345 self._get_indent_string('\n'.join(
345 346 prompt_less_lines[:new_line_pos-1]))
346 347 if len(lines) == 1:
347 348 # We are starting a first continuation line. Indent it.
348 349 new_line += '\t'
349 350 elif current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
350 351 # The last line ends with ":", autoindent the new line.
351 352 new_line += '\t'
352 353
353 354 if new_line_pos == 0:
354 355 lines.append(new_line)
355 356 else:
356 357 lines.insert(new_line_pos, new_line)
357 358 self.input_buffer = '\n'.join(lines)
358 359
359 360
360 361 def _get_indent_string(self, string):
361 362 """ Return the string of whitespace that prefixes a line. Used to
362 363 add the right amount of indendation when creating a new line.
363 364 """
364 365 string = string.replace('\t', ' '*4)
365 366 string = string.split('\n')[-1]
366 367 indent_chars = len(string) - len(string.lstrip())
367 368 indent_string = '\t'*(indent_chars // 4) + \
368 369 ' '*(indent_chars % 4)
369 370
370 371 return indent_string
371 372
372 373
@@ -1,264 +1,256 b''
1 1 """
2 2 Frontend class that uses IPython0 to prefilter the inputs.
3 3
4 4 Using the IPython0 mechanism gives us access to the magics.
5 5
6 6 This is a transitory class, used here to do the transition between
7 7 ipython0 and ipython1. This class is meant to be short-lived as more
8 8 functionnality is abstracted out of ipython0 in reusable functions and
9 9 is added on the interpreter. This class can be a used to guide this
10 10 refactoring.
11 11 """
12 12
13 13 #-------------------------------------------------------------------------------
14 14 # Copyright (C) 2008 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-------------------------------------------------------------------------------
19 19
20 20 #-------------------------------------------------------------------------------
21 21 # Imports
22 22 #-------------------------------------------------------------------------------
23 23 import sys
24 24 import pydoc
25 25 import os
26 26 import re
27 27 import __builtin__
28 28
29 from IPython.core.ipapp import IPythonApp
29 from IPython.core.iplib import InteractiveShell
30 30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
31 31
32 32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
33 33
34 34 from IPython.utils.io import Term
35 35
36 36 from linefrontendbase import LineFrontEndBase, common_prefix
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Utility functions
40 40 #-----------------------------------------------------------------------------
41 41
42 42 def mk_system_call(system_call_function, command):
43 43 """ given a os.system replacement, and a leading string command,
44 44 returns a function that will execute the command with the given
45 45 argument string.
46 46 """
47 47 def my_system_call(args):
48 48 system_call_function("%s %s" % (command, args))
49 49
50 50 my_system_call.__doc__ = "Calls %s" % command
51 51 return my_system_call
52 52
53 #-------------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 54 # Frontend class using ipython0 to do the prefiltering.
55 #-------------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56 57 class PrefilterFrontEnd(LineFrontEndBase):
57 58 """ Class that uses ipython0 to do prefilter the input, do the
58 59 completion and the magics.
59 60
60 61 The core trick is to use an ipython0 instance to prefilter the
61 62 input, and share the namespace between the interpreter instance used
62 63 to execute the statements and the ipython0 used for code
63 64 completion...
64 65 """
65 66
66 67 debug = False
67 68
68 def __init__(self, ipython0=None, argv=None, *args, **kwargs):
69 def __init__(self, ipython0=None, *args, **kwargs):
69 70 """ Parameters
70 71 ----------
71 72
72 73 ipython0: an optional ipython0 instance to use for command
73 74 prefiltering and completion.
74
75 argv : list, optional
76 Used as the instance's argv value. If not given, [] is used.
77 75 """
78 if argv is None:
79 argv = ['--no-banner']
80
81 76 LineFrontEndBase.__init__(self, *args, **kwargs)
82 77 self.shell.output_trap = RedirectorOutputTrap(
83 78 out_callback=self.write,
84 79 err_callback=self.write,
85 80 )
86 81 self.shell.traceback_trap = SyncTracebackTrap(
87 82 formatters=self.shell.traceback_trap.formatters,
88 83 )
89 84
90 85 # Start the ipython0 instance:
91 86 self.save_output_hooks()
92 87 if ipython0 is None:
93 # Instanciate an IPython0 interpreter to be able to use the
88 # Instanciate an IPython0 InteractiveShell to be able to use the
94 89 # prefiltering.
95 90 # Suppress all key input, to avoid waiting
96 91 def my_rawinput(x=None):
97 92 return '\n'
98 93 old_rawinput = __builtin__.raw_input
99 94 __builtin__.raw_input = my_rawinput
100 ipython0 = IPythonApp(argv=argv,
101 user_ns=self.shell.user_ns,
102 user_global_ns=self.shell.user_global_ns)
103 ipython0.initialize()
95 ipython0 = InteractiveShell(
96 parent=None, user_ns=self.shell.user_ns,
97 user_global_ns=self.shell.user_global_ns
98 )
104 99 __builtin__.raw_input = old_rawinput
105 # XXX This will need to be updated as we refactor things, but for now,
106 # the .shell attribute of the ipythonapp instance conforms to the old
107 # api.
108 self.ipython0 = ipython0.shell
100 self.ipython0 = ipython0
109 101 # Set the pager:
110 102 self.ipython0.set_hook('show_in_pager',
111 103 lambda s, string: self.write("\n" + string))
112 104 self.ipython0.write = self.write
113 105 self._ip = _ip = self.ipython0
114 106 # Make sure the raw system call doesn't get called, as we don't
115 107 # have a stdin accessible.
116 108 self._ip.system = self.system_call
117 109 # XXX: Muck around with magics so that they work better
118 110 # in our environment
119 111 if not sys.platform.startswith('win'):
120 112 self.ipython0.magic_ls = mk_system_call(self.system_call,
121 113 'ls -CF')
122 114 # And now clean up the mess created by ipython0
123 115 self.release_output()
124 116
125 117
126 118 if not 'banner' in kwargs and self.banner is None:
127 119 self.banner = self.ipython0.banner
128 120
129 121 # FIXME: __init__ and start should be two different steps
130 122 self.start()
131 123
132 124 #--------------------------------------------------------------------------
133 125 # FrontEndBase interface
134 126 #--------------------------------------------------------------------------
135 127
136 128 def show_traceback(self):
137 129 """ Use ipython0 to capture the last traceback and display it.
138 130 """
139 131 # Don't do the capture; the except_hook has already done some
140 132 # modifications to the IO streams, if we store them, we'll be
141 133 # storing the wrong ones.
142 134 #self.capture_output()
143 135 self.ipython0.showtraceback(tb_offset=-1)
144 136 self.release_output()
145 137
146 138
147 139 def execute(self, python_string, raw_string=None):
148 140 if self.debug:
149 141 print 'Executing Python code:', repr(python_string)
150 142 self.capture_output()
151 143 LineFrontEndBase.execute(self, python_string,
152 144 raw_string=raw_string)
153 145 self.release_output()
154 146
155 147
156 148 def save_output_hooks(self):
157 149 """ Store all the output hooks we can think of, to be able to
158 150 restore them.
159 151
160 152 We need to do this early, as starting the ipython0 instance will
161 153 screw ouput hooks.
162 154 """
163 155 self.__old_cout_write = Term.cout.write
164 156 self.__old_cerr_write = Term.cerr.write
165 157 self.__old_stdout = sys.stdout
166 158 self.__old_stderr= sys.stderr
167 159 self.__old_help_output = pydoc.help.output
168 160 self.__old_display_hook = sys.displayhook
169 161
170 162
171 163 def capture_output(self):
172 164 """ Capture all the output mechanisms we can think of.
173 165 """
174 166 self.save_output_hooks()
175 167 Term.cout.write = self.write
176 168 Term.cerr.write = self.write
177 169 sys.stdout = Term.cout
178 170 sys.stderr = Term.cerr
179 171 pydoc.help.output = self.shell.output_trap.out
180 172
181 173
182 174 def release_output(self):
183 175 """ Release all the different captures we have made.
184 176 """
185 177 Term.cout.write = self.__old_cout_write
186 178 Term.cerr.write = self.__old_cerr_write
187 179 sys.stdout = self.__old_stdout
188 180 sys.stderr = self.__old_stderr
189 181 pydoc.help.output = self.__old_help_output
190 182 sys.displayhook = self.__old_display_hook
191 183
192 184
193 185 def complete(self, line):
194 186 # FIXME: This should be factored out in the linefrontendbase
195 187 # method.
196 188 word = self._get_completion_text(line)
197 189 completions = self.ipython0.complete(word)
198 190 # FIXME: The proper sort should be done in the complete method.
199 191 key = lambda x: x.replace('_', '')
200 192 completions.sort(key=key)
201 193 if completions:
202 194 prefix = common_prefix(completions)
203 195 line = line[:-len(word)] + prefix
204 196 return line, completions
205 197
206 198 #--------------------------------------------------------------------------
207 199 # LineFrontEndBase interface
208 200 #--------------------------------------------------------------------------
209 201
210 202 def prefilter_input(self, input_string):
211 203 """ Using IPython0 to prefilter the commands to turn them
212 204 in executable statements that are valid Python strings.
213 205 """
214 206 input_string = LineFrontEndBase.prefilter_input(self, input_string)
215 207 filtered_lines = []
216 208 # The IPython0 prefilters sometime produce output. We need to
217 209 # capture it.
218 210 self.capture_output()
219 211 self.last_result = dict(number=self.prompt_number)
220 212
221 213 try:
222 214 try:
223 215 for line in input_string.split('\n'):
224 216 pf = self.ipython0.prefilter_manager.prefilter_lines
225 217 filtered_lines.append(pf(line, False).rstrip())
226 218 except:
227 219 # XXX: probably not the right thing to do.
228 220 self.ipython0.showsyntaxerror()
229 221 self.after_execute()
230 222 finally:
231 223 self.release_output()
232 224
233 225 # Clean up the trailing whitespace, to avoid indentation errors
234 226 filtered_string = '\n'.join(filtered_lines)
235 227 return filtered_string
236 228
237 229 #--------------------------------------------------------------------------
238 230 # PrefilterFrontEnd interface
239 231 #--------------------------------------------------------------------------
240 232
241 233 def system_call(self, command_string):
242 234 """ Allows for frontend to define their own system call, to be
243 235 able capture output and redirect input.
244 236 """
245 237 return os.system(command_string)
246 238
247 239 def do_exit(self):
248 240 """ Exit the shell, cleanup and save the history.
249 241 """
250 242 self.ipython0.atexit_operations()
251 243
252 244 def _get_completion_text(self, line):
253 245 """ Returns the text to be completed by breaking the line at specified
254 246 delimiters.
255 247 """
256 248 # Break at: spaces, '=', all parentheses (except if balanced).
257 249 # FIXME2: In the future, we need to make the implementation similar to
258 250 # that in the 'pyreadline' module (modes/basemode.py) where we break at
259 251 # each delimiter and try to complete the residual line, until we get a
260 252 # successful list of completions.
261 253 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
262 254 complete_sep = re.compile(expression)
263 255 text = complete_sep.split(line)[-1]
264 256 return text
@@ -1,112 +1,109 b''
1 1 # encoding: utf-8
2
3 2 """This file contains unittests for the asyncfrontendbase module."""
4
5 __docformat__ = "restructuredtext en"
6 3
7 4 # Tell nose to skip this module
8 5 __test__ = {}
9 6
10 7 #---------------------------------------------------------------------------
11 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008-2009 The IPython Development Team
12 9 #
13 10 # Distributed under the terms of the BSD License. The full license is in
14 11 # the file COPYING, distributed as part of this software.
15 12 #---------------------------------------------------------------------------
16 13
17 14 #---------------------------------------------------------------------------
18 15 # Imports
19 16 #---------------------------------------------------------------------------
20 17
21 18 from twisted.trial import unittest
22 19
23 20 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
24 21 from IPython.frontend import frontendbase
25 22 from IPython.kernel.engineservice import EngineService
26 23 from IPython.testing.parametric import Parametric, parametric
27 24
28 25 #-----------------------------------------------------------------------------
29 26 # Classes and functions
30 27 #-----------------------------------------------------------------------------
31 28
32 29 class FrontEndCallbackChecker(AsyncFrontEndBase):
33 30 """FrontEndBase subclass for checking callbacks"""
34 31 def __init__(self, engine=None, history=None):
35 32 super(FrontEndCallbackChecker, self).__init__(engine=engine,
36 33 history=history)
37 34 self.updateCalled = False
38 35 self.renderResultCalled = False
39 36 self.renderErrorCalled = False
40 37
41 38 def update_cell_prompt(self, result, blockID=None):
42 39 self.updateCalled = True
43 40 return result
44 41
45 42 def render_result(self, result):
46 43 self.renderResultCalled = True
47 44 return result
48 45
49 46 def render_error(self, failure):
50 47 self.renderErrorCalled = True
51 48 return failure
52 49
53 50
54 51 class TestAsyncFrontendBase(unittest.TestCase):
55 52 def setUp(self):
56 53 """Setup the EngineService and FrontEndBase"""
57 54
58 55 self.fb = FrontEndCallbackChecker(engine=EngineService())
59 56
60 57 def test_implements_IFrontEnd(self):
61 58 self.assert_(frontendbase.IFrontEnd.implementedBy(
62 59 AsyncFrontEndBase))
63 60
64 61 def test_is_complete_returns_False_for_incomplete_block(self):
65 62 block = """def test(a):"""
66 63 self.assert_(self.fb.is_complete(block) == False)
67 64
68 65 def test_is_complete_returns_True_for_complete_block(self):
69 66 block = """def test(a): pass"""
70 67 self.assert_(self.fb.is_complete(block))
71 68 block = """a=3"""
72 69 self.assert_(self.fb.is_complete(block))
73 70
74 71 def test_blockID_added_to_result(self):
75 72 block = """3+3"""
76 73 d = self.fb.execute(block, blockID='TEST_ID')
77 74 d.addCallback(lambda r: self.assert_(r['blockID']=='TEST_ID'))
78 75 return d
79 76
80 77 def test_blockID_added_to_failure(self):
81 78 block = "raise Exception()"
82 79 d = self.fb.execute(block,blockID='TEST_ID')
83 80 d.addErrback(lambda f: self.assert_(f.blockID=='TEST_ID'))
84 81 return d
85 82
86 83 def test_callbacks_added_to_execute(self):
87 84 d = self.fb.execute("10+10")
88 85 d.addCallback(lambda r: self.assert_(self.fb.updateCalled and self.fb.renderResultCalled))
89 86 return d
90 87
91 88 def test_error_callback_added_to_execute(self):
92 89 """Test that render_error called on execution error."""
93 90
94 91 d = self.fb.execute("raise Exception()")
95 92 d.addErrback(lambda f: self.assert_(self.fb.renderErrorCalled))
96 93 return d
97 94
98 95 def test_history_returns_expected_block(self):
99 96 """Make sure history browsing doesn't fail."""
100 97
101 98 blocks = ["a=1","a=2","a=3"]
102 99 d = self.fb.execute(blocks[0])
103 100 d.addCallback(lambda _: self.fb.execute(blocks[1]))
104 101 d.addCallback(lambda _: self.fb.execute(blocks[2]))
105 102 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-2]))
106 103 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-3]))
107 104 d.addCallback(lambda _: self.assert_(self.fb.get_history_next()==blocks[-2]))
108 105 return d
109 106
110 107 def test_history_returns_none_at_startup(self):
111 108 self.assert_(self.fb.get_history_previous("")==None)
112 109 self.assert_(self.fb.get_history_next()==None)
@@ -1,269 +1,268 b''
1 1 # encoding: utf-8
2 2 """
3 3 Test process execution and IO redirection.
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 9 # Copyright (C) 2008 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is
12 12 # in the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 from copy import copy, deepcopy
16 16 from cStringIO import StringIO
17 17 import string
18 18 import sys
19 19
20 20 from nose.tools import assert_equal
21 21
22 22 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
23 23 from IPython.testing.globalipapp import get_ipython
24 from IPython.testing.tools import default_argv
25 24
26 25 #-----------------------------------------------------------------------------
27 26 # Support utilities
28 27 #-----------------------------------------------------------------------------
29 28
30 29 class TestPrefilterFrontEnd(PrefilterFrontEnd):
31 30
32 31 input_prompt_template = string.Template('')
33 32 output_prompt_template = string.Template('')
34 33 banner = ''
35 34
36 35 def __init__(self):
37 36 self.out = StringIO()
38 PrefilterFrontEnd.__init__(self,argv=default_argv())
37 PrefilterFrontEnd.__init__(self)
39 38 # Some more code for isolation (yeah, crazy)
40 39 self._on_enter()
41 40 self.out.flush()
42 41 self.out.reset()
43 42 self.out.truncate()
44 43
45 44 def write(self, string, *args, **kwargs):
46 45 self.out.write(string)
47 46
48 47 def _on_enter(self):
49 48 self.input_buffer += '\n'
50 49 PrefilterFrontEnd._on_enter(self)
51 50
52 51
53 52 def isolate_ipython0(func):
54 53 """ Decorator to isolate execution that involves an iptyhon0.
55 54
56 55 Notes
57 56 -----
58 57
59 58 Apply only to functions with no arguments. Nose skips functions
60 59 with arguments.
61 60 """
62 61 def my_func():
63 62 ip0 = get_ipython()
64 63 if ip0 is None:
65 64 return func()
66 65 # We have a real ipython running...
67 66 user_ns = ip0.user_ns
68 67 user_global_ns = ip0.user_global_ns
69 68
70 69 # Previously the isolation was attempted with a deep copy of the user
71 70 # dicts, but we found cases where this didn't work correctly. I'm not
72 71 # quite sure why, but basically it did damage the user namespace, such
73 72 # that later tests stopped working correctly. Instead we use a simpler
74 73 # approach, just computing the list of added keys to the namespace and
75 74 # eliminating those afterwards. Existing keys that may have been
76 75 # modified remain modified. So far this has proven to be robust.
77 76
78 77 # Compute set of old local/global keys
79 78 old_locals = set(user_ns.keys())
80 79 old_globals = set(user_global_ns.keys())
81 80 try:
82 81 out = func()
83 82 finally:
84 83 # Find new keys, and if any, remove them
85 84 new_locals = set(user_ns.keys()) - old_locals
86 85 new_globals = set(user_global_ns.keys()) - old_globals
87 86 for k in new_locals:
88 87 del user_ns[k]
89 88 for k in new_globals:
90 89 del user_global_ns[k]
91 90 return out
92 91
93 92 my_func.__name__ = func.__name__
94 93 return my_func
95 94
96 95 #-----------------------------------------------------------------------------
97 96 # Tests
98 97 #-----------------------------------------------------------------------------
99 98
100 99 @isolate_ipython0
101 100 def test_execution():
102 101 """ Test execution of a command.
103 102 """
104 103 f = TestPrefilterFrontEnd()
105 104 f.input_buffer = 'print(1)'
106 105 f._on_enter()
107 106 out_value = f.out.getvalue()
108 107 assert_equal(out_value, '1\n')
109 108
110 109
111 110 @isolate_ipython0
112 111 def test_multiline():
113 112 """ Test execution of a multiline command.
114 113 """
115 114 f = TestPrefilterFrontEnd()
116 115 f.input_buffer = 'if True:'
117 116 f._on_enter()
118 117 f.input_buffer += 'print 1'
119 118 f._on_enter()
120 119 out_value = f.out.getvalue()
121 120 yield assert_equal, out_value, ''
122 121 f._on_enter()
123 122 out_value = f.out.getvalue()
124 123 yield assert_equal, out_value, '1\n'
125 124 f = TestPrefilterFrontEnd()
126 125 f.input_buffer='(1 +'
127 126 f._on_enter()
128 127 f.input_buffer += '0)'
129 128 f._on_enter()
130 129 out_value = f.out.getvalue()
131 130 yield assert_equal, out_value, ''
132 131 f._on_enter()
133 132 out_value = f.out.getvalue()
134 133 yield assert_equal, out_value, '1\n'
135 134
136 135
137 136 @isolate_ipython0
138 137 def test_capture():
139 138 """ Test the capture of output in different channels.
140 139 """
141 140 # Test on the OS-level stdout, stderr.
142 141 f = TestPrefilterFrontEnd()
143 142 f.input_buffer = \
144 143 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
145 144 f._on_enter()
146 145 out_value = f.out.getvalue()
147 146 yield assert_equal, out_value, '1'
148 147 f = TestPrefilterFrontEnd()
149 148 f.input_buffer = \
150 149 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
151 150 f._on_enter()
152 151 out_value = f.out.getvalue()
153 152 yield assert_equal, out_value, '1'
154 153
155 154
156 155 @isolate_ipython0
157 156 def test_magic():
158 157 """ Test the magic expansion and history.
159 158
160 159 This test is fairly fragile and will break when magics change.
161 160 """
162 161 f = TestPrefilterFrontEnd()
163 162 # Before checking the interactive namespace, make sure it's clear (it can
164 163 # otherwise pick up things stored in the user's local db)
165 164 f.input_buffer += '%reset -f'
166 165 f._on_enter()
167 166 f.complete_current_input()
168 167 # Now, run the %who magic and check output
169 168 f.input_buffer += '%who'
170 169 f._on_enter()
171 170 out_value = f.out.getvalue()
172 171 assert_equal(out_value, 'Interactive namespace is empty.\n')
173 172
174 173
175 174 @isolate_ipython0
176 175 def test_help():
177 176 """ Test object inspection.
178 177 """
179 178 f = TestPrefilterFrontEnd()
180 179 f.input_buffer += "def f():"
181 180 f._on_enter()
182 181 f.input_buffer += "'foobar'"
183 182 f._on_enter()
184 183 f.input_buffer += "pass"
185 184 f._on_enter()
186 185 f._on_enter()
187 186 f.input_buffer += "f?"
188 187 f._on_enter()
189 188 assert 'traceback' not in f.last_result
190 189 ## XXX: ipython doctest magic breaks this. I have no clue why
191 190 #out_value = f.out.getvalue()
192 191 #assert out_value.split()[-1] == 'foobar'
193 192
194 193
195 194 @isolate_ipython0
196 195 def test_completion_simple():
197 196 """ Test command-line completion on trivial examples.
198 197 """
199 198 f = TestPrefilterFrontEnd()
200 199 f.input_buffer = 'zzza = 1'
201 200 f._on_enter()
202 201 f.input_buffer = 'zzzb = 2'
203 202 f._on_enter()
204 203 f.input_buffer = 'zz'
205 204 f.complete_current_input()
206 205 out_value = f.out.getvalue()
207 206 yield assert_equal, out_value, '\nzzza zzzb '
208 207 yield assert_equal, f.input_buffer, 'zzz'
209 208
210 209
211 210 @isolate_ipython0
212 211 def test_completion_parenthesis():
213 212 """ Test command-line completion when a parenthesis is open.
214 213 """
215 214 f = TestPrefilterFrontEnd()
216 215 f.input_buffer = 'zzza = 1'
217 216 f._on_enter()
218 217 f.input_buffer = 'zzzb = 2'
219 218 f._on_enter()
220 219 f.input_buffer = 'map(zz'
221 220 f.complete_current_input()
222 221 out_value = f.out.getvalue()
223 222 yield assert_equal, out_value, '\nzzza zzzb '
224 223 yield assert_equal, f.input_buffer, 'map(zzz'
225 224
226 225
227 226 @isolate_ipython0
228 227 def test_completion_indexing():
229 228 """ Test command-line completion when indexing on objects.
230 229 """
231 230 f = TestPrefilterFrontEnd()
232 231 f.input_buffer = 'a = [0]'
233 232 f._on_enter()
234 233 f.input_buffer = 'a[0].'
235 234 f.complete_current_input()
236 235
237 236 if sys.version_info[:2] >= (2,6):
238 237 # In Python 2.6, ints picked up a few non __ methods, so now there are
239 238 # no completions.
240 239 assert_equal(f.input_buffer, 'a[0].')
241 240 else:
242 241 # Right answer for 2.4/2.5
243 242 assert_equal(f.input_buffer, 'a[0].__')
244 243
245 244
246 245 @isolate_ipython0
247 246 def test_completion_equal():
248 247 """ Test command-line completion when the delimiter is "=", not " ".
249 248 """
250 249 f = TestPrefilterFrontEnd()
251 250 f.input_buffer = 'a=1.'
252 251 f.complete_current_input()
253 252 if sys.version_info[:2] >= (2,6):
254 253 # In Python 2.6, ints picked up a few non __ methods, so now there are
255 254 # no completions.
256 255 assert_equal(f.input_buffer, 'a=1.')
257 256 else:
258 257 # Right answer for 2.4/2.5
259 258 assert_equal(f.input_buffer, 'a=1.__')
260 259
261 260
262 261 if __name__ == '__main__':
263 262 test_magic()
264 263 test_help()
265 264 test_execution()
266 265 test_multiline()
267 266 test_capture()
268 267 test_completion_simple()
269 268 test_completion_complex()
@@ -1,624 +1,625 b''
1 1 # encoding: utf-8
2 2 """
3 3 A Wx widget to act as a console and input commands.
4 4
5 5 This widget deals with prompts and provides an edit buffer
6 6 restricted to after the last prompt.
7 7 """
8 8
9 9 __docformat__ = "restructuredtext en"
10 10
11 11 #-------------------------------------------------------------------------------
12 12 # Copyright (C) 2008 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is
15 15 # in the file COPYING, distributed as part of this software.
16 16 #-------------------------------------------------------------------------------
17 17
18 18 #-------------------------------------------------------------------------------
19 19 # Imports
20 20 #-------------------------------------------------------------------------------
21 21
22 22 import wx
23 23 import wx.stc as stc
24 24
25 25 from wx.py import editwindow
26 26 import time
27 27 import sys
28 28 import string
29 29
30 30 LINESEP = '\n'
31 31 if sys.platform == 'win32':
32 32 LINESEP = '\n\r'
33 33
34 34 import re
35 35
36 36 # FIXME: Need to provide an API for non user-generated display on the
37 37 # screen: this should not be editable by the user.
38 38 #-------------------------------------------------------------------------------
39 39 # Constants
40 40 #-------------------------------------------------------------------------------
41 41 _COMPLETE_BUFFER_MARKER = 31
42 42 _ERROR_MARKER = 30
43 43 _INPUT_MARKER = 29
44 44
45 45 _DEFAULT_SIZE = 10
46 46 if sys.platform == 'darwin':
47 47 _DEFAULT_SIZE = 12
48 48
49 49 _DEFAULT_STYLE = {
50 50 #background definition
51 51 'default' : 'size:%d' % _DEFAULT_SIZE,
52 52 'bracegood' : 'fore:#00AA00,back:#000000,bold',
53 53 'bracebad' : 'fore:#FF0000,back:#000000,bold',
54 54
55 55 # Edge column: a number of None
56 56 'edge_column' : -1,
57 57
58 58 # properties for the various Python lexer styles
59 59 'comment' : 'fore:#007F00',
60 60 'number' : 'fore:#007F7F',
61 61 'string' : 'fore:#7F007F,italic',
62 62 'char' : 'fore:#7F007F,italic',
63 63 'keyword' : 'fore:#00007F,bold',
64 64 'triple' : 'fore:#7F0000',
65 65 'tripledouble' : 'fore:#7F0000',
66 66 'class' : 'fore:#0000FF,bold,underline',
67 67 'def' : 'fore:#007F7F,bold',
68 68 'operator' : 'bold',
69 69
70 70 # Default colors
71 71 'trace' : '#FAFAF1', # Nice green
72 72 'stdout' : '#FDFFD3', # Nice yellow
73 73 'stderr' : '#FFF1F1', # Nice red
74 74
75 75 # Default scintilla settings
76 76 'antialiasing' : True,
77 77 'carret_color' : 'BLACK',
78 78 'background_color' :'WHITE',
79 79
80 80 #prompt definition
81 81 'prompt_in1' : \
82 82 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02',
83 83
84 84 'prompt_out': \
85 85 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02',
86 86 }
87 87
88 88 # new style numbers
89 89 _STDOUT_STYLE = 15
90 90 _STDERR_STYLE = 16
91 91 _TRACE_STYLE = 17
92 92
93 93
94 94 # system colors
95 95 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
96 96
97 97 # Translation table from ANSI escape sequences to color.
98 98 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
99 99 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
100 100 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
101 101 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
102 102 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
103 103 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
104 104 '1;34': [12, 'LIGHT BLUE'], '1;35':
105 105 [13, 'MEDIUM VIOLET RED'],
106 106 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
107 107
108 108 # XXX: Maybe one day we should factor this code with coloransi. Right now
109 109 # coloransi is hard to reuse and makes our code more complex.
110 110
111 111 #we define platform specific fonts
112 112 if wx.Platform == '__WXMSW__':
113 113 FACES = { 'times': 'Times New Roman',
114 114 'mono' : 'Courier New',
115 115 'helv' : 'Arial',
116 116 'other': 'Comic Sans MS',
117 117 'size' : 10,
118 118 'size2': 8,
119 119 }
120 120 elif wx.Platform == '__WXMAC__':
121 121 FACES = { 'times': 'Times New Roman',
122 122 'mono' : 'Monaco',
123 123 'helv' : 'Arial',
124 124 'other': 'Comic Sans MS',
125 125 'size' : 10,
126 126 'size2': 8,
127 127 }
128 128 else:
129 129 FACES = { 'times': 'Times',
130 130 'mono' : 'Courier',
131 131 'helv' : 'Helvetica',
132 132 'other': 'new century schoolbook',
133 133 'size' : 10,
134 134 'size2': 8,
135 135 }
136 136
137 137
138 #-------------------------------------------------------------------------------
138 #-----------------------------------------------------------------------------
139 139 # The console widget class
140 #-------------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
141
141 142 class ConsoleWidget(editwindow.EditWindow):
142 143 """ Specialized styled text control view for console-like workflow.
143 144
144 145 This widget is mainly interested in dealing with the prompt and
145 146 keeping the cursor inside the editing line.
146 147 """
147 148
148 149 # This is where the title captured from the ANSI escape sequences are
149 150 # stored.
150 151 title = 'Console'
151 152
152 153 # Last prompt printed
153 154 last_prompt = ''
154 155
155 156 # The buffer being edited.
156 157 def _set_input_buffer(self, string):
157 158 self.SetSelection(self.current_prompt_pos, self.GetLength())
158 159 self.ReplaceSelection(string)
159 160 self.GotoPos(self.GetLength())
160 161
161 162 def _get_input_buffer(self):
162 163 """ Returns the text in current edit buffer.
163 164 """
164 165 input_buffer = self.GetTextRange(self.current_prompt_pos,
165 166 self.GetLength())
166 167 input_buffer = input_buffer.replace(LINESEP, '\n')
167 168 return input_buffer
168 169
169 170 input_buffer = property(_get_input_buffer, _set_input_buffer)
170 171
171 172 style = _DEFAULT_STYLE.copy()
172 173
173 174 # Translation table from ANSI escape sequences to color. Override
174 175 # this to specify your colors.
175 176 ANSI_STYLES = ANSI_STYLES.copy()
176 177
177 178 # Font faces
178 179 faces = FACES.copy()
179 180
180 181 # Store the last time a refresh was done
181 182 _last_refresh_time = 0
182 183
183 184 #--------------------------------------------------------------------------
184 185 # Public API
185 186 #--------------------------------------------------------------------------
186 187
187 188 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
188 189 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
189 190 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
190 191 self.configure_scintilla()
191 192 # Track if 'enter' key as ever been processed
192 193 # This variable will only be reallowed until key goes up
193 194 self.enter_catched = False
194 195 self.current_prompt_pos = 0
195 196
196 197 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
197 198 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
198 199
199 200
200 201 def write(self, text, refresh=True):
201 202 """ Write given text to buffer, while translating the ansi escape
202 203 sequences.
203 204 """
204 205 # XXX: do not put print statements to sys.stdout/sys.stderr in
205 206 # this method, the print statements will call this method, as
206 207 # you will end up with an infinit loop
207 208 title = self.title_pat.split(text)
208 209 if len(title)>1:
209 210 self.title = title[-2]
210 211
211 212 text = self.title_pat.sub('', text)
212 213 segments = self.color_pat.split(text)
213 214 segment = segments.pop(0)
214 215 self.GotoPos(self.GetLength())
215 216 self.StartStyling(self.GetLength(), 0xFF)
216 217 try:
217 218 self.AppendText(segment)
218 219 except UnicodeDecodeError:
219 220 # XXX: Do I really want to skip the exception?
220 221 pass
221 222
222 223 if segments:
223 224 for ansi_tag, text in zip(segments[::2], segments[1::2]):
224 225 self.StartStyling(self.GetLength(), 0xFF)
225 226 try:
226 227 self.AppendText(text)
227 228 except UnicodeDecodeError:
228 229 # XXX: Do I really want to skip the exception?
229 230 pass
230 231
231 232 if ansi_tag not in self.ANSI_STYLES:
232 233 style = 0
233 234 else:
234 235 style = self.ANSI_STYLES[ansi_tag][0]
235 236
236 237 self.SetStyling(len(text), style)
237 238
238 239 self.GotoPos(self.GetLength())
239 240 if refresh:
240 241 current_time = time.time()
241 242 if current_time - self._last_refresh_time > 0.03:
242 243 if sys.platform == 'win32':
243 244 wx.SafeYield()
244 245 else:
245 246 wx.Yield()
246 247 # self.ProcessEvent(wx.PaintEvent())
247 248 self._last_refresh_time = current_time
248 249
249 250
250 251 def new_prompt(self, prompt):
251 252 """ Prints a prompt at start of line, and move the start of the
252 253 current block there.
253 254
254 255 The prompt can be given with ascii escape sequences.
255 256 """
256 257 self.write(prompt, refresh=False)
257 258 # now we update our cursor giving end of prompt
258 259 self.current_prompt_pos = self.GetLength()
259 260 self.current_prompt_line = self.GetCurrentLine()
260 261 self.EnsureCaretVisible()
261 262 self.last_prompt = prompt
262 263
263 264
264 265 def continuation_prompt(self):
265 266 """ Returns the current continuation prompt.
266 267 We need to implement this method here to deal with the
267 268 ascii escape sequences cleaning up.
268 269 """
269 270 # ASCII-less prompt
270 271 ascii_less = ''.join(self.color_pat.split(self.last_prompt)[2::2])
271 272 return "."*(len(ascii_less)-2) + ': '
272 273
273 274
274 275 def scroll_to_bottom(self):
275 276 maxrange = self.GetScrollRange(wx.VERTICAL)
276 277 self.ScrollLines(maxrange)
277 278
278 279
279 280 def pop_completion(self, possibilities, offset=0):
280 281 """ Pops up an autocompletion menu. Offset is the offset
281 282 in characters of the position at which the menu should
282 283 appear, relativ to the cursor.
283 284 """
284 285 self.AutoCompSetIgnoreCase(False)
285 286 self.AutoCompSetAutoHide(False)
286 287 self.AutoCompSetMaxHeight(len(possibilities))
287 288 self.AutoCompShow(offset, " ".join(possibilities))
288 289
289 290
290 291 def get_line_width(self):
291 292 """ Return the width of the line in characters.
292 293 """
293 294 return self.GetSize()[0]/self.GetCharWidth()
294 295
295 296
296 297 def configure_scintilla(self):
297 298 """ Set up all the styling option of the embedded scintilla
298 299 widget.
299 300 """
300 301 p = self.style.copy()
301 302
302 303 # Marker for complete buffer.
303 304 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
304 305 background=p['trace'])
305 306
306 307 # Marker for current input buffer.
307 308 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
308 309 background=p['stdout'])
309 310 # Marker for tracebacks.
310 311 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
311 312 background=p['stderr'])
312 313
313 314 self.SetEOLMode(stc.STC_EOL_LF)
314 315
315 316 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
316 317 # the widget
317 318 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
318 319 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
319 320 # Also allow Ctrl Shift "=" for poor non US keyboard users.
320 321 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
321 322 stc.STC_CMD_ZOOMIN)
322 323
323 324 # Keys: we need to clear some of the keys the that don't play
324 325 # well with a console.
325 326 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
326 327 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
327 328 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
328 329 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
329 330
330 331 self.SetEOLMode(stc.STC_EOL_CRLF)
331 332 self.SetWrapMode(stc.STC_WRAP_CHAR)
332 333 self.SetWrapMode(stc.STC_WRAP_WORD)
333 334 self.SetBufferedDraw(True)
334 335
335 336 self.SetUseAntiAliasing(p['antialiasing'])
336 337
337 338 self.SetLayoutCache(stc.STC_CACHE_PAGE)
338 339 self.SetUndoCollection(False)
339 340 self.SetUseTabs(True)
340 341 self.SetIndent(4)
341 342 self.SetTabWidth(4)
342 343
343 344 # we don't want scintilla's autocompletion to choose
344 345 # automaticaly out of a single choice list, as we pop it up
345 346 # automaticaly
346 347 self.AutoCompSetChooseSingle(False)
347 348 self.AutoCompSetMaxHeight(10)
348 349 # XXX: this doesn't seem to have an effect.
349 350 self.AutoCompSetFillUps('\n')
350 351
351 352 self.SetMargins(3, 3) #text is moved away from border with 3px
352 353 # Suppressing Scintilla margins
353 354 self.SetMarginWidth(0, 0)
354 355 self.SetMarginWidth(1, 0)
355 356 self.SetMarginWidth(2, 0)
356 357
357 358 # Xterm escape sequences
358 359 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
359 360 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
360 361
361 362 # styles
362 363
363 364 self.SetCaretForeground(p['carret_color'])
364 365
365 366 background_color = p['background_color']
366 367
367 368 if 'default' in p:
368 369 if 'back' not in p['default']:
369 370 p['default'] += ',back:%s' % background_color
370 371 if 'size' not in p['default']:
371 372 p['default'] += ',size:%s' % self.faces['size']
372 373 if 'face' not in p['default']:
373 374 p['default'] += ',face:%s' % self.faces['mono']
374 375
375 376 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
376 377 else:
377 378 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
378 379 "fore:%s,back:%s,size:%d,face:%s"
379 380 % (self.ANSI_STYLES['0;30'][1],
380 381 background_color,
381 382 self.faces['size'], self.faces['mono']))
382 383
383 384 self.StyleClearAll()
384 385
385 386 # XXX: two lines below are usefull if not using the lexer
386 387 #for style in self.ANSI_STYLES.values():
387 388 # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
388 389
389 390 # prompt definition
390 391 self.prompt_in1 = p['prompt_in1']
391 392 self.prompt_out = p['prompt_out']
392 393
393 394 self.output_prompt_template = string.Template(self.prompt_out)
394 395 self.input_prompt_template = string.Template(self.prompt_in1)
395 396
396 397 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
397 398 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
398 399 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
399 400 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
400 401 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
401 402 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
402 403 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
403 404 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
404 405 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
405 406 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
406 407 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
407 408 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
408 409 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
409 410 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
410 411 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
411 412 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
412 413 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
413 414
414 415 edge_column = p['edge_column']
415 416 if edge_column is not None and edge_column > 0:
416 417 #we add a vertical line to console widget
417 418 self.SetEdgeMode(stc.STC_EDGE_LINE)
418 419 self.SetEdgeColumn(edge_column)
419 420
420 421
421 422 #--------------------------------------------------------------------------
422 423 # EditWindow API
423 424 #--------------------------------------------------------------------------
424 425
425 426 def OnUpdateUI(self, event):
426 427 """ Override the OnUpdateUI of the EditWindow class, to prevent
427 428 syntax highlighting both for faster redraw, and for more
428 429 consistent look and feel.
429 430 """
430 431
431 432
432 433 #--------------------------------------------------------------------------
433 434 # Private API
434 435 #--------------------------------------------------------------------------
435 436
436 437 def _on_key_down(self, event, skip=True):
437 438 """ Key press callback used for correcting behavior for
438 439 console-like interfaces: the cursor is constraint to be after
439 440 the last prompt.
440 441
441 442 Return True if event as been catched.
442 443 """
443 444 catched = True
444 445 # XXX: Would the right way to do this be to have a
445 446 # dictionary at the instance level associating keys with
446 447 # callbacks? How would we deal with inheritance? And Do the
447 448 # different callbacks share local variables?
448 449
449 450 # Intercept some specific keys.
450 451 key_code = event.GetKeyCode()
451 452 if key_code == ord('L') and event.ControlDown() :
452 453 self.scroll_to_bottom()
453 454 elif key_code == ord('K') and event.ControlDown() :
454 455 self.input_buffer = ''
455 456 elif key_code == ord('A') and event.ControlDown() :
456 457 self.GotoPos(self.GetLength())
457 458 self.SetSelectionStart(self.current_prompt_pos)
458 459 self.SetSelectionEnd(self.GetCurrentPos())
459 460 catched = True
460 461 elif key_code == ord('E') and event.ControlDown() :
461 462 self.GotoPos(self.GetLength())
462 463 catched = True
463 464 elif key_code == wx.WXK_PAGEUP:
464 465 self.ScrollPages(-1)
465 466 elif key_code == wx.WXK_PAGEDOWN:
466 467 self.ScrollPages(1)
467 468 elif key_code == wx.WXK_HOME:
468 469 self.GotoPos(self.GetLength())
469 470 elif key_code == wx.WXK_END:
470 471 self.GotoPos(self.GetLength())
471 472 elif key_code == wx.WXK_UP and event.ShiftDown():
472 473 self.ScrollLines(-1)
473 474 elif key_code == wx.WXK_DOWN and event.ShiftDown():
474 475 self.ScrollLines(1)
475 476 else:
476 477 catched = False
477 478
478 479 if self.AutoCompActive():
479 480 event.Skip()
480 481 else:
481 482 if key_code in (13, wx.WXK_NUMPAD_ENTER):
482 483 # XXX: not catching modifiers, to be wx2.6-compatible
483 484 catched = True
484 485 if not self.enter_catched:
485 486 self.CallTipCancel()
486 487 if event.ShiftDown():
487 488 # Try to force execution
488 489 self.GotoPos(self.GetLength())
489 490 self.write('\n' + self.continuation_prompt(),
490 491 refresh=False)
491 492 self._on_enter()
492 493 else:
493 494 self._on_enter()
494 495 self.enter_catched = True
495 496
496 497 elif key_code == wx.WXK_HOME:
497 498 if not event.ShiftDown():
498 499 self.GotoPos(self.current_prompt_pos)
499 500 catched = True
500 501 else:
501 502 # FIXME: This behavior is not ideal: if the selection
502 503 # is already started, it will jump.
503 504 self.SetSelectionStart(self.current_prompt_pos)
504 505 self.SetSelectionEnd(self.GetCurrentPos())
505 506 catched = True
506 507
507 508 elif key_code == wx.WXK_UP:
508 509 if self.GetCurrentLine() > self.current_prompt_line:
509 510 if self.GetCurrentLine() == self.current_prompt_line + 1 \
510 511 and self.GetColumn(self.GetCurrentPos()) < \
511 512 self.GetColumn(self.current_prompt_pos):
512 513 self.GotoPos(self.current_prompt_pos)
513 514 else:
514 515 event.Skip()
515 516 catched = True
516 517
517 518 elif key_code in (wx.WXK_LEFT, wx.WXK_BACK):
518 519 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
519 520 event.Skip()
520 521 catched = True
521 522
522 523 elif key_code == wx.WXK_RIGHT:
523 524 if not self._keep_cursor_in_buffer(self.GetCurrentPos() + 1):
524 525 event.Skip()
525 526 catched = True
526 527
527 528
528 529 elif key_code == wx.WXK_DELETE:
529 530 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
530 531 event.Skip()
531 532 catched = True
532 533
533 534 if skip and not catched:
534 535 # Put the cursor back in the edit region
535 536 if not self._keep_cursor_in_buffer():
536 537 if not (self.GetCurrentPos() == self.GetLength()
537 538 and key_code == wx.WXK_DELETE):
538 539 event.Skip()
539 540 catched = True
540 541
541 542 return catched
542 543
543 544
544 545 def _on_key_up(self, event, skip=True):
545 546 """ If cursor is outside the editing region, put it back.
546 547 """
547 548 if skip:
548 549 event.Skip()
549 550 self._keep_cursor_in_buffer()
550 551
551 552
552 553 # XXX: I need to avoid the problem of having an empty glass;
553 554 def _keep_cursor_in_buffer(self, pos=None):
554 555 """ Checks if the cursor is where it is allowed to be. If not,
555 556 put it back.
556 557
557 558 Returns
558 559 -------
559 560 cursor_moved: Boolean
560 561 whether or not the cursor was moved by this routine.
561 562
562 563 Notes
563 564 ------
564 565 WARNING: This does proper checks only for horizontal
565 566 movements.
566 567 """
567 568 if pos is None:
568 569 current_pos = self.GetCurrentPos()
569 570 else:
570 571 current_pos = pos
571 572 if current_pos < self.current_prompt_pos:
572 573 self.GotoPos(self.current_prompt_pos)
573 574 return True
574 575 line_num = self.LineFromPosition(current_pos)
575 576 if not current_pos > self.GetLength():
576 577 line_pos = self.GetColumn(current_pos)
577 578 else:
578 579 line_pos = self.GetColumn(self.GetLength())
579 580 line = self.GetLine(line_num)
580 581 # Jump the continuation prompt
581 582 continuation_prompt = self.continuation_prompt()
582 583 if ( line.startswith(continuation_prompt)
583 584 and line_pos < len(continuation_prompt)):
584 585 if line_pos < 2:
585 586 # We are at the beginning of the line, trying to move
586 587 # forward: jump forward.
587 588 self.GotoPos(current_pos + 1 +
588 589 len(continuation_prompt) - line_pos)
589 590 else:
590 591 # Jump back up
591 592 self.GotoPos(self.GetLineEndPosition(line_num-1))
592 593 return True
593 594 elif ( current_pos > self.GetLineEndPosition(line_num)
594 595 and not current_pos == self.GetLength()):
595 596 # Jump to next line
596 597 self.GotoPos(current_pos + 1 +
597 598 len(continuation_prompt))
598 599 return True
599 600
600 601 # We re-allow enter event processing
601 602 self.enter_catched = False
602 603 return False
603 604
604 605
605 606 if __name__ == '__main__':
606 607 # Some simple code to test the console widget.
607 608 class MainWindow(wx.Frame):
608 609 def __init__(self, parent, id, title):
609 610 wx.Frame.__init__(self, parent, id, title, size=(300, 250))
610 611 self._sizer = wx.BoxSizer(wx.VERTICAL)
611 612 self.console_widget = ConsoleWidget(self)
612 613 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
613 614 self.SetSizer(self._sizer)
614 615 self.SetAutoLayout(1)
615 616 self.Show(True)
616 617
617 618 app = wx.PySimpleApp()
618 619 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
619 620 w.SetSize((780, 460))
620 621 w.Show()
621 622
622 623 app.MainLoop()
623 624
624 625
@@ -1,118 +1,118 b''
1 1 """
2 2 Entry point for a simple application giving a graphical frontend to
3 3 ipython.
4 4 """
5 5
6 6 try:
7 7 import wx
8 8 except ImportError, e:
9 9 e.args[0] = """%s
10 10 ________________________________________________________________________________
11 11 You need wxPython to run this application.
12 12 """ % e.args[0]
13 13 raise e
14 14
15 15 from wx_frontend import WxController
16 16 import __builtin__
17 17
18 18
19 19 class IPythonXController(WxController):
20 20 """ Sub class of WxController that adds some application-specific
21 21 bindings.
22 22 """
23 23
24 24 debug = False
25 25
26 26 def __init__(self, *args, **kwargs):
27 27 WxController.__init__(self, *args, **kwargs)
28 28 self.ipython0.ask_exit = self.do_exit
29 29 # Scroll to top
30 30 maxrange = self.GetScrollRange(wx.VERTICAL)
31 31 self.ScrollLines(-maxrange)
32 32
33 33
34 34 def _on_key_down(self, event, skip=True):
35 35 # Intercept Ctrl-D to quit
36 36 if event.KeyCode == ord('D') and event.ControlDown() and \
37 37 self.input_buffer == '' and \
38 38 self._input_state == 'readline':
39 39 wx.CallAfter(self.ask_exit)
40 40 else:
41 41 WxController._on_key_down(self, event, skip=skip)
42 42
43 43
44 44 def ask_exit(self):
45 45 """ Ask the user whether to exit.
46 46 """
47 47 self._input_state = 'subprocess'
48 48 self.write('\n', refresh=False)
49 49 self.capture_output()
50 self.ipython0.shell.exit()
50 self.ipython0.exit()
51 51 self.release_output()
52 52 if not self.ipython0.exit_now:
53 53 wx.CallAfter(self.new_prompt,
54 54 self.input_prompt_template.substitute(
55 55 number=self.last_result['number'] + 1))
56 56 else:
57 57 wx.CallAfter(wx.GetApp().Exit)
58 58 self.write('Exiting ...', refresh=False)
59 59
60 60
61 61 def do_exit(self):
62 62 """ Exits the interpreter, kills the windows.
63 63 """
64 64 WxController.do_exit(self)
65 65 self.release_output()
66 66 wx.CallAfter(wx.Exit)
67 67
68 68
69 69
70 70 class IPythonX(wx.Frame):
71 71 """ Main frame of the IPythonX app.
72 72 """
73 73
74 74 def __init__(self, parent, id, title, debug=False):
75 75 wx.Frame.__init__(self, parent, id, title, size=(300,250))
76 76 self._sizer = wx.BoxSizer(wx.VERTICAL)
77 77 self.shell = IPythonXController(self, debug=debug)
78 78 self._sizer.Add(self.shell, 1, wx.EXPAND)
79 79 self.SetSizer(self._sizer)
80 80 self.SetAutoLayout(1)
81 81 self.Show(True)
82 82 wx.EVT_CLOSE(self, self.on_close)
83 83
84 84
85 85 def on_close(self, event):
86 86 """ Called on closing the windows.
87 87
88 88 Stops the event loop, to close all the child windows.
89 89 """
90 90 wx.CallAfter(wx.Exit)
91 91
92 92
93 93 def main():
94 94 from optparse import OptionParser
95 95 usage = """usage: %prog [options]
96 96
97 97 Simple graphical frontend to IPython, using WxWidgets."""
98 98 parser = OptionParser(usage=usage)
99 99 parser.add_option("-d", "--debug",
100 100 action="store_true", dest="debug", default=False,
101 101 help="Enable debug message for the wx frontend.")
102 102
103 103 options, args = parser.parse_args()
104 104
105 105 # Clear the options, to avoid having the ipython0 instance complain
106 106 import sys
107 107 sys.argv = sys.argv[:1]
108 108
109 109 app = wx.PySimpleApp()
110 110 frame = IPythonX(None, wx.ID_ANY, 'IPythonX', debug=options.debug)
111 111 frame.shell.SetFocus()
112 112 frame.shell.app = app
113 113 frame.SetSize((680, 460))
114 114
115 115 app.MainLoop()
116 116
117 117 if __name__ == '__main__':
118 118 main()
@@ -1,528 +1,518 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3 '''
4 4 Provides IPython remote instance.
5 5
6 6 @author: Laurent Dufrechou
7 7 laurent.dufrechou _at_ gmail.com
8 8 @license: BSD
9 9
10 10 All rights reserved. This program and the accompanying materials are made
11 11 available under the terms of the BSD which accompanies this distribution, and
12 12 is available at U{http://www.opensource.org/licenses/bsd-license.php}
13 13 '''
14 14
15 15 __version__ = 0.9
16 16 __author__ = "Laurent Dufrechou"
17 17 __email__ = "laurent.dufrechou _at_ gmail.com"
18 18 __license__ = "BSD"
19 19
20 20 import re
21 21 import sys
22 22 import os
23 23 import locale
24 24 from thread_ex import ThreadEx
25 25
26 import IPython
27 from IPython.core import iplib, ipapp
26 from IPython.core import iplib
28 27 from IPython.utils.io import Term
29 28
30 29 ##############################################################################
31 30 class _Helper(object):
32 31 """Redefine the built-in 'help'.
33 32 This is a wrapper around pydoc.help (with a twist).
34 33 """
35 34
36 35 def __init__(self, pager):
37 36 self._pager = pager
38 37
39 38 def __repr__(self):
40 39 return "Type help() for interactive help, " \
41 40 "or help(object) for help about object."
42 41
43 42 def __call__(self, *args, **kwds):
44 43 class DummyWriter(object):
45 44 '''Dumy class to handle help output'''
46 45 def __init__(self, pager):
47 46 self._pager = pager
48 47
49 48 def write(self, data):
50 49 '''hook to fill self._pager'''
51 50 self._pager(data)
52 51
53 52 import pydoc
54 53 pydoc.help.output = DummyWriter(self._pager)
55 54 pydoc.help.interact = lambda :1
56 55
57 56 return pydoc.help(*args, **kwds)
58 57
59 58
60 59 ##############################################################################
61 60 class _CodeExecutor(ThreadEx):
62 61 ''' Thread that execute ipython code '''
63 62 def __init__(self, instance):
64 63 ThreadEx.__init__(self)
65 64 self.instance = instance
66 65
67 66 def run(self):
68 67 '''Thread main loop'''
69 68 try:
70 69 self.instance._doc_text = None
71 70 self.instance._help_text = None
72 71 self.instance._execute()
73 72 # used for uper class to generate event after execution
74 73 self.instance._after_execute()
75 74
76 75 except KeyboardInterrupt:
77 76 pass
78 77
79 78
80 79 ##############################################################################
81 80 class NonBlockingIPShell(object):
82 81 '''
83 82 Create an IPython instance, running the commands in a separate,
84 83 non-blocking thread.
85 84 This allows embedding in any GUI without blockage.
86 85
87 86 Note: The ThreadEx class supports asynchroneous function call
88 87 via raise_exc()
89 88 '''
90 89
91 def __init__(self, argv=[], user_ns={}, user_global_ns=None,
90 def __init__(self, user_ns={}, user_global_ns=None,
92 91 cin=None, cout=None, cerr=None,
93 92 ask_exit_handler=None):
94 93 '''
95 @param argv: Command line options for IPython
96 @type argv: list
97 94 @param user_ns: User namespace.
98 95 @type user_ns: dictionary
99 96 @param user_global_ns: User global namespace.
100 97 @type user_global_ns: dictionary.
101 98 @param cin: Console standard input.
102 99 @type cin: IO stream
103 100 @param cout: Console standard output.
104 101 @type cout: IO stream
105 102 @param cerr: Console standard error.
106 103 @type cerr: IO stream
107 104 @param exit_handler: Replacement for builtin exit() function
108 105 @type exit_handler: function
109 106 @param time_loop: Define the sleep time between two thread's loop
110 107 @type int
111 108 '''
112 109 #ipython0 initialisation
113 110 self._IP = None
114 self.init_ipython0(argv, user_ns, user_global_ns,
115 cin, cout, cerr,
116 ask_exit_handler)
111 self.init_ipython0(user_ns, user_global_ns,
112 cin, cout, cerr,
113 ask_exit_handler)
117 114
118 115 #vars used by _execute
119 116 self._iter_more = 0
120 117 self._history_level = 0
121 118 self._complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
122 119 self._prompt = str(self._IP.outputcache.prompt1).strip()
123 120
124 121 #thread working vars
125 122 self._line_to_execute = ''
126 123 self._threading = True
127 124
128 125 #vars that will be checked by GUI loop to handle thread states...
129 126 #will be replaced later by PostEvent GUI funtions...
130 127 self._doc_text = None
131 128 self._help_text = None
132 129 self._add_button = None
133 130
134 def init_ipython0(self, argv=[], user_ns={}, user_global_ns=None,
131 def init_ipython0(self, user_ns={}, user_global_ns=None,
135 132 cin=None, cout=None, cerr=None,
136 133 ask_exit_handler=None):
137 134 ''' Initialize an ipython0 instance '''
138 135
139 136 #first we redefine in/out/error functions of IPython
140 137 #BUG: we've got a limitation form ipython0 there
141 138 #only one instance can be instanciated else tehre will be
142 139 #cin/cout/cerr clash...
143 140 if cin:
144 141 Term.cin = cin
145 142 if cout:
146 143 Term.cout = cout
147 144 if cerr:
148 145 Term.cerr = cerr
149 146
150 147 excepthook = sys.excepthook
151 148
152 149 #Hack to save sys.displayhook, because ipython seems to overwrite it...
153 150 self.sys_displayhook_ori = sys.displayhook
154
155 ipython0 = ipapp.IPythonApp(argv,user_ns=user_ns,
156 user_global_ns=user_global_ns)
157 ipython0.initialize()
158 self._IP = ipython0.shell
159
160 ## self._IP = IPython.shell.make_IPython(
161 ## argv,user_ns=user_ns,
162 ## user_global_ns=user_global_ns,
163 ## embedded=True,
164 ## shell_class=IPython.shell.InteractiveShell)
151 ipython0 = iplib.InteractiveShell(
152 parent=None, config=None,
153 user_ns=user_ns,
154 user_global_ns=user_global_ns
155 )
156 self._IP = ipython0
165 157
166 158 #we save ipython0 displayhook and we restore sys.displayhook
167 159 self.displayhook = sys.displayhook
168 160 sys.displayhook = self.sys_displayhook_ori
169 161
170 162 #we replace IPython default encoding by wx locale encoding
171 163 loc = locale.getpreferredencoding()
172 164 if loc:
173 165 self._IP.stdin_encoding = loc
174 166 #we replace the ipython default pager by our pager
175 167 self._IP.set_hook('show_in_pager', self._pager)
176 168
177 169 #we replace the ipython default shell command caller
178 170 #by our shell handler
179 171 self._IP.set_hook('shell_hook', self._shell)
180 172
181 173 #we replace the ipython default input command caller by our method
182 174 iplib.raw_input_original = self._raw_input_original
183 175 #we replace the ipython default exit command by our method
184 176 self._IP.exit = ask_exit_handler
185 177 #we replace the help command
186 178 self._IP.user_ns['help'] = _Helper(self._pager_help)
187 179
188 #we disable cpase magic... until we found a way to use it properly.
189 from IPython.core import ipapi
190 ip = ipapi.get()
180 #we disable cpaste magic... until we found a way to use it properly.
191 181 def bypass_magic(self, arg):
192 182 print '%this magic is currently disabled.'
193 ip.define_magic('cpaste', bypass_magic)
183 ipython0.define_magic('cpaste', bypass_magic)
194 184
195 185 import __builtin__
196 186 __builtin__.raw_input = self._raw_input
197 187
198 188 sys.excepthook = excepthook
199 189
200 190 #----------------------- Thread management section ----------------------
201 191 def do_execute(self, line):
202 192 """
203 193 Tell the thread to process the 'line' command
204 194 """
205 195
206 196 self._line_to_execute = line
207 197
208 198 if self._threading:
209 199 #we launch the ipython line execution in a thread to make it
210 200 #interruptible with include it in self namespace to be able
211 201 #to call ce.raise_exc(KeyboardInterrupt)
212 202 self.ce = _CodeExecutor(self)
213 203 self.ce.start()
214 204 else:
215 205 try:
216 206 self._doc_text = None
217 207 self._help_text = None
218 208 self._execute()
219 209 # used for uper class to generate event after execution
220 210 self._after_execute()
221 211
222 212 except KeyboardInterrupt:
223 213 pass
224 214
225 215 #----------------------- IPython management section ----------------------
226 216 def get_threading(self):
227 217 """
228 218 Returns threading status, is set to True, then each command sent to
229 219 the interpreter will be executed in a separated thread allowing,
230 220 for example, breaking a long running commands.
231 221 Disallowing it, permits better compatibilty with instance that is embedding
232 222 IPython instance.
233 223
234 224 @return: Execution method
235 225 @rtype: bool
236 226 """
237 227 return self._threading
238 228
239 229 def set_threading(self, state):
240 230 """
241 231 Sets threading state, if set to True, then each command sent to
242 232 the interpreter will be executed in a separated thread allowing,
243 233 for example, breaking a long running commands.
244 234 Disallowing it, permits better compatibilty with instance that is embedding
245 235 IPython instance.
246 236
247 237 @param state: Sets threading state
248 238 @type bool
249 239 """
250 240 self._threading = state
251 241
252 242 def get_doc_text(self):
253 243 """
254 244 Returns the output of the processing that need to be paged (if any)
255 245
256 246 @return: The std output string.
257 247 @rtype: string
258 248 """
259 249 return self._doc_text
260 250
261 251 def get_help_text(self):
262 252 """
263 253 Returns the output of the processing that need to be paged via help pager(if any)
264 254
265 255 @return: The std output string.
266 256 @rtype: string
267 257 """
268 258 return self._help_text
269 259
270 260 def get_banner(self):
271 261 """
272 262 Returns the IPython banner for useful info on IPython instance
273 263
274 264 @return: The banner string.
275 265 @rtype: string
276 266 """
277 267 return self._IP.banner
278 268
279 269 def get_prompt_count(self):
280 270 """
281 271 Returns the prompt number.
282 272 Each time a user execute a line in the IPython shell the prompt count is increased
283 273
284 274 @return: The prompt number
285 275 @rtype: int
286 276 """
287 277 return self._IP.outputcache.prompt_count
288 278
289 279 def get_prompt(self):
290 280 """
291 281 Returns current prompt inside IPython instance
292 282 (Can be In [...]: ot ...:)
293 283
294 284 @return: The current prompt.
295 285 @rtype: string
296 286 """
297 287 return self._prompt
298 288
299 289 def get_indentation(self):
300 290 """
301 291 Returns the current indentation level
302 292 Usefull to put the caret at the good start position if we want to do autoindentation.
303 293
304 294 @return: The indentation level.
305 295 @rtype: int
306 296 """
307 297 return self._IP.indent_current_nsp
308 298
309 299 def update_namespace(self, ns_dict):
310 300 '''
311 301 Add the current dictionary to the shell namespace.
312 302
313 303 @param ns_dict: A dictionary of symbol-values.
314 304 @type ns_dict: dictionary
315 305 '''
316 306 self._IP.user_ns.update(ns_dict)
317 307
318 308 def complete(self, line):
319 309 '''
320 310 Returns an auto completed line and/or posibilities for completion.
321 311
322 312 @param line: Given line so far.
323 313 @type line: string
324 314
325 315 @return: Line completed as for as possible,
326 316 and possible further completions.
327 317 @rtype: tuple
328 318 '''
329 319 split_line = self._complete_sep.split(line)
330 320 possibilities = self._IP.complete(split_line[-1])
331 321 if possibilities:
332 322
333 323 def _common_prefix(str1, str2):
334 324 '''
335 325 Reduction function. returns common prefix of two given strings.
336 326
337 327 @param str1: First string.
338 328 @type str1: string
339 329 @param str2: Second string
340 330 @type str2: string
341 331
342 332 @return: Common prefix to both strings.
343 333 @rtype: string
344 334 '''
345 335 for i in range(len(str1)):
346 336 if not str2.startswith(str1[:i+1]):
347 337 return str1[:i]
348 338 return str1
349 339 common_prefix = reduce(_common_prefix, possibilities)
350 340 completed = line[:-len(split_line[-1])]+common_prefix
351 341 else:
352 342 completed = line
353 343 return completed, possibilities
354 344
355 345 def history_back(self):
356 346 '''
357 347 Provides one history command back.
358 348
359 349 @return: The command string.
360 350 @rtype: string
361 351 '''
362 352 history = ''
363 353 #the below while loop is used to suppress empty history lines
364 354 while((history == '' or history == '\n') and self._history_level >0):
365 355 if self._history_level >= 1:
366 356 self._history_level -= 1
367 357 history = self._get_history()
368 358 return history
369 359
370 360 def history_forward(self):
371 361 '''
372 362 Provides one history command forward.
373 363
374 364 @return: The command string.
375 365 @rtype: string
376 366 '''
377 367 history = ''
378 368 #the below while loop is used to suppress empty history lines
379 369 while((history == '' or history == '\n') \
380 370 and self._history_level <= self._get_history_max_index()):
381 371 if self._history_level < self._get_history_max_index():
382 372 self._history_level += 1
383 373 history = self._get_history()
384 374 else:
385 375 if self._history_level == self._get_history_max_index():
386 376 history = self._get_history()
387 377 self._history_level += 1
388 378 else:
389 379 history = ''
390 380 return history
391 381
392 382 def init_history_index(self):
393 383 '''
394 384 set history to last command entered
395 385 '''
396 386 self._history_level = self._get_history_max_index()+1
397 387
398 388 #----------------------- IPython PRIVATE management section --------------
399 389 def _after_execute(self):
400 390 '''
401 391 Can be redefined to generate post event after excution is done
402 392 '''
403 393 pass
404 394
405 395 def _ask_exit(self):
406 396 '''
407 397 Can be redefined to generate post event to exit the Ipython shell
408 398 '''
409 399 pass
410 400
411 401 def _get_history_max_index(self):
412 402 '''
413 403 returns the max length of the history buffer
414 404
415 405 @return: history length
416 406 @rtype: int
417 407 '''
418 408 return len(self._IP.input_hist_raw)-1
419 409
420 410 def _get_history(self):
421 411 '''
422 412 Get's the command string of the current history level.
423 413
424 414 @return: Historic command stri
425 415 @rtype: string
426 416 '''
427 417 rv = self._IP.input_hist_raw[self._history_level].strip('\n')
428 418 return rv
429 419
430 420 def _pager_help(self, text):
431 421 '''
432 422 This function is used as a callback replacment to IPython help pager function
433 423
434 424 It puts the 'text' value inside the self._help_text string that can be retrived via
435 425 get_help_text function.
436 426 '''
437 427 if self._help_text == None:
438 428 self._help_text = text
439 429 else:
440 430 self._help_text += text
441 431
442 432 def _pager(self, IP, text):
443 433 '''
444 434 This function is used as a callback replacment to IPython pager function
445 435
446 436 It puts the 'text' value inside the self._doc_text string that can be retrived via
447 437 get_doc_text function.
448 438 '''
449 439 self._doc_text = text
450 440
451 441 def _raw_input_original(self, prompt=''):
452 442 '''
453 443 Custom raw_input() replacement. Get's current line from console buffer.
454 444
455 445 @param prompt: Prompt to print. Here for compatability as replacement.
456 446 @type prompt: string
457 447
458 448 @return: The current command line text.
459 449 @rtype: string
460 450 '''
461 451 return self._line_to_execute
462 452
463 453 def _raw_input(self, prompt=''):
464 454 """ A replacement from python's raw_input.
465 455 """
466 456 raise NotImplementedError
467 457
468 458 def _execute(self):
469 459 '''
470 460 Executes the current line provided by the shell object.
471 461 '''
472 462
473 463 orig_stdout = sys.stdout
474 464 sys.stdout = Term.cout
475 465 #self.sys_displayhook_ori = sys.displayhook
476 466 #sys.displayhook = self.displayhook
477 467
478 468 try:
479 469 line = self._IP.raw_input(None, self._iter_more)
480 470 if self._IP.autoindent:
481 471 self._IP.readline_startup_hook(None)
482 472
483 473 except KeyboardInterrupt:
484 474 self._IP.write('\nKeyboardInterrupt\n')
485 475 self._IP.resetbuffer()
486 476 # keep cache in sync with the prompt counter:
487 477 self._IP.outputcache.prompt_count -= 1
488 478
489 479 if self._IP.autoindent:
490 480 self._IP.indent_current_nsp = 0
491 481 self._iter_more = 0
492 482 except:
493 483 self._IP.showtraceback()
494 484 else:
495 485 self._IP.write(str(self._IP.outputcache.prompt_out).strip())
496 486 self._iter_more = self._IP.push_line(line)
497 487 if (self._IP.SyntaxTB.last_syntax_error and \
498 488 self._IP.autoedit_syntax):
499 489 self._IP.edit_syntax_error()
500 490 if self._iter_more:
501 491 self._prompt = str(self._IP.outputcache.prompt2).strip()
502 492 if self._IP.autoindent:
503 493 self._IP.readline_startup_hook(self._IP.pre_readline)
504 494 else:
505 495 self._prompt = str(self._IP.outputcache.prompt1).strip()
506 496 self._IP.indent_current_nsp = 0 #we set indentation to 0
507 497
508 498 sys.stdout = orig_stdout
509 499 #sys.displayhook = self.sys_displayhook_ori
510 500
511 501 def _shell(self, ip, cmd):
512 502 '''
513 503 Replacement method to allow shell commands without them blocking.
514 504
515 505 @param ip: Ipython instance, same as self._IP
516 506 @type cmd: Ipython instance
517 507 @param cmd: Shell command to execute.
518 508 @type cmd: string
519 509 '''
520 510 stdin, stdout = os.popen4(cmd)
521 511 result = stdout.read().decode('cp437').\
522 512 encode(locale.getpreferredencoding())
523 513 #we use print command because the shell command is called
524 514 #inside IPython instance and thus is redirected to thread cout
525 515 #"\x01\x1b[1;36m\x02" <-- add colour to the text...
526 516 print "\x01\x1b[1;36m\x02"+result
527 517 stdout.close()
528 518 stdin.close()
@@ -1,509 +1,510 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3 import wx
4 4 import wx.stc as stc
5 5 import keyword
6 6
7 7 #-----------------------------------------
8 8 # History widget for IPython
9 9 __version__ = 0.5
10 10 __author__ = "Laurent Dufrechou"
11 11 __email__ = "laurent.dufrechou _at_ gmail.com"
12 12 __license__ = "BSD"
13 13 #-----------------------------------------
14
14 15 class IPythonHistoryPanel(wx.Panel):
15 16
16 17 def __init__(self, parent,flt_empty=True,
17 18 flt_doc=True,flt_cmd=True,flt_magic=True):
18 19
19 20 wx.Panel.__init__(self,parent,-1)
20 21 #text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
21 22 text_ctrl = PythonSTC(self, -1)
22 23
23 24
24 25 st_filt = wx.StaticText(self, -1, " Filter:")
25 26
26 27 self.filter_empty = wx.CheckBox(self, -1, "Empty commands")
27 28 self.filter_doc = wx.CheckBox(self, -1, "?: Doc commands")
28 29 self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
29 30 self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
30 31
31 32 self.options={'filter_empty':{'value':'True',
32 33 'checkbox':self.filter_empty, \
33 34 'True':True,'False':False,
34 35 'setfunc':lambda x:None},
35 36 'filter_doc':{'value':'True',
36 37 'checkbox':self.filter_doc, \
37 38 'True':True,'False':False,
38 39 'setfunc':lambda x:None},
39 40 'filter_cmd':{'value':'True',
40 41 'checkbox':self.filter_cmd, \
41 42 'True':True,'False':False,
42 43 'setfunc':lambda x:None},
43 44 'filter_magic':{'value':'True',
44 45 'checkbox':self.filter_magic, \
45 46 'True':True,'False':False,
46 47 'setfunc':lambda x:None},
47 48 }
48 49 self.reloadOptions(self.options)
49 50
50 51 self.filter_empty.Bind(wx.EVT_CHECKBOX, self.evtCheckEmptyFilter)
51 52 self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter)
52 53 self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter)
53 54 self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter)
54 55
55 56 #self.filter_empty.SetValue(flt_empty)
56 57 #self.filter_doc.SetValue(flt_doc)
57 58 #self.filter_cmd.SetValue(flt_cmd)
58 59 #self.filter_magic.SetValue(flt_magic)
59 60
60 61 sizer = wx.BoxSizer(wx.VERTICAL)
61 62
62 63 sizer.Add(text_ctrl, 1, wx.EXPAND)
63 64 sizer.AddMany( [(5,5),
64 65 st_filt,
65 66 (10,10),
66 67 self.filter_empty,
67 68 self.filter_doc,
68 69 self.filter_cmd,
69 70 self.filter_magic,
70 71 (10,10),
71 72 ])
72 73 self.SetAutoLayout(True)
73 74 sizer.Fit(self)
74 75 sizer.SetSizeHints(self)
75 76 self.SetSizer(sizer)
76 77 self.text_ctrl=text_ctrl
77 78 #text_ctrl.SetText(demoText + open('Main.py').read())
78 79 text_ctrl.EmptyUndoBuffer()
79 80 text_ctrl.Colourise(0, -1)
80 81
81 82 # line numbers in the margin
82 83 text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER)
83 84 text_ctrl.SetMarginWidth(1, 15)
84 85
85 86
86 87 def write(self,history_line):
87 88 add = True
88 89 if self.filter_empty.GetValue() == True and history_line == '':
89 90 add = False
90 91 if len(history_line)>0:
91 92 if self.filter_doc.GetValue() == True and history_line[-1:] == '?':
92 93 add = False
93 94 if self.filter_cmd.GetValue() == True and history_line[0] == '!':
94 95 add = False
95 96 if self.filter_magic.GetValue() == True and history_line[0] == '%':
96 97 add = False
97 98 if add:
98 99 self.text_ctrl.AppendText(history_line+'\n')
99 100
100 101 #------------------------ Option Section -----------------------------------
101 102 def processOptionCheckedEvt(self, event, name):
102 103 if event.IsChecked():
103 104 self.options[name]['value']='True'
104 105 else:
105 106 self.options[name]['value']='False'
106 107 self.updateOptionTracker(name,
107 108 self.options[name]['value'])
108 109
109 110 def evtCheckEmptyFilter(self, event):
110 111 self.processOptionCheckedEvt(event, 'filter_empty')
111 112
112 113 def evtCheckDocFilter(self, event):
113 114 self.processOptionCheckedEvt(event, 'filter_doc')
114 115
115 116 def evtCheckCmdFilter(self, event):
116 117 self.processOptionCheckedEvt(event, 'filter_cmd')
117 118
118 119 def evtCheckMagicFilter(self, event):
119 120 self.processOptionCheckedEvt(event, 'filter_magic')
120 121
121 122 def getOptions(self):
122 123 return self.options
123 124
124 125 def reloadOptions(self,options):
125 126 self.options = options
126 127 for key in self.options.keys():
127 128 value = self.options[key]['value']
128 129 self.options[key]['checkbox'].SetValue(self.options[key][value])
129 130 self.options[key]['setfunc'](value)
130 131
131 132 #------------------------ Hook Section -----------------------------------
132 133 def updateOptionTracker(self,name,value):
133 134 '''
134 135 Default history tracker (does nothing)
135 136 '''
136 137 pass
137 138
138 139 def setOptionTrackerHook(self,func):
139 140 '''
140 141 Define a new history tracker
141 142 '''
142 143 self.updateOptionTracker = func
143 144
144 145
145 146 #----------------------------------------------------------------------
146 147 # Font definition for Styled Text Control
147 148
148 149 if wx.Platform == '__WXMSW__':
149 150 faces = { 'times': 'Times New Roman',
150 151 'mono' : 'Courier New',
151 152 'helv' : 'Arial',
152 153 'other': 'Comic Sans MS',
153 154 'size' : 8,
154 155 'size2': 6,
155 156 }
156 157 elif wx.Platform == '__WXMAC__':
157 158 faces = { 'times': 'Times New Roman',
158 159 'mono' : 'Monaco',
159 160 'helv' : 'Arial',
160 161 'other': 'Comic Sans MS',
161 162 'size' : 8,
162 163 'size2': 6,
163 164 }
164 165 else:
165 166 faces = { 'times': 'Times',
166 167 'mono' : 'Courier',
167 168 'helv' : 'Helvetica',
168 169 'other': 'new century schoolbook',
169 170 'size' : 8,
170 171 'size2': 6,
171 172 }
172 173
173 174
174 175 #----------------------------------------------------------------------
175 176
176 177 class PythonSTC(stc.StyledTextCtrl):
177 178
178 179 fold_symbols = 3
179 180
180 181 def __init__(self, parent, ID,
181 182 pos=wx.DefaultPosition, size=wx.DefaultSize,
182 183 style=0):
183 184 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
184 185 #self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
185 186 #self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
186 187
187 188 self.SetLexer(stc.STC_LEX_PYTHON)
188 189 self.SetKeyWords(0, " ".join(keyword.kwlist))
189 190
190 191 #self.SetProperty("fold", "1")
191 192 #self.SetProperty("tab.timmy.whinge.level", "1")
192 193 #self.SetMargins(0,0)
193 194
194 195 #self.SetViewWhiteSpace(False)
195 196 #self.SetBufferedDraw(False)
196 197 #self.SetViewEOL(True)
197 198 self.SetEOLMode(stc.STC_EOL_CRLF)
198 199 #self.SetUseAntiAliasing(True)
199 200
200 201 self.SetEdgeMode(stc.STC_EDGE_LINE)
201 202 self.SetEdgeColumn(80)
202 203 self.SetEdgeColour(wx.LIGHT_GREY)
203 204 self.SetLayoutCache(stc.STC_CACHE_PAGE)
204 205
205 206 # Setup a margin to hold fold markers
206 207 #self.SetFoldFlags(16)
207 208 ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
208 209 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
209 210 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
210 211 self.SetMarginSensitive(2, True)
211 212 self.SetMarginWidth(2, 12)
212 213
213 214 if self.fold_symbols == 0:
214 215 # Arrow pointing right for contracted folders,
215 216 # arrow pointing down for expanded
216 217 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
217 218 stc.STC_MARK_ARROWDOWN, "black", "black")
218 219 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
219 220 stc.STC_MARK_ARROW, "black", "black")
220 221 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
221 222 stc.STC_MARK_EMPTY, "black", "black")
222 223 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
223 224 stc.STC_MARK_EMPTY, "black", "black")
224 225 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
225 226 stc.STC_MARK_EMPTY, "white", "black")
226 227 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
227 228 stc.STC_MARK_EMPTY, "white", "black")
228 229 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
229 230 stc.STC_MARK_EMPTY, "white", "black")
230 231
231 232 elif self.fold_symbols == 1:
232 233 # Plus for contracted folders, minus for expanded
233 234 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
234 235 stc.STC_MARK_MINUS, "white", "black")
235 236 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
236 237 stc.STC_MARK_PLUS, "white", "black")
237 238 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
238 239 stc.STC_MARK_EMPTY, "white", "black")
239 240 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
240 241 stc.STC_MARK_EMPTY, "white", "black")
241 242 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
242 243 stc.STC_MARK_EMPTY, "white", "black")
243 244 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
244 245 stc.STC_MARK_EMPTY, "white", "black")
245 246 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
246 247 stc.STC_MARK_EMPTY, "white", "black")
247 248
248 249 elif self.fold_symbols == 2:
249 250 # Like a flattened tree control using circular headers and curved joins
250 251 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
251 252 stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
252 253 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
253 254 stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
254 255 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
255 256 stc.STC_MARK_VLINE, "white", "#404040")
256 257 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
257 258 stc.STC_MARK_LCORNERCURVE, "white", "#404040")
258 259 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
259 260 stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
260 261 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
261 262 stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
262 263 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
263 264 stc.STC_MARK_TCORNERCURVE, "white", "#404040")
264 265
265 266 elif self.fold_symbols == 3:
266 267 # Like a flattened tree control using square headers
267 268 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
268 269 stc.STC_MARK_BOXMINUS, "white", "#808080")
269 270 self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
270 271 stc.STC_MARK_BOXPLUS, "white", "#808080")
271 272 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
272 273 stc.STC_MARK_VLINE, "white", "#808080")
273 274 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
274 275 stc.STC_MARK_LCORNER, "white", "#808080")
275 276 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
276 277 stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
277 278 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
278 279 stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
279 280 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
280 281 stc.STC_MARK_TCORNER, "white", "#808080")
281 282
282 283
283 284 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
284 285 self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
285 286 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
286 287
287 288 # Make some styles, The lexer defines what each style is used for, we
288 289 # just have to define what each style looks like. This set is adapted from
289 290 # Scintilla sample property files.
290 291
291 292 # Global default styles for all languages
292 293 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
293 294 self.StyleClearAll() # Reset all to be like the default
294 295
295 296 # Global default styles for all languages
296 297 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
297 298 self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
298 299 self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
299 300 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
300 301 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
301 302
302 303 # Python styles
303 304 # Default
304 305 self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
305 306 # Comments
306 307 self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
307 308 # Number
308 309 self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
309 310 # String
310 311 self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
311 312 # Single quoted string
312 313 self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
313 314 # Keyword
314 315 self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
315 316 # Triple quotes
316 317 self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
317 318 # Triple double quotes
318 319 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
319 320 # Class name definition
320 321 self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
321 322 # Function or method name definition
322 323 self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
323 324 # Operators
324 325 self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces)
325 326 # Identifiers
326 327 self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
327 328 # Comment-blocks
328 329 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
329 330 # End of line where string is not closed
330 331 self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
331 332
332 333 self.SetCaretForeground("BLUE")
333 334
334 335
335 336 # register some images for use in the AutoComplete box.
336 337 #self.RegisterImage(1, images.getSmilesBitmap())
337 338 #self.RegisterImage(2,
338 339 # wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
339 340 #self.RegisterImage(3,
340 341 # wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
341 342
342 343
343 344 def OnKeyPressed(self, event):
344 345 if self.CallTipActive():
345 346 self.CallTipCancel()
346 347 key = event.GetKeyCode()
347 348
348 349 if key == 32 and event.ControlDown():
349 350 pos = self.GetCurrentPos()
350 351
351 352 # Tips
352 353 if event.ShiftDown():
353 354 self.CallTipSetBackground("yellow")
354 355 self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
355 356 'show some suff, maybe parameters..\n\n'
356 357 'fubar(param1, param2)')
357 358 # Code completion
358 359 else:
359 360 #lst = []
360 361 #for x in range(50000):
361 362 # lst.append('%05d' % x)
362 363 #st = " ".join(lst)
363 364 #print len(st)
364 365 #self.AutoCompShow(0, st)
365 366
366 367 kw = keyword.kwlist[:]
367 368
368 369 kw.sort() # Python sorts are case sensitive
369 370 self.AutoCompSetIgnoreCase(False) # so this needs to match
370 371
371 372 # Images are specified with a appended "?type"
372 373 for i in range(len(kw)):
373 374 if kw[i] in keyword.kwlist:
374 375 kw[i] = kw[i]# + "?1"
375 376
376 377 self.AutoCompShow(0, " ".join(kw))
377 378 else:
378 379 event.Skip()
379 380
380 381
381 382 def OnUpdateUI(self, evt):
382 383 # check for matching braces
383 384 braceAtCaret = -1
384 385 braceOpposite = -1
385 386 charBefore = None
386 387 caretPos = self.GetCurrentPos()
387 388
388 389 if caretPos > 0:
389 390 charBefore = self.GetCharAt(caretPos - 1)
390 391 styleBefore = self.GetStyleAt(caretPos - 1)
391 392
392 393 # check before
393 394 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
394 395 braceAtCaret = caretPos - 1
395 396
396 397 # check after
397 398 if braceAtCaret < 0:
398 399 charAfter = self.GetCharAt(caretPos)
399 400 styleAfter = self.GetStyleAt(caretPos)
400 401
401 402 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
402 403 braceAtCaret = caretPos
403 404
404 405 if braceAtCaret >= 0:
405 406 braceOpposite = self.BraceMatch(braceAtCaret)
406 407
407 408 if braceAtCaret != -1 and braceOpposite == -1:
408 409 self.BraceBadLight(braceAtCaret)
409 410 else:
410 411 self.BraceHighlight(braceAtCaret, braceOpposite)
411 412 #pt = self.PointFromPosition(braceOpposite)
412 413 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
413 414 #print pt
414 415 #self.Refresh(False)
415 416
416 417
417 418 def OnMarginClick(self, evt):
418 419 # fold and unfold as needed
419 420 if evt.GetMargin() == 2:
420 421 if evt.GetShift() and evt.GetControl():
421 422 self.FoldAll()
422 423 else:
423 424 lineClicked = self.LineFromPosition(evt.GetPosition())
424 425
425 426 if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
426 427 if evt.GetShift():
427 428 self.SetFoldExpanded(lineClicked, True)
428 429 self.Expand(lineClicked, True, True, 1)
429 430 elif evt.GetControl():
430 431 if self.GetFoldExpanded(lineClicked):
431 432 self.SetFoldExpanded(lineClicked, False)
432 433 self.Expand(lineClicked, False, True, 0)
433 434 else:
434 435 self.SetFoldExpanded(lineClicked, True)
435 436 self.Expand(lineClicked, True, True, 100)
436 437 else:
437 438 self.ToggleFold(lineClicked)
438 439
439 440
440 441 def FoldAll(self):
441 442 lineCount = self.GetLineCount()
442 443 expanding = True
443 444
444 445 # find out if we are folding or unfolding
445 446 for lineNum in range(lineCount):
446 447 if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
447 448 expanding = not self.GetFoldExpanded(lineNum)
448 449 break
449 450
450 451 lineNum = 0
451 452
452 453 while lineNum < lineCount:
453 454 level = self.GetFoldLevel(lineNum)
454 455 if level & stc.STC_FOLDLEVELHEADERFLAG and \
455 456 (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
456 457
457 458 if expanding:
458 459 self.SetFoldExpanded(lineNum, True)
459 460 lineNum = self.Expand(lineNum, True)
460 461 lineNum = lineNum - 1
461 462 else:
462 463 lastChild = self.GetLastChild(lineNum, -1)
463 464 self.SetFoldExpanded(lineNum, False)
464 465
465 466 if lastChild > lineNum:
466 467 self.HideLines(lineNum+1, lastChild)
467 468
468 469 lineNum = lineNum + 1
469 470
470 471
471 472
472 473 def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
473 474 lastChild = self.GetLastChild(line, level)
474 475 line = line + 1
475 476
476 477 while line <= lastChild:
477 478 if force:
478 479 if visLevels > 0:
479 480 self.ShowLines(line, line)
480 481 else:
481 482 self.HideLines(line, line)
482 483 else:
483 484 if doExpand:
484 485 self.ShowLines(line, line)
485 486
486 487 if level == -1:
487 488 level = self.GetFoldLevel(line)
488 489
489 490 if level & stc.STC_FOLDLEVELHEADERFLAG:
490 491 if force:
491 492 if visLevels > 1:
492 493 self.SetFoldExpanded(line, True)
493 494 else:
494 495 self.SetFoldExpanded(line, False)
495 496
496 497 line = self.Expand(line, doExpand, force, visLevels-1)
497 498
498 499 else:
499 500 if doExpand and self.GetFoldExpanded(line):
500 501 line = self.Expand(line, True, force, visLevels-1)
501 502 else:
502 503 line = self.Expand(line, False, force, visLevels-1)
503 504 else:
504 505 line = line + 1
505 506
506 507 return line
507 508
508 509
509 510 #----------------------------------------------------------------------
@@ -1,460 +1,463 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The ipcluster application.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
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 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 import logging
19 19 import os
20 20 import signal
21 21
22 22 if os.name=='posix':
23 23 from twisted.scripts._twistd_unix import daemonize
24 24
25 25 from IPython.core import release
26 26 from IPython.external.argparse import ArgumentParser
27 27 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
28 28 from IPython.utils.importstring import import_item
29 29
30 30 from IPython.kernel.clusterdir import (
31 31 ApplicationWithClusterDir, ClusterDirError, PIDFileError
32 32 )
33 33
34 34 from twisted.internet import reactor, defer
35 35 from twisted.python import log, failure
36 36
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # The ipcluster application
40 40 #-----------------------------------------------------------------------------
41 41
42 42
43 43 # Exit codes for ipcluster
44 44
45 45 # This will be the exit code if the ipcluster appears to be running because
46 46 # a .pid file exists
47 47 ALREADY_STARTED = 10
48 48
49 49 # This will be the exit code if ipcluster stop is run, but there is not .pid
50 50 # file to be found.
51 51 ALREADY_STOPPED = 11
52 52
53 53
54 54 class IPClusterCLLoader(ArgParseConfigLoader):
55 55
56 56 def _add_other_arguments(self):
57 57 # This has all the common options that all subcommands use
58 58 parent_parser1 = ArgumentParser(add_help=False,
59 59 argument_default=NoConfigDefault)
60 60 parent_parser1.add_argument('--ipython-dir',
61 61 dest='Global.ipython_dir',type=unicode,
62 62 help='Set to override default location of Global.ipython_dir.',
63 63 metavar='Global.ipython_dir')
64 64 parent_parser1.add_argument('--log-level',
65 65 dest="Global.log_level",type=int,
66 66 help='Set the log level (0,10,20,30,40,50). Default is 30.',
67 67 metavar='Global.log_level')
68 68
69 69 # This has all the common options that other subcommands use
70 70 parent_parser2 = ArgumentParser(add_help=False,
71 71 argument_default=NoConfigDefault)
72 72 parent_parser2.add_argument('-p','--profile',
73 73 dest='Global.profile',type=unicode,
74 74 help='The string name of the profile to be used. This determines '
75 75 'the name of the cluster dir as: cluster_<profile>. The default profile '
76 76 'is named "default". The cluster directory is resolve this way '
77 77 'if the --cluster-dir option is not used.',
78 78 metavar='Global.profile')
79 79 parent_parser2.add_argument('--cluster-dir',
80 80 dest='Global.cluster_dir',type=unicode,
81 81 help='Set the cluster dir. This overrides the logic used by the '
82 82 '--profile option.',
83 83 metavar='Global.cluster_dir'),
84 84 parent_parser2.add_argument('--work-dir',
85 85 dest='Global.work_dir',type=unicode,
86 86 help='Set the working dir for the process.',
87 87 metavar='Global.work_dir')
88 88 parent_parser2.add_argument('--log-to-file',
89 89 action='store_true', dest='Global.log_to_file',
90 90 help='Log to a file in the log directory (default is stdout)'
91 91 )
92 92
93 93 subparsers = self.parser.add_subparsers(
94 94 dest='Global.subcommand',
95 95 title='ipcluster subcommands',
96 96 description='ipcluster has a variety of subcommands. '
97 97 'The general way of running ipcluster is "ipcluster <cmd> '
98 98 ' [options]""',
99 99 help='For more help, type "ipcluster <cmd> -h"')
100 100
101 101 parser_list = subparsers.add_parser(
102 102 'list',
103 103 help='List all clusters in cwd and ipython_dir.',
104 104 parents=[parent_parser1]
105 105 )
106 106
107 107 parser_create = subparsers.add_parser(
108 108 'create',
109 109 help='Create a new cluster directory.',
110 110 parents=[parent_parser1, parent_parser2]
111 111 )
112 112 parser_create.add_argument(
113 113 '--reset-config',
114 114 dest='Global.reset_config', action='store_true',
115 115 default=NoConfigDefault,
116 116 help='Recopy the default config files to the cluster directory. '
117 117 'You will loose any modifications you have made to these files.'
118 118 )
119 119
120 120 parser_start = subparsers.add_parser(
121 121 'start',
122 122 help='Start a cluster.',
123 123 parents=[parent_parser1, parent_parser2]
124 124 )
125 125 parser_start.add_argument(
126 126 '-n', '--number',
127 127 type=int, dest='Global.n',
128 128 help='The number of engines to start.',
129 129 metavar='Global.n'
130 130 )
131 131 parser_start.add_argument('--clean-logs',
132 132 dest='Global.clean_logs', action='store_true',
133 133 help='Delete old log flies before starting.',
134 134 )
135 135 parser_start.add_argument('--no-clean-logs',
136 136 dest='Global.clean_logs', action='store_false',
137 137 help="Don't delete old log flies before starting.",
138 138 )
139 139 parser_start.add_argument('--daemon',
140 140 dest='Global.daemonize', action='store_true',
141 141 help='Daemonize the ipcluster program. This implies --log-to-file',
142 142 )
143 143 parser_start.add_argument('--no-daemon',
144 144 dest='Global.daemonize', action='store_false',
145 145 help="Dont't daemonize the ipcluster program.",
146 146 )
147 147
148 148 parser_start = subparsers.add_parser(
149 149 'stop',
150 150 help='Stop a cluster.',
151 151 parents=[parent_parser1, parent_parser2]
152 152 )
153 153 parser_start.add_argument('--signal',
154 154 dest='Global.signal', type=int,
155 155 help="The signal number to use in stopping the cluster (default=2).",
156 156 metavar="Global.signal",
157 157 )
158 158
159 159
160 160 default_config_file_name = u'ipcluster_config.py'
161 161
162 162
163 163 _description = """Start an IPython cluster for parallel computing.\n\n
164 164
165 165 An IPython cluster consists of 1 controller and 1 or more engines.
166 166 This command automates the startup of these processes using a wide
167 167 range of startup methods (SSH, local processes, PBS, mpiexec,
168 168 Windows HPC Server 2008). To start a cluster with 4 engines on your
169 169 local host simply do "ipcluster start -n 4". For more complex usage
170 170 you will typically do "ipcluster create -p mycluster", then edit
171 171 configuration files, followed by "ipcluster start -p mycluster -n 4".
172 172 """
173 173
174 174
175 175 class IPClusterApp(ApplicationWithClusterDir):
176 176
177 177 name = u'ipcluster'
178 178 description = _description
179 179 config_file_name = default_config_file_name
180 180 default_log_level = logging.INFO
181 181 auto_create_cluster_dir = False
182 182
183 183 def create_default_config(self):
184 184 super(IPClusterApp, self).create_default_config()
185 185 self.default_config.Global.controller_launcher = \
186 186 'IPython.kernel.launcher.LocalControllerLauncher'
187 187 self.default_config.Global.engine_launcher = \
188 188 'IPython.kernel.launcher.LocalEngineSetLauncher'
189 189 self.default_config.Global.n = 2
190 190 self.default_config.Global.reset_config = False
191 191 self.default_config.Global.clean_logs = True
192 192 self.default_config.Global.signal = 2
193 193 self.default_config.Global.daemonize = False
194 194
195 195 def create_command_line_config(self):
196 196 """Create and return a command line config loader."""
197 197 return IPClusterCLLoader(
198 198 description=self.description,
199 199 version=release.version
200 200 )
201 201
202 202 def find_resources(self):
203 203 subcommand = self.command_line_config.Global.subcommand
204 204 if subcommand=='list':
205 205 self.list_cluster_dirs()
206 206 # Exit immediately because there is nothing left to do.
207 207 self.exit()
208 208 elif subcommand=='create':
209 209 self.auto_create_cluster_dir = True
210 210 super(IPClusterApp, self).find_resources()
211 211 elif subcommand=='start' or subcommand=='stop':
212 212 self.auto_create_cluster_dir = True
213 213 try:
214 214 super(IPClusterApp, self).find_resources()
215 215 except ClusterDirError:
216 216 raise ClusterDirError(
217 217 "Could not find a cluster directory. A cluster dir must "
218 218 "be created before running 'ipcluster start'. Do "
219 219 "'ipcluster create -h' or 'ipcluster list -h' for more "
220 220 "information about creating and listing cluster dirs."
221 221 )
222 222
223 223 def list_cluster_dirs(self):
224 224 # Find the search paths
225 225 cluster_dir_paths = os.environ.get('IPCLUSTER_DIR_PATH','')
226 226 if cluster_dir_paths:
227 227 cluster_dir_paths = cluster_dir_paths.split(':')
228 228 else:
229 229 cluster_dir_paths = []
230 230 try:
231 231 ipython_dir = self.command_line_config.Global.ipython_dir
232 232 except AttributeError:
233 233 ipython_dir = self.default_config.Global.ipython_dir
234 234 paths = [os.getcwd(), ipython_dir] + \
235 235 cluster_dir_paths
236 236 paths = list(set(paths))
237 237
238 238 self.log.info('Searching for cluster dirs in paths: %r' % paths)
239 239 for path in paths:
240 240 files = os.listdir(path)
241 241 for f in files:
242 242 full_path = os.path.join(path, f)
243 243 if os.path.isdir(full_path) and f.startswith('cluster_'):
244 244 profile = full_path.split('_')[-1]
245 245 start_cmd = 'ipcluster start -p %s -n 4' % profile
246 246 print start_cmd + " ==> " + full_path
247 247
248 248 def pre_construct(self):
249 249 # IPClusterApp.pre_construct() is where we cd to the working directory.
250 250 super(IPClusterApp, self).pre_construct()
251 251 config = self.master_config
252 252 try:
253 253 daemon = config.Global.daemonize
254 254 if daemon:
255 255 config.Global.log_to_file = True
256 256 except AttributeError:
257 257 pass
258 258
259 259 def construct(self):
260 260 config = self.master_config
261 261 subcmd = config.Global.subcommand
262 262 reset = config.Global.reset_config
263 263 if subcmd == 'list':
264 264 return
265 265 if subcmd == 'create':
266 266 self.log.info('Copying default config files to cluster directory '
267 267 '[overwrite=%r]' % (reset,))
268 268 self.cluster_dir_obj.copy_all_config_files(overwrite=reset)
269 269 if subcmd =='start':
270 270 self.cluster_dir_obj.copy_all_config_files(overwrite=False)
271 271 self.start_logging()
272 272 reactor.callWhenRunning(self.start_launchers)
273 273
274 274 def start_launchers(self):
275 275 config = self.master_config
276 276
277 277 # Create the launchers. In both bases, we set the work_dir of
278 278 # the launcher to the cluster_dir. This is where the launcher's
279 279 # subprocesses will be launched. It is not where the controller
280 280 # and engine will be launched.
281 281 el_class = import_item(config.Global.engine_launcher)
282 282 self.engine_launcher = el_class(
283 283 work_dir=self.cluster_dir, config=config
284 284 )
285 285 cl_class = import_item(config.Global.controller_launcher)
286 286 self.controller_launcher = cl_class(
287 287 work_dir=self.cluster_dir, config=config
288 288 )
289 289
290 290 # Setup signals
291 291 signal.signal(signal.SIGINT, self.sigint_handler)
292 292
293 293 # Setup the observing of stopping. If the controller dies, shut
294 294 # everything down as that will be completely fatal for the engines.
295 295 d1 = self.controller_launcher.observe_stop()
296 296 d1.addCallback(self.stop_launchers)
297 297 # But, we don't monitor the stopping of engines. An engine dying
298 298 # is just fine and in principle a user could start a new engine.
299 299 # Also, if we did monitor engine stopping, it is difficult to
300 300 # know what to do when only some engines die. Currently, the
301 301 # observing of engine stopping is inconsistent. Some launchers
302 302 # might trigger on a single engine stopping, other wait until
303 303 # all stop. TODO: think more about how to handle this.
304 304
305 305 # Start the controller and engines
306 306 self._stopping = False # Make sure stop_launchers is not called 2x.
307 307 d = self.start_controller()
308 308 d.addCallback(self.start_engines)
309 309 d.addCallback(self.startup_message)
310 310 # If the controller or engines fail to start, stop everything
311 311 d.addErrback(self.stop_launchers)
312 312 return d
313 313
314 314 def startup_message(self, r=None):
315 315 log.msg("IPython cluster: started")
316 316 return r
317 317
318 318 def start_controller(self, r=None):
319 319 # log.msg("In start_controller")
320 320 config = self.master_config
321 321 d = self.controller_launcher.start(
322 322 cluster_dir=config.Global.cluster_dir
323 323 )
324 324 return d
325 325
326 326 def start_engines(self, r=None):
327 327 # log.msg("In start_engines")
328 328 config = self.master_config
329 329 d = self.engine_launcher.start(
330 330 config.Global.n,
331 331 cluster_dir=config.Global.cluster_dir
332 332 )
333 333 return d
334 334
335 335 def stop_controller(self, r=None):
336 336 # log.msg("In stop_controller")
337 337 if self.controller_launcher.running:
338 338 d = self.controller_launcher.stop()
339 339 d.addErrback(self.log_err)
340 340 return d
341 341 else:
342 342 return defer.succeed(None)
343 343
344 344 def stop_engines(self, r=None):
345 345 # log.msg("In stop_engines")
346 346 if self.engine_launcher.running:
347 347 d = self.engine_launcher.stop()
348 348 d.addErrback(self.log_err)
349 349 return d
350 350 else:
351 351 return defer.succeed(None)
352 352
353 353 def log_err(self, f):
354 354 log.msg(f.getTraceback())
355 355 return None
356 356
357 357 def stop_launchers(self, r=None):
358 358 if not self._stopping:
359 359 self._stopping = True
360 360 if isinstance(r, failure.Failure):
361 361 log.msg('Unexpected error in ipcluster:')
362 362 log.msg(r.getTraceback())
363 363 log.msg("IPython cluster: stopping")
364 self.stop_engines()
365 self.stop_controller()
364 # These return deferreds. We are not doing anything with them
365 # but we are holding refs to them as a reminder that they
366 # do return deferreds.
367 d1 = self.stop_engines()
368 d2 = self.stop_controller()
366 369 # Wait a few seconds to let things shut down.
367 370 reactor.callLater(4.0, reactor.stop)
368 371
369 372 def sigint_handler(self, signum, frame):
370 373 self.stop_launchers()
371 374
372 375 def start_logging(self):
373 376 # Remove old log files of the controller and engine
374 377 if self.master_config.Global.clean_logs:
375 378 log_dir = self.master_config.Global.log_dir
376 379 for f in os.listdir(log_dir):
377 380 if f.startswith('ipengine' + '-'):
378 381 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
379 382 os.remove(os.path.join(log_dir, f))
380 383 if f.startswith('ipcontroller' + '-'):
381 384 if f.endswith('.log') or f.endswith('.out') or f.endswith('.err'):
382 385 os.remove(os.path.join(log_dir, f))
383 386 # This will remote old log files for ipcluster itself
384 387 super(IPClusterApp, self).start_logging()
385 388
386 389 def start_app(self):
387 390 """Start the application, depending on what subcommand is used."""
388 391 subcmd = self.master_config.Global.subcommand
389 392 if subcmd=='create' or subcmd=='list':
390 393 return
391 394 elif subcmd=='start':
392 395 self.start_app_start()
393 396 elif subcmd=='stop':
394 397 self.start_app_stop()
395 398
396 399 def start_app_start(self):
397 400 """Start the app for the start subcommand."""
398 401 config = self.master_config
399 402 # First see if the cluster is already running
400 403 try:
401 404 pid = self.get_pid_from_file()
402 405 except PIDFileError:
403 406 pass
404 407 else:
405 408 self.log.critical(
406 409 'Cluster is already running with [pid=%s]. '
407 410 'use "ipcluster stop" to stop the cluster.' % pid
408 411 )
409 412 # Here I exit with a unusual exit status that other processes
410 413 # can watch for to learn how I existed.
411 414 self.exit(ALREADY_STARTED)
412 415
413 416 # Now log and daemonize
414 417 self.log.info(
415 418 'Starting ipcluster with [daemon=%r]' % config.Global.daemonize
416 419 )
417 420 # TODO: Get daemonize working on Windows or as a Windows Server.
418 421 if config.Global.daemonize:
419 422 if os.name=='posix':
420 423 daemonize()
421 424
422 425 # Now write the new pid file AFTER our new forked pid is active.
423 426 self.write_pid_file()
424 427 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
425 428 reactor.run()
426 429
427 430 def start_app_stop(self):
428 431 """Start the app for the stop subcommand."""
429 432 config = self.master_config
430 433 try:
431 434 pid = self.get_pid_from_file()
432 435 except PIDFileError:
433 436 self.log.critical(
434 437 'Problem reading pid file, cluster is probably not running.'
435 438 )
436 439 # Here I exit with a unusual exit status that other processes
437 440 # can watch for to learn how I existed.
438 441 self.exit(ALREADY_STOPPED)
439 442 else:
440 443 if os.name=='posix':
441 444 sig = config.Global.signal
442 445 self.log.info(
443 446 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
444 447 )
445 448 os.kill(pid, sig)
446 449 elif os.name=='nt':
447 450 # As of right now, we don't support daemonize on Windows, so
448 451 # stop will not do anything. Minimally, it should clean up the
449 452 # old .pid files.
450 453 self.remove_pid_file()
451 454
452 455 def launch_new_instance():
453 456 """Create and run the IPython cluster."""
454 457 app = IPClusterApp()
455 458 app.start()
456 459
457 460
458 461 if __name__ == '__main__':
459 462 launch_new_instance()
460 463
@@ -1,182 +1,185 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 A module to change reload() so that it acts recursively.
4 To enable it type:
5 >>> import __builtin__, deepreload
6 >>> __builtin__.reload = deepreload.reload
4 To enable it type::
7 5
8 You can then disable it with:
9 >>> __builtin__.reload = deepreload.original_reload
6 import __builtin__, deepreload
7 __builtin__.reload = deepreload.reload
8
9 You can then disable it with::
10
11 __builtin__.reload = deepreload.original_reload
10 12
11 Alternatively, you can add a dreload builtin alongside normal reload with:
12 >>> __builtin__.dreload = deepreload.reload
13 Alternatively, you can add a dreload builtin alongside normal reload with::
14
15 __builtin__.dreload = deepreload.reload
13 16
14 17 This code is almost entirely based on knee.py from the standard library.
15 18 """
16 19
17 20 #*****************************************************************************
18 21 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
19 22 #
20 23 # Distributed under the terms of the BSD License. The full license is in
21 24 # the file COPYING, distributed as part of this software.
22 25 #*****************************************************************************
23 26
24 27 import __builtin__
25 28 import imp
26 29 import sys
27 30
28 31 # Replacement for __import__()
29 32 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
30 33 # For now level is ignored, it's just there to prevent crash
31 34 # with from __future__ import absolute_import
32 35 parent = determine_parent(globals)
33 36 q, tail = find_head_package(parent, name)
34 37 m = load_tail(q, tail)
35 38 if not fromlist:
36 39 return q
37 40 if hasattr(m, "__path__"):
38 41 ensure_fromlist(m, fromlist)
39 42 return m
40 43
41 44 def determine_parent(globals):
42 45 if not globals or not globals.has_key("__name__"):
43 46 return None
44 47 pname = globals['__name__']
45 48 if globals.has_key("__path__"):
46 49 parent = sys.modules[pname]
47 50 assert globals is parent.__dict__
48 51 return parent
49 52 if '.' in pname:
50 53 i = pname.rfind('.')
51 54 pname = pname[:i]
52 55 parent = sys.modules[pname]
53 56 assert parent.__name__ == pname
54 57 return parent
55 58 return None
56 59
57 60 def find_head_package(parent, name):
58 61 # Import the first
59 62 if '.' in name:
60 63 # 'some.nested.package' -> head = 'some', tail = 'nested.package'
61 64 i = name.find('.')
62 65 head = name[:i]
63 66 tail = name[i+1:]
64 67 else:
65 68 # 'packagename' -> head = 'packagename', tail = ''
66 69 head = name
67 70 tail = ""
68 71 if parent:
69 72 # If this is a subpackage then qname = parent's name + head
70 73 qname = "%s.%s" % (parent.__name__, head)
71 74 else:
72 75 qname = head
73 76 q = import_module(head, qname, parent)
74 77 if q: return q, tail
75 78 if parent:
76 79 qname = head
77 80 parent = None
78 81 q = import_module(head, qname, parent)
79 82 if q: return q, tail
80 83 raise ImportError, "No module named " + qname
81 84
82 85 def load_tail(q, tail):
83 86 m = q
84 87 while tail:
85 88 i = tail.find('.')
86 89 if i < 0: i = len(tail)
87 90 head, tail = tail[:i], tail[i+1:]
88 91
89 92 # fperez: fix dotted.name reloading failures by changing:
90 93 #mname = "%s.%s" % (m.__name__, head)
91 94 # to:
92 95 mname = m.__name__
93 96 # This needs more testing!!! (I don't understand this module too well)
94 97
95 98 #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg
96 99 m = import_module(head, mname, m)
97 100 if not m:
98 101 raise ImportError, "No module named " + mname
99 102 return m
100 103
101 104 def ensure_fromlist(m, fromlist, recursive=0):
102 105 for sub in fromlist:
103 106 if sub == "*":
104 107 if not recursive:
105 108 try:
106 109 all = m.__all__
107 110 except AttributeError:
108 111 pass
109 112 else:
110 113 ensure_fromlist(m, all, 1)
111 114 continue
112 115 if sub != "*" and not hasattr(m, sub):
113 116 subname = "%s.%s" % (m.__name__, sub)
114 117 submod = import_module(sub, subname, m)
115 118 if not submod:
116 119 raise ImportError, "No module named " + subname
117 120
118 121 # Need to keep track of what we've already reloaded to prevent cyclic evil
119 122 found_now = {}
120 123
121 124 def import_module(partname, fqname, parent):
122 125 global found_now
123 126 if found_now.has_key(fqname):
124 127 try:
125 128 return sys.modules[fqname]
126 129 except KeyError:
127 130 pass
128 131
129 132 print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \
130 133 #sys.displayhook is sys.__displayhook__
131 134
132 135 found_now[fqname] = 1
133 136 try:
134 137 fp, pathname, stuff = imp.find_module(partname,
135 138 parent and parent.__path__)
136 139 except ImportError:
137 140 return None
138 141
139 142 try:
140 143 m = imp.load_module(fqname, fp, pathname, stuff)
141 144 finally:
142 145 if fp: fp.close()
143 146
144 147 if parent:
145 148 setattr(parent, partname, m)
146 149
147 150 return m
148 151
149 152 def deep_reload_hook(module):
150 153 name = module.__name__
151 154 if '.' not in name:
152 155 return import_module(name, name, None)
153 156 i = name.rfind('.')
154 157 pname = name[:i]
155 158 parent = sys.modules[pname]
156 159 return import_module(name[i+1:], name, parent)
157 160
158 161 # Save the original hooks
159 162 original_reload = __builtin__.reload
160 163
161 164 # Replacement for reload()
162 165 def reload(module, exclude=['sys', '__builtin__', '__main__']):
163 166 """Recursively reload all modules used in the given module. Optionally
164 167 takes a list of modules to exclude from reloading. The default exclude
165 168 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
166 169 display, exception, and io hooks.
167 170 """
168 171 global found_now
169 172 for i in exclude:
170 173 found_now[i] = 1
171 174 original_import = __builtin__.__import__
172 175 __builtin__.__import__ = deep_import_hook
173 176 try:
174 177 ret = deep_reload_hook(module)
175 178 finally:
176 179 __builtin__.__import__ = original_import
177 180 found_now = {}
178 181 return ret
179 182
180 183 # Uncomment the following to automatically activate deep reloading whenever
181 184 # this module is imported
182 185 #__builtin__.reload = reload
@@ -1,172 +1,174 b''
1 1 """Global IPython app to support test running.
2 2
3 3 We must start our own ipython object and heavily muck with it so that all the
4 4 modifications IPython makes to system behavior don't send the doctest machinery
5 5 into a fit. This code should be considered a gross hack, but it gets the job
6 6 done.
7 7 """
8 8
9 9 from __future__ import absolute_import
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2009 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import __builtin__
23 23 import commands
24 24 import os
25 25 import sys
26 26
27 27 from . import tools
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Functions
31 31 #-----------------------------------------------------------------------------
32 32
33 33 # Hack to modify the %run command so we can sync the user's namespace with the
34 34 # test globals. Once we move over to a clean magic system, this will be done
35 35 # with much less ugliness.
36 36
37 37 class py_file_finder(object):
38 38 def __init__(self,test_filename):
39 39 self.test_filename = test_filename
40 40
41 41 def __call__(self,name):
42 42 from IPython.utils.path import get_py_filename
43 43 try:
44 44 return get_py_filename(name)
45 45 except IOError:
46 46 test_dir = os.path.dirname(self.test_filename)
47 47 new_path = os.path.join(test_dir,name)
48 48 return get_py_filename(new_path)
49 49
50 50
51 51 def _run_ns_sync(self,arg_s,runner=None):
52 52 """Modified version of %run that syncs testing namespaces.
53 53
54 54 This is strictly needed for running doctests that call %run.
55 55 """
56 56 #print >> sys.stderr, 'in run_ns_sync', arg_s # dbg
57 57
58 58 _ip = get_ipython()
59 59 finder = py_file_finder(arg_s)
60 60 out = _ip.magic_run_ori(arg_s,runner,finder)
61 61 return out
62 62
63 63
64 64 class ipnsdict(dict):
65 65 """A special subclass of dict for use as an IPython namespace in doctests.
66 66
67 67 This subclass adds a simple checkpointing capability so that when testing
68 68 machinery clears it (we use it as the test execution context), it doesn't
69 69 get completely destroyed.
70 70 """
71 71
72 72 def __init__(self,*a):
73 73 dict.__init__(self,*a)
74 74 self._savedict = {}
75 75
76 76 def clear(self):
77 77 dict.clear(self)
78 78 self.update(self._savedict)
79 79
80 80 def _checkpoint(self):
81 81 self._savedict.clear()
82 82 self._savedict.update(self)
83 83
84 84 def update(self,other):
85 85 self._checkpoint()
86 86 dict.update(self,other)
87 87
88 88 # If '_' is in the namespace, python won't set it when executing code,
89 89 # and we have examples that test it. So we ensure that the namespace
90 90 # is always 'clean' of it before it's used for test code execution.
91 91 self.pop('_',None)
92 92
93 93 # The builtins namespace must *always* be the real __builtin__ module,
94 94 # else weird stuff happens. The main ipython code does have provisions
95 95 # to ensure this after %run, but since in this class we do some
96 96 # aggressive low-level cleaning of the execution namespace, we need to
97 97 # correct for that ourselves, to ensure consitency with the 'real'
98 98 # ipython.
99 99 self['__builtins__'] = __builtin__
100
100
101 101
102 102 def get_ipython():
103 103 # This will get replaced by the real thing once we start IPython below
104 104 return start_ipython()
105 105
106
106 107 def start_ipython():
107 108 """Start a global IPython shell, which we need for IPython-specific syntax.
108 109 """
109 110 global get_ipython
110 111
111 112 # This function should only ever run once!
112 if hasattr(start_ipython,'already_called'):
113 if hasattr(start_ipython, 'already_called'):
113 114 return
114 115 start_ipython.already_called = True
115 116
116 117 # Ok, first time we're called, go ahead
117 from IPython.core import ipapp, iplib
118 from IPython.core import iplib
118 119
119 120 def xsys(cmd):
120 121 """Execute a command and print its output.
121 122
122 123 This is just a convenience function to replace the IPython system call
123 124 with one that is more doctest-friendly.
124 125 """
125 126 cmd = _ip.var_expand(cmd,depth=1)
126 127 sys.stdout.write(commands.getoutput(cmd))
127 128 sys.stdout.flush()
128 129
129 130 # Store certain global objects that IPython modifies
130 131 _displayhook = sys.displayhook
131 132 _excepthook = sys.excepthook
132 133 _main = sys.modules.get('__main__')
133 134
134 135 # Create custom argv and namespaces for our IPython to be test-friendly
135 argv = tools.default_argv()
136 user_ns, global_ns = iplib.make_user_namespaces(ipnsdict(), {})
137
136 config = tools.default_config()
137
138 138 # Create and initialize our test-friendly IPython instance.
139 ip = ipapp.IPythonApp(argv, user_ns=user_ns, user_global_ns=global_ns)
140 ip.initialize()
139 shell = iplib.InteractiveShell(
140 parent=None, config=config,
141 user_ns=ipnsdict(), user_global_ns={}
142 )
141 143
142 144 # A few more tweaks needed for playing nicely with doctests...
143 145
144 146 # These traps are normally only active for interactive use, set them
145 147 # permanently since we'll be mocking interactive sessions.
146 ip.shell.builtin_trap.set()
148 shell.builtin_trap.set()
147 149
148 150 # Set error printing to stdout so nose can doctest exceptions
149 ip.shell.InteractiveTB.out_stream = 'stdout'
151 shell.InteractiveTB.out_stream = 'stdout'
150 152
151 153 # Modify the IPython system call with one that uses getoutput, so that we
152 154 # can capture subcommands and print them to Python's stdout, otherwise the
153 155 # doctest machinery would miss them.
154 ip.shell.system = xsys
156 shell.system = xsys
155 157
156 158 # IPython is ready, now clean up some global state...
157 159
158 160 # Deactivate the various python system hooks added by ipython for
159 161 # interactive convenience so we don't confuse the doctest system
160 162 sys.modules['__main__'] = _main
161 163 sys.displayhook = _displayhook
162 164 sys.excepthook = _excepthook
163 165
164 166 # So that ipython magics and aliases can be doctested (they work by making
165 167 # a call into a global _ip object). Also make the top-level get_ipython
166 168 # now return this without recursively calling here again.
167 _ip = ip.shell
169 _ip = shell
168 170 get_ipython = _ip.get_ipython
169 171 __builtin__._ip = _ip
170 172 __builtin__.get_ipython = get_ipython
171 173
172 174 return _ip
@@ -1,488 +1,488 b''
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Test Suite Runner.
3 3
4 4 This module provides a main entry point to a user script to test IPython
5 5 itself from the command line. There are two ways of running this script:
6 6
7 7 1. With the syntax `iptest all`. This runs our entire test suite by
8 8 calling this script (with different arguments) or trial recursively. This
9 9 causes modules and package to be tested in different processes, using nose
10 10 or trial where appropriate.
11 11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 12 the script simply calls nose, but with special command line flags and
13 13 plugins loaded.
14 14
15 15 For now, this script requires that both nose and twisted are installed. This
16 16 will change in the future.
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Copyright (C) 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 # Stdlib
31 31 import os
32 32 import os.path as path
33 33 import signal
34 34 import sys
35 35 import subprocess
36 36 import tempfile
37 37 import time
38 38 import warnings
39 39
40 40
41 41 # Ugly, but necessary hack to ensure the test suite finds our version of
42 42 # IPython and not a possibly different one that may exist system-wide.
43 43 # Note that this must be done here, so the imports that come next work
44 44 # correctly even if IPython isn't installed yet.
45 45 p = os.path
46 46 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
47 47 sys.path.insert(0, ippath)
48 48
49 49 # Note: monkeypatch!
50 50 # We need to monkeypatch a small problem in nose itself first, before importing
51 51 # it for actual use. This should get into nose upstream, but its release cycle
52 52 # is slow and we need it for our parametric tests to work correctly.
53 53 from IPython.testing import nosepatch
54 54 # Now, proceed to import nose itself
55 55 import nose.plugins.builtin
56 56 from nose.core import TestProgram
57 57
58 58 # Our own imports
59 59 from IPython.utils.path import get_ipython_module_path
60 60 from IPython.utils.process import find_cmd, pycmd2argv
61 61 from IPython.utils.sysinfo import sys_info
62 62
63 63 from IPython.testing import globalipapp
64 64 from IPython.testing.plugin.ipdoctest import IPythonDoctest
65 65
66 66 pjoin = path.join
67 67
68 68
69 69 #-----------------------------------------------------------------------------
70 70 # Globals
71 71 #-----------------------------------------------------------------------------
72 72
73 73 # By default, we assume IPython has been installed. But if the test suite is
74 74 # being run from a source tree that has NOT been installed yet, this flag can
75 75 # be set to False by the entry point scripts, to let us know that we must call
76 76 # the source tree versions of the scripts which manipulate sys.path instead of
77 77 # assuming that things exist system-wide.
78 78 INSTALLED = True
79 79
80 80 #-----------------------------------------------------------------------------
81 81 # Warnings control
82 82 #-----------------------------------------------------------------------------
83 83 # Twisted generates annoying warnings with Python 2.6, as will do other code
84 84 # that imports 'sets' as of today
85 85 warnings.filterwarnings('ignore', 'the sets module is deprecated',
86 86 DeprecationWarning )
87 87
88 88 # This one also comes from Twisted
89 89 warnings.filterwarnings('ignore', 'the sha module is deprecated',
90 90 DeprecationWarning)
91 91
92 92 # Wx on Fedora11 spits these out
93 93 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
94 94 UserWarning)
95 95
96 96 #-----------------------------------------------------------------------------
97 97 # Logic for skipping doctests
98 98 #-----------------------------------------------------------------------------
99 99
100 100 def test_for(mod):
101 101 """Test to see if mod is importable."""
102 102 try:
103 103 __import__(mod)
104 104 except (ImportError, RuntimeError):
105 105 # GTK reports Runtime error if it can't be initialized even if it's
106 106 # importable.
107 107 return False
108 108 else:
109 109 return True
110 110
111 111 # Global dict where we can store information on what we have and what we don't
112 112 # have available at test run time
113 113 have = {}
114 114
115 115 have['curses'] = test_for('_curses')
116 116 have['wx'] = test_for('wx')
117 117 have['wx.aui'] = test_for('wx.aui')
118 118 have['zope.interface'] = test_for('zope.interface')
119 119 have['twisted'] = test_for('twisted')
120 120 have['foolscap'] = test_for('foolscap')
121 121 have['objc'] = test_for('objc')
122 122 have['pexpect'] = test_for('pexpect')
123 123 have['gtk'] = test_for('gtk')
124 124 have['gobject'] = test_for('gobject')
125 125
126 126 #-----------------------------------------------------------------------------
127 127 # Functions and classes
128 128 #-----------------------------------------------------------------------------
129 129
130 130 def report():
131 131 """Return a string with a summary report of test-related variables."""
132 132
133 133 out = [ sys_info() ]
134 134
135 135 out.append('\nRunning from an installed IPython: %s\n' % INSTALLED)
136 136
137 137 avail = []
138 138 not_avail = []
139 139
140 140 for k, is_avail in have.items():
141 141 if is_avail:
142 142 avail.append(k)
143 143 else:
144 144 not_avail.append(k)
145 145
146 146 if avail:
147 147 out.append('\nTools and libraries available at test time:\n')
148 148 avail.sort()
149 149 out.append(' ' + ' '.join(avail)+'\n')
150 150
151 151 if not_avail:
152 152 out.append('\nTools and libraries NOT available at test time:\n')
153 153 not_avail.sort()
154 154 out.append(' ' + ' '.join(not_avail)+'\n')
155 155
156 156 return ''.join(out)
157 157
158 158
159 159 def make_exclude():
160 160 """Make patterns of modules and packages to exclude from testing.
161 161
162 162 For the IPythonDoctest plugin, we need to exclude certain patterns that
163 163 cause testing problems. We should strive to minimize the number of
164 164 skipped modules, since this means untested code. As the testing
165 165 machinery solidifies, this list should eventually become empty.
166 166 These modules and packages will NOT get scanned by nose at all for tests.
167 167 """
168 168 # Simple utility to make IPython paths more readably, we need a lot of
169 169 # these below
170 170 ipjoin = lambda *paths: pjoin('IPython', *paths)
171 171
172 172 exclusions = [ipjoin('external'),
173 173 ipjoin('frontend', 'process', 'winprocess.py'),
174 174 # Deprecated old Shell and iplib modules, skip to avoid
175 175 # warnings
176 176 ipjoin('Shell'),
177 177 ipjoin('iplib'),
178 178 pjoin('IPython_doctest_plugin'),
179 179 ipjoin('quarantine'),
180 180 ipjoin('deathrow'),
181 181 ipjoin('testing', 'attic'),
182 182 # This guy is probably attic material
183 183 ipjoin('testing', 'mkdoctests'),
184 184 # Testing inputhook will need a lot of thought, to figure out
185 185 # how to have tests that don't lock up with the gui event
186 186 # loops in the picture
187 187 ipjoin('lib', 'inputhook'),
188 188 # Config files aren't really importable stand-alone
189 189 ipjoin('config', 'default'),
190 190 ipjoin('config', 'profile'),
191 191 ]
192 192
193 193 if not have['wx']:
194 194 exclusions.append(ipjoin('gui'))
195 195 exclusions.append(ipjoin('frontend', 'wx'))
196 196 exclusions.append(ipjoin('lib', 'inputhookwx'))
197 197
198 198 if not have['gtk'] or not have['gobject']:
199 199 exclusions.append(ipjoin('lib', 'inputhookgtk'))
200 200
201 201 if not have['wx.aui']:
202 202 exclusions.append(ipjoin('gui', 'wx', 'wxIPython'))
203 203
204 204 if not have['objc']:
205 205 exclusions.append(ipjoin('frontend', 'cocoa'))
206 206
207 207 # These have to be skipped on win32 because the use echo, rm, cd, etc.
208 208 # See ticket https://bugs.launchpad.net/bugs/366982
209 209 if sys.platform == 'win32':
210 210 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
211 211 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
212 212
213 213 if not have['pexpect']:
214 214 exclusions.extend([ipjoin('scripts', 'irunner'),
215 215 ipjoin('lib', 'irunner')])
216 216
217 217 # This is scary. We still have things in frontend and testing that
218 218 # are being tested by nose that use twisted. We need to rethink
219 219 # how we are isolating dependencies in testing.
220 220 if not (have['twisted'] and have['zope.interface'] and have['foolscap']):
221 221 exclusions.extend(
222 222 [ipjoin('frontend', 'asyncfrontendbase'),
223 223 ipjoin('frontend', 'prefilterfrontend'),
224 224 ipjoin('frontend', 'frontendbase'),
225 225 ipjoin('frontend', 'linefrontendbase'),
226 226 ipjoin('frontend', 'tests', 'test_linefrontend'),
227 227 ipjoin('frontend', 'tests', 'test_frontendbase'),
228 228 ipjoin('frontend', 'tests', 'test_prefilterfrontend'),
229 229 ipjoin('frontend', 'tests', 'test_asyncfrontendbase'),
230 230 ipjoin('testing', 'parametric'),
231 231 ipjoin('testing', 'util'),
232 232 ipjoin('testing', 'tests', 'test_decorators_trial'),
233 233 ] )
234 234
235 235 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
236 236 if sys.platform == 'win32':
237 237 exclusions = [s.replace('\\','\\\\') for s in exclusions]
238 238
239 239 return exclusions
240 240
241 241
242 242 class IPTester(object):
243 243 """Call that calls iptest or trial in a subprocess.
244 244 """
245 245 #: string, name of test runner that will be called
246 246 runner = None
247 247 #: list, parameters for test runner
248 248 params = None
249 249 #: list, arguments of system call to be made to call test runner
250 250 call_args = None
251 251 #: list, process ids of subprocesses we start (for cleanup)
252 252 pids = None
253 253
254 254 def __init__(self, runner='iptest', params=None):
255 255 """Create new test runner."""
256 256 p = os.path
257 257 if runner == 'iptest':
258 258 if INSTALLED:
259 259 iptest_app = get_ipython_module_path('IPython.testing.iptest')
260 260 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
261 261 else:
262 262 # Find our own 'iptest' script OS-level entry point. Don't
263 263 # look system-wide, so we are sure we pick up *this one*. And
264 264 # pass through to subprocess call our own sys.argv
265 265 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
266 266 script = p.join(ippath, 'iptest.py')
267 267 self.runner = pycmd2argv(script) + sys.argv[1:]
268 268
269 269 else:
270 270 # For trial, it needs to be installed system-wide
271 271 self.runner = pycmd2argv(p.abspath(find_cmd('trial')))
272 272 if params is None:
273 273 params = []
274 274 if isinstance(params, str):
275 275 params = [params]
276 276 self.params = params
277 277
278 278 # Assemble call
279 279 self.call_args = self.runner+self.params
280 280
281 281 # Store pids of anything we start to clean up on deletion, if possible
282 282 # (on posix only, since win32 has no os.kill)
283 283 self.pids = []
284 284
285 285 if sys.platform == 'win32':
286 286 def _run_cmd(self):
287 287 # On Windows, use os.system instead of subprocess.call, because I
288 288 # was having problems with subprocess and I just don't know enough
289 289 # about win32 to debug this reliably. Os.system may be the 'old
290 290 # fashioned' way to do it, but it works just fine. If someone
291 291 # later can clean this up that's fine, as long as the tests run
292 292 # reliably in win32.
293 293 return os.system(' '.join(self.call_args))
294 294 else:
295 295 def _run_cmd(self):
296 296 #print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
297 297 subp = subprocess.Popen(self.call_args)
298 298 self.pids.append(subp.pid)
299 299 # If this fails, the pid will be left in self.pids and cleaned up
300 300 # later, but if the wait call succeeds, then we can clear the
301 301 # stored pid.
302 302 retcode = subp.wait()
303 303 self.pids.pop()
304 304 return retcode
305 305
306 306 def run(self):
307 307 """Run the stored commands"""
308 308 try:
309 309 return self._run_cmd()
310 310 except:
311 311 import traceback
312 312 traceback.print_exc()
313 313 return 1 # signal failure
314 314
315 315 def __del__(self):
316 316 """Cleanup on exit by killing any leftover processes."""
317 317
318 318 if not hasattr(os, 'kill'):
319 319 return
320 320
321 321 for pid in self.pids:
322 322 try:
323 323 print 'Cleaning stale PID:', pid
324 324 os.kill(pid, signal.SIGKILL)
325 325 except OSError:
326 326 # This is just a best effort, if we fail or the process was
327 327 # really gone, ignore it.
328 328 pass
329 329
330 330
331 331 def make_runners():
332 332 """Define the top-level packages that need to be tested.
333 333 """
334 334
335 335 # Packages to be tested via nose, that only depend on the stdlib
336 336 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
337 337 'scripts', 'testing', 'utils' ]
338 338 # The machinery in kernel needs twisted for real testing
339 339 trial_pkg_names = []
340 340
341 341 if have['wx']:
342 342 nose_pkg_names.append('gui')
343 343
344 344 # And add twisted ones if conditions are met
345 345 if have['zope.interface'] and have['twisted'] and have['foolscap']:
346 # Note that we list the kernel here, though the bulk of it is
347 # twisted-based, because nose picks up doctests that twisted doesn't.
348 nose_pkg_names.append('kernel')
346 # We only list IPython.kernel for testing using twisted.trial as
347 # nose and twisted.trial have conflicts that make the testing system
348 # unstable.
349 349 trial_pkg_names.append('kernel')
350 350
351 351 # For debugging this code, only load quick stuff
352 352 #nose_pkg_names = ['core', 'extensions'] # dbg
353 353 #trial_pkg_names = [] # dbg
354 354
355 355 # Make fully qualified package names prepending 'IPython.' to our name lists
356 356 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
357 357 trial_packages = ['IPython.%s' % m for m in trial_pkg_names ]
358 358
359 359 # Make runners
360 360 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
361 361 runners.extend([ (v, IPTester('trial', params=v)) for v in trial_packages ])
362 362
363 363 return runners
364 364
365 365
366 366 def run_iptest():
367 367 """Run the IPython test suite using nose.
368 368
369 369 This function is called when this script is **not** called with the form
370 370 `iptest all`. It simply calls nose with appropriate command line flags
371 371 and accepts all of the standard nose arguments.
372 372 """
373 373
374 374 warnings.filterwarnings('ignore',
375 375 'This will be removed soon. Use IPython.testing.util instead')
376 376
377 377 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
378 378
379 379 # Loading ipdoctest causes problems with Twisted, but
380 380 # our test suite runner now separates things and runs
381 381 # all Twisted tests with trial.
382 382 '--with-ipdoctest',
383 383 '--ipdoctest-tests','--ipdoctest-extension=txt',
384 384
385 385 # We add --exe because of setuptools' imbecility (it
386 386 # blindly does chmod +x on ALL files). Nose does the
387 387 # right thing and it tries to avoid executables,
388 388 # setuptools unfortunately forces our hand here. This
389 389 # has been discussed on the distutils list and the
390 390 # setuptools devs refuse to fix this problem!
391 391 '--exe',
392 392 ]
393 393
394 394 if nose.__version__ >= '0.11':
395 395 # I don't fully understand why we need this one, but depending on what
396 396 # directory the test suite is run from, if we don't give it, 0 tests
397 397 # get run. Specifically, if the test suite is run from the source dir
398 398 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
399 399 # even if the same call done in this directory works fine). It appears
400 400 # that if the requested package is in the current dir, nose bails early
401 401 # by default. Since it's otherwise harmless, leave it in by default
402 402 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
403 403 argv.append('--traverse-namespace')
404 404
405 405 # Construct list of plugins, omitting the existing doctest plugin, which
406 406 # ours replaces (and extends).
407 407 plugins = [IPythonDoctest(make_exclude())]
408 408 for p in nose.plugins.builtin.plugins:
409 409 plug = p()
410 410 if plug.name == 'doctest':
411 411 continue
412 412 plugins.append(plug)
413 413
414 414 # We need a global ipython running in this process
415 415 globalipapp.start_ipython()
416 416 # Now nose can run
417 417 TestProgram(argv=argv, plugins=plugins)
418 418
419 419
420 420 def run_iptestall():
421 421 """Run the entire IPython test suite by calling nose and trial.
422 422
423 423 This function constructs :class:`IPTester` instances for all IPython
424 424 modules and package and then runs each of them. This causes the modules
425 425 and packages of IPython to be tested each in their own subprocess using
426 426 nose or twisted.trial appropriately.
427 427 """
428 428
429 429 runners = make_runners()
430 430
431 431 # Run the test runners in a temporary dir so we can nuke it when finished
432 432 # to clean up any junk files left over by accident. This also makes it
433 433 # robust against being run in non-writeable directories by mistake, as the
434 434 # temp dir will always be user-writeable.
435 435 curdir = os.getcwd()
436 436 testdir = tempfile.gettempdir()
437 437 os.chdir(testdir)
438 438
439 439 # Run all test runners, tracking execution time
440 440 failed = []
441 441 t_start = time.time()
442 442 try:
443 443 for (name, runner) in runners:
444 444 print '*'*70
445 445 print 'IPython test group:',name
446 446 res = runner.run()
447 447 if res:
448 448 failed.append( (name, runner) )
449 449 finally:
450 450 os.chdir(curdir)
451 451 t_end = time.time()
452 452 t_tests = t_end - t_start
453 453 nrunners = len(runners)
454 454 nfail = len(failed)
455 455 # summarize results
456 456 print
457 457 print '*'*70
458 458 print 'Test suite completed for system with the following information:'
459 459 print report()
460 460 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
461 461 print
462 462 print 'Status:'
463 463 if not failed:
464 464 print 'OK'
465 465 else:
466 466 # If anything went wrong, point out what command to rerun manually to
467 467 # see the actual errors and individual summary
468 468 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
469 469 for name, failed_runner in failed:
470 470 print '-'*40
471 471 print 'Runner failed:',name
472 472 print 'You may wish to rerun this one individually, with:'
473 473 print ' '.join(failed_runner.call_args)
474 474 print
475 475
476 476
477 477 def main():
478 478 for arg in sys.argv[1:]:
479 479 if arg.startswith('IPython'):
480 480 # This is in-process
481 481 run_iptest()
482 482 else:
483 483 # This starts subprocesses
484 484 run_iptestall()
485 485
486 486
487 487 if __name__ == '__main__':
488 488 main()
@@ -1,282 +1,292 b''
1 1 """Generic testing tools that do NOT depend on Twisted.
2 2
3 3 In particular, this module exposes a set of top-level assert* functions that
4 4 can be used in place of nose.tools.assert* in method generators (the ones in
5 5 nose can not, at least as of nose 0.10.4).
6 6
7 7 Note: our testing package contains testing.util, which does depend on Twisted
8 8 and provides utilities for tests that manage Deferreds. All testing support
9 9 tools that only depend on nose, IPython or the standard library should go here
10 10 instead.
11 11
12 12
13 13 Authors
14 14 -------
15 15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 16 """
17 17
18 18 from __future__ import absolute_import
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Copyright (C) 2009 The IPython Development Team
22 22 #
23 23 # Distributed under the terms of the BSD License. The full license is in
24 24 # the file COPYING, distributed as part of this software.
25 25 #-----------------------------------------------------------------------------
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Imports
29 29 #-----------------------------------------------------------------------------
30 30
31 31 import os
32 32 import re
33 33 import sys
34 34
35 35 try:
36 36 # These tools are used by parts of the runtime, so we make the nose
37 37 # dependency optional at this point. Nose is a hard dependency to run the
38 38 # test suite, but NOT to use ipython itself.
39 39 import nose.tools as nt
40 40 has_nose = True
41 41 except ImportError:
42 42 has_nose = False
43 43
44 from IPython.config.loader import Config
44 45 from IPython.utils.process import find_cmd, getoutputerror
45 46 from IPython.utils.text import list_strings
46 47 from IPython.utils.io import temp_pyfile
47 48
48 49 from . import decorators as dec
49 50
50 51 #-----------------------------------------------------------------------------
51 52 # Globals
52 53 #-----------------------------------------------------------------------------
53 54
54 55 # By default, we assume IPython has been installed. But if the test suite is
55 56 # being run from a source tree that has NOT been installed yet, this flag can
56 57 # be set to False by the entry point scripts, to let us know that we must call
57 58 # the source tree versions of the scripts which manipulate sys.path instead of
58 59 # assuming that things exist system-wide.
59 60 INSTALLED = True
60 61
61 62 # Make a bunch of nose.tools assert wrappers that can be used in test
62 63 # generators. This will expose an assert* function for each one in nose.tools.
63 64
64 65 _tpl = """
65 66 def %(name)s(*a,**kw):
66 67 return nt.%(name)s(*a,**kw)
67 68 """
68 69
69 70 if has_nose:
70 71 for _x in [a for a in dir(nt) if a.startswith('assert')]:
71 72 exec _tpl % dict(name=_x)
72 73
73 74 #-----------------------------------------------------------------------------
74 75 # Functions and classes
75 76 #-----------------------------------------------------------------------------
76 77
77 78 # The docstring for full_path doctests differently on win32 (different path
78 79 # separator) so just skip the doctest there. The example remains informative.
79 80 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
80 81
81 82 @doctest_deco
82 83 def full_path(startPath,files):
83 84 """Make full paths for all the listed files, based on startPath.
84 85
85 86 Only the base part of startPath is kept, since this routine is typically
86 87 used with a script's __file__ variable as startPath. The base of startPath
87 88 is then prepended to all the listed files, forming the output list.
88 89
89 90 Parameters
90 91 ----------
91 92 startPath : string
92 93 Initial path to use as the base for the results. This path is split
93 94 using os.path.split() and only its first component is kept.
94 95
95 96 files : string or list
96 97 One or more files.
97 98
98 99 Examples
99 100 --------
100 101
101 102 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
102 103 ['/foo/a.txt', '/foo/b.txt']
103 104
104 105 >>> full_path('/foo',['a.txt','b.txt'])
105 106 ['/a.txt', '/b.txt']
106 107
107 108 If a single file is given, the output is still a list:
108 109 >>> full_path('/foo','a.txt')
109 110 ['/a.txt']
110 111 """
111 112
112 113 files = list_strings(files)
113 114 base = os.path.split(startPath)[0]
114 115 return [ os.path.join(base,f) for f in files ]
115 116
116 117
117 118 def parse_test_output(txt):
118 119 """Parse the output of a test run and return errors, failures.
119 120
120 121 Parameters
121 122 ----------
122 123 txt : str
123 124 Text output of a test run, assumed to contain a line of one of the
124 125 following forms::
125 126 'FAILED (errors=1)'
126 127 'FAILED (failures=1)'
127 128 'FAILED (errors=1, failures=1)'
128 129
129 130 Returns
130 131 -------
131 132 nerr, nfail: number of errors and failures.
132 133 """
133 134
134 135 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
135 136 if err_m:
136 137 nerr = int(err_m.group(1))
137 138 nfail = 0
138 139 return nerr, nfail
139 140
140 141 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
141 142 if fail_m:
142 143 nerr = 0
143 144 nfail = int(fail_m.group(1))
144 145 return nerr, nfail
145 146
146 147 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
147 148 re.MULTILINE)
148 149 if both_m:
149 150 nerr = int(both_m.group(1))
150 151 nfail = int(both_m.group(2))
151 152 return nerr, nfail
152 153
153 154 # If the input didn't match any of these forms, assume no error/failures
154 155 return 0, 0
155 156
156 157
157 158 # So nose doesn't think this is a test
158 159 parse_test_output.__test__ = False
159 160
160 161
161 162 def default_argv():
162 163 """Return a valid default argv for creating testing instances of ipython"""
163 164
164 165 return ['--quick', # so no config file is loaded
165 166 # Other defaults to minimize side effects on stdout
166 167 '--colors=NoColor', '--no-term-title','--no-banner',
167 168 '--autocall=0']
168
169
170
171 def default_config():
172 """Return a config object with good defaults for testing."""
173 config = Config()
174 config.InteractiveShell.colors = 'NoColor'
175 config.InteractiveShell.term_title = False,
176 config.InteractiveShell.autocall = 0
177 return config
178
169 179
170 180 def ipexec(fname, options=None):
171 181 """Utility to call 'ipython filename'.
172 182
173 183 Starts IPython witha minimal and safe configuration to make startup as fast
174 184 as possible.
175 185
176 186 Note that this starts IPython in a subprocess!
177 187
178 188 Parameters
179 189 ----------
180 190 fname : str
181 191 Name of file to be executed (should have .py or .ipy extension).
182 192
183 193 options : optional, list
184 194 Extra command-line flags to be passed to IPython.
185 195
186 196 Returns
187 197 -------
188 198 (stdout, stderr) of ipython subprocess.
189 199 """
190 200 if options is None: options = []
191 201
192 202 # For these subprocess calls, eliminate all prompt printing so we only see
193 203 # output from script execution
194 204 prompt_opts = ['--prompt-in1=""', '--prompt-in2=""', '--prompt-out=""']
195 205 cmdargs = ' '.join(default_argv() + prompt_opts + options)
196 206
197 207 _ip = get_ipython()
198 208 test_dir = os.path.dirname(__file__)
199 209
200 210 # Find the ipython script from the package we're using, so that the test
201 211 # suite can be run from the source tree without an installed IPython
202 212 p = os.path
203 213 if INSTALLED:
204 214 ipython_cmd = find_cmd('ipython')
205 215 else:
206 216 ippath = p.abspath(p.join(p.dirname(__file__),'..','..'))
207 217 ipython_script = p.join(ippath, 'ipython.py')
208 218 ipython_cmd = 'python "%s"' % ipython_script
209 219 # Absolute path for filename
210 220 full_fname = p.join(test_dir, fname)
211 221 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
212 222 #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
213 223 return getoutputerror(full_cmd)
214 224
215 225
216 226 def ipexec_validate(fname, expected_out, expected_err='',
217 227 options=None):
218 228 """Utility to call 'ipython filename' and validate output/error.
219 229
220 230 This function raises an AssertionError if the validation fails.
221 231
222 232 Note that this starts IPython in a subprocess!
223 233
224 234 Parameters
225 235 ----------
226 236 fname : str
227 237 Name of the file to be executed (should have .py or .ipy extension).
228 238
229 239 expected_out : str
230 240 Expected stdout of the process.
231 241
232 242 expected_err : optional, str
233 243 Expected stderr of the process.
234 244
235 245 options : optional, list
236 246 Extra command-line flags to be passed to IPython.
237 247
238 248 Returns
239 249 -------
240 250 None
241 251 """
242 252
243 253 import nose.tools as nt
244 254
245 255 out, err = ipexec(fname)
246 256 #print 'OUT', out # dbg
247 257 #print 'ERR', err # dbg
248 258 # If there are any errors, we must check those befor stdout, as they may be
249 259 # more informative than simply having an empty stdout.
250 260 if err:
251 261 if expected_err:
252 262 nt.assert_equals(err.strip(), expected_err.strip())
253 263 else:
254 264 raise ValueError('Running file %r produced error: %r' %
255 265 (fname, err))
256 266 # If no errors or output on stderr was expected, match stdout
257 267 nt.assert_equals(out.strip(), expected_out.strip())
258 268
259 269
260 270 class TempFileMixin(object):
261 271 """Utility class to create temporary Python/IPython files.
262 272
263 273 Meant as a mixin class for test cases."""
264 274
265 275 def mktmp(self, src, ext='.py'):
266 276 """Make a valid python temp file."""
267 277 fname, f = temp_pyfile(src, ext)
268 278 self.tmpfile = f
269 279 self.fname = fname
270 280
271 281 def teardown(self):
272 282 if hasattr(self, 'tmpfile'):
273 283 # If the tmpfile wasn't made because of skipped tests, like in
274 284 # win32, there's nothing to cleanup.
275 285 self.tmpfile.close()
276 286 try:
277 287 os.unlink(self.fname)
278 288 except:
279 289 # On Windows, even though we close the file, we still can't
280 290 # delete it. I have no clue why
281 291 pass
282 292
@@ -1,342 +1,340 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for path handling.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2009 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import os
18 18 import sys
19 19
20 20 import IPython
21 21 from IPython.utils.process import xsys
22 22 from IPython.utils.importstring import import_item
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Code
26 26 #-----------------------------------------------------------------------------
27 27
28 28
29 29 def _get_long_path_name(path):
30 30 """Dummy no-op."""
31 31 return path
32 32
33 33
34 34 if sys.platform == 'win32':
35 35 def _get_long_path_name(path):
36 36 """Get a long path name (expand ~) on Windows using ctypes.
37 37
38 38 Examples
39 39 --------
40 40
41 41 >>> get_long_path_name('c:\\docume~1')
42 42 u'c:\\\\Documents and Settings'
43 43
44 44 """
45 45 try:
46 46 import ctypes
47 47 except ImportError:
48 48 raise ImportError('you need to have ctypes installed for this to work')
49 49 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
50 50 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
51 51 ctypes.c_uint ]
52 52
53 53 buf = ctypes.create_unicode_buffer(260)
54 54 rv = _GetLongPathName(path, buf, 260)
55 55 if rv == 0 or rv > 260:
56 56 return path
57 57 else:
58 58 return buf.value
59 59
60 60
61 61 def get_long_path_name(path):
62 62 """Expand a path into its long form.
63 63
64 64 On Windows this expands any ~ in the paths. On other platforms, it is
65 65 a null operation.
66 66 """
67 67 return _get_long_path_name(path)
68 68
69 69
70 70 def get_py_filename(name):
71 71 """Return a valid python filename in the current directory.
72 72
73 73 If the given name is not a file, it adds '.py' and searches again.
74 74 Raises IOError with an informative message if the file isn't found."""
75 75
76 76 name = os.path.expanduser(name)
77 77 if not os.path.isfile(name) and not name.endswith('.py'):
78 78 name += '.py'
79 79 if os.path.isfile(name):
80 80 return name
81 81 else:
82 82 raise IOError,'File `%s` not found.' % name
83 83
84 84
85 85 def filefind(filename, path_dirs=None):
86 86 """Find a file by looking through a sequence of paths.
87 87
88 88 This iterates through a sequence of paths looking for a file and returns
89 89 the full, absolute path of the first occurence of the file. If no set of
90 90 path dirs is given, the filename is tested as is, after running through
91 91 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
92 92
93 93 filefind('myfile.txt')
94 94
95 95 will find the file in the current working dir, but::
96 96
97 97 filefind('~/myfile.txt')
98 98
99 99 Will find the file in the users home directory. This function does not
100 100 automatically try any paths, such as the cwd or the user's home directory.
101 101
102 102 Parameters
103 103 ----------
104 104 filename : str
105 105 The filename to look for.
106 106 path_dirs : str, None or sequence of str
107 107 The sequence of paths to look for the file in. If None, the filename
108 108 need to be absolute or be in the cwd. If a string, the string is
109 109 put into a sequence and the searched. If a sequence, walk through
110 110 each element and join with ``filename``, calling :func:`expandvars`
111 111 and :func:`expanduser` before testing for existence.
112 112
113 113 Returns
114 114 -------
115 115 Raises :exc:`IOError` or returns absolute path to file.
116 116 """
117 117
118 118 # If paths are quoted, abspath gets confused, strip them...
119 119 filename = filename.strip('"').strip("'")
120 120 # If the input is an absolute path, just check it exists
121 121 if os.path.isabs(filename) and os.path.isfile(filename):
122 122 return filename
123 123
124 124 if path_dirs is None:
125 125 path_dirs = ("",)
126 126 elif isinstance(path_dirs, basestring):
127 127 path_dirs = (path_dirs,)
128 128
129 129 for path in path_dirs:
130 130 if path == '.': path = os.getcwd()
131 131 testname = expand_path(os.path.join(path, filename))
132 132 if os.path.isfile(testname):
133 133 return os.path.abspath(testname)
134 134
135 135 raise IOError("File %r does not exist in any of the search paths: %r" %
136 136 (filename, path_dirs) )
137 137
138 138
139 139 class HomeDirError(Exception):
140 140 pass
141 141
142 142
143 143 def get_home_dir():
144 144 """Return the closest possible equivalent to a 'home' directory.
145 145
146 146 * On POSIX, we try $HOME.
147 147 * On Windows we try:
148 148 - %HOME%: rare, but some people with unix-like setups may have defined it
149 149 - %HOMESHARE%
150 150 - %HOMEDRIVE\%HOMEPATH%
151 151 - %USERPROFILE%
152 152 - Registry hack
153 153 * On Dos C:\
154 154
155 155 Currently only Posix and NT are implemented, a HomeDirError exception is
156 156 raised for all other OSes.
157 157 """
158 158
159 159 isdir = os.path.isdir
160 160 env = os.environ
161 161
162 162 # first, check py2exe distribution root directory for _ipython.
163 163 # This overrides all. Normally does not exist.
164 164
165 165 if hasattr(sys, "frozen"): #Is frozen by py2exe
166 166 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
167 167 root, rest = IPython.__file__.lower().split('library.zip')
168 168 else:
169 169 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
170 170 root=os.path.abspath(root).rstrip('\\')
171 171 if isdir(os.path.join(root, '_ipython')):
172 172 os.environ["IPYKITROOT"] = root
173 173 return root.decode(sys.getfilesystemencoding())
174 174
175 175 if os.name == 'posix':
176 176 # Linux, Unix, AIX, OS X
177 177 try:
178 178 homedir = env['HOME']
179 179 except KeyError:
180 180 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
181 181 else:
182 182 return homedir.decode(sys.getfilesystemencoding())
183 183 elif os.name == 'nt':
184 184 # Now for win9x, XP, Vista, 7?
185 185 # For some strange reason all of these return 'nt' for os.name.
186 186 # First look for a network home directory. This will return the UNC
187 187 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
188 188 # is needed when running IPython on cluster where all paths have to
189 189 # be UNC.
190 190 try:
191 191 # A user with a lot of unix tools in win32 may have defined $HOME,
192 192 # honor it if it exists, but otherwise let the more typical
193 193 # %HOMESHARE% variable be used.
194 194 homedir = env.get('HOME')
195 195 if homedir is None:
196 196 homedir = env['HOMESHARE']
197 197 except KeyError:
198 198 pass
199 199 else:
200 200 if isdir(homedir):
201 201 return homedir.decode(sys.getfilesystemencoding())
202 202
203 203 # Now look for a local home directory
204 204 try:
205 205 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
206 206 except KeyError:
207 207 pass
208 208 else:
209 209 if isdir(homedir):
210 210 return homedir.decode(sys.getfilesystemencoding())
211 211
212 212 # Now the users profile directory
213 213 try:
214 214 homedir = os.path.join(env['USERPROFILE'])
215 215 except KeyError:
216 216 pass
217 217 else:
218 218 if isdir(homedir):
219 219 return homedir.decode(sys.getfilesystemencoding())
220 220
221 221 # Use the registry to get the 'My Documents' folder.
222 222 try:
223 223 import _winreg as wreg
224 224 key = wreg.OpenKey(
225 225 wreg.HKEY_CURRENT_USER,
226 226 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
227 227 )
228 228 homedir = wreg.QueryValueEx(key,'Personal')[0]
229 229 key.Close()
230 230 except:
231 231 pass
232 232 else:
233 233 if isdir(homedir):
234 234 return homedir.decode(sys.getfilesystemencoding())
235 235
236 236 # If all else fails, raise HomeDirError
237 237 raise HomeDirError('No valid home directory could be found')
238 238 elif os.name == 'dos':
239 239 # Desperate, may do absurd things in classic MacOS. May work under DOS.
240 240 return 'C:\\'.decode(sys.getfilesystemencoding())
241 241 else:
242 242 raise HomeDirError('No valid home directory could be found for your OS')
243 243
244 244
245 245 def get_ipython_dir():
246 246 """Get the IPython directory for this platform and user.
247 247
248 248 This uses the logic in `get_home_dir` to find the home directory
249 249 and the adds .ipython to the end of the path.
250 250 """
251 251 ipdir_def = '.ipython'
252 print get_home_dir
253 252 home_dir = get_home_dir()
254 print home_dir
255 253 #import pdb; pdb.set_trace() # dbg
256 254 ipdir = os.environ.get(
257 255 'IPYTHON_DIR', os.environ.get(
258 256 'IPYTHONDIR', os.path.join(home_dir, ipdir_def)
259 257 )
260 258 )
261 259 return ipdir.decode(sys.getfilesystemencoding())
262 260
263 261
264 262 def get_ipython_package_dir():
265 263 """Get the base directory where IPython itself is installed."""
266 264 ipdir = os.path.dirname(IPython.__file__)
267 265 return ipdir.decode(sys.getfilesystemencoding())
268 266
269 267
270 268 def get_ipython_module_path(module_str):
271 269 """Find the path to an IPython module in this version of IPython.
272 270
273 271 This will always find the version of the module that is in this importable
274 272 IPython package. This will always return the path to the ``.py``
275 273 version of the module.
276 274 """
277 275 if module_str == 'IPython':
278 276 return os.path.join(get_ipython_package_dir(), '__init__.py')
279 277 mod = import_item(module_str)
280 278 the_path = mod.__file__.replace('.pyc', '.py')
281 279 the_path = the_path.replace('.pyo', '.py')
282 280 return the_path.decode(sys.getfilesystemencoding())
283 281
284 282
285 283 def expand_path(s):
286 284 """Expand $VARS and ~names in a string, like a shell
287 285
288 286 :Examples:
289 287
290 288 In [2]: os.environ['FOO']='test'
291 289
292 290 In [3]: expand_path('variable FOO is $FOO')
293 291 Out[3]: 'variable FOO is test'
294 292 """
295 293 # This is a pretty subtle hack. When expand user is given a UNC path
296 294 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
297 295 # the $ to get (\\server\share\%username%). I think it considered $
298 296 # alone an empty var. But, we need the $ to remains there (it indicates
299 297 # a hidden share).
300 298 if os.name=='nt':
301 299 s = s.replace('$\\', 'IPYTHON_TEMP')
302 300 s = os.path.expandvars(os.path.expanduser(s))
303 301 if os.name=='nt':
304 302 s = s.replace('IPYTHON_TEMP', '$\\')
305 303 return s
306 304
307 305
308 306 def target_outdated(target,deps):
309 307 """Determine whether a target is out of date.
310 308
311 309 target_outdated(target,deps) -> 1/0
312 310
313 311 deps: list of filenames which MUST exist.
314 312 target: single filename which may or may not exist.
315 313
316 314 If target doesn't exist or is older than any file listed in deps, return
317 315 true, otherwise return false.
318 316 """
319 317 try:
320 318 target_time = os.path.getmtime(target)
321 319 except os.error:
322 320 return 1
323 321 for dep in deps:
324 322 dep_time = os.path.getmtime(dep)
325 323 if dep_time > target_time:
326 324 #print "For target",target,"Dep failed:",dep # dbg
327 325 #print "times (dep,tar):",dep_time,target_time # dbg
328 326 return 1
329 327 return 0
330 328
331 329
332 330 def target_update(target,deps,cmd):
333 331 """Update a target with a given command given a list of dependencies.
334 332
335 333 target_update(target,deps,cmd) -> runs cmd if target is outdated.
336 334
337 335 This is just a wrapper around target_outdated() which calls the given
338 336 command if target is outdated."""
339 337
340 338 if target_outdated(target,deps):
341 339 xsys(cmd)
342 340
@@ -1,388 +1,388 b''
1 1 .. _testing:
2 2
3 3 ==========================================
4 4 Testing IPython for users and developers
5 5 ==========================================
6 6
7 7 Overview
8 8 ========
9 9
10 10 It is extremely important that all code contributed to IPython has tests.
11 11 Tests should be written as unittests, doctests or other entities that the
12 12 IPython test system can detect. See below for more details on this.
13 13
14 14 Each subpackage in IPython should have its own :file:`tests` directory that
15 15 contains all of the tests for that subpackage. All of the files in the
16 16 :file:`tests` directory should have the word "tests" in them to enable
17 17 the testing framework to find them.
18 18
19 19 In docstrings, examples (either using IPython prompts like ``In [1]:`` or
20 20 'classic' python ``>>>`` ones) can and should be included. The testing system
21 21 will detect them as doctests and will run them; it offers control to skip parts
22 22 or all of a specific doctest if the example is meant to be informative but
23 23 shows non-reproducible information (like filesystem data).
24 24
25 25 If a subpackage has any dependencies beyond the Python standard library, the
26 26 tests for that subpackage should be skipped if the dependencies are not found.
27 27 This is very important so users don't get tests failing simply because they
28 28 don't have dependencies.
29 29
30 30 The testing system we use is a hybrid of nose_ and Twisted's trial_ test runner.
31 31 We use both because nose detects more things than Twisted and allows for more
32 32 flexible (and lighter-weight) ways of writing tests; in particular we've
33 33 developed a nose plugin that allows us to paste verbatim IPython sessions and
34 34 test them as doctests, which is extremely important for us. But the parts of
35 35 IPython that depend on Twisted must be tested using trial, because only trial
36 36 manages the Twisted reactor correctly.
37 37
38 38 .. _nose: http://code.google.com/p/python-nose
39 39 .. _trial: http://twistedmatrix.com/trac/wiki/TwistedTrial
40 40
41 41
42 42 For the impatient: running the tests
43 43 ====================================
44 44
45 45 You can run IPython from the source download directory without even installing
46 46 it system-wide or having configure anything, by typing at the terminal:
47 47
48 48 .. code-block:: bash
49 49
50 50 python ipython.py
51 51
52 52 and similarly, you can execute the built-in test suite with:
53 53
54 54 .. code-block:: bash
55 55
56 56 python iptest.py
57 57
58 58
59 59 This script manages intelligently both nose and trial, choosing the correct
60 60 test system for each of IPython's components.
61 61
62 62 Once you have either installed it or at least configured your system to be
63 63 able to import IPython, you can run the tests with:
64 64
65 65 .. code-block:: bash
66 66
67 67 python -c "import IPython; IPython.test()"
68 68
69 69 This should work as long as IPython can be imported, even if you haven't fully
70 70 installed the user-facing scripts yet (common in a development environment).
71 71 Once you have installed IPython, you will have available system-wide a script
72 72 called :file:`iptest` that does the exact same as the :file:`iptest.py` script
73 73 in the source directory, so you can then test simply with:
74 74
75 75 .. code-block:: bash
76 76
77 77 iptest [args]
78 78
79 79
80 80 Regardless of how you run things, you should eventually see something like:
81 81
82 82 .. code-block:: bash
83 83
84 84 **********************************************************************
85 85 Test suite completed for system with the following information:
86 86 IPython version: 0.11.bzr.r1340
87 87 BZR revision : 1340
88 88 Platform info : os.name -> posix, sys.platform -> linux2
89 89 : Linux-2.6.31-17-generic-i686-with-Ubuntu-9.10-karmic
90 90 Python info : 2.6.4 (r264:75706, Dec 7 2009, 18:45:15)
91 91 [GCC 4.4.1]
92 92
93 93 Running from an installed IPython: True
94 94
95 95 Tools and libraries available at test time:
96 96 curses foolscap gobject gtk pexpect twisted wx wx.aui zope.interface
97 97
98 98 Tools and libraries NOT available at test time:
99 99 objc
100 100
101 101 Ran 11 test groups in 36.244s
102 102
103 103 Status:
104 104 OK
105 105
106 106 If not, there will be a message indicating which test group failed and how to
107 107 rerun that group individually. For example, this tests the
108 108 :mod:`IPython.utils` subpackage, the :option:`-v` option shows progress
109 109 indicators:
110 110
111 111 .. code-block:: bash
112 112
113 113 $ python iptest.py -v IPython.utils
114 114 ..........................SS..SSS............................S.S...
115 115 .........................................................
116 116 ----------------------------------------------------------------------
117 117 Ran 125 tests in 0.119s
118 118
119 119 OK (SKIP=7)
120 120
121 121
122 122 Because the IPython test machinery is based on nose, you can use all nose
123 123 options and syntax, typing ``iptest -h`` shows all available options. For
124 124 example, this lets you run the specific test :func:`test_rehashx` inside the
125 125 :mod:`test_magic` module:
126 126
127 127 .. code-block:: bash
128 128
129 129 $ python iptest.py -vv IPython.core.tests.test_magic:test_rehashx
130 130 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
131 131 IPython.core.tests.test_magic.test_rehashx(True,) ... ok
132 132
133 133 ----------------------------------------------------------------------
134 134 Ran 2 tests in 0.100s
135 135
136 136 OK
137 137
138 138 When developing, the :option:`--pdb` and :option:`--pdb-failures` of nose are
139 139 particularly useful, these drop you into an interactive pdb session at the
140 140 point of the error or failure respectively.
141 141
142 142 To run Twisted-using tests, use the :command:`trial` command on a per file or
143 143 package basis:
144 144
145 145 .. code-block:: bash
146 146
147 147 trial IPython.kernel
148 148
149 149
150 150 For developers: writing tests
151 151 =============================
152 152
153 153 By now IPython has a reasonable test suite, so the best way to see what's
154 154 available is to look at the :file:`tests` directory in most subpackages. But
155 155 here are a few pointers to make the process easier.
156 156
157 157
158 158 Main tools: :mod:`IPython.testing`
159 159 ----------------------------------
160 160
161 161 The :mod:`IPython.testing` package is where all of the machinery to test
162 162 IPython (rather than the tests for its various parts) lives. In particular,
163 163 the :mod:`iptest` module in there has all the smarts to control the test
164 164 process. In there, the :func:`make_exclude` function is used to build a
165 165 blacklist of exclusions, these are modules that do not get even imported for
166 166 tests. This is important so that things that would fail to even import because
167 167 of missing dependencies don't give errors to end users, as we stated above.
168 168
169 169 The :mod:`decorators` module contains a lot of useful decorators, especially
170 170 useful to mark individual tests that should be skipped under certain conditions
171 171 (rather than blacklisting the package altogether because of a missing major
172 172 dependency).
173 173
174 174 Our nose plugin for doctests
175 175 ----------------------------
176 176
177 177 The :mod:`plugin` subpackage in testing contains a nose plugin called
178 178 :mod:`ipdoctest` that teaches nose about IPython syntax, so you can write
179 179 doctests with IPython prompts. You can also mark doctest output with ``#
180 180 random`` for the output corresponding to a single input to be ignored (stronger
181 181 than using ellipsis and useful to keep it as an example). If you want the
182 182 entire docstring to be executed but none of the output from any input to be
183 183 checked, you can use the ``# all-random`` marker. The
184 184 :mod:`IPython.testing.plugin.dtexample` module contains examples of how to use
185 185 these; for reference here is how to use ``# random``::
186 186
187 187 def ranfunc():
188 188 """A function with some random output.
189 189
190 190 Normal examples are verified as usual:
191 191 >>> 1+3
192 192 4
193 193
194 194 But if you put '# random' in the output, it is ignored:
195 195 >>> 1+3
196 196 junk goes here... # random
197 197
198 198 >>> 1+2
199 199 again, anything goes #random
200 200 if multiline, the random mark is only needed once.
201 201
202 202 >>> 1+2
203 203 You can also put the random marker at the end:
204 204 # random
205 205
206 206 >>> 1+2
207 207 # random
208 208 .. or at the beginning.
209 209
210 210 More correct input is properly verified:
211 211 >>> ranfunc()
212 212 'ranfunc'
213 213 """
214 214 return 'ranfunc'
215 215
216 216 and an example of ``# all-random``::
217 217
218 218 def random_all():
219 219 """A function where we ignore the output of ALL examples.
220 220
221 221 Examples:
222 222
223 223 # all-random
224 224
225 225 This mark tells the testing machinery that all subsequent examples
226 226 should be treated as random (ignoring their output). They are still
227 227 executed, so if a they raise an error, it will be detected as such,
228 228 but their output is completely ignored.
229 229
230 230 >>> 1+3
231 231 junk goes here...
232 232
233 233 >>> 1+3
234 234 klasdfj;
235 235
236 236 In [8]: print 'hello'
237 237 world # random
238 238
239 239 In [9]: iprand()
240 240 Out[9]: 'iprand'
241 241 """
242 242 return 'iprand'
243 243
244 244
245 245 When writing docstrings, you can use the ``@skip_doctest`` decorator to
246 246 indicate that a docstring should *not* be treated as a doctest at all. The
247 difference betwee ``# all-random`` and ``@skip_doctest`` is that the former
247 difference between ``# all-random`` and ``@skip_doctest`` is that the former
248 248 executes the example but ignores output, while the latter doesn't execute any
249 249 code. ``@skip_doctest`` should be used for docstrings whose examples are
250 250 purely informational.
251 251
252 252 If a given docstring fails under certain conditions but otherwise is a good
253 253 doctest, you can use code like the following, that relies on the 'null'
254 254 decorator to leave the docstring intact where it works as a test::
255 255
256 256 # The docstring for full_path doctests differently on win32 (different path
257 257 # separator) so just skip the doctest there, and use a null decorator
258 258 # elsewhere:
259 259
260 260 doctest_deco = dec.skip_doctest if sys.platform == 'win32' else dec.null_deco
261 261
262 262 @doctest_deco
263 263 def full_path(startPath,files):
264 264 """Make full paths for all the listed files, based on startPath..."""
265 265
266 266 # function body follows...
267 267
268 268 With our nose plugin that understands IPython syntax, an extremely effective
269 269 way to write tests is to simply copy and paste an interactive session into a
270 270 docstring. You can writing this type of test, where your docstring is meant
271 271 *only* as a test, by prefixing the function name with ``doctest_`` and leaving
272 272 its body *absolutely empty* other than the docstring. In
273 273 :mod:`IPython.core.tests.test_magic` you can find several examples of this, but
274 274 for completeness sake, your code should look like this (a simple case)::
275 275
276 276 def doctest_time():
277 277 """
278 278 In [10]: %time None
279 279 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
280 280 Wall time: 0.00 s
281 281 """
282 282
283 283 This function is only analyzed for its docstring but it is not considered a
284 284 separate test, which is why its body should be empty.
285 285
286 286
287 287 Parametric tests done right
288 288 ---------------------------
289 289
290 290 If you need to run multiple tests inside the same standalone function or method
291 291 of a :class:`unittest.TestCase` subclass, IPython provides the ``parametric``
292 292 decorator for this purpose. This is superior to how test generators work in
293 293 nose, because IPython's keeps intact your stack, which makes debugging vastly
294 294 easier. For example, these are some parametric tests both in class form and as
295 295 a standalone function (choose in each situation the style that best fits the
296 296 problem at hand, since both work)::
297 297
298 298 from IPython.testing import decorators as dec
299 299
300 300 def is_smaller(i,j):
301 301 assert i<j,"%s !< %s" % (i,j)
302 302
303 303 class Tester(ParametricTestCase):
304 304
305 305 def test_parametric(self):
306 306 yield is_smaller(3, 4)
307 307 x, y = 1, 2
308 308 yield is_smaller(x, y)
309 309
310 310 @dec.parametric
311 311 def test_par_standalone():
312 312 yield is_smaller(3, 4)
313 313 x, y = 1, 2
314 314 yield is_smaller(x, y)
315 315
316 316
317 317 Writing tests for Twisted-using code
318 318 ------------------------------------
319 319
320 320 Tests of Twisted [Twisted]_ using code should be written by subclassing the
321 321 ``TestCase`` class that comes with ``twisted.trial.unittest``. Furthermore, all
322 322 :class:`Deferred` instances that are created in the test must be properly
323 323 chained and the final one *must* be the return value of the test method.
324 324
325 325 .. note::
326 326
327 327 The best place to see how to use the testing tools, are the tests for these
328 328 tools themselves, which live in :mod:`IPython.testing.tests`.
329 329
330 330
331 331 Design requirements
332 332 ===================
333 333
334 334 This section is a set of notes on the key points of the IPython testing needs,
335 335 that were used when writing the system and should be kept for reference as it
336 336 eveolves.
337 337
338 338 Testing IPython in full requires modifications to the default behavior of nose
339 339 and doctest, because the IPython prompt is not recognized to determine Python
340 340 input, and because IPython admits user input that is not valid Python (things
341 341 like ``%magics`` and ``!system commands``.
342 342
343 343 We basically need to be able to test the following types of code:
344 344
345 345 1. Pure Python files containing normal tests. These are not a problem, since
346 346 Nose will pick them up as long as they conform to the (flexible) conventions
347 347 used by nose to recognize tests.
348 348
349 349 2. Python files containing doctests. Here, we have two possibilities:
350 350 - The prompts are the usual ``>>>`` and the input is pure Python.
351 351 - The prompts are of the form ``In [1]:`` and the input can contain extended
352 352 IPython expressions.
353 353
354 354 In the first case, Nose will recognize the doctests as long as it is called
355 355 with the ``--with-doctest`` flag. But the second case will likely require
356 356 modifications or the writing of a new doctest plugin for Nose that is
357 357 IPython-aware.
358 358
359 359 3. ReStructuredText files that contain code blocks. For this type of file, we
360 360 have three distinct possibilities for the code blocks:
361 361 - They use ``>>>`` prompts.
362 362 - They use ``In [1]:`` prompts.
363 363 - They are standalone blocks of pure Python code without any prompts.
364 364
365 365 The first two cases are similar to the situation #2 above, except that in
366 366 this case the doctests must be extracted from input code blocks using
367 367 docutils instead of from the Python docstrings.
368 368
369 369 In the third case, we must have a convention for distinguishing code blocks
370 370 that are meant for execution from others that may be snippets of shell code
371 371 or other examples not meant to be run. One possibility is to assume that
372 372 all indented code blocks are meant for execution, but to have a special
373 373 docutils directive for input that should not be executed.
374 374
375 375 For those code blocks that we will execute, the convention used will simply
376 376 be that they get called and are considered successful if they run to
377 377 completion without raising errors. This is similar to what Nose does for
378 378 standalone test functions, and by putting asserts or other forms of
379 379 exception-raising statements it becomes possible to have literate examples
380 380 that double as lightweight tests.
381 381
382 382 4. Extension modules with doctests in function and method docstrings.
383 383 Currently Nose simply can't find these docstrings correctly, because the
384 384 underlying doctest DocTestFinder object fails there. Similarly to #2 above,
385 385 the docstrings could have either pure python or IPython prompts.
386 386
387 387 Of these, only 3-c (reST with standalone code blocks) is not implemented at
388 388 this point.
@@ -1,642 +1,635 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Sphinx directive to support embedded IPython code.
3 3
4 4 This directive allows pasting of entire interactive IPython sessions, prompts
5 5 and all, and their code will actually get re-executed at doc build time, with
6 6 all prompts renumbered sequentially.
7 7
8 8 To enable this directive, simply list it in your Sphinx ``conf.py`` file
9 9 (making sure the directory where you placed it is visible to sphinx, as is
10 10 needed for all Sphinx directives).
11 11
12 12 By default this directive assumes that your prompts are unchanged IPython ones,
13 13 but this can be customized. For example, the following code in your Sphinx
14 14 config file will configure this directive for the following input/output
15 15 prompts ``Yade [1]:`` and ``-> [1]:``::
16 16
17 17 import ipython_directive as id
18 18 id.rgxin =re.compile(r'(?:In |Yade )\[(\d+)\]:\s?(.*)\s*')
19 19 id.rgxout=re.compile(r'(?:Out| -> )\[(\d+)\]:\s?(.*)\s*')
20 20 id.fmtin ='Yade [%d]:'
21 21 id.fmtout=' -> [%d]:'
22 22
23 23 from IPython import Config
24 24 id.CONFIG = Config(
25 25 prompt_in1="Yade [\#]:",
26 26 prompt_in2=" .\D..",
27 27 prompt_out=" -> [\#]:"
28 28 )
29 29 id.reconfig_shell()
30 30
31 31 import ipython_console_highlighting as ich
32 32 ich.IPythonConsoleLexer.input_prompt=
33 33 re.compile("(Yade \[[0-9]+\]: )|( \.\.\.+:)")
34 34 ich.IPythonConsoleLexer.output_prompt=
35 35 re.compile("(( -> )|(Out)\[[0-9]+\]: )|( \.\.\.+:)")
36 36 ich.IPythonConsoleLexer.continue_prompt=re.compile(" \.\.\.+:")
37 37
38 38
39 39 ToDo
40 40 ----
41 41
42 42 - Turn the ad-hoc test() function into a real test suite.
43 43 - Break up ipython-specific functionality from matplotlib stuff into better
44 44 separated code.
45 45 - Make sure %bookmarks used internally are removed on exit.
46 46
47 47
48 48 Authors
49 49 -------
50 50
51 51 - John D Hunter: orignal author.
52 52 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
53 53 - VΓ‘clavΕ milauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
54 54 """
55 55
56 56 #-----------------------------------------------------------------------------
57 57 # Imports
58 58 #-----------------------------------------------------------------------------
59 59
60 60 # Stdlib
61 61 import cStringIO
62 import imp
63 62 import os
64 63 import re
65 import shutil
66 64 import sys
67 import warnings
68 65
69 66 # To keep compatibility with various python versions
70 67 try:
71 68 from hashlib import md5
72 69 except ImportError:
73 70 from md5 import md5
74 71
75 72 # Third-party
76 73 import matplotlib
77 74 import sphinx
78 75 from docutils.parsers.rst import directives
79 76
80 77 matplotlib.use('Agg')
81 78
82 79 # Our own
83 from IPython import Config, IPythonApp
84 from IPython.utils.io import Term, Tee
80 from IPython import Config, InteractiveShell
81 from IPython.utils.io import Term
85 82
86 83 #-----------------------------------------------------------------------------
87 84 # Globals
88 85 #-----------------------------------------------------------------------------
89 86
90 87 sphinx_version = sphinx.__version__.split(".")
91 88 # The split is necessary for sphinx beta versions where the string is
92 89 # '6b1'
93 90 sphinx_version = tuple([int(re.split('[a-z]', x)[0])
94 91 for x in sphinx_version[:2]])
95 92
96 93 COMMENT, INPUT, OUTPUT = range(3)
97 94 CONFIG = Config()
98 95 rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*')
99 96 rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*')
100 97 fmtin = 'In [%d]:'
101 98 fmtout = 'Out[%d]:'
102 99
103 100 #-----------------------------------------------------------------------------
104 101 # Functions and class declarations
105 102 #-----------------------------------------------------------------------------
106 103 def block_parser(part):
107 104 """
108 105 part is a string of ipython text, comprised of at most one
109 106 input, one ouput, comments, and blank lines. The block parser
110 107 parses the text into a list of::
111 108
112 109 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
113 110
114 111 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
115 112 data is, depending on the type of token::
116 113
117 114 COMMENT : the comment string
118 115
119 116 INPUT: the (DECORATOR, INPUT_LINE, REST) where
120 117 DECORATOR: the input decorator (or None)
121 118 INPUT_LINE: the input as string (possibly multi-line)
122 119 REST : any stdout generated by the input line (not OUTPUT)
123 120
124 121
125 122 OUTPUT: the output string, possibly multi-line
126 123 """
127 124
128 125 block = []
129 126 lines = part.split('\n')
130 127 N = len(lines)
131 128 i = 0
132 129 decorator = None
133 130 while 1:
134 131
135 132 if i==N:
136 133 # nothing left to parse -- the last line
137 134 break
138 135
139 136 line = lines[i]
140 137 i += 1
141 138 line_stripped = line.strip()
142 139 if line_stripped.startswith('#'):
143 140 block.append((COMMENT, line))
144 141 continue
145 142
146 143 if line_stripped.startswith('@'):
147 144 # we're assuming at most one decorator -- may need to
148 145 # rethink
149 146 decorator = line_stripped
150 147 continue
151 148
152 149 # does this look like an input line?
153 150 matchin = rgxin.match(line)
154 151 if matchin:
155 152 lineno, inputline = int(matchin.group(1)), matchin.group(2)
156 153
157 154 # the ....: continuation string
158 155 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
159 156 Nc = len(continuation)
160 157 # input lines can continue on for more than one line, if
161 158 # we have a '\' line continuation char or a function call
162 159 # echo line 'print'. The input line can only be
163 160 # terminated by the end of the block or an output line, so
164 161 # we parse out the rest of the input line if it is
165 162 # multiline as well as any echo text
166 163
167 164 rest = []
168 165 while i<N:
169 166
170 167 # look ahead; if the next line is blank, or a comment, or
171 168 # an output line, we're done
172 169
173 170 nextline = lines[i]
174 171 matchout = rgxout.match(nextline)
175 172 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
176 173 if matchout or nextline.startswith('#'):
177 174 break
178 175 elif nextline.startswith(continuation):
179 176 inputline += '\n' + nextline[Nc:]
180 177 else:
181 178 rest.append(nextline)
182 179 i+= 1
183 180
184 181 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
185 182 continue
186 183
187 184 # if it looks like an output line grab all the text to the end
188 185 # of the block
189 186 matchout = rgxout.match(line)
190 187 if matchout:
191 188 lineno, output = int(matchout.group(1)), matchout.group(2)
192 189 if i<N-1:
193 190 output = '\n'.join([output] + lines[i:])
194 191
195 192 block.append((OUTPUT, output))
196 193 break
197 194
198 195 return block
199 196
200 197
201 198 class EmbeddedSphinxShell(object):
202 199 """An embedded IPython instance to run inside Sphinx"""
203 200
204 201 def __init__(self):
205 202
206 203 self.cout = cStringIO.StringIO()
207 204 Term.cout = self.cout
208 205 Term.cerr = self.cout
209 206
210 207 # For debugging, so we can see normal output, use this:
211 208 # from IPython.utils.io import Tee
212 209 #Term.cout = Tee(self.cout, channel='stdout') # dbg
213 210 #Term.cerr = Tee(self.cout, channel='stderr') # dbg
214 211
215 212 # Create config object for IPython
216 213 config = Config()
217 214 config.Global.display_banner = False
218 215 config.Global.exec_lines = ['import numpy as np',
219 216 'from pylab import *'
220 217 ]
221 218 config.InteractiveShell.autocall = False
222 219 config.InteractiveShell.autoindent = False
223 220 config.InteractiveShell.colors = 'NoColor'
224 221
225 # Merge global config which can be used to override.
226 config._merge(CONFIG)
227
228 222 # Create and initialize ipython, but don't start its mainloop
229 IP = IPythonApp(override_config=config)
230 IP.initialize()
223 IP = InteractiveShell(parent=None, config=config)
231 224
232 225 # Store a few parts of IPython we'll need.
233 self.IP = IP.shell
226 self.IP = IP
234 227 self.user_ns = self.IP.user_ns
235 228 self.user_global_ns = self.IP.user_global_ns
236 229
237 230 self.input = ''
238 231 self.output = ''
239 232
240 233 self.is_verbatim = False
241 234 self.is_doctest = False
242 235 self.is_suppress = False
243 236
244 237 # on the first call to the savefig decorator, we'll import
245 238 # pyplot as plt so we can make a call to the plt.gcf().savefig
246 239 self._pyplot_imported = False
247 240
248 241 # we need bookmark the current dir first so we can save
249 242 # relative to it
250 243 self.process_input_line('bookmark ipy_basedir')
251 244 self.cout.seek(0)
252 245 self.cout.truncate(0)
253 246
254 247 def process_input_line(self, line):
255 248 """process the input, capturing stdout"""
256 249 #print "input='%s'"%self.input
257 250 stdout = sys.stdout
258 251 try:
259 252 sys.stdout = self.cout
260 253 self.IP.push_line(line)
261 254 finally:
262 255 sys.stdout = stdout
263 256
264 257 # Callbacks for each type of token
265 258 def process_input(self, data, input_prompt, lineno):
266 259 """Process data block for INPUT token."""
267 260 decorator, input, rest = data
268 261 image_file = None
269 262 #print 'INPUT:', data # dbg
270 263 is_verbatim = decorator=='@verbatim' or self.is_verbatim
271 264 is_doctest = decorator=='@doctest' or self.is_doctest
272 265 is_suppress = decorator=='@suppress' or self.is_suppress
273 266 is_savefig = decorator is not None and \
274 267 decorator.startswith('@savefig')
275 268
276 269 input_lines = input.split('\n')
277 270
278 271 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
279 272 Nc = len(continuation)
280 273
281 274 if is_savefig:
282 275 saveargs = decorator.split(' ')
283 276 filename = saveargs[1]
284 277 outfile = os.path.join('_static/%s'%filename)
285 278 # build out an image directive like
286 279 # .. image:: somefile.png
287 280 # :width 4in
288 281 #
289 282 # from an input like
290 283 # savefig somefile.png width=4in
291 284 imagerows = ['.. image:: %s'%outfile]
292 285
293 286 for kwarg in saveargs[2:]:
294 287 arg, val = kwarg.split('=')
295 288 arg = arg.strip()
296 289 val = val.strip()
297 290 imagerows.append(' :%s: %s'%(arg, val))
298 291
299 292 image_file = outfile
300 293 image_directive = '\n'.join(imagerows)
301 294
302 295 # TODO: can we get "rest" from ipython
303 296 #self.process_input_line('\n'.join(input_lines))
304 297
305 298 ret = []
306 299 is_semicolon = False
307 300
308 301 for i, line in enumerate(input_lines):
309 302 if line.endswith(';'):
310 303 is_semicolon = True
311 304
312 305 if i==0:
313 306 # process the first input line
314 307 if is_verbatim:
315 308 self.process_input_line('')
316 309 else:
317 310 # only submit the line in non-verbatim mode
318 311 self.process_input_line(line)
319 312 formatted_line = '%s %s'%(input_prompt, line)
320 313 else:
321 314 # process a continuation line
322 315 if not is_verbatim:
323 316 self.process_input_line(line)
324 317
325 318 formatted_line = '%s %s'%(continuation, line)
326 319
327 320 if not is_suppress:
328 321 ret.append(formatted_line)
329 322
330 323 if not is_suppress:
331 324 if len(rest.strip()):
332 325 if is_verbatim:
333 326 # the "rest" is the standard output of the
334 327 # input, which needs to be added in
335 328 # verbatim mode
336 329 ret.append(rest)
337 330
338 331 self.cout.seek(0)
339 332 output = self.cout.read()
340 333 if not is_suppress and not is_semicolon:
341 334 ret.append(output)
342 335
343 336 self.cout.truncate(0)
344 337 return ret, input_lines, output, is_doctest, image_file
345 338 #print 'OUTPUT', output # dbg
346 339
347 340 def process_output(self, data, output_prompt,
348 341 input_lines, output, is_doctest, image_file):
349 342 """Process data block for OUTPUT token."""
350 343 if is_doctest:
351 344 submitted = data.strip()
352 345 found = output
353 346 if found is not None:
354 347 found = found.strip()
355 348
356 349 # XXX - fperez: in 0.11, 'output' never comes with the prompt
357 350 # in it, just the actual output text. So I think all this code
358 351 # can be nuked...
359 352 ## ind = found.find(output_prompt)
360 353 ## if ind<0:
361 354 ## e='output prompt="%s" does not match out line=%s' % \
362 355 ## (output_prompt, found)
363 356 ## raise RuntimeError(e)
364 357 ## found = found[len(output_prompt):].strip()
365 358
366 359 if found!=submitted:
367 360 e = ('doctest failure for input_lines="%s" with '
368 361 'found_output="%s" and submitted output="%s"' %
369 362 (input_lines, found, submitted) )
370 363 raise RuntimeError(e)
371 364 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
372 365
373 366 def process_comment(self, data):
374 367 """Process data block for COMMENT token."""
375 368 if not self.is_suppress:
376 369 return [data]
377 370
378 371 def process_block(self, block):
379 372 """
380 373 process block from the block_parser and return a list of processed lines
381 374 """
382 375
383 376 ret = []
384 377 output = None
385 378 input_lines = None
386 379
387 380 m = rgxin.match(str(self.IP.outputcache.prompt1).strip())
388 381 lineno = int(m.group(1))
389 382
390 383 input_prompt = fmtin%lineno
391 384 output_prompt = fmtout%lineno
392 385 image_file = None
393 386 image_directive = None
394 387 # XXX - This needs a second refactor. There's too much state being
395 388 # held globally, which makes for a very awkward interface and large,
396 389 # hard to test functions. I've already broken this up at least into
397 390 # three separate processors to isolate the logic better, but this only
398 391 # serves to highlight the coupling. Next we need to clean it up...
399 392 for token, data in block:
400 393 if token==COMMENT:
401 394 out_data = self.process_comment(data)
402 395 elif token==INPUT:
403 396 out_data, input_lines, output, is_doctest, image_file= \
404 397 self.process_input(data, input_prompt, lineno)
405 398 elif token==OUTPUT:
406 399 out_data = \
407 400 self.process_output(data, output_prompt,
408 401 input_lines, output, is_doctest,
409 402 image_file)
410 403 if out_data:
411 404 ret.extend(out_data)
412 405
413 406 if image_file is not None:
414 407 self.ensure_pyplot()
415 408 command = 'plt.gcf().savefig("%s")'%image_file
416 409 print 'SAVEFIG', command # dbg
417 410 self.process_input_line('bookmark ipy_thisdir')
418 411 self.process_input_line('cd -b ipy_basedir')
419 412 self.process_input_line(command)
420 413 self.process_input_line('cd -b ipy_thisdir')
421 414 self.cout.seek(0)
422 415 self.cout.truncate(0)
423 416 return ret, image_directive
424 417
425 418 def ensure_pyplot(self):
426 419 if self._pyplot_imported:
427 420 return
428 421 self.process_input_line('import matplotlib.pyplot as plt')
429 422
430 423 # A global instance used below. XXX: not sure why this can't be created inside
431 424 # ipython_directive itself.
432 425 shell = EmbeddedSphinxShell()
433 426
434 427 def reconfig_shell():
435 428 """Called after setting module-level variables to re-instantiate
436 429 with the set values (since shell is instantiated first at import-time
437 430 when module variables have default values)"""
438 431 global shell
439 432 shell = EmbeddedSphinxShell()
440 433
441 434
442 435 def ipython_directive(name, arguments, options, content, lineno,
443 436 content_offset, block_text, state, state_machine,
444 437 ):
445 438
446 439 debug = ipython_directive.DEBUG
447 440 shell.is_suppress = options.has_key('suppress')
448 441 shell.is_doctest = options.has_key('doctest')
449 442 shell.is_verbatim = options.has_key('verbatim')
450 443
451 444 #print 'ipy', shell.is_suppress, options
452 445 parts = '\n'.join(content).split('\n\n')
453 446 lines = ['.. sourcecode:: ipython', '']
454 447
455 448 figures = []
456 449 for part in parts:
457 450 block = block_parser(part)
458 451
459 452 if len(block):
460 453 rows, figure = shell.process_block(block)
461 454 for row in rows:
462 455 lines.extend([' %s'%line for line in row.split('\n')])
463 456
464 457 if figure is not None:
465 458 figures.append(figure)
466 459
467 460 for figure in figures:
468 461 lines.append('')
469 462 lines.extend(figure.split('\n'))
470 463 lines.append('')
471 464
472 465 #print lines
473 466 if len(lines)>2:
474 467 if debug:
475 468 print '\n'.join(lines)
476 469 else:
477 470 #print 'INSERTING %d lines'%len(lines)
478 471 state_machine.insert_input(
479 472 lines, state_machine.input_lines.source(0))
480 473
481 474 return []
482 475
483 476 ipython_directive.DEBUG = False
484 477 ipython_directive.DEBUG = True # dbg
485 478
486 479 # Enable as a proper Sphinx directive
487 480 def setup(app):
488 481 setup.app = app
489 482 options = {'suppress': directives.flag,
490 483 'doctest': directives.flag,
491 484 'verbatim': directives.flag,
492 485 }
493 486
494 487 app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options)
495 488
496 489
497 490 # Simple smoke test, needs to be converted to a proper automatic test.
498 491 def test():
499 492
500 493 examples = [
501 494 r"""
502 495 In [9]: pwd
503 496 Out[9]: '/home/jdhunter/py4science/book'
504 497
505 498 In [10]: cd bookdata/
506 499 /home/jdhunter/py4science/book/bookdata
507 500
508 501 In [2]: from pylab import *
509 502
510 503 In [2]: ion()
511 504
512 505 In [3]: im = imread('stinkbug.png')
513 506
514 507 @savefig mystinkbug.png width=4in
515 508 In [4]: imshow(im)
516 509 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
517 510
518 511 """,
519 512 r"""
520 513
521 514 In [1]: x = 'hello world'
522 515
523 516 # string methods can be
524 517 # used to alter the string
525 518 @doctest
526 519 In [2]: x.upper()
527 520 Out[2]: 'HELLO WORLD'
528 521
529 522 @verbatim
530 523 In [3]: x.st<TAB>
531 524 x.startswith x.strip
532 525 """,
533 526 r"""
534 527
535 528 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
536 529 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
537 530
538 531 In [131]: print url.split('&')
539 532 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
540 533
541 534 In [60]: import urllib
542 535
543 536 """,
544 537 r"""\
545 538
546 539 In [133]: import numpy.random
547 540
548 541 @suppress
549 542 In [134]: numpy.random.seed(2358)
550 543
551 544 @doctest
552 545 In [135]: np.random.rand(10,2)
553 546 Out[135]:
554 547 array([[ 0.64524308, 0.59943846],
555 548 [ 0.47102322, 0.8715456 ],
556 549 [ 0.29370834, 0.74776844],
557 550 [ 0.99539577, 0.1313423 ],
558 551 [ 0.16250302, 0.21103583],
559 552 [ 0.81626524, 0.1312433 ],
560 553 [ 0.67338089, 0.72302393],
561 554 [ 0.7566368 , 0.07033696],
562 555 [ 0.22591016, 0.77731835],
563 556 [ 0.0072729 , 0.34273127]])
564 557
565 558 """,
566 559
567 560 r"""
568 561 In [106]: print x
569 562 jdh
570 563
571 564 In [109]: for i in range(10):
572 565 .....: print i
573 566 .....:
574 567 .....:
575 568 0
576 569 1
577 570 2
578 571 3
579 572 4
580 573 5
581 574 6
582 575 7
583 576 8
584 577 9
585 578 """,
586 579
587 580 r"""
588 581
589 582 In [144]: from pylab import *
590 583
591 584 In [145]: ion()
592 585
593 586 # use a semicolon to suppress the output
594 587 @savefig test_hist.png width=4in
595 588 In [151]: hist(np.random.randn(10000), 100);
596 589
597 590
598 591 @savefig test_plot.png width=4in
599 592 In [151]: plot(np.random.randn(10000), 'o');
600 593 """,
601 594
602 595 r"""
603 596 # use a semicolon to suppress the output
604 597 In [151]: plt.clf()
605 598
606 599 @savefig plot_simple.png width=4in
607 600 In [151]: plot([1,2,3])
608 601
609 602 @savefig hist_simple.png width=4in
610 603 In [151]: hist(np.random.randn(10000), 100);
611 604
612 605 """,
613 606 r"""
614 607 # update the current fig
615 608 In [151]: ylabel('number')
616 609
617 610 In [152]: title('normal distribution')
618 611
619 612
620 613 @savefig hist_with_text.png
621 614 In [153]: grid(True)
622 615
623 616 """,
624 617 ]
625 618
626 619 #ipython_directive.DEBUG = True # dbg
627 620 #options = dict(suppress=True) # dbg
628 621 options = dict()
629 622 for example in examples:
630 623 content = example.split('\n')
631 624 ipython_directive('debug', arguments=None, options=options,
632 625 content=content, lineno=0,
633 626 content_offset=None, block_text=None,
634 627 state=None, state_machine=None,
635 628 )
636 629
637 630 # Run test suite as a script
638 631 if __name__=='__main__':
639 632 if not os.path.isdir('_static'):
640 633 os.mkdir('_static')
641 634 test()
642 635 print 'All OK? Check figures in _static/'
General Comments 0
You need to be logged in to leave comments. Login now