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