Skip to content

Update handler for mkdocstrings 0.28 #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions ci-constraints.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mkdocstrings==0.26.1
griffe==1.3.1
mkdocstrings==0.30.0
griffe==1.12.1
mkdocs-material==9.2.1
78 changes: 47 additions & 31 deletions mkdocstrings_handlers/vba/_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

from __future__ import annotations

import copy
from collections import ChainMap
from copy import deepcopy
from pathlib import Path
from typing import (
Any,
Expand All @@ -16,9 +15,9 @@
)

from griffe import patch_loggers
from markdown import Markdown
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.exceptions import PluginError
from mkdocstrings.handlers.base import BaseHandler, CollectionError
from mkdocstrings import BaseHandler, CollectionError
from mkdocstrings.loggers import get_logger

from ._crossref import do_crossref, do_multi_crossref
Expand Down Expand Up @@ -51,12 +50,12 @@ def __init__(self, *, base_dir: Path, encoding: str, **kwargs: Any) -> None:
self.base_dir = base_dir
self.encoding = encoding

name: str = "vba"
name: str = "vba" # type: ignore[misc]
"""
The handler's name.
"""

domain: str = "vba"
domain: str = "vba" # type: ignore[misc]
"""
The cross-documentation domain/language for this handler.
"""
Expand Down Expand Up @@ -107,6 +106,17 @@ def __init__(self, *, base_dir: Path, encoding: str, **kwargs: Any) -> None:
**`docstring_section_style`** | `str` | The style used to render docstring sections. Options: `table`, `list`, `spacy`. | `table`
"""

def get_options(self, local_options: Mapping[str, Any]) -> Dict[str, Any]:
"""Combine the default options with the local options.

Arguments:
local_options: The options provided in Markdown pages.

Returns:
The combined options.
"""
return deepcopy({**self.default_config, **local_options})

def collect(
self,
identifier: str,
Expand Down Expand Up @@ -141,75 +151,81 @@ def collect(
def render(
self,
data: VbaModuleInfo,
config: Mapping[str, Any],
options: MutableMapping[str, Any],
*,
locale: str | None = None,
) -> str:
final_config = ChainMap(dict(copy.deepcopy(config)), self.default_config)
template = self.env.get_template(f"module.html")

# Heading level is a "state" variable, that will change at each step
# of the rendering recursion. Therefore, it's easier to use it as a plain value
# than as an item in a dictionary.
heading_level = final_config["heading_level"]
heading_level = options["heading_level"]
try:
final_config["members_order"] = Order(final_config["members_order"])
options["members_order"] = Order(options["members_order"])
except ValueError:
choices = "', '".join(item.value for item in Order)
raise PluginError(
f"Unknown members_order '{final_config['members_order']}', choose between '{choices}'."
f"Unknown members_order '{options['members_order']}', choose between '{choices}'."
)

return template.render(
config=final_config,
config=options,
module=data,
heading_level=heading_level,
root=True,
)

def update_env(self, md: Markdown, config: Dict[Any, Any]) -> None:
super().update_env(md, config)
def update_env(self, config: Dict[Any, Any]) -> None:
self.env.trim_blocks = True
self.env.lstrip_blocks = True
self.env.keep_trailing_newline = False
self.env.filters["crossref"] = do_crossref
self.env.filters["multi_crossref"] = do_multi_crossref
self.env.filters["order_members"] = do_order_members

def get_anchors(self, data: VbaModuleInfo) -> Tuple[str, ...]:
def get_aliases(self, identifier: str) -> Tuple[str, ...]:
"""Get the aliases of the given identifier.

Aliases are used to register secondary URLs in mkdocs-autorefs,
to make sure cross-references work with any location of the same object.

Arguments:
identifier: The identifier to get aliases for.

Returns:
A tuple of aliases for the given identifier.
"""
try:
data = self.collect(identifier, {})
except CollectionError:
return ()
return data.path.as_posix(), *(p.signature.name for p in data.procedures)
Comment on lines +199 to 203
Copy link
Member Author

@pawamoy pawamoy Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have replicated previous behavior here, but I have to note that this seems incorrect to return both the path of the file, as well as all the procedure names within it. It's possible that the previous method (get_anchors) was confusing, and the "anchors" concept not well explained. The renaming to get_aliases is to make it more clear: it's not really about HTML anchors, it's about obtaining all the different "aliases" ("locations") for a given object, to correctly populate mkdocs-autorefs data. I know nothing about VBA, but surely Procedure1 is not an alias of Procedure2?

Aliases (and the identifier) are supposed to be strings that you can pass to collect.

Here I'd either just return (data.path.as_posix(),) (or even an empty tuple ()), or add a way to support collecting Procedure1 without a file path (or these procedure objects should expose fully qualified names that can be collected).



def get_handler(
*,
theme: str = "material",
custom_templates: str | None = None,
config_file_path: str | None = None,
encoding: str = "latin1",
tool_config: MkDocsConfig | None = None,
**kwargs: Any,
) -> VbaHandler:
"""
Get a new `VbaHandler`.

Arguments:
theme: The theme to use when rendering contents.
custom_templates: Directory containing custom templates.
config_file_path: The MkDocs configuration file path.
encoding:
The encoding to use when reading VBA files.
Excel exports .bas and .cls files as `latin1`.
See https://en.wikipedia.org/wiki/ISO/IEC_8859-1 .
tool_config: SSG configuration.
kwargs: Extra keyword arguments that we don't use.

Returns:
An instance of `VbaHandler`.
"""
return VbaHandler(
base_dir=(
Path(config_file_path).resolve().parent
if config_file_path
else Path(".").resolve()
),
encoding=encoding,
handler="vba",
theme=theme,
custom_templates=custom_templates,
base_dir = (
Path(getattr(tool_config, "config_file_path", None) or "./mkdocs.yml")
.resolve()
.parent
)
return VbaHandler(base_dir=base_dir, encoding=encoding, **kwargs)
4 changes: 2 additions & 2 deletions mypy-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mypy==1.11.2
types-setuptools==75.*
mypy==1.17.*
types-setuptools==80.*
types-Markdown==3.*
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"setuptools_scm",
],
install_requires=[
"mkdocstrings>=0.26.1,<1",
"mkdocstrings>=0.30,<1",
"griffe>=1.3.1,<2",
"mkdocs-material>=9.2,<10",
],
Expand Down
Loading