Skip to content

Commit 738ee2f

Browse files
committedFeb 7, 2024
Revise signatures and types on hover
- Only show signatures for function and class types - Also show types if there are definitons without signatures next to definitions with signatures
1 parent 5b5abf3 commit 738ee2f

File tree

1 file changed

+38
-26
lines changed

1 file changed

+38
-26
lines changed
 

‎pylsp/plugins/hover.py

+38-26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright 2017-2020 Palantir Technologies, Inc.
22
# Copyright 2021- Python Language Server Contributors.
33

4+
import itertools
45
import logging
56

67
from pylsp import _utils, hookimpl
@@ -42,38 +43,49 @@ def _find_docstring(definitions):
4243
return types[0].docstring(raw=True)
4344

4445

45-
def _find_signatures(definitions, word):
46-
# Get the signatures of all definitions
47-
signatures = [
48-
signature.to_string()
49-
for definition in definitions
50-
for signature in definition.get_signatures()
51-
if signature.type not in ["module"]
52-
]
53-
54-
if len(signatures) != 0:
46+
def _find_signatures_and_types(definitions):
47+
def _line_number(definition):
48+
"""Helper for sorting definitions by line number (which might be None)."""
49+
return definition.line if definition.line is not None else 0
50+
51+
def _get_signatures(definition):
52+
"""Get the signatures of functions and classes."""
53+
return [
54+
signature.to_string()
55+
for signature in definition.get_signatures()
56+
if signature.type in ["class", "function"]
57+
]
58+
59+
definitions = sorted(definitions, key=_line_number)
60+
signatures_per_def = [_get_signatures(d) for d in definitions]
61+
types_per_def = [d.infer() for d in definitions]
62+
63+
# a flat list with all signatures
64+
signatures = list(itertools.chain(*signatures_per_def))
65+
66+
# We want to show the type if there is at least one type that does not
67+
# correspond to a signature
68+
if any(
69+
len(s) == 0 and len(t) > 0 for s, t in zip(signatures_per_def, types_per_def)
70+
):
71+
# Get all types (also the ones that correspond to a signature)
72+
types = set(itertools.chain(*types_per_def))
73+
type_names = [t.name for t in sorted(types, key=_line_number)]
74+
75+
if len(type_names) == 1:
76+
return [*signatures, type_names[0]]
77+
elif len(type_names) > 1:
78+
return [*signatures, f"Union[{', '.join(type_names)}]"]
79+
80+
else:
81+
# The type does not add any information because it is already in the signatures
5582
return signatures
5683

57-
# If we did not find a signature, infer the possible types of all definitions
58-
types = [
59-
t.name
60-
for d in sorted(definitions, key=lambda d: d.line)
61-
for t in sorted(d.infer(), key=lambda t: t.line)
62-
]
63-
if len(types) == 1:
64-
return [types[0]]
65-
elif len(types) > 1:
66-
return [f"Union[{', '.join(types)}]"]
67-
6884

6985
@hookimpl
7086
def pylsp_hover(config, document, position):
7187
code_position = _utils.position_to_jedi_linecolumn(document, position)
72-
73-
# TODO(Review)
74-
# We could also use Script.help here. It would not resolve keywords
7588
definitions = document.jedi_script(use_document_path=True).help(**code_position)
76-
word = document.word_at_position(position)
7789

7890
hover_capabilities = config.capabilities.get("textDocument", {}).get("hover", {})
7991
supported_markup_kinds = hover_capabilities.get("contentFormat", ["markdown"])
@@ -83,6 +95,6 @@ def pylsp_hover(config, document, position):
8395
"contents": _utils.format_docstring(
8496
_find_docstring(definitions),
8597
preferred_markup_kind,
86-
signatures=_find_signatures(definitions, word),
98+
signatures=_find_signatures_and_types(definitions),
8799
)
88100
}

0 commit comments

Comments
 (0)