From 328956589283e4098318a2a1f7bb4373cef2b520 Mon Sep 17 00:00:00 2001 From: Rens Date: Thu, 16 Jul 2026 09:38:15 +0200 Subject: [PATCH] add reads_ipynb for reading dialogs from JSON strings --- llmsurgery/_modidx.py | 1 + llmsurgery/ipynb.py | 13 ++++++++++--- nbs/01_ipynb.ipynb | 44 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/llmsurgery/_modidx.py b/llmsurgery/_modidx.py index efd7eb2..f7270c5 100644 --- a/llmsurgery/_modidx.py +++ b/llmsurgery/_modidx.py @@ -195,6 +195,7 @@ 'llmsurgery.ipynb.get_ipynb': ('ipynb.html#get_ipynb', 'llmsurgery/ipynb.py'), 'llmsurgery.ipynb.ipynb_cells': ('ipynb.html#ipynb_cells', 'llmsurgery/ipynb.py'), 'llmsurgery.ipynb.read_ipynb': ('ipynb.html#read_ipynb', 'llmsurgery/ipynb.py'), + 'llmsurgery.ipynb.reads_ipynb': ('ipynb.html#reads_ipynb', 'llmsurgery/ipynb.py'), 'llmsurgery.ipynb.split_cell_src': ('ipynb.html#split_cell_src', 'llmsurgery/ipynb.py'), 'llmsurgery.ipynb.write_ipynb': ('ipynb.html#write_ipynb', 'llmsurgery/ipynb.py')}, 'llmsurgery.oai': { 'llmsurgery.oai.CodexAppServer': ('oai.html#codexappserver', 'llmsurgery/oai.py'), diff --git a/llmsurgery/ipynb.py b/llmsurgery/ipynb.py index 124e5ce..2f53f21 100644 --- a/llmsurgery/ipynb.py +++ b/llmsurgery/ipynb.py @@ -5,7 +5,8 @@ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/01_ipynb.ipynb. # %% auto #0 -__all__ = ['reply_sep', 'att2dict', 'split_cell_src', 'get_ipynb', 'write_ipynb', 'ipynb_cells', 'dict2att', 'read_ipynb'] +__all__ = ['reply_sep', 'att2dict', 'split_cell_src', 'get_ipynb', 'write_ipynb', 'ipynb_cells', 'dict2att', 'reads_ipynb', + 'read_ipynb'] # %% ../nbs/01_ipynb.ipynb #d3d0463b from fastcore.utils import * @@ -130,14 +131,20 @@ def from_cells(self:Dialog, cells): self.messages = Msgs(cells).map(self.cell2msg) return self +# %% ../nbs/01_ipynb.ipynb #6bdaa293 +def reads_ipynb(txt, cls=Dialog, name='dialog'): + "Read a dialog from notebook JSON string `txt`, constructing via `cls`" + nb = nbformat.reads(txt, as_version=nbformat.NO_CONVERT) + return cls(name, meta=dict(nb.get('metadata', {}))).from_cells(nb.cells) + +# %% ../nbs/01_ipynb.ipynb #7e8912e8 def read_ipynb(fname, cls=Dialog, name=None): "Read a dialog from notebook file `fname` (`.ipynb` added if missing), constructing via `cls`; `name` defaults to the file stem" f = Path(fname).expanduser() if f.suffix != '.ipynb': f = f.with_suffix('.ipynb') if not f.exists(): return print(f,'does not exist') - try: nb = nbformat.read(f, as_version=nbformat.NO_CONVERT) + try: res = reads_ipynb(f.read_text(encoding='utf-8'), cls, name or f.stem) except (NotJSONError, nbformat.ValidationError, PermissionError): return - res = cls(name or f.stem, meta=dict(nb.get('metadata', {}))).from_cells(nb.cells) res.path_ = f return res diff --git a/nbs/01_ipynb.ipynb b/nbs/01_ipynb.ipynb index 981d108..e75b3e8 100644 --- a/nbs/01_ipynb.ipynb +++ b/nbs/01_ipynb.ipynb @@ -524,16 +524,38 @@ "@patch\n", "def from_cells(self:Dialog, cells):\n", " self.messages = Msgs(cells).map(self.cell2msg)\n", - " return self\n", - "\n", + " return self" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6bdaa293", + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "def reads_ipynb(txt, cls=Dialog, name='dialog'):\n", + " \"Read a dialog from notebook JSON string `txt`, constructing via `cls`\"\n", + " nb = nbformat.reads(txt, as_version=nbformat.NO_CONVERT)\n", + " return cls(name, meta=dict(nb.get('metadata', {}))).from_cells(nb.cells)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e8912e8", + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", "def read_ipynb(fname, cls=Dialog, name=None):\n", " \"Read a dialog from notebook file `fname` (`.ipynb` added if missing), constructing via `cls`; `name` defaults to the file stem\"\n", " f = Path(fname).expanduser()\n", " if f.suffix != '.ipynb': f = f.with_suffix('.ipynb')\n", " if not f.exists(): return print(f,'does not exist')\n", - " try: nb = nbformat.read(f, as_version=nbformat.NO_CONVERT)\n", + " try: res = reads_ipynb(f.read_text(encoding='utf-8'), cls, name or f.stem)\n", " except (NotJSONError, nbformat.ValidationError, PermissionError): return\n", - " res = cls(name or f.stem, meta=dict(nb.get('metadata', {}))).from_cells(nb.cells)\n", " res.path_ = f\n", " return res" ] @@ -585,6 +607,20 @@ "dlg" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "5dfd922f", + "metadata": {}, + "outputs": [], + "source": [ + "s = (tstdir/'dlg.ipynb').read_text()\n", + "dlg2 = reads_ipynb(s)\n", + "test_eq(dlg2.name, 'dialog')\n", + "test_eq(write_ipynb(dlg2), s)\n", + "with expect_fail(NotJSONError): reads_ipynb('not json')" + ] + }, { "cell_type": "code", "execution_count": null,