Skip to content

Commit 24130b5

Browse files
committed
nb_export now exports notebooks in ascending-filename-order
1 parent 656b7bc commit 24130b5

File tree

2 files changed

+42
-13
lines changed

2 files changed

+42
-13
lines changed

nbdev/doclinks.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,18 @@ def _build_modidx(dest=None, nbs_path=None, skip_exists=False):
100100

101101
# %% ../nbs/api/doclinks.ipynb 20
102102
@delegates(globtastic)
103-
def nbglob(path=None, skip_folder_re = '^[_.]', file_glob='*.ipynb', skip_file_re='^[_.]', key='nbs_path', as_path=False, **kwargs):
103+
def nbglob(path=None, skip_folder_re = '^[_.]', file_glob='*.ipynb', skip_file_re='^[_.]', key='nbs_path', as_path=False, sort_by=None, **kwargs):
104104
"Find all files in a directory matching an extension given a config key."
105105
path = Path(path or get_config()[key])
106106
recursive=get_config().recursive
107107
res = globtastic(path, file_glob=file_glob, skip_folder_re=skip_folder_re,
108108
skip_file_re=skip_file_re, recursive=recursive, **kwargs)
109-
return res.map(Path) if as_path else res
109+
res = res.map(Path) if as_path else res
110+
if sort_by is not None:
111+
res.sort(key=sort_by)
112+
return res
110113

111-
# %% ../nbs/api/doclinks.ipynb 21
114+
# %% ../nbs/api/doclinks.ipynb 23
112115
def nbglob_cli(
113116
path:str=None, # Path to notebooks
114117
symlinks:bool=False, # Follow symlinks?
@@ -122,24 +125,24 @@ def nbglob_cli(
122125
return nbglob(path, symlinks=symlinks, file_glob=file_glob, file_re=file_re, folder_re=folder_re,
123126
skip_file_glob=skip_file_glob, skip_file_re=skip_file_re, skip_folder_re=skip_folder_re)
124127

125-
# %% ../nbs/api/doclinks.ipynb 22
128+
# %% ../nbs/api/doclinks.ipynb 24
126129
@call_parse
127130
@delegates(nbglob_cli)
128131
def nbdev_export(
129132
path:str=None, # Path or filename
130133
**kwargs):
131134
"Export notebooks in `path` to Python modules"
132135
if os.environ.get('IN_TEST',0): return
133-
files = nbglob(path=path, **kwargs)
136+
files = nbglob(path=path, as_path=True, sort_by=lambda path_str: Path(path_str).name, **kwargs)
134137
for f in files: nb_export(f)
135138
add_init(get_config().lib_path)
136139
_build_modidx()
137140

138-
# %% ../nbs/api/doclinks.ipynb 24
141+
# %% ../nbs/api/doclinks.ipynb 26
139142
import importlib,ast
140143
from functools import lru_cache
141144

142-
# %% ../nbs/api/doclinks.ipynb 25
145+
# %% ../nbs/api/doclinks.ipynb 27
143146
def _find_mod(mod):
144147
mp,_,mr = mod.partition('/')
145148
spec = importlib.util.find_spec(mp)
@@ -162,7 +165,7 @@ def _get_exps(mod):
162165

163166
def _lineno(sym, fname): return _get_exps(fname).get(sym, None) if fname else None
164167

165-
# %% ../nbs/api/doclinks.ipynb 27
168+
# %% ../nbs/api/doclinks.ipynb 29
166169
def _qual_sym(s, settings):
167170
if not isinstance(s,tuple): return s
168171
nb,py = s
@@ -177,10 +180,10 @@ def _qual_syms(entries):
177180
if 'doc_host' not in settings: return entries
178181
return {'syms': {mod:_qual_mod(d, settings) for mod,d in entries['syms'].items()}, 'settings':settings}
179182

180-
# %% ../nbs/api/doclinks.ipynb 28
183+
# %% ../nbs/api/doclinks.ipynb 30
181184
_re_backticks = re.compile(r'`([^`\s]+)`')
182185

183-
# %% ../nbs/api/doclinks.ipynb 29
186+
# %% ../nbs/api/doclinks.ipynb 31
184187
@lru_cache(None)
185188
class NbdevLookup:
186189
"Mapping from symbol names to docs and source URLs"

nbs/api/doclinks.ipynb

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,39 @@
306306
"source": [
307307
"#|export\n",
308308
"@delegates(globtastic)\n",
309-
"def nbglob(path=None, skip_folder_re = '^[_.]', file_glob='*.ipynb', skip_file_re='^[_.]', key='nbs_path', as_path=False, **kwargs):\n",
309+
"def nbglob(path=None, skip_folder_re = '^[_.]', file_glob='*.ipynb', skip_file_re='^[_.]', key='nbs_path', as_path=False, sort_by=None, **kwargs):\n",
310310
" \"Find all files in a directory matching an extension given a config key.\"\n",
311311
" path = Path(path or get_config()[key])\n",
312312
" recursive=get_config().recursive\n",
313313
" res = globtastic(path, file_glob=file_glob, skip_folder_re=skip_folder_re,\n",
314314
" skip_file_re=skip_file_re, recursive=recursive, **kwargs)\n",
315-
" return res.map(Path) if as_path else res"
315+
" res = res.map(Path) if as_path else res\n",
316+
" if sort_by is not None:\n",
317+
" res.sort(key=sort_by)\n",
318+
" return res"
319+
]
320+
},
321+
{
322+
"cell_type": "markdown",
323+
"metadata": {},
324+
"source": [
325+
"`globtastic` uses `glob.glob`, which in turn uses `os.listdir` under the hood. As the [documentation](https://docs.python.org/3/library/os.html#os.listdir) states, the order of results returned by `os.listdir` is arbitrary, hence we need to be able to sort the notebook-paths when needed:"
326+
]
327+
},
328+
{
329+
"cell_type": "code",
330+
"execution_count": null,
331+
"metadata": {},
332+
"outputs": [],
333+
"source": [
334+
"import copy\n",
335+
"\n",
336+
"globtastic_save = copy.copy(globtastic)\n",
337+
"\n",
338+
"globtastic = lambda *args, **kwargs: ['../../8.ipynb', 'api/3.ipynb', '4.ipynb']\n",
339+
"assert nbglob(sort_by=lambda path_str: Path(path_str).name) == ['api/3.ipynb', '4.ipynb', '../../8.ipynb']\n",
340+
"\n",
341+
"globtastic = globtastic_save"
316342
]
317343
},
318344
{
@@ -350,7 +376,7 @@
350376
" **kwargs):\n",
351377
" \"Export notebooks in `path` to Python modules\"\n",
352378
" if os.environ.get('IN_TEST',0): return\n",
353-
" files = nbglob(path=path, **kwargs)\n",
379+
" files = nbglob(path=path, as_path=True, sort_by=lambda path_str: Path(path_str).name, **kwargs)\n",
354380
" for f in files: nb_export(f)\n",
355381
" add_init(get_config().lib_path)\n",
356382
" _build_modidx()"

0 commit comments

Comments
 (0)