Skip to content

Formatting of signatures in docstrings #630

Open
@krassowski

Description

@krassowski

Problem

The formatting of signatures in hover and code completion documentation is fine for signatures of small functions:

Image

but is not necessarily readable for functions with many complex arguments:

Image

Proposed solution

Add a hook allowing to format the signature with a formatter of choice, e.g. with black. Users could then customize the number of characters in a lines, wrapping, and potentially custom highlighting (instead of using code fences).

Context

Currently docstrings in hover and completion documentation are composed of two parts:

  • signature
  • the docstring itself

The docstring gets formatted by docstring-to-markdown which now supports entrypoints allowing to add support for custom formats used in internal codebases or to override the formatting.

def format_docstring(
contents: str, markup_kind: str, signatures: Optional[List[str]] = None
):
"""Transform the provided docstring into a MarkupContent object.
If `markup_kind` is 'markdown' the docstring will get converted to
markdown representation using `docstring-to-markdown`; if it is
`plaintext`, it will be returned as plain text.
Call signatures of functions (or equivalent code summaries)
provided in optional `signatures` argument will be prepended
to the provided contents of the docstring if given.
"""
if not isinstance(contents, str):
contents = ""
if markup_kind == "markdown":
try:
value = docstring_to_markdown.convert(contents)
except docstring_to_markdown.UnknownFormatError:
# try to escape the Markdown syntax instead:
value = escape_markdown(contents)
if signatures:
value = wrap_signature("\n".join(signatures)) + "\n\n" + value
return {"kind": "markdown", "value": value}
value = contents
if signatures:
value = "\n".join(signatures) + "\n\n" + value
return {"kind": "plaintext", "value": escape_plain_text(value)}

The signature part formatting is hard-coded to use wrap_signature:

def wrap_signature(signature):
return "```python\n" + signature + "\n```\n"

The signature strings come from jedi's BaseSignature.to_string() method:

docs = _utils.format_docstring(
d.docstring(raw=True),
signatures=[signature.to_string() for signature in d.get_signatures()],
markup_kind=markup_kind,

# Find first exact matching signature
signature = next(
(
x.to_string()
for x in definition.get_signatures()
if (x.name == word and x.type not in ["module"])
),
"",
)
return {
"contents": _utils.format_docstring(
# raw docstring returns only doc, without signature
definition.docstring(raw=True),
preferred_markup_kind,
signatures=[signature] if signature else None,
)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions