Skip to content

griffe_sphinx ¤

Griffe Sphinx package.

Parse Sphinx-comments about attributes as docstrings.

Classes:

SphinxCommentsExtension ¤

Bases: Extension

Parse Sphinx-comments about attributes as docstrings.

Methods:

on_attribute_instance ¤

on_attribute_instance(
    *,
    node: AST | ObjectNode,
    attr: Attribute,
    agent: Visitor | Inspector,
    **kwargs: Any,
) -> None

Parse Sphinx-comments about attributes as docstrings.

Parameters:

  • node ¤

    (AST | ObjectNode) –

    The attribute node being visited.

  • attr ¤

    (Attribute) –

    The attribute being built.

  • agent ¤

    (Visitor | Inspector) –

    The visitor or inspector visiting the attribute.

  • **kwargs ¤

    (Any, default: {} ) –

    Additional keyword arguments.

Source code in src/griffe_sphinx/_internal/extension.py
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def on_attribute_instance(
    self,
    *,
    node: ast.AST | griffe.ObjectNode,
    attr: griffe.Attribute,
    agent: griffe.Visitor | griffe.Inspector,
    **kwargs: Any,  # noqa: ARG002
) -> None:
    """Parse Sphinx-comments about attributes as docstrings.

    Parameters:
        node: The attribute node being visited.
        attr: The attribute being built.
        agent: The visitor or inspector visiting the attribute.
        **kwargs: Additional keyword arguments.
    """
    if attr.docstring is None:
        if attr.lineno is None or attr.endlineno is None:
            _logger.debug(f"Skipping Sphinx-comments parsing for {attr.path}: lineno or endlineno is None")
            return

        if isinstance(attr.filepath, list):
            # This should never happen (an attribute cannot be defined in a directory/native-namespace package),
            # but for good measure we handle the case.
            return

        # Look for doc comments in preceding lines first.
        file_lines = attr.lines_collection[attr.filepath]
        line_index = attr.lineno - 2  # -1 to go back one line, -1 to convert to a 0-based index.
        lines = []
        while line_index >= 0 and (line := file_lines[line_index].lstrip()).startswith("#:"):
            lines.append(line[2:])
            line_index -= 1

        if lines:
            attr.docstring = griffe.Docstring(
                dedent("\n".join(reversed(lines))),
                lineno=line_index + 2,
                endlineno=attr.lineno - 1,
                parent=attr,
                parser=agent.docstring_parser,
                parser_options=agent.docstring_options,
            )
            return

        # Otherwise look for inline trailing comments.
        if attr.endlineno != attr.lineno:  # not supported for multi-line assignments
            return

        if not isinstance(node, ast.AST):
            # Parse the source, as ObjectNodes have no source-related data (column offsets).
            try:
                node = ast.parse(attr.source).body[0]
            except (SyntaxError, IndexError):
                _logger.debug(f"Skipping Sphinx-comments parsing for {attr.path}: ast parsing failed")
                return

        try:
            has_col_offsets = node.col_offset is not None and node.end_col_offset is not None  # ty:ignore[unresolved-attribute]
        except AttributeError:
            # This shouldn't happen, as node would be an instance of ast.Assign or ast.AnnAssign.
            has_col_offsets = False

        if not has_col_offsets:
            _logger.debug(f"Skipping Sphinx-comments parsing for {attr.path}: node missing col offset")
            return

        try:
            node_end_in_source = node.end_col_offset - node.col_offset  # ty:ignore[unresolved-attribute]
        except AttributeError:
            return
        try:
            comment = attr.source[node_end_in_source:].split("#", maxsplit=1)[1]
        except IndexError:
            return

        if comment.startswith(":"):
            attr.docstring = griffe.Docstring(
                comment[1:].lstrip(),
                lineno=attr.lineno,
                endlineno=attr.lineno,
                parent=attr,
                parser=agent.docstring_parser,
                parser_options=agent.docstring_options,
            )