From 2cb1bd162f5a70b4d04c57ef2f6208f25c3b4bdf Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 5 May 2019 19:09:21 +0200 Subject: [PATCH] Better signature support for docstrings --- jedi/api/classes.py | 39 +++++++++++++++++++++++------- jedi/api/keywords.py | 2 +- jedi/evaluate/base_context.py | 9 +++---- jedi/evaluate/compiled/access.py | 2 +- jedi/evaluate/compiled/context.py | 2 +- jedi/evaluate/context/klass.py | 3 +-- jedi/evaluate/context/namespace.py | 3 +++ jedi/evaluate/signature.py | 3 ++- jedi/parser_utils.py | 13 ---------- 9 files changed, 42 insertions(+), 34 deletions(-) diff --git a/jedi/api/classes.py b/jedi/api/classes.py index cc47a2ba..4b195a43 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -678,6 +678,13 @@ class CallSignature(Definition): ) +def _format_signatures(context): + return '\n'.join( + signature.to_string() + for signature in context.get_signatures() + ) + + class _Help(object): """ Temporary implementation, will be used as `Script.help() or something in @@ -702,15 +709,29 @@ class _Help(object): See :attr:`doc` for example. """ + full_doc = '' # Using the first docstring that we see. for context in self._get_contexts(fast=fast): - doc = context.py__doc__(include_call_signature=not raw) - if doc: - return doc - if not context.is_stub(): - for c in stub_to_actual_context_set(context): - doc = c.py__doc__(include_call_signature=not raw) - if doc: - return doc + if full_doc: + # In case we have multiple contexts, just return all of them + # separated by a few dashes. + full_doc += '\n' + '-' * 30 + '\n' - return '' + doc = context.py__doc__() + + if raw: + signature_text = '' + else: + signature_text = _format_signatures(context) + if not doc and context.is_stub(): + for c in stub_to_actual_context_set(context): + doc = c.py__doc__() + if doc: + break + + if signature_text and doc: + full_doc += signature_text + '\n\n' + doc + else: + full_doc += signature_text + doc + + return full_doc diff --git a/jedi/api/keywords.py b/jedi/api/keywords.py index 2991a0f8..f5d65e62 100644 --- a/jedi/api/keywords.py +++ b/jedi/api/keywords.py @@ -44,7 +44,7 @@ class Keyword(object): """ For a `parsing.Name` like comparision """ return [self.name] - def py__doc__(self, include_call_signature=False): + def py__doc__(self): return imitate_pydoc(self.name.string_name) def __repr__(self): diff --git a/jedi/evaluate/base_context.py b/jedi/evaluate/base_context.py index 018f42b0..36dfdaa1 100644 --- a/jedi/evaluate/base_context.py +++ b/jedi/evaluate/base_context.py @@ -12,7 +12,7 @@ from parso.python.tree import ExprStmt, CompFor from jedi import debug from jedi._compatibility import Python3Method, zip_longest, unicode -from jedi.parser_utils import clean_scope_docstring, get_doc_with_call_signature +from jedi.parser_utils import clean_scope_docstring from jedi.common import BaseContextSet, BaseContext from jedi.evaluate.helpers import SimpleGetItemNotFound, execute_evaluated from jedi.evaluate.utils import safe_property @@ -168,16 +168,13 @@ class Context(HelperContextMixin, BaseContext): """ return True - def py__doc__(self, include_call_signature=False): + def py__doc__(self): 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 clean_scope_docstring(self.tree_node) return None def py__stop_iteration_returns(self): diff --git a/jedi/evaluate/compiled/access.py b/jedi/evaluate/compiled/access.py index a2d06015..c5f3ab93 100644 --- a/jedi/evaluate/compiled/access.py +++ b/jedi/evaluate/compiled/access.py @@ -197,7 +197,7 @@ class DirectObjectAccess(object): except AttributeError: return None - def py__doc__(self, include_call_signature=False): + def py__doc__(self): return force_unicode(inspect.getdoc(self._obj)) or u'' def py__name__(self): diff --git a/jedi/evaluate/compiled/context.py b/jedi/evaluate/compiled/context.py index 2ec6db79..aa52721f 100644 --- a/jedi/evaluate/compiled/context.py +++ b/jedi/evaluate/compiled/context.py @@ -108,7 +108,7 @@ class CompiledObject(Context): def is_stub(self): return False - def py__doc__(self, include_call_signature=False): + def py__doc__(self): return self.access_handle.py__doc__() def get_param_names(self): diff --git a/jedi/evaluate/context/klass.py b/jedi/evaluate/context/klass.py index bcdf9d56..ee145f60 100644 --- a/jedi/evaluate/context/klass.py +++ b/jedi/evaluate/context/klass.py @@ -32,8 +32,7 @@ py__package__() -> List[str] 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) +py__doc__() Returns the docstring for a context. ====================================== ======================================== """ diff --git a/jedi/evaluate/context/namespace.py b/jedi/evaluate/context/namespace.py index 2616f83b..04351b52 100644 --- a/jedi/evaluate/context/namespace.py +++ b/jedi/evaluate/context/namespace.py @@ -53,5 +53,8 @@ class ImplicitNamespaceContext(Context, SubModuleDictMixin): def py__name__(self): return self._fullname + def is_stub(self): + return False + def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self._fullname) diff --git a/jedi/evaluate/signature.py b/jedi/evaluate/signature.py index d07aca06..ea8373ec 100644 --- a/jedi/evaluate/signature.py +++ b/jedi/evaluate/signature.py @@ -1,4 +1,5 @@ from abc import abstractproperty +from jedi.parser_utils import get_call_signature class AbstractSignature(object): @@ -38,7 +39,7 @@ class TreeSignature(AbstractSignature): return self._function_context.tree_node.annotation def to_string(self, normalize=False): - return self._function_context.tree_node + return get_call_signature(self._function_context.tree_node) class BuiltinSignature(AbstractSignature): diff --git a/jedi/parser_utils.py b/jedi/parser_utils.py index 3c8b31ee..d4f8143a 100644 --- a/jedi/parser_utils.py +++ b/jedi/parser_utils.py @@ -181,19 +181,6 @@ def get_call_signature_for_any(any_node): return call_signature -def get_doc_with_call_signature(scope_node): - """ - Return a document string including call signature. - """ - call_signature = get_call_signature_for_any(scope_node) - doc = clean_scope_docstring(scope_node) - if call_signature is None: - return doc - if not doc: - return call_signature - return '%s\n\n%s' % (call_signature, doc) - - def move(node, line_offset): """ Move the `Node` start_pos.