nbclient icon indicating copy to clipboard operation
nbclient copied to clipboard

Asserts fail with no message

Open cab938 opened this issue 10 months ago • 6 comments

I was trying to programmatically interact with the nbclient package and kept getting blank assertion errors being thrown. It was a bit of a mess on my end to track down since nbclient was being hidden behind numerous other libraries I was working with, here's one of the ones which would regularly throw, indicating that there is no kernel available:

https://github.com/jupyter/nbclient/blob/2650b217c4c9965110ceb4de193092d7eb36c2bb/nbclient/client.py#L960

Any reason to use asserts here instead of something more friendly to calling libraries, e.g. a new KernelNotConfiguredException?

cab938 avatar Feb 20 '25 16:02 cab938

It seems that this was used for static type checking, meaning that it should never happen at runtime either. Could you share how you use nbclient?

davidbrochart avatar Feb 20 '25 16:02 davidbrochart

Yes, I'm building a wrapper for nbclient to make available some of the notebook functions to an LLM agent. More specifically, I'm making a few high level functions like execute_cell() available as tools to langchain agents so that one can ask an LLM with tool support to do things like load, change, execute, and evaluate notebooks.

Here's a bit of pseudocode showing what the workflow looks like:

notebook = nbformat.reads(notebook_content, as_version=4)
client = NotebookClient(notebook)

index=0
for cell in notebook.cells:
    if cell.id == id:
        result = client.execute_cell(cell, index)
   else:
        index += 1

cab938 avatar Feb 20 '25 19:02 cab938

That code likely won't run nicely fwiw, it's sort of ripped out of the stuff I'm building now, and it's possible that code does actually run and initialization of a NotebookClient without a kernel or kernel manager isn't an issue normally and my langchain code is getting in the way.

cab938 avatar Feb 20 '25 19:02 cab938

Here is a better MWE:

from nbclient import NotebookClient
import nbformat

notebook = nbformat.reads(open('test.ipynb','r').read(), as_version=4)
client = NotebookClient(notebook, kernel_name="python3")

for index, cell in enumerate(notebook.cells):
    result = client.execute_cell(cell, index)

Which gives unexpected error:

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Cell In[14], [line 8](vscode-notebook-cell:?execution_count=14&line=8)
      [5](vscode-notebook-cell:?execution_count=14&line=5) client = NotebookClient(notebook, kernel_name="python3")
      [7](vscode-notebook-cell:?execution_count=14&line=7) for index, cell in enumerate(notebook.cells):
----> [8](vscode-notebook-cell:?execution_count=14&line=8)     result = client.execute_cell(cell, index)

File ~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:159, in run_sync.<locals>.wrapped(*args, **kwargs)
    [157](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:157)     if name not in _runner_map:
    [158](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:158)         _runner_map[name] = _TaskRunner()
--> [159](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:159)     return _runner_map[name].run(inner)
    [160](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:160) except RuntimeError:
    [161](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:161)     pass

File ~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:126, in _TaskRunner.run(self, coro)
    [124](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:124)         self.__runner_thread.start()
    [125](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:125) fut = asyncio.run_coroutine_threadsafe(coro, self.__io_loop)
--> [126](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/jupyter_core/utils/__init__.py:126) return fut.result(None)

File /usr/lib/python3.12/concurrent/futures/_base.py:456, in Future.result(self, timeout)
    [454](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:454)     raise CancelledError()
    [455](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:455) elif self._state == FINISHED:
--> [456](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:456)     return self.__get_result()
    [457](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:457) else:
    [458](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:458)     raise TimeoutError()

File /usr/lib/python3.12/concurrent/futures/_base.py:401, in Future.__get_result(self)
    [399](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:399) if self._exception:
    [400](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:400)     try:
--> [401](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:401)         raise self._exception
    [402](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:402)     finally:
    [403](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:403)         # Break a reference cycle with the exception in self._exception
    [404](https://file+.vscode-resource.vscode-cdn.net/usr/lib/python3.12/concurrent/futures/_base.py:404)         self = None

File ~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:960, in NotebookClient.async_execute_cell(self, cell, cell_index, execution_count, store_history)
    [920](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:920) async def async_execute_cell(
    [921](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:921)     self,
    [922](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:922)     cell: NotebookNode,
   (...)
    [925](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:925)     store_history: bool = True,
    [926](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:926) ) -> NotebookNode:
    [927](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:927)     """
    [928](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:928)     Executes a single code cell.
    [929](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:929) 
   (...)
    [958](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:958)         The cell which was just processed.
    [959](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:959)     """
--> [960](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:960)     assert self.kc is not None
    [962](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:962)     await run_hook(self.on_cell_start, cell=cell, cell_index=cell_index)
    [964](https://file+.vscode-resource.vscode-cdn.net/home/brooksch/sandboxes/jupyter_tool/~/sandboxes/jupyter_tool/.venv/lib/python3.12/site-packages/nbclient/client.py:964)     if cell.cell_type != "code" or not cell.source.strip():

AssertionError:

cab938 avatar Feb 20 '25 19:02 cab938

Odd to me is that I can actually execute the whole notebook it appears, so maybe I am misusing the cell execution api? This code seems to work (and at the least does not throw the assertion error):

from nbclient import NotebookClient
import nbformat

notebook = nbformat.reads(open('test.ipynb','r').read(), as_version=4)
client = NotebookClient(notebook, kernel_name="python3")
client.execute()

cab938 avatar Feb 20 '25 19:02 cab938

Just an update for those who might be running into a similar problem or are trying to use the nbclient package in a similar way, this is how I create and init a new NotebookClient such that I can execute individual cells.

from nbclient import NotebookClient
import nbformat

notebook = nbformat.reads(open('test.ipynb','r').read(), as_version=4)
client = NotebookClient(notebook, kernel_name="python3")
client.km = client.create_kernel_manager()
client.start_new_kernel()
client.kc=client.start_new_kernel_client()

for index, cell in enumerate(notebook.cells):
    print(f"Executing cell {index}")
    result = client.execute_cell(cell, index)

cab938 avatar Feb 21 '25 17:02 cab938