mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-09 23:34:45 +08:00
Make partial use the __doc__ of its function, fixes #1621
This commit is contained in:
@@ -18,6 +18,7 @@ def _stub_to_python_value_set(stub_value, ignore_compiled=False):
|
|||||||
|
|
||||||
was_instance = stub_value.is_instance()
|
was_instance = stub_value.is_instance()
|
||||||
if was_instance:
|
if was_instance:
|
||||||
|
arguments = getattr(stub_value, '_arguments', None)
|
||||||
stub_value = stub_value.py__class__()
|
stub_value = stub_value.py__class__()
|
||||||
|
|
||||||
qualified_names = stub_value.get_qualified_names()
|
qualified_names = stub_value.get_qualified_names()
|
||||||
@@ -30,11 +31,12 @@ def _stub_to_python_value_set(stub_value, ignore_compiled=False):
|
|||||||
method_name = qualified_names[-1]
|
method_name = qualified_names[-1]
|
||||||
qualified_names = qualified_names[:-1]
|
qualified_names = qualified_names[:-1]
|
||||||
was_instance = True
|
was_instance = True
|
||||||
|
arguments = None
|
||||||
|
|
||||||
values = _infer_from_stub(stub_module_context, qualified_names, ignore_compiled)
|
values = _infer_from_stub(stub_module_context, qualified_names, ignore_compiled)
|
||||||
if was_instance:
|
if was_instance:
|
||||||
values = ValueSet.from_sets(
|
values = ValueSet.from_sets(
|
||||||
c.execute_with_values()
|
c.execute_with_values() if arguments is None else c.execute(arguments)
|
||||||
for c in values
|
for c in values
|
||||||
if c.is_class()
|
if c.is_class()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -474,11 +474,10 @@ def collections_namedtuple(value, arguments, callback):
|
|||||||
class PartialObject(ValueWrapper):
|
class PartialObject(ValueWrapper):
|
||||||
def __init__(self, actual_value, arguments, instance=None):
|
def __init__(self, actual_value, arguments, instance=None):
|
||||||
super(PartialObject, self).__init__(actual_value)
|
super(PartialObject, self).__init__(actual_value)
|
||||||
self._actual_value = actual_value
|
|
||||||
self._arguments = arguments
|
self._arguments = arguments
|
||||||
self._instance = instance
|
self._instance = instance
|
||||||
|
|
||||||
def _get_function(self, unpacked_arguments):
|
def _get_functions(self, unpacked_arguments):
|
||||||
key, lazy_value = next(unpacked_arguments, (None, None))
|
key, lazy_value = next(unpacked_arguments, (None, None))
|
||||||
if key is not None or lazy_value is None:
|
if key is not None or lazy_value is None:
|
||||||
debug.warning("Partial should have a proper function %s", self._arguments)
|
debug.warning("Partial should have a proper function %s", self._arguments)
|
||||||
@@ -487,8 +486,8 @@ class PartialObject(ValueWrapper):
|
|||||||
|
|
||||||
def get_signatures(self):
|
def get_signatures(self):
|
||||||
unpacked_arguments = self._arguments.unpack()
|
unpacked_arguments = self._arguments.unpack()
|
||||||
func = self._get_function(unpacked_arguments)
|
funcs = self._get_functions(unpacked_arguments)
|
||||||
if func is None:
|
if funcs is None:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
arg_count = 0
|
arg_count = 0
|
||||||
@@ -500,17 +499,30 @@ class PartialObject(ValueWrapper):
|
|||||||
arg_count += 1
|
arg_count += 1
|
||||||
else:
|
else:
|
||||||
keys.add(key)
|
keys.add(key)
|
||||||
return [PartialSignature(s, arg_count, keys) for s in func.get_signatures()]
|
return [PartialSignature(s, arg_count, keys) for s in funcs.get_signatures()]
|
||||||
|
|
||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
func = self._get_function(self._arguments.unpack())
|
funcs = self._get_functions(self._arguments.unpack())
|
||||||
if func is None:
|
if funcs is None:
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
|
|
||||||
return func.execute(
|
return funcs.execute(
|
||||||
MergedPartialArguments(self._arguments, arguments, self._instance)
|
MergedPartialArguments(self._arguments, arguments, self._instance)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def py__doc__(self):
|
||||||
|
"""
|
||||||
|
In CPython partial does not replace the docstring. However we are still
|
||||||
|
imitating it here, because we want this docstring to be worth something
|
||||||
|
for the user.
|
||||||
|
"""
|
||||||
|
callables = self._get_functions(self._arguments.unpack())
|
||||||
|
if callables is None:
|
||||||
|
return ''
|
||||||
|
for callable_ in callables:
|
||||||
|
return callable_.py__doc__()
|
||||||
|
return ''
|
||||||
|
|
||||||
def py__get__(self, instance, class_value):
|
def py__get__(self, instance, class_value):
|
||||||
return ValueSet([self])
|
return ValueSet([self])
|
||||||
|
|
||||||
@@ -519,7 +531,7 @@ class PartialMethodObject(PartialObject):
|
|||||||
def py__get__(self, instance, class_value):
|
def py__get__(self, instance, class_value):
|
||||||
if instance is None:
|
if instance is None:
|
||||||
return ValueSet([self])
|
return ValueSet([self])
|
||||||
return ValueSet([PartialObject(self._actual_value, self._arguments, instance)])
|
return ValueSet([PartialObject(self._wrapped_value, self._arguments, instance)])
|
||||||
|
|
||||||
|
|
||||||
class PartialSignature(SignatureWrapper):
|
class PartialSignature(SignatureWrapper):
|
||||||
|
|||||||
@@ -422,6 +422,19 @@ def test_decorator(Script):
|
|||||||
assert d.docstring(raw=True) == 'Nice docstring'
|
assert d.docstring(raw=True) == 'Nice docstring'
|
||||||
|
|
||||||
|
|
||||||
|
def test_partial(Script):
|
||||||
|
code = dedent('''
|
||||||
|
def foo():
|
||||||
|
'x y z'
|
||||||
|
from functools import partial
|
||||||
|
x = partial(foo)
|
||||||
|
x''')
|
||||||
|
|
||||||
|
p1, p2 = Script(code).infer()
|
||||||
|
assert p1.docstring(raw=True) == 'x y z'
|
||||||
|
assert p2.docstring(raw=True) == 'x y z'
|
||||||
|
|
||||||
|
|
||||||
def test_basic_str_init_signature(Script, disable_typeshed):
|
def test_basic_str_init_signature(Script, disable_typeshed):
|
||||||
# See GH #1414 and GH #1426
|
# See GH #1414 and GH #1426
|
||||||
code = dedent('''
|
code = dedent('''
|
||||||
|
|||||||
Reference in New Issue
Block a user