11# Copyright 2017-2020 Palantir Technologies, Inc.
22# Copyright 2021- Python Language Server Contributors.
33
4+ import itertools
45import logging
56
67from 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
7086def 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