Skip to content

Commit 86b35cf

Browse files
committed
fixes #473
1 parent 9565f0f commit 86b35cf

File tree

5 files changed

+119
-74
lines changed

5 files changed

+119
-74
lines changed

nbdev/_modidx.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,14 @@
100100
'nbdev.maker._filt_dec': ('09_API/maker.html#_filt_dec', 'nbdev/maker.py'),
101101
'nbdev.maker._import2relative': ('09_API/maker.html#_import2relative', 'nbdev/maker.py'),
102102
'nbdev.maker._mark_text_ranges': ('09_API/maker.html#_mark_text_ranges', 'nbdev/maker.py'),
103+
'nbdev.maker._retr_mdoc': ('09_API/maker.html#_retr_mdoc', 'nbdev/maker.py'),
103104
'nbdev.maker._val_or_id': ('09_API/maker.html#_val_or_id', 'nbdev/maker.py'),
104105
'nbdev.maker._wants': ('09_API/maker.html#_wants', 'nbdev/maker.py'),
105106
'nbdev.maker.decor_id': ('09_API/maker.html#decor_id', 'nbdev/maker.py'),
106107
'nbdev.maker.find_var': ('09_API/maker.html#find_var', 'nbdev/maker.py'),
107108
'nbdev.maker.make_code_cells': ('09_API/maker.html#make_code_cells', 'nbdev/maker.py'),
108109
'nbdev.maker.read_var': ('09_API/maker.html#read_var', 'nbdev/maker.py'),
109110
'nbdev.maker.relative_import': ('09_API/maker.html#relative_import', 'nbdev/maker.py'),
110-
'nbdev.maker.retr_exports': ('09_API/maker.html#retr_exports', 'nbdev/maker.py'),
111111
'nbdev.maker.update_import': ('09_API/maker.html#update_import', 'nbdev/maker.py'),
112112
'nbdev.maker.update_var': ('09_API/maker.html#update_var', 'nbdev/maker.py')},
113113
'nbdev.merge': { 'nbdev.merge._git_branch_merge': ('09_API/merge.html#_git_branch_merge', 'nbdev/merge.py'),

nbdev/config.py

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
1+
"""Read and write nbdev's `settings.ini file.
2+
`get_config` is the main function for reading settings."""
3+
14
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/09_API/01_config.ipynb.
25

36
# %% auto 0
47
__all__ = ['nbdev_create_config', 'get_config', 'config_key', 'create_output', 'show_src', 'update_version', 'add_init',
58
'write_cells']
69

710
# %% ../nbs/09_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/09_API/01_config.ipynb 3
815
from datetime import datetime
916
from fastcore.utils import *
1017
from fastcore.meta import *
@@ -17,16 +24,16 @@
1724
from execnb.nbio import read_nb,NbCell
1825
from urllib.error import HTTPError
1926

20-
# %% ../nbs/09_API/01_config.ipynb 7
27+
# %% ../nbs/09_API/01_config.ipynb 8
2128
_nbdev_home_dir = 'nbdev' # sub-directory of xdg base dir
2229
_nbdev_cfg_name = 'settings.ini'
2330

24-
# %% ../nbs/09_API/01_config.ipynb 8
31+
# %% ../nbs/09_API/01_config.ipynb 9
2532
def _git_repo():
2633
try: return repo_details(run('git config --get remote.origin.url'))[1]
2734
except OSError: return
2835

29-
# %% ../nbs/09_API/01_config.ipynb 10
36+
# %% ../nbs/09_API/01_config.ipynb 11
3037
def _apply_defaults(
3138
cfg,
3239
lib_name='%(repo)s', # Package name
@@ -70,24 +77,23 @@ def _apply_defaults(
7077
cfg[k] = v
7178
return cfg
7279

73-
# %% ../nbs/09_API/01_config.ipynb 11
80+
# %% ../nbs/09_API/01_config.ipynb 12
7481
def _get_info(owner, repo, default_branch='main', default_kw='nbdev'):
7582
from ghapi.all import GhApi
7683
api = GhApi(owner=owner, repo=repo, token=os.getenv('GITHUB_TOKEN'))
7784

7885
try: r = api.repos.get()
7986
except HTTPError:
80-
msg= [f"""Could not access repo: {owner}/{repo} to find your default branch - `{default_branch} assumed.
87+
msg= [f"""Could not access repo: {owner}/{repo} to find your default branch - `{default_branch}` assumed.
8188
Edit `settings.ini` if this is incorrect.
8289
In the future, you can allow nbdev to see private repos by setting the environment variable GITHUB_TOKEN as described here:
83-
https://nbdev.fast.ai/cli.html#Using-nbdev_new-with-private-repos
84-
"""]
90+
https://nbdev.fast.ai/cli.html#Using-nbdev_new-with-private-repos"""]
8591
print(''.join(msg))
86-
return (default_branch,default_kw,'')
92+
return default_branch,default_kw,''
8793

8894
return r.default_branch, default_kw if not r.topics else ' '.join(r.topics), r.description
8995

90-
# %% ../nbs/09_API/01_config.ipynb 13
96+
# %% ../nbs/09_API/01_config.ipynb 14
9197
def _fetch_from_git(raise_err=False):
9298
"Get information for settings.ini from the user."
9399
res={}
@@ -103,7 +109,7 @@ def _fetch_from_git(raise_err=False):
103109
else: res['lib_name'] = res['repo'].replace('-','_')
104110
return res
105111

106-
# %% ../nbs/09_API/01_config.ipynb 15
112+
# %% ../nbs/09_API/01_config.ipynb 16
107113
def _prompt_user(cfg, inferred):
108114
"Let user input values not in `cfg` or `inferred`."
109115
res = cfg.copy()
@@ -117,7 +123,7 @@ def _prompt_user(cfg, inferred):
117123
print(msg+res[k]+' # Automatically inferred from git')
118124
return res
119125

120-
# %% ../nbs/09_API/01_config.ipynb 17
126+
# %% ../nbs/09_API/01_config.ipynb 18
121127
def _cfg2txt(cfg, head, sections, tail=''):
122128
"Render `cfg` with commented sections."
123129
nm = cfg.d.name
@@ -129,7 +135,7 @@ def _cfg2txt(cfg, head, sections, tail=''):
129135
res += tail
130136
return res.strip()
131137

132-
# %% ../nbs/09_API/01_config.ipynb 19
138+
# %% ../nbs/09_API/01_config.ipynb 20
133139
_nbdev_cfg_head = '''# All sections below are required unless otherwise specified.
134140
# See https://github.com/fastai/nbdev/blob/master/settings.ini for examples.
135141
@@ -144,7 +150,7 @@ def _cfg2txt(cfg, head, sections, tail=''):
144150
# console_scripts =
145151
'''
146152

147-
# %% ../nbs/09_API/01_config.ipynb 20
153+
# %% ../nbs/09_API/01_config.ipynb 21
148154
@call_parse
149155
@delegates(_apply_defaults, but='cfg')
150156
def nbdev_create_config(
@@ -169,19 +175,19 @@ def nbdev_create_config(
169175
cfg_fn = Path(path)/cfg_name
170176
print(f'{cfg_fn} created.')
171177

172-
# %% ../nbs/09_API/01_config.ipynb 23
178+
# %% ../nbs/09_API/01_config.ipynb 24
173179
def _nbdev_config_file(cfg_name=_nbdev_cfg_name, path=None):
174180
cfg_path = path = Path.cwd() if path is None else Path(path)
175181
while cfg_path != cfg_path.parent and not (cfg_path/cfg_name).exists(): cfg_path = cfg_path.parent
176182
if not (cfg_path/cfg_name).exists(): cfg_path = path
177183
return cfg_path/cfg_name
178184

179-
# %% ../nbs/09_API/01_config.ipynb 25
185+
# %% ../nbs/09_API/01_config.ipynb 26
180186
def _xdg_config_paths(cfg_name=_nbdev_cfg_name):
181187
xdg_config_paths = reversed([xdg_config_home()]+xdg_config_dirs())
182188
return [o/_nbdev_home_dir/cfg_name for o in xdg_config_paths]
183189

184-
# %% ../nbs/09_API/01_config.ipynb 26
190+
# %% ../nbs/09_API/01_config.ipynb 27
185191
_types = dict(custom_sidebar=bool, nbs_path=Path, lib_path=Path, doc_path=Path, recursive=bool,
186192
black_formatting=bool, jupyter_hooks=bool, clean_ids=bool, custom_quarto_yml=bool)
187193

@@ -193,22 +199,22 @@ def get_config(cfg_name=_nbdev_cfg_name, path=None):
193199
cfg = Config(cfg_file.parent, cfg_file.name, extra_files=extra_files, types=_types)
194200
return _apply_defaults(cfg)
195201

196-
# %% ../nbs/09_API/01_config.ipynb 41
202+
# %% ../nbs/09_API/01_config.ipynb 42
197203
def config_key(c, default=None, path=True, missing_ok=None):
198204
"Deprecated: use `get_config().get` or `get_config().path` instead."
199205
warn("`config_key` is deprecated. Use `get_config().get` or `get_config().path` instead.", DeprecationWarning)
200206
return get_config().path(c, default) if path else get_config().get(c, default)
201207

202-
# %% ../nbs/09_API/01_config.ipynb 43
208+
# %% ../nbs/09_API/01_config.ipynb 44
203209
def create_output(txt, mime):
204210
"Add a cell output containing `txt` of the `mime` text MIME sub-type"
205211
return [{"data": { f"text/{mime}": str(txt).splitlines(True) },
206212
"execution_count": 1, "metadata": {}, "output_type": "execute_result"}]
207213

208-
# %% ../nbs/09_API/01_config.ipynb 44
214+
# %% ../nbs/09_API/01_config.ipynb 45
209215
def show_src(src, lang='python'): return Markdown(f'```{lang}\n{src}\n```')
210216

211-
# %% ../nbs/09_API/01_config.ipynb 47
217+
# %% ../nbs/09_API/01_config.ipynb 48
212218
_re_version = re.compile('^__version__\s*=.*$', re.MULTILINE)
213219
_init = '__init__.py'
214220

@@ -237,13 +243,13 @@ def add_init(path=None):
237243
if _has_py(fs) or any(filter(_has_py, subds)) and not (r/_init).exists(): (r/_init).touch()
238244
update_version(path)
239245

240-
# %% ../nbs/09_API/01_config.ipynb 50
246+
# %% ../nbs/09_API/01_config.ipynb 51
241247
def write_cells(cells, hdr, file, offset=0):
242248
"Write `cells` to `file` along with header `hdr` starting at index `offset` (mainly for nbdev internal use)."
243249
for cell in cells:
244250
if cell.source.strip(): file.write(f'\n\n{hdr} {cell.idx_+offset}\n{cell.source}')
245251

246-
# %% ../nbs/09_API/01_config.ipynb 51
252+
# %% ../nbs/09_API/01_config.ipynb 52
247253
def _basic_export_nb(fname, name, dest=None):
248254
"Basic exporter to bootstrap nbdev."
249255
if dest is None: dest = get_config().lib_path

nbdev/maker.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
from __future__ import annotations
55

66
# %% auto 0
7-
__all__ = ['find_var', 'read_var', 'update_var', 'ModuleMaker', 'decor_id', 'retr_exports', 'make_code_cells', 'relative_import',
8-
'update_import']
7+
__all__ = ['find_var', 'read_var', 'update_var', 'ModuleMaker', 'decor_id', 'make_code_cells', 'relative_import', 'update_import']
98

109
# %% ../nbs/09_API/02_maker.ipynb 3
1110
from .config import *
@@ -88,7 +87,11 @@ def _filt_dec(x): return decor_id(x).startswith('patch')
8887
def _wants(o): return isinstance(o,_def_types) and not any(L(o.decorator_list).filter(_filt_dec))
8988

9089
# %% ../nbs/09_API/02_maker.ipynb 20
91-
def retr_exports(trees):
90+
@patch
91+
def make_all(self:ModuleMaker, cells):
92+
"Create `__all__` with all exports in `cells`"
93+
if cells is None: return ''
94+
trees = L(cells).map(NbCell.parsed_).concat()
9295
# include anything mentioned in "_all_", even if otherwise private
9396
# NB: "_all_" can include strings (names), or symbols, so we look for "id" or "value"
9497
assigns = trees.filter(risinstance(_assign_types))
@@ -101,16 +104,9 @@ def retr_exports(trees):
101104
return (exports+all_vals).unique()
102105

103106
# %% ../nbs/09_API/02_maker.ipynb 21
104-
@patch
105-
def make_all(self:ModuleMaker, cells):
106-
"Create `__all__` with all exports in `cells`"
107-
if cells is None: return ''
108-
return retr_exports(L(cells).map(NbCell.parsed_).concat())
109-
110-
# %% ../nbs/09_API/02_maker.ipynb 22
111107
def make_code_cells(*ss): return dict2nb({'cells':L(ss).map(mk_cell)}).cells
112108

113-
# %% ../nbs/09_API/02_maker.ipynb 25
109+
# %% ../nbs/09_API/02_maker.ipynb 24
114110
def relative_import(name, fname, level=0):
115111
"Convert a module `name` to a name relative to `fname`"
116112
assert not level
@@ -122,7 +118,7 @@ def relative_import(name, fname, level=0):
122118
if not all(o=='.' for o in res): res='.'+res
123119
return res.replace(os.path.sep, ".")
124120

125-
# %% ../nbs/09_API/02_maker.ipynb 27
121+
# %% ../nbs/09_API/02_maker.ipynb 26
126122
# Based on https://github.com/thonny/thonny/blob/master/thonny/ast_utils.py
127123
def _mark_text_ranges(
128124
source: str|bytes, # Source code to add ranges to
@@ -140,7 +136,7 @@ def _mark_text_ranges(
140136
child.end_lineno, child.end_col_offset = child.lineno, child.col_offset+2
141137
return root.body
142138

143-
# %% ../nbs/09_API/02_maker.ipynb 28
139+
# %% ../nbs/09_API/02_maker.ipynb 27
144140
def update_import(source, tree, libname, f=relative_import):
145141
if not tree: return
146142
if sys.version_info < (3,8): tree = _mark_text_ranges(source)
@@ -160,7 +156,7 @@ def import2relative(cell:NbCell, libname):
160156
src = update_import(cell.source, cell.parsed_(), libname)
161157
if src: cell.set_source(src)
162158

163-
# %% ../nbs/09_API/02_maker.ipynb 30
159+
# %% ../nbs/09_API/02_maker.ipynb 29
164160
@patch
165161
def _last_future(self:ModuleMaker, cells):
166162
"Returns the location of a `__future__` in `cells`"
@@ -169,13 +165,21 @@ def _last_future(self:ModuleMaker, cells):
169165
isinstance(t,ast.ImportFrom) and t.module=='__future__' for t in tree))+1
170166
except ValueError: return 0
171167

172-
# %% ../nbs/09_API/02_maker.ipynb 31
168+
# %% ../nbs/09_API/02_maker.ipynb 30
173169
def _import2relative(cells, lib_name=None):
174170
"Converts `cells` to use `import2relative` based on `lib_name`"
175171
if lib_name is None: lib_name = get_config().lib_name
176172
for cell in cells: cell.import2relative(lib_name)
177173

178-
# %% ../nbs/09_API/02_maker.ipynb 32
174+
# %% ../nbs/09_API/02_maker.ipynb 31
175+
def _retr_mdoc(cells):
176+
"Search for `_doc_` variable, used to create module docstring"
177+
trees = L(cells).map(NbCell.parsed_).concat()
178+
res = [nested_attr(o, 'value.value') for o in trees
179+
if isinstance(o, _assign_types) and getattr(o.targets[0],'id',None)=='_doc_']
180+
return res[0] if res else None
181+
182+
# %% ../nbs/09_API/02_maker.ipynb 33
179183
@patch
180184
def make(self:ModuleMaker, cells, all_cells=None, lib_path=None):
181185
"Write module containing `cells` with `__all__` generated from `all_cells`"
@@ -195,24 +199,27 @@ def make(self:ModuleMaker, cells, all_cells=None, lib_path=None):
195199
tw = TextWrapper(width=120, initial_indent='', subsequent_indent=' '*11, break_long_words=False)
196200
all_str = '\n'.join(tw.wrap(str(_all)))
197201
with self.fname.open('w') as f:
202+
mdoc = _retr_mdoc(cells)
203+
if mdoc: f.write(f'"""{mdoc}"""\n\n')
198204
f.write(f"# AUTOGENERATED! DO NOT EDIT! File to edit: {self.dest2nb}.")
199205
if last_future > 0: write_cells(cells[:last_future], self.hdr, f)
200206
if self.parse: f.write(f"\n\n# %% auto 0\n__all__ = {all_str}")
201207
write_cells(cells[last_future:], self.hdr, f)
202208
f.write('\n')
203209

204-
# %% ../nbs/09_API/02_maker.ipynb 37
210+
# %% ../nbs/09_API/02_maker.ipynb 38
205211
@patch
206212
def _update_all(self:ModuleMaker, all_cells, alls):
207213
return pformat(alls + self.make_all(all_cells), width=160)
208214

209215
@patch
210216
def _make_exists(self:ModuleMaker, cells, all_cells=None):
211217
"`make` for `is_new=False`"
212-
if all_cells and self.parse: update_var('__all__', partial(self._update_all, all_cells), fn=self.fname)
218+
if all_cells and self.parse:
219+
update_var('__all__', partial(self._update_all, all_cells), fn=self.fname)
213220
with self.fname.open('a') as f: write_cells(cells, self.hdr, f)
214221

215-
# %% ../nbs/09_API/02_maker.ipynb 43
222+
# %% ../nbs/09_API/02_maker.ipynb 44
216223
def _basic_export_nb2(fname, name, dest=None):
217224
"A basic exporter to bootstrap nbdev using `ModuleMaker`"
218225
if dest is None: dest = get_config().lib_path

nbs/09_API/01_config.ipynb

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@
1919
"#|default_exp config"
2020
]
2121
},
22+
{
23+
"cell_type": "code",
24+
"execution_count": null,
25+
"metadata": {},
26+
"outputs": [],
27+
"source": [
28+
"#|export\n",
29+
"_doc_ = \"\"\"Read and write nbdev's `settings.ini file.\n",
30+
"`get_config` is the main function for reading settings.\"\"\""
31+
]
32+
},
2233
{
2334
"cell_type": "code",
2435
"execution_count": null,
@@ -174,13 +185,12 @@
174185
" \n",
175186
" try: r = api.repos.get()\n",
176187
" except HTTPError:\n",
177-
" msg= [f\"\"\"Could not access repo: {owner}/{repo} to find your default branch - `{default_branch} assumed.\n",
188+
" msg= [f\"\"\"Could not access repo: {owner}/{repo} to find your default branch - `{default_branch}` assumed.\n",
178189
"Edit `settings.ini` if this is incorrect.\n",
179190
"In the future, you can allow nbdev to see private repos by setting the environment variable GITHUB_TOKEN as described here:\n",
180-
"https://nbdev.fast.ai/cli.html#Using-nbdev_new-with-private-repos\n",
181-
"\"\"\"]\n",
191+
"https://nbdev.fast.ai/cli.html#Using-nbdev_new-with-private-repos\"\"\"]\n",
182192
" print(''.join(msg))\n",
183-
" return (default_branch,default_kw,'')\n",
193+
" return default_branch,default_kw,''\n",
184194
" \n",
185195
" return r.default_branch, default_kw if not r.topics else ' '.join(r.topics), r.description"
186196
]
@@ -189,16 +199,7 @@
189199
"cell_type": "code",
190200
"execution_count": null,
191201
"metadata": {},
192-
"outputs": [
193-
{
194-
"name": "stderr",
195-
"output_type": "stream",
196-
"text": [
197-
"/Users/jhoward/git/ghapi/ghapi/core.py:99: UserWarning: Neither GITHUB_TOKEN nor GITHUB_JWT_TOKEN found: running as unauthenticated\n",
198-
" else: warn('Neither GITHUB_TOKEN nor GITHUB_JWT_TOKEN found: running as unauthenticated')\n"
199-
]
200-
}
201-
],
202+
"outputs": [],
202203
"source": [
203204
"#|hide\n",
204205
"if os.getenv('GITHUB_ACTIONS') != 'true': # GITHUB_TOKEN in actions has limited scope.\n",

0 commit comments

Comments
 (0)