##// END OF EJS Templates
Revert Shell.py changes, they don't work.
fperez -
Show More
@@ -1,861 +1,881 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 874 2005-09-20 20:13:04Z fperez $"""
7 $Id: Shell.py 882 2005-09-20 23:17:41Z fperez $"""
8 8
9 9 #*****************************************************************************
10 10 # Copyright (C) 2001-2004 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 import __main__
22 22 import __builtin__
23 23 import sys
24 24 import os
25 25 import code
26 26 import threading
27 27 import signal
28 28
29 29 import IPython
30 30 from IPython.iplib import InteractiveShell
31 31 from IPython.ipmaker import make_IPython
32 32 from IPython.genutils import Term,warn,error,flag_calls
33 33 from IPython.Struct import Struct
34 34 from IPython.Magic import Magic
35 35 from IPython import ultraTB
36 36
37 # global flag to pass around information about Ctrl-C without exceptions
38 KBINT = False
39
37 40 # global flag to turn on/off Tk support.
38 41 USE_TK = False
39 42
40 43 #-----------------------------------------------------------------------------
41 44 # This class is trivial now, but I want to have it in to publish a clean
42 45 # interface. Later when the internals are reorganized, code that uses this
43 46 # shouldn't have to change.
44 47
45 48 class IPShell:
46 49 """Create an IPython instance."""
47 50
48 51 def __init__(self,argv=None,user_ns=None,debug=1,
49 52 shell_class=InteractiveShell):
50 53 self.IP = make_IPython(argv,user_ns=user_ns,debug=debug,
51 54 shell_class=shell_class)
52 55
53 56 def mainloop(self,sys_exit=0,banner=None):
54 57 self.IP.mainloop(banner)
55 58 if sys_exit:
56 59 sys.exit()
57 60
58 61 #-----------------------------------------------------------------------------
59 62 class IPShellEmbed:
60 63 """Allow embedding an IPython shell into a running program.
61 64
62 65 Instances of this class are callable, with the __call__ method being an
63 66 alias to the embed() method of an InteractiveShell instance.
64 67
65 68 Usage (see also the example-embed.py file for a running example):
66 69
67 70 ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override])
68 71
69 72 - argv: list containing valid command-line options for IPython, as they
70 73 would appear in sys.argv[1:].
71 74
72 75 For example, the following command-line options:
73 76
74 77 $ ipython -prompt_in1 'Input <\\#>' -colors LightBG
75 78
76 79 would be passed in the argv list as:
77 80
78 81 ['-prompt_in1','Input <\\#>','-colors','LightBG']
79 82
80 83 - banner: string which gets printed every time the interpreter starts.
81 84
82 85 - exit_msg: string which gets printed every time the interpreter exits.
83 86
84 87 - rc_override: a dict or Struct of configuration options such as those
85 88 used by IPython. These options are read from your ~/.ipython/ipythonrc
86 89 file when the Shell object is created. Passing an explicit rc_override
87 90 dict with any options you want allows you to override those values at
88 91 creation time without having to modify the file. This way you can create
89 92 embeddable instances configured in any way you want without editing any
90 93 global files (thus keeping your interactive IPython configuration
91 94 unchanged).
92 95
93 96 Then the ipshell instance can be called anywhere inside your code:
94 97
95 98 ipshell(header='') -> Opens up an IPython shell.
96 99
97 100 - header: string printed by the IPython shell upon startup. This can let
98 101 you know where in your code you are when dropping into the shell. Note
99 102 that 'banner' gets prepended to all calls, so header is used for
100 103 location-specific information.
101 104
102 105 For more details, see the __call__ method below.
103 106
104 107 When the IPython shell is exited with Ctrl-D, normal program execution
105 108 resumes.
106 109
107 110 This functionality was inspired by a posting on comp.lang.python by cmkl
108 111 <cmkleffner@gmx.de> on Dec. 06/01 concerning similar uses of pyrepl, and
109 112 by the IDL stop/continue commands."""
110 113
111 114 def __init__(self,argv=None,banner='',exit_msg=None,rc_override=None):
112 115 """Note that argv here is a string, NOT a list."""
113 116 self.set_banner(banner)
114 117 self.set_exit_msg(exit_msg)
115 118 self.set_dummy_mode(0)
116 119
117 120 # sys.displayhook is a global, we need to save the user's original
118 121 # Don't rely on __displayhook__, as the user may have changed that.
119 122 self.sys_displayhook_ori = sys.displayhook
120 123
121 124 # save readline completer status
122 125 try:
123 126 #print 'Save completer',sys.ipcompleter # dbg
124 127 self.sys_ipcompleter_ori = sys.ipcompleter
125 128 except:
126 129 pass # not nested with IPython
127 130
128 131 # FIXME. Passing user_ns breaks namespace handling.
129 132 #self.IP = make_IPython(argv,user_ns=__main__.__dict__)
130 133 self.IP = make_IPython(argv,rc_override=rc_override,embedded=True)
131 134
132 135 self.IP.name_space_init()
133 136 # mark this as an embedded instance so we know if we get a crash
134 137 # post-mortem
135 138 self.IP.rc.embedded = 1
136 139 # copy our own displayhook also
137 140 self.sys_displayhook_embed = sys.displayhook
138 141 # and leave the system's display hook clean
139 142 sys.displayhook = self.sys_displayhook_ori
140 143 # don't use the ipython crash handler so that user exceptions aren't
141 144 # trapped
142 145 sys.excepthook = ultraTB.FormattedTB(color_scheme = self.IP.rc.colors,
143 146 mode = self.IP.rc.xmode,
144 147 call_pdb = self.IP.rc.pdb)
145 148 self.restore_system_completer()
146 149
147 150 def restore_system_completer(self):
148 151 """Restores the readline completer which was in place.
149 152
150 153 This allows embedded IPython within IPython not to disrupt the
151 154 parent's completion.
152 155 """
153 156
154 157 try:
155 158 self.IP.readline.set_completer(self.sys_ipcompleter_ori)
156 159 sys.ipcompleter = self.sys_ipcompleter_ori
157 160 except:
158 161 pass
159 162
160 163 def __call__(self,header='',local_ns=None,global_ns=None,dummy=None):
161 164 """Activate the interactive interpreter.
162 165
163 166 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
164 167 the interpreter shell with the given local and global namespaces, and
165 168 optionally print a header string at startup.
166 169
167 170 The shell can be globally activated/deactivated using the
168 171 set/get_dummy_mode methods. This allows you to turn off a shell used
169 172 for debugging globally.
170 173
171 174 However, *each* time you call the shell you can override the current
172 175 state of dummy_mode with the optional keyword parameter 'dummy'. For
173 176 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
174 177 can still have a specific call work by making it as IPShell(dummy=0).
175 178
176 179 The optional keyword parameter dummy controls whether the call
177 180 actually does anything. """
178 181
179 182 # Allow the dummy parameter to override the global __dummy_mode
180 183 if dummy or (dummy != 0 and self.__dummy_mode):
181 184 return
182 185
183 186 # Set global subsystems (display,completions) to our values
184 187 sys.displayhook = self.sys_displayhook_embed
185 188 if self.IP.has_readline:
186 189 self.IP.readline.set_completer(self.IP.Completer.complete)
187 190
188 191 if self.banner and header:
189 192 format = '%s\n%s\n'
190 193 else:
191 194 format = '%s%s\n'
192 195 banner = format % (self.banner,header)
193 196
194 197 # Call the embedding code with a stack depth of 1 so it can skip over
195 198 # our call and get the original caller's namespaces.
196 199 self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1)
197 200
198 201 if self.exit_msg:
199 202 print self.exit_msg
200 203
201 204 # Restore global systems (display, completion)
202 205 sys.displayhook = self.sys_displayhook_ori
203 206 self.restore_system_completer()
204 207
205 208 def set_dummy_mode(self,dummy):
206 209 """Sets the embeddable shell's dummy mode parameter.
207 210
208 211 set_dummy_mode(dummy): dummy = 0 or 1.
209 212
210 213 This parameter is persistent and makes calls to the embeddable shell
211 214 silently return without performing any action. This allows you to
212 215 globally activate or deactivate a shell you're using with a single call.
213 216
214 217 If you need to manually"""
215 218
216 219 if dummy not in [0,1]:
217 220 raise ValueError,'dummy parameter must be 0 or 1'
218 221 self.__dummy_mode = dummy
219 222
220 223 def get_dummy_mode(self):
221 224 """Return the current value of the dummy mode parameter.
222 225 """
223 226 return self.__dummy_mode
224 227
225 228 def set_banner(self,banner):
226 229 """Sets the global banner.
227 230
228 231 This banner gets prepended to every header printed when the shell
229 232 instance is called."""
230 233
231 234 self.banner = banner
232 235
233 236 def set_exit_msg(self,exit_msg):
234 237 """Sets the global exit_msg.
235 238
236 239 This exit message gets printed upon exiting every time the embedded
237 240 shell is called. It is None by default. """
238 241
239 242 self.exit_msg = exit_msg
240 243
241 244 #-----------------------------------------------------------------------------
242 245 def sigint_handler (signum,stack_frame):
243 246 """Sigint handler for threaded apps.
244 """
245 raise KeyboardInterrupt
247
248 This is a horrible hack to pass information about SIGINT _without_ using
249 exceptions, since I haven't been able to properly manage cross-thread
250 exceptions in GTK/WX. In fact, I don't think it can be done (or at least
251 that's my understanding from a c.l.py thread where this was discussed)."""
252
253 global KBINT
254
255 print '\nKeyboardInterrupt - Press <Enter> to continue.',
256 Term.cout.flush()
257 # Set global flag so that runsource can know that Ctrl-C was hit
258 KBINT = True
246 259
247 260 class MTInteractiveShell(InteractiveShell):
248 261 """Simple multi-threaded shell."""
249 262
250 263 # Threading strategy taken from:
251 264 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65109, by Brian
252 265 # McErlean and John Finlay. Modified with corrections by Antoon Pardon,
253 266 # from the pygtk mailing list, to avoid lockups with system calls.
254 267
255 268 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
256 269 user_ns = None, banner2='',**kw):
257 270 """Similar to the normal InteractiveShell, but with threading control"""
258 271
259 272 IPython.iplib.InteractiveShell.__init__(self,name,usage,rc,user_ns,banner2)
260 273
261 274 # Locking control variable
262 275 self.thread_ready = threading.Condition()
263 276
264 277 # Stuff to do at closing time
265 278 self._kill = False
266 279 on_kill = kw.get('on_kill')
267 280 if on_kill is None:
268 281 on_kill = []
269 282 # Check that all things to kill are callable:
270 283 for t in on_kill:
271 284 if not callable(t):
272 285 raise TypeError,'on_kill must be a list of callables'
273 286 self.on_kill = on_kill
274 287
275 288 def runsource(self, source, filename="<input>", symbol="single"):
276 289 """Compile and run some source in the interpreter.
277 290
278 291 Modified version of code.py's runsource(), to handle threading issues.
279 292 See the original for full docstring details."""
293
294 global KBINT
295
296 # If Ctrl-C was typed, we reset the flag and return right away
297 if KBINT:
298 KBINT = False
299 return False
280 300
281 301 try:
282 302 code = self.compile(source, filename, symbol)
283 303 except (OverflowError, SyntaxError, ValueError):
284 304 # Case 1
285 305 self.showsyntaxerror(filename)
286 306 return False
287 307
288 308 if code is None:
289 309 # Case 2
290 310 return True
291 311
292 312 # Case 3
293 313 # Store code in self, so the execution thread can handle it
294 314 self.thread_ready.acquire()
295 315 self.code_to_run = code
296 316 self.thread_ready.wait() # Wait until processed in timeout interval
297 317 self.thread_ready.release()
298 318
299 319 return False
300 320
301 321 def runcode(self):
302 322 """Execute a code object.
303 323
304 324 Multithreaded wrapper around IPython's runcode()."""
305 325
306 326 # lock thread-protected stuff
307 327 self.thread_ready.acquire()
308 328
309 329 # Install sigint handler
310 330 try:
311 331 signal.signal(signal.SIGINT, sigint_handler)
312 332 except SystemError:
313 333 # This happens under Windows, which seems to have all sorts
314 334 # of problems with signal handling. Oh well...
315 335 pass
316 336
317 337 if self._kill:
318 338 print >>Term.cout, 'Closing threads...',
319 339 Term.cout.flush()
320 340 for tokill in self.on_kill:
321 341 tokill()
322 342 print >>Term.cout, 'Done.'
323 343
324 344 # Run pending code by calling parent class
325 345 if self.code_to_run is not None:
326 346 self.thread_ready.notify()
327 347 InteractiveShell.runcode(self,self.code_to_run)
328 348
329 349 # We're done with thread-protected variables
330 350 self.thread_ready.release()
331 351 # This MUST return true for gtk threading to work
332 352 return True
333 353
334 354 def kill (self):
335 355 """Kill the thread, returning when it has been shut down."""
336 356 self.thread_ready.acquire()
337 357 self._kill = True
338 358 self.thread_ready.release()
339 359
340 360 class MatplotlibShellBase:
341 361 """Mixin class to provide the necessary modifications to regular IPython
342 362 shell classes for matplotlib support.
343 363
344 364 Given Python's MRO, this should be used as the FIRST class in the
345 365 inheritance hierarchy, so that it overrides the relevant methods."""
346 366
347 367 def _matplotlib_config(self,name):
348 368 """Return various items needed to setup the user's shell with matplotlib"""
349 369
350 370 # Initialize matplotlib to interactive mode always
351 371 import matplotlib
352 372 from matplotlib import backends
353 373 matplotlib.interactive(True)
354 374
355 375 def use(arg):
356 376 """IPython wrapper for matplotlib's backend switcher.
357 377
358 378 In interactive use, we can not allow switching to a different
359 379 interactive backend, since thread conflicts will most likely crash
360 380 the python interpreter. This routine does a safety check first,
361 381 and refuses to perform a dangerous switch. It still allows
362 382 switching to non-interactive backends."""
363 383
364 384 if arg in backends.interactive_bk and arg != self.mpl_backend:
365 385 m=('invalid matplotlib backend switch.\n'
366 386 'This script attempted to switch to the interactive '
367 387 'backend: `%s`\n'
368 388 'Your current choice of interactive backend is: `%s`\n\n'
369 389 'Switching interactive matplotlib backends at runtime\n'
370 390 'would crash the python interpreter, '
371 391 'and IPython has blocked it.\n\n'
372 392 'You need to either change your choice of matplotlib backend\n'
373 393 'by editing your .matplotlibrc file, or run this script as a \n'
374 394 'standalone file from the command line, not using IPython.\n' %
375 395 (arg,self.mpl_backend) )
376 396 raise RuntimeError, m
377 397 else:
378 398 self.mpl_use(arg)
379 399 self.mpl_use._called = True
380 400
381 401 self.matplotlib = matplotlib
382 402 self.mpl_backend = matplotlib.rcParams['backend']
383 403
384 404 # we also need to block switching of interactive backends by use()
385 405 self.mpl_use = matplotlib.use
386 406 self.mpl_use._called = False
387 407 # overwrite the original matplotlib.use with our wrapper
388 408 matplotlib.use = use
389 409
390 410
391 411 # This must be imported last in the matplotlib series, after
392 412 # backend/interactivity choices have been made
393 413 try:
394 414 import matplotlib.pylab as pylab
395 415 self.pylab = pylab
396 416 self.pylab_name = 'pylab'
397 417 except ImportError:
398 418 import matplotlib.matlab as matlab
399 419 self.pylab = matlab
400 420 self.pylab_name = 'matlab'
401 421
402 422 self.pylab.show._needmain = False
403 423 # We need to detect at runtime whether show() is called by the user.
404 424 # For this, we wrap it into a decorator which adds a 'called' flag.
405 425 self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive)
406 426
407 427 # Build a user namespace initialized with matplotlib/matlab features.
408 428 user_ns = {'__name__':'__main__',
409 429 '__builtins__' : __builtin__ }
410 430
411 431 # Be careful not to remove the final \n in the code string below, or
412 432 # things will break badly with py22 (I think it's a python bug, 2.3 is
413 433 # OK).
414 434 pname = self.pylab_name # Python can't interpolate dotted var names
415 435 exec ("import matplotlib\n"
416 436 "import matplotlib.%(pname)s as %(pname)s\n"
417 437 "from matplotlib.%(pname)s import *\n" % locals()) in user_ns
418 438
419 439 # Build matplotlib info banner
420 440 b="""
421 441 Welcome to pylab, a matplotlib-based Python environment.
422 442 For more information, type 'help(pylab)'.
423 443 """
424 444 return user_ns,b
425 445
426 446 def mplot_exec(self,fname,*where,**kw):
427 447 """Execute a matplotlib script.
428 448
429 449 This is a call to execfile(), but wrapped in safeties to properly
430 450 handle interactive rendering and backend switching."""
431 451
432 452 #print '*** Matplotlib runner ***' # dbg
433 453 # turn off rendering until end of script
434 454 isInteractive = self.matplotlib.rcParams['interactive']
435 455 self.matplotlib.interactive(False)
436 456 self.safe_execfile(fname,*where,**kw)
437 457 self.matplotlib.interactive(isInteractive)
438 458 # make rendering call now, if the user tried to do it
439 459 if self.pylab.draw_if_interactive.called:
440 460 self.pylab.draw()
441 461 self.pylab.draw_if_interactive.called = False
442 462
443 463 # if a backend switch was performed, reverse it now
444 464 if self.mpl_use._called:
445 465 self.matplotlib.rcParams['backend'] = self.mpl_backend
446 466
447 467 def magic_run(self,parameter_s=''):
448 468 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
449 469
450 470 # Fix the docstring so users see the original as well
451 471 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
452 472 "\n *** Modified %run for Matplotlib,"
453 473 " with proper interactive handling ***")
454 474
455 475 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
456 476 # and multithreaded. Note that these are meant for internal use, the IPShell*
457 477 # classes below are the ones meant for public consumption.
458 478
459 479 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
460 480 """Single-threaded shell with matplotlib support."""
461 481
462 482 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
463 483 user_ns = None, **kw):
464 484 user_ns,b2 = self._matplotlib_config(name)
465 485 InteractiveShell.__init__(self,name,usage,rc,user_ns,banner2=b2,**kw)
466 486
467 487 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
468 488 """Multi-threaded shell with matplotlib support."""
469 489
470 490 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
471 491 user_ns = None, **kw):
472 492 user_ns,b2 = self._matplotlib_config(name)
473 493 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,banner2=b2,**kw)
474 494
475 495 #-----------------------------------------------------------------------------
476 496 # Utility functions for the different GUI enabled IPShell* classes.
477 497
478 498 def get_tk():
479 499 """Tries to import Tkinter and returns a withdrawn Tkinter root
480 500 window. If Tkinter is already imported or not available, this
481 501 returns None. This function calls `hijack_tk` underneath.
482 502 """
483 503 if not USE_TK or sys.modules.has_key('Tkinter'):
484 504 return None
485 505 else:
486 506 try:
487 507 import Tkinter
488 508 except ImportError:
489 509 return None
490 510 else:
491 511 hijack_tk()
492 512 r = Tkinter.Tk()
493 513 r.withdraw()
494 514 return r
495 515
496 516 def hijack_tk():
497 517 """Modifies Tkinter's mainloop with a dummy so when a module calls
498 518 mainloop, it does not block.
499 519
500 520 """
501 521 def misc_mainloop(self, n=0):
502 522 pass
503 523 def tkinter_mainloop(n=0):
504 524 pass
505 525
506 526 import Tkinter
507 527 Tkinter.Misc.mainloop = misc_mainloop
508 528 Tkinter.mainloop = tkinter_mainloop
509 529
510 530 def update_tk(tk):
511 531 """Updates the Tkinter event loop. This is typically called from
512 532 the respective WX or GTK mainloops.
513 533 """
514 534 if tk:
515 535 tk.update()
516 536
517 537 def hijack_wx():
518 538 """Modifies wxPython's MainLoop with a dummy so user code does not
519 539 block IPython. The hijacked mainloop function is returned.
520 540 """
521 541 def dummy_mainloop(*args, **kw):
522 542 pass
523 543 import wxPython
524 544 ver = wxPython.__version__
525 545 orig_mainloop = None
526 546 if ver[:3] >= '2.5':
527 547 import wx
528 548 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
529 549 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
530 550 else: raise AttributeError('Could not find wx core module')
531 551 orig_mainloop = core.PyApp_MainLoop
532 552 core.PyApp_MainLoop = dummy_mainloop
533 553 elif ver[:3] == '2.4':
534 554 orig_mainloop = wxPython.wxc.wxPyApp_MainLoop
535 555 wxPython.wxc.wxPyApp_MainLoop = dummy_mainloop
536 556 else:
537 557 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
538 558 return orig_mainloop
539 559
540 560 def hijack_gtk():
541 561 """Modifies pyGTK's mainloop with a dummy so user code does not
542 562 block IPython. This function returns the original `gtk.mainloop`
543 563 function that has been hijacked.
544 564 """
545 565 def dummy_mainloop(*args, **kw):
546 566 pass
547 567 import gtk
548 568 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
549 569 else: orig_mainloop = gtk.mainloop
550 570 gtk.mainloop = dummy_mainloop
551 571 gtk.main = dummy_mainloop
552 572 return orig_mainloop
553 573
554 574 #-----------------------------------------------------------------------------
555 575 # The IPShell* classes below are the ones meant to be run by external code as
556 576 # IPython instances. Note that unless a specific threading strategy is
557 577 # desired, the factory function start() below should be used instead (it
558 578 # selects the proper threaded class).
559 579
560 580 class IPShellGTK(threading.Thread):
561 581 """Run a gtk mainloop() in a separate thread.
562 582
563 583 Python commands can be passed to the thread where they will be executed.
564 584 This is implemented by periodically checking for passed code using a
565 585 GTK timeout callback."""
566 586
567 587 TIMEOUT = 100 # Millisecond interval between timeouts.
568 588
569 589 def __init__(self,argv=None,user_ns=None,debug=1,
570 590 shell_class=MTInteractiveShell):
571 591
572 592 import gtk
573 593
574 594 self.gtk = gtk
575 595 self.gtk_mainloop = hijack_gtk()
576 596
577 597 # Allows us to use both Tk and GTK.
578 598 self.tk = get_tk()
579 599
580 600 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
581 601 else: mainquit = self.gtk.mainquit
582 602
583 603 self.IP = make_IPython(argv,user_ns=user_ns,debug=debug,
584 604 shell_class=shell_class,
585 605 on_kill=[mainquit])
586 606 threading.Thread.__init__(self)
587 607
588 608 def run(self):
589 609 self.IP.mainloop()
590 610 self.IP.kill()
591 611
592 612 def mainloop(self):
593 613
594 614 if self.gtk.pygtk_version >= (2,4,0):
595 615 import gobject
596 616 gobject.timeout_add(self.TIMEOUT, self.on_timer)
597 617 else:
598 618 self.gtk.timeout_add(self.TIMEOUT, self.on_timer)
599 619
600 620 if sys.platform != 'win32':
601 621 try:
602 622 if self.gtk.gtk_version[0] >= 2:
603 623 self.gtk.threads_init()
604 624 except AttributeError:
605 625 pass
606 626 except RuntimeError:
607 627 error('Your pyGTK likely has not been compiled with '
608 628 'threading support.\n'
609 629 'The exception printout is below.\n'
610 630 'You can either rebuild pyGTK with threads, or '
611 631 'try using \n'
612 632 'matplotlib with a different backend (like Tk or WX).\n'
613 633 'Note that matplotlib will most likely not work in its '
614 634 'current state!')
615 635 self.IP.InteractiveTB()
616 636 self.start()
617 637 self.gtk.threads_enter()
618 638 self.gtk_mainloop()
619 639 self.gtk.threads_leave()
620 640 self.join()
621 641
622 642 def on_timer(self):
623 643 update_tk(self.tk)
624 644 return self.IP.runcode()
625 645
626 646
627 647 class IPShellWX(threading.Thread):
628 648 """Run a wx mainloop() in a separate thread.
629 649
630 650 Python commands can be passed to the thread where they will be executed.
631 651 This is implemented by periodically checking for passed code using a
632 652 GTK timeout callback."""
633 653
634 654 TIMEOUT = 100 # Millisecond interval between timeouts.
635 655
636 656 def __init__(self,argv=None,user_ns=None,debug=1,
637 657 shell_class=MTInteractiveShell):
638 658
639 659 import wxPython.wx as wx
640 660
641 661 threading.Thread.__init__(self)
642 662 self.wx = wx
643 663 self.wx_mainloop = hijack_wx()
644 664
645 665 # Allows us to use both Tk and GTK.
646 666 self.tk = get_tk()
647 667
648 668 self.IP = make_IPython(argv,user_ns=user_ns,debug=debug,
649 669 shell_class=shell_class,
650 670 on_kill=[self.wxexit])
651 671 self.app = None
652 672
653 673 def wxexit(self, *args):
654 674 if self.app is not None:
655 675 self.app.agent.timer.Stop()
656 676 self.app.ExitMainLoop()
657 677
658 678 def run(self):
659 679 self.IP.mainloop()
660 680 self.IP.kill()
661 681
662 682 def mainloop(self):
663 683
664 684 self.start()
665 685
666 686 class TimerAgent(self.wx.wxMiniFrame):
667 687 wx = self.wx
668 688 IP = self.IP
669 689 tk = self.tk
670 690 def __init__(self, parent, interval):
671 691 style = self.wx.wxDEFAULT_FRAME_STYLE | self.wx.wxTINY_CAPTION_HORIZ
672 692 self.wx.wxMiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
673 693 size=(100, 100),style=style)
674 694 self.Show(False)
675 695 self.interval = interval
676 696 self.timerId = self.wx.wxNewId()
677 697
678 698 def StartWork(self):
679 699 self.timer = self.wx.wxTimer(self, self.timerId)
680 700 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
681 701 self.timer.Start(self.interval)
682 702
683 703 def OnTimer(self, event):
684 704 update_tk(self.tk)
685 705 self.IP.runcode()
686 706
687 707 class App(self.wx.wxApp):
688 708 wx = self.wx
689 709 TIMEOUT = self.TIMEOUT
690 710 def OnInit(self):
691 711 'Create the main window and insert the custom frame'
692 712 self.agent = TimerAgent(None, self.TIMEOUT)
693 713 self.agent.Show(self.wx.false)
694 714 self.agent.StartWork()
695 715 return self.wx.true
696 716
697 717 self.app = App(redirect=False)
698 718 self.wx_mainloop(self.app)
699 719 self.join()
700 720
701 721
702 722 class IPShellQt(threading.Thread):
703 723 """Run a Qt event loop in a separate thread.
704 724
705 725 Python commands can be passed to the thread where they will be executed.
706 726 This is implemented by periodically checking for passed code using a
707 727 Qt timer / slot."""
708 728
709 729 TIMEOUT = 100 # Millisecond interval between timeouts.
710 730
711 731 def __init__(self,argv=None,user_ns=None,debug=0,
712 732 shell_class=MTInteractiveShell):
713 733
714 734 import qt
715 735
716 736 class newQApplication:
717 737 def __init__( self ):
718 738 self.QApplication = qt.QApplication
719 739
720 740 def __call__( *args, **kwargs ):
721 741 return qt.qApp
722 742
723 743 def exec_loop( *args, **kwargs ):
724 744 pass
725 745
726 746 def __getattr__( self, name ):
727 747 return getattr( self.QApplication, name )
728 748
729 749 qt.QApplication = newQApplication()
730 750
731 751 # Allows us to use both Tk and QT.
732 752 self.tk = get_tk()
733 753
734 754 self.IP = make_IPython(argv,user_ns=user_ns,debug=debug,
735 755 shell_class=shell_class,
736 756 on_kill=[qt.qApp.exit])
737 757
738 758 threading.Thread.__init__(self)
739 759
740 760 def run(self):
741 761 #sys.excepthook = self.IP.excepthook # dbg
742 762 self.IP.mainloop()
743 763 self.IP.kill()
744 764
745 765 def mainloop(self):
746 766 import qt, sys
747 767 if qt.QApplication.startingUp():
748 768 a = qt.QApplication.QApplication( sys.argv )
749 769 self.timer = qt.QTimer()
750 770 qt.QObject.connect( self.timer, qt.SIGNAL( 'timeout()' ), self.on_timer )
751 771
752 772 self.start()
753 773 self.timer.start( self.TIMEOUT, True )
754 774 while True:
755 775 if self.IP._kill: break
756 776 qt.qApp.exec_loop()
757 777 self.join()
758 778
759 779 def on_timer(self):
760 780 update_tk(self.tk)
761 781 result = self.IP.runcode()
762 782 self.timer.start( self.TIMEOUT, True )
763 783 return result
764 784
765 785 # A set of matplotlib public IPython shell classes, for single-threaded
766 786 # (Tk* and FLTK* backends) and multithreaded (GTK* and WX* backends) use.
767 787 class IPShellMatplotlib(IPShell):
768 788 """Subclass IPShell with MatplotlibShell as the internal shell.
769 789
770 790 Single-threaded class, meant for the Tk* and FLTK* backends.
771 791
772 792 Having this on a separate class simplifies the external driver code."""
773 793
774 794 def __init__(self,argv=None,user_ns=None,debug=1):
775 795 IPShell.__init__(self,argv,user_ns,debug,shell_class=MatplotlibShell)
776 796
777 797 class IPShellMatplotlibGTK(IPShellGTK):
778 798 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
779 799
780 800 Multi-threaded class, meant for the GTK* backends."""
781 801
782 802 def __init__(self,argv=None,user_ns=None,debug=1):
783 803 IPShellGTK.__init__(self,argv,user_ns,debug,shell_class=MatplotlibMTShell)
784 804
785 805 class IPShellMatplotlibWX(IPShellWX):
786 806 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
787 807
788 808 Multi-threaded class, meant for the WX* backends."""
789 809
790 810 def __init__(self,argv=None,user_ns=None,debug=1):
791 811 IPShellWX.__init__(self,argv,user_ns,debug,shell_class=MatplotlibMTShell)
792 812
793 813 class IPShellMatplotlibQt(IPShellQt):
794 814 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
795 815
796 816 Multi-threaded class, meant for the Qt* backends."""
797 817
798 818 def __init__(self,argv=None,user_ns=None,debug=1):
799 819 IPShellQt.__init__(self,argv,user_ns,debug,shell_class=MatplotlibMTShell)
800 820
801 821 #-----------------------------------------------------------------------------
802 822 # Factory functions to actually start the proper thread-aware shell
803 823
804 824 def _matplotlib_shell_class():
805 825 """Factory function to handle shell class selection for matplotlib.
806 826
807 827 The proper shell class to use depends on the matplotlib backend, since
808 828 each backend requires a different threading strategy."""
809 829
810 830 try:
811 831 import matplotlib
812 832 except ImportError:
813 833 error('matplotlib could NOT be imported! Starting normal IPython.')
814 834 sh_class = IPShell
815 835 else:
816 836 backend = matplotlib.rcParams['backend']
817 837 if backend.startswith('GTK'):
818 838 sh_class = IPShellMatplotlibGTK
819 839 elif backend.startswith('WX'):
820 840 sh_class = IPShellMatplotlibWX
821 841 elif backend.startswith('Qt'):
822 842 sh_class = IPShellMatplotlibQt
823 843 else:
824 844 sh_class = IPShellMatplotlib
825 845 #print 'Using %s with the %s backend.' % (sh_class,backend) # dbg
826 846 return sh_class
827 847
828 848 # This is the one which should be called by external code.
829 849 def start():
830 850 """Return a running shell instance, dealing with threading options.
831 851
832 852 This is a factory function which will instantiate the proper IPython shell
833 853 based on the user's threading choice. Such a selector is needed because
834 854 different GUI toolkits require different thread handling details."""
835 855
836 856 global USE_TK
837 857 # Crude sys.argv hack to extract the threading options.
838 858 if len(sys.argv) > 1:
839 859 if len(sys.argv) > 2:
840 860 arg2 = sys.argv[2]
841 861 if arg2.endswith('-tk'):
842 862 USE_TK = True
843 863 arg1 = sys.argv[1]
844 864 if arg1.endswith('-gthread'):
845 865 shell = IPShellGTK
846 866 elif arg1.endswith( '-qthread' ):
847 867 shell = IPShellQt
848 868 elif arg1.endswith('-wthread'):
849 869 shell = IPShellWX
850 870 elif arg1.endswith('-pylab'):
851 871 shell = _matplotlib_shell_class()
852 872 else:
853 873 shell = IPShell
854 874 else:
855 875 shell = IPShell
856 876 return shell()
857 877
858 878 # Some aliases for backwards compatibility
859 879 IPythonShell = IPShell
860 880 IPythonShellEmbed = IPShellEmbed
861 881 #************************ End of file <Shell.py> ***************************
General Comments 0
You need to be logged in to leave comments. Login now