Skip to content

Conversation

@zohl
Copy link

@zohl zohl commented Sep 28, 2023

Hello!

First of all, thank you for your work, the kernel you wrote is very small and easy to understand, so I had a good time experimenting with it :)

I have the same issue as you had before, but the newer versions of jupyter/ipykernel aren't compatible with your kernel. So here is the PR to fix it.

I've changed command-line interface, so you can use the same options as with vanilla ipykernel. You don't have to manually copy kernel.json anymore, just run python -m async_gui_ipython_kernel install instead.

Newer ipykernel versions don't use priority in message queues, git-bissect shows this happened at version 5.6.0. So I put this restriction in setup.py, but in fact there might be other incompatibilities.

While the hack with returning dispatch(*new_args) instead of scheduling it is still working, I found myself uneasy looking at this for a few reasons:

  • we have to consider different variations of args and duplicate message processing logic (seems no longer the case in current kernels)
  • we might block scheduling process while processing "fast-track" message
  • I had set_parent commented out, so i didn't saw the output and thought it didn't work anymore 🤣

Anyway, now it works like this:

  • we have separate message queues ("regular" and "fast-track" for comm-messages, but we can add more for different types)
  • process_one consumes one message at a time as before (from any queue)
  • but, if there is a "hanging" message in a queue it will process messages from other queues

To illustrate this, we could imagine the following timeline:

fast-track        | -some ux-event- |    | -click- |    /
regular       | -------wait_for_click----------------|  /  | ----
- - - - - - --------------------------------------------/---------->
              ^ start `process_one`                        ^ start `process_one`

Not sure if the timeline clarifies it enough, but you can thing of process_one as of "process one [cluster of messages]" rather than "process one [message]".

FWIW, the example widget didn't work for me, so I used this code to test the kernel:

import asyncio
import ipywidgets as widgets

def wait_for_click(w):
    e = asyncio.Event()
    def handler(_):
        e.set()
        w.on_click(handler, remove = True)
    w.on_click(handler)
    return e.wait()

btn = widgets.Button(description = 'push')
display(btn)

for i in range(1, 1 + 3):
    print(i)
    print('press button to continue...')
    await wait_for_click(btn)

print('done')

Vanilla kernel hangs, while async-gui kernel lets you click the button and prints "done".

PS. I used some hacks and monkey patching to reduce the amount of code needs to be changed, so the disclaimer in README.md is still true.

PPS. There is another project (akernel) that does the similar job, but it puts too much restrictions on the code. In my case it didn't worked well.

@sonthonaxrk
Copy link
Owner

Mate thanks for this and sorry for the time taken to review. I’m going to take a proper look tomorrow.

I rarely if ever check my personal GitHub, I’m always logged into my work account.

Apologies for not looking sooner. Appreciate you put the effort in just as I needed this repo alive again.

@zohl
Copy link
Author

zohl commented Aug 18, 2025

Haha, no problem!
As you can see I'm not an active GitHub user too :)

FWIW, I update the forked repo on GitLab now, feel free to borrow patches and send yours (there were minor fixups for newer kernel versions, the rest is still the same).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants