Skip to content

Commit a657d07

Browse files
committedFeb 28, 2025·
fix: De-duplicate summary sections
Give precedence to manually written sections. Issue-134: #134
1 parent cfa9848 commit a657d07

File tree

5 files changed

+156
-49
lines changed

5 files changed

+156
-49
lines changed
 

‎src/mkdocstrings_handlers/python/templates/material/_base/summary/attributes.html.jinja

+14-12
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
-#}
88
{% endblock logs %}
99

10-
{% with section = obj.attributes
11-
|filter_objects(
12-
filters=config.filters,
13-
members_list=members_list,
14-
inherited_members=config.inherited_members,
15-
keep_no_docstrings=config.show_if_no_docstring,
16-
)
17-
|order_members(config.members_order, members_list)
18-
|as_attributes_section(check_public=not members_list)
19-
%}
20-
{% if section %}{% include "docstring/attributes"|get_template with context %}{% endif %}
21-
{% endwith %}
10+
{% if not obj.docstring.parsed | selectattr("kind.value", "eq", "attributes") %}
11+
{% with section = obj.attributes
12+
|filter_objects(
13+
filters=config.filters,
14+
members_list=members_list,
15+
inherited_members=config.inherited_members,
16+
keep_no_docstrings=config.show_if_no_docstring,
17+
)
18+
|order_members(config.members_order, members_list)
19+
|as_attributes_section(check_public=not members_list)
20+
%}
21+
{% if section %}{% include "docstring/attributes"|get_template with context %}{% endif %}
22+
{% endwith %}
23+
{% endif %}

‎src/mkdocstrings_handlers/python/templates/material/_base/summary/classes.html.jinja

+14-12
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
-#}
88
{% endblock logs %}
99

10-
{% with section = obj.classes
11-
|filter_objects(
12-
filters=config.filters,
13-
members_list=members_list,
14-
inherited_members=config.inherited_members,
15-
keep_no_docstrings=config.show_if_no_docstring,
16-
)
17-
|order_members(config.members_order, members_list)
18-
|as_classes_section(check_public=not members_list)
19-
%}
20-
{% if section %}{% include "docstring/classes"|get_template with context %}{% endif %}
21-
{% endwith %}
10+
{% if not obj.docstring.parsed | selectattr("kind.value", "eq", "classes") %}
11+
{% with section = obj.classes
12+
|filter_objects(
13+
filters=config.filters,
14+
members_list=members_list,
15+
inherited_members=config.inherited_members,
16+
keep_no_docstrings=config.show_if_no_docstring,
17+
)
18+
|order_members(config.members_order, members_list)
19+
|as_classes_section(check_public=not members_list)
20+
%}
21+
{% if section %}{% include "docstring/classes"|get_template with context %}{% endif %}
22+
{% endwith %}
23+
{% endif %}

‎src/mkdocstrings_handlers/python/templates/material/_base/summary/functions.html.jinja

+14-12
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
-#}
88
{% endblock logs %}
99

10-
{% with section = obj.functions
11-
|filter_objects(
12-
filters=config.filters,
13-
members_list=members_list,
14-
inherited_members=config.inherited_members,
15-
keep_no_docstrings=config.show_if_no_docstring,
16-
)
17-
|order_members(config.members_order, members_list)
18-
|as_functions_section(check_public=not members_list)
19-
%}
20-
{% if section %}{% include "docstring/functions"|get_template with context %}{% endif %}
21-
{% endwith %}
10+
{% if not obj.docstring.parsed | selectattr("kind.value", "eq", "functions") %}
11+
{% with section = obj.functions
12+
|filter_objects(
13+
filters=config.filters,
14+
members_list=members_list,
15+
inherited_members=config.inherited_members,
16+
keep_no_docstrings=config.show_if_no_docstring,
17+
)
18+
|order_members(config.members_order, members_list)
19+
|as_functions_section(check_public=not members_list)
20+
%}
21+
{% if section %}{% include "docstring/functions"|get_template with context %}{% endif %}
22+
{% endwith %}
23+
{% endif %}

‎src/mkdocstrings_handlers/python/templates/material/_base/summary/modules.html.jinja

+14-12
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
-#}
88
{% endblock logs %}
99

10-
{% with section = obj.modules
11-
|filter_objects(
12-
filters=config.filters,
13-
members_list=members_list,
14-
inherited_members=config.inherited_members,
15-
keep_no_docstrings=config.show_if_no_docstring,
16-
)
17-
|order_members("alphabetical", members_list)
18-
|as_modules_section(check_public=not members_list)
19-
%}
20-
{% if section %}{% include "docstring/modules"|get_template with context %}{% endif %}
21-
{% endwith %}
10+
{% if not obj.docstring.parsed | selectattr("kind.value", "eq", "modules") %}
11+
{% with section = obj.modules
12+
|filter_objects(
13+
filters=config.filters,
14+
members_list=members_list,
15+
inherited_members=config.inherited_members,
16+
keep_no_docstrings=config.show_if_no_docstring,
17+
)
18+
|order_members("alphabetical", members_list)
19+
|as_modules_section(check_public=not members_list)
20+
%}
21+
{% if section %}{% include "docstring/modules"|get_template with context %}{% endif %}
22+
{% endwith %}
23+
{% endif %}

‎tests/test_handler.py

+100-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from typing import TYPE_CHECKING
1111

1212
import pytest
13-
from griffe import DocstringSectionExamples, DocstringSectionKind, temporary_visited_module
13+
from griffe import Docstring, DocstringSectionExamples, DocstringSectionKind, Module, temporary_visited_module
1414

1515
from mkdocstrings_handlers.python.config import PythonConfig, PythonOptions
1616
from mkdocstrings_handlers.python.handler import CollectionError, PythonHandler
@@ -179,3 +179,102 @@ def test_give_precedence_to_user_paths() -> None:
179179
mdx_config={},
180180
)
181181
assert handler._paths[0] == last_sys_path
182+
183+
184+
@pytest.mark.parametrize(
185+
("section", "code"),
186+
[
187+
(
188+
"Attributes",
189+
"""
190+
class A:
191+
'''Summary.
192+
193+
Attributes:
194+
x: X.
195+
y: Y.
196+
'''
197+
x: int = 0
198+
'''X.'''
199+
y: int = 0
200+
'''Y.'''
201+
""",
202+
),
203+
(
204+
"Methods",
205+
"""
206+
class A:
207+
'''Summary.
208+
209+
Methods:
210+
x: X.
211+
y: Y.
212+
'''
213+
def x(self): ...
214+
'''X.'''
215+
def y(self): ...
216+
'''Y.'''
217+
""",
218+
),
219+
(
220+
"Functions",
221+
"""
222+
'''Summary.
223+
224+
Functions:
225+
x: X.
226+
y: Y.
227+
'''
228+
def x(): ...
229+
'''X.'''
230+
def y(): ...
231+
'''Y.'''
232+
""",
233+
),
234+
(
235+
"Classes",
236+
"""
237+
'''Summary.
238+
239+
Classes:
240+
A: A.
241+
B: B.
242+
'''
243+
class A: ...
244+
'''A.'''
245+
class B: ...
246+
'''B.'''
247+
""",
248+
),
249+
(
250+
"Modules",
251+
"""
252+
'''Summary.
253+
254+
Modules:
255+
a: A.
256+
b: B.
257+
'''
258+
""",
259+
),
260+
],
261+
)
262+
def test_deduplicate_summary_sections(handler: PythonHandler, section: str, code: str) -> None:
263+
"""Assert summary sections are deduplicated."""
264+
summary_section = section.lower()
265+
summary_section = "functions" if summary_section == "methods" else summary_section
266+
with temporary_visited_module(code, docstring_parser="google") as module: # type: ignore[arg-type]
267+
if summary_section == "modules":
268+
module.set_member("a", Module("A", docstring=Docstring("A.")))
269+
module.set_member("b", Module("B", docstring=Docstring("B.")))
270+
html = handler.render(
271+
module,
272+
handler.get_options(
273+
{
274+
"summary": {summary_section: True},
275+
"show_source": False,
276+
"show_submodules": True,
277+
},
278+
),
279+
)
280+
assert html.count(f"{section}:") == 1

0 commit comments

Comments
 (0)
Please sign in to comment.