Plugin flow

MkNodesPlugin

on_startup

Activates new-style MkDocs plugin lifecycle.

Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_startup
def on_startup(self, command: CommandStr, dirty: bool = False):
    """Activates new-style MkDocs plugin lifecycle."""
    if self.config.build_folder:
        self.build_folder = pathlib.Path(self.config.build_folder)
    else:
        self._dir = tempfile.TemporaryDirectory(
            prefix="mknodes_",
            ignore_cleanup_errors=True,
        )
        self.build_folder = pathlib.Path(self._dir.name)
        logger.debug("Creating temporary dir %s", self._dir.name)
Hook info

The startup event runs once at the very beginning of an mkdocs invocation.

New in MkDocs 1.4.

The presence of an on_startup method (even if empty) migrates the plugin to the new system where the plugin object is kept across builds within one mkdocs serve.

Note that for initializing variables, the __init__ method is still preferred. For initializing per-build variables (and whenever in doubt), use the on_config event.

Parameters:

Name Type Description Default
command Literal['build', 'gh-deploy', 'serve']

the command that MkDocs was invoked with, e.g. "serve" for mkdocs serve.

required
dirty bool

whether --dirty flag was passed.

required

on_config

Create the project based on MkDocs config.

Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_config
def on_config(self, config: MkDocsConfig):
    """Create the project based on MkDocs config."""
    if not self.config.build_fn:
        return
    skin = mk.Theme.get_theme(
        theme_name=config.theme.name or "material",
        data=dict(config.theme),
    )
    self.project = project.Project(
        base_url=config.site_url or "",
        use_directory_urls=config.use_directory_urls,
        theme=skin,
        repo=self.config.repo_path,
        clone_depth=self.config.clone_depth,
    )
Hook info

The config event is the first event called on build and is run immediately after the user configuration is loaded and validated. Any alterations to the config should be made here.

Parameters:

Name Type Description Default
config MkDocsConfig

global configuration object

required

Returns:

Type Description
MkDocsConfig | None

global configuration object

on_files

Create the node tree and write files to build folder.

In this step we aggregate all files and info we need to build the website. This includes:

  • Markdown pages (MkPages)
  • Templates
  • CSS files
Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_files
def on_files(self, files: Files, config: MkDocsConfig) -> Files:
    """Create the node tree and write files to build folder.

    In this step we aggregate all files and info we need to build the website.
    This includes:

      - Markdown pages (MkPages)
      - Templates
      - CSS files
    """
    if not self.config.build_fn:
        return files

    logger.info("Generating pages...")
    build_fn = self.config.get_builder()
    build_fn(project=self.project)
    logger.debug("Finished building page.")
    paths = [
        pathlib.Path(node.resolved_file_path).stem
        for _level, node in self.project.root.iter_nodes()
        if hasattr(node, "resolved_file_path")
    ]
    self.project.linkprovider.set_excludes(paths)

    # now we add our stuff to the MkDocs build environment
    cfg = mkdocsconfig.Config(config)

    logger.info("Updating MkDocs config metadata...")
    cfg.update_from_context(self.project.context)
    self.project.theme.adapt_extras(cfg.extra)

    logger.info("Setting up build backends...")
    mkdocs_backend = mkdocsbackend.MkDocsBackend(
        files=files,
        config=config,
        directory=self.build_folder,
    )

    markdown_backend = markdownbackend.MarkdownBackend(
        directory=pathlib.Path(config.site_dir) / "src",
        extension=".original",
    )
    collector = buildcollector.BuildCollector(
        backends=[mkdocs_backend, markdown_backend],
        show_page_info=self.config.show_page_info,
        global_resources=self.config.global_resources,
        render_by_default=self.config.render_by_default,
    )
    self.build_info = collector.collect(self.project.root, self.project.theme)
    if nav_dict := self.project.root.nav.to_nav_dict():
        match config.nav:
            case list():
                for k, v in nav_dict.items():
                    config.nav.append({k: v})
            case dict():
                config.nav |= nav_dict
            case None:
                config.nav = nav_dict
    return mkdocs_backend.files
Hook info

The files event is called after the files collection is populated from the docs_dir. Use this event to add, remove, or alter files in the collection. Note that Page objects have not yet been associated with the file objects in the collection. Use Page Events to manipulate page specific data.

Parameters:

Name Type Description Default
files Files

global files collection

required
config MkDocsConfig

global configuration object

required

Returns:

Type Description
Files | None

global files collection

on_nav

Populate LinkReplacer and build path->MkPage mapping for following steps.

Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_nav
def on_nav(
    self,
    nav: Navigation,
    files: Files,
    config: MkDocsConfig,
) -> Navigation | None:
    """Populate LinkReplacer and build path->MkPage mapping for following steps."""
    for file_ in files:
        filename = pathlib.Path(file_.abs_src_path).name
        url = urllib.parse.unquote(file_.src_uri)
        self.link_replacer.mapping[filename].append(url)
    return nav
Hook info

The nav event is called after the site navigation is created and can be used to alter the site navigation.

Parameters:

Name Type Description Default
nav Navigation

global navigation object

required
config MkDocsConfig

global configuration object

required
files Files

global files collection

required

Returns:

Type Description
Navigation | None

global navigation object

on_env

Add our own info to the MkDocs environment.

Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_env
def on_env(self, env: jinja2.Environment, config: MkDocsConfig, files: Files):
    """Add our own info to the MkDocs environment."""
    rope_env = jinjarope.Environment()
    env.globals["mknodes"] = rope_env.globals
    env.filters |= rope_env.filters
    logger.debug("Added macros / filters to MkDocs jinja2 environment.")
    if self.config.rewrite_theme_templates:
        assert env.loader
        env.loader = jinjarope.RewriteLoader(env.loader, rewriteloader.rewrite)
        logger.debug("Injected Jinja2 Rewrite loader.")
    return env
Hook info

The env event is called after the Jinja template environment is created and can be used to alter the Jinja environment.

Parameters:

Name Type Description Default
env Environment

global Jinja environment

required
config MkDocsConfig

global configuration object

required
files Files

global files collection

required

Returns:

Type Description
Environment | None

global Jinja Environment

on_post_build

Delete the temporary template files.

Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_post_build
def on_post_build(self, config: MkDocsConfig):
    """Delete the temporary template files."""
    if not config.theme.custom_dir or not self.config.build_fn:
        return
    if self.config.auto_delete_generated_templates:
        logger.debug("Deleting page templates...")
        for template in self.build_info.templates:
            assert template.filename
            path = pathlib.Path(config.theme.custom_dir) / template.filename
            path.unlink(missing_ok=True)
Hook info

The post_build event does not alter any variables. Use this event to call post-build scripts.

Parameters:

Name Type Description Default
config MkDocsConfig

global configuration object

required

on_pre_page

During this phase we set the edit paths.

Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_pre_page
def on_pre_page(
    self,
    page: Page,
    config: MkDocsConfig,
    files: Files,
) -> Page | None:
    """During this phase we set the edit paths."""
    node = self.build_info.page_mapping.get(page.file.src_uri)
    edit_path = node._edit_path if isinstance(node, mk.MkPage) else None
    cfg = mkdocsconfig.Config(config)
    if path := cfg.get_edit_url(edit_path):
        page.edit_url = path
    return page
Hook info

The pre_page event is called before any actions are taken on the subject page and can be used to alter the Page instance.

Parameters:

Name Type Description Default
page Page

mkdocs.structure.pages.Page instance

required
config MkDocsConfig

global configuration object

required
files Files

global files collection

required

Returns:

Type Description
Page | None

mkdocs.structure.pages.Page instance

on_page_markdown

During this phase links get replaced and jinja2 stuff get rendered.

Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_page_markdown
def on_page_markdown(
    self,
    markdown: str,
    page: Page,
    config: MkDocsConfig,
    files: Files,
) -> str | None:
    """During this phase links get replaced and `jinja2` stuff get rendered."""
    return self.link_replacer.replace(markdown, page.file.src_uri)
Hook info

The page_markdown event is called after the page's markdown is loaded from file and can be used to alter the Markdown source text. The meta- data has been stripped off and is available as page.meta at this point.

Parameters:

Name Type Description Default
markdown str

Markdown source text of page as string

required
page Page

mkdocs.structure.pages.Page instance

required
config MkDocsConfig

global configuration object

required
files Files

global files collection

required

Returns:

Type Description
str | None

Markdown source text of page as string

on_post_build

Delete the temporary template files.

Source
mkdocs_mknodes.plugin.MkNodesPlugin.on_post_build
def on_post_build(self, config: MkDocsConfig):
    """Delete the temporary template files."""
    if not config.theme.custom_dir or not self.config.build_fn:
        return
    if self.config.auto_delete_generated_templates:
        logger.debug("Deleting page templates...")
        for template in self.build_info.templates:
            assert template.filename
            path = pathlib.Path(config.theme.custom_dir) / template.filename
            path.unlink(missing_ok=True)
Hook info

The post_build event does not alter any variables. Use this event to call post-build scripts.

Parameters:

Name Type Description Default
config MkDocsConfig

global configuration object

required
Page info
Code for this page
mkdocs_mknodes.manual.get_started_section._
@router.route_page("Plugin flow", icon="dev-to", hide="toc")
def _(page: mk.MkPage):
    page += mk.MkPluginFlow()
Resources
Resources(css=[],
          markdown_extensions={'admonition': {},
                               'attr_list': {},
                               'md_in_html': {},
                               'pymdownx.details': {},
                               'pymdownx.emoji': {'emoji_generator': <function to_svg at 0x7f170970c540>,
                                                  'emoji_index': <function twemoji at 0x7f170970c400>},
                               'pymdownx.highlight': {'anchor_linenums': True,
                                                      'line_spans': '__span',
                                                      'pygments_lang_class': True},
                               'pymdownx.magiclink': {'repo': 'mkdocs_mknodes',
                                                      'repo_url_shorthand': True,
                                                      'user': 'phil65'},
                               'pymdownx.superfences': {}},
          plugins=[Plugin('mkdocstrings')],
          js=[],
          assets=[Asset('speechbubble_10d5a72.css')],
          packages=[])
Metadata
created:
  source_filename: /home/runner/work/mkdocs-mknodes/mkdocs-mknodes/mkdocs_mknodes/manual/root.py
  source_function: Build.on_root
  source_line_no: 19
hide:
- toc
icon: material/dev-to
template: Get started/plugin_flow.html
title: Plugin flow