From 7d160f96f61f7e573fccc85a356898c1a34c51e2 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 1 Jan 2021 23:51:41 +0100 Subject: [PATCH] Do not show signatures for properties, fixes #1695 --- conftest.py | 5 +++++ jedi/api/classes.py | 2 ++ jedi/inference/names.py | 2 +- jedi/parser_utils.py | 6 ++--- test/test_inference/test_docstring.py | 32 +++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/conftest.py b/conftest.py index eeb531c3..c5d88f3b 100644 --- a/conftest.py +++ b/conftest.py @@ -140,6 +140,11 @@ def goto_or_help_or_infer(request, Script): return do +@pytest.fixture(scope='session', params=['goto', 'complete', 'help']) +def goto_or_complete(request, Script): + return lambda code, *args, **kwargs: getattr(Script(code), request.param)(*args, **kwargs) + + @pytest.fixture(scope='session') def has_django(environment): script = jedi.Script('import django', environment=environment) diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 0cd3371d..fba9b5ad 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -550,6 +550,8 @@ class BaseName: return ''.join(lines[start_index:index + after + 1]) def _get_signatures(self, for_docstring=False): + if self._name.api_type == 'property': + return [] if for_docstring and self._name.api_type == 'statement' and not self.is_stub(): # For docstrings we don't resolve signatures if they are simple # statements and not stubs. This is a speed optimization. diff --git a/jedi/inference/names.py b/jedi/inference/names.py index 2be1427c..f90f9749 100644 --- a/jedi/inference/names.py +++ b/jedi/inference/names.py @@ -340,7 +340,7 @@ class TreeNameDefinition(AbstractTreeName): @inference_state_method_cache(default='') def py__doc__(self): api_type = self.api_type - if api_type in ('function', 'class'): + if api_type in ('function', 'class', 'property'): # Make sure the names are not TreeNameDefinitions anymore. return clean_scope_docstring(self.tree_name.get_definition()) diff --git a/jedi/parser_utils.py b/jedi/parser_utils.py index 9c1290be..1a59165b 100644 --- a/jedi/parser_utils.py +++ b/jedi/parser_utils.py @@ -306,7 +306,7 @@ def expr_is_dotted(node): return node.type == 'name' -def _function_is_x_method(method_name): +def _function_is_x_method(*method_names): def wrapper(function_node): """ This is a heuristic. It will not hold ALL the times, but it will be @@ -316,7 +316,7 @@ def _function_is_x_method(method_name): """ for decorator in function_node.get_decorators(): dotted_name = decorator.children[1] - if dotted_name.get_code() == method_name: + if dotted_name.get_code() in method_names: return True return False return wrapper @@ -324,4 +324,4 @@ def _function_is_x_method(method_name): function_is_staticmethod = _function_is_x_method('staticmethod') function_is_classmethod = _function_is_x_method('classmethod') -function_is_property = _function_is_x_method('property') +function_is_property = _function_is_x_method('property', 'cached_property') diff --git a/test/test_inference/test_docstring.py b/test/test_inference/test_docstring.py index 62d36683..85e33933 100644 --- a/test/test_inference/test_docstring.py +++ b/test/test_inference/test_docstring.py @@ -507,3 +507,35 @@ def test_doctest_function_start(Script): return ''') assert Script(code).complete(7, 8) + + +@pytest.mark.parametrize( + "name, docstring", [ + ('prop1', 'Returns prop1.'), + ('prop2', 'Returns None or ...'), + ('prop3', 'Non-sense property.'), + ('prop4', 'Django like property'), + ] +) +def test_property(name, docstring, goto_or_complete): + code = dedent(''' + from typing import Optional + class Test: + @property + def prop1(self) -> int: + """Returns prop1.""" + + @property + def prop2(self) -> Optional[int]: + """Returns None or ...""" + + @property + def prop3(self) -> None: + """Non-sense property.""" + + @cached_property # Not imported, but Jedi uses a heuristic + def prop4(self) -> None: + """Django like property""" + ''') + n, = goto_or_complete(code + 'Test().' + name) + assert n.docstring() == docstring