1
0
forked from VimPlug/jedi

Rework some call signature issues

This commit is contained in:
Dave Halter
2018-11-11 17:01:12 +01:00
parent c29cde6784
commit 4fbede7445
7 changed files with 51 additions and 34 deletions

View File

@@ -345,12 +345,12 @@ class Script(object):
) )
debug.speed('func_call followed') debug.speed('func_call followed')
return [classes.CallSignature(self._evaluator, signature, return [classes.CallSignature(definition, signature,
call_signature_details.bracket_leaf.start_pos, call_signature_details.bracket_leaf.start_pos,
call_signature_details.call_index, call_signature_details.call_index,
call_signature_details.keyword_name_str) call_signature_details.keyword_name_str)
for d in definitions for definition in definitions
for signature in d.get_signatures()] for signature in definition.get_signatures()]
def _analysis(self): def _analysis(self):
self._evaluator.is_analysis = True self._evaluator.is_analysis = True

View File

@@ -320,12 +320,13 @@ class BaseDefinition(object):
Raises an ``AttributeError``if the definition is not callable. Raises an ``AttributeError``if the definition is not callable.
Otherwise returns a list of `Definition` that represents the params. Otherwise returns a list of `Definition` that represents the params.
""" """
def get_param_names(context): def get_param_names(signature):
param_names = [] param_names = []
if context.api_type == 'function': if context.api_type == 'function':
param_names = list(context.get_param_names()) param_names = list(context.get_param_names())
if isinstance(context, instance.BoundMethod): if isinstance(context, instance.BoundMethod):
param_names = param_names[1:] param_names = param_names[1:]
return param_names
elif context.is_class() or context.is_instance(): elif context.is_class() or context.is_instance():
if context.is_class(): if context.is_class():
search = u'__init__' search = u'__init__'
@@ -346,12 +347,13 @@ class BaseDefinition(object):
return list(context.get_param_names()) return list(context.get_param_names())
return param_names return param_names
followed = list(self._name.infer()) # Only return the first one. There might be multiple one, especially
if not followed or not hasattr(followed[0], 'py__call__'): # with overloading.
raise AttributeError('There are no params defined on this.') for context in self._name.infer():
context = followed[0] # only check the first one. for signature in context.get_signatures():
return [Definition(self._evaluator, n) for n in signature.get_param_names()]
return [Definition(self._evaluator, n) for n in get_param_names(context)] raise AttributeError('There are no params defined on this.')
def parent(self): def parent(self):
context = self._name.parent_context context = self._name.parent_context
@@ -600,8 +602,8 @@ class CallSignature(Definition):
It knows what functions you are currently in. e.g. `isinstance(` would It knows what functions you are currently in. e.g. `isinstance(` would
return the `isinstance` function. without `(` it would return nothing. return the `isinstance` function. without `(` it would return nothing.
""" """
def __init__(self, evaluator, signature, bracket_start_pos, index, key_name_str): def __init__(self, definition, signature, bracket_start_pos, index, key_name_str):
super(CallSignature, self).__init__(evaluator, signature.name) super(CallSignature, self).__init__(definition.evaluator, definition.name)
self._index = index self._index = index
self._key_name_str = key_name_str self._key_name_str = key_name_str
self._bracket_start_pos = bracket_start_pos self._bracket_start_pos = bracket_start_pos
@@ -634,6 +636,10 @@ class CallSignature(Definition):
return None return None
return self._index return self._index
@property
def params(self):
return [Definition(self._evaluator, n) for n in self._signature.get_param_names()]
@property @property
def bracket_start(self): def bracket_start(self):
""" """

View File

@@ -323,12 +323,8 @@ class Evaluator(object):
context_set = eval_trailer(context, context_set, trailer) context_set = eval_trailer(context, context_set, trailer)
param_names = [] param_names = []
for context in context_set: for context in context_set:
try: for signature in context.get_signatures():
get_param_names = context.get_param_names for param_name in signature.get_param_names():
except AttributeError:
pass
else:
for param_name in get_param_names():
if param_name.string_name == name.value: if param_name.string_name == name.value:
param_names.append(param_name) param_names.append(param_name)
return param_names return param_names

View File

@@ -356,6 +356,9 @@ class ContextSet(BaseContextSet):
context_set |= method() context_set |= method()
return context_set return context_set
def get_signatures(self):
return [sig for c in self._set for sig in c.get_signatures()]
NO_CONTEXTS = ContextSet([]) NO_CONTEXTS = ContextSet([])

View File

@@ -218,6 +218,10 @@ class AbstractInstanceContext(Context):
raise NotImplementedError raise NotImplementedError
return class_context return class_context
def get_signatures(self):
init_funcs = self.py__getattribute__('__call__')
return [sig.bind() for sig in init_funcs.get_signatures()]
def __repr__(self): def __repr__(self):
return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_context, return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_context,
self.var_args) self.var_args)
@@ -296,7 +300,9 @@ class TreeInstance(AbstractInstanceContext):
return self._get_annotated_class_object() or self.class_context return self._get_annotated_class_object() or self.class_context
def _get_annotation_init_functions(self): def _get_annotation_init_functions(self):
for init in self.class_context.py__getattribute__('__init__'): filter = next(self.class_context.get_filters())
for init_name in filter.get('__init__'):
for init in init_name.infer():
if isinstance(init, OverloadedFunctionContext): if isinstance(init, OverloadedFunctionContext):
for func in init.overloaded_functions: for func in init.overloaded_functions:
yield func yield func

View File

@@ -292,6 +292,4 @@ class ClassContext(use_metaclass(CachedMetaClass, ClassMixin, TreeContext)):
def get_signatures(self): def get_signatures(self):
init_funcs = self.py__getattribute__('__init__') init_funcs = self.py__getattribute__('__init__')
return [ return [sig.bind() for sig in init_funcs.get_signatures()]
s for f in init_funcs for s in f.get_signatures()
]

View File

@@ -424,20 +424,28 @@ def test_lambda_params(Script):
assert [p.name for p in sig.params] == ['x'] assert [p.name for p in sig.params] == ['x']
def test_class_creation(Script): CLASS_CODE = dedent('''\
code = dedent('''\ class X():
class X():
def __init__(self, foo, bar): def __init__(self, foo, bar):
self.foo = foo self.foo = foo
''') ''')
sig, = Script(code + 'X(').call_signatures()
def test_class_creation(Script):
sig, = Script(CLASS_CODE + 'X(').call_signatures()
assert sig.index == 0 assert sig.index == 0
assert sig.name == 'X' assert sig.name == 'X'
assert [p.name for p in sig.params] == ['foo', 'bar'] assert [p.name for p in sig.params] == ['foo', 'bar']
sig, = Script(code + 'X.__init__(').call_signatures()
def test_call_init_on_class(Script):
sig, = Script(CLASS_CODE + 'X.__init__(').call_signatures()
assert [p.name for p in sig.params] == ['self', 'foo', 'bar'] assert [p.name for p in sig.params] == ['self', 'foo', 'bar']
sig, = Script(code + 'X().__init__(').call_signatures()
def test_call_init_on_instance(Script):
sig, = Script(CLASS_CODE + 'X().__init__(').call_signatures()
assert [p.name for p in sig.params] == ['foo', 'bar'] assert [p.name for p in sig.params] == ['foo', 'bar']