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

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions