##// END OF EJS Templates
Fix wx deprecation warning
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

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