From f90a71dc916270c3a7af7fe7fda3a13a671ffdf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Clavi=C3=A9?= Date: Mon, 24 Feb 2025 11:55:41 +0900 Subject: [PATCH 1/3] feat: auto-generate contribute.md from nbs, re-add original contrib --- nbdev/_modidx.py | 4 ++- nbdev/cli.py | 3 +- nbdev/quarto.py | 61 +++++++++++++++++++++++++++++++-- nbs/api/13_cli.ipynb | 5 +-- nbs/api/14_quarto.ipynb | 75 +++++++++++++++++++++++++++++++++++++++-- settings.ini | 1 + 6 files changed, 139 insertions(+), 10 deletions(-) diff --git a/nbdev/_modidx.py b/nbdev/_modidx.py index d00d0ee8d..01a28cd49 100644 --- a/nbdev/_modidx.py +++ b/nbdev/_modidx.py @@ -257,20 +257,22 @@ 'nbdev.quarto._SidebarYmlRemoved.__init__': ( 'api/quarto.html#_sidebarymlremoved.__init__', 'nbdev/quarto.py'), 'nbdev.quarto._copytree': ('api/quarto.html#_copytree', 'nbdev/quarto.py'), + 'nbdev.quarto._doc_mtime_not_older': ('api/quarto.html#_doc_mtime_not_older', 'nbdev/quarto.py'), 'nbdev.quarto._ensure_quarto': ('api/quarto.html#_ensure_quarto', 'nbdev/quarto.py'), 'nbdev.quarto._install_linux': ('api/quarto.html#_install_linux', 'nbdev/quarto.py'), 'nbdev.quarto._install_mac': ('api/quarto.html#_install_mac', 'nbdev/quarto.py'), 'nbdev.quarto._nbglob_docs': ('api/quarto.html#_nbglob_docs', 'nbdev/quarto.py'), 'nbdev.quarto._pre': ('api/quarto.html#_pre', 'nbdev/quarto.py'), 'nbdev.quarto._pre_docs': ('api/quarto.html#_pre_docs', 'nbdev/quarto.py'), - 'nbdev.quarto._readme_mtime_not_older': ('api/quarto.html#_readme_mtime_not_older', 'nbdev/quarto.py'), 'nbdev.quarto._recursive_parser': ('api/quarto.html#_recursive_parser', 'nbdev/quarto.py'), + 'nbdev.quarto._save_cached_contributing': ('api/quarto.html#_save_cached_contributing', 'nbdev/quarto.py'), 'nbdev.quarto._save_cached_readme': ('api/quarto.html#_save_cached_readme', 'nbdev/quarto.py'), 'nbdev.quarto._sort': ('api/quarto.html#_sort', 'nbdev/quarto.py'), 'nbdev.quarto._sprun': ('api/quarto.html#_sprun', 'nbdev/quarto.py'), 'nbdev.quarto.fs_watchdog': ('api/quarto.html#fs_watchdog', 'nbdev/quarto.py'), 'nbdev.quarto.install': ('api/quarto.html#install', 'nbdev/quarto.py'), 'nbdev.quarto.install_quarto': ('api/quarto.html#install_quarto', 'nbdev/quarto.py'), + 'nbdev.quarto.nbdev_contributing': ('api/quarto.html#nbdev_contributing', 'nbdev/quarto.py'), 'nbdev.quarto.nbdev_docs': ('api/quarto.html#nbdev_docs', 'nbdev/quarto.py'), 'nbdev.quarto.nbdev_preview': ('api/quarto.html#nbdev_preview', 'nbdev/quarto.py'), 'nbdev.quarto.nbdev_proc_nbs': ('api/quarto.html#nbdev_proc_nbs', 'nbdev/quarto.py'), diff --git a/nbdev/cli.py b/nbdev/cli.py index c306677cb..ff6754cca 100644 --- a/nbdev/cli.py +++ b/nbdev/cli.py @@ -13,7 +13,7 @@ from .doclinks import * from .test import * from .clean import * -from .quarto import nbdev_readme, refresh_quarto_yml, fs_watchdog +from .quarto import nbdev_readme, nbdev_contributing, refresh_quarto_yml, fs_watchdog from .export import nb_export from .frontmatter import FrontmatterProc @@ -121,6 +121,7 @@ def nbdev_new(**kwargs): refresh_quarto_yml() nbdev_export.__wrapped__() nbdev_readme.__wrapped__() + nbdev_contributing.__wrapped__() # %% ../nbs/api/13_cli.ipynb mapping = { diff --git a/nbdev/quarto.py b/nbdev/quarto.py index 2c60764f4..a0d12ef50 100644 --- a/nbdev/quarto.py +++ b/nbdev/quarto.py @@ -21,7 +21,8 @@ # %% auto 0 __all__ = ['BASE_QUARTO_URL', 'install_quarto', 'install', 'IndentDumper', 'nbdev_sidebar', 'refresh_quarto_yml', - 'nbdev_proc_nbs', 'nbdev_readme', 'nbdev_docs', 'prepare', 'fs_watchdog', 'nbdev_preview'] + 'nbdev_proc_nbs', 'nbdev_readme', 'nbdev_contributing', 'nbdev_docs', 'prepare', 'fs_watchdog', + 'nbdev_preview'] # %% ../nbs/api/14_quarto.ipynb def _sprun(cmd): @@ -214,7 +215,7 @@ def nbdev_proc_nbs(**kwargs): _pre_docs(**kwargs)[0] # %% ../nbs/api/14_quarto.ipynb -def _readme_mtime_not_older(readme_path, readme_nb_path): +def _doc_mtime_not_older(readme_path, readme_nb_path): if not readme_nb_path.exists(): print(f"Could not find {readme_nb_path}") return True @@ -259,7 +260,7 @@ def nbdev_readme( "Create README.md from readme_nb (index.ipynb by default)" cfg = get_config() path = Path(path) if path else cfg.nbs_path - if chk_time and _readme_mtime_not_older(cfg.config_path/'README.md', path/cfg.readme_nb): return + if chk_time and _doc_mtime_not_older(cfg.config_path/'README.md', path/cfg.readme_nb): return with _SidebarYmlRemoved(path): # to avoid rendering whole website cache = proc_nbs(path) @@ -267,6 +268,58 @@ def nbdev_readme( _save_cached_readme(cache, cfg) +# %% ../nbs/api/14_quarto.ipynb +def _save_cached_contributing(cache, cfg, contrib_nb): + "Move CONTRIBUTING.md (and any `_files` assets) from the Quarto build cache to the repo root." + tmp_doc_path = cache / cfg.doc_path.name + contrib_file = tmp_doc_path / 'CONTRIBUTING.md' + if contrib_file.exists(): + final_path = cfg.config_path / 'CONTRIBUTING.md' + if final_path.exists(): final_path.unlink() # Py3.7 doesn't have missing_ok + move(contrib_file, final_path) + # Move any supporting files folder + assets_folder = tmp_doc_path / (Path(contrib_nb).stem + '_files') + if assets_folder.exists(): + _copytree(assets_folder, cfg.config_path / assets_folder.name) + +# %% ../nbs/api/14_quarto.ipynb +@call_parse +def nbdev_contributing( + path:str=None, # Path to notebooks (defaults to nbs_path) + chk_time:bool=False # Only build if out-of-date +): + """ + Create CONTRIBUTING.md from contributing_nb (defaults to 'contributing.ipynb' if present). + Skips if the file doesn't exist. + """ + cfg = get_config() + path = Path(path) if path else cfg.nbs_path + + # Decide which notebook is your "contributing" NB (you can hardcode or add to settings.ini) + contrib_nb_name = cfg.get('contributing_nb', 'contributing.ipynb') + contrib_nb_path = path / contrib_nb_name + + contrib_md = cfg.config_path / 'CONTRIBUTING.md' + + # If out of date check is requested, skip if up-to-date or missing + if chk_time and _doc_mtime_not_older(contrib_md, contrib_nb_path): + return + + # If there's no contributing notebook, do nothing + if not contrib_nb_path.exists(): + return + + # Temporarily remove sidebar.yml so Quarto doesn't try to build the entire site + with _SidebarYmlRemoved(path): + cache = proc_nbs(path) + + # Render a single .ipynb -> .md in GFM + _sprun(f'cd "{cache}" && quarto render "{cache/contrib_nb_name}" -o CONTRIBUTING.md -t gfm --no-execute') + + # Copy the newly created CONTRIBUTING.md and _files folder back to the repo root + _save_cached_contributing(cache, cfg, contrib_nb_name) + + # %% ../nbs/api/14_quarto.ipynb @call_parse @delegates(_nbglob_docs) @@ -277,6 +330,7 @@ def nbdev_docs( "Create Quarto docs and README.md" cache,cfg,path = _pre_docs(path, n_workers=n_workers, **kwargs) nbdev_readme.__wrapped__(path=path, chk_time=True) + nbdev_contributing.__wrapped__(path=path, chk_time=True) _sprun(f'cd "{cache}" && quarto render --no-cache') shutil.rmtree(cfg.doc_path, ignore_errors=True) move(cache/cfg.doc_path.name, cfg.config_path) @@ -291,6 +345,7 @@ def prepare(): nbdev.clean.nbdev_clean.__wrapped__() refresh_quarto_yml() nbdev_readme.__wrapped__(chk_time=True) + nbdev_contributing.__wrapped__(chk_time=True) # %% ../nbs/api/14_quarto.ipynb @contextmanager diff --git a/nbs/api/13_cli.ipynb b/nbs/api/13_cli.ipynb index ac6f68b7d..feacf458b 100644 --- a/nbs/api/13_cli.ipynb +++ b/nbs/api/13_cli.ipynb @@ -38,7 +38,7 @@ "from nbdev.doclinks import *\n", "from nbdev.test import *\n", "from nbdev.clean import *\n", - "from nbdev.quarto import nbdev_readme, refresh_quarto_yml, fs_watchdog\n", + "from nbdev.quarto import nbdev_readme, nbdev_contributing, refresh_quarto_yml, fs_watchdog\n", "from nbdev.export import nb_export\n", "from nbdev.frontmatter import FrontmatterProc\n", "\n", @@ -222,7 +222,8 @@ "\n", " refresh_quarto_yml()\n", " nbdev_export.__wrapped__()\n", - " nbdev_readme.__wrapped__()" + " nbdev_readme.__wrapped__()\n", + " nbdev_contributing.__wrapped__()" ] }, { diff --git a/nbs/api/14_quarto.ipynb b/nbs/api/14_quarto.ipynb index 7cfb1ed53..3c5089398 100644 --- a/nbs/api/14_quarto.ipynb +++ b/nbs/api/14_quarto.ipynb @@ -404,7 +404,7 @@ "outputs": [], "source": [ "#|export\n", - "def _readme_mtime_not_older(readme_path, readme_nb_path):\n", + "def _doc_mtime_not_older(readme_path, readme_nb_path):\n", " if not readme_nb_path.exists():\n", " print(f\"Could not find {readme_nb_path}\")\n", " return True\n", @@ -482,7 +482,7 @@ " \"Create README.md from readme_nb (index.ipynb by default)\"\n", " cfg = get_config()\n", " path = Path(path) if path else cfg.nbs_path\n", - " if chk_time and _readme_mtime_not_older(cfg.config_path/'README.md', path/cfg.readme_nb): return\n", + " if chk_time and _doc_mtime_not_older(cfg.config_path/'README.md', path/cfg.readme_nb): return\n", "\n", " with _SidebarYmlRemoved(path): # to avoid rendering whole website\n", " cache = proc_nbs(path)\n", @@ -510,6 +510,73 @@ "# nbdev_readme.__wrapped__(chk_time=False)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef3f1e1f", + "metadata": {}, + "outputs": [], + "source": [ + "#|export\n", + "def _save_cached_contributing(cache, cfg, contrib_nb):\n", + " \"Move CONTRIBUTING.md (and any `_files` assets) from the Quarto build cache to the repo root.\"\n", + " tmp_doc_path = cache / cfg.doc_path.name\n", + " contrib_file = tmp_doc_path / 'CONTRIBUTING.md'\n", + " if contrib_file.exists():\n", + " final_path = cfg.config_path / 'CONTRIBUTING.md'\n", + " if final_path.exists(): final_path.unlink() # Py3.7 doesn't have missing_ok\n", + " move(contrib_file, final_path)\n", + " # Move any supporting files folder\n", + " assets_folder = tmp_doc_path / (Path(contrib_nb).stem + '_files')\n", + " if assets_folder.exists():\n", + " _copytree(assets_folder, cfg.config_path / assets_folder.name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "729a0fa1", + "metadata": {}, + "outputs": [], + "source": [ + "#|export\n", + "@call_parse\n", + "def nbdev_contributing(\n", + " path:str=None, # Path to notebooks (defaults to nbs_path)\n", + " chk_time:bool=False # Only build if out-of-date\n", + "):\n", + " \"\"\"\n", + " Create CONTRIBUTING.md from contributing_nb (defaults to 'contributing.ipynb' if present).\n", + " Skips if the file doesn't exist.\n", + " \"\"\"\n", + " cfg = get_config()\n", + " path = Path(path) if path else cfg.nbs_path\n", + " \n", + " # Decide which notebook is your \"contributing\" NB (you can hardcode or add to settings.ini)\n", + " contrib_nb_name = cfg.get('contributing_nb', 'contributing.ipynb')\n", + " contrib_nb_path = path / contrib_nb_name\n", + " \n", + " contrib_md = cfg.config_path / 'CONTRIBUTING.md'\n", + " \n", + " # If out of date check is requested, skip if up-to-date or missing\n", + " if chk_time and _doc_mtime_not_older(contrib_md, contrib_nb_path):\n", + " return\n", + " \n", + " # If there's no contributing notebook, do nothing\n", + " if not contrib_nb_path.exists():\n", + " return\n", + " \n", + " # Temporarily remove sidebar.yml so Quarto doesn't try to build the entire site\n", + " with _SidebarYmlRemoved(path):\n", + " cache = proc_nbs(path)\n", + " \n", + " # Render a single .ipynb -> .md in GFM\n", + " _sprun(f'cd \"{cache}\" && quarto render \"{cache/contrib_nb_name}\" -o CONTRIBUTING.md -t gfm --no-execute')\n", + " \n", + " # Copy the newly created CONTRIBUTING.md and _files folder back to the repo root\n", + " _save_cached_contributing(cache, cfg, contrib_nb_name)\n" + ] + }, { "cell_type": "code", "execution_count": null, @@ -527,6 +594,7 @@ " \"Create Quarto docs and README.md\"\n", " cache,cfg,path = _pre_docs(path, n_workers=n_workers, **kwargs)\n", " nbdev_readme.__wrapped__(path=path, chk_time=True)\n", + " nbdev_contributing.__wrapped__(path=path, chk_time=True)\n", " _sprun(f'cd \"{cache}\" && quarto render --no-cache')\n", " shutil.rmtree(cfg.doc_path, ignore_errors=True)\n", " move(cache/cfg.doc_path.name, cfg.config_path)" @@ -559,7 +627,8 @@ " nbdev.test.nbdev_test.__wrapped__()\n", " nbdev.clean.nbdev_clean.__wrapped__()\n", " refresh_quarto_yml()\n", - " nbdev_readme.__wrapped__(chk_time=True)" + " nbdev_readme.__wrapped__(chk_time=True)\n", + " nbdev_contributing.__wrapped__(chk_time=True)" ] }, { diff --git a/settings.ini b/settings.ini index 19c54442b..8d766f219 100644 --- a/settings.ini +++ b/settings.ini @@ -40,6 +40,7 @@ console_scripts = nbdev_create_config=nbdev.config:nbdev_create_config nbdev_preview=nbdev.quarto:nbdev_preview nbdev_prepare=nbdev.quarto:prepare nbdev_readme=nbdev.quarto:nbdev_readme + nbdev_contributing=nbdev.quarto:nbdev_contributing nbdev_release_gh=nbdev.release:release_gh nbdev_release_git=nbdev.release:release_git nbdev_changelog=nbdev.release:changelog From 5531feb4896583f98bb8f1dd08a9d4933610ecf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Clavi=C3=A9?= Date: Mon, 24 Feb 2025 12:34:43 +0900 Subject: [PATCH 2/3] update style --- nbdev/quarto.py | 35 ++++++++--------------------------- nbs/api/14_quarto.ipynb | 35 ++++++++--------------------------- 2 files changed, 16 insertions(+), 54 deletions(-) diff --git a/nbdev/quarto.py b/nbdev/quarto.py index a0d12ef50..35d7f6b8a 100644 --- a/nbdev/quarto.py +++ b/nbdev/quarto.py @@ -275,48 +275,29 @@ def _save_cached_contributing(cache, cfg, contrib_nb): contrib_file = tmp_doc_path / 'CONTRIBUTING.md' if contrib_file.exists(): final_path = cfg.config_path / 'CONTRIBUTING.md' - if final_path.exists(): final_path.unlink() # Py3.7 doesn't have missing_ok + if final_path.exists(): final_path.unlink() # py37 doesn't have `missing_ok` move(contrib_file, final_path) - # Move any supporting files folder - assets_folder = tmp_doc_path / (Path(contrib_nb).stem + '_files') - if assets_folder.exists(): - _copytree(assets_folder, cfg.config_path / assets_folder.name) + assets_folder = tmp_doc_path / (Path(contrib_nb).stem + '_files') # Supporting files for CONTRIBUTING + if assets_folder.exists(): _copytree(assets_folder, cfg.config_path / assets_folder.name) # %% ../nbs/api/14_quarto.ipynb @call_parse def nbdev_contributing( - path:str=None, # Path to notebooks (defaults to nbs_path) + path:str=None, # Path to notebooks chk_time:bool=False # Only build if out-of-date ): - """ - Create CONTRIBUTING.md from contributing_nb (defaults to 'contributing.ipynb' if present). - Skips if the file doesn't exist. - """ + """Create CONTRIBUTING.md from contributing_nb (defaults to 'contributing.ipynb' if present). Skips if the file doesn't exist.""" cfg = get_config() path = Path(path) if path else cfg.nbs_path - - # Decide which notebook is your "contributing" NB (you can hardcode or add to settings.ini) contrib_nb_name = cfg.get('contributing_nb', 'contributing.ipynb') contrib_nb_path = path / contrib_nb_name + if not contrib_nb_path.exists(): return + if chk_time and _doc_mtime_not_older(cfg.config_path / 'CONTRIBUTING.md' , contrib_nb_path): return - contrib_md = cfg.config_path / 'CONTRIBUTING.md' - - # If out of date check is requested, skip if up-to-date or missing - if chk_time and _doc_mtime_not_older(contrib_md, contrib_nb_path): - return - - # If there's no contributing notebook, do nothing - if not contrib_nb_path.exists(): - return - - # Temporarily remove sidebar.yml so Quarto doesn't try to build the entire site - with _SidebarYmlRemoved(path): + with _SidebarYmlRemoved(path): # to avoid rendering whole website cache = proc_nbs(path) - - # Render a single .ipynb -> .md in GFM _sprun(f'cd "{cache}" && quarto render "{cache/contrib_nb_name}" -o CONTRIBUTING.md -t gfm --no-execute') - # Copy the newly created CONTRIBUTING.md and _files folder back to the repo root _save_cached_contributing(cache, cfg, contrib_nb_name) diff --git a/nbs/api/14_quarto.ipynb b/nbs/api/14_quarto.ipynb index 3c5089398..c1e92452d 100644 --- a/nbs/api/14_quarto.ipynb +++ b/nbs/api/14_quarto.ipynb @@ -524,12 +524,10 @@ " contrib_file = tmp_doc_path / 'CONTRIBUTING.md'\n", " if contrib_file.exists():\n", " final_path = cfg.config_path / 'CONTRIBUTING.md'\n", - " if final_path.exists(): final_path.unlink() # Py3.7 doesn't have missing_ok\n", + " if final_path.exists(): final_path.unlink() # py37 doesn't have `missing_ok`\n", " move(contrib_file, final_path)\n", - " # Move any supporting files folder\n", - " assets_folder = tmp_doc_path / (Path(contrib_nb).stem + '_files')\n", - " if assets_folder.exists():\n", - " _copytree(assets_folder, cfg.config_path / assets_folder.name)" + " assets_folder = tmp_doc_path / (Path(contrib_nb).stem + '_files') # Supporting files for CONTRIBUTING\n", + " if assets_folder.exists(): _copytree(assets_folder, cfg.config_path / assets_folder.name)" ] }, { @@ -542,38 +540,21 @@ "#|export\n", "@call_parse\n", "def nbdev_contributing(\n", - " path:str=None, # Path to notebooks (defaults to nbs_path)\n", + " path:str=None, # Path to notebooks\n", " chk_time:bool=False # Only build if out-of-date\n", "):\n", - " \"\"\"\n", - " Create CONTRIBUTING.md from contributing_nb (defaults to 'contributing.ipynb' if present).\n", - " Skips if the file doesn't exist.\n", - " \"\"\"\n", + " \"\"\"Create CONTRIBUTING.md from contributing_nb (defaults to 'contributing.ipynb' if present). Skips if the file doesn't exist.\"\"\"\n", " cfg = get_config()\n", " path = Path(path) if path else cfg.nbs_path\n", - " \n", - " # Decide which notebook is your \"contributing\" NB (you can hardcode or add to settings.ini)\n", " contrib_nb_name = cfg.get('contributing_nb', 'contributing.ipynb')\n", " contrib_nb_path = path / contrib_nb_name\n", + " if not contrib_nb_path.exists(): return\n", + " if chk_time and _doc_mtime_not_older(cfg.config_path / 'CONTRIBUTING.md' , contrib_nb_path): return\n", " \n", - " contrib_md = cfg.config_path / 'CONTRIBUTING.md'\n", - " \n", - " # If out of date check is requested, skip if up-to-date or missing\n", - " if chk_time and _doc_mtime_not_older(contrib_md, contrib_nb_path):\n", - " return\n", - " \n", - " # If there's no contributing notebook, do nothing\n", - " if not contrib_nb_path.exists():\n", - " return\n", - " \n", - " # Temporarily remove sidebar.yml so Quarto doesn't try to build the entire site\n", - " with _SidebarYmlRemoved(path):\n", + " with _SidebarYmlRemoved(path): # to avoid rendering whole website\n", " cache = proc_nbs(path)\n", - " \n", - " # Render a single .ipynb -> .md in GFM\n", " _sprun(f'cd \"{cache}\" && quarto render \"{cache/contrib_nb_name}\" -o CONTRIBUTING.md -t gfm --no-execute')\n", " \n", - " # Copy the newly created CONTRIBUTING.md and _files folder back to the repo root\n", " _save_cached_contributing(cache, cfg, contrib_nb_name)\n" ] }, From 2c15d52c38c627e473ccaded5677e88d343b7046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Clavi=C3=A9?= Date: Mon, 24 Feb 2025 12:35:49 +0900 Subject: [PATCH 3/3] nit: remove trailing newline --- nbdev/quarto.py | 1 - nbs/api/14_quarto.ipynb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/nbdev/quarto.py b/nbdev/quarto.py index 35d7f6b8a..4742d1c6e 100644 --- a/nbdev/quarto.py +++ b/nbdev/quarto.py @@ -300,7 +300,6 @@ def nbdev_contributing( _save_cached_contributing(cache, cfg, contrib_nb_name) - # %% ../nbs/api/14_quarto.ipynb @call_parse @delegates(_nbglob_docs) diff --git a/nbs/api/14_quarto.ipynb b/nbs/api/14_quarto.ipynb index c1e92452d..5ceabb923 100644 --- a/nbs/api/14_quarto.ipynb +++ b/nbs/api/14_quarto.ipynb @@ -555,7 +555,7 @@ " cache = proc_nbs(path)\n", " _sprun(f'cd \"{cache}\" && quarto render \"{cache/contrib_nb_name}\" -o CONTRIBUTING.md -t gfm --no-execute')\n", " \n", - " _save_cached_contributing(cache, cfg, contrib_nb_name)\n" + " _save_cached_contributing(cache, cfg, contrib_nb_name)" ] }, {