Show More
@@ -170,10 +170,13 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
170 | help="Enable auto setting the terminal title." |
|
170 | help="Enable auto setting the terminal title." | |
171 | ) |
|
171 | ) | |
172 |
|
172 | |||
173 | def __init__(self, config=None, ipython_dir=None, profile_dir=None, user_ns=None, |
|
173 | # In the terminal, GUI control is done via PyOS_InputHook | |
174 | user_module=None, custom_exceptions=((),None), |
|
174 | from IPython.lib.inputhook import enable_gui | |
175 | usage=None, banner1=None, banner2=None, |
|
175 | enable_gui = staticmethod(enable_gui) | |
176 | display_banner=None): |
|
176 | ||
|
177 | def __init__(self, config=None, ipython_dir=None, profile_dir=None, | |||
|
178 | user_ns=None, user_module=None, custom_exceptions=((),None), | |||
|
179 | usage=None, banner1=None, banner2=None, display_banner=None): | |||
177 |
|
180 | |||
178 | super(TerminalInteractiveShell, self).__init__( |
|
181 | super(TerminalInteractiveShell, self).__init__( | |
179 | config=config, profile_dir=profile_dir, user_ns=user_ns, |
|
182 | config=config, profile_dir=profile_dir, user_ns=user_ns, | |
@@ -516,14 +519,6 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
516 | return True |
|
519 | return True | |
517 |
|
520 | |||
518 | #------------------------------------------------------------------------- |
|
521 | #------------------------------------------------------------------------- | |
519 | # Things related to GUI support and pylab |
|
|||
520 | #------------------------------------------------------------------------- |
|
|||
521 |
|
||||
522 | def enable_gui(self, gui=None): |
|
|||
523 | from IPython.lib.inputhook import enable_gui |
|
|||
524 | enable_gui(gui) |
|
|||
525 |
|
||||
526 | #------------------------------------------------------------------------- |
|
|||
527 | # Things related to exiting |
|
522 | # Things related to exiting | |
528 | #------------------------------------------------------------------------- |
|
523 | #------------------------------------------------------------------------- | |
529 |
|
524 |
@@ -510,190 +510,6 b' class Kernel(Configurable):' | |||||
510 | # before Python truly shuts down. |
|
510 | # before Python truly shuts down. | |
511 | time.sleep(0.01) |
|
511 | time.sleep(0.01) | |
512 |
|
512 | |||
513 |
|
||||
514 | #------------------------------------------------------------------------------ |
|
|||
515 | # Eventloops for integrating the Kernel into different GUIs |
|
|||
516 | #------------------------------------------------------------------------------ |
|
|||
517 |
|
||||
518 |
|
||||
519 | def loop_qt4(kernel): |
|
|||
520 | """Start a kernel with PyQt4 event loop integration.""" |
|
|||
521 |
|
||||
522 | from IPython.external.qt_for_kernel import QtCore |
|
|||
523 | from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4 |
|
|||
524 |
|
||||
525 | kernel.app = get_app_qt4([" "]) |
|
|||
526 | kernel.app.setQuitOnLastWindowClosed(False) |
|
|||
527 | kernel.timer = QtCore.QTimer() |
|
|||
528 | kernel.timer.timeout.connect(kernel.do_one_iteration) |
|
|||
529 | # Units for the timer are in milliseconds |
|
|||
530 | kernel.timer.start(1000*kernel._poll_interval) |
|
|||
531 | start_event_loop_qt4(kernel.app) |
|
|||
532 |
|
||||
533 |
|
||||
534 | def loop_wx(kernel): |
|
|||
535 | """Start a kernel with wx event loop support.""" |
|
|||
536 |
|
||||
537 | import wx |
|
|||
538 | from IPython.lib.guisupport import start_event_loop_wx |
|
|||
539 |
|
||||
540 | doi = kernel.do_one_iteration |
|
|||
541 | # Wx uses milliseconds |
|
|||
542 | poll_interval = int(1000*kernel._poll_interval) |
|
|||
543 |
|
||||
544 | # We have to put the wx.Timer in a wx.Frame for it to fire properly. |
|
|||
545 | # We make the Frame hidden when we create it in the main app below. |
|
|||
546 | class TimerFrame(wx.Frame): |
|
|||
547 | def __init__(self, func): |
|
|||
548 | wx.Frame.__init__(self, None, -1) |
|
|||
549 | self.timer = wx.Timer(self) |
|
|||
550 | # Units for the timer are in milliseconds |
|
|||
551 | self.timer.Start(poll_interval) |
|
|||
552 | self.Bind(wx.EVT_TIMER, self.on_timer) |
|
|||
553 | self.func = func |
|
|||
554 |
|
||||
555 | def on_timer(self, event): |
|
|||
556 | self.func() |
|
|||
557 |
|
||||
558 | # We need a custom wx.App to create our Frame subclass that has the |
|
|||
559 | # wx.Timer to drive the ZMQ event loop. |
|
|||
560 | class IPWxApp(wx.App): |
|
|||
561 | def OnInit(self): |
|
|||
562 | self.frame = TimerFrame(doi) |
|
|||
563 | self.frame.Show(False) |
|
|||
564 | return True |
|
|||
565 |
|
||||
566 | # The redirect=False here makes sure that wx doesn't replace |
|
|||
567 | # sys.stdout/stderr with its own classes. |
|
|||
568 | kernel.app = IPWxApp(redirect=False) |
|
|||
569 | start_event_loop_wx(kernel.app) |
|
|||
570 |
|
||||
571 |
|
||||
572 | def loop_tk(kernel): |
|
|||
573 | """Start a kernel with the Tk event loop.""" |
|
|||
574 |
|
||||
575 | import Tkinter |
|
|||
576 | doi = kernel.do_one_iteration |
|
|||
577 | # Tk uses milliseconds |
|
|||
578 | poll_interval = int(1000*kernel._poll_interval) |
|
|||
579 | # For Tkinter, we create a Tk object and call its withdraw method. |
|
|||
580 | class Timer(object): |
|
|||
581 | def __init__(self, func): |
|
|||
582 | self.app = Tkinter.Tk() |
|
|||
583 | self.app.withdraw() |
|
|||
584 | self.func = func |
|
|||
585 |
|
||||
586 | def on_timer(self): |
|
|||
587 | self.func() |
|
|||
588 | self.app.after(poll_interval, self.on_timer) |
|
|||
589 |
|
||||
590 | def start(self): |
|
|||
591 | self.on_timer() # Call it once to get things going. |
|
|||
592 | self.app.mainloop() |
|
|||
593 |
|
||||
594 | kernel.timer = Timer(doi) |
|
|||
595 | kernel.timer.start() |
|
|||
596 |
|
||||
597 |
|
||||
598 | def loop_gtk(kernel): |
|
|||
599 | """Start the kernel, coordinating with the GTK event loop""" |
|
|||
600 | from .gui.gtkembed import GTKEmbed |
|
|||
601 |
|
||||
602 | gtk_kernel = GTKEmbed(kernel) |
|
|||
603 | gtk_kernel.start() |
|
|||
604 |
|
||||
605 |
|
||||
606 | def loop_cocoa(kernel): |
|
|||
607 | """Start the kernel, coordinating with the Cocoa CFRunLoop event loop |
|
|||
608 | via the matplotlib MacOSX backend. |
|
|||
609 | """ |
|
|||
610 | import matplotlib |
|
|||
611 | if matplotlib.__version__ < '1.1.0': |
|
|||
612 | kernel.log.warn( |
|
|||
613 | "MacOSX backend in matplotlib %s doesn't have a Timer, " |
|
|||
614 | "falling back on Tk for CFRunLoop integration. Note that " |
|
|||
615 | "even this won't work if Tk is linked against X11 instead of " |
|
|||
616 | "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, " |
|
|||
617 | "you must use matplotlib >= 1.1.0, or a native libtk." |
|
|||
618 | ) |
|
|||
619 | return loop_tk(kernel) |
|
|||
620 |
|
||||
621 | from matplotlib.backends.backend_macosx import TimerMac, show |
|
|||
622 |
|
||||
623 | # scale interval for sec->ms |
|
|||
624 | poll_interval = int(1000*kernel._poll_interval) |
|
|||
625 |
|
||||
626 | real_excepthook = sys.excepthook |
|
|||
627 | def handle_int(etype, value, tb): |
|
|||
628 | """don't let KeyboardInterrupts look like crashes""" |
|
|||
629 | if etype is KeyboardInterrupt: |
|
|||
630 | io.raw_print("KeyboardInterrupt caught in CFRunLoop") |
|
|||
631 | else: |
|
|||
632 | real_excepthook(etype, value, tb) |
|
|||
633 |
|
||||
634 | # add doi() as a Timer to the CFRunLoop |
|
|||
635 | def doi(): |
|
|||
636 | # restore excepthook during IPython code |
|
|||
637 | sys.excepthook = real_excepthook |
|
|||
638 | kernel.do_one_iteration() |
|
|||
639 | # and back: |
|
|||
640 | sys.excepthook = handle_int |
|
|||
641 |
|
||||
642 | t = TimerMac(poll_interval) |
|
|||
643 | t.add_callback(doi) |
|
|||
644 | t.start() |
|
|||
645 |
|
||||
646 | # but still need a Poller for when there are no active windows, |
|
|||
647 | # during which time mainloop() returns immediately |
|
|||
648 | poller = zmq.Poller() |
|
|||
649 | poller.register(kernel.shell_socket, zmq.POLLIN) |
|
|||
650 |
|
||||
651 | while True: |
|
|||
652 | try: |
|
|||
653 | # double nested try/except, to properly catch KeyboardInterrupt |
|
|||
654 | # due to pyzmq Issue #130 |
|
|||
655 | try: |
|
|||
656 | # don't let interrupts during mainloop invoke crash_handler: |
|
|||
657 | sys.excepthook = handle_int |
|
|||
658 | show.mainloop() |
|
|||
659 | sys.excepthook = real_excepthook |
|
|||
660 | # use poller if mainloop returned (no windows) |
|
|||
661 | # scale by extra factor of 10, since it's a real poll |
|
|||
662 | poller.poll(10*poll_interval) |
|
|||
663 | kernel.do_one_iteration() |
|
|||
664 | except: |
|
|||
665 | raise |
|
|||
666 | except KeyboardInterrupt: |
|
|||
667 | # Ctrl-C shouldn't crash the kernel |
|
|||
668 | io.raw_print("KeyboardInterrupt caught in kernel") |
|
|||
669 | finally: |
|
|||
670 | # ensure excepthook is restored |
|
|||
671 | sys.excepthook = real_excepthook |
|
|||
672 |
|
||||
673 | # mapping of keys to loop functions |
|
|||
674 | loop_map = { |
|
|||
675 | 'qt' : loop_qt4, |
|
|||
676 | 'qt4': loop_qt4, |
|
|||
677 | 'inline': None, |
|
|||
678 | 'osx': loop_cocoa, |
|
|||
679 | 'wx' : loop_wx, |
|
|||
680 | 'tk' : loop_tk, |
|
|||
681 | 'gtk': loop_gtk, |
|
|||
682 | None : None, |
|
|||
683 | } |
|
|||
684 |
|
||||
685 | def enable_gui(gui, kernel=None): |
|
|||
686 | """Enable integration with a given GUI""" |
|
|||
687 | if kernel is None: |
|
|||
688 | kernel = IPKernelApp.instance().kernel |
|
|||
689 | if gui not in loop_map: |
|
|||
690 | raise ValueError("GUI %r not supported" % gui) |
|
|||
691 | loop = loop_map[gui] |
|
|||
692 | if kernel.eventloop is not None and kernel.eventloop is not loop: |
|
|||
693 | raise RuntimeError("Cannot activate multiple GUI eventloops") |
|
|||
694 | kernel.eventloop = loop |
|
|||
695 |
|
||||
696 |
|
||||
697 | #----------------------------------------------------------------------------- |
|
513 | #----------------------------------------------------------------------------- | |
698 | # Aliases and Flags for the IPKernelApp |
|
514 | # Aliases and Flags for the IPKernelApp | |
699 | #----------------------------------------------------------------------------- |
|
515 | #----------------------------------------------------------------------------- |
@@ -109,6 +109,11 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
109 |
|
109 | |||
110 | keepkernel_on_exit = None |
|
110 | keepkernel_on_exit = None | |
111 |
|
111 | |||
|
112 | # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no | |||
|
113 | # interactive input being read; we provide event loop support in ipkernel | |||
|
114 | from .eventloops import enable_gui | |||
|
115 | enable_gui = staticmethod(enable_gui) | |||
|
116 | ||||
112 | def init_environment(self): |
|
117 | def init_environment(self): | |
113 | """Configure the user's environment. |
|
118 | """Configure the user's environment. | |
114 |
|
119 | |||
@@ -390,10 +395,6 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
390 | } |
|
395 | } | |
391 | self.payload_manager.write_payload(payload) |
|
396 | self.payload_manager.write_payload(payload) | |
392 |
|
397 | |||
393 | def enable_gui(self, gui=None): |
|
|||
394 | from IPython.zmq.ipkernel import enable_gui |
|
|||
395 | enable_gui(gui) |
|
|||
396 |
|
||||
397 | # A few magics that are adapted to the specifics of using pexpect and a |
|
398 | # A few magics that are adapted to the specifics of using pexpect and a | |
398 | # remote terminal |
|
399 | # remote terminal | |
399 |
|
400 |
General Comments 0
You need to be logged in to leave comments.
Login now