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