##// END OF EJS Templates
Catch IOError on windows with -gthread....
Fernando Perez -
Show More
@@ -1,1245 +1,1247 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
848 update_tk(self.tk)
849 self.IP.runcode()
850 time.sleep(0.01)
851 return True
847 try:
848 update_tk(self.tk)
849 self.IP.runcode()
850 time.sleep(0.01)
851 return True
852 except IOError:
853 return True
852 854
853 855
854 856 class IPShellWX(IPThread):
855 857 """Run a wx mainloop() in a separate thread.
856 858
857 859 Python commands can be passed to the thread where they will be executed.
858 860 This is implemented by periodically checking for passed code using a
859 861 GTK timeout callback."""
860 862
861 863 TIMEOUT = 100 # Millisecond interval between timeouts.
862 864
863 865 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
864 866 debug=1,shell_class=MTInteractiveShell):
865 867
866 868 self.IP = make_IPython(argv,user_ns=user_ns,
867 869 user_global_ns=user_global_ns,
868 870 debug=debug,
869 871 shell_class=shell_class,
870 872 on_kill=[self.wxexit])
871 873
872 874 wantedwxversion=self.IP.rc.wxversion
873 875 if wantedwxversion!="0":
874 876 try:
875 877 import wxversion
876 878 except ImportError:
877 879 error('The wxversion module is needed for WX version selection')
878 880 else:
879 881 try:
880 882 wxversion.select(wantedwxversion)
881 883 except:
882 884 self.IP.InteractiveTB()
883 885 error('Requested wxPython version %s could not be loaded' %
884 886 wantedwxversion)
885 887
886 888 import wx
887 889
888 890 threading.Thread.__init__(self)
889 891 self.wx = wx
890 892 self.wx_mainloop = hijack_wx()
891 893
892 894 # Allows us to use both Tk and GTK.
893 895 self.tk = get_tk()
894 896
895 897 # HACK: slot for banner in self; it will be passed to the mainloop
896 898 # method only and .run() needs it. The actual value will be set by
897 899 # .mainloop().
898 900 self._banner = None
899 901
900 902 self.app = None
901 903
902 904 def wxexit(self, *args):
903 905 if self.app is not None:
904 906 self.app.agent.timer.Stop()
905 907 self.app.ExitMainLoop()
906 908
907 909 def mainloop(self,sys_exit=0,banner=None):
908 910
909 911 self._banner = banner
910 912
911 913 self.start()
912 914
913 915 class TimerAgent(self.wx.MiniFrame):
914 916 wx = self.wx
915 917 IP = self.IP
916 918 tk = self.tk
917 919 def __init__(self, parent, interval):
918 920 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
919 921 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
920 922 size=(100, 100),style=style)
921 923 self.Show(False)
922 924 self.interval = interval
923 925 self.timerId = self.wx.NewId()
924 926
925 927 def StartWork(self):
926 928 self.timer = self.wx.Timer(self, self.timerId)
927 929 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
928 930 self.timer.Start(self.interval)
929 931
930 932 def OnTimer(self, event):
931 933 update_tk(self.tk)
932 934 self.IP.runcode()
933 935
934 936 class App(self.wx.App):
935 937 wx = self.wx
936 938 TIMEOUT = self.TIMEOUT
937 939 def OnInit(self):
938 940 'Create the main window and insert the custom frame'
939 941 self.agent = TimerAgent(None, self.TIMEOUT)
940 942 self.agent.Show(False)
941 943 self.agent.StartWork()
942 944 return True
943 945
944 946 self.app = App(redirect=False)
945 947 self.wx_mainloop(self.app)
946 948 self.join()
947 949
948 950
949 951 class IPShellQt(IPThread):
950 952 """Run a Qt event loop in a separate thread.
951 953
952 954 Python commands can be passed to the thread where they will be executed.
953 955 This is implemented by periodically checking for passed code using a
954 956 Qt timer / slot."""
955 957
956 958 TIMEOUT = 100 # Millisecond interval between timeouts.
957 959
958 960 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
959 961 debug=0, shell_class=MTInteractiveShell):
960 962
961 963 import qt
962 964
963 965 self.exec_loop = hijack_qt()
964 966
965 967 # Allows us to use both Tk and QT.
966 968 self.tk = get_tk()
967 969
968 970 self.IP = make_IPython(argv,
969 971 user_ns=user_ns,
970 972 user_global_ns=user_global_ns,
971 973 debug=debug,
972 974 shell_class=shell_class,
973 975 on_kill=[qt.qApp.exit])
974 976
975 977 # HACK: slot for banner in self; it will be passed to the mainloop
976 978 # method only and .run() needs it. The actual value will be set by
977 979 # .mainloop().
978 980 self._banner = None
979 981
980 982 threading.Thread.__init__(self)
981 983
982 984 def mainloop(self, sys_exit=0, banner=None):
983 985
984 986 import qt
985 987
986 988 self._banner = banner
987 989
988 990 if qt.QApplication.startingUp():
989 991 a = qt.QApplication(sys.argv)
990 992
991 993 self.timer = qt.QTimer()
992 994 qt.QObject.connect(self.timer,
993 995 qt.SIGNAL('timeout()'),
994 996 self.on_timer)
995 997
996 998 self.start()
997 999 self.timer.start(self.TIMEOUT, True)
998 1000 while True:
999 1001 if self.IP._kill: break
1000 1002 self.exec_loop()
1001 1003 self.join()
1002 1004
1003 1005 def on_timer(self):
1004 1006 update_tk(self.tk)
1005 1007 result = self.IP.runcode()
1006 1008 self.timer.start(self.TIMEOUT, True)
1007 1009 return result
1008 1010
1009 1011
1010 1012 class IPShellQt4(IPThread):
1011 1013 """Run a Qt event loop in a separate thread.
1012 1014
1013 1015 Python commands can be passed to the thread where they will be executed.
1014 1016 This is implemented by periodically checking for passed code using a
1015 1017 Qt timer / slot."""
1016 1018
1017 1019 TIMEOUT = 100 # Millisecond interval between timeouts.
1018 1020
1019 1021 def __init__(self, argv=None, user_ns=None, user_global_ns=None,
1020 1022 debug=0, shell_class=MTInteractiveShell):
1021 1023
1022 1024 from PyQt4 import QtCore, QtGui
1023 1025
1024 1026 try:
1025 1027 # present in PyQt4-4.2.1 or later
1026 1028 QtCore.pyqtRemoveInputHook()
1027 1029 except AttributeError:
1028 1030 pass
1029 1031
1030 1032 if QtCore.PYQT_VERSION_STR == '4.3':
1031 1033 warn('''PyQt4 version 4.3 detected.
1032 1034 If you experience repeated threading warnings, please update PyQt4.
1033 1035 ''')
1034 1036
1035 1037 self.exec_ = hijack_qt4()
1036 1038
1037 1039 # Allows us to use both Tk and QT.
1038 1040 self.tk = get_tk()
1039 1041
1040 1042 self.IP = make_IPython(argv,
1041 1043 user_ns=user_ns,
1042 1044 user_global_ns=user_global_ns,
1043 1045 debug=debug,
1044 1046 shell_class=shell_class,
1045 1047 on_kill=[QtGui.qApp.exit])
1046 1048
1047 1049 # HACK: slot for banner in self; it will be passed to the mainloop
1048 1050 # method only and .run() needs it. The actual value will be set by
1049 1051 # .mainloop().
1050 1052 self._banner = None
1051 1053
1052 1054 threading.Thread.__init__(self)
1053 1055
1054 1056 def mainloop(self, sys_exit=0, banner=None):
1055 1057
1056 1058 from PyQt4 import QtCore, QtGui
1057 1059
1058 1060 self._banner = banner
1059 1061
1060 1062 if QtGui.QApplication.startingUp():
1061 1063 a = QtGui.QApplication(sys.argv)
1062 1064
1063 1065 self.timer = QtCore.QTimer()
1064 1066 QtCore.QObject.connect(self.timer,
1065 1067 QtCore.SIGNAL('timeout()'),
1066 1068 self.on_timer)
1067 1069
1068 1070 self.start()
1069 1071 self.timer.start(self.TIMEOUT)
1070 1072 while True:
1071 1073 if self.IP._kill: break
1072 1074 self.exec_()
1073 1075 self.join()
1074 1076
1075 1077 def on_timer(self):
1076 1078 update_tk(self.tk)
1077 1079 result = self.IP.runcode()
1078 1080 self.timer.start(self.TIMEOUT)
1079 1081 return result
1080 1082
1081 1083
1082 1084 # A set of matplotlib public IPython shell classes, for single-threaded (Tk*
1083 1085 # and FLTK*) and multithreaded (GTK*, WX* and Qt*) backends to use.
1084 1086 def _load_pylab(user_ns):
1085 1087 """Allow users to disable pulling all of pylab into the top-level
1086 1088 namespace.
1087 1089
1088 1090 This little utility must be called AFTER the actual ipython instance is
1089 1091 running, since only then will the options file have been fully parsed."""
1090 1092
1091 1093 ip = IPython.ipapi.get()
1092 1094 if ip.options.pylab_import_all:
1093 1095 ip.ex("from matplotlib.pylab import *")
1094 1096 ip.IP.user_config_ns.update(ip.user_ns)
1095 1097
1096 1098
1097 1099 class IPShellMatplotlib(IPShell):
1098 1100 """Subclass IPShell with MatplotlibShell as the internal shell.
1099 1101
1100 1102 Single-threaded class, meant for the Tk* and FLTK* backends.
1101 1103
1102 1104 Having this on a separate class simplifies the external driver code."""
1103 1105
1104 1106 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1105 1107 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
1106 1108 shell_class=MatplotlibShell)
1107 1109 _load_pylab(self.IP.user_ns)
1108 1110
1109 1111 class IPShellMatplotlibGTK(IPShellGTK):
1110 1112 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
1111 1113
1112 1114 Multi-threaded class, meant for the GTK* backends."""
1113 1115
1114 1116 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1115 1117 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
1116 1118 shell_class=MatplotlibMTShell)
1117 1119 _load_pylab(self.IP.user_ns)
1118 1120
1119 1121 class IPShellMatplotlibWX(IPShellWX):
1120 1122 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
1121 1123
1122 1124 Multi-threaded class, meant for the WX* backends."""
1123 1125
1124 1126 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1125 1127 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
1126 1128 shell_class=MatplotlibMTShell)
1127 1129 _load_pylab(self.IP.user_ns)
1128 1130
1129 1131 class IPShellMatplotlibQt(IPShellQt):
1130 1132 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
1131 1133
1132 1134 Multi-threaded class, meant for the Qt* backends."""
1133 1135
1134 1136 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1135 1137 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
1136 1138 shell_class=MatplotlibMTShell)
1137 1139 _load_pylab(self.IP.user_ns)
1138 1140
1139 1141 class IPShellMatplotlibQt4(IPShellQt4):
1140 1142 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
1141 1143
1142 1144 Multi-threaded class, meant for the Qt4* backends."""
1143 1145
1144 1146 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
1145 1147 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
1146 1148 shell_class=MatplotlibMTShell)
1147 1149 _load_pylab(self.IP.user_ns)
1148 1150
1149 1151 #-----------------------------------------------------------------------------
1150 1152 # Factory functions to actually start the proper thread-aware shell
1151 1153
1152 1154 def _select_shell(argv):
1153 1155 """Select a shell from the given argv vector.
1154 1156
1155 1157 This function implements the threading selection policy, allowing runtime
1156 1158 control of the threading mode, both for general users and for matplotlib.
1157 1159
1158 1160 Return:
1159 1161 Shell class to be instantiated for runtime operation.
1160 1162 """
1161 1163
1162 1164 global USE_TK
1163 1165
1164 1166 mpl_shell = {'gthread' : IPShellMatplotlibGTK,
1165 1167 'wthread' : IPShellMatplotlibWX,
1166 1168 'qthread' : IPShellMatplotlibQt,
1167 1169 'q4thread' : IPShellMatplotlibQt4,
1168 1170 'tkthread' : IPShellMatplotlib, # Tk is built-in
1169 1171 }
1170 1172
1171 1173 th_shell = {'gthread' : IPShellGTK,
1172 1174 'wthread' : IPShellWX,
1173 1175 'qthread' : IPShellQt,
1174 1176 'q4thread' : IPShellQt4,
1175 1177 'tkthread' : IPShell, # Tk is built-in
1176 1178 }
1177 1179
1178 1180 backends = {'gthread' : 'GTKAgg',
1179 1181 'wthread' : 'WXAgg',
1180 1182 'qthread' : 'QtAgg',
1181 1183 'q4thread' :'Qt4Agg',
1182 1184 'tkthread' :'TkAgg',
1183 1185 }
1184 1186
1185 1187 all_opts = set(['tk','pylab','gthread','qthread','q4thread','wthread',
1186 1188 'tkthread'])
1187 1189 user_opts = set([s.replace('-','') for s in argv[:3]])
1188 1190 special_opts = user_opts & all_opts
1189 1191
1190 1192 if 'tk' in special_opts:
1191 1193 USE_TK = True
1192 1194 special_opts.remove('tk')
1193 1195
1194 1196 if 'pylab' in special_opts:
1195 1197
1196 1198 try:
1197 1199 import matplotlib
1198 1200 except ImportError:
1199 1201 error('matplotlib could NOT be imported! Starting normal IPython.')
1200 1202 return IPShell
1201 1203
1202 1204 special_opts.remove('pylab')
1203 1205 # If there's any option left, it means the user wants to force the
1204 1206 # threading backend, else it's auto-selected from the rc file
1205 1207 if special_opts:
1206 1208 th_mode = special_opts.pop()
1207 1209 matplotlib.rcParams['backend'] = backends[th_mode]
1208 1210 else:
1209 1211 backend = matplotlib.rcParams['backend']
1210 1212 if backend.startswith('GTK'):
1211 1213 th_mode = 'gthread'
1212 1214 elif backend.startswith('WX'):
1213 1215 th_mode = 'wthread'
1214 1216 elif backend.startswith('Qt4'):
1215 1217 th_mode = 'q4thread'
1216 1218 elif backend.startswith('Qt'):
1217 1219 th_mode = 'qthread'
1218 1220 else:
1219 1221 # Any other backend, use plain Tk
1220 1222 th_mode = 'tkthread'
1221 1223 return mpl_shell[th_mode]
1222 1224 else:
1223 1225 # No pylab requested, just plain threads
1224 1226 try:
1225 1227 th_mode = special_opts.pop()
1226 1228 except KeyError:
1227 1229 th_mode = 'tkthread'
1228 1230 return th_shell[th_mode]
1229 1231
1230 1232
1231 1233 # This is the one which should be called by external code.
1232 1234 def start(user_ns = None):
1233 1235 """Return a running shell instance, dealing with threading options.
1234 1236
1235 1237 This is a factory function which will instantiate the proper IPython shell
1236 1238 based on the user's threading choice. Such a selector is needed because
1237 1239 different GUI toolkits require different thread handling details."""
1238 1240
1239 1241 shell = _select_shell(sys.argv)
1240 1242 return shell(user_ns = user_ns)
1241 1243
1242 1244 # Some aliases for backwards compatibility
1243 1245 IPythonShell = IPShell
1244 1246 IPythonShellEmbed = IPShellEmbed
1245 1247 #************************ End of file <Shell.py> ***************************
General Comments 0
You need to be logged in to leave comments. Login now