mkdocs.py

This module makes documentation for a project using MkDocs. It uses the project's source files and the config file "mkdocs.yml" to create MarkDown files in the "docs" folder. It then builds the html file structure in the "site" folder. It uses the "gh-deploy" program to publish the site to a remote-only branch. It then instructs GitHub Pages to auto-publish your docs at .github.io/ from that branch. As much code/settings/constants as can be are reused from conf.py.

deploy_docs(dir_prj, _dict_prv, _dict_pub, p_dir_pp, p_dir_pp_venv)

Deploy docs using mkdocs

Parameters:

Name Type Description Default
dir_prj

The root of the new project

required
dict_prv

The dictionary containing private pyplate data

required
dict_pub

The dictionary containing public project data

required
p_dir_pp

Path to PyPlate program

required
p_dir_pp_env

Path to PyPlate's venv (to activate pdoc3)

required

Deploy the documents using the specified parameters.

Source code in conf/mkdocs.py
def deploy_docs(dir_prj, _dict_prv, _dict_pub, p_dir_pp, p_dir_pp_venv):
    """
    Deploy docs using mkdocs

    Args:
        dir_prj: The root of the new project
        dict_prv: The dictionary containing private pyplate data
        dict_pub: The dictionary containing public project data
        p_dir_pp: Path to PyPlate program
        p_dir_pp_env: Path to PyPlate's venv (to activate pdoc3)

    Deploy the documents using the specified parameters.
    """

    # format cmd using pdoc template dir, output dir, and start dir
    cmd_docs = S_CMD_DOC_DEPLOY.format(
        p_dir_pp,
        p_dir_pp_venv,
        dir_prj,
    )

    # the command to run mkdocs
    try:
        subprocess.run(
            cmd_docs,
            shell=True,
            check=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.STDOUT,
        )
    except Exception as e:
        raise OSError(S_ERR_NO_REPO) from e

make_docs(dir_prj, dict_prv, dict_pub, p_dir_pp, p_dir_pp_venv)

Make docs using mkdocs

Parameters:

Name Type Description Default
dir_prj

The root of the new project

required
dict_prv

The dictionary containing private pyplate data

required
dict_pub

The dictionary containing public project data

required
p_dir_pp

Path to PyPlate program

required
p_dir_pp_env

Path to PyPlate's venv (to activate pdoc3)

required

Make the documents using the specified parameters.

Source code in conf/mkdocs.py
def make_docs(dir_prj, dict_prv, dict_pub, p_dir_pp, p_dir_pp_venv):
    """
    Make docs using mkdocs

    Args:
        dir_prj: The root of the new project
        dict_prv: The dictionary containing private pyplate data
        dict_pub: The dictionary containing public project data
        p_dir_pp: Path to PyPlate program
        p_dir_pp_env: Path to PyPlate's venv (to activate pdoc3)

    Make the documents using the specified parameters.
    """

    # where to put the .md files
    dir_docs_out = dir_prj / conf.S_DIR_DOCS

    # --------------------------------------------------------------------------
    # make yaml

    # get theme from dict_pub
    dict_docs = dict_pub[conf.S_KEY_PUB_DOCS]
    theme = dict_docs.get(conf.S_KEY_DOCS_THEME, "")

    # path to file
    yaml_file = dir_prj / S_YML_NAME
    if not yaml_file.exists():

        # create a new yaml with default text
        text = S_YML_TEXT.format(dir_prj.name, theme)

        # write file
        with open(yaml_file, "w", encoding=conf.S_ENCODING) as a_file:
            a_file.write(text)

    # --------------------------------------------------------------------------
    # make home page
    # NB: just copy readme.md to index.md

    # path to files
    readme_file = dir_prj / conf.S_FILE_README
    index_file = dir_docs_out / S_INDEX_NAME
    if not index_file.exists():
        # read input file
        text = ""
        with open(readme_file, "r", encoding=conf.S_ENCODING) as a_file:
            text = a_file.read()

        # write file
        with open(index_file, "w", encoding=conf.S_ENCODING) as a_file:
            a_file.write(text)

    # copy image for index.md as README.md
    prj_name = dict_prv[conf.S_KEY_PRV_PRJ]["__PP_NAME_PRJ_SMALL__"]
    prj_img = prj_name + ".png"
    img_src = dir_prj / conf.S_DIR_IMAGES / prj_img
    dir_img_dest = dir_docs_out / conf.S_DIR_IMAGES
    dir_img_dest.mkdir(parents=True, exist_ok=True)

    shutil.copy(img_src, dir_img_dest)

    # --------------------------------------------------------------------------
    # run mkdocstrings

    # NB: this function uses the blacklist to filter files at the very end of
    # the fix process. at this point you can assume ALL dunders in ALL eligible
    # files have been fixed, as well as paths/filenames. also dict_pub and
    # dict_prv have been undunderized
    dict_bl = dict_pub[conf.S_KEY_PUB_BL]

    # just shorten the names
    skip_all = dict_bl[conf.S_KEY_SKIP_ALL]
    skip_contents = dict_bl[conf.S_KEY_SKIP_CONTENTS]

    # --------------------------------------------------------------------------
    # do the fixes

    files_out = []

    # NB: root is a full path, dirs and files are relative to root
    for root, root_dirs, root_files in dir_prj.walk():

        # handle dirs in skip_all
        if root in skip_all:
            # NB: don't recurse into subfolders
            root_dirs.clear()
            continue

        # convert files into Paths
        files = [root / f for f in root_files]
        files = [f for f in files if f.suffix.lower() == S_EXT_IN]

        # for each file item
        for item in files:

            # handle files in skip_all
            if item in skip_all:
                continue

            # handle dirs/files in skip_contents
            if not root in skip_contents and not item in skip_contents:

                # add the python file to the list
                files_out.append(item)

    # --------------------------------------------------------------------------
    # make structure

    # make the api folder
    dir_docs_api = dir_prj / S_DIR_API
    dir_docs_api.mkdir(parents=True, exist_ok=True)

    # for each py file
    for f in files_out:

        # make a parent folder in docs (goes in nav bar)
        # NB: basically we find every .py file and get its path relative to
        # project dir
        # then we make a folder with the same relative path, but rel to docs
        # dir
        path_rel = f.relative_to(dir_prj)
        path_doc = dir_docs_api / path_rel.parent
        path_doc.mkdir(parents=True, exist_ok=True)

        # create a default file
        # NB: just swap ".py" ext for ".md"
        file_md = path_doc / Path(str(f.stem) + S_EXT_OUT)

        # fix rel path into package dot notation
        s_parts = ".".join(path_rel.parts)
        if s_parts.endswith(S_EXT_IN):
            s_parts = s_parts.removesuffix(S_EXT_IN)

        # format contents of file
        file_fmt = S_DEF_FILE.format(f.name, s_parts)
        with open(file_md, "w", encoding=conf.S_ENCODING) as a_file:
            a_file.write(file_fmt)

    # --------------------------------------------------------------------------
    # make docs

    # format cmd using pdoc template dir, output dir, and start dir
    cmd_docs = S_CMD_DOC_BUILD.format(
        p_dir_pp,
        p_dir_pp_venv,
        dir_prj,
    )

    # the command to run pdoc
    try:
        subprocess.run(
            cmd_docs,
            shell=True,
            check=True,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.STDOUT,
        )
    except Exception as e:
        raise e