Skip to content

Commit 66542e3

Browse files
committed
feat: Release Insiders project
1 parent 6393375 commit 66542e3

5 files changed

Lines changed: 137 additions & 2 deletions

File tree

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,63 @@ Parse Sphinx-comments above attributes as docstrings.
1111
This project is available to sponsors only, through my Insiders program.
1212
See Insiders [explanation](https://mkdocstrings.github.io/griffe-sphinx/insiders/)
1313
and [installation instructions](https://mkdocstrings.github.io/griffe-sphinx/insiders/installation/).
14+
15+
## Usage
16+
17+
Griffe Sphinx allows reading Sphinx comments above attribute assignments as docstrings.
18+
19+
```python
20+
# your_module.py
21+
22+
#: Summary of your attribute.
23+
#:
24+
#: This is a longer description of your attribute.
25+
#: You can use any markup in here (Markdown, AsciiDoc, rST, etc.).
26+
#:
27+
#: Be careful with indented blocks: they need 4 spaces plus the initial 1-space indent, so 5.
28+
#:
29+
#: print("hello!")
30+
your_attribute = "Hello Sphinx!"
31+
```
32+
33+
This works for module attributes as well as class and instance attributes.
34+
35+
```python
36+
class Hello:
37+
#: Summary of attribute.
38+
attr1 = "hello"
39+
40+
def __init__(self):
41+
#: Summary of attribute.
42+
self.attr2 = "sphinx"
43+
```
44+
45+
Trailing comments (appearing at the end of a line) are not supported.
46+
47+
You can now enable the extension when loading data with Griffe on the command-line, in Python code or with MkDocs.
48+
49+
**On the command-line:**
50+
51+
```bash
52+
griffe dump your_package -e griffe_sphinx
53+
```
54+
55+
**In Python code:**
56+
57+
```python
58+
import griffe
59+
60+
data = griffe.load("your_package", extensions=griffe.load_extensions("griffe_sphinx"))
61+
```
62+
63+
**With [MkDocs](https://www.mkdocs.org/):**
64+
65+
```yaml
66+
plugins:
67+
- mkdocstrings:
68+
handlers:
69+
python:
70+
options:
71+
extensions:
72+
- griffe_sphinx
73+
```

docs/insiders/goals.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ goals:
77
features: []
88
1500:
99
name: HyperLamp Navigation Tips
10-
features: []
10+
features:
11+
- name: "[Project] Parse Sphinx-comments above attributes as docstrings"
12+
ref: /
13+
since: 2024/08/15
1114
2000:
1215
name: FusionDrive Ejection Configuration
1316
features: []

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ classifiers = [
2929
"Typing :: Typed",
3030
]
3131
dependencies = [
32-
"griffe>=0.48",
32+
"griffe>=0.49",
3333
]
3434

3535
[project.urls]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,41 @@
1+
from __future__ import annotations
2+
3+
from typing import Any
4+
15
import griffe
26

7+
logger = griffe.get_logger("griffe_sphinx")
8+
39

410
class SphinxCommentsExtension(griffe.Extension):
511
"""Parse Sphinx-comments above attributes as docstrings."""
12+
13+
def on_attribute_instance(
14+
self,
15+
*,
16+
attr: griffe.Attribute,
17+
agent: griffe.Visitor | griffe.Inspector,
18+
**kwargs: Any, # noqa: ARG002
19+
) -> None:
20+
if attr.docstring is None:
21+
if attr.lineno is None or attr.endlineno is None:
22+
logger.debug(f"Skipping Sphinx-comments parsing for {attr.path}: lineno or endlineno is None")
23+
return
24+
if isinstance(attr.filepath, list):
25+
# This should never happen (an attribute cannot be defined in a directory/native-namespace package),
26+
# but for good measure we handle the case.
27+
return
28+
lineno = attr.lineno - 2
29+
lines = []
30+
while lineno and (line := attr.lines_collection[attr.filepath][lineno].lstrip()).startswith("#:"):
31+
lines.append(line[3:])
32+
lineno -= 1
33+
if lines:
34+
attr.docstring = griffe.Docstring(
35+
"\n".join(reversed(lines)),
36+
lineno=lineno + 2,
37+
endlineno=attr.lineno - 1,
38+
parent=attr,
39+
parser=agent.docstring_parser,
40+
parser_options=agent.docstring_options,
41+
)

tests/test_extension.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Tests for the extension module."""
2+
3+
from __future__ import annotations
4+
5+
import griffe
6+
7+
from griffe_sphinx import SphinxCommentsExtension
8+
9+
10+
def test_extension() -> None:
11+
"""Fetch comments from source."""
12+
with griffe.temporary_visited_module(
13+
"""
14+
#: Summary for `a`.
15+
#:
16+
#: Description for `a`.
17+
a = 0
18+
19+
class C:
20+
#: Summary for `b`.
21+
#:
22+
#: Description for `b`.
23+
b = 1
24+
25+
def __init__(self):
26+
#: Summary for `i`.
27+
#:
28+
#: Description for `i`.
29+
self.i = 2
30+
31+
""",
32+
extensions=griffe.load_extensions(SphinxCommentsExtension),
33+
) as module:
34+
assert module["a"].docstring.value == "Summary for `a`.\n\nDescription for `a`."
35+
assert module["C.b"].docstring.value == "Summary for `b`.\n\nDescription for `b`."
36+
assert module["C.i"].docstring.value == "Summary for `i`.\n\nDescription for `i`."

0 commit comments

Comments
 (0)