Merge pull request #1861 from qmmp123/master

Fix: #1847
This commit is contained in:
Dave Halter
2022-11-11 16:00:39 +00:00
committed by GitHub
4 changed files with 41 additions and 3 deletions

3
.gitignore vendored
View File

@@ -14,3 +14,6 @@ record.json
/.pytest_cache /.pytest_cache
/.mypy_cache /.mypy_cache
/venv/ /venv/
.nvimrc
poetry.lock
pyproject.toml

View File

@@ -1,6 +1,7 @@
from abc import abstractproperty from abc import abstractproperty
from parso.tree import search_ancestor from parso.tree import search_ancestor
from parso.python.tree import Name
from jedi import debug from jedi import debug
from jedi import settings from jedi import settings
@@ -231,6 +232,8 @@ class _BaseTreeInstance(AbstractInstanceValue):
func_node = new func_node = new
new = search_ancestor(new, 'funcdef', 'classdef') new = search_ancestor(new, 'funcdef', 'classdef')
if class_context.tree_node is new: if class_context.tree_node is new:
if isinstance(func_node, Name):
func_node = new
func = FunctionValue.from_context(class_context, func_node) func = FunctionValue.from_context(class_context, func_node)
bound_method = BoundMethod(self, class_context, func) bound_method = BoundMethod(self, class_context, func)
if func_node.name.value == '__init__': if func_node.name.value == '__init__':
@@ -582,6 +585,11 @@ class SelfAttributeFilter(ClassFilter):
# filter. # filter.
if self._is_in_right_scope(trailer.parent.children[0], name): if self._is_in_right_scope(trailer.parent.children[0], name):
yield name yield name
elif trailer.type == "expr_stmt" \
and len(trailer.parent.children) == 2:
if name.is_definition() and self._access_possible(name):
if trailer.children[1].type == "annassign":
yield name
def _is_in_right_scope(self, self_name, name): def _is_in_right_scope(self, self_name, name):
self_context = self._node_context.create_context(self_name) self_context = self._node_context.create_context(self_name)

View File

@@ -58,6 +58,7 @@ class VarClass:
var_instance2: float var_instance2: float
var_class1: typing.ClassVar[str] = 1 var_class1: typing.ClassVar[str] = 1
var_class2: typing.ClassVar[bytes] var_class2: typing.ClassVar[bytes]
var_class3 = None
def __init__(self): def __init__(self):
#? int() #? int()
@@ -70,11 +71,17 @@ class VarClass:
d.var_class2 d.var_class2
#? [] #? []
d.int d.int
#? ['var_class1', 'var_class2', 'var_instance1', 'var_instance2'] #? ['var_class1', 'var_class2', 'var_instance1', 'var_instance2', 'var_class3']
self.var_ self.var_
class VarClass2(VarClass):
var_class3: typing.ClassVar[int]
#? ['var_class1', 'var_class2', 'var_instance1'] def __init__(self):
#? int()
self.var_class3
#? ['var_class1', 'var_class2', 'var_instance1', 'var_class3']
VarClass.var_ VarClass.var_
#? int() #? int()
VarClass.var_instance1 VarClass.var_instance1
@@ -88,7 +95,7 @@ VarClass.var_class2
VarClass.int VarClass.int
d = VarClass() d = VarClass()
#? ['var_class1', 'var_class2', 'var_instance1', 'var_instance2'] #? ['var_class1', 'var_class2', 'var_class3', 'var_instance1', 'var_instance2']
d.var_ d.var_
#? int() #? int()
d.var_instance1 d.var_instance1

View File

@@ -41,6 +41,26 @@ def test_in_empty_space(Script):
assert def_.name == 'X' assert def_.name == 'X'
def test_classvar_completion(Script):
code = dedent('''\
from typing import ClassVar # 1
class Foo: # 2
var_class = None # 3
def __init__(self, var_class=None): # 4
self.var_class = var_class # 5
class Bar(Foo): # 6
var_class: ClassVar[int] # 7
def __init__(self): # 9
self.var_class.
int().
''')
expected_value = set(completion.name for completion in Script(code).complete(11, 14))
for completion in Script(code).complete(10, 23):
expected_value.remove(completion.name)
assert len(expected_value) == 0
def test_indent_value(Script): def test_indent_value(Script):
""" """
If an INDENT is the next supposed token, we should still be able to If an INDENT is the next supposed token, we should still be able to