nbdev 2.3.27__tar.gz → 2.3.28__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 (38) hide show
  1. {nbdev-2.3.27/nbdev.egg-info → nbdev-2.3.28}/PKG-INFO +3 -2
  2. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/__init__.py +1 -1
  3. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/_modidx.py +1 -0
  4. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/clean.py +17 -15
  5. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/cli.py +10 -8
  6. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/config.py +21 -26
  7. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/doclinks.py +16 -14
  8. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/export.py +22 -15
  9. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/frontmatter.py +5 -3
  10. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/maker.py +28 -26
  11. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/merge.py +11 -9
  12. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/migrate.py +19 -17
  13. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/process.py +16 -14
  14. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/processors.py +26 -24
  15. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/qmd.py +9 -7
  16. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/quarto.py +25 -21
  17. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/release.py +30 -28
  18. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/serve.py +6 -4
  19. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/showdoc.py +17 -15
  20. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/sync.py +10 -8
  21. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/test.py +6 -4
  22. {nbdev-2.3.27 → nbdev-2.3.28/nbdev.egg-info}/PKG-INFO +3 -2
  23. {nbdev-2.3.27 → nbdev-2.3.28}/settings.ini +2 -2
  24. {nbdev-2.3.27 → nbdev-2.3.28}/setup.py +1 -1
  25. {nbdev-2.3.27 → nbdev-2.3.28}/CONTRIBUTING.md +0 -0
  26. {nbdev-2.3.27 → nbdev-2.3.28}/LICENSE +0 -0
  27. {nbdev-2.3.27 → nbdev-2.3.28}/MANIFEST.in +0 -0
  28. {nbdev-2.3.27 → nbdev-2.3.28}/README.md +0 -0
  29. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/extract_attachments.py +0 -0
  30. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/imports.py +0 -0
  31. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev/serve_drv.py +0 -0
  32. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev.egg-info/SOURCES.txt +0 -0
  33. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev.egg-info/dependency_links.txt +0 -0
  34. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev.egg-info/entry_points.txt +0 -0
  35. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev.egg-info/not-zip-safe +0 -0
  36. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev.egg-info/requires.txt +0 -0
  37. {nbdev-2.3.27 → nbdev-2.3.28}/nbdev.egg-info/top_level.txt +0 -0
  38. {nbdev-2.3.27 → nbdev-2.3.28}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nbdev
3
- Version: 2.3.27
3
+ Version: 2.3.28
4
4
  Summary: Create delightful software with Jupyter Notebooks
5
5
  Home-page: https://github.com/fastai/nbdev
6
6
  Author: Jeremy Howard and Hamel Husain
@@ -15,7 +15,8 @@ Classifier: Programming Language :: Python :: 3.7
15
15
  Classifier: Programming Language :: Python :: 3.8
16
16
  Classifier: Programming Language :: Python :: 3.9
17
17
  Classifier: Programming Language :: Python :: 3.10
18
- Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
19
20
  Classifier: License :: OSI Approved :: Apache Software License
20
21
  Requires-Python: >=3.7
21
22
  Description-Content-Type: text/markdown
@@ -1,4 +1,4 @@
1
- __version__ = "2.3.27"
1
+ __version__ = "2.3.28"
2
2
 
3
3
  from .doclinks import nbdev_export
4
4
  from .showdoc import show_doc
@@ -71,6 +71,7 @@ d = { 'settings': { 'branch': 'master',
71
71
  'nbdev.doclinks.nbglob_cli': ('api/doclinks.html#nbglob_cli', 'nbdev/doclinks.py'),
72
72
  'nbdev.doclinks.patch_name': ('api/doclinks.html#patch_name', 'nbdev/doclinks.py')},
73
73
  'nbdev.export': { 'nbdev.export.ExportModuleProc': ('api/export.html#exportmoduleproc', 'nbdev/export.py'),
74
+ 'nbdev.export.ExportModuleProc.__call__': ('api/export.html#exportmoduleproc.__call__', 'nbdev/export.py'),
74
75
  'nbdev.export.ExportModuleProc._default_exp_': ( 'api/export.html#exportmoduleproc._default_exp_',
75
76
  'nbdev/export.py'),
76
77
  'nbdev.export.ExportModuleProc._export_': ('api/export.html#exportmoduleproc._export_', 'nbdev/export.py'),
@@ -1,9 +1,11 @@
1
+ """Strip superfluous metadata from notebooks"""
2
+
1
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/11_clean.ipynb.
2
4
 
3
5
  # %% auto 0
4
6
  __all__ = ['nbdev_trust', 'clean_nb', 'process_write', 'nbdev_clean', 'clean_jupyter', 'nbdev_install_hooks']
5
7
 
6
- # %% ../nbs/api/11_clean.ipynb 2
8
+ # %% ../nbs/api/11_clean.ipynb
7
9
  import ast,warnings,stat
8
10
  from astunparse import unparse
9
11
  from textwrap import indent
@@ -18,7 +20,7 @@ from .config import *
18
20
  from .sync import *
19
21
  from .process import first_code_ln
20
22
 
21
- # %% ../nbs/api/11_clean.ipynb 6
23
+ # %% ../nbs/api/11_clean.ipynb
22
24
  @call_parse
23
25
  def nbdev_trust(
24
26
  fname:str=None, # A notebook name or glob to trust
@@ -45,7 +47,7 @@ def nbdev_trust(
45
47
  if not NotebookNotary().check_signature(nb): NotebookNotary().sign(nb)
46
48
  check_fname.touch(exist_ok=True)
47
49
 
48
- # %% ../nbs/api/11_clean.ipynb 9
50
+ # %% ../nbs/api/11_clean.ipynb
49
51
  _repr_id_re = re.compile('(<.*?)( at 0x[0-9a-fA-F]+)(>)')
50
52
 
51
53
  _sub = partial(_repr_id_re.sub, r'\1\3')
@@ -55,7 +57,7 @@ def _skip_or_sub(x): return _sub(x) if "at 0x" in x else x
55
57
  def _clean_cell_output_id(lines):
56
58
  return _skip_or_sub(lines) if isinstance(lines,str) else [_skip_or_sub(o) for o in lines]
57
59
 
58
- # %% ../nbs/api/11_clean.ipynb 11
60
+ # %% ../nbs/api/11_clean.ipynb
59
61
  def _clean_cell_output(cell, clean_ids):
60
62
  "Remove `cell` output execution count and optionally ids from text reprs"
61
63
  outputs = cell.get('outputs', [])
@@ -69,7 +71,7 @@ def _clean_cell_output(cell, clean_ids):
69
71
  if 'text' in o and clean_ids: o['text'] = _clean_cell_output_id(o['text'])
70
72
  o.get('metadata', {}).pop('tags', None)
71
73
 
72
- # %% ../nbs/api/11_clean.ipynb 12
74
+ # %% ../nbs/api/11_clean.ipynb
73
75
  def _clean_cell(cell, clear_all, allowed_metadata_keys, clean_ids):
74
76
  "Clean `cell` by removing superfluous metadata or everything except the input if `clear_all`"
75
77
  if 'execution_count' in cell: cell['execution_count'] = None
@@ -80,7 +82,7 @@ def _clean_cell(cell, clear_all, allowed_metadata_keys, clean_ids):
80
82
  cell['metadata'] = {} if clear_all else {
81
83
  k:v for k,v in cell['metadata'].items() if k in allowed_metadata_keys}
82
84
 
83
- # %% ../nbs/api/11_clean.ipynb 13
85
+ # %% ../nbs/api/11_clean.ipynb
84
86
  def clean_nb(
85
87
  nb, # The notebook to clean
86
88
  clear_all=False, # Remove all cell metadata and cell outputs?
@@ -98,12 +100,12 @@ def clean_nb(
98
100
  nb['metadata']['kernelspec']['display_name'] = nb["metadata"]["kernelspec"]["name"]
99
101
  nb['metadata'] = {k:v for k,v in nb['metadata'].items() if k in metadata_keys}
100
102
 
101
- # %% ../nbs/api/11_clean.ipynb 26
103
+ # %% ../nbs/api/11_clean.ipynb
102
104
  def _reconfigure(*strms):
103
105
  for s in strms:
104
106
  if hasattr(s,'reconfigure'): s.reconfigure(encoding='utf-8')
105
107
 
106
- # %% ../nbs/api/11_clean.ipynb 27
108
+ # %% ../nbs/api/11_clean.ipynb
107
109
  def process_write(warn_msg, proc_nb, f_in, f_out=None, disp=False):
108
110
  if not f_out: f_out = f_in
109
111
  if isinstance(f_in, (str,Path)): f_in = Path(f_in).open(encoding="utf-8")
@@ -116,7 +118,7 @@ def process_write(warn_msg, proc_nb, f_in, f_out=None, disp=False):
116
118
  warn(f'{warn_msg}')
117
119
  warn(e)
118
120
 
119
- # %% ../nbs/api/11_clean.ipynb 28
121
+ # %% ../nbs/api/11_clean.ipynb
120
122
  def _nbdev_clean(nb, path=None, clear_all=None):
121
123
  cfg = get_config(path=path)
122
124
  clear_all = clear_all or cfg.clear_all
@@ -125,7 +127,7 @@ def _nbdev_clean(nb, path=None, clear_all=None):
125
127
  clean_nb(nb, clear_all, allowed_metadata_keys, allowed_cell_metadata_keys, cfg.clean_ids)
126
128
  if path: nbdev_trust.__wrapped__(path)
127
129
 
128
- # %% ../nbs/api/11_clean.ipynb 29
130
+ # %% ../nbs/api/11_clean.ipynb
129
131
  @call_parse
130
132
  def nbdev_clean(
131
133
  fname:str=None, # A notebook name or glob to clean
@@ -141,7 +143,7 @@ def nbdev_clean(
141
143
  if fname is None: fname = get_config().nbs_path
142
144
  for f in globtastic(fname, file_glob='*.ipynb', skip_folder_re='^[_.]'): _write(f_in=f, disp=disp)
143
145
 
144
- # %% ../nbs/api/11_clean.ipynb 32
146
+ # %% ../nbs/api/11_clean.ipynb
145
147
  def clean_jupyter(path, model, **kwargs):
146
148
  "Clean Jupyter `model` pre save to `path`"
147
149
  if not (model['type']=='notebook' and model['content']['nbformat']==4): return
@@ -149,7 +151,7 @@ def clean_jupyter(path, model, **kwargs):
149
151
  jupyter_hooks = get_config(path=path).jupyter_hooks
150
152
  if jupyter_hooks: _nbdev_clean(model['content'], path=path)
151
153
 
152
- # %% ../nbs/api/11_clean.ipynb 35
154
+ # %% ../nbs/api/11_clean.ipynb
153
155
  _pre_save_hook_src = '''
154
156
  def nbdev_clean_jupyter(**kwargs):
155
157
  try: from nbdev.clean import clean_jupyter
@@ -159,7 +161,7 @@ def nbdev_clean_jupyter(**kwargs):
159
161
  c.ContentsManager.pre_save_hook = nbdev_clean_jupyter'''.strip()
160
162
  _pre_save_hook_re = re.compile(r'c\.(File)?ContentsManager\.pre_save_hook')
161
163
 
162
- # %% ../nbs/api/11_clean.ipynb 36
164
+ # %% ../nbs/api/11_clean.ipynb
163
165
  def _add_jupyter_hooks(src, path):
164
166
  if _pre_save_hook_src in src: return
165
167
  mod = ast.parse(src)
@@ -177,12 +179,12 @@ def _add_jupyter_hooks(src, path):
177
179
  if src: src+='\n\n'
178
180
  return src+_pre_save_hook_src
179
181
 
180
- # %% ../nbs/api/11_clean.ipynb 40
182
+ # %% ../nbs/api/11_clean.ipynb
181
183
  def _git_root():
182
184
  try: return Path(run('git rev-parse --show-toplevel'))
183
185
  except OSError: return None
184
186
 
185
- # %% ../nbs/api/11_clean.ipynb 43
187
+ # %% ../nbs/api/11_clean.ipynb
186
188
  @call_parse
187
189
  def nbdev_install_hooks():
188
190
  "Install Jupyter and git hooks to automatically clean, trust, and fix merge conflicts in notebooks"
@@ -1,3 +1,5 @@
1
+ """CLI commands"""
2
+
1
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/13_cli.ipynb.
2
4
 
3
5
  # %% ../nbs/api/13_cli.ipynb 2
@@ -27,7 +29,7 @@ import os, tarfile, sys
27
29
  # %% auto 0
28
30
  __all__ = ['mapping', 'nbdev_filter', 'extract_tgz', 'nbdev_new', 'nbdev_update_license', 'chelp']
29
31
 
30
- # %% ../nbs/api/13_cli.ipynb 5
32
+ # %% ../nbs/api/13_cli.ipynb
31
33
  @call_parse
32
34
  def nbdev_filter(
33
35
  nb_txt:str=None, # Notebook text (uses stdin if not provided)
@@ -50,12 +52,12 @@ def nbdev_filter(
50
52
  if printit: print(res, flush=True)
51
53
  else: return res
52
54
 
53
- # %% ../nbs/api/13_cli.ipynb 8
55
+ # %% ../nbs/api/13_cli.ipynb
54
56
  def extract_tgz(url, dest='.'):
55
57
  from fastcore.net import urlopen
56
58
  with urlopen(url) as u: tarfile.open(mode='r:gz', fileobj=u).extractall(dest)
57
59
 
58
- # %% ../nbs/api/13_cli.ipynb 9
60
+ # %% ../nbs/api/13_cli.ipynb
59
61
  def _render_nb(fn, cfg):
60
62
  "Render templated values like `{{lib_name}}` in notebook at `fn` from `cfg`"
61
63
  txt = fn.read_text()
@@ -63,7 +65,7 @@ def _render_nb(fn, cfg):
63
65
  for k,v in cfg.d.items(): txt = txt.replace('{{'+k+'}}', v)
64
66
  fn.write_text(txt)
65
67
 
66
- # %% ../nbs/api/13_cli.ipynb 10
68
+ # %% ../nbs/api/13_cli.ipynb
67
69
  def _update_repo_meta(cfg):
68
70
  "Enable gh pages and update the homepage and description in your GitHub repo."
69
71
  token=os.getenv('GITHUB_TOKEN')
@@ -74,7 +76,7 @@ def _update_repo_meta(cfg):
74
76
  except HTTPError:print(f"Could not update the description & URL on the repo: {cfg.user}/{cfg.repo} using $GITHUB_TOKEN.\n"
75
77
  "Use a token with the correction permissions or perform these steps manually.")
76
78
 
77
- # %% ../nbs/api/13_cli.ipynb 11
79
+ # %% ../nbs/api/13_cli.ipynb
78
80
  @call_parse
79
81
  @delegates(nbdev_create_config)
80
82
  def nbdev_new(**kwargs):
@@ -123,7 +125,7 @@ def nbdev_new(**kwargs):
123
125
  nbdev_export.__wrapped__()
124
126
  nbdev_readme.__wrapped__()
125
127
 
126
- # %% ../nbs/api/13_cli.ipynb 13
128
+ # %% ../nbs/api/13_cli.ipynb
127
129
  mapping = {
128
130
  'mit': 'mit',
129
131
  'apache2': 'apache-2.0',
@@ -132,7 +134,7 @@ mapping = {
132
134
  'bsd3': 'bsd-3-clause'
133
135
  }
134
136
 
135
- # %% ../nbs/api/13_cli.ipynb 14
137
+ # %% ../nbs/api/13_cli.ipynb
136
138
  @call_parse
137
139
  def nbdev_update_license(
138
140
  to: str=None, # update license to
@@ -163,7 +165,7 @@ def nbdev_update_license(
163
165
  lic.write(body)
164
166
  print(f"License updated from {curr_lic} to {to}")
165
167
 
166
- # %% ../nbs/api/13_cli.ipynb 17
168
+ # %% ../nbs/api/13_cli.ipynb
167
169
  @call_parse
168
170
  def chelp():
169
171
  "Show help for all console scripts"
@@ -1,5 +1,4 @@
1
- """Read and write nbdev's `settings.ini` file.
2
- `get_config` is the main function for reading settings."""
1
+ """Configuring nbdev and bootstrapping notebook export"""
3
2
 
4
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/01_config.ipynb.
5
4
 
@@ -7,11 +6,7 @@
7
6
  __all__ = ['nbdev_create_config', 'get_config', 'config_key', 'create_output', 'show_src', 'update_version', 'add_init',
8
7
  'write_cells']
9
8
 
10
- # %% ../nbs/api/01_config.ipynb 2
11
- _doc_ = """Read and write nbdev's `settings.ini` file.
12
- `get_config` is the main function for reading settings."""
13
-
14
- # %% ../nbs/api/01_config.ipynb 3
9
+ # %% ../nbs/api/01_config.ipynb
15
10
  from datetime import datetime
16
11
  from fastcore.docments import *
17
12
  from fastcore.utils import *
@@ -25,16 +20,16 @@ from IPython.display import Markdown
25
20
  from execnb.nbio import read_nb,NbCell
26
21
  from urllib.error import HTTPError
27
22
 
28
- # %% ../nbs/api/01_config.ipynb 8
23
+ # %% ../nbs/api/01_config.ipynb
29
24
  _nbdev_home_dir = 'nbdev' # sub-directory of xdg base dir
30
25
  _nbdev_cfg_name = 'settings.ini'
31
26
 
32
- # %% ../nbs/api/01_config.ipynb 9
27
+ # %% ../nbs/api/01_config.ipynb
33
28
  def _git_repo():
34
29
  try: return repo_details(run('git config --get remote.origin.url'))[1]
35
30
  except OSError: return
36
31
 
37
- # %% ../nbs/api/01_config.ipynb 11
32
+ # %% ../nbs/api/01_config.ipynb
38
33
  # When adding a named default to the list below, be sure that that name
39
34
  # is also added to one of the sections in `_nbdev_cfg_sections` as well,
40
35
  # or it won't get written by `nbdev_create_config`:
@@ -82,7 +77,7 @@ def _apply_defaults(
82
77
  cfg[k] = v
83
78
  return cfg
84
79
 
85
- # %% ../nbs/api/01_config.ipynb 12
80
+ # %% ../nbs/api/01_config.ipynb
86
81
  def _get_info(owner, repo, default_branch='main', default_kw='nbdev'):
87
82
  from ghapi.all import GhApi
88
83
  api = GhApi(owner=owner, repo=repo, token=os.getenv('GITHUB_TOKEN'))
@@ -98,7 +93,7 @@ https://nbdev.fast.ai/api/release.html#setup"""]
98
93
 
99
94
  return r.default_branch, default_kw if not getattr(r, 'topics', []) else ' '.join(r.topics), r.description
100
95
 
101
- # %% ../nbs/api/01_config.ipynb 14
96
+ # %% ../nbs/api/01_config.ipynb
102
97
  def _fetch_from_git(raise_err=False):
103
98
  "Get information for settings.ini from the user."
104
99
  res={}
@@ -114,7 +109,7 @@ def _fetch_from_git(raise_err=False):
114
109
  else: res['lib_name'] = res['repo'].replace('-','_')
115
110
  return res
116
111
 
117
- # %% ../nbs/api/01_config.ipynb 16
112
+ # %% ../nbs/api/01_config.ipynb
118
113
  def _prompt_user(cfg, inferred):
119
114
  "Let user input values not in `cfg` or `inferred`."
120
115
  res = cfg.copy()
@@ -128,7 +123,7 @@ def _prompt_user(cfg, inferred):
128
123
  print(msg+res[k]+' # Automatically inferred from git')
129
124
  return res
130
125
 
131
- # %% ../nbs/api/01_config.ipynb 18
126
+ # %% ../nbs/api/01_config.ipynb
132
127
  def _cfg2txt(cfg, head, sections, tail=''):
133
128
  "Render `cfg` with commented sections."
134
129
  nm = cfg.d.name
@@ -140,7 +135,7 @@ def _cfg2txt(cfg, head, sections, tail=''):
140
135
  res += tail
141
136
  return res.strip()
142
137
 
143
- # %% ../nbs/api/01_config.ipynb 20
138
+ # %% ../nbs/api/01_config.ipynb
144
139
  _nbdev_cfg_head = '''# All sections below are required unless otherwise specified.
145
140
  # See https://github.com/fastai/nbdev/blob/master/settings.ini for examples.
146
141
 
@@ -157,7 +152,7 @@ _nbdev_cfg_tail = '''### Optional ###
157
152
  # package_data =
158
153
  '''
159
154
 
160
- # %% ../nbs/api/01_config.ipynb 21
155
+ # %% ../nbs/api/01_config.ipynb
161
156
  @call_parse
162
157
  @delegates(_apply_defaults, but='cfg')
163
158
  def nbdev_create_config(
@@ -183,19 +178,19 @@ def nbdev_create_config(
183
178
  cfg_fn = Path(path)/cfg_name
184
179
  print(f'{cfg_fn} created.')
185
180
 
186
- # %% ../nbs/api/01_config.ipynb 24
181
+ # %% ../nbs/api/01_config.ipynb
187
182
  def _nbdev_config_file(cfg_name=_nbdev_cfg_name, path=None):
188
183
  cfg_path = path = Path.cwd() if path is None else Path(path)
189
184
  while cfg_path != cfg_path.parent and not (cfg_path/cfg_name).exists(): cfg_path = cfg_path.parent
190
185
  if not (cfg_path/cfg_name).exists(): cfg_path = path
191
186
  return cfg_path/cfg_name
192
187
 
193
- # %% ../nbs/api/01_config.ipynb 26
188
+ # %% ../nbs/api/01_config.ipynb
194
189
  def _xdg_config_paths(cfg_name=_nbdev_cfg_name):
195
190
  xdg_config_paths = reversed([xdg_config_home()]+xdg_config_dirs())
196
191
  return [o/_nbdev_home_dir/cfg_name for o in xdg_config_paths]
197
192
 
198
- # %% ../nbs/api/01_config.ipynb 27
193
+ # %% ../nbs/api/01_config.ipynb
199
194
  def _type(t): return bool if t==bool_arg else t
200
195
  _types = {k:_type(v['anno']) for k,v in docments(_apply_defaults,full=True,returns=False).items() if k != 'cfg'}
201
196
 
@@ -207,22 +202,22 @@ def get_config(cfg_name=_nbdev_cfg_name, path=None):
207
202
  cfg = Config(cfg_file.parent, cfg_file.name, extra_files=extra_files, types=_types)
208
203
  return _apply_defaults(cfg)
209
204
 
210
- # %% ../nbs/api/01_config.ipynb 42
205
+ # %% ../nbs/api/01_config.ipynb
211
206
  def config_key(c, default=None, path=True, missing_ok=None):
212
207
  "Deprecated: use `get_config().get` or `get_config().path` instead."
213
208
  warn("`config_key` is deprecated. Use `get_config().get` or `get_config().path` instead.", DeprecationWarning)
214
209
  return get_config().path(c, default) if path else get_config().get(c, default)
215
210
 
216
- # %% ../nbs/api/01_config.ipynb 44
211
+ # %% ../nbs/api/01_config.ipynb
217
212
  def create_output(txt, mime):
218
213
  "Add a cell output containing `txt` of the `mime` text MIME sub-type"
219
214
  return [{"data": { f"text/{mime}": str(txt).splitlines(True) },
220
215
  "execution_count": 1, "metadata": {}, "output_type": "execute_result"}]
221
216
 
222
- # %% ../nbs/api/01_config.ipynb 45
217
+ # %% ../nbs/api/01_config.ipynb
223
218
  def show_src(src, lang='python'): return Markdown(f'```{lang}\n{src}\n```')
224
219
 
225
- # %% ../nbs/api/01_config.ipynb 48
220
+ # %% ../nbs/api/01_config.ipynb
226
221
  _re_version = re.compile(r'^__version__\s*=.*$', re.MULTILINE)
227
222
  _init = '__init__.py'
228
223
 
@@ -251,15 +246,15 @@ def add_init(path=None):
251
246
  if _has_py(fs) or any(filter(_has_py, subds)) and not (r/_init).exists(): (r/_init).touch()
252
247
  if get_config().get('put_version_in_init', True): update_version(path)
253
248
 
254
- # %% ../nbs/api/01_config.ipynb 51
249
+ # %% ../nbs/api/01_config.ipynb
255
250
  def write_cells(cells, hdr, file, offset=0, cell_number=True):
256
251
  "Write `cells` to `file` along with header `hdr` starting at index `offset` (mainly for nbdev internal use)."
257
252
  for cell in cells:
258
- if cell.source.strip():
253
+ if cell.cell_type=='code' and cell.source.strip():
259
254
  idx = f" {cell.idx_+offset}" if cell_number else ""
260
255
  file.write(f'\n\n{hdr}{idx}\n{cell.source}')
261
256
 
262
- # %% ../nbs/api/01_config.ipynb 52
257
+ # %% ../nbs/api/01_config.ipynb
263
258
  def _basic_export_nb(fname, name, dest=None):
264
259
  "Basic exporter to bootstrap nbdev."
265
260
  if dest is None: dest = get_config().lib_path
@@ -1,9 +1,11 @@
1
+ """Generating a documentation index from a module"""
2
+
1
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/05_doclinks.ipynb.
2
4
 
3
5
  # %% auto 0
4
6
  __all__ = ['patch_name', 'nbglob', 'nbglob_cli', 'nbdev_export', 'NbdevLookup']
5
7
 
6
- # %% ../nbs/api/05_doclinks.ipynb 2
8
+ # %% ../nbs/api/05_doclinks.ipynb
7
9
  from .config import *
8
10
  from .maker import *
9
11
  from .export import *
@@ -21,7 +23,7 @@ from pprint import pformat
21
23
  from urllib.parse import urljoin
22
24
  from functools import lru_cache
23
25
 
24
- # %% ../nbs/api/05_doclinks.ipynb 5
26
+ # %% ../nbs/api/05_doclinks.ipynb
25
27
  def _sym_nm(klas, sym): return f'{unparse(klas).strip()}.{sym.name}'
26
28
 
27
29
  def _binop_leafs(bo, o):
@@ -42,7 +44,7 @@ def patch_name(o):
42
44
  else: return o.name
43
45
  return _sym_nm(a,o)
44
46
 
45
- # %% ../nbs/api/05_doclinks.ipynb 9
47
+ # %% ../nbs/api/05_doclinks.ipynb
46
48
  def _iter_py_cells(p):
47
49
  "Yield cells from an exported Python file."
48
50
  p = Path(p)
@@ -64,10 +66,10 @@ def _iter_py_cells(p):
64
66
  if code.endswith('\n'): code=code[:-1]
65
67
  yield AttrDict(nb=nb, idx=idx, code=code, nb_path=nb_path, py_path=p.resolve())
66
68
 
67
- # %% ../nbs/api/05_doclinks.ipynb 11
69
+ # %% ../nbs/api/05_doclinks.ipynb
68
70
  def _nbpath2html(p): return p.with_name(re.sub(r'^\d+[a-zA-Z0-9]*_', '', p.name.lower())).with_suffix('.html')
69
71
 
70
- # %% ../nbs/api/05_doclinks.ipynb 13
72
+ # %% ../nbs/api/05_doclinks.ipynb
71
73
  def _get_modidx(py_path, code_root, nbs_path):
72
74
  "Get module symbol index for a Python source file"
73
75
  cfg = get_config()
@@ -89,7 +91,7 @@ def _get_modidx(py_path, code_root, nbs_path):
89
91
  if isinstance(t2, _def_types): _stor(f'{tree.name}.{t2.name}')
90
92
  return {mod_name: d}
91
93
 
92
- # %% ../nbs/api/05_doclinks.ipynb 15
94
+ # %% ../nbs/api/05_doclinks.ipynb
93
95
  def _build_modidx(dest=None, nbs_path=None, skip_exists=False):
94
96
  "Create _modidx.py"
95
97
  if dest is None: dest = get_config().lib_path
@@ -108,7 +110,7 @@ def _build_modidx(dest=None, nbs_path=None, skip_exists=False):
108
110
  res['syms'].update(_get_modidx((dest.parent/file).resolve(), code_root, nbs_path=nbs_path))
109
111
  idxfile.write_text("# Autogenerated by nbdev\n\nd = "+pformat(res, width=140, indent=2, compact=True)+'\n')
110
112
 
111
- # %% ../nbs/api/05_doclinks.ipynb 20
113
+ # %% ../nbs/api/05_doclinks.ipynb
112
114
  @delegates(globtastic)
113
115
  def nbglob(path=None, skip_folder_re = '^[_.]', file_glob='*.ipynb', skip_file_re='^[_.]', key='nbs_path', as_path=False, **kwargs):
114
116
  "Find all files in a directory matching an extension given a config key."
@@ -118,7 +120,7 @@ def nbglob(path=None, skip_folder_re = '^[_.]', file_glob='*.ipynb', skip_file_r
118
120
  skip_file_re=skip_file_re, recursive=recursive, **kwargs)
119
121
  return res.map(Path) if as_path else res
120
122
 
121
- # %% ../nbs/api/05_doclinks.ipynb 21
123
+ # %% ../nbs/api/05_doclinks.ipynb
122
124
  def nbglob_cli(
123
125
  path:str=None, # Path to notebooks
124
126
  symlinks:bool=False, # Follow symlinks?
@@ -132,7 +134,7 @@ def nbglob_cli(
132
134
  return nbglob(path, symlinks=symlinks, file_glob=file_glob, file_re=file_re, folder_re=folder_re,
133
135
  skip_file_glob=skip_file_glob, skip_file_re=skip_file_re, skip_folder_re=skip_folder_re)
134
136
 
135
- # %% ../nbs/api/05_doclinks.ipynb 22
137
+ # %% ../nbs/api/05_doclinks.ipynb
136
138
  @call_parse
137
139
  @delegates(nbglob_cli)
138
140
  def nbdev_export(
@@ -149,11 +151,11 @@ def nbdev_export(
149
151
  add_init(get_config().lib_path)
150
152
  _build_modidx()
151
153
 
152
- # %% ../nbs/api/05_doclinks.ipynb 25
154
+ # %% ../nbs/api/05_doclinks.ipynb
153
155
  import importlib,ast
154
156
  from functools import lru_cache
155
157
 
156
- # %% ../nbs/api/05_doclinks.ipynb 26
158
+ # %% ../nbs/api/05_doclinks.ipynb
157
159
  def _find_mod(mod):
158
160
  mp,_,mr = mod.partition('/')
159
161
  spec = importlib.util.find_spec(mp)
@@ -176,7 +178,7 @@ def _get_exps(mod):
176
178
 
177
179
  def _lineno(sym, fname): return _get_exps(fname).get(sym, None) if fname else None
178
180
 
179
- # %% ../nbs/api/05_doclinks.ipynb 28
181
+ # %% ../nbs/api/05_doclinks.ipynb
180
182
  def _qual_sym(s, settings):
181
183
  if not isinstance(s,tuple): return s
182
184
  nb,py = s
@@ -191,10 +193,10 @@ def _qual_syms(entries):
191
193
  if 'doc_host' not in settings: return entries
192
194
  return {'syms': {mod:_qual_mod(d, settings) for mod,d in entries['syms'].items()}, 'settings':settings}
193
195
 
194
- # %% ../nbs/api/05_doclinks.ipynb 29
196
+ # %% ../nbs/api/05_doclinks.ipynb
195
197
  _re_backticks = re.compile(r'`([^`\s]+)`')
196
198
 
197
- # %% ../nbs/api/05_doclinks.ipynb 30
199
+ # %% ../nbs/api/05_doclinks.ipynb
198
200
  @lru_cache(None)
199
201
  class NbdevLookup:
200
202
  "Mapping from symbol names to docs and source URLs"
@@ -1,9 +1,11 @@
1
+ """Exporting a notebook to a library"""
2
+
1
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/04_export.ipynb.
2
4
 
3
5
  # %% auto 0
4
6
  __all__ = ['ExportModuleProc', 'black_format', 'scrub_magics', 'optional_procs', 'nb_export']
5
7
 
6
- # %% ../nbs/api/04_export.ipynb 2
8
+ # %% ../nbs/api/04_export.ipynb
7
9
  from .config import *
8
10
  from .maker import *
9
11
  from .imports import *
@@ -15,7 +17,7 @@ from fastcore.imports import *
15
17
 
16
18
  from collections import defaultdict
17
19
 
18
- # %% ../nbs/api/04_export.ipynb 4
20
+ # %% ../nbs/api/04_export.ipynb
19
21
  class ExportModuleProc:
20
22
  "A processor which exports code to a module"
21
23
  def begin(self): self.modules,self.in_all = defaultdict(L),defaultdict(L)
@@ -24,9 +26,13 @@ class ExportModuleProc:
24
26
  def _export_(self, cell, exp_to=None):
25
27
  self._exporti_(cell, exp_to)
26
28
  self.in_all[ifnone(exp_to, '#')].append(cell)
29
+ def __call__(self, cell):
30
+ src = cell.source
31
+ if not src: return
32
+ if cell.cell_type=='markdown' and src.startswith('# '): self.modules['#'].append(cell)
27
33
  _exports_=_export_
28
34
 
29
- # %% ../nbs/api/04_export.ipynb 8
35
+ # %% ../nbs/api/04_export.ipynb
30
36
  def black_format(cell, # Cell to format
31
37
  force=False): # Turn black formatting on regardless of settings.ini
32
38
  "Processor to format code with `black`"
@@ -40,7 +46,7 @@ def black_format(cell, # Cell to format
40
46
  try: cell.source = _format_str(cell.source).strip()
41
47
  except: pass
42
48
 
43
- # %% ../nbs/api/04_export.ipynb 10
49
+ # %% ../nbs/api/04_export.ipynb
44
50
  # includes the newline, because calling .strip() would affect all cells.
45
51
  _magics_pattern = re.compile(r'^\s*(%%|%).*\n?', re.MULTILINE)
46
52
 
@@ -52,14 +58,14 @@ def scrub_magics(cell): # Cell to format
52
58
  try: cell.source = _magics_pattern.sub('', cell.source)
53
59
  except: pass
54
60
 
55
- # %% ../nbs/api/04_export.ipynb 13
61
+ # %% ../nbs/api/04_export.ipynb
56
62
  import nbdev.export
57
63
  def optional_procs():
58
64
  "An explicit list of processors that could be used by `nb_export`"
59
65
  return L([p for p in nbdev.export.__all__
60
66
  if p not in ["nb_export", "ExportModuleProc", "optional_procs"]])
61
67
 
62
- # %% ../nbs/api/04_export.ipynb 16
68
+ # %% ../nbs/api/04_export.ipynb
63
69
  def nb_export(nbname, lib_path=None, procs=None, debug=False, mod_maker=ModuleMaker, name=None):
64
70
  "Create module(s) from notebook"
65
71
  if lib_path is None: lib_path = get_config().lib_path
@@ -67,12 +73,13 @@ def nb_export(nbname, lib_path=None, procs=None, debug=False, mod_maker=ModuleMa
67
73
  nb = NBProcessor(nbname, [exp]+L(procs), debug=debug)
68
74
  nb.process()
69
75
  for mod,cells in exp.modules.items():
70
- all_cells = exp.in_all[mod]
71
- nm = ifnone(name, getattr(exp, 'default_exp', None) if mod=='#' else mod)
72
- if not nm:
73
- warn(f"Notebook '{nbname}' uses `#|export` without `#|default_exp` cell.\n"
74
- "Note nbdev2 no longer supports nbdev1 syntax. Run `nbdev_migrate` to upgrade.\n"
75
- "See https://nbdev.fast.ai/getting_started.html for more information.")
76
- return
77
- mm = mod_maker(dest=lib_path, name=nm, nb_path=nbname, is_new=bool(name) or mod=='#')
78
- mm.make(cells, all_cells, lib_path=lib_path)
76
+ if first(1 for o in cells if o.cell_type=='code'):
77
+ all_cells = exp.in_all[mod]
78
+ nm = ifnone(name, getattr(exp, 'default_exp', None) if mod=='#' else mod)
79
+ if not nm:
80
+ warn(f"Notebook '{nbname}' uses `#|export` without `#|default_exp` cell.\n"
81
+ "Note nbdev2 no longer supports nbdev1 syntax. Run `nbdev_migrate` to upgrade.\n"
82
+ "See https://nbdev.fast.ai/getting_started.html for more information.")
83
+ return
84
+ mm = mod_maker(dest=lib_path, name=nm, nb_path=nbname, is_new=bool(name) or mod=='#')
85
+ mm.make(cells, all_cells, lib_path=lib_path)
@@ -1,9 +1,11 @@
1
+ """A YAML and formatted-markdown frontmatter processor"""
2
+
1
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/09_frontmatter.ipynb.
2
4
 
3
5
  # %% auto 0
4
6
  __all__ = ['FrontmatterProc']
5
7
 
6
- # %% ../nbs/api/09_frontmatter.ipynb 2
8
+ # %% ../nbs/api/09_frontmatter.ipynb
7
9
  from .imports import *
8
10
  from .process import *
9
11
  from .doclinks import _nbpath2html
@@ -12,7 +14,7 @@ from execnb.nbio import *
12
14
  from fastcore.imports import *
13
15
  import yaml
14
16
 
15
- # %% ../nbs/api/09_frontmatter.ipynb 5
17
+ # %% ../nbs/api/09_frontmatter.ipynb
16
18
  _RE_FM_BASE=r'''^---\s*
17
19
  (.*?\S+.*?)
18
20
  ---\s*'''
@@ -40,7 +42,7 @@ def _md2dict(s:str):
40
42
  except Exception as e: warn(f'Failed to create YAML dict for:\n{r}\n\n{e}\n')
41
43
  return res
42
44
 
43
- # %% ../nbs/api/09_frontmatter.ipynb 6
45
+ # %% ../nbs/api/09_frontmatter.ipynb
44
46
  def _dict2fm(d): return f'---\n{yaml.dump(d)}\n---\n\n'
45
47
  def _insertfm(nb, fm): nb.cells.insert(0, mk_cell(_dict2fm(fm), 'raw'))
46
48