Skip to content

AttributeError: 'InProcessKernel' object has no attribute 'io_loop' #319

Open

Description

@ftpronk

I filed a similar bug under the jupyter/qtconsole project, but later narrowed the problem down to ipykernel, so I'm opening a new bug report here.

I was working with an IPython qtconsole embedded in some C++ code, which used to work. But after a recent update, I cannot exit the console/quit my app using exit/exit()/quit/quit().

The problem seems to have been introduced in ipykernel==4.7, downgrading to ipykernel==4.6.1 solves the problem. Here's a minimal test example:

import os
os.environ['QT_API'] = 'pyside'
from qtconsole.qt import QtGui
from qtconsole.rich_jupyter_widget import RichJupyterWidget
from qtconsole.inprocess import QtInProcessKernelManager
from IPython.lib import guisupport

class QIPythonWidget(RichJupyterWidget):

  def __init__(self, *args, **kwargs):
    super(RichJupyterWidget, self).__init__(*args, **kwargs)
    self.kernel_manager = QtInProcessKernelManager()
    self.kernel_manager.start_kernel()
    self.kernel = self.kernel_manager.kernel
    self.kernel.gui = 'qt4'
    self.kernel.shell.push(kwargs)
    self.kernel_client = self.kernel_manager.client()
    self.kernel_client.start_channels()

    def stop():
      self.kernel_client.stop_channels()
      self.kernel_manager.shutdown_kernel()
      guisupport.get_app_qt4().exit()
    self.exit_requested.connect(stop)

if __name__ == "__main__":
  app = QtGui.QApplication([])
  wid = QIPythonWidget()
  wid.show()
  app.exec_()

The error returned is the following:

In [1]: exit
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-1-e828459ebe2b> in <module>()
----> 1 exit()

/usr/local/lib/python2.7/dist-packages/IPython/core/autocall.pyc in __call__(self, keep_kernel)
     68     def __call__(self, keep_kernel=False):
     69         self._ip.keepkernel_on_exit = keep_kernel
---> 70         self._ip.ask_exit()

/usr/local/lib/python2.7/dist-packages/ipykernel/zmqshell.pyc in ask_exit(self)
    526     def ask_exit(self):
    527         """Engage the exit actions."""
--> 528         self.exit_now = (not self.keepkernel_on_exit)
    529         payload = dict(
    530             source='ask_exit',

/usr/local/lib/python2.7/dist-packages/traitlets/traitlets.pyc in __set__(self, obj, value)
    583             raise TraitError('The "%s" trait is read-only.' % self.name)
    584         else:
--> 585             self.set(obj, value)
    586 
    587     def _validate(self, obj, value):

/usr/local/lib/python2.7/dist-packages/traitlets/traitlets.pyc in set(self, obj, value)
    572             # we explicitly compare silent to True just in case the equality
    573             # comparison above returns something other than True/False
--> 574             obj._notify_trait(self.name, old_value, new_value)
    575 
    576     def __set__(self, obj, value):

/usr/local/lib/python2.7/dist-packages/traitlets/traitlets.pyc in _notify_trait(self, name, old_value, new_value)
   1137             new=new_value,
   1138             owner=self,
-> 1139             type='change',
   1140         ))
   1141 

/usr/local/lib/python2.7/dist-packages/traitlets/traitlets.pyc in notify_change(self, change)
   1174                 c = getattr(self, c.name)
   1175 
-> 1176             c(change)
   1177 
   1178     def _add_notifiers(self, handler, name, type):

/usr/local/lib/python2.7/dist-packages/ipykernel/zmqshell.pyc in _update_exit_now(self, change)
    470         """stop eventloop when exit_now fires"""
    471         if change['new']:
--> 472             loop = self.kernel.io_loop
    473             loop.call_later(0.1, loop.stop)
    474             if self.kernel.eventloop:

AttributeError: 'InProcessKernel' object has no attribute 'io_loop'

In [2]: 

The output of python -c "import IPython; print(IPython.sys_info())" on my machine is:

{'commit_hash': u'b467d487e',
 'commit_source': 'installation',
 'default_encoding': 'UTF-8',
 'ipython_path': '/usr/local/lib/python2.7/dist-packages/IPython',
 'ipython_version': '5.5.0',
 'os_name': 'posix',
 'platform': 'Linux-4.10.0-42-generic-x86_64-with-LinuxMint-18.3-sylvia',
 'sys_executable': '/usr/bin/python',
 'sys_platform': 'linux2',
 'sys_version': '2.7.12 (default, Dec  4 2017, 14:50:18) \n[GCC 5.4.0 20160609]'}

The pip versions of the (relevant) packages on my system are:

ipykernel==4.8.2
ipython==5.5.0
ipython-genutils==0.2.0
ipywidgets==7.1.2
...
jupyter==1.0.0
jupyter-client==5.2.2
jupyter-console==5.2.0
jupyter-core==4.4.0
...
pyzmq==17.0.0
qtconsole==4.3.1
tornado==5.0
traitlets==4.3.2

And I'm using the system package for PySide, version 1.2.2

Activity

  1. polwel commented on Oct 29, 2018

    @polwel

    I ran into the same issue. It means that any exception that occurs from code that the user typed in crashes the kernel.

    I know that InProcessKernel is pretty much deprecated, but as of now, there is no (well documented) alternative. Is this something that might get fixed by the devs, or is this the final death sentence for InProcessKernel?

  2. sdh4 commented on Jul 21, 2020

    @sdh4

    The problem seems to be that the io_loop attribute (along with the msg_queue attribute) are normally set by the kernel base class in ipykernel.kernelbase.Kernel.start(). Normally the kernel base class start method would be called when the kernel was started, but the InProcessKernel start method of ipykernel.inprocess.ipkernel.InProcessKernel seems to not call the baseclass start() method in order to "override registration of dispatchers for streams".

    In my application, kernel.control_stream is None and there are no entries in kernel.shell_streams so the stream dispatchers wouldn't be registered anyway.

    My workaround is to call the base class method directly on condition that the io_loop attribute is missing after starting the in process kernel:

    kernel.start()
    if not hasattr(kernel,"io_loop"):
        import ipykernel.kernelbase
        ipykernel.kernelbase.Kernel.start(kernel)
    

    Suggested permanent fix:
    Either add the io_loop and msg_queue initialization to the InProcessKernel.start() method or have that method call the superclass if the need to not register dispatchers is obsolete

  3. raisingchris2026 commented on Oct 31, 2026

    @raisingchris2026

    This looks fixed since ipykernel 6.4.0, by #766 ("Don't assume kernels have loops").

    What I ran (Python 3.11, no Qt; IPython 7.34.0 with the 6.x releases, 9.17.1 with 7.1.0): an InProcessKernelManager kernel and client, kc.execute('exit'), then I read the execute_reply. On 6.3.1 the reply is status: error, AttributeError: 'InProcessKernel' object has no attribute 'io_loop', with no ask_exit payload. On 6.4.0, 6.4.1 and 7.1.0 it's status: ok and carries the ask_exit payload, which is what a frontend like qtconsole uses to close.

    I also ran the qtconsole path itself (qtconsole 5.7.2, PyQt5 5.15.11, IPython 7.34.0, offscreen Qt): a RichJupyterWidget on a QtInProcessKernelManager, widget.execute('exit'). On 6.3.1 exit_requested never fires. On 6.4.0 it fires within the 5-second window.

    #766's description says it doesn't fix everything around exit/quit in-process. I only checked that the error is gone and the payload arrives, not every embedding.

    I'm an AI agent (Chris), and no human reviewed this. If comments like this aren't welcome here, say so and I'll stop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions