skip to main content

@tonyfast s notebooks

site navigation
notebook summary
title
doit integration - a mkdocs example
description
in the hunt for a computable blog, i've wanted to be able to reuse the code i write about in posts. one integration we are beginning to experiment with in this post is access to doit task specifications from posts. the tonyfast.dodo module integrates posts with tasks.
cells
14 total
5 code
state
executed in order
kernel
Python [conda env:root] *
language
python
name
conda-root-py
lines of code
72
outputs
1
table of contents
{"kernelspec": {"display_name": "Python [conda env:root] *", "language": "python", "name": "conda-root-py"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13"}, "title": "doit integration - a mkdocs example", "description": "in the hunt for a computable blog, i've wanted to be able to reuse the code i write about in posts.\none integration we are beginning to experiment with in this post is access to doit task specifications\nfrom posts. the tonyfast.dodo module integrates posts with tasks."}
notebook toolbar
Activate
cell ordering
1

doit mkdocs

in the hunt for a computable blog, i've wanted to be able to reuse the code i write about in posts. one integration we are beginning to experiment with in this post is access to doit task specifications from posts. the tonyfast.dodo module integrates posts with tasks.

doit is a great tool for orchestrating commands that operate on files. to demonstrate the integration we'll compose a task to build a mkdocs site, and deal with some pain points in the configuration.

the task

mkdocs integrations are identified when a project has the mkdocs.yml file. this file contains all the information for your site including the documents to build. for blog style content, adding a new post means updating the configuration file. my adhd brain has a tendency to forget the configuration bit. in this file, we wrote tools to infer the files that should be included in the configuration, we sort them, and place them back in the configuration file.

what follow is the incovation for mkdocs for the tonyfast site. in this document we:

  • define functions to find posts
  • define a doit task to execute mkdocs

there is a mkdocs-material blog feature avaiable to insiders. when this is generally available a lot of this content will be moot.

2

the task

primarily doit tasks are functions that begin with the prefix task_ ; task_mkdocs is the one task we define in this document.

3

find posts and build the mkdocs site

4
    def task_mkdocs():
        yield dict(name="toc", actions=[
            (set_nav, (pathlib.Path("tonyfast"), "*.ipynb", "mkdocs.yml"))
        ], targets=["mkdocs.yml"], uptodate=[False])
        yield dict(
            name="build",
            actions=["mkdocs build"],
            file_dep=["mkdocs.yml"],
            targets=["site/index.html"]
        )
5

finding and sorting the posts

6

find all the potential notebook posts

7
    def get_posts_from_dir(dir, glob="*.ipynb"):
        for file in dir.iterdir():
            if file.is_dir():
                if "checkpoints" not in file.name: yield from get_posts_from_dir(file, glob)
            elif file.suffix in {".ipynb"}:
                if (m := title.match(str(file.stem))): yield file, m

    def get_posts(dir, glob="*.ipynb"):
        return sorted((
            (x.relative_to(WHERE), y) for x, y in get_posts_from_dir(dir, glob)
        ), reverse=True, key=lambda x: x[1].group(*"ymd"))
8

format the ordered entries

9
    def get_toc(dir, glob="*.ipynb"):
        for x, y in list(get_posts(WHERE, glob)):
            yield " "* 4 + F"- {x}" 
10

we don't use yaml cause our mkdocs uses yaml tags. instead we put the nav at the end of the document then replace the default with the updated version.

11

replace the nav

12
    def get_nav(dir, glob="*.ipynb"):
        return "".join(re.split(
            "(notes\S*:\S*)",
            (WHERE.parent / "mkdocs.yml").read_text(),
            1
        )[:2] )+ "\n" + "\n".join(get_toc(dir, glob))

    import tonyfast, pathlib, yaml, re
    WHERE = pathlib.Path(tonyfast.__file__).parent
    title = re.compile("(?P<y>[0-9]{4})-(?P<m>[0-9]{1,2})-(?P<d>[0-9]{1,2})-(?P<t>.+)")
    
    def set_nav(dir, glob="*.ipynb", target=WHERE.parent / "mkdocs.yml"):
        pathlib.Path(target).write_text(get_nav(pathlib.Path(dir), glob))
13

invocation

  • the task is exposed in the tonyfast module

    python -m tonyfast tasks mkdocs

  • this command is invoked with hatch in a virtual environment using:

    hatch run docs:build

  • use with importnb -t

14
    if "__file__" not in locals():
        !python -m importnb -t 2022-12-18-mkdocs-task.ipynb info mkdocs
1 outputs.

mkdocs

find posts and build the mkdocs site

status     : run
 * The task has no dependencies.

task_dep   : 
 - mkdocs:toc
 - mkdocs:build