Skip to content

Commit 65dace6

Browse files
committed
fixes #1626
1 parent 9d4a6d6 commit 65dace6

6 files changed

Lines changed: 42 additions & 15 deletions

File tree

‎nbdev/_modidx.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,5 +385,6 @@
385385
'nbdev.sync.absolute_import': ('api/sync.html#absolute_import', 'nbdev/sync.py'),
386386
'nbdev.sync.nbdev_update': ('api/sync.html#nbdev_update', 'nbdev/sync.py')},
387387
'nbdev.test': { 'nbdev.test._keep_file': ('api/test.html#_keep_file', 'nbdev/test.py'),
388+
'nbdev.test._test_nb_sync': ('api/test.html#_test_nb_sync', 'nbdev/test.py'),
388389
'nbdev.test.nbdev_test': ('api/test.html#nbdev_test', 'nbdev/test.py'),
389390
'nbdev.test.test_nb': ('api/test.html#test_nb', 'nbdev/test.py')}}}

‎nbdev/processors.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
# %% ../nbs/api/10_processors.ipynb #2398f5ef-06d3-4890-8a54-7cf4f81f3894
1313
import ast
1414

15+
from fastcore.aio import run_sync
16+
1517
from .config import *
1618
from .imports import *
1719
from .process import *
@@ -255,7 +257,7 @@ def __call__(self, cell):
255257
if not self.nb.has_docs_ or not hasattr(self, 'k'): return
256258
fm = getattr(self.nb, 'frontmatter_', {})
257259
if str2bool(fm.get('skip_showdoc', False)): return
258-
if _do_eval(cell): self.k.cell(cell)
260+
if _do_eval(cell): run_sync(self.k.cell(cell))
259261
title = fm.get('title', '')
260262
if self.k.exc:
261263
raise Exception(f"Error{' in notebook: '+title if title else ''} in cell {cell.idx_} :\n{cell.source}") from self.k.exc

‎nbdev/test.py‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
__all__ = ['test_nb', 'nbdev_test']
99

1010
# %% ../nbs/api/12_test.ipynb #45e10c3f
11-
import time,os,sys,traceback,contextlib,inspect,faulthandler,signal
11+
import time,os,sys,traceback,contextlib,inspect,faulthandler,signal,asyncio
1212
from fastcore.basics import *
1313
from fastcore.imports import *
1414
from fastcore.foundation import *
@@ -25,7 +25,7 @@
2525
from execnb.shell import *
2626

2727
# %% ../nbs/api/12_test.ipynb #3f4fa1ad
28-
def test_nb(
28+
async def test_nb(
2929
fn, # file name of notebook to test
3030
skip_flags=None, # list of flags marking cells to skip
3131
force_flags=None, # list of flags marking cells to always run
@@ -61,7 +61,7 @@ def _no_eval(cell):
6161
if do_print: print(f'Starting {fn}')
6262
try:
6363
with working_directory(fn.parent):
64-
k.run_all(nb, exc_stop=True, preproc=_no_eval, verbose=verbose)
64+
await k.run_all(nb, exc_stop=True, preproc=_no_eval, verbose=verbose)
6565
if save: write_nb(nb, fn)
6666
res = True
6767
except:
@@ -74,6 +74,9 @@ def _no_eval(cell):
7474
else: os.environ['IN_TEST'] = prev_test
7575

7676

77+
# %% ../nbs/api/12_test.ipynb #12516e0a
78+
def _test_nb_sync(fn, **kwargs): return asyncio.run(test_nb(fn, **kwargs))
79+
7780
# %% ../nbs/api/12_test.ipynb #d8bf1f1b-935d-4b69-ba96-827c5d7213f0
7881
def _keep_file(
7982
p:Path, # filename for which to check for `indicator_fname`
@@ -112,7 +115,7 @@ def nbdev_test(
112115
else: kw = {'method':'spawn'} if sys.platform=='darwin' else {}
113116
wd_pth = cfg.nbs_path
114117
with working_directory(wd_pth if (wd_pth and wd_pth.exists()) else os.getcwd()):
115-
results = parallel(test_nb, files, skip_flags=skip_flags, force_flags=force_flags, n_workers=n_workers,
118+
results = parallel(_test_nb_sync, files, skip_flags=skip_flags, force_flags=force_flags, n_workers=n_workers,
116119
basepath=cfg.config_path, pause=pause, do_print=do_print, verbose=verbose, save=save, **kw)
117120
passed,times = zip(*results)
118121
if all(passed): print("Success.")

‎nbs/api/10_processors.ipynb‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
"#| export\n",
3131
"import ast\n",
3232
"\n",
33+
"from fastcore.aio import run_sync\n",
34+
"\n",
3335
"from nbdev.config import *\n",
3436
"from nbdev.imports import *\n",
3537
"from nbdev.process import *\n",
@@ -763,7 +765,7 @@
763765
" if not self.nb.has_docs_ or not hasattr(self, 'k'): return\n",
764766
" fm = getattr(self.nb, 'frontmatter_', {})\n",
765767
" if str2bool(fm.get('skip_showdoc', False)): return\n",
766-
" if _do_eval(cell): self.k.cell(cell)\n",
768+
" if _do_eval(cell): run_sync(self.k.cell(cell))\n",
767769
" title = fm.get('title', '')\n",
768770
" if self.k.exc: \n",
769771
" raise Exception(f\"Error{' in notebook: '+title if title else ''} in cell {cell.idx_} :\\n{cell.source}\") from self.k.exc\n",

‎nbs/api/12_test.ipynb‎

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"outputs": [],
2929
"source": [
3030
"#| export\n",
31-
"import time,os,sys,traceback,contextlib,inspect,faulthandler,signal\n",
31+
"import time,os,sys,traceback,contextlib,inspect,faulthandler,signal,asyncio\n",
3232
"from fastcore.basics import *\n",
3333
"from fastcore.imports import *\n",
3434
"from fastcore.foundation import *\n",
@@ -53,7 +53,7 @@
5353
"outputs": [],
5454
"source": [
5555
"#| export\n",
56-
"def test_nb(\n",
56+
"async def test_nb(\n",
5757
" fn, # file name of notebook to test\n",
5858
" skip_flags=None, # list of flags marking cells to skip\n",
5959
" force_flags=None, # list of flags marking cells to always run\n",
@@ -89,7 +89,7 @@
8989
" if do_print: print(f'Starting {fn}')\n",
9090
" try:\n",
9191
" with working_directory(fn.parent):\n",
92-
" k.run_all(nb, exc_stop=True, preproc=_no_eval, verbose=verbose)\n",
92+
" await k.run_all(nb, exc_stop=True, preproc=_no_eval, verbose=verbose)\n",
9393
" if save: write_nb(nb, fn)\n",
9494
" res = True\n",
9595
" except: \n",
@@ -102,6 +102,25 @@
102102
" else: os.environ['IN_TEST'] = prev_test\n"
103103
]
104104
},
105+
{
106+
"cell_type": "markdown",
107+
"id": "d7a14cc3",
108+
"metadata": {},
109+
"source": [
110+
"`test_nb` is async. `parallel` workers are fresh loopless processes, so each enters through `asyncio.run` at its process boundary, which keeps cells on the worker's main thread (where SIGALRM timeouts can arm). `run_sync` is reserved for sync callers already inside a running loop, like `exec_show_docs` under the sync processor pipeline.\n"
111+
]
112+
},
113+
{
114+
"cell_type": "code",
115+
"execution_count": null,
116+
"id": "12516e0a",
117+
"metadata": {},
118+
"outputs": [],
119+
"source": [
120+
"#| export\n",
121+
"def _test_nb_sync(fn, **kwargs): return asyncio.run(test_nb(fn, **kwargs))"
122+
]
123+
},
105124
{
106125
"cell_type": "markdown",
107126
"id": "9dc26b80-6e4e-4a16-bcde-dd4d156289e5",
@@ -118,7 +137,7 @@
118137
"outputs": [],
119138
"source": [
120139
"_nb = Path('../../tests/directives.ipynb')\n",
121-
"success,duration = test_nb(_nb, skip_flags=['notest'])\n",
140+
"success,duration = await test_nb(_nb, skip_flags=['notest'])\n",
122141
"assert success"
123142
]
124143
},
@@ -138,7 +157,7 @@
138157
"outputs": [],
139158
"source": [
140159
"_nb = Path('../../tests/directives.ipynb')\n",
141-
"success,duration = test_nb(_nb, showerr=False)\n",
160+
"success,duration = await test_nb(_nb, showerr=False)\n",
142161
"assert not success"
143162
]
144163
},
@@ -175,8 +194,8 @@
175194
" nbp = td/'prof.ipynb'\n",
176195
" write_nb(new_nb([mk_cell('assert prof_x==7')]), nbp)\n",
177196
" with modified_env(IPYTHONDIR=str(td)):\n",
178-
" assert test_nb(nbp, showerr=False)[0]\n",
179-
" assert not test_nb(nbp, showerr=False, profile=False)[0]"
197+
" assert (await test_nb(nbp, showerr=False))[0]\n",
198+
" assert not (await test_nb(nbp, showerr=False, profile=False))[0]"
180199
]
181200
},
182201
{
@@ -240,7 +259,7 @@
240259
" else: kw = {'method':'spawn'} if sys.platform=='darwin' else {}\n",
241260
" wd_pth = cfg.nbs_path\n",
242261
" with working_directory(wd_pth if (wd_pth and wd_pth.exists()) else os.getcwd()):\n",
243-
" results = parallel(test_nb, files, skip_flags=skip_flags, force_flags=force_flags, n_workers=n_workers,\n",
262+
" results = parallel(_test_nb_sync, files, skip_flags=skip_flags, force_flags=force_flags, n_workers=n_workers,\n",
244263
" basepath=cfg.config_path, pause=pause, do_print=do_print, verbose=verbose, save=save, **kw)\n",
245264
" passed,times = zip(*results)\n",
246265
" if all(passed): print(\"Success.\")\n",

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ classifiers = [
1919
"License :: OSI Approved :: Apache Software License",
2020
]
2121
dynamic = ["version"]
22-
dependencies = [ "fastcore>=2.2.3", "execnb>=0.2.8", "astunparse", "ghapi>=2.0.2", "watchdog", "asttokens",
22+
dependencies = [ "fastcore>=2.2.3", "execnb>=0.2.11", "astunparse", "ghapi>=2.0.2", "watchdog", "asttokens",
2323
"setuptools", "build", "fastgit>=0.0.7", "pyyaml", "tomli; python_version < '3.11'", ]
2424

2525
[project.optional-dependencies]

0 commit comments

Comments
 (0)