Make sure to use _stub_to_python_value_set for all conversions, see #1466

This commit is contained in:
Dave Halter
2020-01-07 01:27:50 +01:00
parent d8deceb4b1
commit 9b9cacfbf9
6 changed files with 53 additions and 25 deletions

View File

@@ -59,27 +59,22 @@ def _try_stub_to_python_names(names, prefer_stub_to_compiled=False):
yield name
continue
name_list = name.get_qualified_names()
if name_list is None:
values = NO_VALUES
if name.api_type == 'module':
values = convert_values(name.infer(), ignore_compiled=prefer_stub_to_compiled)
if values:
for v in values:
yield v.name
continue
else:
values = _infer_from_stub(
module_context,
name_list[:-1],
ignore_compiled=prefer_stub_to_compiled,
)
if values and name_list:
new_names = values.goto(name_list[-1])
for new_name in new_names:
yield new_name
if new_names:
v = name.get_defining_qualified_value()
if v is not None:
converted = _stub_to_python_value_set(v, ignore_compiled=prefer_stub_to_compiled)
if converted:
converted_names = converted.goto(name.get_public_name())
if converted_names:
for n in converted_names:
yield n
continue
elif values:
for c in values:
yield c.name
continue
# This is the part where if we haven't found anything, just return the
# stub name.
yield name

View File

@@ -79,6 +79,13 @@ class AbstractNameDefinition(object):
def api_type(self):
return self.parent_context.api_type
def get_defining_qualified_value(self):
"""
Returns either None or the value that is public and qualified. Won't
return a function, because a name in a function is never public.
"""
return None
class AbstractArbitraryName(AbstractNameDefinition):
"""
@@ -124,6 +131,15 @@ class AbstractTreeName(AbstractNameDefinition):
return None
return parent_names + (self.tree_name.value,)
def get_defining_qualified_value(self):
if self.is_import():
raise 1
elif self.parent_context:
values = self.parent_context.name.infer()
if len(values) == 1:
return next(iter(values))
return None
def goto(self):
context = self.parent_context
name = self.tree_name

View File

@@ -509,6 +509,9 @@ class SelfName(TreeNameDefinition):
def parent_context(self):
return self._instance.create_instance_context(self.class_context, self.tree_name)
def get_defining_qualified_value(self):
return self._instance
class LazyInstanceClassName(NameWrapper):
def __init__(self, instance, class_member_name):
@@ -524,6 +527,9 @@ class LazyInstanceClassName(NameWrapper):
def get_signatures(self):
return self.infer().get_signatures()
def get_defining_qualified_value(self):
return self._instance
class InstanceClassFilter(AbstractFilter):
"""

View File

@@ -74,6 +74,10 @@ class ClassName(TreeNameDefinition):
else:
yield result_value
@property
def defining_qualified_value(self):
return self._class_value
class ClassFilter(ParserTreeFilter):
def __init__(self, class_value, node_context=None, until_position=None,

View File

@@ -437,16 +437,17 @@ def test_import(names):
assert n.name == 'os'
assert n.type == 'module'
n = nms[2].goto()[0]
assert n.name == 'path'
assert n.type == 'module'
nms = nms[2].goto()
assert nms
assert all(n.type == 'module' for n in nms)
assert 'posixpath' in {n.name for n in nms}
nms = names('import os.path', references=True)
n = nms[0].goto()[0]
assert n.name == 'os'
assert n.type == 'module'
n = nms[1].goto()[0]
# This is very special, normally the name doesn't chance, but since
# This is very special, normally the name doesn't change, but since
# os.path is a sys.modules hack, it does.
assert n.name in ('macpath', 'ntpath', 'posixpath', 'os2emxpath')
assert n.type == 'module'

View File

@@ -152,6 +152,12 @@ def test_method_doc_with_signature(Script):
assert c.docstring() == 'writelines(lines: Iterable[AnyStr]) -> None'
def test_method_doc_with_signature2(Script):
code = 'f = open("")\nf.writelines'
d, = Script(code).goto()
assert d.docstring() == 'writelines(lines: Iterable[AnyStr]) -> None'
def test_with_stmt_error_recovery(Script):
assert Script('with open('') as foo: foo.\na').complete(line=1)