Skip to content

fix: support PyPI jupyter-kernel-client>=1.0 (JupyterKernelClient rename) - #125

Open
theaathish wants to merge 2 commits into
googlecolab:mainfrom
theaathish:fix-jupyter-kernel-client-1x-compat
Open

theaathish wants to merge 2 commits into
googlecolab:mainfrom
theaathish:fix-jupyter-kernel-client-1x-compat

Conversation

@theaathish

Copy link
Copy Markdown

Problem

Installing from PyPI (uv tool install google-colab-cli / pip install google-colab-cli) resolves the unpinned jupyter-kernel-client dependency to 1.0.2, where KernelClient was renamed to JupyterKernelClient.

colab exec then fails on any session (auth + colab status/colab ls still work):

AttributeError: module 'jupyter_kernel_client' has no attribute 'KernelClient'

Full traceback originates at src/colab_cli/runtime.py in ColabRuntime.kernel_client (jupyter_kernel_client.KernelClient(...)).

Repro (CLI 0.6.0 + PyPI jupyter-kernel-client 1.0.2):

colab status   # OK - shows session, IDLE
colab ls       # OK
echo "print('hi')" | colab exec   # AttributeError above

Fix

Resolve the client class across all known variants in ColabRuntime.kernel_client:

  • ColabKernelClient(proxy_token=...) (git fork version)
  • KernelClient(token=...) (PyPI <1.0)
  • JupyterKernelClient(token=...) (PyPI >=1.0, fallback)

The JupyterKernelClient constructor is compatible (passes through to KernelHttpManager via **kwargs: server_url, token, kernel_id, client_kwargs, headers), verified live with colab exec after patching.

Tests

  • Updated test_colab_runtime_kernel_client to handle all three variants.
  • Added test_colab_runtime_kernel_client_jupyterclient_fallback simulating PyPI>=1.0 (only JupyterKernelClient present).
  • uv run pytest tests/test_runtime.py -v: 9 passed.
  • uv run ruff check + ruff format --check: clean.
  • Live: echo "print('connection_test_ok')" | colab execconnection_test_ok.

…ame)

PyPI jupyter-kernel-client 1.x renamed KernelClient -> JupyterKernelClient.
uv/pip installs of google-colab-cli resolve the unpinned dependency to
1.0.2, so colab exec fails with:

  AttributeError: module 'jupyter_kernel_client' has no attribute 'KernelClient'

Resolve the client class as ColabKernelClient -> KernelClient ->
JupyterKernelClient, keeping proxy_token vs token params correct.
@google-cla

google-cla Bot commented Sep 6, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@crichalchemist

Copy link
Copy Markdown

Verified this patch independently. Took runtime.py from this PR's head (23d14db) and constructed ColabRuntime.kernel_client against each release in its own venv:

jupyter-kernel-client resolves to token kwarg
0.9.0 KernelClient token
0.11.0 ColabKernelClient proxy_token
1.0.0 ColabKernelClient proxy_token
1.0.1 JupyterKernelClient token
1.0.2 JupyterKernelClient token
googlecolab fork @ f18e982 (the uv.lock pin) KernelClient token

Current main (465b941) fails on 1.0.1 and 1.0.2 only; the rest of that column is unchanged by this PR.

Three notes for review:

1. Comparison with #99. That PR changes the same else branch to JupyterKernelClient rather than adding a third branch. With that one-line change applied I measured:

AttributeError: module 'jupyter_kernel_client' has no attribute 'JupyterKernelClient'

on 0.9.0 and on the googlecolab fork at the uv.lock pin. The three-branch form in this PR does not have that effect, since it only reaches JupyterKernelClient when neither other name is present.

2. This PR leaves the dependency unbounded. pyproject.toml line 31 is still "jupyter-kernel-client" at 23d14db. Because [tool.uv.sources] is uv-only and is not carried in wheel METADATA, released installs keep resolving unbounded even with this change merged, so the runtime fallback and a version bound address different halves of the problem.

>=0.9 matches what this patch supports. 0.8.0 fails earlier than the class lookup — runtime.py:99 reads jupyter_kernel_client.JupyterSubprotocol, which PyPI 0.8.0 does not export — so a >=0.9 floor is also the relevant data point for #121, which proposes ==0.8.

3. _own_kernel still behaves as the comment assumes. runtime.py sets _own_kernel = False after construction to stop the client deleting the kernel on close. In both 0.15.0 and 1.0.2 that attribute is assigned in client.py __init__ (not in start()) and read in stop(), at identical line numbers, so the post-construction override still applies under 1.x and the kernel is not torn down.

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