nbdev 3.3.3__tar.gz → 3.3.5__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.
Files changed (40) hide show
  1. {nbdev-3.3.3/nbdev.egg-info → nbdev-3.3.5}/PKG-INFO +1 -1
  2. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/__init__.py +2 -1
  3. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/_modidx.py +1 -0
  4. nbdev-3.3.5/nbdev/moddocs.py +84 -0
  5. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/quarto.py +9 -5
  6. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/release.py +6 -3
  7. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/serve.py +1 -1
  8. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/skill.py +2 -0
  9. {nbdev-3.3.3 → nbdev-3.3.5/nbdev.egg-info}/PKG-INFO +1 -1
  10. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev.egg-info/SOURCES.txt +1 -0
  11. {nbdev-3.3.3 → nbdev-3.3.5}/CONTRIBUTING.md +0 -0
  12. {nbdev-3.3.3 → nbdev-3.3.5}/LICENSE +0 -0
  13. {nbdev-3.3.3 → nbdev-3.3.5}/MANIFEST.in +0 -0
  14. {nbdev-3.3.3 → nbdev-3.3.5}/README.md +0 -0
  15. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/clean.py +0 -0
  16. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/cli.py +0 -0
  17. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/config.py +0 -0
  18. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/diff.py +0 -0
  19. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/doclinks.py +0 -0
  20. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/export.py +0 -0
  21. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/extract_attachments.py +0 -0
  22. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/frontmatter.py +0 -0
  23. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/imports.py +0 -0
  24. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/maker.py +0 -0
  25. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/merge.py +0 -0
  26. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/migrate.py +0 -0
  27. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/process.py +0 -0
  28. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/processors.py +0 -0
  29. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/qmd.py +0 -0
  30. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/scrubmagics.py +0 -0
  31. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/serve_drv.py +0 -0
  32. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/showdoc.py +0 -0
  33. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/sync.py +0 -0
  34. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev/test.py +0 -0
  35. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev.egg-info/dependency_links.txt +0 -0
  36. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev.egg-info/entry_points.txt +0 -0
  37. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev.egg-info/requires.txt +0 -0
  38. {nbdev-3.3.3 → nbdev-3.3.5}/nbdev.egg-info/top_level.txt +0 -0
  39. {nbdev-3.3.3 → nbdev-3.3.5}/pyproject.toml +0 -0
  40. {nbdev-3.3.3 → nbdev-3.3.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nbdev
3
- Version: 3.3.3
3
+ Version: 3.3.5
4
4
  Summary: Create delightful software with Jupyter Notebooks
5
5
  Author-email: "Jeremy Howard and the fast.ai community" <j@fast.ai>
6
6
  License: Apache-2.0
@@ -3,9 +3,10 @@
3
3
  Modules:
4
4
 
5
5
  - `nbdev.extract_attachments`: A preprocessor that extracts all of the attachments from the notebook file. The extracted attachments are returned in the 'resources' dictionary.
6
+ - `nbdev.moddocs`: # Module docs: creating them from existing notebooks
6
7
  - `nbdev.skill`: Author clear, executable nbdev notebooks where code, prose, examples, outputs, and tests form one coherent narrative."""
7
8
 
8
- __version__ = "3.3.3"
9
+ __version__ = "3.3.5"
9
10
 
10
11
  from .doclinks import nbdev_export
11
12
  from .showdoc import show_doc
@@ -210,6 +210,7 @@ d = { 'settings': { 'branch': 'main',
210
210
  'nbdev.migrate.migrate_nb': ('api/migrate.html#migrate_nb', 'nbdev/migrate.py'),
211
211
  'nbdev.migrate.nbdev_migrate': ('api/migrate.html#nbdev_migrate', 'nbdev/migrate.py'),
212
212
  'nbdev.migrate.nbdev_migrate_config': ('api/migrate.html#nbdev_migrate_config', 'nbdev/migrate.py')},
213
+ 'nbdev.moddocs': {},
213
214
  'nbdev.process': { 'nbdev.process.NBProcessor': ('api/process.html#nbprocessor', 'nbdev/process.py'),
214
215
  'nbdev.process.NBProcessor.__init__': ('api/process.html#nbprocessor.__init__', 'nbdev/process.py'),
215
216
  'nbdev.process.NBProcessor._proc': ('api/process.html#nbprocessor._proc', 'nbdev/process.py'),
@@ -0,0 +1,84 @@
1
+ r"""# Module docs: creating them from existing notebooks
2
+
3
+ Module docs are the LLM-facing documentation channel of an nbdev project: module docstrings, the package docstring, and `llms.txt`, all generated by `nbdev-export`. They ship inside the code, so they are there for every user of the library with no separate network lookup, and they cannot be stale relative to the installed version. They also make learning uniform. One call, `doc(foo)`, teaches a package, a module, a class, or a function, and plain `help(foo)` shows the same text. A reader works progressively: `llms.txt` or the package docstring says which modules matter, `doc(module)` teaches one module in a single read, and the `Docs:` URL ending each docstring leads to the full page when needed.
4
+
5
+ This guide covers one task. A project's notebooks already exist, and you are creating the module docs from them. General notebook authoring, and the `#| export`/`#| exportd` docstring mechanics, are `doc(nbdev.skill)`'s job. Read it first.
6
+
7
+ ## Creating a module's docs from its notebook
8
+
9
+ The notebook already contains the documentation. Its author made the content decisions when writing it: which ideas get prose, which examples demonstrate them, what matters. Creating module docs is a projection of that material, not new writing. The work is deciding which prose becomes the docstring, and reshaping it to stand alone.
10
+
11
+ Start with the baseline. Run `doc(module)` as-is and note what a reader gets today, usually the bare summary line. Then read the whole notebook, sorting its markdown into two kinds:
12
+
13
+ - Standalone prose, which teaches a concept without depending on the cells around it. These are tagging candidates.
14
+ - Cell-adjacent prose ("...to this:", "The code for `Int` is shown below:", six cells walking one function's variations). These cannot export as-is.
15
+
16
+ The mix decides between two options, and the user picks:
17
+
18
+ **Option 1: extract.** Build the docstring from the notebook's own narrative. When a cell stands alone, tag it `#| export` where it sits. When it nearly stands alone, reshape lightly first:
19
+
20
+ - Split the cell so only the standalone part is tagged.
21
+ - End a summary with a colon so it reads straight into a `#| exportd` demo.
22
+ - Fix wording that only works on the page, such as "the helpers below" or "as shown above".
23
+
24
+ Where a section's prose is all cell-adjacent, write one new summary cell under its heading, condensing what those cells teach: the idioms a reader could not guess from signatures, with the long tail left to the docs page. This improves the docs page at the same time, since a section that jumped straight into per-function detail was missing its overview anyway. When most of a module's docs can be tagged nearly as-is, the original notebook was authored well, and the docstring comes almost for free.
25
+
26
+ **Option 2: front block.** Write the docstring as a few fresh markdown cells right after the title, optionally with `#| exportd` demos between them, all tagged, forming one self-contained overview read top to bottom. Reach for this when extraction keeps producing fragments, when the notebook's structure doesn't match the story the docstring should tell, or when the user simply prefers it. It is the simplest safe default. Nothing the author wrote is touched, so nothing on the page changes, except that the page gains an overview at the top, which usually helps. Don't push for restructuring the whole notebook when a front block serves.
27
+
28
+ **Demos.** An existing example cell can often be tagged `#| exportd` as-is. A new demo must run after the definitions it uses, so its notebook position is constrained, but its docstring position is not. Only tagged cells assemble, so a summary and its demo sit adjacent in the docstring however many definition cells separate them in the notebook. Run every demo in notebook order and see it pass. Run code to check every prose claim too, since old prose can be stale, and a docstring stating something false is worse than one stating nothing.
29
+
30
+ **Iterate and review.** Preview with `nbdev.export.nb_mdoc(nbname)`, which shows the docstring the notebook would produce, until it reads well top to bottom. Then show the user every new and changed cell verbatim, as markdown and code with their directives. Cell ids and diffs are not reviewable. The actual text is. After export, read `doc(module)` the way the eventual reader will.
31
+
32
+ ## Creating the package docs from index.ipynb
33
+
34
+ The same projection applies at package level. `index.ipynb` already carries the project intro, and tagging markdown there feeds both the package docstring (written into `__init__.py`) and `llms.txt`. The pieces:
35
+
36
+ - The summary line is `[project].description` from `pyproject.toml`.
37
+ - Tag the intro paragraphs `#| export`. Tips lists, curated links, and a short `#| exportd` quick-start demo all project well. Installation instructions and marketing positioning stay untagged.
38
+ - The `Modules:` list assembles itself: every module whose docstring now says more than the default summary-plus-link is listed with its summary line. Finishing a module's docs is what lists it, so do the modules first and the package list follows.
39
+ - `llms.txt` is the same parts in llms.txt shape, written into `nbs/` on export.
40
+
41
+ ## Ask the user
42
+
43
+ - Which modules get docs at all, before starting. Internal, vendored, and niche modules can stay bare, which also keeps them out of the package listing. Leaving a module bare is itself a curation decision.
44
+ - The cut for each module, before writing: propose a summary paragraph and demo for the defining idioms, a sentence naming the supporting functions, and nothing for the rest, then wait for a steer.
45
+ - Whether existing page prose may be rewritten in place, since that changes the docs site too.
46
+ - Extract or front block. Present the choice with your read of how well the existing prose extracts, and let the user pick.
47
+ - Exact-output assertions in demos, when an exact string arguably is the contract, such as a rendered template or a signature.
48
+ - Anything discovered along the way. Report and propose stale claims in old prose, candidate deprecations, and missing features, and let the user decide. API changes are never part of a docs pass.
49
+
50
+ ## Worked example: fastcore.script
51
+
52
+ `fastcore/nbs/06_script.ipynb` opens with a bare title cell, then a tagged overview whose first line becomes the module summary:
53
+
54
+ # Script - CLI
55
+
56
+ [cell] #| export
57
+ Creates a CLI from a Python function decorated with `call_parse`.
58
+
59
+ The function's parameters become the script's arguments, its docstring becomes the program description, and its [docments](https://fastcore.fast.ai/docments.html) comments become the help for each argument.
60
+
61
+ Deeper in the notebook, after `is_cli` is defined, an existing summary and demo pair was tagged where it stood:
62
+
63
+ [cell] #| export
64
+ A function usable both from the command line and from Python can call `is_cli` to tell which way it was invoked, e.g. returning a value to Python callers but printing it (or exiting with an error code) when run as a CLI:
65
+
66
+ [cell] #| exportd
67
+ @call_parse
68
+ def sum_args(a:int=0, b:int=0):
69
+ "Add `a` and `b`"
70
+ if is_cli(): print(a+b)
71
+ else: return a+b
72
+
73
+ test_eq(sum_args(1,2), 3) # Python call: returns the value, prints nothing
74
+
75
+ In the assembled docstring the pair renders as the summary followed by a fenced python block, and the package artifacts pick the module up automatically. Its line in fastcore's `llms.txt`:
76
+
77
+ - [fastcore.script](https://fastcore.fast.ai/script.html.md): Creates a CLI from a Python function decorated with `call_parse`.
78
+
79
+ Points to notice:
80
+
81
+ - The docstring is a small fraction of the docs page, yet answers most usage questions. That ratio is the target.
82
+ - The overview and the `is_cli` pair were existing cells, tagged in place with light tightening.
83
+ - The "Param types" summary in the same notebook was condensed from scattered examples into a new cell, improving the page and the docstring together.
84
+ - The demo asserts the behavior it teaches, and its assertion runs in the notebook's test suite from then on."""
@@ -208,8 +208,10 @@ def _chk_nbdev_yml(path):
208
208
 
209
209
  # %% ../nbs/api/14_quarto.ipynb #6b880922
210
210
  def _pre_docs(path=None, n_workers:int=defaults.cpus, **kwargs):
211
- cfg = get_config()
212
- path = Path(path) if path else cfg.nbs_path
211
+ cfg = get_config(path)
212
+ path = Path(path).absolute() if path else cfg.nbs_path
213
+ if not (path/'nbdev.yml').exists(): path = cfg.nbs_path # given a project root, fall back to its configured nbs
214
+ os.chdir(cfg.config_path) # bare `get_config()` runs downstream (including in render workers), so anchor the cwd
213
215
  _chk_nbdev_yml(path)
214
216
  _ensure_quarto()
215
217
  refresh_quarto_yml()
@@ -272,12 +274,14 @@ def _save_cached_readme(cache, cfg):
272
274
  # %% ../nbs/api/14_quarto.ipynb #45d6bb5d
273
275
  @call_parse
274
276
  def nbdev_readme(
275
- path:str=None, # Path to notebooks
277
+ path:str=None, # Path to notebooks (or project root)
276
278
  chk_time:bool=False): # Only build if out of date
277
279
  "Create README.md from readme_nb (index.ipynb by default). Skips if the file doesn't exist."
278
- cfg = get_config()
279
- path = Path(path) if path else cfg.nbs_path
280
+ cfg = get_config(path)
281
+ path = Path(path).absolute() if path else cfg.nbs_path
282
+ if not (path/cfg.readme_nb).exists(): path = cfg.nbs_path # given a project root, fall back to its configured nbs
280
283
  if not (path/cfg.readme_nb).exists(): return
284
+ os.chdir(cfg.config_path) # bare `get_config()` runs downstream (including in render workers), so anchor the cwd
281
285
  _chk_nbdev_yml(path)
282
286
  if chk_time and _doc_mtime_not_older(cfg.config_path/'README.md', path/cfg.readme_nb): return
283
287
 
@@ -77,6 +77,7 @@ class Release:
77
77
  os.chdir(self.cfg.config_path)
78
78
  if repo and '/' in repo: owner,repo = repo.split('/', 1)
79
79
  owner,repo = owner or self.cfg.user, repo or self.cfg.repo
80
+ if not owner or not repo: raise Exception("Could not infer `user`/`repo` from config: add a `Repository` key under `[project.urls]` in pyproject.toml, or pass `repo='owner/repo'`")
80
81
  token = ifnone(token, os.getenv('NBDEV_TOKEN',None))
81
82
  if not token and Path('token').exists(): token = Path('token').read_text().strip()
82
83
  token = ifnone(token, os.getenv('GITHUB_TOKEN',None))
@@ -98,7 +99,7 @@ async def changelog(self:Release,
98
99
  try: self.commit_date = (lr:=await self.gh.repos.get_latest_release()).published_at
99
100
  except APIError as e:
100
101
  if e.status_code != 404: raise
101
- lr,self.commit_date = None,'2000-01-01T00:00:004Z'
102
+ lr,self.commit_date = None,'2000-01-01T00:00:00Z'
102
103
  if lr:
103
104
  run('git fetch --tags --quiet')
104
105
  _check_changelog_base(lr.tag_name)
@@ -355,14 +356,16 @@ def chk_conda_rel(
355
356
  @call_parse
356
357
  def release_pypi(
357
358
  repository:str="pypi", # Respository to upload to (defined in ~/.pypirc)
358
- quiet:bool=False # Reduce output verbosity
359
+ quiet:bool=False, # Reduce output verbosity
360
+ verbose:bool=False # Pass --verbose to twine upload
359
361
  ):
360
362
  "Create and upload Python package to PyPI"
361
363
  _dir = get_config().lib_path.parent
362
364
  q = ' --quiet' if quiet else ''
363
365
  p = ' --disable-progress-bar' if quiet else ''
364
366
  system(f'cd {_dir} && rm -rf dist build && python -m build{q}')
365
- system(f'twine upload --repository {repository}{p} {_dir}/dist/*')
367
+ v = ' --verbose' if verbose else ''
368
+ system(f'twine upload{v} --repository {repository}{p} {_dir}/dist/*')
366
369
 
367
370
  # %% ../nbs/api/18_release.ipynb #06edfcb0
368
371
  @call_parse
@@ -70,7 +70,7 @@ def proc_nbs(
70
70
  file_re:str='', # Only process notebooks matching regex (other files are always included)
71
71
  **kwargs):
72
72
  "Process notebooks in `path` for docs rendering"
73
- cfg = get_config()
73
+ cfg = get_config(path or None)
74
74
  cache = cfg.config_path/'_proc'
75
75
  path = Path(path or cfg.nbs_path)
76
76
  files = nbglob(path, func=Path, file_glob='', file_re='', **kwargs)
@@ -72,6 +72,8 @@ Keep imports in dedicated import cells, define values near first use, reuse esta
72
72
 
73
73
  Everything here describes nbdev v3 (released Jan 2026, possibly after a model's training cutoff). Key user-visible changes from v2: config moved from `settings.ini` to `pyproject.toml`, with standard metadata in `[project]`, nbdev-specific keys in `[tool.nbdev]` (defaults `nbs_path='nbs'`, `doc_path='_docs'`), version in `__init__.py` via `dynamic = ["version"]`, and `_modidx` registered under `[project.entry-points.nbdev]`. CLI commands use hyphens (`nbdev-export`, `nbdev-test`, ...) though Python functions keep underscores. GitHub workflows use the v3 actions (`fastai/workflows/nbdev3-ci`, `quarto-ghp3`).
74
74
 
75
+ Directives can also live in cell *metadata*, under the `nbdev` key (`{"nbdev": {"export": "true"}}`), instead of `#|` comment lines. Export and the rest of the toolchain honor both; `mk_cell(source, metadata=...).directives` is the merged read, with the comment winning when both set the same key. The editing toolkit keeps the meta form visible: summaries show it bracketed after the type char (`id:c[export]:...` in nbio's `CellRow` and aidialog's previews), XML views render it as attrs (a bare `export` on the tag), and aidialog's `Message` offers `exported` (either form, read-only) and `meta_exported` (meta only, assignable), with `export=`/`meta=` params on the add functions.
76
+
75
77
  # Before you finish
76
78
 
77
79
  Each new test cell ran red then green, failing before the change and passing after. Re-read the touched section as a reader would, against the conventions above. Style damage breaks no test and no export, so the harm only shows on the docs page.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nbdev
3
- Version: 3.3.3
3
+ Version: 3.3.5
4
4
  Summary: Create delightful software with Jupyter Notebooks
5
5
  Author-email: "Jeremy Howard and the fast.ai community" <j@fast.ai>
6
6
  License: Apache-2.0
@@ -17,6 +17,7 @@ nbdev/imports.py
17
17
  nbdev/maker.py
18
18
  nbdev/merge.py
19
19
  nbdev/migrate.py
20
+ nbdev/moddocs.py
20
21
  nbdev/process.py
21
22
  nbdev/processors.py
22
23
  nbdev/qmd.py
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