##// END OF EJS Templates
MTInteractiveShell.runsource() - return immediately if we are being killed (code would never get run -> deadlock)
vivainio2 -
Show More
@@ -1,1201 +1,1205
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
362 362 # A queue to hold the code to be executed.
363 363 self.code_queue = Queue.Queue()
364 364
365 365 # Stuff to do at closing time
366 366 self._kill = None
367 367 on_kill = kw.get('on_kill', [])
368 368 # Check that all things to kill are callable:
369 369 for t in on_kill:
370 370 if not callable(t):
371 371 raise TypeError,'on_kill must be a list of callables'
372 372 self.on_kill = on_kill
373 373 # thread identity of the "worker thread" (that may execute code directly)
374 374 self.worker_ident = None
375 375 def runsource(self, source, filename="<input>", symbol="single"):
376 376 """Compile and run some source in the interpreter.
377 377
378 378 Modified version of code.py's runsource(), to handle threading issues.
379 379 See the original for full docstring details."""
380 380
381 381 global KBINT
382 382
383 383 # If Ctrl-C was typed, we reset the flag and return right away
384 384 if KBINT:
385 385 KBINT = False
386 386 return False
387 387
388 if self._kill:
389 # can't queue new code if we are being killed
390 return True
391
388 392 try:
389 393 code = self.compile(source, filename, symbol)
390 394 except (OverflowError, SyntaxError, ValueError):
391 395 # Case 1
392 396 self.showsyntaxerror(filename)
393 397 return False
394 398
395 399 if code is None:
396 400 # Case 2
397 401 return True
398 402
399 403 # shortcut - if we are in worker thread, or the worker thread is not running,
400 404 # execute directly (to allow recursion and prevent deadlock if code is run early
401 405 # in IPython construction)
402 406
403 407 if self.worker_ident is None or self.worker_ident == thread.get_ident():
404 408 InteractiveShell.runcode(self,code)
405 409 return
406 410
407 411 # Case 3
408 412 # Store code in queue, so the execution thread can handle it.
409 413
410 414 ev = threading.Event()
411 415 self.code_queue.put((code,ev))
412 416 ev.wait()
413 417 return False
414 418
415 419 def runcode(self):
416 420 """Execute a code object.
417 421
418 422 Multithreaded wrapper around IPython's runcode()."""
419 423
420 424 global CODE_RUN
421 425
422 426 # we are in worker thread, stash out the id for runsource()
423 427 self.worker_ident = thread.get_ident()
424 428
425 429 if self._kill:
426 430 print >>Term.cout, 'Closing threads...',
427 431 Term.cout.flush()
428 432 for tokill in self.on_kill:
429 433 tokill()
430 434 print >>Term.cout, 'Done.'
431 435 # allow kill() to return
432 436 self._kill.set()
433 437 return True
434 438
435 439 # Install sigint handler. We do it every time to ensure that if user
436 440 # code modifies it, we restore our own handling.
437 441 try:
438 442 signal(SIGINT,sigint_handler)
439 443 except SystemError:
440 444 # This happens under Windows, which seems to have all sorts
441 445 # of problems with signal handling. Oh well...
442 446 pass
443 447
444 448 # Flush queue of pending code by calling the run methood of the parent
445 449 # class with all items which may be in the queue.
446 450 code_to_run = None
447 451 while 1:
448 452 try:
449 453 code_to_run, event = self.code_queue.get_nowait()
450 454 except Queue.Empty:
451 455 break
452 456 # Exceptions need to be raised differently depending on which
453 457 # thread is active. This convoluted try/except is only there to
454 458 # protect against asynchronous exceptions, to ensure that a KBINT
455 459 # at the wrong time doesn't deadlock everything. The global
456 460 # CODE_TO_RUN is set to true/false as close as possible to the
457 461 # runcode() call, so that the KBINT handler is correctly informed.
458 462 try:
459 463 try:
460 464 CODE_RUN = True
461 465 InteractiveShell.runcode(self,code_to_run)
462 466 except KeyboardInterrupt:
463 467 print "Keyboard interrupted in mainloop"
464 468 while not self.code_queue.empty():
465 469 code, ev = self.code_queue.get_nowait()
466 470 ev.set()
467 471 break
468 472 finally:
469 473 CODE_RUN = False
470 474 # allow runsource() return from wait
471 475 event.set()
472 476
473 477
474 478 # This MUST return true for gtk threading to work
475 479 return True
476 480
477 481 def kill(self):
478 482 """Kill the thread, returning when it has been shut down."""
479 483 self._kill = threading.Event()
480 484 self._kill.wait()
481 485
482 486 class MatplotlibShellBase:
483 487 """Mixin class to provide the necessary modifications to regular IPython
484 488 shell classes for matplotlib support.
485 489
486 490 Given Python's MRO, this should be used as the FIRST class in the
487 491 inheritance hierarchy, so that it overrides the relevant methods."""
488 492
489 493 def _matplotlib_config(self,name,user_ns):
490 494 """Return items needed to setup the user's shell with matplotlib"""
491 495
492 496 # Initialize matplotlib to interactive mode always
493 497 import matplotlib
494 498 from matplotlib import backends
495 499 matplotlib.interactive(True)
496 500
497 501 def use(arg):
498 502 """IPython wrapper for matplotlib's backend switcher.
499 503
500 504 In interactive use, we can not allow switching to a different
501 505 interactive backend, since thread conflicts will most likely crash
502 506 the python interpreter. This routine does a safety check first,
503 507 and refuses to perform a dangerous switch. It still allows
504 508 switching to non-interactive backends."""
505 509
506 510 if arg in backends.interactive_bk and arg != self.mpl_backend:
507 511 m=('invalid matplotlib backend switch.\n'
508 512 'This script attempted to switch to the interactive '
509 513 'backend: `%s`\n'
510 514 'Your current choice of interactive backend is: `%s`\n\n'
511 515 'Switching interactive matplotlib backends at runtime\n'
512 516 'would crash the python interpreter, '
513 517 'and IPython has blocked it.\n\n'
514 518 'You need to either change your choice of matplotlib backend\n'
515 519 'by editing your .matplotlibrc file, or run this script as a \n'
516 520 'standalone file from the command line, not using IPython.\n' %
517 521 (arg,self.mpl_backend) )
518 522 raise RuntimeError, m
519 523 else:
520 524 self.mpl_use(arg)
521 525 self.mpl_use._called = True
522 526
523 527 self.matplotlib = matplotlib
524 528 self.mpl_backend = matplotlib.rcParams['backend']
525 529
526 530 # we also need to block switching of interactive backends by use()
527 531 self.mpl_use = matplotlib.use
528 532 self.mpl_use._called = False
529 533 # overwrite the original matplotlib.use with our wrapper
530 534 matplotlib.use = use
531 535
532 536 # This must be imported last in the matplotlib series, after
533 537 # backend/interactivity choices have been made
534 538 import matplotlib.pylab as pylab
535 539 self.pylab = pylab
536 540
537 541 self.pylab.show._needmain = False
538 542 # We need to detect at runtime whether show() is called by the user.
539 543 # For this, we wrap it into a decorator which adds a 'called' flag.
540 544 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
541 545
542 546 # Build a user namespace initialized with matplotlib/matlab features.
543 547 user_ns = IPython.ipapi.make_user_ns(user_ns)
544 548
545 549 exec ("import matplotlib\n"
546 550 "import matplotlib.pylab as pylab\n") in user_ns
547 551
548 552 # Build matplotlib info banner
549 553 b="""
550 554 Welcome to pylab, a matplotlib-based Python environment.
551 555 For more information, type 'help(pylab)'.
552 556 """
553 557 return user_ns,b
554 558
555 559 def mplot_exec(self,fname,*where,**kw):
556 560 """Execute a matplotlib script.
557 561
558 562 This is a call to execfile(), but wrapped in safeties to properly
559 563 handle interactive rendering and backend switching."""
560 564
561 565 #print '*** Matplotlib runner ***' # dbg
562 566 # turn off rendering until end of script
563 567 isInteractive = self.matplotlib.rcParams['interactive']
564 568 self.matplotlib.interactive(False)
565 569 self.safe_execfile(fname,*where,**kw)
566 570 self.matplotlib.interactive(isInteractive)
567 571 # make rendering call now, if the user tried to do it
568 572 if self.pylab.draw_if_interactive.called:
569 573 self.pylab.draw()
570 574 self.pylab.draw_if_interactive.called = False
571 575
572 576 # if a backend switch was performed, reverse it now
573 577 if self.mpl_use._called:
574 578 self.matplotlib.rcParams['backend'] = self.mpl_backend
575 579
576 580 def magic_run(self,parameter_s=''):
577 581 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
578 582
579 583 # Fix the docstring so users see the original as well
580 584 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
581 585 "\n *** Modified %run for Matplotlib,"
582 586 " with proper interactive handling ***")
583 587
584 588 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
585 589 # and multithreaded. Note that these are meant for internal use, the IPShell*
586 590 # classes below are the ones meant for public consumption.
587 591
588 592 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
589 593 """Single-threaded shell with matplotlib support."""
590 594
591 595 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
592 596 user_ns=None,user_global_ns=None,**kw):
593 597 user_ns,b2 = self._matplotlib_config(name,user_ns)
594 598 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
595 599 banner2=b2,**kw)
596 600
597 601 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
598 602 """Multi-threaded shell with matplotlib support."""
599 603
600 604 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
601 605 user_ns=None,user_global_ns=None, **kw):
602 606 user_ns,b2 = self._matplotlib_config(name,user_ns)
603 607 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
604 608 banner2=b2,**kw)
605 609
606 610 #-----------------------------------------------------------------------------
607 611 # Utility functions for the different GUI enabled IPShell* classes.
608 612
609 613 def get_tk():
610 614 """Tries to import Tkinter and returns a withdrawn Tkinter root
611 615 window. If Tkinter is already imported or not available, this
612 616 returns None. This function calls `hijack_tk` underneath.
613 617 """
614 618 if not USE_TK or sys.modules.has_key('Tkinter'):
615 619 return None
616 620 else:
617 621 try:
618 622 import Tkinter
619 623 except ImportError:
620 624 return None
621 625 else:
622 626 hijack_tk()
623 627 r = Tkinter.Tk()
624 628 r.withdraw()
625 629 return r
626 630
627 631 def hijack_tk():
628 632 """Modifies Tkinter's mainloop with a dummy so when a module calls
629 633 mainloop, it does not block.
630 634
631 635 """
632 636 def misc_mainloop(self, n=0):
633 637 pass
634 638 def tkinter_mainloop(n=0):
635 639 pass
636 640
637 641 import Tkinter
638 642 Tkinter.Misc.mainloop = misc_mainloop
639 643 Tkinter.mainloop = tkinter_mainloop
640 644
641 645 def update_tk(tk):
642 646 """Updates the Tkinter event loop. This is typically called from
643 647 the respective WX or GTK mainloops.
644 648 """
645 649 if tk:
646 650 tk.update()
647 651
648 652 def hijack_wx():
649 653 """Modifies wxPython's MainLoop with a dummy so user code does not
650 654 block IPython. The hijacked mainloop function is returned.
651 655 """
652 656 def dummy_mainloop(*args, **kw):
653 657 pass
654 658
655 659 try:
656 660 import wx
657 661 except ImportError:
658 662 # For very old versions of WX
659 663 import wxPython as wx
660 664
661 665 ver = wx.__version__
662 666 orig_mainloop = None
663 667 if ver[:3] >= '2.5':
664 668 import wx
665 669 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
666 670 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
667 671 else: raise AttributeError('Could not find wx core module')
668 672 orig_mainloop = core.PyApp_MainLoop
669 673 core.PyApp_MainLoop = dummy_mainloop
670 674 elif ver[:3] == '2.4':
671 675 orig_mainloop = wx.wxc.wxPyApp_MainLoop
672 676 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
673 677 else:
674 678 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
675 679 return orig_mainloop
676 680
677 681 def hijack_gtk():
678 682 """Modifies pyGTK's mainloop with a dummy so user code does not
679 683 block IPython. This function returns the original `gtk.mainloop`
680 684 function that has been hijacked.
681 685 """
682 686 def dummy_mainloop(*args, **kw):
683 687 pass
684 688 import gtk
685 689 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
686 690 else: orig_mainloop = gtk.mainloop
687 691 gtk.mainloop = dummy_mainloop
688 692 gtk.main = dummy_mainloop
689 693 return orig_mainloop
690 694
691 695 def hijack_qt():
692 696 """Modifies PyQt's mainloop with a dummy so user code does not
693 697 block IPython. This function returns the original
694 698 `qt.qApp.exec_loop` function that has been hijacked.
695 699 """
696 700 def dummy_mainloop(*args, **kw):
697 701 pass
698 702 import qt
699 703 orig_mainloop = qt.qApp.exec_loop
700 704 qt.qApp.exec_loop = dummy_mainloop
701 705 qt.QApplication.exec_loop = dummy_mainloop
702 706 return orig_mainloop
703 707
704 708 def hijack_qt4():
705 709 """Modifies PyQt4's mainloop with a dummy so user code does not
706 710 block IPython. This function returns the original
707 711 `QtGui.qApp.exec_` function that has been hijacked.
708 712 """
709 713 def dummy_mainloop(*args, **kw):
710 714 pass
711 715 from PyQt4 import QtGui, QtCore
712 716 orig_mainloop = QtGui.qApp.exec_
713 717 QtGui.qApp.exec_ = dummy_mainloop
714 718 QtGui.QApplication.exec_ = dummy_mainloop
715 719 QtCore.QCoreApplication.exec_ = dummy_mainloop
716 720 return orig_mainloop
717 721
718 722 #-----------------------------------------------------------------------------
719 723 # The IPShell* classes below are the ones meant to be run by external code as
720 724 # IPython instances. Note that unless a specific threading strategy is
721 725 # desired, the factory function start() below should be used instead (it
722 726 # selects the proper threaded class).
723 727
724 728 class IPThread(threading.Thread):
725 729 def run(self):
726 730 self.IP.mainloop(self._banner)
727 731 self.IP.kill()
728 732
729 733 class IPShellGTK(IPThread):
730 734 """Run a gtk mainloop() in a separate thread.
731 735
732 736 Python commands can be passed to the thread where they will be executed.
733 737 This is implemented by periodically checking for passed code using a
734 738 GTK timeout callback."""
735 739
736 740 TIMEOUT = 100 # Millisecond interval between timeouts.
737 741
738 742 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
739 743 debug=1,shell_class=MTInteractiveShell):
740 744
741 745 import gtk
742 746
743 747 self.gtk = gtk
744 748 self.gtk_mainloop = hijack_gtk()
745 749
746 750 # Allows us to use both Tk and GTK.
747 751 self.tk = get_tk()
748 752
749 753 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
750 754 else: mainquit = self.gtk.mainquit
751 755
752 756 self.IP = make_IPython(argv,user_ns=user_ns,
753 757 user_global_ns=user_global_ns,
754 758 debug=debug,
755 759 shell_class=shell_class,
756 760 on_kill=[mainquit])
757 761
758 762 # HACK: slot for banner in self; it will be passed to the mainloop
759 763 # method only and .run() needs it. The actual value will be set by
760 764 # .mainloop().
761 765 self._banner = None
762 766
763 767 threading.Thread.__init__(self)
764 768
765 769 def mainloop(self,sys_exit=0,banner=None):
766 770
767 771 self._banner = banner
768 772
769 773 if self.gtk.pygtk_version >= (2,4,0):
770 774 import gobject
771 775 gobject.idle_add(self.on_timer)
772 776 else:
773 777 self.gtk.idle_add(self.on_timer)
774 778
775 779 if sys.platform != 'win32':
776 780 try:
777 781 if self.gtk.gtk_version[0] >= 2:
778 782 self.gtk.gdk.threads_init()
779 783 except AttributeError:
780 784 pass
781 785 except RuntimeError:
782 786 error('Your pyGTK likely has not been compiled with '
783 787 'threading support.\n'
784 788 'The exception printout is below.\n'
785 789 'You can either rebuild pyGTK with threads, or '
786 790 'try using \n'
787 791 'matplotlib with a different backend (like Tk or WX).\n'
788 792 'Note that matplotlib will most likely not work in its '
789 793 'current state!')
790 794 self.IP.InteractiveTB()
791 795
792 796 self.start()
793 797 self.gtk.gdk.threads_enter()
794 798 self.gtk_mainloop()
795 799 self.gtk.gdk.threads_leave()
796 800 self.join()
797 801
798 802 def on_timer(self):
799 803 """Called when GTK is idle.
800 804
801 805 Must return True always, otherwise GTK stops calling it"""
802 806
803 807 update_tk(self.tk)
804 808 self.IP.runcode()
805 809 time.sleep(0.01)
806 810 return True
807 811
808 812
809 813 class IPShellWX(IPThread):
810 814 """Run a wx mainloop() in a separate thread.
811 815
812 816 Python commands can be passed to the thread where they will be executed.
813 817 This is implemented by periodically checking for passed code using a
814 818 GTK timeout callback."""
815 819
816 820 TIMEOUT = 100 # Millisecond interval between timeouts.
817 821
818 822 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
819 823 debug=1,shell_class=MTInteractiveShell):
820 824
821 825 self.IP = make_IPython(argv,user_ns=user_ns,
822 826 user_global_ns=user_global_ns,
823 827 debug=debug,
824 828 shell_class=shell_class,
825 829 on_kill=[self.wxexit])
826 830
827 831 wantedwxversion=self.IP.rc.wxversion
828 832 if wantedwxversion!="0":
829 833 try:
830 834 import wxversion
831 835 except ImportError:
832 836 error('The wxversion module is needed for WX version selection')
833 837 else:
834 838 try:
835 839 wxversion.select(wantedwxversion)
836 840 except:
837 841 self.IP.InteractiveTB()
838 842 error('Requested wxPython version %s could not be loaded' %
839 843 wantedwxversion)
840 844
841 845 import wx
842 846
843 847 threading.Thread.__init__(self)
844 848 self.wx = wx
845 849 self.wx_mainloop = hijack_wx()
846 850
847 851 # Allows us to use both Tk and GTK.
848 852 self.tk = get_tk()
849 853
850 854 # HACK: slot for banner in self; it will be passed to the mainloop
851 855 # method only and .run() needs it. The actual value will be set by
852 856 # .mainloop().
853 857 self._banner = None
854 858
855 859 self.app = None
856 860
857 861 def wxexit(self, *args):
858 862 if self.app is not None:
859 863 self.app.agent.timer.Stop()
860 864 self.app.ExitMainLoop()
861 865
862 866 def mainloop(self,sys_exit=0,banner=None):
863 867
864 868 self._banner = banner
865 869
866 870 self.start()
867 871
868 872 class TimerAgent(self.wx.MiniFrame):
869 873 wx = self.wx
870 874 IP = self.IP
871 875 tk = self.tk
872 876 def __init__(self, parent, interval):
873 877 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
874 878 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
875 879 size=(100, 100),style=style)
876 880 self.Show(False)
877 881 self.interval = interval
878 882 self.timerId = self.wx.NewId()
879 883
880 884 def StartWork(self):
881 885 self.timer = self.wx.Timer(self, self.timerId)
882 886 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
883 887 self.timer.Start(self.interval)
884 888
885 889 def OnTimer(self, event):
886 890 update_tk(self.tk)
887 891 self.IP.runcode()
888 892
889 893 class App(self.wx.App):
890 894 wx = self.wx
891 895 TIMEOUT = self.TIMEOUT
892 896 def OnInit(self):
893 897 'Create the main window and insert the custom frame'
894 898 self.agent = TimerAgent(None, self.TIMEOUT)
895 899 self.agent.Show(False)
896 900 self.agent.StartWork()
897 901 return True
898 902
899 903 self.app = App(redirect=False)
900 904 self.wx_mainloop(self.app)
901 905 self.join()
902 906
903 907
904 908 class IPShellQt(IPThread):
905 909 """Run a Qt event loop in a separate thread.
906 910
907 911 Python commands can be passed to the thread where they will be executed.
908 912 This is implemented by periodically checking for passed code using a
909 913 Qt timer / slot."""
910 914
911 915 TIMEOUT = 100 # Millisecond interval between timeouts.
912 916
913 917 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
914 918 debug=0, shell_class=MTInteractiveShell):
915 919
916 920 import qt
917 921
918 922 self.exec_loop = hijack_qt()
919 923
920 924 # Allows us to use both Tk and QT.
921 925 self.tk = get_tk()
922 926
923 927 self.IP = make_IPython(argv,
924 928 user_ns=user_ns,
925 929 user_global_ns=user_global_ns,
926 930 debug=debug,
927 931 shell_class=shell_class,
928 932 on_kill=[qt.qApp.exit])
929 933
930 934 # HACK: slot for banner in self; it will be passed to the mainloop
931 935 # method only and .run() needs it. The actual value will be set by
932 936 # .mainloop().
933 937 self._banner = None
934 938
935 939 threading.Thread.__init__(self)
936 940
937 941 def mainloop(self, sys_exit=0, banner=None):
938 942
939 943 import qt
940 944
941 945 self._banner = banner
942 946
943 947 if qt.QApplication.startingUp():
944 948 a = qt.QApplication(sys.argv)
945 949
946 950 self.timer = qt.QTimer()
947 951 qt.QObject.connect(self.timer,
948 952 qt.SIGNAL('timeout()'),
949 953 self.on_timer)
950 954
951 955 self.start()
952 956 self.timer.start(self.TIMEOUT, True)
953 957 while True:
954 958 if self.IP._kill: break
955 959 self.exec_loop()
956 960 self.join()
957 961
958 962 def on_timer(self):
959 963 update_tk(self.tk)
960 964 result = self.IP.runcode()
961 965 self.timer.start(self.TIMEOUT, True)
962 966 return result
963 967
964 968
965 969 class IPShellQt4(IPThread):
966 970 """Run a Qt event loop in a separate thread.
967 971
968 972 Python commands can be passed to the thread where they will be executed.
969 973 This is implemented by periodically checking for passed code using a
970 974 Qt timer / slot."""
971 975
972 976 TIMEOUT = 100 # Millisecond interval between timeouts.
973 977
974 978 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
975 979 debug=0, shell_class=MTInteractiveShell):
976 980
977 981 from PyQt4 import QtCore, QtGui
978 982
979 983 try:
980 984 # present in PyQt4-4.2.1 or later
981 985 QtCore.pyqtRemoveInputHook()
982 986 except AttributeError:
983 987 pass
984 988
985 989 if QtCore.PYQT_VERSION_STR == '4.3':
986 990 warn('''PyQt4 version 4.3 detected.
987 991 If you experience repeated threading warnings, please update PyQt4.
988 992 ''')
989 993
990 994 self.exec_ = hijack_qt4()
991 995
992 996 # Allows us to use both Tk and QT.
993 997 self.tk = get_tk()
994 998
995 999 self.IP = make_IPython(argv,
996 1000 user_ns=user_ns,
997 1001 user_global_ns=user_global_ns,
998 1002 debug=debug,
999 1003 shell_class=shell_class,
1000 1004 on_kill=[QtGui.qApp.exit])
1001 1005
1002 1006 # HACK: slot for banner in self; it will be passed to the mainloop
1003 1007 # method only and .run() needs it. The actual value will be set by
1004 1008 # .mainloop().
1005 1009 self._banner = None
1006 1010
1007 1011 threading.Thread.__init__(self)
1008 1012
1009 1013 def mainloop(self, sys_exit=0, banner=None):
1010 1014
1011 1015 from PyQt4 import QtCore, QtGui
1012 1016
1013 1017 self._banner = banner
1014 1018
1015 1019 if QtGui.QApplication.startingUp():
1016 1020 a = QtGui.QApplication(sys.argv)
1017 1021
1018 1022 self.timer = QtCore.QTimer()
1019 1023 QtCore.QObject.connect(self.timer,
1020 1024 QtCore.SIGNAL('timeout()'),
1021 1025 self.on_timer)
1022 1026
1023 1027 self.start()
1024 1028 self.timer.start(self.TIMEOUT)
1025 1029 while True:
1026 1030 if self.IP._kill: break
1027 1031 self.exec_()
1028 1032 self.join()
1029 1033
1030 1034 def on_timer(self):
1031 1035 update_tk(self.tk)
1032 1036 result = self.IP.runcode()
1033 1037 self.timer.start(self.TIMEOUT)
1034 1038 return result
1035 1039
1036 1040
1037 1041 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1038 1042 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1039 1043 def _load_pylab(user_ns):
1040 1044 """Allow users to disable pulling all of pylab into the top-level
1041 1045 namespace.
1042 1046
1043 1047 This little utility must be called AFTER the actual ipython instance is
1044 1048 running, since only then will the options file have been fully parsed."""
1045 1049
1046 1050 ip = IPython.ipapi.get()
1047 1051 if ip.options.pylab_import_all:
1048 1052 ip.ex("from matplotlib.pylab import *")
1049 1053 ip.IP.user_config_ns.update(ip.user_ns)
1050 1054
1051 1055
1052 1056 class IPShellMatplotlib(IPShell):
1053 1057 """Subclass IPShell with MatplotlibShell as the internal shell.
1054 1058
1055 1059 Single-threaded class, meant for the Tk* and FLTK* backends.
1056 1060
1057 1061 Having this on a separate class simplifies the external driver code."""
1058 1062
1059 1063 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1060 1064 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1061 1065 shell_class=MatplotlibShell)
1062 1066 _load_pylab(self.IP.user_ns)
1063 1067
1064 1068 class IPShellMatplotlibGTK(IPShellGTK):
1065 1069 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1066 1070
1067 1071 Multi-threaded class, meant for the GTK* backends."""
1068 1072
1069 1073 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1070 1074 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1071 1075 shell_class=MatplotlibMTShell)
1072 1076 _load_pylab(self.IP.user_ns)
1073 1077
1074 1078 class IPShellMatplotlibWX(IPShellWX):
1075 1079 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1076 1080
1077 1081 Multi-threaded class, meant for the WX* backends."""
1078 1082
1079 1083 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1080 1084 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1081 1085 shell_class=MatplotlibMTShell)
1082 1086 _load_pylab(self.IP.user_ns)
1083 1087
1084 1088 class IPShellMatplotlibQt(IPShellQt):
1085 1089 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1086 1090
1087 1091 Multi-threaded class, meant for the Qt* backends."""
1088 1092
1089 1093 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1090 1094 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1091 1095 shell_class=MatplotlibMTShell)
1092 1096 _load_pylab(self.IP.user_ns)
1093 1097
1094 1098 class IPShellMatplotlibQt4(IPShellQt4):
1095 1099 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1096 1100
1097 1101 Multi-threaded class, meant for the Qt4* backends."""
1098 1102
1099 1103 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1100 1104 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1101 1105 shell_class=MatplotlibMTShell)
1102 1106 _load_pylab(self.IP.user_ns)
1103 1107
1104 1108 #-----------------------------------------------------------------------------
1105 1109 # Factory functions to actually start the proper thread-aware shell
1106 1110
1107 1111 def _select_shell(argv):
1108 1112 """Select a shell from the given argv vector.
1109 1113
1110 1114 This function implements the threading selection policy, allowing runtime
1111 1115 control of the threading mode, both for general users and for matplotlib.
1112 1116
1113 1117 Return:
1114 1118 Shell class to be instantiated for runtime operation.
1115 1119 """
1116 1120
1117 1121 global USE_TK
1118 1122
1119 1123 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1120 1124 'wthread' : IPShellMatplotlibWX,
1121 1125 'qthread' : IPShellMatplotlibQt,
1122 1126 'q4thread' : IPShellMatplotlibQt4,
1123 1127 'tkthread' : IPShellMatplotlib, # Tk is built-in
1124 1128 }
1125 1129
1126 1130 th_shell = {'gthread' : IPShellGTK,
1127 1131 'wthread' : IPShellWX,
1128 1132 'qthread' : IPShellQt,
1129 1133 'q4thread' : IPShellQt4,
1130 1134 'tkthread' : IPShell, # Tk is built-in
1131 1135 }
1132 1136
1133 1137 backends = {'gthread' : 'GTKAgg',
1134 1138 'wthread' : 'WXAgg',
1135 1139 'qthread' : 'QtAgg',
1136 1140 'q4thread' :'Qt4Agg',
1137 1141 'tkthread' :'TkAgg',
1138 1142 }
1139 1143
1140 1144 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1141 1145 'tkthread'])
1142 1146 user_opts = set([s.replace('-','') for s in argv[:3]])
1143 1147 special_opts = user_opts & all_opts
1144 1148
1145 1149 if 'tk' in special_opts:
1146 1150 USE_TK = True
1147 1151 special_opts.remove('tk')
1148 1152
1149 1153 if 'pylab' in special_opts:
1150 1154
1151 1155 try:
1152 1156 import matplotlib
1153 1157 except ImportError:
1154 1158 error('matplotlib could NOT be imported! Starting normal IPython.')
1155 1159 return IPShell
1156 1160
1157 1161 special_opts.remove('pylab')
1158 1162 # If there's any option left, it means the user wants to force the
1159 1163 # threading backend, else it's auto-selected from the rc file
1160 1164 if special_opts:
1161 1165 th_mode = special_opts.pop()
1162 1166 matplotlib.rcParams['backend'] = backends[th_mode]
1163 1167 else:
1164 1168 backend = matplotlib.rcParams['backend']
1165 1169 if backend.startswith('GTK'):
1166 1170 th_mode = 'gthread'
1167 1171 elif backend.startswith('WX'):
1168 1172 th_mode = 'wthread'
1169 1173 elif backend.startswith('Qt4'):
1170 1174 th_mode = 'q4thread'
1171 1175 elif backend.startswith('Qt'):
1172 1176 th_mode = 'qthread'
1173 1177 else:
1174 1178 # Any other backend, use plain Tk
1175 1179 th_mode = 'tkthread'
1176 1180
1177 1181 return mpl_shell[th_mode]
1178 1182 else:
1179 1183 # No pylab requested, just plain threads
1180 1184 try:
1181 1185 th_mode = special_opts.pop()
1182 1186 except KeyError:
1183 1187 th_mode = 'tkthread'
1184 1188 return th_shell[th_mode]
1185 1189
1186 1190
1187 1191 # This is the one which should be called by external code.
1188 1192 def start(user_ns = None):
1189 1193 """Return a running shell instance, dealing with threading options.
1190 1194
1191 1195 This is a factory function which will instantiate the proper IPython shell
1192 1196 based on the user's threading choice. Such a selector is needed because
1193 1197 different GUI toolkits require different thread handling details."""
1194 1198
1195 1199 shell = _select_shell(sys.argv)
1196 1200 return shell(user_ns = user_ns)
1197 1201
1198 1202 # Some aliases for backwards compatibility
1199 1203 IPythonShell = IPShell
1200 1204 IPythonShellEmbed = IPShellEmbed
1201 1205 #************************ End of file <Shell.py> ***************************
General Comments 0
You need to be logged in to leave comments. Login now