Example #1
0
 def object_info_request(self, ident, parent):
     object_info = self.shell.object_inspect(parent['content']['oname'])
     # Before we send this object over, we scrub it for JSON usage
     oinfo = json_clean(object_info)
     msg = self.session.send(self.reply_socket, 'object_info_reply',
                             oinfo, parent, ident)
     io.raw_print(msg)
Example #2
0
 def connect_request(self, ident, parent):
     if self._recorded_ports is not None:
         content = self._recorded_ports.copy()
     else:
         content = {}
     msg = self.session.send(self.reply_socket, "connect_reply", content, parent, ident)
     io.raw_print(msg)
Example #3
0
    def init_sockets(self):
        # Create a context, a session, and the kernel sockets.
        io.raw_print("Starting the kernel at pid:", os.getpid())
        context = zmq.Context.instance()
        # Uncomment this to try closing the context.
        # atexit.register(context.term)

        self.shell_socket = context.socket(zmq.XREP)
        self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
        self.log.debug("shell XREP Channel on port: %i"%self.shell_port)

        self.iopub_socket = context.socket(zmq.PUB)
        self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
        self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port)

        self.stdin_socket = context.socket(zmq.XREQ)
        self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
        self.log.debug("stdin XREQ Channel on port: %i"%self.stdin_port)

        self.heartbeat = Heartbeat(context, (self.ip, self.hb_port))
        self.hb_port = self.heartbeat.port
        self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)

        # Helper to make it easier to connect to an existing kernel, until we have
        # single-port connection negotiation fully implemented.
        self.log.info("To connect another client to this kernel, use:")
        self.log.info("--external shell={0} iopub={1} stdin={2} hb={3}".format(
            self.shell_port, self.iopub_port, self.stdin_port, self.hb_port))


        self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
                                stdin=self.stdin_port, hb=self.hb_port)
Example #4
0
    def start(self):
        """ Start the kernel main loop.
        """
        poller = zmq.Poller()
        poller.register(self.shell_socket, zmq.POLLIN)
        # loop while self.eventloop has not been overridden
        while self.eventloop is None:
            try:
                # scale by extra factor of 10, because there is no
                # reason for this to be anything less than ~ 0.1s
                # since it is a real poller and will respond
                # to events immediately

                # double nested try/except, to properly catch KeyboardInterrupt
                # due to pyzmq Issue #130
                try:
                    poller.poll(10*1000*self._poll_interval)
                    self.do_one_iteration()
                except:
                    raise
            except KeyboardInterrupt:
                # Ctrl-C shouldn't crash the kernel
                io.raw_print("KeyboardInterrupt caught in kernel")
        if self.eventloop is not None:
            try:
                self.eventloop(self)
            except KeyboardInterrupt:
                # Ctrl-C shouldn't crash the kernel
                io.raw_print("KeyboardInterrupt caught in kernel")
Example #5
0
def loop_cocoa(kernel):
    """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
    via the matplotlib MacOSX backend.
    """
    from ._eventloop_macos import mainloop, stop

    real_excepthook = sys.excepthook
    def handle_int(etype, value, tb):
        """don't let KeyboardInterrupts look like crashes"""
        # wake the eventloop when we get a signal
        stop()
        if etype is KeyboardInterrupt:
            io.raw_print("KeyboardInterrupt caught in CFRunLoop")
        else:
            real_excepthook(etype, value, tb)

    while not kernel.shell.exit_now:
        try:
            # double nested try/except, to properly catch KeyboardInterrupt
            # due to pyzmq Issue #130
            try:
                # don't let interrupts during mainloop invoke crash_handler:
                sys.excepthook = handle_int
                mainloop(kernel._poll_interval)
                sys.excepthook = real_excepthook
                kernel.do_one_iteration()
            except:
                raise
        except KeyboardInterrupt:
            # Ctrl-C shouldn't crash the kernel
            io.raw_print("KeyboardInterrupt caught in kernel")
        finally:
            # ensure excepthook is restored
            sys.excepthook = real_excepthook
Example #6
0
    def run(self):
        """ Run the poll loop. This method never returns.
        """
        from _subprocess import WAIT_OBJECT_0, INFINITE

        # Build the list of handle to listen on.
        handles = []
        if self.interrupt_handle:
            handles.append(self.interrupt_handle)
        if self.parent_handle:
            handles.append(self.parent_handle)

        # Listen forever.
        while True:
            result = ctypes.windll.kernel32.WaitForMultipleObjects(
                len(handles),                            # nCount
                (ctypes.c_int * len(handles))(*handles), # lpHandles
                False,                                   # bWaitAll
                INFINITE)                                # dwMilliseconds

            if WAIT_OBJECT_0 <= result < len(handles):
                handle = handles[result - WAIT_OBJECT_0]

                if handle == self.interrupt_handle:
                    raw_print('Interrupted by parent poller!')
                    interrupt_main()

                elif handle == self.parent_handle:
                    raw_print('Killed by parent poller!')
                    os._exit(1)
Example #7
0
 def complete_request(self, ident, parent):
     txt, matches = self._complete(parent)
     matches = {'matches' : matches,
                'matched_text' : txt,
                'status' : 'ok'}
     completion_msg = self.session.send(self.reply_socket, 'complete_reply',
                                        matches, parent, ident)
     io.raw_print(completion_msg)
Example #8
0
 def history_request(self, ident, parent):
     output = parent["content"]["output"]
     index = parent["content"]["index"]
     raw = parent["content"]["raw"]
     hist = self.shell.get_history(index=index, raw=raw, output=output)
     content = {"history": hist}
     msg = self.session.send(self.reply_socket, "history_reply", content, parent, ident)
     io.raw_print(msg)
Example #9
0
 def handle_int(etype, value, tb):
     """don't let KeyboardInterrupts look like crashes"""
     # wake the eventloop when we get a signal
     stop()
     if etype is KeyboardInterrupt:
         io.raw_print("KeyboardInterrupt caught in CFRunLoop")
     else:
         real_excepthook(etype, value, tb)
Example #10
0
 def history_request(self, ident, parent):
     output = parent['content']['output']
     index = parent['content']['index']
     raw = parent['content']['raw']
     hist = self.shell.get_history(index=index, raw=raw, output=output)
     content = {'history' : hist}
     msg = self.session.send(self.reply_socket, 'history_reply',
                             content, parent, ident)
     io.raw_print(msg)
Example #11
0
 def start(self):
     """ Start the kernel main loop.
     """
     while True:
         try:
             time.sleep(self._poll_interval)
             self.do_one_iteration()
         except KeyboardInterrupt:
             # Ctrl-C shouldn't crash the kernel
             io.raw_print("KeyboardInterrupt caught in kernel")
Example #12
0
    def call_handlers(self, msg):
        """ Overridden for the in-process channel.

        This methods simply calls raw_input directly.
        """
        msg_type = msg["header"]["msg_type"]
        if msg_type == "input_request":
            _raw_input = self.client.kernel._sys_raw_input
            prompt = msg["content"]["prompt"]
            raw_print(prompt, end="")
            self.client.input(_raw_input())
Example #13
0
    def call_handlers(self, msg):
        """ Overridden for the in-process channel.

        This methods simply calls raw_input directly.
        """
        msg_type = msg['header']['msg_type']
        if msg_type == 'input_request':
            _raw_input = self.client.kernel._sys_raw_input
            prompt = msg['content']['prompt']
            raw_print(prompt, end='')
            self.client.input(_raw_input())
Example #14
0
 def _at_shutdown(self):
     """Actions taken at shutdown by the kernel, called by python's atexit.
     """
     # io.rprint("Kernel at_shutdown") # dbg
     if self._shutdown_message is not None:
         self.reply_socket.send_json(self._shutdown_message)
         self.pub_socket.send_json(self._shutdown_message)
         io.raw_print(self._shutdown_message)
         # A very short sleep to give zmq time to flush its message buffers
         # before Python truly shuts down.
         time.sleep(0.01)
Example #15
0
 def run(self):
     # We cannot use os.waitpid because it works only for child processes.
     from errno import EINTR
     while True:
         try:
             if os.getppid() == 1:
                 raw_print('Killed by parent poller!')
                 os._exit(1)
             time.sleep(1.0)
         except OSError, e:
             if e.errno == EINTR:
                 continue
             raise
Example #16
0
 def flush(self):
     #io.rprint('>>>flushing output buffer: %s<<<' % self.name)  # dbg
     if self.pub_socket is None:
         raise ValueError('I/O operation on closed file')
     else:
         data = self._buffer.getvalue()
         if data:
             content = {'name':self.name, 'data':data}
             msg = self.session.send(self.pub_socket, 'stream', content=content,
                                    parent=self.parent_header)
             io.raw_print(msg)
             
             self._buffer.close()
             self._new_buffer()
Example #17
0
 def start(self):
     """ Start the kernel main loop.
     """
     poller = zmq.Poller()
     poller.register(self.shell_socket, zmq.POLLIN)
     while True:
         try:
             # scale by extra factor of 10, because there is no
             # reason for this to be anything less than ~ 0.1s
             # since it is a real poller and will respond
             # to events immediately
             poller.poll(10*1000*self._poll_interval)
             self.do_one_iteration()
         except KeyboardInterrupt:
             # Ctrl-C shouldn't crash the kernel
             io.raw_print("KeyboardInterrupt caught in kernel")
Example #18
0
 def _abort_queue(self):
     while True:
         ident,msg = self.session.recv(self.reply_socket, zmq.NOBLOCK)
         if msg is None:
             break
         else:
             assert ident is not None, \
                    "Unexpected missing message part."
         io.raw_print("Aborting:\n", Message(msg))
         msg_type = msg['msg_type']
         reply_type = msg_type.split('_')[0] + '_reply'
         reply_msg = self.session.send(self.reply_socket, reply_type, 
                 {'status' : 'aborted'}, msg, ident=ident)
         io.raw_print(reply_msg)
         # We need to wait a bit for requests to come in. This can probably
         # be set shorter for true asynchronous clients.
         time.sleep(0.1)
Example #19
0
    def start(self):
        """ Start the kernel main loop.
        """
        # a KeyboardInterrupt (SIGINT) can occur on any python statement, so
        # let's ignore (SIG_IGN) them until we're in a place to handle them properly
        signal(SIGINT,SIG_IGN)
        poller = zmq.Poller()
        poller.register(self.shell_socket, zmq.POLLIN)
        # loop while self.eventloop has not been overridden
        while self.eventloop is None:
            try:
                # scale by extra factor of 10, because there is no
                # reason for this to be anything less than ~ 0.1s
                # since it is a real poller and will respond
                # to events immediately

                # double nested try/except, to properly catch KeyboardInterrupt
                # due to pyzmq Issue #130
                try:
                    poller.poll(10*1000*self._poll_interval)
                    # restore raising of KeyboardInterrupt
                    signal(SIGINT, default_int_handler)
                    self.do_one_iteration()
                except:
                    raise
                finally:
                    # prevent raising of KeyboardInterrupt
                    signal(SIGINT,SIG_IGN)
            except KeyboardInterrupt:
                # Ctrl-C shouldn't crash the kernel
                io.raw_print("KeyboardInterrupt caught in kernel")
        # stop ignoring sigint, now that we are out of our own loop,
        # we don't want to prevent future code from handling it
        signal(SIGINT, default_int_handler)
        while self.eventloop is not None:
            try:
                self.eventloop(self)
            except KeyboardInterrupt:
                # Ctrl-C shouldn't crash the kernel
                io.raw_print("KeyboardInterrupt caught in kernel")
                continue
            else:
                # eventloop exited cleanly, this means we should stop (right?)
                self.eventloop = None
                break
Example #20
0
 def _abort_queue(self):
     while True:
         try:
             ident = self.reply_socket.recv(zmq.NOBLOCK)
         except zmq.ZMQError, e:
             if e.errno == zmq.EAGAIN:
                 break
         else:
             assert self.reply_socket.rcvmore(), "Unexpected missing message part."
             msg = self.reply_socket.recv_json()
         io.raw_print("Aborting:\n", Message(msg))
         msg_type = msg["msg_type"]
         reply_type = msg_type.split("_")[0] + "_reply"
         reply_msg = self.session.msg(reply_type, {"status": "aborted"}, msg)
         io.raw_print(reply_msg)
         self.reply_socket.send(ident, zmq.SNDMORE)
         self.reply_socket.send_json(reply_msg)
         # We need to wait a bit for requests to come in. This can probably
         # be set shorter for true asynchronous clients.
         time.sleep(0.1)
Example #21
0
    def do_one_iteration(self):
        """Do one iteration of the kernel's evaluation loop.
        """
        ident,msg = self.session.recv(self.reply_socket, zmq.NOBLOCK)
        if msg is None:
            return
        
        # This assert will raise in versions of zeromq 2.0.7 and lesser.
        # We now require 2.0.8 or above, so we can uncomment for safety.
        # print(ident,msg, file=sys.__stdout__)
        assert ident is not None, "Missing message part."
        
        # Print some info about this message and leave a '--->' marker, so it's
        # easier to trace visually the message chain when debugging.  Each
        # handler prints its message at the end.
        # Eventually we'll move these from stdout to a logger.
        io.raw_print('\n*** MESSAGE TYPE:', msg['msg_type'], '***')
        io.raw_print('   Content: ', msg['content'],
                     '\n   --->\n   ', sep='', end='')

        # Find and call actual handler for message
        handler = self.handlers.get(msg['msg_type'], None)
        if handler is None:
            io.raw_print_err("UNKNOWN MESSAGE TYPE:", msg)
        else:
            handler(ident, msg)
            
        # Check whether we should exit, in case the incoming message set the
        # exit flag on
        if self.shell.exit_now:
            io.raw_print('\nExiting IPython kernel...')
            # We do a normal, clean exit, which allows any actions registered
            # via atexit (such as history saving) to take place.
            sys.exit(0)
Example #22
0
    def execute_request(self, ident, parent):

        status_msg = self.session.msg(u"status", {u"execution_state": u"busy"}, parent=parent)
        self.pub_socket.send_json(status_msg)

        try:
            content = parent[u"content"]
            code = content[u"code"]
            silent = content[u"silent"]
        except:
            io.raw_print_err("Got bad msg: ")
            io.raw_print_err(Message(parent))
            return

        shell = self.shell  # we'll need this a lot here

        # Replace raw_input. Note that is not sufficient to replace
        # raw_input in the user namespace.
        raw_input = lambda prompt="": self._raw_input(prompt, ident, parent)
        __builtin__.raw_input = raw_input

        # Set the parent message of the display hook and out streams.
        shell.displayhook.set_parent(parent)
        sys.stdout.set_parent(parent)
        sys.stderr.set_parent(parent)

        # Re-broadcast our input for the benefit of listening clients, and
        # start computing output
        if not silent:
            self._publish_pyin(code, parent)

        reply_content = {}
        try:
            if silent:
                # runcode uses 'exec' mode, so no displayhook will fire, and it
                # doesn't call logging or history manipulations.  Print
                # statements in that code will obviously still execute.
                shell.runcode(code)
            else:
                # FIXME: runlines calls the exception handler itself.
                shell._reply_content = None

                # For now leave this here until we're sure we can stop using it
                # shell.runlines(code)

                # Experimental: cell mode!  Test more before turning into
                # default and removing the hacks around runlines.
                shell.run_cell(code)
        except:
            status = u"error"
            # FIXME: this code right now isn't being used yet by default,
            # because the runlines() call above directly fires off exception
            # reporting.  This code, therefore, is only active in the scenario
            # where runlines itself has an unhandled exception.  We need to
            # uniformize this, for all exception construction to come from a
            # single location in the codbase.
            etype, evalue, tb = sys.exc_info()
            tb_list = traceback.format_exception(etype, evalue, tb)
            reply_content.update(shell._showtraceback(etype, evalue, tb_list))
        else:
            status = u"ok"

        reply_content[u"status"] = status
        # Compute the execution counter so clients can display prompts
        reply_content["execution_count"] = shell.displayhook.prompt_count

        # FIXME - fish exception info out of shell, possibly left there by
        # runlines.  We'll need to clean up this logic later.
        if shell._reply_content is not None:
            reply_content.update(shell._reply_content)

        # At this point, we can tell whether the main code execution succeeded
        # or not.  If it did, we proceed to evaluate user_variables/expressions
        if reply_content["status"] == "ok":
            reply_content[u"user_variables"] = shell.user_variables(content[u"user_variables"])
            reply_content[u"user_expressions"] = shell.user_expressions(content[u"user_expressions"])
        else:
            # If there was an error, don't even try to compute variables or
            # expressions
            reply_content[u"user_variables"] = {}
            reply_content[u"user_expressions"] = {}

        # Payloads should be retrieved regardless of outcome, so we can both
        # recover partial output (that could have been generated early in a
        # block, before an error) and clear the payload system always.
        reply_content[u"payload"] = shell.payload_manager.read_payload()
        # Be agressive about clearing the payload because we don't want
        # it to sit in memory until the next execute_request comes in.
        shell.payload_manager.clear_payload()

        # Send the reply.
        reply_msg = self.session.msg(u"execute_reply", reply_content, parent)
        io.raw_print(reply_msg)

        # Flush output before sending the reply.
        sys.stdout.flush()
        sys.stderr.flush()
        # FIXME: on rare occasions, the flush doesn't seem to make it to the
        # clients... This seems to mitigate the problem, but we definitely need
        # to better understand what's going on.
        if self._execute_sleep:
            time.sleep(self._execute_sleep)

        self.reply_socket.send(ident, zmq.SNDMORE)
        self.reply_socket.send_json(reply_msg)
        if reply_msg["content"]["status"] == u"error":
            self._abort_queue()

        status_msg = self.session.msg(u"status", {u"execution_state": u"idle"}, parent=parent)
        self.pub_socket.send_json(status_msg)
Example #23
0
def make_kernel(namespace, kernel_factory, 
                out_stream_factory=None, display_hook_factory=None):
    """ Creates a kernel, redirects stdout/stderr, and installs a display hook
    and exception handler.
    """
    # Re-direct stdout/stderr, if necessary.
    if namespace.no_stdout or namespace.no_stderr:
        blackhole = file(os.devnull, 'w')
        if namespace.no_stdout:
            sys.stdout = sys.__stdout__ = blackhole
        if namespace.no_stderr:
            sys.stderr = sys.__stderr__ = blackhole

    # Install minimal exception handling
    sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', 
                                 ostream=sys.__stdout__)

    # Create a context, a session, and the kernel sockets.
    io.raw_print("Starting the kernel at pid:", os.getpid())
    context = zmq.Context()
    # Uncomment this to try closing the context.
    # atexit.register(context.close)
    session = Session(username=u'kernel')

    reply_socket = context.socket(zmq.XREP)
    xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
    io.raw_print("XREP Channel on port", xrep_port)

    pub_socket = context.socket(zmq.PUB)
    pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
    io.raw_print("PUB Channel on port", pub_port)

    req_socket = context.socket(zmq.XREQ)
    req_port = bind_port(req_socket, namespace.ip, namespace.req)
    io.raw_print("REQ Channel on port", req_port)

    hb = Heartbeat(context, (namespace.ip, namespace.hb))
    hb.start()
    hb_port = hb.port
    io.raw_print("Heartbeat REP Channel on port", hb_port)

    # Helper to make it easier to connect to an existing kernel, until we have
    # single-port connection negotiation fully implemented.
    io.raw_print("To connect another client to this kernel, use:")
    io.raw_print("-e --xreq {0} --sub {1} --rep {2} --hb {3}".format(
        xrep_port, pub_port, req_port, hb_port))

    # Redirect input streams and set a display hook.
    if out_stream_factory:
        sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
        sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
    if display_hook_factory:
        sys.displayhook = display_hook_factory(session, pub_socket)

    # Create the kernel.
    kernel = kernel_factory(session=session, reply_socket=reply_socket, 
                            pub_socket=pub_socket, req_socket=req_socket)
    kernel.record_ports(xrep_port=xrep_port, pub_port=pub_port,
                        req_port=req_port, hb_port=hb_port)
    return kernel
def make_kernel(namespace, kernel_factory, 
                out_stream_factory=None, display_hook_factory=None):
    """ Creates a kernel, redirects stdout/stderr, and installs a display hook
    and exception handler.
    """
    # If running under pythonw.exe, the interpreter will crash if more than 4KB
    # of data is written to stdout or stderr. This is a bug that has been with
    # Python for a very long time; see http://bugs.python.org/issue706263.
    if sys.executable.endswith('pythonw.exe'):
        blackhole = file(os.devnull, 'w')
        sys.stdout = sys.stderr = blackhole
        sys.__stdout__ = sys.__stderr__ = blackhole 

    # Install minimal exception handling
    sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', 
                                 ostream=sys.__stdout__)

    # Create a context, a session, and the kernel sockets.
    io.raw_print("Starting the kernel at pid:", os.getpid())
    context = zmq.Context()
    # Uncomment this to try closing the context.
    # atexit.register(context.close)
    session = Session(username=u'kernel')

    reply_socket = context.socket(zmq.XREP)
    xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
    io.raw_print("XREP Channel on port", xrep_port)

    pub_socket = context.socket(zmq.PUB)
    pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
    io.raw_print("PUB Channel on port", pub_port)

    req_socket = context.socket(zmq.XREQ)
    req_port = bind_port(req_socket, namespace.ip, namespace.req)
    io.raw_print("REQ Channel on port", req_port)

    hb = Heartbeat(context, (namespace.ip, namespace.hb))
    hb.start()
    hb_port = hb.port
    io.raw_print("Heartbeat REP Channel on port", hb_port)

    # Helper to make it easier to connect to an existing kernel, until we have
    # single-port connection negotiation fully implemented.
    io.raw_print("To connect another client to this kernel, use:")
    io.raw_print("-e --xreq {0} --sub {1} --rep {2} --hb {3}".format(
        xrep_port, pub_port, req_port, hb_port))

    # Redirect input streams and set a display hook.
    if out_stream_factory:
        sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
        sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
    if display_hook_factory:
        sys.displayhook = display_hook_factory(session, pub_socket)

    # Create the kernel.
    kernel = kernel_factory(session=session, reply_socket=reply_socket, 
                            pub_socket=pub_socket, req_socket=req_socket)
    kernel.record_ports(xrep_port=xrep_port, pub_port=pub_port,
                        req_port=req_port, hb_port=hb_port)
    return kernel
Example #25
0
def loop_cocoa(kernel):
    """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
    via the matplotlib MacOSX backend.
    """
    import matplotlib
    if matplotlib.__version__ < '1.1.0':
        kernel.log.warn(
            "MacOSX backend in matplotlib %s doesn't have a Timer, "
            "falling back on Tk for CFRunLoop integration.  Note that "
            "even this won't work if Tk is linked against X11 instead of "
            "Cocoa (e.g. EPD).  To use the MacOSX backend in the kernel, "
            "you must use matplotlib >= 1.1.0, or a native libtk.")
        return loop_tk(kernel)

    from matplotlib.backends.backend_macosx import TimerMac, show

    # scale interval for sec->ms
    poll_interval = int(1000 * kernel._poll_interval)

    real_excepthook = sys.excepthook

    def handle_int(etype, value, tb):
        """don't let KeyboardInterrupts look like crashes"""
        if etype is KeyboardInterrupt:
            io.raw_print("KeyboardInterrupt caught in CFRunLoop")
        else:
            real_excepthook(etype, value, tb)

    # add doi() as a Timer to the CFRunLoop
    def doi():
        # restore excepthook during IPython code
        sys.excepthook = real_excepthook
        kernel.do_one_iteration()
        # and back:
        sys.excepthook = handle_int

    t = TimerMac(poll_interval)
    t.add_callback(doi)
    t.start()

    # but still need a Poller for when there are no active windows,
    # during which time mainloop() returns immediately
    poller = zmq.Poller()
    if kernel.control_stream:
        poller.register(kernel.control_stream.socket, zmq.POLLIN)
    for stream in kernel.shell_streams:
        poller.register(stream.socket, zmq.POLLIN)

    while True:
        try:
            # double nested try/except, to properly catch KeyboardInterrupt
            # due to pyzmq Issue #130
            try:
                # don't let interrupts during mainloop invoke crash_handler:
                sys.excepthook = handle_int
                show.mainloop()
                sys.excepthook = real_excepthook
                # use poller if mainloop returned (no windows)
                # scale by extra factor of 10, since it's a real poll
                poller.poll(10 * poll_interval)
                kernel.do_one_iteration()
            except:
                raise
        except KeyboardInterrupt:
            # Ctrl-C shouldn't crash the kernel
            io.raw_print("KeyboardInterrupt caught in kernel")
        finally:
            # ensure excepthook is restored
            sys.excepthook = real_excepthook
Example #26
0
class Kernel(Configurable):

    #---------------------------------------------------------------------------
    # Kernel interface
    #---------------------------------------------------------------------------

    shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
    session = Instance(Session)
    reply_socket = Instance('zmq.Socket')
    pub_socket = Instance('zmq.Socket')
    req_socket = Instance('zmq.Socket')

    # Private interface

    # Time to sleep after flushing the stdout/err buffers in each execute
    # cycle.  While this introduces a hard limit on the minimal latency of the
    # execute cycle, it helps prevent output synchronization problems for
    # clients.
    # Units are in seconds.  The minimum zmq latency on local host is probably
    # ~150 microseconds, set this to 500us for now.  We may need to increase it
    # a little if it's not enough after more interactive testing.
    _execute_sleep = Float(0.0005, config=True)

    # Frequency of the kernel's event loop.
    # Units are in seconds, kernel subclasses for GUI toolkits may need to
    # adapt to milliseconds.
    _poll_interval = Float(0.05, config=True)

    # If the shutdown was requested over the network, we leave here the
    # necessary reply message so it can be sent by our registered atexit
    # handler.  This ensures that the reply is only sent to clients truly at
    # the end of our shutdown process (which happens after the underlying
    # IPython shell's own shutdown).
    _shutdown_message = None

    # This is a dict of port number that the kernel is listening on. It is set
    # by record_ports and used by connect_request.
    _recorded_ports = None
    
    def __init__(self, **kwargs):
        super(Kernel, self).__init__(**kwargs)

        # Before we even start up the shell, register *first* our exit handlers
        # so they come before the shell's
        atexit.register(self._at_shutdown)

        # Initialize the InteractiveShell subclass
        self.shell = ZMQInteractiveShell.instance()
        self.shell.displayhook.session = self.session
        self.shell.displayhook.pub_socket = self.pub_socket

        # TMP - hack while developing
        self.shell._reply_content = None

        # Build dict of handlers for message types
        msg_types = [ 'execute_request', 'complete_request', 
                      'object_info_request', 'history_request',
                      'connect_request', 'shutdown_request']
        self.handlers = {}
        for msg_type in msg_types:
            self.handlers[msg_type] = getattr(self, msg_type)

    def do_one_iteration(self):
        """Do one iteration of the kernel's evaluation loop.
        """
        try:
            ident = self.reply_socket.recv(zmq.NOBLOCK)
        except zmq.ZMQError, e:
            if e.errno == zmq.EAGAIN:
                return
            else:
                raise
        # This assert will raise in versions of zeromq 2.0.7 and lesser.
        # We now require 2.0.8 or above, so we can uncomment for safety.
        assert self.reply_socket.rcvmore(), "Missing message part."
        msg = self.reply_socket.recv_json()
        
        # Print some info about this message and leave a '--->' marker, so it's
        # easier to trace visually the message chain when debugging.  Each
        # handler prints its message at the end.
        # Eventually we'll move these from stdout to a logger.
        io.raw_print('\n*** MESSAGE TYPE:', msg['msg_type'], '***')
        io.raw_print('   Content: ', msg['content'],
                     '\n   --->\n   ', sep='', end='')

        # Find and call actual handler for message
        handler = self.handlers.get(msg['msg_type'], None)
        if handler is None:
            io.raw_print_err("UNKNOWN MESSAGE TYPE:", msg)
        else:
            handler(ident, msg)
            
        # Check whether we should exit, in case the incoming message set the
        # exit flag on
        if self.shell.exit_now:
            io.raw_print('\nExiting IPython kernel...')
            # We do a normal, clean exit, which allows any actions registered
            # via atexit (such as history saving) to take place.
            sys.exit(0)
Example #27
0
def loop_cocoa(kernel):
    """Start the kernel, coordinating with the Cocoa CFRunLoop event loop
    via the matplotlib MacOSX backend.
    """
    import matplotlib
    if matplotlib.__version__ < '1.1.0':
        kernel.log.warn(
        "MacOSX backend in matplotlib %s doesn't have a Timer, "
        "falling back on Tk for CFRunLoop integration.  Note that "
        "even this won't work if Tk is linked against X11 instead of "
        "Cocoa (e.g. EPD).  To use the MacOSX backend in the kernel, "
        "you must use matplotlib >= 1.1.0, or a native libtk."
        )
        return loop_tk(kernel)
    
    from matplotlib.backends.backend_macosx import TimerMac, show

    # scale interval for sec->ms
    poll_interval = int(1000*kernel._poll_interval)

    real_excepthook = sys.excepthook
    def handle_int(etype, value, tb):
        """don't let KeyboardInterrupts look like crashes"""
        if etype is KeyboardInterrupt:
            io.raw_print("KeyboardInterrupt caught in CFRunLoop")
        else:
            real_excepthook(etype, value, tb)

    # add doi() as a Timer to the CFRunLoop
    def doi():
        # restore excepthook during IPython code
        sys.excepthook = real_excepthook
        kernel.do_one_iteration()
        # and back:
        sys.excepthook = handle_int

    t = TimerMac(poll_interval)
    t.add_callback(doi)
    t.start()

    # but still need a Poller for when there are no active windows,
    # during which time mainloop() returns immediately
    poller = zmq.Poller()
    if kernel.control_stream:
        poller.register(kernel.control_stream.socket, zmq.POLLIN)
    for stream in kernel.shell_streams:
        poller.register(stream.socket, zmq.POLLIN)

    while True:
        try:
            # double nested try/except, to properly catch KeyboardInterrupt
            # due to pyzmq Issue #130
            try:
                # don't let interrupts during mainloop invoke crash_handler:
                sys.excepthook = handle_int
                show.mainloop()
                sys.excepthook = real_excepthook
                # use poller if mainloop returned (no windows)
                # scale by extra factor of 10, since it's a real poll
                poller.poll(10*poll_interval)
                kernel.do_one_iteration()
            except:
                raise
        except KeyboardInterrupt:
            # Ctrl-C shouldn't crash the kernel
            io.raw_print("KeyboardInterrupt caught in kernel")
        finally:
            # ensure excepthook is restored
            sys.excepthook = real_excepthook
Example #28
0
 def handle_int(etype, value, tb):
     """don't let KeyboardInterrupts look like crashes"""
     if etype is KeyboardInterrupt:
         io.raw_print("KeyboardInterrupt caught in CFRunLoop")
     else:
         real_excepthook(etype, value, tb)
Example #29
0
 def handle_int(etype, value, tb):
     """don't let KeyboardInterrupts look like crashes"""
     if etype is KeyboardInterrupt:
         io.raw_print("KeyboardInterrupt caught in CFRunLoop")
     else:
         real_excepthook(etype, value, tb)
Example #30
0
 def complete_request(self, ident, parent):
     txt, matches = self._complete(parent)
     matches = {"matches": matches, "matched_text": txt, "status": "ok"}
     completion_msg = self.session.send(self.reply_socket, "complete_reply", matches, parent, ident)
     io.raw_print(completion_msg)
Example #31
0
def make_kernel(namespace, kernel_factory, 
                out_stream_factory=None, display_hook_factory=None):
    """ Creates a kernel, redirects stdout/stderr, and installs a display hook
    and exception handler.
    """
    # If running under pythonw.exe, the interpreter will crash if more than 4KB
    # of data is written to stdout or stderr. This is a bug that has been with
    # Python for a very long time; see http://bugs.python.org/issue706263.
    if sys.executable.endswith('pythonw.exe'):
        blackhole = file(os.devnull, 'w')
        sys.stdout = sys.stderr = blackhole
        sys.__stdout__ = sys.__stderr__ = blackhole 

    # Install minimal exception handling
    sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', 
                                 ostream=sys.__stdout__)

    # Create a context, a session, and the kernel sockets.
    io.raw_print("Starting the kernel at pid:", os.getpid())
    context = zmq.Context()
    # Uncomment this to try closing the context.
    # atexit.register(context.close)
    session = Session(username=u'kernel')

    reply_socket = context.socket(zmq.XREP)
    xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
    io.raw_print("XREP Channel on port", xrep_port)

    pub_socket = context.socket(zmq.PUB)
    pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
    io.raw_print("PUB Channel on port", pub_port)

    req_socket = context.socket(zmq.XREQ)
    req_port = bind_port(req_socket, namespace.ip, namespace.req)
    io.raw_print("REQ Channel on port", req_port)

    hb = Heartbeat(context, (namespace.ip, namespace.hb))
    hb.start()
    hb_port = hb.port
    io.raw_print("Heartbeat REP Channel on port", hb_port)

    # Helper to make it easier to connect to an existing kernel, until we have
    # single-port connection negotiation fully implemented.
    io.raw_print("To connect another client to this kernel, use:")
    io.raw_print("-e --xreq {0} --sub {1} --rep {2} --hb {3}".format(
        xrep_port, pub_port, req_port, hb_port))

    # Redirect input streams and set a display hook.
    if out_stream_factory:
        sys.stdout = out_stream_factory(session, pub_socket, u'stdout')
        sys.stderr = out_stream_factory(session, pub_socket, u'stderr')
    if display_hook_factory:
        sys.displayhook = display_hook_factory(session, pub_socket)

    # Create the kernel.
    kernel = kernel_factory(session=session, reply_socket=reply_socket, 
                            pub_socket=pub_socket, req_socket=req_socket)
    kernel.record_ports(xrep_port=xrep_port, pub_port=pub_port,
                        req_port=req_port, hb_port=hb_port)
    return kernel
Example #32
0
    def execute_request(self, ident, parent):
        
        status_msg = self.session.msg(
            u'status',
            {u'execution_state':u'busy'},
            parent=parent
        )
        self.pub_socket.send_json(status_msg)
        
        try:
            content = parent[u'content']
            code = content[u'code']
            silent = content[u'silent'] 
        except:
            io.raw_print_err("Got bad msg: ")
            io.raw_print_err(Message(parent))
            return

        shell = self.shell # we'll need this a lot here

        # Replace raw_input. Note that is not sufficient to replace 
        # raw_input in the user namespace.
        raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
        __builtin__.raw_input = raw_input

        # Set the parent message of the display hook and out streams.
        shell.displayhook.set_parent(parent)
        sys.stdout.set_parent(parent)
        sys.stderr.set_parent(parent)

        # Re-broadcast our input for the benefit of listening clients, and
        # start computing output
        if not silent:
            self._publish_pyin(code, parent)

        reply_content = {}
        try:
            if silent:
                # run_code uses 'exec' mode, so no displayhook will fire, and it
                # doesn't call logging or history manipulations.  Print
                # statements in that code will obviously still execute.
                shell.run_code(code)
            else:
                # FIXME: the shell calls the exception handler itself.
                shell._reply_content = None
                shell.run_cell(code)
        except:
            status = u'error'
            # FIXME: this code right now isn't being used yet by default,
            # because the runlines() call above directly fires off exception
            # reporting.  This code, therefore, is only active in the scenario
            # where runlines itself has an unhandled exception.  We need to
            # uniformize this, for all exception construction to come from a
            # single location in the codbase.
            etype, evalue, tb = sys.exc_info()
            tb_list = traceback.format_exception(etype, evalue, tb)
            reply_content.update(shell._showtraceback(etype, evalue, tb_list))
        else:
            status = u'ok'

        reply_content[u'status'] = status
        
        # Return the execution counter so clients can display prompts
        reply_content['execution_count'] = shell.execution_count -1

        # FIXME - fish exception info out of shell, possibly left there by
        # runlines.  We'll need to clean up this logic later.
        if shell._reply_content is not None:
            reply_content.update(shell._reply_content)

        # At this point, we can tell whether the main code execution succeeded
        # or not.  If it did, we proceed to evaluate user_variables/expressions
        if reply_content['status'] == 'ok':
            reply_content[u'user_variables'] = \
                         shell.user_variables(content[u'user_variables'])
            reply_content[u'user_expressions'] = \
                         shell.user_expressions(content[u'user_expressions'])
        else:
            # If there was an error, don't even try to compute variables or
            # expressions
            reply_content[u'user_variables'] = {}
            reply_content[u'user_expressions'] = {}

        # Payloads should be retrieved regardless of outcome, so we can both
        # recover partial output (that could have been generated early in a
        # block, before an error) and clear the payload system always.
        reply_content[u'payload'] = shell.payload_manager.read_payload()
        # Be agressive about clearing the payload because we don't want
        # it to sit in memory until the next execute_request comes in.
        shell.payload_manager.clear_payload()

        # Send the reply.
        reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
        io.raw_print(reply_msg)

        # Flush output before sending the reply.
        sys.stdout.flush()
        sys.stderr.flush()
        # FIXME: on rare occasions, the flush doesn't seem to make it to the
        # clients... This seems to mitigate the problem, but we definitely need
        # to better understand what's going on.
        if self._execute_sleep:
            time.sleep(self._execute_sleep)
        
        self.reply_socket.send(ident, zmq.SNDMORE)
        self.reply_socket.send_json(reply_msg)
        if reply_msg['content']['status'] == u'error':
            self._abort_queue()

        status_msg = self.session.msg(
            u'status',
            {u'execution_state':u'idle'},
            parent=parent
        )
        self.pub_socket.send_json(status_msg)