Skip to content

Commit 862eb5b

Browse files
authored
Fix the mkdocstrings-macros pluglet (#352)
The new mkdocstrings-macros *pluglet* didn't work with the latest `mkdocstrings-python` version. To fix this we need to require a newer version of `mkdocstrings-python` and update the `mkdocstrings_macros.py` file to work with the new version.
2 parents 7d21f0b + b9ec9a2 commit 862eb5b

File tree

12 files changed

+40
-169
lines changed

12 files changed

+40
-169
lines changed

.github/cookiecutter-migrate.template.py

+21
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
And remember to follow any manual instructions for each run.
2121
""" # noqa: E501
2222

23+
import hashlib
2324
import os
2425
import subprocess
2526
import tempfile
@@ -98,6 +99,26 @@ def replace_file_contents_atomically( # noqa; DOC501
9899
raise
99100

100101

102+
def calculate_file_sha256_skip_lines(filepath: Path, skip_lines: int) -> str | None:
103+
"""Calculate SHA256 of file contents excluding the first N lines.
104+
105+
Args:
106+
filepath: Path to the file to hash
107+
skip_lines: Number of lines to skip at the beginning
108+
109+
Returns:
110+
The SHA256 hex digest, or None if the file doesn't exist
111+
"""
112+
if not filepath.exists():
113+
return None
114+
115+
# Read file and normalize line endings to LF
116+
content = filepath.read_text(encoding="utf-8").replace("\r\n", "\n")
117+
# Skip first N lines and ensure there's a trailing newline
118+
remaining_content = "\n".join(content.splitlines()[skip_lines:]) + "\n"
119+
return hashlib.sha256(remaining_content.encode()).hexdigest()
120+
121+
101122
def manual_step(message: str) -> None:
102123
"""Print a manual step message in yellow."""
103124
print(f"\033[0;33m>>> {message}\033[0m")

.github/workflows/ci.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ jobs:
197197
# This ensures that the runner has access to the pip cache.
198198
- name: Reset pip cache ownership
199199
if: always()
200-
run: sudo chown -R $USER:$USER /tmp/pip-cache
200+
run: if [[ -e /tmp/pip-cache ]]; then sudo chown -R $USER:$USER /tmp/pip-cache; fi
201201

202202
# This job runs if all the `nox-cross-arch` matrix jobs ran and succeeded.
203203
# As the `nox-all` job, its main purpose is to provide a single point of

RELEASE_NOTES.md

+2-35
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,9 @@
11
# Frequenz Repository Configuration Release Notes
22

3-
## Summary
4-
5-
This release introduces a new MkDocs macros *pluglet* system that simplifies documentation setup and provides enhanced functionality for version information and code annotations. It also includes changes to how pytest warnings are handled in templates.
6-
73
## Upgrading
84

9-
- The `nox` default `pytest` session doesn't pass `-W=all -vv` to `pytest` anymore. You can use the `pyproject.toml` file to configure default options for `pytest`, for example:
10-
11-
```toml
12-
[tool.pytest.ini_options]
13-
addopts = "-W=all -Werror -Wdefault::DeprecationWarning -Wdefault::PendingDeprecationWarning -vv"
14-
```
15-
16-
### Cookiecutter template
17-
18-
All upgrading should be done via the migration script or regenerating the templates.
19-
20-
```bash
21-
curl -sSL https://raw.githubusercontent.com/frequenz-floss/frequenz-repo-config-python/v0.12/cookiecutter/migrate.py | python3
22-
```
23-
24-
But you might still need to adapt your code:
25-
26-
- `pytest` now uses `-Werror` by default (but still treat deprecations as normal warnings), so if your tests run with warnings, they will now be turned to errors, and you'll need to fix them.
27-
28-
- Projects using `docs/_scripts/macros.py` with customized scripts can use the new provided utility functions. See the [`mkdocstrings_macros` documentation](https://frequenz-floss.github.io/frequenz-repo-config-python/v0.12/reference/frequenz/repo/config/mkdocs/mkdocstrings_macros/) for the new features and setup.
29-
30-
## New Features
31-
32-
- Two new modules were introduced to facilitate the configuration of `macros` for use within docstrings via `mkdocstrings`: [`mkdocstrings_macros`](https://frequenz-floss.github.io/frequenz-repo-config-python/v0.12/reference/frequenz/repo/config/mkdocs/mkdocstrings_macros/) and [`annotations`](https://frequenz-floss.github.io/frequenz-repo-config-python/v0.12/reference/frequenz/repo/config/mkdocs/annotations/).
33-
34-
### Cookiecutter template
35-
36-
- `pytest` now uses `-Werror -Wdefault::DeprecationWarning -Wdefault::PendingDeprecationWarning` by default. Deprecations are still treated as warnings, as when testing with the `pytest_min` session is normal to get deprecation warnings as we are using old versions of dependencies.
5+
Even if this is a patch release, it will require a dependency bump for `mkdocstrings-python` to v1.14.6 or newer, but since these are only dev dependencies and things will break if you update the dependencies anyway, it seems like a reasonable trade-off.
376

387
## Bug Fixes
398

40-
### Cookiecutter template
41-
42-
- Fixed a compatibility issue in the macros doc script with `mkdocsstrings` 0.28.
9+
- The new mkdocstrings-macros *pluglet* didn't work with the latest `mkdocstrings-python` version.

cookiecutter/migrate.py

+6-123
Original file line numberDiff line numberDiff line change
@@ -30,125 +30,8 @@
3030

3131
def main() -> None:
3232
"""Run the migration steps."""
33-
add_default_pytest_options()
33+
# Add a separation line like this one after each migration step.
3434
print("=" * 72)
35-
migrate_mkdocs_macros()
36-
print("=" * 72)
37-
38-
39-
def add_default_pytest_options() -> None:
40-
"""Add default pytest options to pyproject.toml."""
41-
pyproject_toml = Path("pyproject.toml")
42-
pyproject_toml_content = pyproject_toml.read_text(encoding="utf-8")
43-
marker = "[tool.pytest.ini_options]\n"
44-
new_options = (
45-
"-W=all -Werror -Wdefault::DeprecationWarning "
46-
"-Wdefault::PendingDeprecationWarning -vv"
47-
)
48-
49-
print(f"Adding default pytest options to {pyproject_toml}...")
50-
if pyproject_toml_content.find(marker) == -1:
51-
print(
52-
"Couldn't find the the {marker.strip()} marker in pyproject.toml, skipping update."
53-
)
54-
return
55-
56-
if pyproject_toml_content.find("\naddopts") >= 0:
57-
print("It looks like some options are already configured, skipping update.")
58-
manual_step(f"Please consider `{new_options}` if they are not there yet.")
59-
return
60-
61-
replace_file_contents_atomically(
62-
pyproject_toml,
63-
marker,
64-
marker + f'addopts = "{new_options}"\n',
65-
)
66-
67-
68-
def migrate_mkdocs_macros() -> None:
69-
"""Migrate from custom macros.py to standard module."""
70-
macros_file = Path("docs/_scripts/macros.py")
71-
mkdocs_yaml = Path("mkdocs.yaml")
72-
if not mkdocs_yaml.exists():
73-
mkdocs_yaml = Path("mkdocs.yml")
74-
75-
known_hashes = {
76-
"47a991286132471b6cb666577beb89e78c0f5d4975c53f0dcb319c4338a2c3cb",
77-
"6bb960c72b370ac77918f49d7a35f39c0ddb58fe52cf2d12caa2577098fd8469",
78-
"7351276ac314955a343bab09d1602e50300887291f841643e9fb79c94acc923c",
79-
"8fa5f9f3fd928e17f590e3ab056434474633259d615971404db0d2f3034adb62",
80-
"ba3ff5f1612b3dd22372a8ca95394b8ea468f18dcefc494c73811c8433fcb880",
81-
"dd32e8759abc43232bb3db5b33c0a7cf8d8442db6135c594968c499d8bae0ce5",
82-
}
83-
84-
print("Checking if docs/_scripts/macros.py can be migrated...")
85-
86-
file_hash = calculate_file_sha256_skip_lines(macros_file, 2)
87-
if not file_hash:
88-
return
89-
90-
if file_hash not in known_hashes:
91-
manual_step("The macros.py file seems to be customized. You have two options:")
92-
manual_step("")
93-
manual_step(
94-
"1. Switch to the standard module (if you don't have custom macros):"
95-
)
96-
manual_step(" a. Update mkdocs.yaml to use the standard module:")
97-
manual_step(
98-
' module_name: docs/_scripts/macros -> modules: ["frequenz.repo.config.mkdocs.mkdocstrings_macros"]' # noqa: E501
99-
)
100-
manual_step(" b. Remove docs/_scripts/macros.py")
101-
manual_step("")
102-
manual_step("2. Keep your custom macros but use the standard functionality:")
103-
manual_step(" a. Update mkdocs.yaml:")
104-
manual_step(" - Keep using module_name: docs/_scripts/macros")
105-
manual_step(" b. Update your macros.py to be minimal:")
106-
manual_step(" ```python")
107-
manual_step(
108-
" from frequenz.repo.config.mkdocs.mkdocstrings_macros import hook_env_with_everything" # noqa: E501
109-
)
110-
manual_step("")
111-
manual_step(" def define_env(env):")
112-
manual_step(" # Add your custom variables, filters, and macros here")
113-
manual_step(" env.variables.my_var = 'Example'")
114-
manual_step(" env.filters.my_filter = lambda x: x.upper()")
115-
manual_step("")
116-
manual_step(
117-
" # This must be at the end to enable all standard features"
118-
)
119-
manual_step(" hook_env_with_everything(env)")
120-
manual_step(" ```")
121-
manual_step("")
122-
manual_step("See the docs for more details:")
123-
manual_step(
124-
"https://frequenz-floss.github.io/frequenz-repo-config-python/v0.12/reference/frequenz/repo/config/mkdocs/mkdocstrings_macros/" # noqa: E501
125-
)
126-
return
127-
128-
if not mkdocs_yaml.exists():
129-
print("mkdocs.yaml/yml not found, skipping macros migration")
130-
return
131-
132-
content = mkdocs_yaml.read_text(encoding="utf-8")
133-
if "module_name: docs/_scripts/macros" not in content:
134-
print("Custom macros configuration not found in mkdocs.yaml")
135-
return
136-
137-
print("Updating mkdocs.yaml to use standard module...")
138-
new_content = content.replace(
139-
"module_name: docs/_scripts/macros",
140-
'modules: ["frequenz.repo.config.mkdocs.mkdocstrings_macros"]',
141-
)
142-
new_content = new_content.replace(
143-
"# inside docstrings. See the comment in `docs/_scripts/macros.py` for more\n"
144-
" # details\n",
145-
"# inside docstrings.\n",
146-
)
147-
148-
replace_file_contents_atomically(mkdocs_yaml, content, new_content)
149-
150-
print("Removing docs/_scripts/macros.py...")
151-
macros_file.unlink()
15235

15336

15437
def apply_patch(patch_content: str) -> None:
@@ -216,11 +99,6 @@ def replace_file_contents_atomically( # noqa; DOC501
21699
raise
217100

218101

219-
def manual_step(message: str) -> None:
220-
"""Print a manual step message in yellow."""
221-
print(f"\033[0;33m>>> {message}\033[0m")
222-
223-
224102
def calculate_file_sha256_skip_lines(filepath: Path, skip_lines: int) -> str | None:
225103
"""Calculate SHA256 of file contents excluding the first N lines.
226104
@@ -241,5 +119,10 @@ def calculate_file_sha256_skip_lines(filepath: Path, skip_lines: int) -> str | N
241119
return hashlib.sha256(remaining_content.encode()).hexdigest()
242120

243121

122+
def manual_step(message: str) -> None:
123+
"""Print a manual step message in yellow."""
124+
print(f"\033[0;33m>>> {message}\033[0m")
125+
126+
244127
if __name__ == "__main__":
245128
main()

cookiecutter/{{cookiecutter.github_repo_name}}/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ dev-mkdocs = [
100100
"mkdocs-macros-plugin == 1.3.7",
101101
"mkdocs-material == 9.6.2",
102102
"mkdocstrings[python] == 0.28.0",
103-
"mkdocstrings-python == 1.14.0",
103+
"mkdocstrings-python == 1.14.6",
104104
"frequenz-repo-config[{{cookiecutter.type}}] == 0.12.0",
105105
]
106106
dev-mypy = [

pyproject.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ dependencies = [
4141
"mkdocs-gen-files >= 0.4.0, < 0.6.0",
4242
"semver >= 3.0.1, < 4",
4343
"github-action-utils >= 1.1.0, < 2",
44+
"mkdocstrings-python >= 1.14.6, < 2",
4445
]
4546
dynamic = ["version"]
4647

@@ -83,7 +84,7 @@ dev-mkdocs = [
8384
"mkdocs-macros-plugin == 1.3.7",
8485
"mkdocs-material == 9.6.2",
8586
"mkdocstrings[python] == 0.28.0",
86-
"mkdocstrings-python == 1.13.0",
87+
"mkdocstrings-python == 1.14.6",
8788
]
8889
dev-mypy = [
8990
"mypy == 1.14.1",

src/frequenz/repo/config/mkdocs/mkdocstrings_macros.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ def define_env(env: macros.MacrosPlugin) -> None:
112112
import logging
113113
from typing import Any
114114

115-
import markdown as md
116115
from markdown.extensions import toc
117116
from mkdocs_macros import plugin as macros
118117

@@ -210,8 +209,8 @@ def hook_macros_plugin(env: macros.MacrosPlugin) -> None:
210209
update_env = python_handler.update_env
211210

212211
# override the `update_env` method of the Python handler
213-
def patched_update_env(md: md.Markdown, config: dict[str, Any]) -> None:
214-
update_env(md, config)
212+
def patched_update_env(config: dict[str, Any]) -> None:
213+
update_env(config=config)
215214

216215
# get the `convert_markdown` filter of the env
217216
convert_markdown = python_handler.env.filters["convert_markdown"]

tests_golden/integration/test_cookiecutter_generation/actor/frequenz-actor-test/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ dev-mkdocs = [
5959
"mkdocs-macros-plugin == 1.3.7",
6060
"mkdocs-material == 9.6.2",
6161
"mkdocstrings[python] == 0.28.0",
62-
"mkdocstrings-python == 1.14.0",
62+
"mkdocstrings-python == 1.14.6",
6363
"frequenz-repo-config[actor] == 0.12.0",
6464
]
6565
dev-mypy = [

tests_golden/integration/test_cookiecutter_generation/api/frequenz-api-test/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ dev-mkdocs = [
7070
"mkdocs-macros-plugin == 1.3.7",
7171
"mkdocs-material == 9.6.2",
7272
"mkdocstrings[python] == 0.28.0",
73-
"mkdocstrings-python == 1.14.0",
73+
"mkdocstrings-python == 1.14.6",
7474
"frequenz-repo-config[api] == 0.12.0",
7575
]
7676
dev-mypy = [

tests_golden/integration/test_cookiecutter_generation/app/frequenz-app-test/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ dev-mkdocs = [
5858
"mkdocs-macros-plugin == 1.3.7",
5959
"mkdocs-material == 9.6.2",
6060
"mkdocstrings[python] == 0.28.0",
61-
"mkdocstrings-python == 1.14.0",
61+
"mkdocstrings-python == 1.14.6",
6262
"frequenz-repo-config[app] == 0.12.0",
6363
]
6464
dev-mypy = [

tests_golden/integration/test_cookiecutter_generation/lib/frequenz-test-python/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ dev-mkdocs = [
5555
"mkdocs-macros-plugin == 1.3.7",
5656
"mkdocs-material == 9.6.2",
5757
"mkdocstrings[python] == 0.28.0",
58-
"mkdocstrings-python == 1.14.0",
58+
"mkdocstrings-python == 1.14.6",
5959
"frequenz-repo-config[lib] == 0.12.0",
6060
]
6161
dev-mypy = [

tests_golden/integration/test_cookiecutter_generation/model/frequenz-model-test/pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ dev-mkdocs = [
5959
"mkdocs-macros-plugin == 1.3.7",
6060
"mkdocs-material == 9.6.2",
6161
"mkdocstrings[python] == 0.28.0",
62-
"mkdocstrings-python == 1.14.0",
62+
"mkdocstrings-python == 1.14.6",
6363
"frequenz-repo-config[model] == 0.12.0",
6464
]
6565
dev-mypy = [

0 commit comments

Comments
 (0)