From 7ca62578e11031ae09a6ad79fd74089de25ed46d Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Thu, 20 Apr 2017 09:45:12 +0200 Subject: [PATCH] Add py__doc__ as a better approach to docstrings. --- jedi/api/classes.py | 45 ++++++++++------------------- jedi/evaluate/compiled/__init__.py | 8 ++--- jedi/evaluate/context.py | 13 +++++++++ jedi/evaluate/representation.py | 2 ++ test/test_api/test_classes.py | 24 ++++++++++++--- test/test_evaluate/test_compiled.py | 2 +- 6 files changed, 56 insertions(+), 38 deletions(-) diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 0839014c..315195db 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -15,9 +15,9 @@ from jedi.evaluate import representation as er from jedi.evaluate import instance from jedi.evaluate import imports from jedi.evaluate import compiled -from jedi.evaluate.filters import ParamName +from jedi.evaluate.filters import ParamName, TreeNameDefinition +from jedi.evaluate.imports import ImportName from jedi.api.keywords import KeywordName -from jedi.parser_utils import clean_scope_docstring, get_doc_with_call_signature def _sort_names_by_start_pos(names): @@ -255,7 +255,7 @@ class BaseDefinition(object): .. todo:: Remove! """ warnings.warn("Use docstring() instead.", DeprecationWarning) - return self.docstring() + return self.docstring(raw=False) @property def raw_doc(self): @@ -469,7 +469,7 @@ class Completion(BaseDefinition): # In this case we can just resolve the like name, because we # wouldn't load like > 100 Python modules anymore. fast = False - return super(Completion, self,).docstring(raw, fast) + return super(Completion, self).docstring(raw=raw, fast=fast) @property def description(self): @@ -698,22 +698,14 @@ class _Help(object): self._name = definition @memoize_method - def _get_node(self, fast): - if isinstance(self._name, (compiled.CompiledContextName, compiled.CompiledName)): - followed = self._name.infer() - if followed: - return next(iter(followed)) - return None + def _get_contexts(self, fast): + if isinstance(self._name, ImportName) and fast: + return {} - if self._name.api_type == 'module' and not fast: - followed = self._name.infer() - if followed: - # TODO: Use all of the followed objects as input to Documentation. - context = next(iter(followed)) - return context.tree_node - if self._name.tree_name is None: - return None - return self._name.tree_name.get_definition() + if self._name.api_type == 'statement': + return {} + + return self._name.infer() def docstring(self, fast=True, raw=True): """ @@ -721,14 +713,9 @@ class _Help(object): See :attr:`doc` for example. """ - node = self._get_node(fast) + # TODO: Use all of the followed objects as output. Possibly divinding + # them by a few dashes. + for context in self._get_contexts(fast=fast): + return context.py__doc__(include_call_signature=not raw) - try: - node.get_doc_node - except AttributeError: - return '' - else: - if raw: - return clean_scope_docstring(node) - else: - return get_doc_with_call_signature(node) + return '' diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index 5d5fb1ac..88c65367 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -94,8 +94,7 @@ class CompiledObject(Context): def is_class(self): return inspect.isclass(self.obj) - @property - def doc(self): + def py__doc__(self, include_call_signature=False): return inspect.getdoc(self.obj) or '' @property @@ -129,10 +128,11 @@ class CompiledObject(Context): @underscore_memoization def _parse_function_doc(self): - if self.doc is None: + doc = self.py__doc__() + if doc is None: return '', '' - return _parse_function_doc(self.doc) + return _parse_function_doc(doc) @property def api_type(self): diff --git a/jedi/evaluate/context.py b/jedi/evaluate/context.py index 58872527..cef67689 100644 --- a/jedi/evaluate/context.py +++ b/jedi/evaluate/context.py @@ -1,6 +1,7 @@ from jedi._compatibility import Python3Method from jedi.common import unite from jedi.parser.python.tree import ExprStmt, CompFor +from jedi.parser_utils import clean_scope_docstring, get_doc_with_call_signature class Context(object): @@ -63,6 +64,18 @@ class Context(object): """ return True + def py__doc__(self, include_call_signature=False): + try: + self.tree_node.get_doc_node + except AttributeError: + return '' + else: + if include_call_signature: + return get_doc_with_call_signature(self.tree_node) + else: + return clean_scope_docstring(self.tree_node) + return None + class TreeContext(Context): def __init__(self, evaluator, parent_context=None): diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index d759bc6b..73a75670 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -32,6 +32,8 @@ py__package__() Only on modules. For the import system. py__path__() Only on modules. For the import system. py__get__(call_object) Only on instances. Simulates descriptors. +py__doc__(include_call_signature: Returns the docstring for a context. + bool) ====================================== ======================================== """ diff --git a/test/test_api/test_classes.py b/test/test_api/test_classes.py index c1a76219..9cea9cd9 100644 --- a/test/test_api/test_classes.py +++ b/test/test_api/test_classes.py @@ -129,11 +129,27 @@ def test_completion_docstring(): docstr('import jedi\njedi.Scr', cleandoc(Script.__doc__)) docstr('abcd=3;abcd', '') - docstr('"hello"\nabcd=3\nabcd', 'hello') - # It works with a ; as well. - docstr('"hello"\nabcd=3;abcd', 'hello') + docstr('"hello"\nabcd=3\nabcd', '') + docstr(dedent(''' + def x(): + "hello" + 0 + x'''), + 'hello' + ) + docstr(dedent(''' + def x(): + "hello";0 + x'''), + 'hello' + ) # Shouldn't work with a tuple. - docstr('"hello",0\nabcd=3\nabcd', '') + docstr(dedent(''' + def x(): + "hello",0 + x'''), + '' + ) def test_completion_params(): diff --git a/test/test_evaluate/test_compiled.py b/test/test_evaluate/test_compiled.py index 78ab8e3c..5bcaa2e7 100644 --- a/test/test_evaluate/test_compiled.py +++ b/test/test_evaluate/test_compiled.py @@ -53,7 +53,7 @@ def test_doc(): just a Jedi API definition. """ obj = compiled.CompiledObject(_evaluator(), ''.__getnewargs__) - assert obj.doc == '' + assert obj.py__doc__() == '' def test_string_literals():