Skip to content

Support Jupyter Notebook 7 and enable JupyterLab debugger#81

Open
yufengzjj wants to merge 3 commits into
eset:masterfrom
yufengzjj:master
Open

Support Jupyter Notebook 7 and enable JupyterLab debugger#81
yufengzjj wants to merge 3 commits into
eset:masterfrom
yufengzjj:master

Conversation

@yufengzjj
Copy link
Copy Markdown

@yufengzjj yufengzjj commented May 16, 2026

Summary

  • Extend %open_notebook to work on Notebook 7 (served by jupyter_server)
    in addition to the existing Notebook 6 path.
  • Enable the JupyterLab/Notebook 7 Debug toolbar button so cells inside
    IDA's kernel can be debugged from the browser.
  • Stop launching the notebook via the jupyter-notebook console script so
    stale scripts left behind by pip downgrades between 6 and 7 don't break
    startup.

Notebook 7 compatibility (ipyida/notebook.py)

  • _list_running_servers() reads from jupyter_server.serverapp on
    Notebook >= 7 (the notebook.notebookapp module was removed) and from
    notebook.notebookapp on 6.x.
  • _server_root_dir() normalises the root-dir field across servers
    (root_dir on jupyter_server, notebook_dir on Notebook 6).
  • _create_proxy_session() posts a session to /api/sessions bound to the
    proxy kernel before opening the page. The JupyterLab-based UI in
    Notebook 7 does not honour the legacy ?kernel_name= query string the
    way Notebook 6 did, so the kernel is now attached server-side. Harmless
    on Notebook 6 (the existing session is reused).
  • _popen_python_module("notebook", ...) replaces
    _popen_python_module("jupyter", "notebook", ...). This bypasses
    jupyter_core's dispatch to the jupyter-notebook script on PATH —
    pip downgrades between Notebook 7 and 6 can leave that script pointing
    at the wrong module (e.g. 7's notebook.app after a downgrade to 6),
    triggering ModuleNotFoundError: No module named 'notebook.app'.
    notebook/__main__.py exists in both 6 and 7 and routes to the right
    entry point.
  • _popen_python_module() is factored to use a shared _python_executable()
    helper that derives the real Python interpreter from sys.prefix
    (sys.executable in IDA is ida{q,t}.exe, not Python).

Debugger support

JupyterLab decides whether to show the Debug button purely from
kernel_info_reply.debugger / kernelspec metadata, not from a
debug_request probe. Three changes are needed to make it light up and
actually work behind jupyter_kernel_proxy:

  1. Kernelspec metadata (ensure_kernelspec_installed): patch
    metadata.debugger = true into the proxy kernelspec. The proxy ships
    without it, so the button stays greyed out.
  2. Proxy wrapper (ipyida/proxy_runner.py, new):
    jupyter_kernel_proxy.KernelProxyManager._send_proxy_kernel_info is a
    3s fallback that synthesises a minimal kernel_info_reply lacking the
    debugger field. When a real kernel is already connected we suppress
    the fallback so the front-end always sees the real reply. The proxy
    kernelspec argv is rewritten to launch via python -m ipyida.proxy_runner so the patch is applied.
  3. debugpy.configure(python=...) (ipyida/kernel.py,
    _configure_debugpy_python): clicking Debug runs
    debugpy.listen(...) inside the kernel, which spawns the DAP adapter
    via subprocess.Popen([sys.executable, adapter_dir, ...]). In IDA
    sys.executable == idaq.exe, so the spawn launches another IDA
    instance instead of the adapter and endpoints_listener.accept()
    times out after 30s with RuntimeError: timed out waiting for adapter to connect. Configuring debugpy._config["python"] to the real
    interpreter at kernel start fixes this.

Packaging (setup.py)

  • New notebook7 extra: notebook>=7, jupyter-server>=2,
    jupyter-client>=7.4.4, jupyter-kernel-proxy.
  • Existing notebook extra now pins notebook<7, jupyter-server<2,
    jupyter-client<7 so the 6.x stack installs cleanly.
  • Top-level jupyter-client constraint relaxed from <6.1.13 to
    !=6.1.13 — only the broken release needs to be excluded.

Test

Tested on Python 3.12. IDA 9.0+ win11

  • On a fresh env with pip install .[notebook7], run %open_notebook
    in IDA — browser opens, the cell uses IDA's kernel, and the Debug
    toolbar button is enabled.
  • Click Debug, set a breakpoint in a cell, run — control hits the
    breakpoint within ~1s (no 30s timeout, no
    timed out waiting for adapter to connect).
  • On a fresh env with pip install .[notebook] and notebook==6.5.7,
    run %open_notebook — the page loads against IDA's kernel as before
    (regression check for the 6.x path, including the python -m notebook
    change).
  • Downgrade notebook from 7 to 6.5.7 in the same env (stale
    jupyter-notebook script scenario) and run %open_notebook — no
    longer fails with ModuleNotFoundError: No module named 'notebook.app'.

yufengzjj added 3 commits May 16, 2026 16:00
fix a bug when jupyter_core's dispatch to the jupyter-notebook script
fix IDA unexpected exit when shutdown in notebook
@marc-etienne
Copy link
Copy Markdown
Collaborator

Hi!

Thanks so much your contribution! I just wanted to let you know I've seen your patch and I'll be reviewing within the next two weeks. I quickly glanced at it and it looks good to me, but I'll check in more details as soon as I can.

Cheers!

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