forked from VimPlug/jedi
Properly convert compiled values to generic classes
This commit is contained in:
@@ -5,6 +5,7 @@ import sys
|
|||||||
import operator as op
|
import operator as op
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import warnings
|
import warnings
|
||||||
|
import re
|
||||||
|
|
||||||
from jedi._compatibility import unicode, is_py3, builtins, \
|
from jedi._compatibility import unicode, is_py3, builtins, \
|
||||||
py_version, force_unicode
|
py_version, force_unicode
|
||||||
@@ -491,10 +492,15 @@ class DirectObjectAccess(object):
|
|||||||
if sys.version_info < (3, 5):
|
if sys.version_info < (3, 5):
|
||||||
return None, ()
|
return None, ()
|
||||||
|
|
||||||
|
name = None
|
||||||
|
args = ()
|
||||||
|
if safe_getattr(self._obj, '__module__', default='') == 'typing':
|
||||||
|
m = re.match(r'typing.(\w+)\[', repr(self._obj))
|
||||||
|
if m is not None:
|
||||||
|
name = m.group(1)
|
||||||
|
|
||||||
import typing
|
import typing
|
||||||
args = typing.get_args(self._obj)
|
args = typing.get_args(self._obj)
|
||||||
origin = typing.get_origin(self._obj)
|
|
||||||
name = None if origin is None else str(origin)
|
|
||||||
return name, tuple(self._create_access_path(arg) for arg in args)
|
return name, tuple(self._create_access_path(arg) for arg in args)
|
||||||
|
|
||||||
def needs_type_completions(self):
|
def needs_type_completions(self):
|
||||||
|
|||||||
@@ -273,9 +273,20 @@ class CompiledObject(Value):
|
|||||||
return ValueSet([self])
|
return ValueSet([self])
|
||||||
|
|
||||||
name, args = self.access_handle.get_annotation_name_and_args()
|
name, args = self.access_handle.get_annotation_name_and_args()
|
||||||
arguments = [create_from_access_path(self.inference_state, path) for path in args]
|
arguments = [
|
||||||
if name == 'typing.Union':
|
ValueSet([create_from_access_path(self.inference_state, path)])
|
||||||
|
for path in args
|
||||||
|
]
|
||||||
|
if name == 'Union':
|
||||||
return ValueSet.from_sets(arg.execute_annotation() for arg in arguments)
|
return ValueSet.from_sets(arg.execute_annotation() for arg in arguments)
|
||||||
|
elif name:
|
||||||
|
# While with_generics only exists on very specific objects, we
|
||||||
|
# should probably be fine, because we control all the typing
|
||||||
|
# objects.
|
||||||
|
return ValueSet([
|
||||||
|
v.with_generics(arguments)
|
||||||
|
for v in self.inference_state.typing_module.py__getattribute__(name)
|
||||||
|
]).execute_annotation()
|
||||||
return super(CompiledObject, self).execute_annotation()
|
return super(CompiledObject, self).execute_annotation()
|
||||||
|
|
||||||
def negate(self):
|
def negate(self):
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from jedi.inference.names import NameWrapper, ValueName
|
|||||||
from jedi.inference.value.klass import ClassMixin
|
from jedi.inference.value.klass import ClassMixin
|
||||||
from jedi.inference.gradual.base import BaseTypingValue, BaseTypingValueWithGenerics
|
from jedi.inference.gradual.base import BaseTypingValue, BaseTypingValueWithGenerics
|
||||||
from jedi.inference.gradual.type_var import TypeVarClass
|
from jedi.inference.gradual.type_var import TypeVarClass
|
||||||
from jedi.inference.gradual.generics import LazyGenericManager
|
from jedi.inference.gradual.generics import LazyGenericManager, TupleGenericManager
|
||||||
|
|
||||||
_PROXY_CLASS_TYPES = 'Tuple Generic Protocol Callable Type'.split()
|
_PROXY_CLASS_TYPES = 'Tuple Generic Protocol Callable Type'.split()
|
||||||
_TYPE_ALIAS_TYPES = {
|
_TYPE_ALIAS_TYPES = {
|
||||||
@@ -144,6 +144,14 @@ class ProxyTypingValue(BaseTypingValue):
|
|||||||
index_class = TypingValueWithIndex
|
index_class = TypingValueWithIndex
|
||||||
py__simple_getitem__ = None
|
py__simple_getitem__ = None
|
||||||
|
|
||||||
|
def with_generics(self, generics_tuple):
|
||||||
|
return self.index_class.create_cached(
|
||||||
|
self.inference_state,
|
||||||
|
self.parent_context,
|
||||||
|
self._tree_name,
|
||||||
|
generics_manager=TupleGenericManager(generics_tuple)
|
||||||
|
)
|
||||||
|
|
||||||
def py__getitem__(self, index_value_set, contextualized_node):
|
def py__getitem__(self, index_value_set, contextualized_node):
|
||||||
return ValueSet(
|
return ValueSet(
|
||||||
self.index_class.create_cached(
|
self.index_class.create_cached(
|
||||||
|
|||||||
@@ -286,6 +286,13 @@ class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase
|
|||||||
for index_value in index_value_set
|
for index_value in index_value_set
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def with_generics(self, generics_tuple):
|
||||||
|
from jedi.inference.gradual.base import GenericClass
|
||||||
|
return GenericClass(
|
||||||
|
self,
|
||||||
|
TupleGenericManager(generics_tuple)
|
||||||
|
)
|
||||||
|
|
||||||
def define_generics(self, type_var_dict):
|
def define_generics(self, type_var_dict):
|
||||||
from jedi.inference.gradual.base import GenericClass
|
from jedi.inference.gradual.base import GenericClass
|
||||||
|
|
||||||
|
|||||||
@@ -643,29 +643,46 @@ def bar():
|
|||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (3, 5), reason="Ignore Python 2, because EOL")
|
@pytest.mark.skipif(sys.version_info < (3, 5), reason="Ignore Python 2, because EOL")
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'annotations, result', [
|
'annotations, result, code', [
|
||||||
({}, []),
|
({}, [], ''),
|
||||||
(None, []),
|
(None, [], ''),
|
||||||
({'asdf': 'str'}, []),
|
({'asdf': 'str'}, [], ''),
|
||||||
|
|
||||||
|
({'return': 'str'}, ['str'], ''),
|
||||||
|
({'return': 'None'}, ['NoneType'], ''),
|
||||||
|
({'return': 'str().upper'}, [], ''),
|
||||||
|
({'return': 'foo()'}, [], ''),
|
||||||
|
({'return': 'bar()'}, ['float'], ''),
|
||||||
|
|
||||||
({'return': 'str'}, ['str']),
|
|
||||||
({'return': 'str().upper'}, []),
|
|
||||||
({'return': 'foo()'}, []),
|
|
||||||
({'return': 'bar()'}, ['float']),
|
|
||||||
# typing is available via globals.
|
# typing is available via globals.
|
||||||
({'return': 'typing.Union[str, int]'}, ['int', 'str']),
|
({'return': 'typing.Union[str, int]'}, ['int', 'str'], ''),
|
||||||
({'return': 'typing.Union["str", int]'}, ['int']),
|
({'return': 'typing.Union["str", int]'}, ['int'], ''),
|
||||||
({'return': 'typing.Union["str", 1]'}, []),
|
({'return': 'typing.Union["str", 1]'}, [], ''),
|
||||||
({'return': 'typing.Optional[str]'}, ['NoneType', 'str']),
|
({'return': 'typing.Optional[str]'}, ['NoneType', 'str'], ''),
|
||||||
({'return': 'typing.Optional[str, int]'}, []), # Takes only one arg
|
({'return': 'typing.Optional[str, int]'}, [], ''), # Takes only one arg
|
||||||
|
({'return': 'typing.Any'}, [], ''),
|
||||||
|
|
||||||
({'return': 'decimal.Decimal'}, []),
|
({'return': 'typing.Tuple[int, str]'}, ['tuple'], ''),
|
||||||
({'return': 'lalalalallalaa'}, []),
|
({'return': 'typing.Tuple[int, str]'}, ['int'], 'x()[0]'),
|
||||||
({'return': 'lalalalallalaa.lala'}, []),
|
({'return': 'typing.Tuple[int, str]'}, ['str'], 'x()[1]'),
|
||||||
|
({'return': 'typing.Tuple[int, str]'}, [], 'x()[2]'),
|
||||||
|
|
||||||
|
({'return': 'typing.List'}, ['list'], 'list'),
|
||||||
|
({'return': 'typing.List[int]'}, ['list'], 'list'),
|
||||||
|
({'return': 'typing.List[int]'}, ['int'], 'x()[0]'),
|
||||||
|
({'return': 'typing.List[int, str]'}, [], 'x()[0]'),
|
||||||
|
|
||||||
|
({'return': 'typing.Iterator[int]'}, [], 'x()[0]'),
|
||||||
|
({'return': 'typing.Iterator[int]'}, ['int'], 'next(x())'),
|
||||||
|
({'return': 'typing.Iterable[float]'}, ['float'], 'list(x())[0]'),
|
||||||
|
|
||||||
|
({'return': 'decimal.Decimal'}, [], ''),
|
||||||
|
({'return': 'lalalalallalaa'}, [], ''),
|
||||||
|
({'return': 'lalalalallalaa.lala'}, [], ''),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_string_annotation(annotations, result):
|
def test_string_annotation(annotations, result, code):
|
||||||
x = lambda foo: 1
|
x = lambda foo: 1
|
||||||
x.__annotations__ = annotations
|
x.__annotations__ = annotations
|
||||||
defs = jedi.Interpreter('x()', [locals()]).goto_definitions()
|
defs = jedi.Interpreter(code or 'x()', [locals()]).goto_definitions()
|
||||||
assert [d.name for d in defs] == result
|
assert [d.name for d in defs] == result
|
||||||
|
|||||||
Reference in New Issue
Block a user