Skip to content

Commit ae42356

Browse files
committed
feat: Support inheritance
Issue mkdocstrings#157: mkdocstrings/mkdocstrings#157 Discussion mkdocstrings#536: mkdocstrings/mkdocstrings#536
1 parent 8eb459f commit ae42356

File tree

8 files changed

+325
-41
lines changed

8 files changed

+325
-41
lines changed

docs/usage/configuration/members.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,169 @@ this_attribute = 0
8989

9090
INFO: **The default behavior (with unspecified `members` or `members: null`) is to use [`filters`][].**
9191

92+
## `inherited_members`
93+
94+
- **:octicons-package-24: Type <code><span data-autorefs-optional="list">list</span>[<span data-autorefs-optional="str">str</span>] |
95+
<span data-autorefs-optional="bool">bool</span></code> :material-equal: `False`{ title="default value" }**
96+
<!-- - **:octicons-project-template-24: Template :material-null:** (N/A) -->
97+
98+
An explicit list of inherited members (for classes) to render.
99+
100+
Inherited members are always fetched from classes that are in the same package
101+
as the currently rendered class. To fetch members inherited from base classes,
102+
themselves coming from external packages, use the [`preload_modules`][preload_modules] option.
103+
For example, if your class inherits from Pydantic's `BaseModel`, and you want to render
104+
`BaseModel`'s methods in your class, use `preload_modules: [pydantic]`.
105+
The `pydantic` package must be available in the current environment.
106+
107+
Passing a falsy value (`no`, `false` in YAML) or an empty list (`[]`)
108+
will tell the Python handler not to render any inherited member.
109+
Passing a truthy value (`yes`, `true` in YAML)
110+
will tell the Python handler to render every inherited member.
111+
112+
When all inherited members are selected with `inherited_members: true`,
113+
it is possible to specify both members and inherited members in the `members` list:
114+
115+
```yaml
116+
inherited_members: true
117+
members:
118+
- inherited_member_a
119+
- inherited_member_b
120+
- member_x
121+
- member_y
122+
```
123+
124+
The alternative is not supported:
125+
126+
```yaml
127+
inherited_members:
128+
- inherited_member_a
129+
- inherited_member_b
130+
members:
131+
- member_x
132+
- member_y
133+
```
134+
135+
...because it would make members ordering ambiguous/unspecified.
136+
137+
You can render inherited members *only* by setting `inherited_members: true`
138+
(or a list of inherited members) and setting `members: false`:
139+
140+
```yaml
141+
inherited_members: true
142+
members: false
143+
```
144+
145+
```yaml
146+
inherited_members:
147+
- inherited_member_a
148+
- inherited_member_b
149+
members: false
150+
```
151+
152+
You can render *all declared members* and all or specific inherited members
153+
by leaving `members` as null (default):
154+
155+
```yaml
156+
inherited_members:
157+
- inherited_member_a
158+
- inherited_member_b
159+
# members: null # (1)
160+
```
161+
162+
1. In this case, only declared members will be subject
163+
to further filtering with [`filters`][filters] and [`docstrings`][show_if_no_docstring].
164+
165+
```yaml
166+
inherited_members: true # (1)
167+
# members: null
168+
```
169+
170+
1. In this case, both declared and inherited members will be subject
171+
to further filtering with [`filters`][filters] and [`docstrings`][show_if_no_docstring].
172+
173+
You can render *all declared members* and all or specific inherited members,
174+
avoiding further filtering with [`filters`][filters] and [`docstrings`][show_if_no_docstring]
175+
by setting `members: true`:
176+
177+
```yaml
178+
inherited_members: true
179+
members: true
180+
```
181+
182+
```yaml
183+
inherited_members:
184+
- inherited_member_a
185+
- inherited_member_b
186+
members: true
187+
```
188+
189+
The general rule is that declared or inherited members specified in lists
190+
are never filtered out.
191+
192+
```yaml title="in mkdocs.yml (global configuration)"
193+
plugins:
194+
- mkdocstrings:
195+
handlers:
196+
python:
197+
options:
198+
inherited_members: false
199+
```
200+
201+
```md title="or in docs/some_page.md (local configuration)"
202+
::: package.module
203+
options:
204+
inherited_members: true
205+
```
206+
207+
```python title="package/module.py"
208+
"""Module docstring."""
209+
210+
class Base:
211+
"""Base class."""
212+
213+
def base(self):
214+
"""Base method."""
215+
216+
217+
class Main(Base):
218+
"""Main class."""
219+
220+
def main(self):
221+
"""Main method."""
222+
```
223+
224+
/// admonition | Preview
225+
type: preview
226+
227+
//// tab | With inherited members
228+
<p>Module docstring.</p>
229+
<h2><code>Base</code></h2>
230+
<p>Base class.</p>
231+
<h3><code>base</code></h3>
232+
<p>Base method.</p>
233+
<h2><code>Main</code></h2>
234+
<p>Main class.</p>
235+
<h3><code>base</code></h3>
236+
<p>Base method.</p>
237+
<h3><code>main</code></h3>
238+
<p>Main method.</p>
239+
////
240+
241+
//// tab | Without inherited members
242+
<p>Module docstring.</p>
243+
<h2><code>Base</code></h2>
244+
<p>Base class.</p>
245+
<h3><code>base</code></h3>
246+
<p>Base method.</p>
247+
<h2><code>Main</code></h2>
248+
<p>Main class.</p>
249+
<h3><code>main</code></h3>
250+
<p>Main method.</p>
251+
////
252+
253+
///
254+
92255
## `members_order`
93256

94257
- **:octicons-package-24: Type [`str`][] :material-equal: `"alphabetical"`{ title="default value" }**

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ plugins:
143143
ignore_init_summary: true
144144
docstring_section_style: list
145145
heading_level: 1
146+
inherited_members: true
146147
merge_init_into_class: true
148+
preload_modules: [mkdocstrings]
147149
separate_signature: true
148150
show_root_heading: true
149151
show_root_full_path: false

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ classifiers = [
3030
]
3131
dependencies = [
3232
"mkdocstrings>=0.20",
33-
"griffe>=0.24",
33+
"griffe>=0.30",
3434
]
3535

3636
[project.urls]

src/mkdocstrings_handlers/python/handler.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class PythonHandler(BaseHandler):
106106
"members_order": rendering.Order.alphabetical.value,
107107
"docstring_section_style": "table",
108108
"members": None,
109+
"inherited_members": False,
109110
"filters": ["!^_[^_]"],
110111
"annotations_path": "brief",
111112
"preload_modules": None,
@@ -138,7 +139,13 @@ class PythonHandler(BaseHandler):
138139
show_category_heading (bool): When grouped by categories, show a heading for each category. Default: `False`.
139140
140141
Attributes: Members options:
141-
members (list[str] | False | None): An explicit list of members to render. Default: `None`.
142+
inherited_members (list[str] | bool | None): A boolean, or an explicit list of inherited members to render.
143+
If true, select all inherited members, which can then be filtered with `members`.
144+
If false or empty list, do not select any inherited member. Default: `False`.
145+
members (list[str] | bool | None): A boolean, or an explicit list of members to render.
146+
If true, select all members without further filtering.
147+
If false or empty list, do not render members.
148+
If none, select all members and apply further filtering with filters and docstrings. Default: `None`.
142149
members_order (str): The members ordering to use. Options: `alphabetical` - order by the members names,
143150
`source` - order members as they appear in the source file. Default: `"alphabetical"`.
144151
filters (list[str] | None): A list of filters applied to filter objects based on their name.

src/mkdocstrings_handlers/python/rendering.py

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ def do_filter_objects(
194194
objects_dictionary: dict[str, Object | Alias],
195195
*,
196196
filters: Sequence[tuple[Pattern, bool]] | None = None,
197-
members_list: list[str] | None = None,
197+
members_list: bool | list[str] | None = None,
198+
inherited_members: bool | list[str] = False,
198199
keep_no_docstrings: bool = True,
199200
) -> list[Object | Alias]:
200201
"""Filter a dictionary of objects based on their docstrings.
@@ -207,31 +208,49 @@ def do_filter_objects(
207208
members_list: An optional, explicit list of members to keep.
208209
When given and empty, return an empty list.
209210
When given and not empty, ignore filters and docstrings presence/absence.
211+
inherited_members: Whether to keep inherited members or exclude them.
210212
keep_no_docstrings: Whether to keep objects with no/empty docstrings (recursive check).
211213
212214
Returns:
213215
A list of objects.
214216
"""
215-
# no members
216-
if members_list is False or members_list == []:
217-
return []
218-
219-
objects = list(objects_dictionary.values())
217+
inherited_members_specified = False
218+
if inherited_members is True:
219+
# Include all inherited members.
220+
objects = list(objects_dictionary.values())
221+
elif inherited_members is False:
222+
# Include no inherited members.
223+
objects = [obj for obj in objects_dictionary.values() if not obj.inherited]
224+
else:
225+
# Include specific inherited members.
226+
inherited_members_specified = True
227+
objects = [
228+
obj for obj in objects_dictionary.values() if not obj.inherited or obj.name in set(inherited_members)
229+
]
220230

221-
# all members
222231
if members_list is True:
232+
# Return all pre-selected members.
223233
return objects
224234

225-
# list of members
235+
if members_list is False or members_list == []:
236+
# Return selected inherited members, if any.
237+
return [obj for obj in objects if obj.inherited]
238+
226239
if members_list is not None:
227-
return [obj for obj in objects if obj.name in set(members_list)]
240+
# Return selected members (keeping any pre-selected inherited members).
241+
return [
242+
obj for obj in objects if obj.name in set(members_list) or (inherited_members_specified and obj.inherited)
243+
]
228244

229-
# none, use filters and docstrings
245+
# Use filters and docstrings.
230246
if filters:
231-
objects = [obj for obj in objects if _keep_object(obj.name, filters)]
247+
objects = [
248+
obj for obj in objects if _keep_object(obj.name, filters) or (inherited_members_specified and obj.inherited)
249+
]
232250
if keep_no_docstrings:
233251
return objects
234-
return [obj for obj in objects if obj.has_docstrings]
252+
253+
return [obj for obj in objects if obj.has_docstrings or (inherited_members_specified and obj.inherited)]
235254

236255

237256
@lru_cache(maxsize=1)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy