Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu, macos]
version: ["3.10", "3.11", "3.12", "3.13"]
version: ["3.11", "3.12", "3.13"]
runs-on: ${{ matrix.os }}-latest
steps:
- uses: answerdotai/workflows/nbdev3-ci@master
Expand All @@ -20,7 +20,7 @@ jobs:
- name: test Python modules
run: pytest -q
- name: test docs build
if: ${{ (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') && matrix.version == '3.10' && matrix.os == 'ubuntu' }}
if: ${{ (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') && matrix.version == '3.11' && matrix.os == 'ubuntu' }}
run: |
set -ux
wget -q $(curl https://latest.fast.ai/pre/quarto-dev/quarto-cli/linux-amd64.deb)
Expand Down
3 changes: 1 addition & 2 deletions nbdev/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
from IPython.display import Markdown
from fastcore.nbio import read_nb,NbCell

try: import tomllib
except ImportError: import tomli as tomllib
import tomllib

# %% ../nbs/api/01_config.ipynb #117128e6
pyproject_nm = 'pyproject.toml'
Expand Down
6 changes: 2 additions & 4 deletions nbdev/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@
__all__ = ['proc_nbs']

# %% ../nbs/api/17_serve.ipynb #6899a335
import ast,subprocess,threading,sys
import ast
from shutil import rmtree,copy2
from fnmatch import fnmatch

from fastcore.utils import *
from fastcore.parallel import parallel
from fastcore.script import call_parse
from fastcore.meta import delegates

from .config import get_config
Expand Down Expand Up @@ -95,7 +94,6 @@ def proc_nbs(
_rm_stale(cache, path)

files = files.map(_proc_file, cache=cache, path=path).filter()
kw = {} if in_notebook() else {'method':'spawn'}
parallel(nbdev.serve_drv.main, files, n_workers=n_workers, pause=0.01, **kw)
parallel(nbdev.serve_drv.main, files, n_workers=n_workers, pause=0.01, max_tasks_per_child=1)
if cache.exists(): cache.touch()
return cache
6 changes: 2 additions & 4 deletions nbdev/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def nbdev_test(
cell_timing_min:float=None, # Print cells slower than this many seconds (default `cell_timing_min` config, else none)
**kwargs
):
"Test in parallel notebooks matching `path`, passing along `flags`"
"Test in parallel notebooks matching `path`, each in a process of its own, passing along `flags`"
if path and not Path(path).exists(): kwargs['path_glob'],path = os.path.abspath(path),Path.cwd()
cfg = get_config(Path(path).resolve() if path else None)
cell_timeout,cell_timing_min = ifnone(cell_timeout, cfg.cell_timeout),ifnone(cell_timing_min, cfg.get('cell_timing_min'))
Expand All @@ -168,16 +168,14 @@ def nbdev_test(
if len(files)==0: return print('No files were eligible for testing')

if n_workers is None: n_workers = 0 if len(files)==1 else min(num_cpus(), 8)
if in_notebook(): kw = {'method':'spawn'} if os.name=='nt' or sys.platform=='darwin' else {'method':'forkserver'}
else: kw = {'method':'spawn'} if sys.platform=='darwin' else {}
wd_pth = cfg.nbs_path
with working_directory(wd_pth if (wd_pth and wd_pth.exists()) else os.getcwd()):
setup = cfg.get('test_setup')
if setup: import_obj(setup)([c for f in files for c in nb_test_cells(f, skip_flags, force_flags)])
try:
results = parallel(test_nb, files, skip_flags=skip_flags, force_flags=force_flags, n_workers=n_workers,
basepath=cfg.config_path, pause=pause, do_print=do_print, verbose=verbose, save=save,
cell_timeout=cell_timeout or None, cell_timing_min=cell_timing_min, **kw)
cell_timeout=cell_timeout or None, cell_timing_min=cell_timing_min, max_tasks_per_child=1)
except KeyboardInterrupt:
sys.stderr.write('\nnbdev-test interrupted; in-flight notebook stacks shown above\n')
sys.exit(130)
Expand Down
10 changes: 6 additions & 4 deletions nbs/api/01_config.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@
"from IPython.display import Markdown\n",
"from fastcore.nbio import read_nb,NbCell\n",
"\n",
"try: import tomllib\n",
"except ImportError: import tomli as tomllib"
"import tomllib"
]
},
{
Expand Down Expand Up @@ -1287,10 +1286,13 @@
"solveit": {
"default_code": true,
"mode": "learning",
"reasoning_effort": "h",
"reasoning_model": "anthropic/claude-opus-5-5",
"standard_effort": "m",
"standard_model": "openai/gpt-6-luna",
"use_fence": false,
"use_thinking": false,
"use_tools": true,
"ver": 2
"use_tools": true
}
},
"nbformat": 4,
Expand Down
13 changes: 7 additions & 6 deletions nbs/api/12_test.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@
" cell_timing_min:float=None, # Print cells slower than this many seconds (default `cell_timing_min` config, else none)\n",
" **kwargs\n",
"):\n",
" \"Test in parallel notebooks matching `path`, passing along `flags`\"\n",
" \"Test in parallel notebooks matching `path`, each in a process of its own, passing along `flags`\"\n",
" if path and not Path(path).exists(): kwargs['path_glob'],path = os.path.abspath(path),Path.cwd()\n",
" cfg = get_config(Path(path).resolve() if path else None)\n",
" cell_timeout,cell_timing_min = ifnone(cell_timeout, cfg.cell_timeout),ifnone(cell_timing_min, cfg.get('cell_timing_min'))\n",
Expand All @@ -369,16 +369,14 @@
" if len(files)==0: return print('No files were eligible for testing')\n",
"\n",
" if n_workers is None: n_workers = 0 if len(files)==1 else min(num_cpus(), 8)\n",
" if in_notebook(): kw = {'method':'spawn'} if os.name=='nt' or sys.platform=='darwin' else {'method':'forkserver'}\n",
" else: kw = {'method':'spawn'} if sys.platform=='darwin' else {}\n",
" wd_pth = cfg.nbs_path\n",
" with working_directory(wd_pth if (wd_pth and wd_pth.exists()) else os.getcwd()):\n",
" setup = cfg.get('test_setup')\n",
" if setup: import_obj(setup)([c for f in files for c in nb_test_cells(f, skip_flags, force_flags)])\n",
" try:\n",
" results = parallel(test_nb, files, skip_flags=skip_flags, force_flags=force_flags, n_workers=n_workers,\n",
" basepath=cfg.config_path, pause=pause, do_print=do_print, verbose=verbose, save=save,\n",
" cell_timeout=cell_timeout or None, cell_timing_min=cell_timing_min, **kw)\n",
" cell_timeout=cell_timeout or None, cell_timing_min=cell_timing_min, max_tasks_per_child=1)\n",
" except KeyboardInterrupt:\n",
" sys.stderr.write('\\nnbdev-test interrupted; in-flight notebook stacks shown above\\n')\n",
" sys.exit(130)\n",
Expand Down Expand Up @@ -500,10 +498,13 @@
"solveit": {
"default_code": false,
"mode": "concise",
"reasoning_effort": "h",
"reasoning_model": "anthropic/claude-opus-5-5",
"standard_effort": "m",
"standard_model": "openai/gpt-6-luna",
"use_fence": false,
"use_thinking": true,
"use_tools": true,
"ver": 2
"use_tools": true
}
},
"nbformat": 4,
Expand Down
14 changes: 11 additions & 3 deletions nbs/api/16_migrate.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1380,8 +1380,7 @@
"outputs": [],
"source": [
"from configparser import ConfigParser\n",
"try: import tomllib\n",
"except ImportError: import tomli as tomllib"
"import tomllib"
]
},
{
Expand Down Expand Up @@ -1542,7 +1541,16 @@
]
}
],
"metadata": {},
"metadata": {
"solveit": {
"mode": "learning",
"reasoning_effort": "h",
"reasoning_model": "anthropic/claude-opus-5-5",
"standard_effort": "m",
"standard_model": "openai/gpt-6-luna",
"use_thinking": false
}
},
"nbformat": 4,
"nbformat_minor": 5
}
17 changes: 12 additions & 5 deletions nbs/api/17_serve.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@
"outputs": [],
"source": [
"#| export\n",
"import ast,subprocess,threading,sys\n",
"import ast\n",
"from shutil import rmtree,copy2\n",
"from fnmatch import fnmatch\n",
"\n",
"from fastcore.utils import *\n",
"from fastcore.parallel import parallel\n",
"from fastcore.script import call_parse\n",
"from fastcore.meta import delegates\n",
"\n",
"from nbdev.config import get_config\n",
Expand Down Expand Up @@ -223,8 +222,7 @@
" _rm_stale(cache, path)\n",
"\n",
" files = files.map(_proc_file, cache=cache, path=path).filter()\n",
" kw = {} if in_notebook() else {'method':'spawn'}\n",
" parallel(nbdev.serve_drv.main, files, n_workers=n_workers, pause=0.01, **kw)\n",
" parallel(nbdev.serve_drv.main, files, n_workers=n_workers, pause=0.01, max_tasks_per_child=1)\n",
" if cache.exists(): cache.touch()\n",
" return cache"
]
Expand Down Expand Up @@ -268,7 +266,16 @@
"source": []
}
],
"metadata": {},
"metadata": {
"solveit": {
"mode": "learning",
"reasoning_effort": "h",
"reasoning_model": "anthropic/claude-opus-5-5",
"standard_effort": "m",
"standard_model": "openai/gpt-6-luna",
"use_thinking": false
}
},
"nbformat": 4,
"nbformat_minor": 5
}
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
name = "nbdev"
description = "Create delightful software with Jupyter Notebooks"
readme = "README.md"
requires-python = ">=3.10"
requires-python = ">=3.11"
license = "Apache-2.0"
authors = [{name = "Jeremy Howard and the fast.ai community", email = "j@fast.ai"}]
keywords = ["nbdev", "fastai", "jupyter", "notebook", "export"]
Expand All @@ -18,8 +18,8 @@ classifiers = [
"Programming Language :: Python :: 3 :: Only",
]
dynamic = ["version"]
dependencies = [ "fastcore>=2.2.28", "execnb>=0.3.3", "astunparse", "ghapi>=2.0.2", "watchdog", "asttokens",
"setuptools", "build", "fastgit>=0.0.7", "pyyaml", "tomli; python_version < '3.11'", ]
dependencies = [ "fastcore>=2.2.39", "execnb>=0.3.3", "astunparse", "ghapi>=2.0.2", "watchdog", "asttokens",
"setuptools", "build", "fastgit>=0.0.7", "pyyaml", ]

[project.optional-dependencies]
dev = [ "ipywidgets", "nbdev-numpy", "nbdev-stdlib", "pandas", "matplotlib", "black", "svg.py", "pysym2md>=0.0.6", "llms-txt", "sphinx", "plum-dispatch", "nbclient", "ipykernel", "pytest", ]
Expand Down
9 changes: 9 additions & 0 deletions tests/test_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from fastcore.nbio import new_nb, write_nb, mk_cell

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Careful not to add tests like this. It's a whole new test file just to test a fact that python already makes true by definition. AI is more than happy to let complexity in test suites blow up. It thinks of that as a good thing, because RLHF feedback rewards adding more tests!

from nbdev.test import nbdev_test


def test_fresh_process_per_notebook(tmp_path):
"State one notebook leaves on an imported module never reaches the next, even on a single worker"
write_nb(new_nb([mk_cell('import json\njson.leak = 1')]), tmp_path/'a.ipynb')
write_nb(new_nb([mk_cell('import json\nassert not hasattr(json, "leak")')]), tmp_path/'b.ipynb')
nbdev_test(path=tmp_path, n_workers=1)
Loading