diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 88e39d364..cec7384a0 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -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 @@ -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) diff --git a/nbdev/config.py b/nbdev/config.py index dcce9eb9a..c42278e2e 100644 --- a/nbdev/config.py +++ b/nbdev/config.py @@ -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' diff --git a/nbdev/serve.py b/nbdev/serve.py index 91626b29c..bc5b6217a 100644 --- a/nbdev/serve.py +++ b/nbdev/serve.py @@ -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 @@ -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 diff --git a/nbdev/test.py b/nbdev/test.py index 490020dec..f276c577e 100644 --- a/nbdev/test.py +++ b/nbdev/test.py @@ -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')) @@ -168,8 +168,6 @@ 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') @@ -177,7 +175,7 @@ def nbdev_test( 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) diff --git a/nbs/api/01_config.ipynb b/nbs/api/01_config.ipynb index 4b4e3ed62..878197e9f 100644 --- a/nbs/api/01_config.ipynb +++ b/nbs/api/01_config.ipynb @@ -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" ] }, { @@ -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, diff --git a/nbs/api/12_test.ipynb b/nbs/api/12_test.ipynb index 951ef4927..8ce38d1f2 100644 --- a/nbs/api/12_test.ipynb +++ b/nbs/api/12_test.ipynb @@ -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", @@ -369,8 +369,6 @@ " 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", @@ -378,7 +376,7 @@ " 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", @@ -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, diff --git a/nbs/api/16_migrate.ipynb b/nbs/api/16_migrate.ipynb index 51827d18c..2ab25a953 100644 --- a/nbs/api/16_migrate.ipynb +++ b/nbs/api/16_migrate.ipynb @@ -1380,8 +1380,7 @@ "outputs": [], "source": [ "from configparser import ConfigParser\n", - "try: import tomllib\n", - "except ImportError: import tomli as tomllib" + "import tomllib" ] }, { @@ -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 } diff --git a/nbs/api/17_serve.ipynb b/nbs/api/17_serve.ipynb index 089cc79e7..9b4c1e991 100644 --- a/nbs/api/17_serve.ipynb +++ b/nbs/api/17_serve.ipynb @@ -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", @@ -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" ] @@ -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 } diff --git a/pyproject.toml b/pyproject.toml index 3c4968e7f..0c06eaa2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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"] @@ -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", ] diff --git a/tests/test_test.py b/tests/test_test.py new file mode 100644 index 000000000..2c8f22a78 --- /dev/null +++ b/tests/test_test.py @@ -0,0 +1,9 @@ +from fastcore.nbio import new_nb, write_nb, mk_cell +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)