mkdocstrings: jinja2.exceptions.TemplateNotFound: alias.html

Describe the bug

While running mkdocs build I get an exception:

$ mkdocs build
INFO     -  Cleaning site directory
INFO     -  Building documentation to directory: C:\Users\lameg\kubekind\site
WARNING  -  mkdocstrings_handlers: 1 aliases were still unresolved after 2 iterations
ERROR    -  mkdocstrings: Template 'alias.html' not found for 'python' handler and theme 'material'.
ERROR    -  Error reading page 'index.md': alias.html
Traceback (most recent call last):
  File "C:\Users\lameg\miniforge3\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\lameg\miniforge3\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\lameg\miniforge3\Scripts\mkdocs.exe\__main__.py", line 7, in <module>
  File "C:\Users\lameg\miniforge3\lib\site-packages\click\core.py", line 1137, in __call__
    return self.main(*args, **kwargs)
  File "C:\Users\lameg\miniforge3\lib\site-packages\click\core.py", line 1062, in main
    rv = self.invoke(ctx)
  File "C:\Users\lameg\miniforge3\lib\site-packages\click\core.py", line 1668, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "C:\Users\lameg\miniforge3\lib\site-packages\click\core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "C:\Users\lameg\miniforge3\lib\site-packages\click\core.py", line 763, in invoke
    return __callback(*args, **kwargs)
  File "C:\Users\lameg\miniforge3\lib\site-packages\mkdocs\__main__.py", line 192, in build_command
    build.build(config.load_config(**kwargs), dirty=not clean)
  File "C:\Users\lameg\miniforge3\lib\site-packages\mkdocs\commands\build.py", line 292, in build
    _populate_page(file.page, config, files, dirty)
  File "C:\Users\lameg\miniforge3\lib\site-packages\mkdocs\commands\build.py", line 174, in _populate_page
    page.render(config, files)
  File "C:\Users\lameg\miniforge3\lib\site-packages\mkdocs\structure\pages.py", line 175, in render
    self.content = md.convert(self.markdown)
  File "C:\Users\lameg\miniforge3\lib\site-packages\markdown\core.py", line 264, in convert
    root = self.parser.parseDocument(self.lines).getroot()
  File "C:\Users\lameg\miniforge3\lib\site-packages\markdown\blockparser.py", line 90, in parseDocument
    self.parseChunk(self.root, '\n'.join(lines))
  File "C:\Users\lameg\miniforge3\lib\site-packages\markdown\blockparser.py", line 105, in parseChunk
    self.parseBlocks(parent, text.split('\n\n'))
  File "C:\Users\lameg\miniforge3\lib\site-packages\markdown\blockparser.py", line 123, in parseBlocks
    if processor.run(parent, blocks) is not False:
  File "C:\Users\lameg\miniforge3\lib\site-packages\mkdocstrings\extension.py", line 121, in run
    html, handler, data = self._process_block(identifier, block, heading_level)
  File "C:\Users\lameg\miniforge3\lib\site-packages\mkdocstrings\extension.py", line 209, in _process_block
    rendered = handler.render(data, options)
  File "C:\Users\lameg\miniforge3\lib\site-packages\mkdocstrings_handlers\python\handler.py", line 215, in render
    template = self.env.get_template(f"{data.kind.value}.html")
  File "C:\Users\lameg\miniforge3\lib\site-packages\jinja2\environment.py", line 1010, in get_template
    return self._load_template(name, globals)
  File "C:\Users\lameg\miniforge3\lib\site-packages\jinja2\environment.py", line 969, in _load_template
    template = self.loader.load(self, name, self.make_globals(globals))
  File "C:\Users\lameg\miniforge3\lib\site-packages\jinja2\loaders.py", line 126, in load
    source, filename, uptodate = self.get_source(environment, name)
  File "C:\Users\lameg\miniforge3\lib\site-packages\jinja2\loaders.py", line 218, in get_source
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: alias.html

To Reproduce Steps to reproduce the behavior:

git clone git@github.com:joaompinto/kubekind.git
cd kubekind
pip install mkdocs mkdocstrings mkdocstrings[python]
mkdocs build

Expected behavior A clear and concise description of what you expected to happen.

Information (please complete the following information):

  • OS: Windows 10
  • mkdocstrings 0.19.0

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 33 (15 by maintainers)

Commits related to this issue

Most upvoted comments

Ah interesting. It looks like that’s an implementation detail of the Maturin build tool. I’ve opened a discussion question about best practices here: https://github.com/PyO3/maturin/discussions/1365. Please chime in if you have any thoughts about Maturin/PyO3, or if you can clarify exactly how the mkdocs tool is getting confused. (I’m not familiar with it.)

Just published blake3 v0.3.3 with __module__ set to blake3.blake3. Could you give this another try?

The Maturin maintainer has asked for repro steps here: https://github.com/PyO3/maturin/discussions/1365#discussioncomment-4454070. Could someone from this thread add a mkdocs repro to that thread?

As I tried to explain before, ::: blake2signer.hashers.blake3 will not make Griffe load the blake3 package, so you won’t have any information about the blake3 class.

The idea is that later, you’ll be able to use something like this:

# mkdocs.yml
plugins:
- mkdocstrings:
    handlers:
      python:
        preload: [blake3]

…so that you don’t have to rely on this hidden div hack 🙂

If blake3 patches the module (again 🙏 🙇 ❤️), then you can enable the md_in_html Markdown extension in mkdocs.yml and use this:

# Hashers

<div style="display: none;" markdown=1>

::: blake3
    options:
        members: false
        show_root_heading: false
        show_root_toc_entry: false

</div>

::: blake2signer.hashers
    options:
        merge_init_into_class: true
        filters: ["!^_"]

Indeed, it does work when I do something like explained here 😄 🥳

It still fails if I use ::: blake2signer.hashers.blake3 instead of ::: blake3, but this is good enough 😅

Seems to be working fine! I’ll let @HacKanCuBa confirm 🙂

Your toy example is correct, however your code/project has one more layer:

blake3/  # <- module == blake3
    __init__.py  # <- imports blake3 class from compiled blake3 below
    blake3.cpython-311-x86_64-linux-gnu.so  # <- module == blake3.blake3

Generally, it seems that objects do have the full, canonical path to the module they are defined in as value for __module__. Some examples:

>>> from griffe import load_git  # indirect import
>>> load_git.__module__
'griffe.git'

>>> from griffe.agents.base import BaseVisitor  # direct import
>>> BaseVisitor.__module__
'griffe.agents.base'

I wonder if this is because @oconnor663 set the parent to module to blake3 instead of blake3.blake3 🤔

mkdocs build -v

Hmmm interesting, I do not see that griffe issue in my log:

...
INFO     -  Cleaning site directory
INFO     -  Building documentation to directory: /home/hackan/Workspace/blake2signer/docs/site
DEBUG    -  An external link to 'https://blake2signer.hackan.net/en/stable/' is included in the
            'nav' configuration.
DEBUG    -  An external link to 'https://blake2signer.hackan.net/en/latest/' is included in the
            'nav' configuration.
DEBUG    -  An external link to 'https://readthedocs.org/projects/blake2signer/' is included in
            the 'nav' configuration.
DEBUG    -  Reading markdown pages.
DEBUG    -  Reading: index.md
DEBUG    -  Running 1 `page_markdown` events
DEBUG    -  Running 1 `page_content` events
DEBUG    -  Reading: bases.md
DEBUG    -  Running 1 `page_markdown` events
DEBUG    -  mkdocstrings: Matched '::: blake2signer.bases.Base'
DEBUG    -  mkdocstrings: Using handler 'python'
DEBUG    -  mkdocstrings: Collecting data
DEBUG    -  griffe: Found blake2signer: loading
DEBUG    -  griffe: Loading path /home/hackan/Workspace/blake2signer/blake2signer/__init__.py
DEBUG    -  griffe: Loading path /home/hackan/Workspace/blake2signer/blake2signer/signers.py
DEBUG    -  griffe: Loading path /home/hackan/Workspace/blake2signer/blake2signer/utils.py
DEBUG    -  griffe: Loading path /home/hackan/Workspace/blake2signer/blake2signer/interfaces.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/compressors.py
DEBUG    -  griffe: Loading path /home/hackan/Workspace/blake2signer/blake2signer/errors.py
DEBUG    -  griffe: Loading path /home/hackan/Workspace/blake2signer/blake2signer/encoders.py
DEBUG    -  griffe: Loading path /home/hackan/Workspace/blake2signer/blake2signer/bases.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/serializers.py
DEBUG    -  griffe: Loading path /home/hackan/Workspace/blake2signer/blake2signer/mixins.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/hashers/__init__.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/tests/__init__.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/hashers/blake3_package.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/hashers/blakehashers.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/tests/test_hashers.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/tests/test_signer.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/tests/test_serializersigner.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/tests/test_timestampsigner.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/tests/test_utils.py
DEBUG    -  griffe: Loading path
            /home/hackan/Workspace/blake2signer/blake2signer/tests/bases.py
DEBUG    -  griffe: Alias blake2signer.Blake2SerializerSigner was resolved to
            blake2signer.signers.Blake2SerializerSigner
DEBUG    -  griffe: Alias blake2signer.Blake2Signature was resolved to
            blake2signer.signers.Blake2Signature
DEBUG    -  griffe: Alias blake2signer.Blake2SignatureDump was resolved to
            blake2signer.signers.Blake2SignatureDump
DEBUG    -  griffe: Alias blake2signer.Blake2Signer was resolved to
            blake2signer.signers.Blake2Signer
DEBUG    -  griffe: Alias blake2signer.Blake2TimestampSigner was resolved to
            blake2signer.signers.Blake2TimestampSigner
DEBUG    -  griffe: Alias resolution error for blake2signer.hashers.blake3 -> blake3.blake3
DEBUG    -  griffe: Alias blake2signer.hashers.has_blake3 was resolved to
            blake2signer.hashers.blake3_package.has_blake3
DEBUG    -  griffe: Alias blake2signer.hashers.BLAKE2Hasher was resolved to
            blake2signer.hashers.blakehashers.BLAKE2Hasher
DEBUG    -  griffe: Alias blake2signer.hashers.BLAKE3Hasher was resolved to
            blake2signer.hashers.blakehashers.BLAKE3Hasher
DEBUG    -  griffe: Alias blake2signer.hashers.HasherChoice was resolved to
            blake2signer.hashers.blakehashers.HasherChoice
DEBUG    -  griffe: Iteration 1 finished, 9 aliases resolved, still 1 to go
DEBUG    -  griffe: Alias resolution error for blake2signer.hashers.blake3 -> blake3.blake3
DEBUG    -  griffe: Iteration 2 finished, 0 aliases resolved, still 1 to go
WARNING  -  mkdocstrings_handlers: 1 aliases were still unresolved after 2 iterations
DEBUG    -  mkdocstrings: Updating renderer's env
DEBUG    -  mkdocstrings: Rendering templates
...

This line caught my attention: Alias resolution error for blake2signer.hashers.blake3 -> blake3.blake3: blake2signer.hashers.blake3 does not exists per se, hashers is a module, and blake3 is an import from a submodule in __init__.py: from .blake3_package import blake3. It seems that Griffe is having issues w/ that.
This is referenced in a doc file as: ::: blake2signer.hashers, and blake3 does not appear in the rendered docs.
If I instead reference directly blake2signer.hashers.blake3, as ::: blake2signer.hashers.blake3, I get this exception, and the build fails:

...
DEBUG    -  griffe: Alias resolution error for blake2signer.hashers.blake3 -> blake3.blake3
DEBUG    -  griffe: Alias blake2signer.hashers.has_blake3 was resolved to
            blake2signer.hashers.blake3_package.has_blake3
DEBUG    -  griffe: Alias blake2signer.hashers.BLAKE2Hasher was resolved to
            blake2signer.hashers.blakehashers.BLAKE2Hasher
DEBUG    -  griffe: Alias blake2signer.hashers.BLAKE3Hasher was resolved to
            blake2signer.hashers.blakehashers.BLAKE3Hasher
DEBUG    -  griffe: Alias blake2signer.hashers.HasherChoice was resolved to
            blake2signer.hashers.blakehashers.HasherChoice
DEBUG    -  griffe: Iteration 1 finished, 9 aliases resolved, still 1 to go
DEBUG    -  griffe: Alias resolution error for blake2signer.hashers.blake3 -> blake3.blake3
DEBUG    -  griffe: Iteration 2 finished, 0 aliases resolved, still 1 to go
WARNING  -  mkdocstrings_handlers: 1 aliases were still unresolved after 2 iterations
...
DEBUG    -  mkdocstrings: Using handler 'python'
DEBUG    -  mkdocstrings: Collecting data
DEBUG    -  mkdocstrings: Rendering templates
ERROR    -  mkdocstrings: Template 'alias.html' not found for 'python' handler and theme
            'material'.
ERROR    -  Error reading page 'hashers.md': alias.html
Traceback (most recent call last):
...
    raise TemplateNotFound(template)
jinja2.exceptions.TemplateNotFound: alias.html

This is from my open-source project, you can build the docs yourself if needed: https://gitlab.com/hackancuba/blake2signer/

  1. Clone the repo: git clone git@gitlab.com:hackancuba/blake2signer.git
  2. Go into project dir, ignore main project: cd blake2signer
  3. Go into docs subdir: cd docs
  4. Install deps: poetry install (a .venv dir is automatically created locally by Poetry)
  5. Run mkdocs: poetry run mkdocs build -v

Thanks a lot. i’ll try to find some time the next days to setup a simplified project-repo to reproduce the error.