|
306 | 306 | "source": [ |
307 | 307 | "#|export\n", |
308 | 308 | "@delegates(globtastic)\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", |
| 309 | + "def nbglob(path=None, skip_folder_re = '^[_.]', file_glob='*.ipynb', skip_file_re='^[_.]', key='nbs_path', as_path=False, **kwargs):\n", |
310 | 310 | " \"Find all files in a directory matching an extension given a config key.\"\n", |
311 | 311 | " path = Path(path or get_config()[key])\n", |
312 | 312 | " recursive=get_config().recursive\n", |
313 | 313 | " res = globtastic(path, file_glob=file_glob, skip_folder_re=skip_folder_re,\n", |
314 | 314 | " skip_file_re=skip_file_re, recursive=recursive, **kwargs)\n", |
315 | 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 | 316 | " return res" |
319 | 317 | ] |
320 | 318 | }, |
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" |
342 | | - ] |
343 | | - }, |
344 | 319 | { |
345 | 320 | "cell_type": "code", |
346 | 321 | "execution_count": null, |
|
376 | 351 | " **kwargs):\n", |
377 | 352 | " \"Export notebooks in `path` to Python modules\"\n", |
378 | 353 | " if os.environ.get('IN_TEST',0): return\n", |
379 | | - " files = nbglob(path=path, sort_by=lambda path_str: Path(path_str).name, **kwargs)\n", |
| 354 | + " files = sorted(nbglob(path=path, **kwargs), key=lambda path_str: Path(path_str).name)\n", |
380 | 355 | " for f in files: nb_export(f)\n", |
381 | 356 | " add_init(get_config().lib_path)\n", |
382 | 357 | " _build_modidx()" |
383 | 358 | ] |
384 | 359 | }, |
| 360 | + { |
| 361 | + "cell_type": "markdown", |
| 362 | + "metadata": {}, |
| 363 | + "source": [ |
| 364 | + "When exporting the notebooks, they should be exported in order of the filename to ensure deterministic build behaviour. The below test patches `nbglob` to return a non-ordered list, then checks that `nb_export` is still called on the notebooks in the right order:" |
| 365 | + ] |
| 366 | + }, |
| 367 | + { |
| 368 | + "cell_type": "code", |
| 369 | + "execution_count": null, |
| 370 | + "metadata": {}, |
| 371 | + "outputs": [], |
| 372 | + "source": [ |
| 373 | + "from copy import copy\n", |
| 374 | + "\n", |
| 375 | + "\n", |
| 376 | + "class EscapeException(Exception):\n", |
| 377 | + " pass\n", |
| 378 | + "\n", |
| 379 | + "def nb_export_mock(nb_path: str):\n", |
| 380 | + " assert nb_path==expected_order.pop()\n", |
| 381 | + " \n", |
| 382 | + " # escape from the outer function as the tests are done\n", |
| 383 | + " if not expected_order:\n", |
| 384 | + " raise EscapeException()\n", |
| 385 | + " \n", |
| 386 | + "\n", |
| 387 | + "nbglob_save = copy(nbglob)\n", |
| 388 | + "nb_export_save = copy(nb_export)\n", |
| 389 | + "\n", |
| 390 | + "nbglob = lambda *args, **kwargs: ['../../8.ipynb', 'api/3.ipynb', '4.ipynb']\n", |
| 391 | + "\n", |
| 392 | + "expected_order = ['api/3.ipynb', '4.ipynb', '../../8.ipynb']\n", |
| 393 | + "expected_order.reverse()\n", |
| 394 | + "nb_export = nb_export_mock\n", |
| 395 | + "\n", |
| 396 | + "try:\n", |
| 397 | + " nbdev_export()\n", |
| 398 | + "except EscapeException:\n", |
| 399 | + " pass # this silences the exception used to end nbdev_export early\n", |
| 400 | + "\n", |
| 401 | + "nbglob = nbglob_save\n", |
| 402 | + "nb_export = nb_export_save" |
| 403 | + ] |
| 404 | + }, |
385 | 405 | { |
386 | 406 | "cell_type": "markdown", |
387 | 407 | "metadata": {}, |
|
578 | 598 | "text/markdown": [ |
579 | 599 | "---\n", |
580 | 600 | "\n", |
581 | | - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L209){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
| 601 | + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L211){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
582 | 602 | "\n", |
583 | 603 | "### NbdevLookup.doc\n", |
584 | 604 | "\n", |
|
589 | 609 | "text/plain": [ |
590 | 610 | "---\n", |
591 | 611 | "\n", |
592 | | - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L209){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
| 612 | + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L211){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
593 | 613 | "\n", |
594 | 614 | "### NbdevLookup.doc\n", |
595 | 615 | "\n", |
|
672 | 692 | "text/markdown": [ |
673 | 693 | "---\n", |
674 | 694 | "\n", |
675 | | - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L214){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
| 695 | + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L216){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
676 | 696 | "\n", |
677 | 697 | "### NbdevLookup.code\n", |
678 | 698 | "\n", |
|
683 | 703 | "text/plain": [ |
684 | 704 | "---\n", |
685 | 705 | "\n", |
686 | | - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L214){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
| 706 | + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L216){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
687 | 707 | "\n", |
688 | 708 | "### NbdevLookup.code\n", |
689 | 709 | "\n", |
|
731 | 751 | "text/markdown": [ |
732 | 752 | "---\n", |
733 | 753 | "\n", |
734 | | - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L231){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
| 754 | + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L233){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
735 | 755 | "\n", |
736 | 756 | "### NbdevLookup.linkify\n", |
737 | 757 | "\n", |
|
740 | 760 | "text/plain": [ |
741 | 761 | "---\n", |
742 | 762 | "\n", |
743 | | - "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L231){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
| 763 | + "[source](https://github.com/fastai/nbdev/blob/master/nbdev/doclinks.py#L233){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", |
744 | 764 | "\n", |
745 | 765 | "### NbdevLookup.linkify\n", |
746 | 766 | "\n", |
|
0 commit comments