Skip to content

Commit d0e744b

Browse files
committed
docs: add griffe_exts.py script for prettier docs
This allows to dynamically link to the Slurm Documentation with different Slurm versions. For example it will replace this in the docstring: {slurm.conf#OPT_MpiParams} with this in the finally rendered docs, when we are on pyslurm 24.11.x: https://slurm.schedmd.com/archive/slurm-24.11-latest/slurm.conf.html#OPT_MpiParams This way we can dynamically link to the Slurm docs.
1 parent 4fd6443 commit d0e744b

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ plugins:
6060
show_root_heading: true
6161
show_symbol_type_toc: true
6262
show_symbol_type_heading: true
63+
extensions:
64+
- scripts/griffe_exts.py:DynamicDocstrings
6365

6466
markdown_extensions:
6567
- admonition

scripts/griffe_exts.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#########################################################################
2+
# scripts/griffe_exts.py - griffe extensions for documentation
3+
#########################################################################
4+
# Copyright (C) 2025 Toni Harzendorf <[email protected]>
5+
#
6+
# This file is part of PySlurm
7+
#
8+
# PySlurm is free software; you can redistribute it and/or modify
9+
# it under the terms of the GNU General Public License as published by
10+
# the Free Software Foundation; either version 2 of the License, or
11+
# (at your option) any later version.
12+
13+
# PySlurm is distributed in the hope that it will be useful,
14+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
# GNU General Public License for more details.
17+
#
18+
# You should have received a copy of the GNU General Public License along
19+
# with PySlurm; if not, write to the Free Software Foundation, Inc.,
20+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21+
22+
import ast
23+
import inspect
24+
import griffe
25+
import pyslurm
26+
import re
27+
28+
logger = griffe.get_logger(__name__)
29+
SLURM_VERSION = ".".join(pyslurm.__version__.split(".")[:-1])
30+
SLURM_DOCS_URL_BASE = "https://slurm.schedmd.com/archive"
31+
SLURM_DOCS_URL_VERSIONED = f"{SLURM_DOCS_URL_BASE}/slurm-{SLURM_VERSION}-latest"
32+
33+
config_files = ["acct_gather.conf", "slurm.conf", "cgroup.conf", "mpi.conf"]
34+
35+
36+
def replace_with_slurm_docs_url(match):
37+
first_part = match.group(1)
38+
second_part = match.group(2)
39+
ref = f"[{first_part}{second_part}]"
40+
return f'{ref}({SLURM_DOCS_URL_VERSIONED}/{first_part}.html{second_part})'
41+
42+
43+
pattern = re.compile(
44+
r'\{('
45+
+ '|'.join([re.escape(config) for config in config_files])
46+
+ r')' # Match the first word before "#"
47+
+ r'([#][^}]+)\}' # Match "#" and everything after it until }
48+
)
49+
50+
# This class is inspired from here, with a few adaptions:
51+
# https://github.com/mkdocstrings/griffe/blob/97f3613c5f0ae5653e8b91479c716b9ec44baacc/docs/guide/users/extending.md#full-example
52+
#
53+
# ISC License
54+
#
55+
# Copyright (c) 2021, Timothée Mazzucotelli
56+
#
57+
# Permission to use, copy, modify, and/or distribute this software for any
58+
# purpose with or without fee is hereby granted, provided that the above
59+
# copyright notice and this permission notice appear in all copies.
60+
#
61+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
62+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
63+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
64+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
65+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
66+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
67+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
68+
class DynamicDocstrings(griffe.Extension):
69+
def __init__(self, object_paths: list[str] | None = None) -> None:
70+
self.object_paths = object_paths
71+
72+
def on_instance(
73+
self,
74+
node: ast.AST | griffe.ObjectNode,
75+
obj: griffe.Object,
76+
agent: griffe.Visitor | griffe.Inspector,
77+
**kwargs,
78+
) -> None:
79+
if self.object_paths and obj.path not in self.object_paths:
80+
return
81+
82+
try:
83+
runtime_obj = griffe.dynamic_import(obj.path)
84+
docstring = runtime_obj.__doc__
85+
except ImportError:
86+
logger.debug(f"Could not get dynamic docstring for {obj.path}")
87+
return
88+
except AttributeError:
89+
logger.debug(f"Object {obj.path} does not have a __doc__ attribute")
90+
return
91+
92+
if not docstring or not obj.docstring:
93+
return
94+
95+
# Update the object instance with the evaluated docstring.
96+
fmt_docstring = pattern.sub(replace_with_slurm_docs_url, docstring)
97+
docstring = inspect.cleandoc(fmt_docstring)
98+
obj.docstring.value = docstring

0 commit comments

Comments
 (0)