From 5d45e44d14d970664079dc20bf3a941fb53b3ee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Fri, 24 Jan 2025 13:20:34 +0100 Subject: [PATCH 1/4] Update handler for mkdocstrings 0.28 --- ci-constraints.txt | 4 +- mkdocstrings_handlers/vba/_handler.py | 78 ++++++++++++++++----------- mypy-requirements.txt | 4 +- setup.py | 2 +- 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/ci-constraints.txt b/ci-constraints.txt index 8dd68c6..bbedc19 100644 --- a/ci-constraints.txt +++ b/ci-constraints.txt @@ -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 diff --git a/mkdocstrings_handlers/vba/_handler.py b/mkdocstrings_handlers/vba/_handler.py index 60828f9..5a71e3f 100644 --- a/mkdocstrings_handlers/vba/_handler.py +++ b/mkdocstrings_handlers/vba/_handler.py @@ -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, @@ -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 @@ -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. """ @@ -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, @@ -141,32 +151,32 @@ 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 @@ -174,42 +184,48 @@ def update_env(self, md: Markdown, config: Dict[Any, Any]) -> None: 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) 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) diff --git a/mypy-requirements.txt b/mypy-requirements.txt index fab278d..7f188ec 100644 --- a/mypy-requirements.txt +++ b/mypy-requirements.txt @@ -1,3 +1,3 @@ -mypy==1.11.2 -types-setuptools==75.* +mypy==1.17.* +types-setuptools==80.* types-Markdown==3.* diff --git a/setup.py b/setup.py index acfa5ff..fc2e0b2 100644 --- a/setup.py +++ b/setup.py @@ -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", ], From e57a4a8b092490dcd2cdfe9221b829c8e18d0864 Mon Sep 17 00:00:00 2001 From: dolf Date: Mon, 1 Sep 2025 10:06:59 +0200 Subject: [PATCH 2/4] Use proper `ClassVar` typing for overrides. --- mkdocstrings_handlers/vba/_handler.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mkdocstrings_handlers/vba/_handler.py b/mkdocstrings_handlers/vba/_handler.py index 5a71e3f..ae45498 100644 --- a/mkdocstrings_handlers/vba/_handler.py +++ b/mkdocstrings_handlers/vba/_handler.py @@ -12,6 +12,7 @@ Dict, Mapping, Tuple, + ClassVar, ) from griffe import patch_loggers @@ -50,17 +51,17 @@ def __init__(self, *, base_dir: Path, encoding: str, **kwargs: Any) -> None: self.base_dir = base_dir self.encoding = encoding - name: str = "vba" # type: ignore[misc] + name: ClassVar[str] = "vba" """ The handler's name. """ - domain: str = "vba" # type: ignore[misc] + domain: ClassVar[str] = "vba" """ The cross-documentation domain/language for this handler. """ - fallback_theme = "material" + fallback_theme: ClassVar[str] = "material" """ The theme to fall back to. """ From 256f7740299a930ae432432ff7c07e51e05de98d Mon Sep 17 00:00:00 2001 From: dolf Date: Mon, 1 Sep 2025 09:54:57 +0200 Subject: [PATCH 3/4] Refactor `find_procedures` to satisfy MyPy. --- mkdocstrings_handlers/vba/_util.py | 35 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/mkdocstrings_handlers/vba/_util.py b/mkdocstrings_handlers/vba/_util.py index 6b8af72..d1146df 100644 --- a/mkdocstrings_handlers/vba/_util.py +++ b/mkdocstrings_handlers/vba/_util.py @@ -1,5 +1,5 @@ import re -from typing import List, Generator +from typing import List, Generator, Tuple from griffe import Docstring, Function, Parameters, Parameter, Parser @@ -132,7 +132,12 @@ def parse_signature(line: str) -> VbaSignatureInfo: def find_procedures(code: str) -> Generator[VbaProcedureInfo, None, None]: lines = code.splitlines() - procedure = None + + procedure: Tuple[VbaSignatureInfo, int] | None = None + """ + The signature and first line number of the procedure currently being parsed, + or None when scanning for the start of the next procedure. + """ for i, line in enumerate(lines): if procedure is None: @@ -140,21 +145,17 @@ def find_procedures(code: str) -> Generator[VbaProcedureInfo, None, None]: if not is_signature(line): continue - procedure = { - "signature": parse_signature(line), - "first_line": i + 1, - } + procedure = parse_signature(line), i + 1 continue if is_end(line): # Found the end of a procedure. - procedure["last_line"] = i + 1 + signature, first_line = procedure + last_line = i + 1 # The docstring consists of the comment lines directly after the signature. docstring_lines = [] - procedure_source = lines[ - procedure["first_line"] - 1 : procedure["last_line"] - 1 - ] + procedure_source = lines[first_line - 1 : last_line - 1] for source_line in procedure_source[1:]: if not is_comment(source_line): break @@ -167,9 +168,9 @@ def find_procedures(code: str) -> Generator[VbaProcedureInfo, None, None]: value=docstring_value, parser=Parser.google, parser_options={}, - lineno=procedure["first_line"] + 1, + lineno=first_line + 1, parent=Function( - name=procedure["signature"].name, + name=signature.name, parameters=Parameters( *( Parameter( @@ -177,19 +178,19 @@ def find_procedures(code: str) -> Generator[VbaProcedureInfo, None, None]: annotation=arg.arg_type, default=arg.default, ) - for arg in procedure["signature"].args + for arg in signature.args ) ), - returns=procedure["signature"].return_type, + returns=signature.return_type, ), ) # Yield it and start over. yield VbaProcedureInfo( - signature=procedure["signature"], + signature=signature, docstring=docstring, - first_line=procedure["first_line"], - last_line=procedure["last_line"], + first_line=first_line, + last_line=last_line, source=procedure_source, ) procedure = None From 99d3e6ea6f340140d7df5104853ff541f1a1a47a Mon Sep 17 00:00:00 2001 From: dolf Date: Mon, 1 Sep 2025 10:08:25 +0200 Subject: [PATCH 4/4] Add missing required kwargs in unit test. --- test/handler/test_collect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/handler/test_collect.py b/test/handler/test_collect.py index 5fdff67..5d23143 100644 --- a/test/handler/test_collect.py +++ b/test/handler/test_collect.py @@ -11,7 +11,7 @@ def _test_collect(*, write_bytes: bytes, read_encoding: str) -> VbaModuleInfo: with TemporaryDirectory() as tmp_dir_str: tmp_dir = Path(tmp_dir_str) - handler = get_handler(encoding=read_encoding) + handler = get_handler(encoding=read_encoding, mdx=[], mdx_config={}) p = tmp_dir / "source.bas" p.write_bytes(write_bytes) return handler.collect(identifier=p.as_posix(), config={})