##// END OF EJS Templates
Small fix to pylab imports
fperez -
Show More
@@ -1,1061 +1,1061 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 2156 2007-03-19 02:32:19Z fperez $"""
7 $Id: Shell.py 2164 2007-03-20 00:15:03Z 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") in user_ns
450 450
451 451 # Build matplotlib info banner
452 452 b="""
453 453 Welcome to pylab, a matplotlib-based Python environment.
454 454 For more information, type 'help(pylab)'.
455 455 """
456 456 return user_ns,b
457 457
458 458 def mplot_exec(self,fname,*where,**kw):
459 459 """Execute a matplotlib script.
460 460
461 461 This is a call to execfile(), but wrapped in safeties to properly
462 462 handle interactive rendering and backend switching."""
463 463
464 464 #print '*** Matplotlib runner ***' # dbg
465 465 # turn off rendering until end of script
466 466 isInteractive = self.matplotlib.rcParams['interactive']
467 467 self.matplotlib.interactive(False)
468 468 self.safe_execfile(fname,*where,**kw)
469 469 self.matplotlib.interactive(isInteractive)
470 470 # make rendering call now, if the user tried to do it
471 471 if self.pylab.draw_if_interactive.called:
472 472 self.pylab.draw()
473 473 self.pylab.draw_if_interactive.called = False
474 474
475 475 # if a backend switch was performed, reverse it now
476 476 if self.mpl_use._called:
477 477 self.matplotlib.rcParams['backend'] = self.mpl_backend
478 478
479 479 def magic_run(self,parameter_s=''):
480 480 Magic.magic_run(self,parameter_s,runner=self.mplot_exec)
481 481
482 482 # Fix the docstring so users see the original as well
483 483 magic_run.__doc__ = "%s\n%s" % (Magic.magic_run.__doc__,
484 484 "\n *** Modified %run for Matplotlib,"
485 485 " with proper interactive handling ***")
486 486
487 487 # Now we provide 2 versions of a matplotlib-aware IPython base shells, single
488 488 # and multithreaded. Note that these are meant for internal use, the IPShell*
489 489 # classes below are the ones meant for public consumption.
490 490
491 491 class MatplotlibShell(MatplotlibShellBase,InteractiveShell):
492 492 """Single-threaded shell with matplotlib support."""
493 493
494 494 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
495 495 user_ns=None,user_global_ns=None,**kw):
496 496 user_ns,b2 = self._matplotlib_config(name,user_ns)
497 497 InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
498 498 banner2=b2,**kw)
499 499
500 500 class MatplotlibMTShell(MatplotlibShellBase,MTInteractiveShell):
501 501 """Multi-threaded shell with matplotlib support."""
502 502
503 503 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
504 504 user_ns=None,user_global_ns=None, **kw):
505 505 user_ns,b2 = self._matplotlib_config(name,user_ns)
506 506 MTInteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns,
507 507 banner2=b2,**kw)
508 508
509 509 #-----------------------------------------------------------------------------
510 510 # Utility functions for the different GUI enabled IPShell* classes.
511 511
512 512 def get_tk():
513 513 """Tries to import Tkinter and returns a withdrawn Tkinter root
514 514 window. If Tkinter is already imported or not available, this
515 515 returns None. This function calls `hijack_tk` underneath.
516 516 """
517 517 if not USE_TK or sys.modules.has_key('Tkinter'):
518 518 return None
519 519 else:
520 520 try:
521 521 import Tkinter
522 522 except ImportError:
523 523 return None
524 524 else:
525 525 hijack_tk()
526 526 r = Tkinter.Tk()
527 527 r.withdraw()
528 528 return r
529 529
530 530 def hijack_tk():
531 531 """Modifies Tkinter's mainloop with a dummy so when a module calls
532 532 mainloop, it does not block.
533 533
534 534 """
535 535 def misc_mainloop(self, n=0):
536 536 pass
537 537 def tkinter_mainloop(n=0):
538 538 pass
539 539
540 540 import Tkinter
541 541 Tkinter.Misc.mainloop = misc_mainloop
542 542 Tkinter.mainloop = tkinter_mainloop
543 543
544 544 def update_tk(tk):
545 545 """Updates the Tkinter event loop. This is typically called from
546 546 the respective WX or GTK mainloops.
547 547 """
548 548 if tk:
549 549 tk.update()
550 550
551 551 def hijack_wx():
552 552 """Modifies wxPython's MainLoop with a dummy so user code does not
553 553 block IPython. The hijacked mainloop function is returned.
554 554 """
555 555 def dummy_mainloop(*args, **kw):
556 556 pass
557 557
558 558 try:
559 559 import wx
560 560 except ImportError:
561 561 # For very old versions of WX
562 562 import wxPython as wx
563 563
564 564 ver = wx.__version__
565 565 orig_mainloop = None
566 566 if ver[:3] >= '2.5':
567 567 import wx
568 568 if hasattr(wx, '_core_'): core = getattr(wx, '_core_')
569 569 elif hasattr(wx, '_core'): core = getattr(wx, '_core')
570 570 else: raise AttributeError('Could not find wx core module')
571 571 orig_mainloop = core.PyApp_MainLoop
572 572 core.PyApp_MainLoop = dummy_mainloop
573 573 elif ver[:3] == '2.4':
574 574 orig_mainloop = wx.wxc.wxPyApp_MainLoop
575 575 wx.wxc.wxPyApp_MainLoop = dummy_mainloop
576 576 else:
577 577 warn("Unable to find either wxPython version 2.4 or >= 2.5.")
578 578 return orig_mainloop
579 579
580 580 def hijack_gtk():
581 581 """Modifies pyGTK's mainloop with a dummy so user code does not
582 582 block IPython. This function returns the original `gtk.mainloop`
583 583 function that has been hijacked.
584 584 """
585 585 def dummy_mainloop(*args, **kw):
586 586 pass
587 587 import gtk
588 588 if gtk.pygtk_version >= (2,4,0): orig_mainloop = gtk.main
589 589 else: orig_mainloop = gtk.mainloop
590 590 gtk.mainloop = dummy_mainloop
591 591 gtk.main = dummy_mainloop
592 592 return orig_mainloop
593 593
594 594 #-----------------------------------------------------------------------------
595 595 # The IPShell* classes below are the ones meant to be run by external code as
596 596 # IPython instances. Note that unless a specific threading strategy is
597 597 # desired, the factory function start() below should be used instead (it
598 598 # selects the proper threaded class).
599 599
600 600 class IPShellGTK(threading.Thread):
601 601 """Run a gtk mainloop() in a separate thread.
602 602
603 603 Python commands can be passed to the thread where they will be executed.
604 604 This is implemented by periodically checking for passed code using a
605 605 GTK timeout callback."""
606 606
607 607 TIMEOUT = 100 # Millisecond interval between timeouts.
608 608
609 609 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
610 610 debug=1,shell_class=MTInteractiveShell):
611 611
612 612 import gtk
613 613
614 614 self.gtk = gtk
615 615 self.gtk_mainloop = hijack_gtk()
616 616
617 617 # Allows us to use both Tk and GTK.
618 618 self.tk = get_tk()
619 619
620 620 if gtk.pygtk_version >= (2,4,0): mainquit = self.gtk.main_quit
621 621 else: mainquit = self.gtk.mainquit
622 622
623 623 self.IP = make_IPython(argv,user_ns=user_ns,
624 624 user_global_ns=user_global_ns,
625 625 debug=debug,
626 626 shell_class=shell_class,
627 627 on_kill=[mainquit])
628 628
629 629 # HACK: slot for banner in self; it will be passed to the mainloop
630 630 # method only and .run() needs it. The actual value will be set by
631 631 # .mainloop().
632 632 self._banner = None
633 633
634 634 threading.Thread.__init__(self)
635 635
636 636 def run(self):
637 637 self.IP.mainloop(self._banner)
638 638 self.IP.kill()
639 639
640 640 def mainloop(self,sys_exit=0,banner=None):
641 641
642 642 self._banner = banner
643 643
644 644 if self.gtk.pygtk_version >= (2,4,0):
645 645 import gobject
646 646 gobject.idle_add(self.on_timer)
647 647 else:
648 648 self.gtk.idle_add(self.on_timer)
649 649
650 650 if sys.platform != 'win32':
651 651 try:
652 652 if self.gtk.gtk_version[0] >= 2:
653 653 self.gtk.gdk.threads_init()
654 654 except AttributeError:
655 655 pass
656 656 except RuntimeError:
657 657 error('Your pyGTK likely has not been compiled with '
658 658 'threading support.\n'
659 659 'The exception printout is below.\n'
660 660 'You can either rebuild pyGTK with threads, or '
661 661 'try using \n'
662 662 'matplotlib with a different backend (like Tk or WX).\n'
663 663 'Note that matplotlib will most likely not work in its '
664 664 'current state!')
665 665 self.IP.InteractiveTB()
666 666
667 667 self.start()
668 668 self.gtk.gdk.threads_enter()
669 669 self.gtk_mainloop()
670 670 self.gtk.gdk.threads_leave()
671 671 self.join()
672 672
673 673 def on_timer(self):
674 674 """Called when GTK is idle.
675 675
676 676 Must return True always, otherwise GTK stops calling it"""
677 677
678 678 update_tk(self.tk)
679 679 self.IP.runcode()
680 680 time.sleep(0.01)
681 681 return True
682 682
683 683 class IPShellWX(threading.Thread):
684 684 """Run a wx mainloop() in a separate thread.
685 685
686 686 Python commands can be passed to the thread where they will be executed.
687 687 This is implemented by periodically checking for passed code using a
688 688 GTK timeout callback."""
689 689
690 690 TIMEOUT = 100 # Millisecond interval between timeouts.
691 691
692 692 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
693 693 debug=1,shell_class=MTInteractiveShell):
694 694
695 695 self.IP = make_IPython(argv,user_ns=user_ns,
696 696 user_global_ns=user_global_ns,
697 697 debug=debug,
698 698 shell_class=shell_class,
699 699 on_kill=[self.wxexit])
700 700
701 701 wantedwxversion=self.IP.rc.wxversion
702 702 if wantedwxversion!="0":
703 703 try:
704 704 import wxversion
705 705 except ImportError:
706 706 error('The wxversion module is needed for WX version selection')
707 707 else:
708 708 try:
709 709 wxversion.select(wantedwxversion)
710 710 except:
711 711 self.IP.InteractiveTB()
712 712 error('Requested wxPython version %s could not be loaded' %
713 713 wantedwxversion)
714 714
715 715 import wx
716 716
717 717 threading.Thread.__init__(self)
718 718 self.wx = wx
719 719 self.wx_mainloop = hijack_wx()
720 720
721 721 # Allows us to use both Tk and GTK.
722 722 self.tk = get_tk()
723 723
724 724
725 725 # HACK: slot for banner in self; it will be passed to the mainloop
726 726 # method only and .run() needs it. The actual value will be set by
727 727 # .mainloop().
728 728 self._banner = None
729 729
730 730 self.app = None
731 731
732 732 def wxexit(self, *args):
733 733 if self.app is not None:
734 734 self.app.agent.timer.Stop()
735 735 self.app.ExitMainLoop()
736 736
737 737 def run(self):
738 738 self.IP.mainloop(self._banner)
739 739 self.IP.kill()
740 740
741 741 def mainloop(self,sys_exit=0,banner=None):
742 742
743 743 self._banner = banner
744 744
745 745 self.start()
746 746
747 747 class TimerAgent(self.wx.MiniFrame):
748 748 wx = self.wx
749 749 IP = self.IP
750 750 tk = self.tk
751 751 def __init__(self, parent, interval):
752 752 style = self.wx.DEFAULT_FRAME_STYLE | self.wx.TINY_CAPTION_HORIZ
753 753 self.wx.MiniFrame.__init__(self, parent, -1, ' ', pos=(200, 200),
754 754 size=(100, 100),style=style)
755 755 self.Show(False)
756 756 self.interval = interval
757 757 self.timerId = self.wx.NewId()
758 758
759 759 def StartWork(self):
760 760 self.timer = self.wx.Timer(self, self.timerId)
761 761 self.wx.EVT_TIMER(self, self.timerId, self.OnTimer)
762 762 self.timer.Start(self.interval)
763 763
764 764 def OnTimer(self, event):
765 765 update_tk(self.tk)
766 766 self.IP.runcode()
767 767
768 768 class App(self.wx.App):
769 769 wx = self.wx
770 770 TIMEOUT = self.TIMEOUT
771 771 def OnInit(self):
772 772 'Create the main window and insert the custom frame'
773 773 self.agent = TimerAgent(None, self.TIMEOUT)
774 774 self.agent.Show(False)
775 775 self.agent.StartWork()
776 776 return True
777 777
778 778 self.app = App(redirect=False)
779 779 self.wx_mainloop(self.app)
780 780 self.join()
781 781
782 782
783 783 class IPShellQt(threading.Thread):
784 784 """Run a Qt event loop in a separate thread.
785 785
786 786 Python commands can be passed to the thread where they will be executed.
787 787 This is implemented by periodically checking for passed code using a
788 788 Qt timer / slot."""
789 789
790 790 TIMEOUT = 100 # Millisecond interval between timeouts.
791 791
792 792 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
793 793 debug=0,shell_class=MTInteractiveShell):
794 794
795 795 import qt
796 796
797 797 class newQApplication:
798 798 def __init__( self ):
799 799 self.QApplication = qt.QApplication
800 800
801 801 def __call__( *args, **kwargs ):
802 802 return qt.qApp
803 803
804 804 def exec_loop( *args, **kwargs ):
805 805 pass
806 806
807 807 def __getattr__( self, name ):
808 808 return getattr( self.QApplication, name )
809 809
810 810 qt.QApplication = newQApplication()
811 811
812 812 # Allows us to use both Tk and QT.
813 813 self.tk = get_tk()
814 814
815 815 self.IP = make_IPython(argv,user_ns=user_ns,
816 816 user_global_ns=user_global_ns,
817 817 debug=debug,
818 818 shell_class=shell_class,
819 819 on_kill=[qt.qApp.exit])
820 820
821 821 # HACK: slot for banner in self; it will be passed to the mainloop
822 822 # method only and .run() needs it. The actual value will be set by
823 823 # .mainloop().
824 824 self._banner = None
825 825
826 826 threading.Thread.__init__(self)
827 827
828 828 def run(self):
829 829 self.IP.mainloop(self._banner)
830 830 self.IP.kill()
831 831
832 832 def mainloop(self,sys_exit=0,banner=None):
833 833
834 834 import qt
835 835
836 836 self._banner = banner
837 837
838 838 if qt.QApplication.startingUp():
839 839 a = qt.QApplication.QApplication(sys.argv)
840 840 self.timer = qt.QTimer()
841 841 qt.QObject.connect( self.timer, qt.SIGNAL( 'timeout()' ), self.on_timer )
842 842
843 843 self.start()
844 844 self.timer.start( self.TIMEOUT, True )
845 845 while True:
846 846 if self.IP._kill: break
847 847 qt.qApp.exec_loop()
848 848 self.join()
849 849
850 850 def on_timer(self):
851 851 update_tk(self.tk)
852 852 result = self.IP.runcode()
853 853 self.timer.start( self.TIMEOUT, True )
854 854 return result
855 855
856 856
857 857 class IPShellQt4(threading.Thread):
858 858 """Run a Qt event loop in a separate thread.
859 859
860 860 Python commands can be passed to the thread where they will be executed.
861 861 This is implemented by periodically checking for passed code using a
862 862 Qt timer / slot."""
863 863
864 864 TIMEOUT = 100 # Millisecond interval between timeouts.
865 865
866 866 def __init__(self,argv=None,user_ns=None,user_global_ns=None,
867 867 debug=0,shell_class=MTInteractiveShell):
868 868
869 869 from PyQt4 import QtCore, QtGui
870 870
871 871 class newQApplication:
872 872 def __init__( self ):
873 873 self.QApplication = QtGui.QApplication
874 874
875 875 def __call__( *args, **kwargs ):
876 876 return QtGui.qApp
877 877
878 878 def exec_loop( *args, **kwargs ):
879 879 pass
880 880
881 881 def __getattr__( self, name ):
882 882 return getattr( self.QApplication, name )
883 883
884 884 QtGui.QApplication = newQApplication()
885 885
886 886 # Allows us to use both Tk and QT.
887 887 self.tk = get_tk()
888 888
889 889 self.IP = make_IPython(argv,user_ns=user_ns,
890 890 user_global_ns=user_global_ns,
891 891 debug=debug,
892 892 shell_class=shell_class,
893 893 on_kill=[QtGui.qApp.exit])
894 894
895 895 # HACK: slot for banner in self; it will be passed to the mainloop
896 896 # method only and .run() needs it. The actual value will be set by
897 897 # .mainloop().
898 898 self._banner = None
899 899
900 900 threading.Thread.__init__(self)
901 901
902 902 def run(self):
903 903 self.IP.mainloop(self._banner)
904 904 self.IP.kill()
905 905
906 906 def mainloop(self,sys_exit=0,banner=None):
907 907
908 908 from PyQt4 import QtCore, QtGui
909 909
910 910 self._banner = banner
911 911
912 912 if QtGui.QApplication.startingUp():
913 913 a = QtGui.QApplication.QApplication(sys.argv)
914 914 self.timer = QtCore.QTimer()
915 915 QtCore.QObject.connect( self.timer, QtCore.SIGNAL( 'timeout()' ), self.on_timer )
916 916
917 917 self.start()
918 918 self.timer.start( self.TIMEOUT )
919 919 while True:
920 920 if self.IP._kill: break
921 921 QtGui.qApp.exec_()
922 922 self.join()
923 923
924 924 def on_timer(self):
925 925 update_tk(self.tk)
926 926 result = self.IP.runcode()
927 927 self.timer.start( self.TIMEOUT )
928 928 return result
929 929
930 930
931 931 # A set of matplotlib public IPython shell classes, for single-threaded
932 932 # (Tk* and FLTK* backends) and multithreaded (GTK* and WX* backends) use.
933 933 def _load_pylab(user_ns):
934 934 """Allow users to disable pulling all of pylab into the top-level
935 935 namespace.
936 936
937 937 This little utility must be called AFTER the actual ipython instance is
938 938 running, since only then will the options file have been fully parsed."""
939 939
940 940 ip = IPython.ipapi.get()
941 941 if ip.options.pylab_import_all:
942 942 exec "from matplotlib.pylab import *" in user_ns
943 943
944 944 class IPShellMatplotlib(IPShell):
945 945 """Subclass IPShell with MatplotlibShell as the internal shell.
946 946
947 947 Single-threaded class, meant for the Tk* and FLTK* backends.
948 948
949 949 Having this on a separate class simplifies the external driver code."""
950 950
951 951 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
952 952 IPShell.__init__(self,argv,user_ns,user_global_ns,debug,
953 953 shell_class=MatplotlibShell)
954 _load_pylab(user_ns)
954 _load_pylab(self.IP.user_ns)
955 955
956 956 class IPShellMatplotlibGTK(IPShellGTK):
957 957 """Subclass IPShellGTK with MatplotlibMTShell as the internal shell.
958 958
959 959 Multi-threaded class, meant for the GTK* backends."""
960 960
961 961 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
962 962 IPShellGTK.__init__(self,argv,user_ns,user_global_ns,debug,
963 963 shell_class=MatplotlibMTShell)
964 _load_pylab(user_ns)
964 _load_pylab(self.IP.user_ns)
965 965
966 966 class IPShellMatplotlibWX(IPShellWX):
967 967 """Subclass IPShellWX with MatplotlibMTShell as the internal shell.
968 968
969 969 Multi-threaded class, meant for the WX* backends."""
970 970
971 971 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
972 972 IPShellWX.__init__(self,argv,user_ns,user_global_ns,debug,
973 973 shell_class=MatplotlibMTShell)
974 _load_pylab(user_ns)
974 _load_pylab(self.IP.user_ns)
975 975
976 976 class IPShellMatplotlibQt(IPShellQt):
977 977 """Subclass IPShellQt with MatplotlibMTShell as the internal shell.
978 978
979 979 Multi-threaded class, meant for the Qt* backends."""
980 980
981 981 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
982 982 IPShellQt.__init__(self,argv,user_ns,user_global_ns,debug,
983 983 shell_class=MatplotlibMTShell)
984 _load_pylab(user_ns)
984 _load_pylab(self.IP.user_ns)
985 985
986 986 class IPShellMatplotlibQt4(IPShellQt4):
987 987 """Subclass IPShellQt4 with MatplotlibMTShell as the internal shell.
988 988
989 989 Multi-threaded class, meant for the Qt4* backends."""
990 990
991 991 def __init__(self,argv=None,user_ns=None,user_global_ns=None,debug=1):
992 992 IPShellQt4.__init__(self,argv,user_ns,user_global_ns,debug,
993 993 shell_class=MatplotlibMTShell)
994 _load_pylab(user_ns)
994 _load_pylab(self.IP.user_ns)
995 995
996 996 #-----------------------------------------------------------------------------
997 997 # Factory functions to actually start the proper thread-aware shell
998 998
999 999 def _matplotlib_shell_class():
1000 1000 """Factory function to handle shell class selection for matplotlib.
1001 1001
1002 1002 The proper shell class to use depends on the matplotlib backend, since
1003 1003 each backend requires a different threading strategy."""
1004 1004
1005 1005 try:
1006 1006 import matplotlib
1007 1007 except ImportError:
1008 1008 error('matplotlib could NOT be imported! Starting normal IPython.')
1009 1009 sh_class = IPShell
1010 1010 else:
1011 1011 backend = matplotlib.rcParams['backend']
1012 1012 if backend.startswith('GTK'):
1013 1013 sh_class = IPShellMatplotlibGTK
1014 1014 elif backend.startswith('WX'):
1015 1015 sh_class = IPShellMatplotlibWX
1016 1016 elif backend.startswith('Qt4'):
1017 1017 sh_class = IPShellMatplotlibQt4
1018 1018 elif backend.startswith('Qt'):
1019 1019 sh_class = IPShellMatplotlibQt
1020 1020 else:
1021 1021 sh_class = IPShellMatplotlib
1022 1022 #print 'Using %s with the %s backend.' % (sh_class,backend) # dbg
1023 1023 return sh_class
1024 1024
1025 1025 # This is the one which should be called by external code.
1026 1026 def start(user_ns = None):
1027 1027 """Return a running shell instance, dealing with threading options.
1028 1028
1029 1029 This is a factory function which will instantiate the proper IPython shell
1030 1030 based on the user's threading choice. Such a selector is needed because
1031 1031 different GUI toolkits require different thread handling details."""
1032 1032
1033 1033 global USE_TK
1034 1034 # Crude sys.argv hack to extract the threading options.
1035 1035 argv = sys.argv
1036 1036 if len(argv) > 1:
1037 1037 if len(argv) > 2:
1038 1038 arg2 = argv[2]
1039 1039 if arg2.endswith('-tk'):
1040 1040 USE_TK = True
1041 1041 arg1 = argv[1]
1042 1042 if arg1.endswith('-gthread'):
1043 1043 shell = IPShellGTK
1044 1044 elif arg1.endswith( '-qthread' ):
1045 1045 shell = IPShellQt
1046 1046 elif arg1.endswith( '-q4thread' ):
1047 1047 shell = IPShellQt4
1048 1048 elif arg1.endswith('-wthread'):
1049 1049 shell = IPShellWX
1050 1050 elif arg1.endswith('-pylab'):
1051 1051 shell = _matplotlib_shell_class()
1052 1052 else:
1053 1053 shell = IPShell
1054 1054 else:
1055 1055 shell = IPShell
1056 1056 return shell(user_ns = user_ns)
1057 1057
1058 1058 # Some aliases for backwards compatibility
1059 1059 IPythonShell = IPShell
1060 1060 IPythonShellEmbed = IPShellEmbed
1061 1061 #************************ End of file <Shell.py> ***************************
General Comments 0
You need to be logged in to leave comments. Login now