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