nbdev 3.3.25__tar.gz → 3.3.27__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nbdev-3.3.25/nbdev.egg-info → nbdev-3.3.27}/PKG-INFO +1 -1
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/__init__.py +1 -1
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/quarto.py +4 -5
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/quarto_render.py +16 -5
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/release.py +16 -13
- nbdev-3.3.27/nbdev/skill.py +63 -0
- {nbdev-3.3.25 → nbdev-3.3.27/nbdev.egg-info}/PKG-INFO +1 -1
- {nbdev-3.3.25 → nbdev-3.3.27}/tests/test_quarto_render.py +14 -6
- nbdev-3.3.25/nbdev/skill.py +0 -82
- {nbdev-3.3.25 → nbdev-3.3.27}/CONTRIBUTING.md +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/LICENSE +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/README.md +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/_modidx.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/clean.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/cli.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/config.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/diff.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/doclinks.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/export.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/extract_attachments.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/frontmatter.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/imports.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/maker.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/merge.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/migrate.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/moddocs.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/process.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/processors.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/qmd.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/readme_filter.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/scrubmagics.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/serve.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/serve_drv.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/showdoc.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/sync.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev/test.py +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev.egg-info/SOURCES.txt +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev.egg-info/dependency_links.txt +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev.egg-info/entry_points.txt +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev.egg-info/requires.txt +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/nbdev.egg-info/top_level.txt +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/pyproject.toml +0 -0
- {nbdev-3.3.25 → nbdev-3.3.27}/setup.cfg +0 -0
|
@@ -6,7 +6,7 @@ Modules:
|
|
|
6
6
|
- `nbdev.moddocs`: # Module docs: creating them from existing notebooks
|
|
7
7
|
- `nbdev.skill`: Write, read and review nbdev notebooks as source, documentation, examples and tests. You MUST read this before any work on a project with notebooks."""
|
|
8
8
|
|
|
9
|
-
__version__ = "3.3.
|
|
9
|
+
__version__ = "3.3.27"
|
|
10
10
|
|
|
11
11
|
from .doclinks import nbdev_export
|
|
12
12
|
from .showdoc import show_doc
|
|
@@ -23,7 +23,7 @@ from fastcore.shutil import rmtree,move,copytree
|
|
|
23
23
|
from fastcore.meta import delegates
|
|
24
24
|
from .serve import proc_nbs,_proc_file
|
|
25
25
|
from . import serve_drv
|
|
26
|
-
from .quarto_render import render_quarto
|
|
26
|
+
from .quarto_render import render_quarto, quarto_stale
|
|
27
27
|
import yaml
|
|
28
28
|
|
|
29
29
|
# %% ../nbs/api/14_quarto.ipynb #aae2d2be-ad03-4536-bf70-c4575f39cea3
|
|
@@ -75,7 +75,7 @@ def _sort(a):
|
|
|
75
75
|
|
|
76
76
|
_def_file_re = r'\.(?:ipynb|qmd|html)$'
|
|
77
77
|
|
|
78
|
-
@delegates
|
|
78
|
+
@delegates(nbglob_cli)
|
|
79
79
|
def _nbglob_docs(
|
|
80
80
|
path:str=None, # Path to notebooks
|
|
81
81
|
file_glob:str=None, # Only include files matching glob
|
|
@@ -214,9 +214,8 @@ def _pre_docs(path=None, n_workers:int=defaults.cpus, **kwargs):
|
|
|
214
214
|
path = Path(path).absolute() if path else cfg.nbs_path
|
|
215
215
|
if not (path/'nbdev.yml').exists(): path = cfg.nbs_path # given a project root, fall back to its configured nbs
|
|
216
216
|
os.chdir(cfg.config_path) # bare `get_config()` runs downstream (including in render workers), so anchor the cwd
|
|
217
|
-
_chk_nbdev_yml(path)
|
|
218
|
-
_ensure_quarto()
|
|
219
217
|
refresh_quarto_yml()
|
|
218
|
+
_ensure_quarto()
|
|
220
219
|
import nbdev.doclinks
|
|
221
220
|
nbdev.doclinks._build_modidx()
|
|
222
221
|
nbdev_sidebar.__wrapped__(path=path, **kwargs)
|
|
@@ -392,7 +391,7 @@ def nbdev_preview(
|
|
|
392
391
|
cache,cfg,path = _pre_docs(path, n_workers=n_workers, **kwargs)
|
|
393
392
|
site = cache/cfg.doc_path.name
|
|
394
393
|
if not (render or site.exists()) and cfg.doc_path.exists(): copytree(cfg.doc_path, site)
|
|
395
|
-
if render or not site.exists(): render_quarto(cache, site, n_workers=n_workers)
|
|
394
|
+
if render or not site.exists() or quarto_stale(cache, site): render_quarto(cache, site, n_workers=n_workers)
|
|
396
395
|
xtra = []
|
|
397
396
|
if port: xtra += ['--port', str(port)]
|
|
398
397
|
if host: xtra += ['--host', host]
|
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
"Parallel Quarto website rendering in isolated project copies."
|
|
2
2
|
|
|
3
3
|
import json, shutil, subprocess, tempfile
|
|
4
|
-
from pathlib import Path
|
|
5
4
|
from xml.etree import ElementTree as ET
|
|
6
5
|
from fastcore.parallel import parallel
|
|
7
|
-
from fastcore.utils import
|
|
6
|
+
from fastcore.utils import *
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
def _quarto(path, *args):
|
|
11
|
-
res = subprocess.run(['quarto', *map(str, args)], cwd=path, capture_output=True, text=True)
|
|
9
|
+
def _quarto(path, *args, env=None):
|
|
10
|
+
res = subprocess.run(['quarto', *map(str, args)], cwd=path, capture_output=True, text=True, env=env)
|
|
12
11
|
if res.returncode: raise RuntimeError(res.stderr or res.stdout or f'Quarto exited with status {res.returncode}')
|
|
13
12
|
return res.stdout
|
|
14
13
|
|
|
15
14
|
|
|
15
|
+
def quarto_stale(path, output_dir):
|
|
16
|
+
"Whether a page's HTML output is missing or older than its processed source."
|
|
17
|
+
path, output_dir = Path(path).resolve(), Path(output_dir).resolve()
|
|
18
|
+
info = loads(_quarto(path, 'inspect'))
|
|
19
|
+
for name,entry in info['fileInformation'].items():
|
|
20
|
+
p = Path(name)
|
|
21
|
+
output = output_dir/p.parent/(entry['metadata'].get('output-file') or p.with_suffix('.html').name)
|
|
22
|
+
if not output.exists() or (path/p).stat().st_mtime>output.stat().st_mtime: return True
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
|
|
16
26
|
def _render_batch(job):
|
|
17
27
|
path, inputs, output = job
|
|
18
|
-
|
|
28
|
+
env = {**os.environ, 'XDG_CACHE_HOME': str(path/'.cache')} if sys.platform == 'linux' else None
|
|
29
|
+
_quarto(path, 'render', *inputs, '--no-cache', '--no-clean', '--output-dir', output, env=env)
|
|
19
30
|
return output
|
|
20
31
|
|
|
21
32
|
|
|
@@ -5,9 +5,10 @@ Docs: https://nbdev.fast.ai/api/release.html.md"""
|
|
|
5
5
|
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/18_release.ipynb.
|
|
6
6
|
|
|
7
7
|
# %% auto #0
|
|
8
|
-
__all__ = ['GH_HOST', '
|
|
9
|
-
'
|
|
10
|
-
'
|
|
8
|
+
__all__ = ['GH_HOST', 'CHANGELOG_MARKER', 'CHANGELOG_TMPL', 'CONDA_WARNING', 'update_changelog', 'Release', 'changelog',
|
|
9
|
+
'push_release', 'release_git', 'release_gh', 'pypi_json', 'latest_pypi', 'pypi_details', 'conda_output_path',
|
|
10
|
+
'write_conda_meta', 'write_requirements', 'anaconda_upload', 'release_conda', 'chk_conda_rel',
|
|
11
|
+
'release_pypi', 'release_both', 'nbdev_bump_version']
|
|
11
12
|
|
|
12
13
|
# %% ../nbs/api/18_release.ipynb #c35cc2b8
|
|
13
14
|
from fastcore.all import *
|
|
@@ -15,7 +16,7 @@ from ghapi.core import *
|
|
|
15
16
|
|
|
16
17
|
from datetime import datetime
|
|
17
18
|
from packaging.version import Version
|
|
18
|
-
import
|
|
19
|
+
import subprocess,asyncio
|
|
19
20
|
|
|
20
21
|
from .doclinks import *
|
|
21
22
|
|
|
@@ -60,8 +61,12 @@ def _release_head():
|
|
|
60
61
|
return head
|
|
61
62
|
|
|
62
63
|
# %% ../nbs/api/18_release.ipynb #dcaba486
|
|
63
|
-
|
|
64
|
+
CHANGELOG_MARKER = '<!-- do not remove -->\n'
|
|
65
|
+
CHANGELOG_TMPL = f'# Release notes\n\n{CHANGELOG_MARKER}'
|
|
66
|
+
|
|
67
|
+
def update_changelog(txt, ver, notes, marker=CHANGELOG_MARKER):
|
|
64
68
|
"Insert `notes` into changelog `txt` after `marker`, replacing any existing section for `ver`"
|
|
69
|
+
if marker not in txt: raise ValueError(f"The changelog has no {marker.strip()!r} marker: add it near the top")
|
|
65
70
|
txt = re.sub(rf'\n## {re.escape(ver)}\n.*?(?=\n## |\Z)', '', txt, flags=re.S)
|
|
66
71
|
return txt.replace(marker, marker+notes.rstrip('\n')+'\n\n').rstrip('\n')+'\n'
|
|
67
72
|
|
|
@@ -86,7 +91,7 @@ class Release:
|
|
|
86
91
|
self.groups = groups
|
|
87
92
|
|
|
88
93
|
async def _issues(self, label):
|
|
89
|
-
return await self.gh.issues.list_for_repo(state='closed', sort='created',
|
|
94
|
+
return await self.gh.issues.list_for_repo(state='closed', sort='created', since=self.commit_date, labels=label)
|
|
90
95
|
async def _issue_groups(self): return await asyncio.gather(*map(self._issues, self.groups.keys()))
|
|
91
96
|
|
|
92
97
|
# %% ../nbs/api/18_release.ipynb #aa22dfe3
|
|
@@ -94,8 +99,7 @@ class Release:
|
|
|
94
99
|
async def changelog(self:Release,
|
|
95
100
|
debug=False): # Just print the latest changes, instead of updating file
|
|
96
101
|
"Create the CHANGELOG.md file, or return the proposed text if `debug` is `True`"
|
|
97
|
-
if not self.changefile.exists(): self.changefile.write_text(
|
|
98
|
-
marker = '<!-- do not remove -->\n'
|
|
102
|
+
if not self.changefile.exists(): self.changefile.write_text(CHANGELOG_TMPL, encoding='utf-8')
|
|
99
103
|
try: self.commit_date = (lr:=await self.gh.repos.get_latest_release()).published_at
|
|
100
104
|
except APIError as e:
|
|
101
105
|
if e.status_code != 404: raise
|
|
@@ -111,9 +115,8 @@ async def changelog(self:Release,
|
|
|
111
115
|
sections = (_issues_txt(*o) for o in zip(issues, self.groups.values()))
|
|
112
116
|
res += '\n\n'.join(filter(None, sections))
|
|
113
117
|
if debug: return res
|
|
114
|
-
res = update_changelog(self.changefile.read_text(), self.cfg.version, res
|
|
115
|
-
|
|
116
|
-
self.changefile.write_text(res)
|
|
118
|
+
res = update_changelog(self.changefile.read_text(encoding='utf-8'), self.cfg.version, res)
|
|
119
|
+
self.changefile.write_text(res, encoding='utf-8')
|
|
117
120
|
run(f'git add {self.changefile}')
|
|
118
121
|
|
|
119
122
|
# %% ../nbs/api/18_release.ipynb #068421c6
|
|
@@ -132,8 +135,8 @@ async def release(self:Release):
|
|
|
132
135
|
def latest_notes(self:Release):
|
|
133
136
|
"Latest CHANGELOG entry"
|
|
134
137
|
if not self.changefile.exists(): return ''
|
|
135
|
-
its = re.split(r'^## ', self.changefile.read_text(), flags=re.MULTILINE)
|
|
136
|
-
if
|
|
138
|
+
its = re.split(r'^## ', self.changefile.read_text(encoding='utf-8'), flags=re.MULTILINE)
|
|
139
|
+
if len(its) < 2: return ''
|
|
137
140
|
return '\n'.join(its[1].splitlines()[1:]).strip()
|
|
138
141
|
|
|
139
142
|
# %% ../nbs/api/18_release.ipynb #01cb1ca4
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Write, read and review nbdev notebooks as source, documentation, examples and tests. You MUST read this before any work on a project with notebooks.
|
|
2
|
+
|
|
3
|
+
## Source and reading
|
|
4
|
+
|
|
5
|
+
Published-library notebooks: interleave implementation, explanation, examples, outputs and failure demonstrations for top-to-bottom reading. Internal projects: match surrounding notebooks.
|
|
6
|
+
|
|
7
|
+
Check each file, not the repo: `# AUTOGENERATED! DO NOT EDIT!` names the source notebook; `# %% ../nbs/04_usage.ipynb #a45f753a` identifies its source cell. Edit that notebook, never generated modules, `__all__`, `_modidx.py`, or module docstrings; `nbdev-export` regenerates them. Unmarked modules are hand-written. Understand and review work through notebooks and their `git diff`, never generated modules: those lack prose, examples and tests.
|
|
8
|
+
|
|
9
|
+
Use notebooks to teach APIs through narrative/examples, plain `.py` for dense mechanism iterated under pytest (rarely; never add pytests to a project without them unless asked). Lessons test notebook code; `tests/*.py` test plain modules. For project-level questions, read `nbs/index.ipynb` (README.md's source); regenerate with `nbdev-readme` after changes.
|
|
10
|
+
|
|
11
|
+
## Authoring
|
|
12
|
+
|
|
13
|
+
Before notebook edits, read the whole notebook or a summary of every cell. For a new notebook, read a role model such as claudette's `00_core.ipynb` to learn the literate form. Choose tutorial, how-to, explanation, or reference. Open with an H1 title cell, `>` subtitle and brief introduction. Use H2s for major concepts without fragmenting short narratives; each heading gets its own markdown cell for Jupyter collapse.
|
|
14
|
+
|
|
15
|
+
Develop one idea at a time: small implementation, explanation, lesson for every substantive API. Basic functionality outside the API, with little logic, generally needs no lesson. Introduce lessons in markdown; split when the introduction becomes complicated. Extend examples rather than adding near-duplicates. Build classes with `@patch` beside each method's explanation unless that obscures the API.
|
|
16
|
+
|
|
17
|
+
When new behavior needs teaching (often unnecessary for trivial logic), choose its narrative position, write the lesson first (better, slightly modify an existing lesson), run preceding cells as needed, see it fail. Add its markdown introduction and implementation above it; run implementation and lesson to see it pass. For bugs, revise an existing example to exercise the failing path; if no revision fits, add an assertion to it. No documented behavior change: change no lesson cells. Never add a cell merely to witness a fix.
|
|
18
|
+
|
|
19
|
+
Read existing examples before experimenting. Explore in the notebook, not a separate kernel check; keep useful explorations as lessons, delete the rest. Always try to leave the notebook better. Reserve underscore names for machinery without a coherent independent contract, not everything used internally. A helper useful only internally often signals awkward design.
|
|
20
|
+
|
|
21
|
+
## Lessons
|
|
22
|
+
|
|
23
|
+
Readability comes first: guide readers through what code does using code and displayed output. If a displayed value is worth testing, assign, test, then show it. Test the point of the code, not incidentals such as formatting. Show errors only when readers are likely to hit them.
|
|
24
|
+
|
|
25
|
+
Use realistic values, minimal setup, reused objects and direct supporting assertions. Show evidence with compact `_repr_markdown_`, structured summaries, plots, tables, images or HTML; explain what matters in large outputs and keep stored results focused. Use `fastcore.test` assertions and `expect_fail` in ordinary code cells.
|
|
26
|
+
|
|
27
|
+
Test-serving cells don't belong on the page: signs include safety-only setup and glue checks. Usually remove them; move substantive logic checks to `#| hide` or pytest. Discuss such changes carefully. Keep plumbing, mocks, dense comprehensions and long setup out of reader-facing examples: extract a small helper or hide the check.
|
|
28
|
+
|
|
29
|
+
Consider these rewrites:
|
|
30
|
+
- Commented examples -> prose/code; numbered steps -> markdown/code pairs. Keep comments stating constraints code cannot show.
|
|
31
|
+
- Sentence-wrapped `print` -> prose/displayed value; final `print(x)` -> bare `x`.
|
|
32
|
+
- Reassignment stages and blank-line groups -> separate cells, each introduced.
|
|
33
|
+
- Near-duplicates: explain the differing argument; don't repeat setup.
|
|
34
|
+
- Errors: `expect_fail`, not `try`/`except`. Long docstrings -> markdown.
|
|
35
|
+
- Resolve TODO/FIXME example comments or move them to issues.
|
|
36
|
+
|
|
37
|
+
## Prose and exports
|
|
38
|
+
|
|
39
|
+
In markdown, explain rationale, distinctions and guarantees, not code line-by-line or filler transitions. Place it for correct generated-page reading, normally after definitions. Use short symbol docstrings, parameter/return docments beside signatures and backticked symbols for nbdev links. Extended explanation, examples and warnings belong in markdown.
|
|
40
|
+
|
|
41
|
+
`nbdev-export` assembles module docstrings from the title's `>` description and exported markdown after H1; use one exported markdown cell per major section for long docstrings. `doc(module)` lists functions; in module prose, explain only shared constraints/workflows.
|
|
42
|
+
|
|
43
|
+
`#| exportd` includes a code cell as fenced docstring source, not module code. Use compact runnable demos after required definitions; end the preceding exported summary with a colon. Intervening unexported definitions don't appear in the docstring. Check claims by running code before documenting; preview assembly with `nbdev.export.nb_mdoc`. A docstring beyond the default summary makes `nbdev-export` list the module in package docs and `llms.txt`. Only extend docstrings of modules read independently. Export `index.ipynb`'s opening paragraphs for the package intro.
|
|
44
|
+
|
|
45
|
+
## State and execution
|
|
46
|
+
|
|
47
|
+
Define values near first use, introduce shared setup, reuse established objects; don't reassign names later cells depend on. End explorations with the expression recording what was learned when useful. Keep imports in dedicated cells, lessons included: docs builds execute import-containing cells in fresh namespaces; mixed state-dependent code can fail or run at documentation time.
|
|
48
|
+
|
|
49
|
+
Outputs are generated and may be stale during edits. Don't stop work, clear them manually, or edit notebook JSON because of source/output mismatch. At PR time, regenerate with `nbdev-test --save` if the project keeps saved outputs. `nbdev-test --file-re` runs several named notebooks in parallel.
|
|
50
|
+
|
|
51
|
+
## Directives and nbdev v3
|
|
52
|
+
|
|
53
|
+
- `#| default_exp` names the generated module; `#| export` includes a cell there. Exported underscore helpers need not be public.
|
|
54
|
+
- `#| hide` hides distracting necessities from the page.
|
|
55
|
+
- `#| eval: false`: code that must not run, not broken code. Later cells can't use its state.
|
|
56
|
+
- Metadata directives work too: `{"nbdev": {"export": "true"}}`; `fastcore.nbio.mk_cell(...).directives` merges both forms, content winning conflicts.
|
|
57
|
+
|
|
58
|
+
nbdev v3 (Jan 2026): `pyproject.toml`, not `settings.ini`; metadata in `[project]`, settings in `[tool.nbdev]` (defaults `nbs_path='nbs'`, `doc_path='_docs'`), version in `__init__.py` via `dynamic = ["version"]`, `_modidx` in `[project.entry-points.nbdev]`. CLIs use hyphens (`nbdev-export`, `nbdev-test`); Python names retain underscores. GitHub actions: `fastai/workflows/nbdev3-ci`, `quarto-ghp3`.
|
|
59
|
+
|
|
60
|
+
## Finish
|
|
61
|
+
|
|
62
|
+
Revise affected prose, displays and assertions together; changed assertions must fail on old code and pass on new. Re-read touched narrative for readability. Run `nbdev-test <nb>`.
|
|
63
|
+
"""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import json, shutil, subprocess, pytest
|
|
1
|
+
import json, shutil, subprocess, sys, pytest
|
|
2
2
|
from xml.etree import ElementTree as ET
|
|
3
3
|
from fastcore.test import test_eq as teq
|
|
4
|
-
from nbdev.quarto_render import render_quarto
|
|
4
|
+
from nbdev.quarto_render import render_quarto, quarto_stale
|
|
5
5
|
from nbdev.quarto import nbdev_readme, refresh_quarto_yml
|
|
6
6
|
from nbdev.readme_filter import doc_link
|
|
7
7
|
from fastcore.nbio import new_nb, mk_cell, write_nb
|
|
@@ -40,7 +40,9 @@ Documentation = "https://example.com/project/"
|
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
@pytest.mark.skipif(not shutil.which('quarto'), reason='requires Quarto')
|
|
43
|
-
def test_website(tmp_path):
|
|
43
|
+
def test_website(tmp_path, monkeypatch):
|
|
44
|
+
cache = tmp_path/'cache'
|
|
45
|
+
monkeypatch.setenv('XDG_CACHE_HOME', str(cache))
|
|
44
46
|
root = tmp_path/'source'
|
|
45
47
|
root.mkdir()
|
|
46
48
|
(root/'_quarto.yml').write_text(r'''project:
|
|
@@ -65,14 +67,18 @@ title: {name}
|
|
|
65
67
|
Page {name}. [Alpha](alpha.qmd#detail). [Download](data.txt).
|
|
66
68
|
''')
|
|
67
69
|
(root/'data.txt').write_text('shared resource')
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
(root/'other.qmd').write_text('---\noutput-file: renamed.html\n---\n# Other')
|
|
71
|
+
serial, parallel = tmp_path/'serial', root/'_site'
|
|
72
|
+
assert quarto_stale(root, parallel)
|
|
70
73
|
render_quarto(root, parallel, n_workers=2)
|
|
74
|
+
if sys.platform == 'linux': assert not (cache/'quarto/sass').exists()
|
|
75
|
+
assert not quarto_stale(root, parallel)
|
|
76
|
+
render_quarto(root, serial, n_workers=1)
|
|
71
77
|
search = lambda d: {e['href']: e['text'] for e in json.loads((d/'search.json').read_text())}
|
|
72
78
|
urls = lambda d: {e.text for e in ET.parse(d/'sitemap.xml').findall('.//{*}loc')}
|
|
73
79
|
teq(search(serial), search(parallel))
|
|
74
80
|
teq(urls(serial), urls(parallel))
|
|
75
|
-
teq(len(urls(parallel)),
|
|
81
|
+
teq(len(urls(parallel)), 4)
|
|
76
82
|
for name in ('index', 'alpha', 'beta'):
|
|
77
83
|
html = (parallel/f'{name}.html').read_text()
|
|
78
84
|
assert 'alpha.html#detail' in html and 'data.txt' in html
|
|
@@ -81,7 +87,9 @@ Page {name}. [Alpha](alpha.qmd#detail). [Download](data.txt).
|
|
|
81
87
|
assert (parallel/'site_libs').is_dir()
|
|
82
88
|
assert 'http-equiv="refresh"' not in (parallel/'index.html').read_text()
|
|
83
89
|
(root/'beta.qmd').write_text('---\ntitle: beta\n---\n## Detail\n\nUpdated beta.')
|
|
90
|
+
assert quarto_stale(root, parallel)
|
|
84
91
|
subprocess.run(['quarto', 'render', 'beta.qmd', '--quiet', '--output-dir', str(parallel)], cwd=root, check=True)
|
|
92
|
+
assert not quarto_stale(root, parallel)
|
|
85
93
|
teq(set(search(serial)), set(search(parallel)))
|
|
86
94
|
assert 'Updated beta.' in search(parallel)['beta.html#detail']
|
|
87
95
|
(root/'beta.qmd').write_text('---\nfilters: [missing.lua]\n---\nBroken.')
|
nbdev-3.3.25/nbdev/skill.py
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
"""Write, read and review nbdev notebooks as source, documentation, examples and tests. You MUST read this before any work on a project with notebooks.
|
|
2
|
-
|
|
3
|
-
## Source
|
|
4
|
-
|
|
5
|
-
Write notebooks to be read top-to-bottom, interleaving implementation, explanation, examples, outputs, and failure demonstrations. Follow these conventions in published libraries. In internal projects, match the surrounding notebooks.
|
|
6
|
-
|
|
7
|
-
Check the file, not the repo: `# AUTOGENERATED! DO NOT EDIT!` names the source notebook; `# %% ../nbs/04_usage.ipynb #a45f753a` identifies the source cell. Edit that notebook, never generated modules, `__all__`, `_modidx.py`, or module docstrings; `nbdev-export` regenerates them. Unmarked modules are hand-written. Use notebooks to teach the API through narrative and examples, and plain `.py` for dense mechanism iterated under pytest (rarely; never add pytests to a project without them unless asked). Lessons test notebook code. Test plain modules in `tests/*.py`.
|
|
8
|
-
|
|
9
|
-
Understand and review work through the notebooks and their `git diff`, never generated modules. Those lack the prose, examples and tests.
|
|
10
|
-
|
|
11
|
-
For project-level questions, read `nbs/index.ipynb`, the source of README.md; regenerate with `nbdev-readme` after changes.
|
|
12
|
-
|
|
13
|
-
## Structure and authoring
|
|
14
|
-
|
|
15
|
-
Choose tutorial, how-to, explanation, or reference. Open with an H1 title cell and `>` subtitle, then a brief introduction. Use H2s for major concepts without fragmenting short narratives. Each heading belongs in its own markdown cell so Jupyter can collapse sections.
|
|
16
|
-
|
|
17
|
-
Before changing a notebook, read the whole notebook or a summary of every cell. For a new notebook, read a role model such as claudette's `00_core.ipynb` to learn the literate form.
|
|
18
|
-
|
|
19
|
-
Develop one idea at a time: a small implementation, its explanation, and a lesson if it's a substantive API. Introduce each lesson in markdown; split it when the introduction becomes complicated. Extend existing examples rather than adding near-duplicates. Build classes with `@patch` beside each method's explanation unless that obscures the API.
|
|
20
|
-
|
|
21
|
-
When new behavior needs a lesson (which it often doesn't, if it's trivial logic that doesn't need teaching), choose its narrative position, write the lesson first (or better still, slightly modify and existing listen), run preceding cells as needed, and see it fail. Add its markdown introduction and implementation above it, then run both to see it pass. For bugs, revise an existing example to exercise the failing path; if no revision fits, add an assertion to it. If no documented behavior changes, change no lesson cells. Never add a cell merely to witness a fix.
|
|
22
|
-
|
|
23
|
-
Read existing examples before experimenting. Explore in the notebook, not in a separate kernel check; keep useful explorations as lessons and delete the rest. Always try to leave a notebook better than you found it.
|
|
24
|
-
|
|
25
|
-
Reserve underscore names for machinery without a coherent independent contract, not for everything used only internally. If a helper is only useful internally, the design is often awkward.
|
|
26
|
-
|
|
27
|
-
## Prose and module documentation
|
|
28
|
-
|
|
29
|
-
In markdown, explain rationale, distinctions and guarantees. Don't narrate code line by line or write filler transitions. Place markdown where it reads correctly on the generated page, normally after the definition. Use short symbol docstrings, parameter/return docments beside signatures, and backticked symbol names for nbdev links. Extended explanation, examples, and warnings belong in markdown.
|
|
30
|
-
|
|
31
|
-
`nbdev-export` builds the module docstring from the title's `>` description and exported markdown after the H1. Use one exported markdown cell per major section for long docstrings. `doc(module)` lists the functions. In module prose, explain only shared constraints and workflows.
|
|
32
|
-
|
|
33
|
-
`#| exportd` includes a code cell as fenced source in the module docstring, not module code. Use compact runnable demos after their required definitions; end the preceding exported summary with a colon. Unexported definitions between the summary and demo don't appear in the docstring.
|
|
34
|
-
|
|
35
|
-
Check claims by running code before documenting them; preview assembly with `nbdev.export.nb_mdoc`. `nbdev-export` lists a module in package documentation and `llms.txt` if its docstring has more than the default summary. Only extend docstrings of modules read on their own. Export the opening paragraphs of `index.ipynb` for the package intro.
|
|
36
|
-
|
|
37
|
-
## Lesson cells
|
|
38
|
-
|
|
39
|
-
A notebook guides a reader through what the code does. Readability comes first.
|
|
40
|
-
|
|
41
|
-
Every substantive API needs a lesson. Basic functionality outside the API, with little logic, generally doesn't.
|
|
42
|
-
|
|
43
|
-
Explain with code and its displayed output. When a displayed value is also worth testing, assign it, test it, then show it. Test results that are the point of the code, not incidentals such as formatting.
|
|
44
|
-
|
|
45
|
-
Show an error only when readers are likely to hit it.
|
|
46
|
-
|
|
47
|
-
A cell that serves a test instead of a reader doesn't belong on the page. Signs include setup that exists only so a check can run safely, and checks on glue code. Usually, remove such a test. If it checks substantive logic, move it to a `#| hide` cell or to pytest. Discuss such changes carefully.
|
|
48
|
-
|
|
49
|
-
Write page content: realistic values, minimal setup, reused objects, and direct assertions that support the lesson. Show evidence with compact `_repr_markdown_` or structured summaries, plots, tables, images or HTML. Explain what matters in large outputs and keep stored results focused.
|
|
50
|
-
|
|
51
|
-
Use `fastcore.test` assertions and `expect_fail` in ordinary code cells. Keep check plumbing, mocks, dense comprehensions, and long setup out of reader-facing examples: extract a small helper or hide the check. Use `nbdev-test --file-re` to run several named notebooks in parallel.
|
|
52
|
-
|
|
53
|
-
Consider a rewrite when you see these:
|
|
54
|
-
|
|
55
|
-
- Split commented examples into prose and code. Split numbered steps into markdown/code pairs. Keep comments that state constraints code cannot show.
|
|
56
|
-
- Replace a sentence-wrapped `print` with prose and a displayed value, and a final `print(x)` with bare `x`.
|
|
57
|
-
- Split reassignment stages and blank-line groups into cells, each with its own introduction.
|
|
58
|
-
- In near-duplicate examples, explain the argument that differs. Don't repeat the setup.
|
|
59
|
-
- Show errors with `expect_fail`, not `try`/`except`. Move long docstrings to markdown.
|
|
60
|
-
- Resolve TODO/FIXME example comments or move them to issues.
|
|
61
|
-
|
|
62
|
-
## State and execution
|
|
63
|
-
|
|
64
|
-
Define values near first use, introduce shared setup, reuse established objects, and don't reassign names later cells depend on. End exploratory cells with the expression recording what was learned when useful.
|
|
65
|
-
|
|
66
|
-
Keep imports in dedicated cells, including in lessons: docs builds execute import-containing cells in fresh namespaces, so mixing imports with state-dependent code can fail or run code at documentation time.
|
|
67
|
-
|
|
68
|
-
Stored outputs are generated and may be stale during editing. Don't stop work, clear them by hand, or edit notebook JSON because they no longer match the source. At PR time, regenerate them with `nbdev-test --save` if the project keeps saved outputs.
|
|
69
|
-
|
|
70
|
-
## Directives and nbdev v3
|
|
71
|
-
|
|
72
|
-
- `#| default_exp` names the generated module; `#| export` includes a cell there. Exported underscore helpers need not be public.
|
|
73
|
-
- `#| hide` hides distracting necessities from the page.
|
|
74
|
-
- `#| eval: false` is for code that must not run, not broken code. Later cells can't use its state.
|
|
75
|
-
- Directives may instead be metadata: `{"nbdev": {"export": "true"}}`. nbdev reads both; `fastcore.nbio.mk_cell(...).directives` merges them with content winning conflicts.
|
|
76
|
-
|
|
77
|
-
nbdev v3 (Jan 2026) uses `pyproject.toml`, not `settings.ini`: metadata in `[project]`, nbdev settings in `[tool.nbdev]` (default `nbs_path='nbs'`, `doc_path='_docs'`), version in `__init__.py` via `dynamic = ["version"]`, and `_modidx` in `[project.entry-points.nbdev]`. CLIs use hyphens (`nbdev-export`, `nbdev-test`); Python names retain underscores. GitHub actions are `fastai/workflows/nbdev3-ci` and `quarto-ghp3`.
|
|
78
|
-
|
|
79
|
-
## Finish
|
|
80
|
-
|
|
81
|
-
Revise affected prose, displays, and assertions together; changed assertions must fail on old code and pass on new. Re-read the touched narrative for readability. Run `nbdev-test <nb>`.
|
|
82
|
-
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|