##// END OF EJS Templates
Fix problem with rc_override....
Václav Šmilauer -
Show More
@@ -1,1246 +1,1261 b''
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Shell classes.
3 3
4 4 All the matplotlib support code was co-developed with John Hunter,
5 5 matplotlib's author.
6 6 """
7 7
8 8 #*****************************************************************************
9 9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
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 # Code begins
16 16 # Stdlib imports
17 17 import __builtin__
18 18 import __main__
19 19 import Queue
20 20 import inspect
21 21 import os
22 22 import sys
23 23 import thread
24 24 import threading
25 25 import time
26 26
27 27 from signal import signal, SIGINT
28 28
29 29 try:
30 30 import ctypes
31 31 HAS_CTYPES = True
32 32 except ImportError:
33 33 HAS_CTYPES = False
34 34
35 35 # IPython imports
36 36 import IPython
37 37 from IPython import ultraTB, ipapi
38 38 from IPython.Magic import Magic
39 39 from IPython.genutils import Term,warn,error,flag_calls, ask_yes_no
40 40 from IPython.iplib import InteractiveShell
41 41 from IPython.ipmaker import make_IPython
42 42 from IPython.ipstruct import Struct
43 43 from IPython.testing import decorators as testdec
44 44
45 45 # Globals
46 46 # global flag to pass around information about Ctrl-C without exceptions
47 47 KBINT = False
48 48
49 49 # global flag to turn on/off Tk support.
50 50 USE_TK = False
51 51
52 52 # ID for the main thread, used for cross-thread exceptions
53 53 MAIN_THREAD_ID = thread.get_ident()
54 54
55 55 # Tag when runcode() is active, for exception handling
56 56 CODE_RUN = None
57 57
58 58 # Default timeout for waiting for multithreaded shells (in seconds)
59 59 GUI_TIMEOUT = 10
60 60
61 61 #-----------------------------------------------------------------------------
62 62 # This class is trivial now, but I want to have it in to publish a clean
63 63 # interface. Later when the internals are reorganized, code that uses this
64 64 # shouldn't have to change.
65 65
66 66 class IPShell:
67 67 """Create an IPython instance."""
68 68
69 69 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
70 70 debug=1,shell_class=InteractiveShell):
71 71 self.IP = make_IPython(argv,user_ns=user_ns,
72 72 user_global_ns=user_global_ns,
73 73 debug=debug,shell_class=shell_class)
74 74
75 75 def mainloop(self,sys_exit=0,banner=None):
76 76 self.IP.mainloop(banner)
77 77 if sys_exit:
78 78 sys.exit()
79 79
80 80 #-----------------------------------------------------------------------------
81 81 def kill_embedded(self,parameter_s=''):
82 82 """%kill_embedded : deactivate for good the current embedded IPython.
83 83
84 84 This function (after asking for confirmation) sets an internal flag so that
85 85 an embedded IPython will never activate again. This is useful to
86 86 permanently disable a shell that is being called inside a loop: once you've
87 87 figured out what you needed from it, you may then kill it and the program
88 88 will then continue to run without the interactive shell interfering again.
89 89 """
90 90
91 91 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
92 92 "(y/n)? [y/N] ",'n')
93 93 if kill:
94 94 self.shell.embedded_active = False
95 95 print "This embedded IPython will not reactivate anymore once you exit."
96 96
97 97 class IPShellEmbed:
98 98 """Allow embedding an IPython shell into a running program.
99 99
100 100 Instances of this class are callable, with the __call__ method being an
101 101 alias to the embed() method of an InteractiveShell instance.
102 102
103 103 Usage (see also the example-embed.py file for a running example):
104 104
105 105 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
106 106
107 107 - argv: list containing valid command-line options for IPython, as they
108 108 would appear in sys.argv[1:].
109 109
110 110 For example, the following command-line options:
111 111
112 112 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
113 113
114 114 would be passed in the argv list as:
115 115
116 116 ['-prompt_in1','Input <\\#>','-colors','LightBG']
117 117
118 118 - banner: string which gets printed every time the interpreter starts.
119 119
120 120 - exit_msg: string which gets printed every time the interpreter exits.
121 121
122 122 - rc_override: a dict or Struct of configuration options such as those
123 123 used by IPython. These options are read from your ~/.ipython/ipythonrc
124 124 file when the Shell object is created. Passing an explicit rc_override
125 125 dict with any options you want allows you to override those values at
126 126 creation time without having to modify the file. This way you can create
127 127 embeddable instances configured in any way you want without editing any
128 128 global files (thus keeping your interactive IPython configuration
129 129 unchanged).
130 130
131 131 Then the ipshell instance can be called anywhere inside your code:
132 132
133 133 ipshell(header='') -> Opens up an IPython shell.
134 134
135 135 - header: string printed by the IPython shell upon startup. This can let
136 136 you know where in your code you are when dropping into the shell. Note
137 137 that 'banner' gets prepended to all calls, so header is used for
138 138 location-specific information.
139 139
140 140 For more details, see the __call__ method below.
141 141
142 142 When the IPython shell is exited with Ctrl-D, normal program execution
143 143 resumes.
144 144
145 145 This functionality was inspired by a posting on comp.lang.python by cmkl
146 146 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
147 147 by the IDL stop/continue commands."""
148 148
149 149 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None,
150 150 user_ns=None):
151 151 """Note that argv here is a string, NOT a list."""
152 152 self.set_banner(banner)
153 153 self.set_exit_msg(exit_msg)
154 154 self.set_dummy_mode(0)
155 155
156 156 # sys.displayhook is a global, we need to save the user's original
157 157 # Don't rely on __displayhook__, as the user may have changed that.
158 158 self.sys_displayhook_ori = sys.displayhook
159 159
160 160 # save readline completer status
161 161 try:
162 162 #print 'Save completer',sys.ipcompleter # dbg
163 163 self.sys_ipcompleter_ori = sys.ipcompleter
164 164 except:
165 165 pass # not nested with IPython
166 166
167 167 self.IP = make_IPython(argv,rc_override=rc_override,
168 168 embedded=True,
169 169 user_ns=user_ns)
170 170
171 171 ip = ipapi.IPApi(self.IP)
172 172 ip.expose_magic("kill_embedded",kill_embedded)
173 173
174 174 # copy our own displayhook also
175 175 self.sys_displayhook_embed = sys.displayhook
176 176 # and leave the system's display hook clean
177 177 sys.displayhook = self.sys_displayhook_ori
178 178 # don't use the ipython crash handler so that user exceptions aren't
179 179 # trapped
180 180 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
181 181 mode = self.IP.rc.xmode,
182 182 call_pdb = self.IP.rc.pdb)
183 183 self.restore_system_completer()
184 184
185 185 def restore_system_completer(self):
186 186 """Restores the readline completer which was in place.
187 187
188 188 This allows embedded IPython within IPython not to disrupt the
189 189 parent's completion.
190 190 """
191 191
192 192 try:
193 193 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
194 194 sys.ipcompleter = self.sys_ipcompleter_ori
195 195 except:
196 196 pass
197 197
198 198 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
199 199 """Activate the interactive interpreter.
200 200
201 201 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
202 202 the interpreter shell with the given local and global namespaces, and
203 203 optionally print a header string at startup.
204 204
205 205 The shell can be globally activated/deactivated using the
206 206 set/get_dummy_mode methods. This allows you to turn off a shell used
207 207 for debugging globally.
208 208
209 209 However, *each* time you call the shell you can override the current
210 210 state of dummy_mode with the optional keyword parameter 'dummy'. For
211 211 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
212 212 can still have a specific call work by making it as IPShell(dummy=0).
213 213
214 214 The optional keyword parameter dummy controls whether the call
215 215 actually does anything. """
216 216
217 217 # If the user has turned it off, go away
218 218 if not self.IP.embedded_active:
219 219 return
220 220
221 221 # Normal exits from interactive mode set this flag, so the shell can't
222 222 # re-enter (it checks this variable at the start of interactive mode).
223 223 self.IP.exit_now = False
224 224
225 225 # Allow the dummy parameter to override the global __dummy_mode
226 226 if dummy or (dummy != 0 and self.__dummy_mode):
227 227 return
228 228
229 229 # Set global subsystems (display,completions) to our values
230 230 sys.displayhook = self.sys_displayhook_embed
231 231 if self.IP.has_readline:
232 232 self.IP.set_completer()
233 233
234 234 if self.banner and header:
235 235 format = '%s\n%s\n'
236 236 else:
237 237 format = '%s%s\n'
238 238 banner = format % (self.banner,header)
239 239
240 240 # Call the embedding code with a stack depth of 1 so it can skip over
241 241 # our call and get the original caller's namespaces.
242 242 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
243 243
244 244 if self.exit_msg:
245 245 print self.exit_msg
246 246
247 247 # Restore global systems (display, completion)
248 248 sys.displayhook = self.sys_displayhook_ori
249 249 self.restore_system_completer()
250 250
251 251 def set_dummy_mode(self,dummy):
252 252 """Sets the embeddable shell's dummy mode parameter.
253 253
254 254 set_dummy_mode(dummy): dummy = 0 or 1.
255 255
256 256 This parameter is persistent and makes calls to the embeddable shell
257 257 silently return without performing any action. This allows you to
258 258 globally activate or deactivate a shell you're using with a single call.
259 259
260 260 If you need to manually"""
261 261
262 262 if dummy not in [0,1,False,True]:
263 263 raise ValueError,'dummy parameter must be boolean'
264 264 self.__dummy_mode = dummy
265 265
266 266 def get_dummy_mode(self):
267 267 """Return the current value of the dummy mode parameter.
268 268 """
269 269 return self.__dummy_mode
270 270
271 271 def set_banner(self,banner):
272 272 """Sets the global banner.
273 273
274 274 This banner gets prepended to every header printed when the shell
275 275 instance is called."""
276 276
277 277 self.banner = banner
278 278
279 279 def set_exit_msg(self,exit_msg):
280 280 """Sets the global exit_msg.
281 281
282 282 This exit message gets printed upon exiting every time the embedded
283 283 shell is called. It is None by default. """
284 284
285 285 self.exit_msg = exit_msg
286 286
287 287 #-----------------------------------------------------------------------------
288 288 if HAS_CTYPES:
289 289 # Add async exception support. Trick taken from:
290 290 # http://sebulba.wikispaces.com/recipe+thread2
291 291 def _async_raise(tid, exctype):
292 292 """raises the exception, performs cleanup if needed"""
293 293 if not inspect.isclass(exctype):
294 294 raise TypeError("Only types can be raised (not instances)")
295 295 # Explicit cast to c_long is necessary for 64-bit support:
296 296 # See https://bugs.launchpad.net/ipython/+bug/237073
297 297 res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
298 298 ctypes.py_object(exctype))
299 299 if res == 0:
300 300 raise ValueError("invalid thread id")
301 301 elif res != 1:
302 302 # If it returns a number greater than one, you're in trouble,
303 303 # and you should call it again with exc=NULL to revert the effect
304 304 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
305 305 raise SystemError("PyThreadState_SetAsyncExc failed")
306 306
307 307 def sigint_handler(signum,stack_frame):
308 308 """Sigint handler for threaded apps.
309 309
310 310 This is a horrible hack to pass information about SIGINT _without_
311 311 using exceptions, since I haven't been able to properly manage
312 312 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
313 313 done (or at least that's my understanding from a c.l.py thread where
314 314 this was discussed)."""
315 315
316 316 global KBINT
317 317
318 318 if CODE_RUN:
319 319 _async_raise(MAIN_THREAD_ID,KeyboardInterrupt)
320 320 else:
321 321 KBINT = True
322 322 print '\nKeyboardInterrupt - Press <Enter> to continue.',
323 323 Term.cout.flush()
324 324
325 325 else:
326 326 def sigint_handler(signum,stack_frame):
327 327 """Sigint handler for threaded apps.
328 328
329 329 This is a horrible hack to pass information about SIGINT _without_
330 330 using exceptions, since I haven't been able to properly manage
331 331 cross-thread exceptions in GTK/WX. In fact, I don't think it can be
332 332 done (or at least that's my understanding from a c.l.py thread where
333 333 this was discussed)."""
334 334
335 335 global KBINT
336 336
337 337 print '\nKeyboardInterrupt - Press <Enter> to continue.',
338 338 Term.cout.flush()
339 339 # Set global flag so that runsource can know that Ctrl-C was hit
340 340 KBINT = True
341 341
342 342
343 343 class MTInteractiveShell(InteractiveShell):
344 344 """Simple multi-threaded shell."""
345 345
346 346 # Threading strategy taken from:
347 347 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
348 348 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
349 349 # from the pygtk mailing list, to avoid lockups with system calls.
350 350
351 351 # class attribute to indicate whether the class supports threads or not.
352 352 # Subclasses with thread support should override this as needed.
353 353 isthreaded = True
354 354
355 355 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
356 356 user_ns=None,user_global_ns=None,banner2='',
357 357 gui_timeout=GUI_TIMEOUT,**kw):
358 358 """Similar to the normal InteractiveShell, but with threading control"""
359 359
360 360 InteractiveShell.__init__(self,name,usage,rc,user_ns,
361 361 user_global_ns,banner2)
362 362
363 363 # Timeout we wait for GUI thread
364 364 self.gui_timeout = gui_timeout
365 365
366 366 # A queue to hold the code to be executed.
367 367 self.code_queue = Queue.Queue()
368 368
369 369 # Stuff to do at closing time
370 370 self._kill = None
371 371 on_kill = kw.get('on_kill', [])
372 372 # Check that all things to kill are callable:
373 373 for t in on_kill:
374 374 if not callable(t):
375 375 raise TypeError,'on_kill must be a list of callables'
376 376 self.on_kill = on_kill
377 377 # thread identity of the "worker thread" (that may execute code directly)
378 378 self.worker_ident = None
379 379
380 380 def runsource(self, source, filename="<input>", symbol="single"):
381 381 """Compile and run some source in the interpreter.
382 382
383 383 Modified version of code.py's runsource(), to handle threading issues.
384 384 See the original for full docstring details."""
385 385
386 386 global KBINT
387 387
388 388 # If Ctrl-C was typed, we reset the flag and return right away
389 389 if KBINT:
390 390 KBINT = False
391 391 return False
392 392
393 393 if self._kill:
394 394 # can't queue new code if we are being killed
395 395 return True
396 396
397 397 try:
398 398 code = self.compile(source, filename, symbol)
399 399 except (OverflowError, SyntaxError, ValueError):
400 400 # Case 1
401 401 self.showsyntaxerror(filename)
402 402 return False
403 403
404 404 if code is None:
405 405 # Case 2
406 406 return True
407 407
408 408 # shortcut - if we are in worker thread, or the worker thread is not
409 409 # running, execute directly (to allow recursion and prevent deadlock if
410 410 # code is run early in IPython construction)
411 411
412 412 if (self.worker_ident is None
413 413 or self.worker_ident == thread.get_ident() ):
414 414 InteractiveShell.runcode(self,code)
415 415 return False
416 416
417 417 # Case 3
418 418 # Store code in queue, so the execution thread can handle it.
419 419
420 420 completed_ev, received_ev = threading.Event(), threading.Event()
421 421
422 422 self.code_queue.put((code,completed_ev, received_ev))
423 423 # first make sure the message was received, with timeout
424 424 received_ev.wait(self.gui_timeout)
425 425 if not received_ev.isSet():
426 426 # the mainloop is dead, start executing code directly
427 427 print "Warning: Timeout for mainloop thread exceeded"
428 428 print "switching to nonthreaded mode (until mainloop wakes up again)"
429 429 self.worker_ident = None
430 430 else:
431 431 completed_ev.wait()
432 432 return False
433 433
434 434 def runcode(self):
435 435 """Execute a code object.
436 436
437 437 Multithreaded wrapper around IPython's runcode()."""
438 438
439 439 global CODE_RUN
440 440
441 441 # we are in worker thread, stash out the id for runsource()
442 442 self.worker_ident = thread.get_ident()
443 443
444 444 if self._kill:
445 445 print >>Term.cout, 'Closing threads...',
446 446 Term.cout.flush()
447 447 for tokill in self.on_kill:
448 448 tokill()
449 449 print >>Term.cout, 'Done.'
450 450 # allow kill() to return
451 451 self._kill.set()
452 452 return True
453 453
454 454 # Install sigint handler. We do it every time to ensure that if user
455 455 # code modifies it, we restore our own handling.
456 456 try:
457 457 signal(SIGINT,sigint_handler)
458 458 except SystemError:
459 459 # This happens under Windows, which seems to have all sorts
460 460 # of problems with signal handling. Oh well...
461 461 pass
462 462
463 463 # Flush queue of pending code by calling the run methood of the parent
464 464 # class with all items which may be in the queue.
465 465 code_to_run = None
466 466 while 1:
467 467 try:
468 468 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
469 469 except Queue.Empty:
470 470 break
471 471 received_ev.set()
472 472
473 473 # Exceptions need to be raised differently depending on which
474 474 # thread is active. This convoluted try/except is only there to
475 475 # protect against asynchronous exceptions, to ensure that a KBINT
476 476 # at the wrong time doesn't deadlock everything. The global
477 477 # CODE_TO_RUN is set to true/false as close as possible to the
478 478 # runcode() call, so that the KBINT handler is correctly informed.
479 479 try:
480 480 try:
481 481 CODE_RUN = True
482 482 InteractiveShell.runcode(self,code_to_run)
483 483 except KeyboardInterrupt:
484 484 print "Keyboard interrupted in mainloop"
485 485 while not self.code_queue.empty():
486 486 code, ev1,ev2 = self.code_queue.get_nowait()
487 487 ev1.set()
488 488 ev2.set()
489 489 break
490 490 finally:
491 491 CODE_RUN = False
492 492 # allow runsource() return from wait
493 493 completed_ev.set()
494 494
495 495
496 496 # This MUST return true for gtk threading to work
497 497 return True
498 498
499 499 def kill(self):
500 500 """Kill the thread, returning when it has been shut down."""
501 501 self._kill = threading.Event()
502 502 self._kill.wait()
503 503
504 504 class MatplotlibShellBase:
505 505 """Mixin class to provide the necessary modifications to regular IPython
506 506 shell classes for matplotlib support.
507 507
508 508 Given Python's MRO, this should be used as the FIRST class in the
509 509 inheritance hierarchy, so that it overrides the relevant methods."""
510 510
511 511 def _matplotlib_config(self,name,user_ns,user_global_ns=None):
512 512 """Return items needed to setup the user's shell with matplotlib"""
513 513
514 514 # Initialize matplotlib to interactive mode always
515 515 import matplotlib
516 516 from matplotlib import backends
517 517 matplotlib.interactive(True)
518 518
519 519 def use(arg):
520 520 """IPython wrapper for matplotlib's backend switcher.
521 521
522 522 In interactive use, we can not allow switching to a different
523 523 interactive backend, since thread conflicts will most likely crash
524 524 the python interpreter. This routine does a safety check first,
525 525 and refuses to perform a dangerous switch. It still allows
526 526 switching to non-interactive backends."""
527 527
528 528 if arg in backends.interactive_bk and arg != self.mpl_backend:
529 529 m=('invalid matplotlib backend switch.\n'
530 530 'This script attempted to switch to the interactive '
531 531 'backend: `%s`\n'
532 532 'Your current choice of interactive backend is: `%s`\n\n'
533 533 'Switching interactive matplotlib backends at runtime\n'
534 534 'would crash the python interpreter, '
535 535 'and IPython has blocked it.\n\n'
536 536 'You need to either change your choice of matplotlib backend\n'
537 537 'by editing your .matplotlibrc file, or run this script as a \n'
538 538 'standalone file from the command line, not using IPython.\n' %
539 539 (arg,self.mpl_backend) )
540 540 raise RuntimeError, m
541 541 else:
542 542 self.mpl_use(arg)
543 543 self.mpl_use._called = True
544 544
545 545 self.matplotlib = matplotlib
546 546 self.mpl_backend = matplotlib.rcParams['backend']
547 547
548 548 # we also need to block switching of interactive backends by use()
549 549 self.mpl_use = matplotlib.use
550 550 self.mpl_use._called = False
551 551 # overwrite the original matplotlib.use with our wrapper
552 552 matplotlib.use = use
553 553
554 554 # This must be imported last in the matplotlib series, after
555 555 # backend/interactivity choices have been made
556 556 import matplotlib.pylab as pylab
557 557 self.pylab = pylab
558 558
559 559 self.pylab.show._needmain = False
560 560 # We need to detect at runtime whether show() is called by the user.
561 561 # For this, we wrap it into a decorator which adds a 'called' flag.
562 562 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
563 563
564 564 # Build a user namespace initialized with matplotlib/matlab features.
565 565 user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns,
566 566 user_global_ns)
567 567
568 568 # Import numpy as np/pyplot as plt are conventions we're trying to
569 569 # somewhat standardize on. Making them available to users by default
570 570 # will greatly help this.
571 571 exec ("import numpy\n"
572 572 "import numpy as np\n"
573 573 "import matplotlib\n"
574 574 "import matplotlib.pylab as pylab\n"
575 575 "try:\n"
576 576 " import matplotlib.pyplot as plt\n"
577 577 "except ImportError:\n"
578 578 " pass\n"
579 579 ) in user_ns
580 580
581 581 # Build matplotlib info banner
582 582 b="""
583 583 Welcome to pylab, a matplotlib-based Python environment.
584 584 For more information, type 'help(pylab)'.
585 585 """
586 586 return user_ns,user_global_ns,b
587 587
588 588 def mplot_exec(self,fname,*where,**kw):
589 589 """Execute a matplotlib script.
590 590
591 591 This is a call to execfile(), but wrapped in safeties to properly
592 592 handle interactive rendering and backend switching."""
593 593
594 594 #print '*** Matplotlib runner ***' # dbg
595 595 # turn off rendering until end of script
596 596 isInteractive = self.matplotlib.rcParams['interactive']
597 597 self.matplotlib.interactive(False)
598 598 self.safe_execfile(fname,*where,**kw)
599 599 self.matplotlib.interactive(isInteractive)
600 600 # make rendering call now, if the user tried to do it
601 601 if self.pylab.draw_if_interactive.called:
602 602 self.pylab.draw()
603 603 self.pylab.draw_if_interactive.called = False
604 604
605 605 # if a backend switch was performed, reverse it now
606 606 if self.mpl_use._called:
607 607 self.matplotlib.rcParams['backend'] = self.mpl_backend
608 608
609 609 @testdec.skip_doctest
610 610 def magic_run(self,parameter_s=''):
611 611 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
612 612
613 613 # Fix the docstring so users see the original as well
614 614 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
615 615 "\n *** Modified %run for Matplotlib,"
616 616 " with proper interactive handling ***")
617 617
618 618 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
619 619 # and multithreaded. Note that these are meant for internal use, the IPShell*
620 620 # classes below are the ones meant for public consumption.
621 621
622 622 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
623 623 """Single-threaded shell with matplotlib support."""
624 624
625 625 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
626 626 user_ns=None,user_global_ns=None,**kw):
627 627 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
628 628 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
629 629 banner2=b2,**kw)
630 630
631 631 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
632 632 """Multi-threaded shell with matplotlib support."""
633 633
634 634 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
635 635 user_ns=None,user_global_ns=None, **kw):
636 636 user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns)
637 637 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
638 638 banner2=b2,**kw)
639 639
640 640 #-----------------------------------------------------------------------------
641 641 # Utility functions for the different GUI enabled IPShell* classes.
642 642
643 643 def get_tk():
644 644 """Tries to import Tkinter and returns a withdrawn Tkinter root
645 645 window. If Tkinter is already imported or not available, this
646 646 returns None. This function calls `hijack_tk` underneath.
647 647 """
648 648 if not USE_TK or sys.modules.has_key('Tkinter'):
649 649 return None
650 650 else:
651 651 try:
652 652 import Tkinter
653 653 except ImportError:
654 654 return None
655 655 else:
656 656 hijack_tk()
657 657 r = Tkinter.Tk()
658 658 r.withdraw()
659 659 return r
660 660
661 661 def hijack_tk():
662 662 """Modifies Tkinter's mainloop with a dummy so when a module calls
663 663 mainloop, it does not block.
664 664
665 665 """
666 666 def misc_mainloop(self, n=0):
667 667 pass
668 668 def tkinter_mainloop(n=0):
669 669 pass
670 670
671 671 import Tkinter
672 672 Tkinter.Misc.mainloop = misc_mainloop
673 673 Tkinter.mainloop = tkinter_mainloop
674 674
675 675 def update_tk(tk):
676 676 """Updates the Tkinter event loop. This is typically called from
677 677 the respective WX or GTK mainloops.
678 678 """
679 679 if tk:
680 680 tk.update()
681 681
682 682 def hijack_wx():
683 683 """Modifies wxPython's MainLoop with a dummy so user code does not
684 684 block IPython. The hijacked mainloop function is returned.
685 685 """
686 686 def dummy_mainloop(*args, **kw):
687 687 pass
688 688
689 689 try:
690 690 import wx
691 691 except ImportError:
692 692 # For very old versions of WX
693 693 import wxPython as wx
694 694
695 695 ver = wx.__version__
696 696 orig_mainloop = None
697 697 if ver[:3] >= '2.5':
698 698 import wx
699 699 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
700 700 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
701 701 else: raise AttributeError('Could not find wx core module')
702 702 orig_mainloop = core.PyApp_MainLoop
703 703 core.PyApp_MainLoop = dummy_mainloop
704 704 elif ver[:3] == '2.4':
705 705 orig_mainloop = wx.wxc.wxPyApp_MainLoop
706 706 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
707 707 else:
708 708 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
709 709 return orig_mainloop
710 710
711 711 def hijack_gtk():
712 712 """Modifies pyGTK's mainloop with a dummy so user code does not
713 713 block IPython. This function returns the original `gtk.mainloop`
714 714 function that has been hijacked.
715 715 """
716 716 def dummy_mainloop(*args, **kw):
717 717 pass
718 718 import gtk
719 719 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
720 720 else: orig_mainloop = gtk.mainloop
721 721 gtk.mainloop = dummy_mainloop
722 722 gtk.main = dummy_mainloop
723 723 return orig_mainloop
724 724
725 725 def hijack_qt():
726 726 """Modifies PyQt's mainloop with a dummy so user code does not
727 727 block IPython. This function returns the original
728 728 `qt.qApp.exec_loop` function that has been hijacked.
729 729 """
730 730 def dummy_mainloop(*args, **kw):
731 731 pass
732 732 import qt
733 733 orig_mainloop = qt.qApp.exec_loop
734 734 qt.qApp.exec_loop = dummy_mainloop
735 735 qt.QApplication.exec_loop = dummy_mainloop
736 736 return orig_mainloop
737 737
738 738 def hijack_qt4():
739 739 """Modifies PyQt4's mainloop with a dummy so user code does not
740 740 block IPython. This function returns the original
741 741 `QtGui.qApp.exec_` function that has been hijacked.
742 742 """
743 743 def dummy_mainloop(*args, **kw):
744 744 pass
745 745 from PyQt4 import QtGui, QtCore
746 746 orig_mainloop = QtGui.qApp.exec_
747 747 QtGui.qApp.exec_ = dummy_mainloop
748 748 QtGui.QApplication.exec_ = dummy_mainloop
749 749 QtCore.QCoreApplication.exec_ = dummy_mainloop
750 750 return orig_mainloop
751 751
752 752 #-----------------------------------------------------------------------------
753 753 # The IPShell* classes below are the ones meant to be run by external code as
754 754 # IPython instances. Note that unless a specific threading strategy is
755 755 # desired, the factory function start() below should be used instead (it
756 756 # selects the proper threaded class).
757 757
758 758 class IPThread(threading.Thread):
759 759 def run(self):
760 760 self.IP.mainloop(self._banner)
761 761 self.IP.kill()
762 762
763 763 class IPShellGTK(IPThread):
764 764 """Run a gtk mainloop() in a separate thread.
765 765
766 766 Python commands can be passed to the thread where they will be executed.
767 767 This is implemented by periodically checking for passed code using a
768 768 GTK timeout callback."""
769 769
770 770 TIMEOUT = 100 # Millisecond interval between timeouts.
771 771
772 772 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
773 773 debug=1,shell_class=MTInteractiveShell):
774 774
775 775 import gtk
776 # Check for set_interactive, coming up in new pygtk.
777 # Disable it so that this code works, but notify
778 # the user that he has a better option as well.
779 # XXX TODO better support when set_interactive is released
780 try:
781 gtk.set_interactive(False)
782 print "Your PyGtk has set_interactive(), so you can use the"
783 print "more stable single-threaded Gtk mode."
784 print "See https://bugs.launchpad.net/ipython/+bug/270856"
785 except AttributeError:
786 pass
776 ## # Check for set_interactive, coming up in new pygtk.
777 ## # Disable it so that this code works, but notify
778 ## # the user that he has a better option as well.
779 ## # XXX TODO better support when set_interactive is released
780 ## try:
781 ## gtk.set_interactive(False)
782 ## print "Your PyGtk has set_interactive(), so you can use the"
783 ## print "more stable single-threaded Gtk mode."
784 ## print "See https://bugs.launchpad.net/ipython/+bug/270856"
785 ## except AttributeError:
786 ## pass
787 787
788 788 self.gtk = gtk
789 789 self.gtk_mainloop = hijack_gtk()
790 790
791 791 # Allows us to use both Tk and GTK.
792 792 self.tk = get_tk()
793 793
794 794 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
795 795 else: mainquit = self.gtk.mainquit
796 796
797 797 self.IP = make_IPython(argv,user_ns=user_ns,
798 798 user_global_ns=user_global_ns,
799 799 debug=debug,
800 800 shell_class=shell_class,
801 801 on_kill=[mainquit])
802 802
803 803 # HACK: slot for banner in self; it will be passed to the mainloop
804 804 # method only and .run() needs it. The actual value will be set by
805 805 # .mainloop().
806 806 self._banner = None
807 807
808 808 threading.Thread.__init__(self)
809 809
810 810 def mainloop(self,sys_exit=0,banner=None):
811 811
812 812 self._banner = banner
813 813
814 814 if self.gtk.pygtk_version >= (2,4,0):
815 815 import gobject
816 816 gobject.idle_add(self.on_timer)
817 817 else:
818 818 self.gtk.idle_add(self.on_timer)
819 819
820 820 if sys.platform != 'win32':
821 821 try:
822 822 if self.gtk.gtk_version[0] >= 2:
823 823 self.gtk.gdk.threads_init()
824 824 except AttributeError:
825 825 pass
826 826 except RuntimeError:
827 827 error('Your pyGTK likely has not been compiled with '
828 828 'threading support.\n'
829 829 'The exception printout is below.\n'
830 830 'You can either rebuild pyGTK with threads, or '
831 831 'try using \n'
832 832 'matplotlib with a different backend (like Tk or WX).\n'
833 833 'Note that matplotlib will most likely not work in its '
834 834 'current state!')
835 835 self.IP.InteractiveTB()
836 836
837 837 self.start()
838 838 self.gtk.gdk.threads_enter()
839 839 self.gtk_mainloop()
840 840 self.gtk.gdk.threads_leave()
841 841 self.join()
842 842
843 843 def on_timer(self):
844 844 """Called when GTK is idle.
845 845
846 846 Must return True always, otherwise GTK stops calling it"""
847 847
848 848 update_tk(self.tk)
849 849 self.IP.runcode()
850 850 time.sleep(0.01)
851 851 return True
852 852
853 853
854 854 class IPShellWX(IPThread):
855 855 """Run a wx mainloop() in a separate thread.
856 856
857 857 Python commands can be passed to the thread where they will be executed.
858 858 This is implemented by periodically checking for passed code using a
859 859 GTK timeout callback."""
860 860
861 861 TIMEOUT = 100 # Millisecond interval between timeouts.
862 862
863 863 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
864 864 debug=1,shell_class=MTInteractiveShell):
865 865
866 866 self.IP = make_IPython(argv,user_ns=user_ns,
867 867 user_global_ns=user_global_ns,
868 868 debug=debug,
869 869 shell_class=shell_class,
870 870 on_kill=[self.wxexit])
871 871
872 872 wantedwxversion=self.IP.rc.wxversion
873 873 if wantedwxversion!="0":
874 874 try:
875 875 import wxversion
876 876 except ImportError:
877 877 error('The wxversion module is needed for WX version selection')
878 878 else:
879 879 try:
880 880 wxversion.select(wantedwxversion)
881 881 except:
882 882 self.IP.InteractiveTB()
883 883 error('Requested wxPython version %s could not be loaded' %
884 884 wantedwxversion)
885 885
886 886 import wx
887 887
888 888 threading.Thread.__init__(self)
889 889 self.wx = wx
890 890 self.wx_mainloop = hijack_wx()
891 891
892 892 # Allows us to use both Tk and GTK.
893 893 self.tk = get_tk()
894 894
895 895 # HACK: slot for banner in self; it will be passed to the mainloop
896 896 # method only and .run() needs it. The actual value will be set by
897 897 # .mainloop().
898 898 self._banner = None
899 899
900 900 self.app = None
901 901
902 902 def wxexit(self, *args):
903 903 if self.app is not None:
904 904 self.app.agent.timer.Stop()
905 905 self.app.ExitMainLoop()
906 906
907 907 def mainloop(self,sys_exit=0,banner=None):
908 908
909 909 self._banner = banner
910 910
911 911 self.start()
912 912
913 913 class TimerAgent(self.wx.MiniFrame):
914 914 wx = self.wx
915 915 IP = self.IP
916 916 tk = self.tk
917 917 def __init__(self, parent, interval):
918 918 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
919 919 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
920 920 size=(100, 100),style=style)
921 921 self.Show(False)
922 922 self.interval = interval
923 923 self.timerId = self.wx.NewId()
924 924
925 925 def StartWork(self):
926 926 self.timer = self.wx.Timer(self, self.timerId)
927 927 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
928 928 self.timer.Start(self.interval)
929 929
930 930 def OnTimer(self, event):
931 931 update_tk(self.tk)
932 932 self.IP.runcode()
933 933
934 934 class App(self.wx.App):
935 935 wx = self.wx
936 936 TIMEOUT = self.TIMEOUT
937 937 def OnInit(self):
938 938 'Create the main window and insert the custom frame'
939 939 self.agent = TimerAgent(None, self.TIMEOUT)
940 940 self.agent.Show(False)
941 941 self.agent.StartWork()
942 942 return True
943 943
944 944 self.app = App(redirect=False)
945 945 self.wx_mainloop(self.app)
946 946 self.join()
947 947
948 948
949 949 class IPShellQt(IPThread):
950 950 """Run a Qt event loop in a separate thread.
951 951
952 952 Python commands can be passed to the thread where they will be executed.
953 953 This is implemented by periodically checking for passed code using a
954 954 Qt timer / slot."""
955 955
956 956 TIMEOUT = 100 # Millisecond interval between timeouts.
957 957
958 958 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
959 959 debug=0, shell_class=MTInteractiveShell):
960 960
961 961 import qt
962 962
963 963 self.exec_loop = hijack_qt()
964 964
965 965 # Allows us to use both Tk and QT.
966 966 self.tk = get_tk()
967 967
968 968 self.IP = make_IPython(argv,
969 969 user_ns=user_ns,
970 970 user_global_ns=user_global_ns,
971 971 debug=debug,
972 972 shell_class=shell_class,
973 973 on_kill=[qt.qApp.exit])
974 974
975 975 # HACK: slot for banner in self; it will be passed to the mainloop
976 976 # method only and .run() needs it. The actual value will be set by
977 977 # .mainloop().
978 978 self._banner = None
979 979
980 980 threading.Thread.__init__(self)
981 981
982 982 def mainloop(self, sys_exit=0, banner=None):
983 983
984 984 import qt
985 985
986 986 self._banner = banner
987 987
988 988 if qt.QApplication.startingUp():
989 989 a = qt.QApplication(sys.argv)
990 990
991 991 self.timer = qt.QTimer()
992 992 qt.QObject.connect(self.timer,
993 993 qt.SIGNAL('timeout()'),
994 994 self.on_timer)
995 995
996 996 self.start()
997 997 self.timer.start(self.TIMEOUT, True)
998 998 while True:
999 999 if self.IP._kill: break
1000 1000 self.exec_loop()
1001 1001 self.join()
1002 1002
1003 1003 def on_timer(self):
1004 1004 update_tk(self.tk)
1005 1005 result = self.IP.runcode()
1006 1006 self.timer.start(self.TIMEOUT, True)
1007 1007 return result
1008 1008
1009 1009
1010 1010 class IPShellQt4(IPThread):
1011 1011 """Run a Qt event loop in a separate thread.
1012 1012
1013 1013 Python commands can be passed to the thread where they will be executed.
1014 1014 This is implemented by periodically checking for passed code using a
1015 1015 Qt timer / slot."""
1016 1016
1017 1017 TIMEOUT = 100 # Millisecond interval between timeouts.
1018 1018
1019 1019 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1020 1020 debug=0, shell_class=MTInteractiveShell):
1021 1021
1022 1022 from PyQt4 import QtCore, QtGui
1023 1023
1024 1024 try:
1025 1025 # present in PyQt4-4.2.1 or later
1026 1026 QtCore.pyqtRemoveInputHook()
1027 1027 except AttributeError:
1028 1028 pass
1029 1029
1030 1030 if QtCore.PYQT_VERSION_STR == '4.3':
1031 1031 warn('''PyQt4 version 4.3 detected.
1032 1032 If you experience repeated threading warnings, please update PyQt4.
1033 1033 ''')
1034 1034
1035 1035 self.exec_ = hijack_qt4()
1036 1036
1037 1037 # Allows us to use both Tk and QT.
1038 1038 self.tk = get_tk()
1039 1039
1040 1040 self.IP = make_IPython(argv,
1041 1041 user_ns=user_ns,
1042 1042 user_global_ns=user_global_ns,
1043 1043 debug=debug,
1044 1044 shell_class=shell_class,
1045 1045 on_kill=[QtGui.qApp.exit])
1046 1046
1047 1047 # HACK: slot for banner in self; it will be passed to the mainloop
1048 1048 # method only and .run() needs it. The actual value will be set by
1049 1049 # .mainloop().
1050 1050 self._banner = None
1051 1051
1052 1052 threading.Thread.__init__(self)
1053 1053
1054 1054 def mainloop(self, sys_exit=0, banner=None):
1055 1055
1056 1056 from PyQt4 import QtCore, QtGui
1057 1057
1058 1058 self._banner = banner
1059 1059
1060 1060 if QtGui.QApplication.startingUp():
1061 1061 a = QtGui.QApplication(sys.argv)
1062 1062
1063 1063 self.timer = QtCore.QTimer()
1064 1064 QtCore.QObject.connect(self.timer,
1065 1065 QtCore.SIGNAL('timeout()'),
1066 1066 self.on_timer)
1067 1067
1068 1068 self.start()
1069 1069 self.timer.start(self.TIMEOUT)
1070 1070 while True:
1071 1071 if self.IP._kill: break
1072 1072 self.exec_()
1073 1073 self.join()
1074 1074
1075 1075 def on_timer(self):
1076 1076 update_tk(self.tk)
1077 1077 result = self.IP.runcode()
1078 1078 self.timer.start(self.TIMEOUT)
1079 1079 return result
1080 1080
1081 1081
1082 1082 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1083 1083 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1084 1084 def _load_pylab(user_ns):
1085 1085 """Allow users to disable pulling all of pylab into the top-level
1086 1086 namespace.
1087 1087
1088 1088 This little utility must be called AFTER the actual ipython instance is
1089 1089 running, since only then will the options file have been fully parsed."""
1090 1090
1091 1091 ip = IPython.ipapi.get()
1092 1092 if ip.options.pylab_import_all:
1093 1093 ip.ex("from matplotlib.pylab import *")
1094 1094 ip.IP.user_config_ns.update(ip.user_ns)
1095 1095
1096 1096
1097 1097 class IPShellMatplotlib(IPShell):
1098 1098 """Subclass IPShell with MatplotlibShell as the internal shell.
1099 1099
1100 1100 Single-threaded class, meant for the Tk* and FLTK* backends.
1101 1101
1102 1102 Having this on a separate class simplifies the external driver code."""
1103 1103
1104 1104 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1105 1105 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1106 1106 shell_class=MatplotlibShell)
1107 1107 _load_pylab(self.IP.user_ns)
1108 1108
1109 1109 class IPShellMatplotlibGTK(IPShellGTK):
1110 1110 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1111 1111
1112 1112 Multi-threaded class, meant for the GTK* backends."""
1113 1113
1114 1114 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1115 1115 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1116 1116 shell_class=MatplotlibMTShell)
1117 1117 _load_pylab(self.IP.user_ns)
1118 1118
1119 1119 class IPShellMatplotlibWX(IPShellWX):
1120 1120 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1121 1121
1122 1122 Multi-threaded class, meant for the WX* backends."""
1123 1123
1124 1124 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1125 1125 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1126 1126 shell_class=MatplotlibMTShell)
1127 1127 _load_pylab(self.IP.user_ns)
1128 1128
1129 1129 class IPShellMatplotlibQt(IPShellQt):
1130 1130 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1131 1131
1132 1132 Multi-threaded class, meant for the Qt* backends."""
1133 1133
1134 1134 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1135 1135 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1136 1136 shell_class=MatplotlibMTShell)
1137 1137 _load_pylab(self.IP.user_ns)
1138 1138
1139 1139 class IPShellMatplotlibQt4(IPShellQt4):
1140 1140 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1141 1141
1142 1142 Multi-threaded class, meant for the Qt4* backends."""
1143 1143
1144 1144 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1145 1145 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1146 1146 shell_class=MatplotlibMTShell)
1147 1147 _load_pylab(self.IP.user_ns)
1148 1148
1149 1149 #-----------------------------------------------------------------------------
1150 1150 # Factory functions to actually start the proper thread-aware shell
1151 1151
1152 def check_gtk(mode):
1153 import gtk
1154 if hasattr(gtk,'set_interactive'):
1155 gtk.set_interactive(False)
1156 return 'tkthread'
1157 else:
1158 return mode
1159
1160
1152 1161 def _select_shell(argv):
1153 1162 """Select a shell from the given argv vector.
1154 1163
1155 1164 This function implements the threading selection policy, allowing runtime
1156 1165 control of the threading mode, both for general users and for matplotlib.
1157 1166
1158 1167 Return:
1159 1168 Shell class to be instantiated for runtime operation.
1160 1169 """
1161 1170
1162 1171 global USE_TK
1163 1172
1164 1173 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1165 1174 'wthread' : IPShellMatplotlibWX,
1166 1175 'qthread' : IPShellMatplotlibQt,
1167 1176 'q4thread' : IPShellMatplotlibQt4,
1168 1177 'tkthread' : IPShellMatplotlib, # Tk is built-in
1169 1178 }
1170 1179
1171 1180 th_shell = {'gthread' : IPShellGTK,
1172 1181 'wthread' : IPShellWX,
1173 1182 'qthread' : IPShellQt,
1174 1183 'q4thread' : IPShellQt4,
1175 1184 'tkthread' : IPShell, # Tk is built-in
1176 1185 }
1177 1186
1178 1187 backends = {'gthread' : 'GTKAgg',
1179 1188 'wthread' : 'WXAgg',
1180 1189 'qthread' : 'QtAgg',
1181 1190 'q4thread' :'Qt4Agg',
1182 1191 'tkthread' :'TkAgg',
1183 1192 }
1184 1193
1185 1194 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1186 1195 'tkthread'])
1187 1196 user_opts = set([s.replace('-','') for s in argv[:3]])
1188 1197 special_opts = user_opts & all_opts
1189 1198
1190 1199 if 'tk' in special_opts:
1191 1200 USE_TK = True
1192 1201 special_opts.remove('tk')
1193 1202
1194 1203 if 'pylab' in special_opts:
1195 1204
1196 1205 try:
1197 1206 import matplotlib
1198 1207 except ImportError:
1199 1208 error('matplotlib could NOT be imported! Starting normal IPython.')
1200 1209 return IPShell
1201 1210
1202 1211 special_opts.remove('pylab')
1203 1212 # If there's any option left, it means the user wants to force the
1204 1213 # threading backend, else it's auto-selected from the rc file
1205 1214 if special_opts:
1206 1215 th_mode = special_opts.pop()
1207 1216 matplotlib.rcParams['backend'] = backends[th_mode]
1208 1217 else:
1209 1218 backend = matplotlib.rcParams['backend']
1210 1219 if backend.startswith('GTK'):
1211 1220 th_mode = 'gthread'
1212 1221 elif backend.startswith('WX'):
1213 1222 th_mode = 'wthread'
1214 1223 elif backend.startswith('Qt4'):
1215 1224 th_mode = 'q4thread'
1216 1225 elif backend.startswith('Qt'):
1217 1226 th_mode = 'qthread'
1218 1227 else:
1219 1228 # Any other backend, use plain Tk
1220 1229 th_mode = 'tkthread'
1230
1231 # New versions of pygtk don't need the brittle threaded support.
1232 th_mode = check_gtk(th_mode)
1221 1233
1222 1234 return mpl_shell[th_mode]
1223 1235 else:
1224 1236 # No pylab requested, just plain threads
1225 1237 try:
1226 1238 th_mode = special_opts.pop()
1227 1239 except KeyError:
1228 1240 th_mode = 'tkthread'
1241
1242 # New versions of pygtk don't need the brittle threaded support.
1243 th_mode = check_gtk(th_mode)
1229 1244 return th_shell[th_mode]
1230 1245
1231 1246
1232 1247 # This is the one which should be called by external code.
1233 1248 def start(user_ns = None):
1234 1249 """Return a running shell instance, dealing with threading options.
1235 1250
1236 1251 This is a factory function which will instantiate the proper IPython shell
1237 1252 based on the user's threading choice. Such a selector is needed because
1238 1253 different GUI toolkits require different thread handling details."""
1239 1254
1240 1255 shell = _select_shell(sys.argv)
1241 1256 return shell(user_ns = user_ns)
1242 1257
1243 1258 # Some aliases for backwards compatibility
1244 1259 IPythonShell = IPShell
1245 1260 IPythonShellEmbed = IPShellEmbed
1246 1261 #************************ End of file <Shell.py> ***************************
@@ -1,605 +1,613 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 id.rc_override=dict(
24 24 prompt_in1="Yade [\#]:",
25 25 prompt_in2=" .\D..",
26 26 prompt_out=" -> [\#]:"
27 27 )
28 id.reconfig_shell()
28 29
29 30 import ipython_console_highlighting as ich
30 31 ich.IPythonConsoleLexer.input_prompt=
31 32 re.compile("(Yade \[[0-9]+\]: )|( \.\.\.+:)")
32 33 ich.IPythonConsoleLexer.output_prompt=
33 34 re.compile("(( -> )|(Out)\[[0-9]+\]: )|( \.\.\.+:)")
34 35 ich.IPythonConsoleLexer.continue_prompt=re.compile(" \.\.\.+:")
35 36
36 37
37 38 ToDo
38 39 ----
39 40
40 41 - Turn the ad-hoc test() function into a real test suite.
41 42 - Break up ipython-specific functionality from matplotlib stuff into better
42 43 separated code.
43 44 - Make sure %bookmarks used internally are removed on exit.
44 45
45 46
46 47 Authors
47 48 -------
48 49
49 50 - John D Hunter: orignal author.
50 51 - Fernando Perez: refactoring, documentation, cleanups.
51 52 - VáclavŠmilauer <eudoxos-AT-arcig.cz>: Prompt generatlizations.
52 53 """
53 54
54 55 #-----------------------------------------------------------------------------
55 56 # Imports
56 57 #-----------------------------------------------------------------------------
57 58
58 59 # Stdlib
59 60 import cStringIO
60 61 import imp
61 62 import os
62 63 import re
63 64 import shutil
64 65 import sys
65 66 import warnings
66 67
67 68 # To keep compatibility with various python versions
68 69 try:
69 70 from hashlib import md5
70 71 except ImportError:
71 72 from md5 import md5
72 73
73 74 # Third-party
74 75 import matplotlib
75 76 import sphinx
76 77 from docutils.parsers.rst import directives
77 78
78 79 matplotlib.use('Agg')
79 80
80 81 # Our own
81 82 import IPython
82 83 from IPython.Shell import MatplotlibShell
83 84
84 85 #-----------------------------------------------------------------------------
85 86 # Globals
86 87 #-----------------------------------------------------------------------------
87 88
88 89 sphinx_version = sphinx.__version__.split(".")
89 90 # The split is necessary for sphinx beta versions where the string is
90 91 # '6b1'
91 92 sphinx_version = tuple([int(re.split('[a-z]', x)[0])
92 93 for x in sphinx_version[:2]])
93 94
94 95 COMMENT, INPUT, OUTPUT = range(3)
95 96 rc_override = {}
96 97 rgxin = re.compile('In \[(\d+)\]:\s?(.*)\s*')
97 98 rgxout = re.compile('Out\[(\d+)\]:\s?(.*)\s*')
98 99 fmtin = 'In [%d]:'
99 100 fmtout = 'Out[%d]:'
100 101
101 102 #-----------------------------------------------------------------------------
102 103 # Functions and class declarations
103 104 #-----------------------------------------------------------------------------
104 105 def block_parser(part):
105 106 """
106 107 part is a string of ipython text, comprised of at most one
107 108 input, one ouput, comments, and blank lines. The block parser
108 109 parses the text into a list of::
109 110
110 111 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
111 112
112 113 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
113 114 data is, depending on the type of token::
114 115
115 116 COMMENT : the comment string
116 117
117 118 INPUT: the (DECORATOR, INPUT_LINE, REST) where
118 119 DECORATOR: the input decorator (or None)
119 120 INPUT_LINE: the input as string (possibly multi-line)
120 121 REST : any stdout generated by the input line (not OUTPUT)
121 122
122 123
123 124 OUTPUT: the output string, possibly multi-line
124 125 """
125 126
126 127 block = []
127 128 lines = part.split('\n')
128 129 N = len(lines)
129 130 i = 0
130 131 decorator = None
131 132 while 1:
132 133
133 134 if i==N:
134 135 # nothing left to parse -- the last line
135 136 break
136 137
137 138 line = lines[i]
138 139 i += 1
139 140 line_stripped = line.strip()
140 141 if line_stripped.startswith('#'):
141 142 block.append((COMMENT, line))
142 143 continue
143 144
144 145 if line_stripped.startswith('@'):
145 146 # we're assuming at most one decorator -- may need to
146 147 # rethink
147 148 decorator = line_stripped
148 149 continue
149 150
150 151 # does this look like an input line?
151 152 matchin = rgxin.match(line)
152 153 if matchin:
153 154 lineno, inputline = int(matchin.group(1)), matchin.group(2)
154 155
155 156 # the ....: continuation string
156 157 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
157 158 Nc = len(continuation)
158 159 # input lines can continue on for more than one line, if
159 160 # we have a '\' line continuation char or a function call
160 161 # echo line 'print'. The input line can only be
161 162 # terminated by the end of the block or an output line, so
162 163 # we parse out the rest of the input line if it is
163 164 # multiline as well as any echo text
164 165
165 166 rest = []
166 167 while i<N:
167 168
168 169 # look ahead; if the next line is blank, or a comment, or
169 170 # an output line, we're done
170 171
171 172 nextline = lines[i]
172 173 matchout = rgxout.match(nextline)
173 174 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
174 175 if matchout or nextline.startswith('#'):
175 176 break
176 177 elif nextline.startswith(continuation):
177 178 inputline += '\n' + nextline[Nc:]
178 179 else:
179 180 rest.append(nextline)
180 181 i+= 1
181 182
182 183 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
183 184 continue
184 185
185 186 # if it looks like an output line grab all the text to the end
186 187 # of the block
187 188 matchout = rgxout.match(line)
188 189 if matchout:
189 190 lineno, output = int(matchout.group(1)), matchout.group(2)
190 191 if i<N-1:
191 192 output = '\n'.join([output] + lines[i:])
192 193
193 194 block.append((OUTPUT, output))
194 195 break
195 196
196 197 return block
197 198
198 199
199 200 class EmbeddedSphinxShell(object):
200 201 """An embedded IPython instance to run inside Sphinx"""
201 202
202 203 def __init__(self):
203 204
204 205 self.cout = cStringIO.StringIO()
205 206
206 207 IPython.Shell.Term.cout = self.cout
207 208 IPython.Shell.Term.cerr = self.cout
208 209 argv = ['-autocall', '0']
209 210 self.user_ns = {}
210 211 self.user_glocal_ns = {}
211 212
212 213 self.IP = IPython.ipmaker.make_IPython(
213 214 argv, self.user_ns, self.user_glocal_ns, embedded=True,
214 215 #shell_class=IPython.Shell.InteractiveShell,
215 216 shell_class=MatplotlibShell,
216 rc_override = dict(colors = 'NoColor'), **rc_override)
217 rc_override = dict(colors = 'NoColor', **rc_override))
217 218
218 219 self.input = ''
219 220 self.output = ''
220 221
221 222 self.is_verbatim = False
222 223 self.is_doctest = False
223 224 self.is_suppress = False
224 225
225 226 # on the first call to the savefig decorator, we'll import
226 227 # pyplot as plt so we can make a call to the plt.gcf().savefig
227 228 self._pyplot_imported = False
228 229
229 230 # we need bookmark the current dir first so we can save
230 231 # relative to it
231 232 self.process_input_line('bookmark ipy_basedir')
232 233 self.cout.seek(0)
233 234 self.cout.truncate(0)
234 235
235 236 def process_input_line(self, line):
236 237 """process the input, capturing stdout"""
237 238 #print "input='%s'"%self.input
238 239 stdout = sys.stdout
239 240 sys.stdout = self.cout
240 241 #self.IP.resetbuffer()
241 242 self.IP.push(self.IP.prefilter(line, 0))
242 243 #self.IP.runlines(line)
243 244 sys.stdout = stdout
244 245
245 246 # Callbacks for each type of token
246 247 def process_input(self, data, input_prompt, lineno):
247 248 """Process data block for INPUT token."""
248 249 decorator, input, rest = data
249 250 image_file = None
250 251 #print 'INPUT:', data
251 252 is_verbatim = decorator=='@verbatim' or self.is_verbatim
252 253 is_doctest = decorator=='@doctest' or self.is_doctest
253 254 is_suppress = decorator=='@suppress' or self.is_suppress
254 255 is_savefig = decorator is not None and \
255 256 decorator.startswith('@savefig')
256 257
257 258 input_lines = input.split('\n')
258 259
259 260 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
260 261 Nc = len(continuation)
261 262
262 263 if is_savefig:
263 264 saveargs = decorator.split(' ')
264 265 filename = saveargs[1]
265 266 outfile = os.path.join('_static/%s'%filename)
266 267 # build out an image directive like
267 268 # .. image:: somefile.png
268 269 # :width 4in
269 270 #
270 271 # from an input like
271 272 # savefig somefile.png width=4in
272 273 imagerows = ['.. image:: %s'%outfile]
273 274
274 275 for kwarg in saveargs[2:]:
275 276 arg, val = kwarg.split('=')
276 277 arg = arg.strip()
277 278 val = val.strip()
278 279 imagerows.append(' :%s: %s'%(arg, val))
279 280
280 281 image_file = outfile
281 282 image_directive = '\n'.join(imagerows)
282 283
283 284 # TODO: can we get "rest" from ipython
284 285 #self.process_input_line('\n'.join(input_lines))
285 286
286 287 ret = []
287 288 is_semicolon = False
288 289
289 290 for i, line in enumerate(input_lines):
290 291 if line.endswith(';'):
291 292 is_semicolon = True
292 293
293 294 if i==0:
294 295 # process the first input line
295 296 if is_verbatim:
296 297 self.process_input_line('')
297 298 else:
298 299 # only submit the line in non-verbatim mode
299 300 self.process_input_line(line)
300 301 formatted_line = '%s %s'%(input_prompt, line)
301 302 else:
302 303 # process a continuation line
303 304 if not is_verbatim:
304 305 self.process_input_line(line)
305 306
306 307 formatted_line = '%s %s'%(continuation, line)
307 308
308 309 if not is_suppress:
309 310 ret.append(formatted_line)
310 311
311 312 if not is_suppress:
312 313 if len(rest.strip()):
313 314 if is_verbatim:
314 315 # the "rest" is the standard output of the
315 316 # input, which needs to be added in
316 317 # verbatim mode
317 318 ret.append(rest)
318 319
319 320 self.cout.seek(0)
320 321 output = self.cout.read()
321 322 if not is_suppress and not is_semicolon:
322 323 ret.append(output)
323 324
324 325 self.cout.truncate(0)
325 326 return ret, input_lines, output, is_doctest, image_file
326 327 #print 'OUTPUT', output # dbg
327 328
328 329 def process_output(self, data, output_prompt,
329 330 input_lines, output, is_doctest, image_file):
330 331 """Process data block for OUTPUT token."""
331 332 if is_doctest:
332 333 submitted = data.strip()
333 334 found = output
334 335 if found is not None:
335 336 ind = found.find(output_prompt)
336 337 if ind<0:
337 338 raise RuntimeError('output prompt="%s" does not match out line=%s'%(output_prompt, found))
338 339 found = found[len(output_prompt):].strip()
339 340
340 341 if found!=submitted:
341 342 raise RuntimeError('doctest failure for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted))
342 343 #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted)
343 344
344 345 def process_comment(self, data):
345 346 """Process data block for COMMENT token."""
346 347 if not self.is_suppress:
347 348 return [data]
348 349
349 350 def process_block(self, block):
350 351 """
351 352 process block from the block_parser and return a list of processed lines
352 353 """
353 354
354 355 ret = []
355 356 output = None
356 357 input_lines = None
357 358
358 359 m = rgxin.match(str(self.IP.outputcache.prompt1).strip())
359 360 lineno = int(m.group(1))
360 361
361 362 input_prompt = fmtin%lineno
362 363 output_prompt = fmtout%lineno
363 364 image_file = None
364 365 image_directive = None
365 366 # XXX - This needs a second refactor. There's too much state being
366 367 # held globally, which makes for a very awkward interface and large,
367 368 # hard to test functions. I've already broken this up at least into
368 369 # three separate processors to isolate the logic better, but this only
369 370 # serves to highlight the coupling. Next we need to clean it up...
370 371 for token, data in block:
371 372 if token==COMMENT:
372 373 out_data = self.process_comment(data)
373 374 elif token==INPUT:
374 375 out_data, input_lines, output, is_doctest, image_file= \
375 376 self.process_input(data, input_prompt, lineno)
376 377 elif token==OUTPUT:
377 378 out_data = \
378 379 self.process_output(data, output_prompt,
379 380 input_lines, output, is_doctest,
380 381 image_file)
381 382 if out_data:
382 383 ret.extend(out_data)
383 384
384 385 if image_file is not None:
385 386 self.ensure_pyplot()
386 387 command = 'plt.gcf().savefig("%s")'%image_file
387 388 #print 'SAVEFIG', command # dbg
388 389 self.process_input_line('bookmark ipy_thisdir')
389 390 self.process_input_line('cd -b ipy_basedir')
390 391 self.process_input_line(command)
391 392 self.process_input_line('cd -b ipy_thisdir')
392 393 self.cout.seek(0)
393 394 self.cout.truncate(0)
394 395 return ret, image_directive
395 396
396 397 def ensure_pyplot(self):
397 398 if self._pyplot_imported:
398 399 return
399 400 self.process_input_line('import matplotlib.pyplot as plt')
400 401
401 402 # A global instance used below. XXX: not sure why this can't be created inside
402 403 # ipython_directive itself.
403 404 shell = EmbeddedSphinxShell()
404 405
406 def reconfig_shell():
407 """Called after setting module-level variables to re-instantiate
408 with the set values (since shell is instantiated first at import-time
409 when module variables have default values)"""
410 global shell
411 shell = EmbeddedSphinxShell()
412
405 413
406 414 def ipython_directive(name, arguments, options, content, lineno,
407 415 content_offset, block_text, state, state_machine,
408 416 ):
409 417
410 418 debug = ipython_directive.DEBUG
411 419 shell.is_suppress = options.has_key('suppress')
412 420 shell.is_doctest = options.has_key('doctest')
413 421 shell.is_verbatim = options.has_key('verbatim')
414 422
415 423 #print 'ipy', shell.is_suppress, options
416 424 parts = '\n'.join(content).split('\n\n')
417 425 lines = ['.. sourcecode:: ipython', '']
418 426
419 427 figures = []
420 428 for part in parts:
421 429 block = block_parser(part)
422 430
423 431 if len(block):
424 432 rows, figure = shell.process_block(block)
425 433 for row in rows:
426 434 lines.extend([' %s'%line for line in row.split('\n')])
427 435
428 436 if figure is not None:
429 437 figures.append(figure)
430 438
431 439 for figure in figures:
432 440 lines.append('')
433 441 lines.extend(figure.split('\n'))
434 442 lines.append('')
435 443
436 444 #print lines
437 445 if len(lines)>2:
438 446 if debug:
439 447 print '\n'.join(lines)
440 448 else:
441 449 #print 'INSERTING %d lines'%len(lines)
442 450 state_machine.insert_input(
443 451 lines, state_machine.input_lines.source(0))
444 452
445 453 return []
446 454
447 455 ipython_directive.DEBUG = False
448 456
449 457 # Enable as a proper Sphinx directive
450 458 def setup(app):
451 459 setup.app = app
452 460 options = {'suppress': directives.flag,
453 461 'doctest': directives.flag,
454 462 'verbatim': directives.flag,
455 463 }
456 464
457 465 app.add_directive('ipython', ipython_directive, True, (0, 2, 0), **options)
458 466
459 467
460 468 # Simple smoke test, needs to be converted to a proper automatic test.
461 469 def test():
462 470
463 471 examples = [
464 472 r"""
465 473 In [9]: pwd
466 474 Out[9]: '/home/jdhunter/py4science/book'
467 475
468 476 In [10]: cd bookdata/
469 477 /home/jdhunter/py4science/book/bookdata
470 478
471 479 In [2]: from pylab import *
472 480
473 481 In [2]: ion()
474 482
475 483 In [3]: im = imread('stinkbug.png')
476 484
477 485 @savefig mystinkbug.png width=4in
478 486 In [4]: imshow(im)
479 487 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
480 488
481 489 """,
482 490 r"""
483 491
484 492 In [1]: x = 'hello world'
485 493
486 494 # string methods can be
487 495 # used to alter the string
488 496 @doctest
489 497 In [2]: x.upper()
490 498 Out[2]: 'HELLO WORLD'
491 499
492 500 @verbatim
493 501 In [3]: x.st<TAB>
494 502 x.startswith x.strip
495 503 """,
496 504 r"""
497 505
498 506 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
499 507 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
500 508
501 509 In [131]: print url.split('&')
502 510 ['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']
503 511
504 512 In [60]: import urllib
505 513
506 514 """,
507 515 r"""\
508 516
509 517 In [133]: import numpy.random
510 518
511 519 @suppress
512 520 In [134]: numpy.random.seed(2358)
513 521
514 522 @doctest
515 523 In [135]: np.random.rand(10,2)
516 524 Out[135]:
517 525 array([[ 0.64524308, 0.59943846],
518 526 [ 0.47102322, 0.8715456 ],
519 527 [ 0.29370834, 0.74776844],
520 528 [ 0.99539577, 0.1313423 ],
521 529 [ 0.16250302, 0.21103583],
522 530 [ 0.81626524, 0.1312433 ],
523 531 [ 0.67338089, 0.72302393],
524 532 [ 0.7566368 , 0.07033696],
525 533 [ 0.22591016, 0.77731835],
526 534 [ 0.0072729 , 0.34273127]])
527 535
528 536 """,
529 537
530 538 r"""
531 539 In [106]: print x
532 540 jdh
533 541
534 542 In [109]: for i in range(10):
535 543 .....: print i
536 544 .....:
537 545 .....:
538 546 0
539 547 1
540 548 2
541 549 3
542 550 4
543 551 5
544 552 6
545 553 7
546 554 8
547 555 9
548 556
549 557
550 558 """,
551 559
552 560 r"""
553 561
554 562 In [144]: from pylab import *
555 563
556 564 In [145]: ion()
557 565
558 566 # use a semicolon to suppress the output
559 567 @savefig test_hist.png width=4in
560 568 In [151]: hist(np.random.randn(10000), 100);
561 569
562 570
563 571 @savefig test_plot.png width=4in
564 572 In [151]: plot(np.random.randn(10000), 'o');
565 573 """,
566 574
567 575 r"""
568 576 # use a semicolon to suppress the output
569 577 In [151]: plt.clf()
570 578
571 579 @savefig plot_simple.png width=4in
572 580 In [151]: plot([1,2,3])
573 581
574 582 @savefig hist_simple.png width=4in
575 583 In [151]: hist(np.random.randn(10000), 100);
576 584
577 585 """,
578 586 r"""
579 587 # update the current fig
580 588 In [151]: ylabel('number')
581 589
582 590 In [152]: title('normal distribution')
583 591
584 592
585 593 @savefig hist_with_text.png
586 594 In [153]: grid(True)
587 595
588 596 """,
589 597 ]
590 598
591 599
592 600 ipython_directive.DEBUG = True
593 601 #options = dict(suppress=True)
594 602 options = dict()
595 603 for example in examples:
596 604 content = example.split('\n')
597 605 ipython_directive('debug', arguments=None, options=options,
598 606 content=content, lineno=0,
599 607 content_offset=None, block_text=None,
600 608 state=None, state_machine=None,
601 609 )
602 610
603 611 # Run test suite as a script
604 612 if __name__=='__main__':
605 613 test()
General Comments 0
You need to be logged in to leave comments. Login now