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