Skip to content

Commit 21c5e66

Browse files
committed
Fix deprecation warnings by combining our Collector and Renderer class into the Handler class. Move static methods and helper functions to separate files.
1 parent 1d02f93 commit 21c5e66

5 files changed

Lines changed: 262 additions & 273 deletions

File tree

mkdocstrings_handlers/vba/_collector.py

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import re
2+
3+
from markupsafe import Markup
4+
5+
6+
def do_crossref(path: str, brief: bool = True) -> Markup:
7+
"""Filter to create cross-references.
8+
9+
Parameters:
10+
path: The path to link to.
11+
brief: Show only the last part of the path, add the full path as hover.
12+
13+
Returns:
14+
Markup text.
15+
"""
16+
full_path = path
17+
if brief:
18+
path = full_path.split(".")[-1]
19+
return Markup(
20+
"<span data-autorefs-optional-hover={full_path}>{path}</span>"
21+
).format(full_path=full_path, path=path)
22+
23+
24+
def do_multi_crossref(text: str, code: bool = True) -> Markup:
25+
"""Filter to create cross-references.
26+
27+
Parameters:
28+
text: The text to scan.
29+
code: Whether to wrap the result in a code tag.
30+
31+
Returns:
32+
Markup text.
33+
"""
34+
group_number = 0
35+
variables = {}
36+
37+
def repl(match): # noqa: WPS430
38+
nonlocal group_number # noqa: WPS420
39+
group_number += 1
40+
path = match.group()
41+
path_var = f"path{group_number}"
42+
variables[path_var] = path
43+
return (
44+
f"<span data-autorefs-optional-hover={{{path_var}}}>{{{path_var}}}</span>"
45+
)
46+
47+
text = re.sub(r"([\w.]+)", repl, text)
48+
if code:
49+
text = f"<code>{text}</code>"
50+
return Markup(text).format(**variables)

mkdocstrings_handlers/vba/_handler.py

Lines changed: 162 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,100 @@
1-
"""This module implements a handler for the VBA language."""
1+
"""
2+
This module implements a handler for the VBA language.
3+
"""
4+
5+
from __future__ import annotations
26

37
import posixpath
8+
from collections import ChainMap
49
from pathlib import Path
510
from typing import Any, BinaryIO, Iterator, Optional, Tuple
611

712
from griffe.logger import patch_loggers
13+
from markdown import Markdown
14+
from mkdocs.exceptions import PluginError
815
from mkdocstrings.handlers.base import BaseHandler
916
from mkdocstrings.inventory import Inventory
1017
from mkdocstrings.loggers import get_logger
1118

12-
from mkdocstrings_handlers.vba._collector import VbaCollector
13-
from mkdocstrings_handlers.vba._renderer import VbaRenderer
19+
from ._crossref import do_crossref, do_multi_crossref
20+
from ._sort import Order, do_order_members
21+
from ._types import VbaModuleInfo
22+
from ._util import find_file_docstring, collapse_long_lines, find_procedures
1423

1524
patch_loggers(get_logger)
1625

1726

1827
class VbaHandler(BaseHandler):
19-
"""The Vba handler class."""
28+
"""
29+
The VBA handler class.
30+
"""
31+
32+
base_dir: Path
33+
"""
34+
The directory in which to look for VBA files.
35+
"""
36+
37+
def __init__(self, *, base_dir: Path, **kwargs: Any) -> None:
38+
super().__init__(**kwargs)
39+
self.base_dir = base_dir
2040

2141
domain: str = "vba"
22-
"""The cross-documentation domain/language for this handler."""
42+
"""
43+
The cross-documentation domain/language for this handler.
44+
"""
2345

2446
enable_inventory: bool = True
25-
"""Whether this handler is interested in enabling the creation of the `objects.inv` Sphinx inventory file."""
47+
"""
48+
Whether this handler is interested in enabling the creation of the `objects.inv` Sphinx inventory file.
49+
"""
50+
51+
fallback_theme = "material"
52+
"""
53+
The theme to fall back to.
54+
"""
55+
56+
default_config: dict = {
57+
"show_root_heading": False,
58+
"show_root_toc_entry": True,
59+
"show_root_full_path": True,
60+
"show_root_members_full_path": False,
61+
"show_object_full_path": False,
62+
"show_category_heading": False,
63+
"show_if_no_docstring": False,
64+
"show_signature": True,
65+
"separate_signature": False,
66+
"line_length": 60,
67+
"show_source": True,
68+
"show_bases": True,
69+
"show_submodules": True,
70+
"heading_level": 2,
71+
"members_order": Order.alphabetical.value,
72+
"docstring_section_style": "table",
73+
}
74+
"""
75+
The default rendering options.
76+
77+
See [`default_config`][mkdocstrings_handlers.vba.renderer.VbaRenderer.default_config].
78+
79+
Option | Type | Description | Default
80+
------ | ---- | ----------- | -------
81+
**`show_root_heading`** | `bool` | Show the heading of the object at the root of the documentation tree. | `False`
82+
**`show_root_toc_entry`** | `bool` | If the root heading is not shown, at least add a ToC entry for it. | `True`
83+
**`show_root_full_path`** | `bool` | Show the full VBA path for the root object heading. | `True`
84+
**`show_object_full_path`** | `bool` | Show the full VBA path of every object. | `False`
85+
**`show_root_members_full_path`** | `bool` | Show the full VBA path of objects that are children of the root object (for example, classes in a module). When False, `show_object_full_path` overrides. | `False`
86+
**`show_category_heading`** | `bool` | When grouped by categories, show a heading for each category. | `False`
87+
**`show_if_no_docstring`** | `bool` | Show the object heading even if it has no docstring or children with docstrings. | `False`
88+
**`show_signature`** | `bool` | Show method and function signatures. | `True`
89+
**`separate_signature`** | `bool` | Whether to put the whole signature in a code block below the heading. | `False`
90+
**`line_length`** | `int` | Maximum line length when formatting code. | `60`
91+
**`show_source`** | `bool` | Show the source code of this object. | `True`
92+
**`show_bases`** | `bool` | Show the base classes of a class. | `True`
93+
**`show_submodules`** | `bool` | When rendering a module, show its submodules recursively. | `True`
94+
**`heading_level`** | `int` | The initial heading level to use. | `2`
95+
**`members_order`** | `str` | The members ordering to use. Options: `alphabetical` - order by the members names, `source` - order members as they appear in the source file. | `alphabetical`
96+
**`docstring_section_style`** | `str` | The style used to render docstring sections. Options: `table`, `list`, `spacy`. | `table`
97+
"""
2698

2799
@classmethod
28100
def load_inventory(
@@ -51,6 +123,81 @@ def load_inventory(
51123
for item in Inventory.parse_sphinx(in_file, domain_filter=("py",)).values():
52124
yield item.name, posixpath.join(base_url, item.uri)
53125

126+
def render(
127+
self,
128+
data: VbaModuleInfo,
129+
config: dict,
130+
) -> str:
131+
final_config = ChainMap(config, self.default_config)
132+
render_type = "module"
133+
134+
template = self.env.get_template(f"{render_type}.html")
135+
136+
# Heading level is a "state" variable, that will change at each step
137+
# of the rendering recursion. Therefore, it's easier to use it as a plain value
138+
# than as an item in a dictionary.
139+
heading_level = final_config["heading_level"]
140+
try:
141+
final_config["members_order"] = Order(final_config["members_order"])
142+
except ValueError:
143+
choices = "', '".join(item.value for item in Order)
144+
raise PluginError(
145+
f"Unknown members_order '{final_config['members_order']}', choose between '{choices}'."
146+
)
147+
148+
return template.render(
149+
**{
150+
"config": final_config,
151+
render_type: data,
152+
"heading_level": heading_level,
153+
"root": True,
154+
},
155+
)
156+
157+
def get_anchors(self, data: VbaModuleInfo) -> list[str]:
158+
return list(
159+
{data.path.as_posix(), *(p.signature.name for p in data.procedures)}
160+
)
161+
162+
def update_env(self, md: Markdown, config: dict) -> None:
163+
super().update_env(md, config)
164+
self.env.trim_blocks = True
165+
self.env.lstrip_blocks = True
166+
self.env.keep_trailing_newline = False
167+
self.env.filters["crossref"] = do_crossref
168+
self.env.filters["multi_crossref"] = do_multi_crossref
169+
self.env.filters["order_members"] = do_order_members
170+
171+
def collect(
172+
self,
173+
identifier: str,
174+
config: dict,
175+
) -> VbaModuleInfo:
176+
"""Collect the documentation tree given an identifier and selection options.
177+
178+
Arguments:
179+
identifier: Which VBA file (.bas or .cls) to collect from.
180+
config: Selection options, used to alter the data collection.
181+
182+
Raises:
183+
CollectionError: When there was a problem collecting the documentation.
184+
185+
Returns:
186+
The collected object tree.
187+
"""
188+
p = Path(self.base_dir, identifier)
189+
with p.open("r") as f:
190+
code = f.read()
191+
192+
code = collapse_long_lines(code)
193+
194+
return VbaModuleInfo(
195+
docstring=find_file_docstring(code),
196+
source=code.splitlines(),
197+
path=p,
198+
procedures=list(find_procedures(code)),
199+
)
200+
54201

55202
def get_handler(
56203
theme: str,
@@ -60,7 +207,8 @@ def get_handler(
60207
locale: str = "en",
61208
**config: Any,
62209
) -> VbaHandler:
63-
"""Simply return an instance of `VbaHandler`.
210+
"""
211+
Simply return an instance of `VbaHandler`.
64212
65213
Arguments:
66214
theme: The theme to use when rendering contents.
@@ -74,6 +222,11 @@ def get_handler(
74222
An instance of `VbaHandler`.
75223
"""
76224
return VbaHandler(
77-
collector=VbaCollector(base_dir=Path(config_file_path).parent),
78-
renderer=VbaRenderer("vba", theme, custom_templates),
225+
base_dir=Path(config_file_path).parent,
226+
handler="vba",
227+
theme=theme,
228+
custom_templates=custom_templates,
229+
config_file_path=config_file_path,
230+
paths=paths,
231+
locale=locale,
79232
)

0 commit comments

Comments
 (0)