From 2a227dcc7a26e9eb7747321804bbe43ff69f8892 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 8 May 2020 17:49:02 +0200 Subject: [PATCH 01/15] Remove is_class_value from infer_type_vars --- jedi/inference/base_value.py | 14 ++---- jedi/inference/gradual/annotation.py | 7 +-- jedi/inference/gradual/base.py | 14 +++--- jedi/inference/gradual/type_var.py | 6 +-- jedi/inference/gradual/typing.py | 64 +++++----------------------- 5 files changed, 23 insertions(+), 82 deletions(-) diff --git a/jedi/inference/base_value.py b/jedi/inference/base_value.py index 3a82e20e..e7ac4baa 100644 --- a/jedi/inference/base_value.py +++ b/jedi/inference/base_value.py @@ -268,7 +268,7 @@ class Value(HelperValueMixin): def get_type_hint(self, add_class_info=True): return None - def infer_type_vars(self, value_set, is_class_value=False): + def infer_type_vars(self, value_set): """ When the current instance represents a type annotation, this method tries to find information about undefined type vars and returns a dict @@ -294,14 +294,6 @@ class Value(HelperValueMixin): we're inferrined for, or (for recursive calls) their types. In the above example this would first be the representation of the list `[1]` and then, when recursing, just of `1`. - - `is_class_value`: tells us whether or not to treat the `value_set` as - representing the instances or types being passed, which is neccesary - to correctly cope with `Type[T]` annotations. When it is True, this - means that we are being called with a nested portion of an - annotation and that the `value_set` represents the types of the - arguments, rather than their actual instances. Note: not all - recursive calls will neccesarily set this to True. """ return {} @@ -538,7 +530,7 @@ class ValueSet(object): s = 'Optional[%s]' % s return s - def infer_type_vars(self, value_set, is_class_value=False): + def infer_type_vars(self, value_set): # Circular from jedi.inference.gradual.annotation import merge_type_var_dicts @@ -546,7 +538,7 @@ class ValueSet(object): for value in self._set: merge_type_var_dicts( type_var_dict, - value.infer_type_vars(value_set, is_class_value), + value.infer_type_vars(value_set), ) return type_var_dict diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index b636240f..e63b9086 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -359,12 +359,7 @@ def merge_pairwise_generics(annotation_value, annotated_argument_class): for annotation_generics_set, actual_generic_set in zip(annotation_generics, actual_generics): merge_type_var_dicts( type_var_dict, - annotation_generics_set.infer_type_vars( - actual_generic_set, - # This is a note to ourselves that we have already - # converted the instance representation to its class. - is_class_value=True, - ), + annotation_generics_set.infer_type_vars(actual_generic_set.execute_annotation()), ) return type_var_dict diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index 70cfa447..59c6c9f3 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -200,29 +200,27 @@ class GenericClass(ClassMixin, DefineGenericBase): return True return self._class_value.is_sub_class_of(class_value) - def infer_type_vars(self, value_set, is_class_value=False): + def infer_type_vars(self, value_set): # Circular from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts annotation_name = self.py__name__() type_var_dict = {} - if annotation_name == 'Iterable' and not is_class_value: + if annotation_name == 'Iterable': annotation_generics = self.get_generics() if annotation_generics: return annotation_generics[0].infer_type_vars( value_set.merge_types_of_iterate(), ) - else: # Note: we need to handle the MRO _in order_, so we need to extract # the elements from the set first, then handle them, even if we put # them back in a set afterwards. for py_class in value_set: - if not is_class_value: - if py_class.is_instance() and not py_class.is_compiled(): - py_class = py_class.get_annotated_class_object() - else: - continue + if py_class.is_instance() and not py_class.is_compiled(): + py_class = py_class.get_annotated_class_object() + else: + continue if py_class.api_type != u'class': # Functions & modules don't have an MRO and we're not diff --git a/jedi/inference/gradual/type_var.py b/jedi/inference/gradual/type_var.py index a5ce65c6..9b041df0 100644 --- a/jedi/inference/gradual/type_var.py +++ b/jedi/inference/gradual/type_var.py @@ -107,11 +107,9 @@ class TypeVar(BaseTypingValue): def execute_annotation(self): return self._get_classes().execute_annotation() - def infer_type_vars(self, value_set, is_class_value=False): + def infer_type_vars(self, value_set): annotation_name = self.py__name__() - if not is_class_value: - return {annotation_name: value_set.py__class__()} - return {annotation_name: value_set} + return {annotation_name: value_set.py__class__()} def __repr__(self): return '<%s: %s>' % (self.__class__.__name__, self.py__name__()) diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index 189fe997..edb3dc2e 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -184,7 +184,7 @@ class _TypingClassMixin(ClassMixin): class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): - def infer_type_vars(self, value_set, is_class_value=False): + def infer_type_vars(self, value_set): # Circular from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts @@ -196,49 +196,18 @@ class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): annotation_name = self.py__name__() if annotation_name == 'Type': - if is_class_value: - # This only applies if we are comparing something like - # List[Type[int]] with Iterable[Type[int]]. First, Jedi tries to - # match List/Iterable. After that we will land here, because - # is_class_value will be True at that point. Obviously we also - # compare below that both sides are `Type`. - for element in value_set: - element_name = element.py__name__() - if element_name == 'Type': - merge_type_var_dicts( - type_var_dict, - merge_pairwise_generics(self, element), - ) - else: - return annotation_generics[0].infer_type_vars( - value_set, - is_class_value=True, - ) + return annotation_generics[0].infer_type_vars( + value_set.execute_with_values(), + ) elif annotation_name == 'Callable': - if len(annotation_generics) == 2: - if is_class_value: - # This only applies if we are comparing something like - # List[Callable[..., T]] with Iterable[Callable[..., T]]. - # First, Jedi tries to match List/Iterable. After that we - # will land here, because is_class_value will be True at - # that point. Obviously we also compare below that both - # sides are `Callable`. - for element in value_set: - element_name = element.py__name__() - if element_name == 'Callable': - merge_type_var_dicts( - type_var_dict, - merge_pairwise_generics(self, element), - ) - else: - return annotation_generics[1].infer_type_vars( - value_set.execute_annotation(), - ) + return annotation_generics[1].infer_type_vars( + value_set.execute_annotation(), + ) elif annotation_name == 'Tuple': tuple_annotation, = self.execute_annotation() - return tuple_annotation.infer_type_vars(value_set, is_class_value) + return tuple_annotation.infer_type_vars(value_set) return type_var_dict @@ -337,7 +306,7 @@ class Tuple(BaseTypingValueWithGenerics): .py__getattribute__('tuple').execute_annotation() return tuple_ - def infer_type_vars(self, value_set, is_class_value=False): + def infer_type_vars(self, value_set): # Circular from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts from jedi.inference.gradual.base import GenericClass @@ -346,14 +315,6 @@ class Tuple(BaseTypingValueWithGenerics): lambda x: x.py__name__().lower() == 'tuple', ) - # Somewhat unusually, this `infer_type_vars` method is on an instance - # representation of a type, rather than the annotation or class - # representation. This means that as a starting point, we need to - # convert the incoming values to their instance style if they're - # classes, rather than the reverse. - if is_class_value: - value_set = value_set.execute_annotation() - if self._is_homogenous(): # The parameter annotation is of the form `Tuple[T, ...]`, # so we treat the incoming tuple like a iterable sequence @@ -370,11 +331,8 @@ class Tuple(BaseTypingValueWithGenerics): type_var_dict = {} for element in value_set: - if not is_class_value: - py_class = element.get_annotated_class_object() - if not isinstance(py_class, GenericClass): - py_class = element - else: + py_class = element.get_annotated_class_object() + if not isinstance(py_class, GenericClass): py_class = element merge_type_var_dicts( From 14ca8e64993454730157a3d5293c8a54846a0180 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 8 May 2020 18:00:35 +0200 Subject: [PATCH 02/15] Add a comment --- jedi/inference/gradual/typing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index edb3dc2e..15922528 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -185,9 +185,6 @@ class _TypingClassMixin(ClassMixin): class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): def infer_type_vars(self, value_set): - # Circular - from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts - type_var_dict = {} annotation_generics = self.get_generics() @@ -197,6 +194,9 @@ class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): annotation_name = self.py__name__() if annotation_name == 'Type': return annotation_generics[0].infer_type_vars( + # This is basically a trick to avoid extra code: We execute the + # incoming classes to be able to use the normal code for type + # var inference. value_set.execute_with_values(), ) From 39a2cd8aa2f4079dc8b25c8a8ecfe78907c29efa Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 8 May 2020 18:07:15 +0200 Subject: [PATCH 03/15] Fix a potential issue with tuples --- jedi/inference/gradual/typing.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index 15922528..121dff3d 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -331,9 +331,17 @@ class Tuple(BaseTypingValueWithGenerics): type_var_dict = {} for element in value_set: - py_class = element.get_annotated_class_object() - if not isinstance(py_class, GenericClass): - py_class = element + try: + method = element.get_annotated_class_object + except AttributeError: + # This might still happen, because the tuple name matching + # above is not 100% correct, so just catch the remaining + # cases here. + continue + else: + py_class = method() + if not isinstance(py_class, GenericClass): + py_class = element merge_type_var_dicts( type_var_dict, From d56f607f35b61dc025b82b65903b965b35935961 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sat, 9 May 2020 00:13:18 +0200 Subject: [PATCH 04/15] Reinstate an if that was deleted by mistake --- jedi/inference/gradual/typing.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index 121dff3d..6ff78c7c 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -201,9 +201,10 @@ class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): ) elif annotation_name == 'Callable': - return annotation_generics[1].infer_type_vars( - value_set.execute_annotation(), - ) + if len(annotation_generics) == 2: + return annotation_generics[1].infer_type_vars( + value_set.execute_annotation(), + ) elif annotation_name == 'Tuple': tuple_annotation, = self.execute_annotation() From 3b48c76e4a069a674cecb5c6602a84d75c9e905b Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sat, 9 May 2020 00:49:37 +0200 Subject: [PATCH 05/15] Make a function private --- jedi/inference/gradual/annotation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index e63b9086..60eb06bd 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -276,7 +276,7 @@ def infer_return_for_callable(arguments, param_values, result_values): all_type_vars = {} for pv in param_values: if pv.array_type == 'list': - type_var_dict = infer_type_vars_for_callable(arguments, pv.py__iter__()) + type_var_dict = _infer_type_vars_for_callable(arguments, pv.py__iter__()) all_type_vars.update(type_var_dict) return ValueSet.from_sets( @@ -286,7 +286,7 @@ def infer_return_for_callable(arguments, param_values, result_values): ).execute_annotation() -def infer_type_vars_for_callable(arguments, lazy_params): +def _infer_type_vars_for_callable(arguments, lazy_params): """ Infers type vars for the Calllable class: From f362932ec5b4b3aaad29d7502132c22448e04188 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sat, 9 May 2020 16:28:05 +0200 Subject: [PATCH 06/15] Return a more correct py__class__ for typing base objects --- jedi/inference/gradual/base.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index 59c6c9f3..8ed1f4bc 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -330,10 +330,9 @@ class _PseudoTreeNameClass(Value): yield EmptyFilter() def py__class__(self): - # TODO this is obviously not correct, but at least gives us a class if - # we have none. Some of these objects don't really have a base class in - # typeshed. - return builtin_from_name(self.inference_state, u'object') + # This might not be 100% correct, but it is good enough. The details of + # the typing library are not really an issue for Jedi. + return builtin_from_name(self.inference_state, u'type') @property def name(self): From c2d1da09cb92616edfc30e92880a242f3810316f Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 May 2020 01:05:55 +0200 Subject: [PATCH 07/15] Make sure that Tuple/Callable instances have the correct py__class__ --- jedi/inference/gradual/annotation.py | 4 +-- jedi/inference/gradual/base.py | 25 +++++++++++++++++++ jedi/inference/gradual/typing.py | 18 ++++++++----- test/completion/pep0484_generic_parameters.py | 4 +++ 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index 60eb06bd..6839d8c9 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -12,7 +12,7 @@ from parso import ParserSyntaxError, parse from jedi._compatibility import force_unicode, Parameter from jedi.inference.cache import inference_state_method_cache from jedi.inference.base_value import ValueSet, NO_VALUES -from jedi.inference.gradual.base import DefineGenericBase, GenericClass +from jedi.inference.gradual.base import DefineGenericBase, GenericClass, BaseTypingInstance from jedi.inference.gradual.generics import TupleGenericManager from jedi.inference.gradual.type_var import TypeVar from jedi.inference.helpers import is_string @@ -350,7 +350,7 @@ def merge_pairwise_generics(annotation_value, annotated_argument_class): type_var_dict = {} - if not isinstance(annotated_argument_class, DefineGenericBase): + if not isinstance(annotated_argument_class, (DefineGenericBase, BaseTypingInstance)): return type_var_dict annotation_generics = annotation_value.get_generics() diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index 8ed1f4bc..de8dee85 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -4,6 +4,7 @@ from jedi.inference.base_value import ValueSet, NO_VALUES, Value, \ from jedi.inference.compiled import builtin_from_name from jedi.inference.value.klass import ClassFilter from jedi.inference.value.klass import ClassMixin +from jedi.inference.value.instance import AbstractInstanceValue from jedi.inference.utils import to_list from jedi.inference.names import AbstractNameDefinition, ValueName from jedi.inference.context import ClassContext @@ -375,3 +376,27 @@ class BaseTypingValueWithGenerics(DefineGenericBase): def __repr__(self): return '%s(%s%s)' % (self.__class__.__name__, self._tree_name.value, self._generics_manager) + + +class BaseTypingInstance(LazyValueWrapper): + def __init__(self, parent_context, class_value, tree_name, generics_manager): + self.inference_state = class_value.inference_state + self.parent_context = parent_context + self._class_value = class_value + self._tree_name = tree_name + self._generics_manager = generics_manager + + def py__class__(self): + return self._class_value + + @property + def name(self): + return ValueName(self, self._tree_name) + + @inference_state_method_cache() + def get_generics(self): + return self._generics_manager.to_tuple() + + def _get_wrapped_value(self): + object_, = builtin_from_name(self.inference_state, u'object').execute_annotation() + return object_ diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index 6ff78c7c..5c30f678 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -17,7 +17,8 @@ from jedi.inference.arguments import repack_with_argument_clinic from jedi.inference.filters import FilterWrapper from jedi.inference.names import NameWrapper, ValueName from jedi.inference.value.klass import ClassMixin -from jedi.inference.gradual.base import BaseTypingValue, BaseTypingValueWithGenerics +from jedi.inference.gradual.base import BaseTypingValue, \ + BaseTypingValueWithGenerics, BaseTypingInstance from jedi.inference.gradual.type_var import TypeVarClass from jedi.inference.gradual.generics import LazyGenericManager, TupleGenericManager @@ -129,6 +130,7 @@ class TypingValueWithIndex(BaseTypingValueWithGenerics): cls = mapped[string_name] return ValueSet([cls( self.parent_context, + self, self._tree_name, generics_manager=self._generics_manager, )]) @@ -197,7 +199,7 @@ class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): # This is basically a trick to avoid extra code: We execute the # incoming classes to be able to use the normal code for type # var inference. - value_set.execute_with_values(), + value_set.execute_annotation(), ) elif annotation_name == 'Callable': @@ -254,7 +256,7 @@ class TypeAlias(LazyValueWrapper): return ValueSet([self._get_wrapped_value()]) -class Callable(BaseTypingValueWithGenerics): +class Callable(BaseTypingInstance): def py__call__(self, arguments): """ def x() -> Callable[[Callable[..., _T]], _T]: ... @@ -271,7 +273,7 @@ class Callable(BaseTypingValueWithGenerics): return infer_return_for_callable(arguments, param_values, result_values) -class Tuple(BaseTypingValueWithGenerics): +class Tuple(BaseTypingInstance): def _is_homogenous(self): # To specify a variable-length tuple of homogeneous type, Tuple[T, ...] # is used. @@ -307,6 +309,10 @@ class Tuple(BaseTypingValueWithGenerics): .py__getattribute__('tuple').execute_annotation() return tuple_ + @property + def name(self): + return self._wrapped_value.name + def infer_type_vars(self, value_set): # Circular from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts @@ -352,11 +358,11 @@ class Tuple(BaseTypingValueWithGenerics): return type_var_dict -class Generic(BaseTypingValueWithGenerics): +class Generic(BaseTypingInstance): pass -class Protocol(BaseTypingValueWithGenerics): +class Protocol(BaseTypingInstance): pass diff --git a/test/completion/pep0484_generic_parameters.py b/test/completion/pep0484_generic_parameters.py index 9edcd061..3898b17f 100644 --- a/test/completion/pep0484_generic_parameters.py +++ b/test/completion/pep0484_generic_parameters.py @@ -10,6 +10,7 @@ from typing import ( Type, TypeVar, Union, + Sequence, ) K = TypeVar('K') @@ -165,6 +166,9 @@ some_str = NotImplemented # type: str #? str() first(some_str) +annotated = [len] # type: List[ Callable[[Sequence[float]], int] ] +#? int() +first(annotated)() # Test that the right type is chosen when a partially realised mapping is expected def values(mapping: Mapping[int, T]) -> List[T]: From 42963a0e03e466f71a24024df6b626e3d2eb0287 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 May 2020 02:52:42 +0200 Subject: [PATCH 08/15] By having get_annotated_class_object for Tuple/Callable, some details are not necessary anymore --- jedi/inference/gradual/annotation.py | 2 +- jedi/inference/gradual/base.py | 6 ++++++ jedi/inference/gradual/typing.py | 6 +----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index 6839d8c9..c1ef2667 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -350,7 +350,7 @@ def merge_pairwise_generics(annotation_value, annotated_argument_class): type_var_dict = {} - if not isinstance(annotated_argument_class, (DefineGenericBase, BaseTypingInstance)): + if not isinstance(annotated_argument_class, (DefineGenericBase)): return type_var_dict annotation_generics = annotation_value.get_generics() diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index de8dee85..14b133d3 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -389,6 +389,9 @@ class BaseTypingInstance(LazyValueWrapper): def py__class__(self): return self._class_value + def get_annotated_class_object(self): + return self._class_value + @property def name(self): return ValueName(self, self._tree_name) @@ -400,3 +403,6 @@ class BaseTypingInstance(LazyValueWrapper): def _get_wrapped_value(self): object_, = builtin_from_name(self.inference_state, u'object').execute_annotation() return object_ + + def __repr__(self): + return '<%s: %s>' % (self.__class__.__name__, self._generics_manager) diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index 5c30f678..fccece66 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -316,7 +316,6 @@ class Tuple(BaseTypingInstance): def infer_type_vars(self, value_set): # Circular from jedi.inference.gradual.annotation import merge_pairwise_generics, merge_type_var_dicts - from jedi.inference.gradual.base import GenericClass value_set = value_set.filter( lambda x: x.py__name__().lower() == 'tuple', @@ -345,11 +344,8 @@ class Tuple(BaseTypingInstance): # above is not 100% correct, so just catch the remaining # cases here. continue - else: - py_class = method() - if not isinstance(py_class, GenericClass): - py_class = element + py_class = method() merge_type_var_dicts( type_var_dict, merge_pairwise_generics(self, py_class), From 434866558a1862e5cf2edcb0e5c877a924539612 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 May 2020 02:58:15 +0200 Subject: [PATCH 09/15] Instances should not need get_generics --- jedi/inference/gradual/annotation.py | 4 ++-- jedi/inference/gradual/base.py | 4 ---- jedi/inference/gradual/typing.py | 4 ++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index c1ef2667..60eb06bd 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -12,7 +12,7 @@ from parso import ParserSyntaxError, parse from jedi._compatibility import force_unicode, Parameter from jedi.inference.cache import inference_state_method_cache from jedi.inference.base_value import ValueSet, NO_VALUES -from jedi.inference.gradual.base import DefineGenericBase, GenericClass, BaseTypingInstance +from jedi.inference.gradual.base import DefineGenericBase, GenericClass from jedi.inference.gradual.generics import TupleGenericManager from jedi.inference.gradual.type_var import TypeVar from jedi.inference.helpers import is_string @@ -350,7 +350,7 @@ def merge_pairwise_generics(annotation_value, annotated_argument_class): type_var_dict = {} - if not isinstance(annotated_argument_class, (DefineGenericBase)): + if not isinstance(annotated_argument_class, DefineGenericBase): return type_var_dict annotation_generics = annotation_value.get_generics() diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index 14b133d3..73697a28 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -396,10 +396,6 @@ class BaseTypingInstance(LazyValueWrapper): def name(self): return ValueName(self, self._tree_name) - @inference_state_method_cache() - def get_generics(self): - return self._generics_manager.to_tuple() - def _get_wrapped_value(self): object_, = builtin_from_name(self.inference_state, u'object').execute_annotation() return object_ diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index fccece66..eb64c1a9 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -325,7 +325,7 @@ class Tuple(BaseTypingInstance): # The parameter annotation is of the form `Tuple[T, ...]`, # so we treat the incoming tuple like a iterable sequence # rather than a positional container of elements. - return self.get_generics()[0].infer_type_vars( + return self._class_value.get_generics()[0].infer_type_vars( value_set.merge_types_of_iterate(), ) @@ -348,7 +348,7 @@ class Tuple(BaseTypingInstance): py_class = method() merge_type_var_dicts( type_var_dict, - merge_pairwise_generics(self, py_class), + merge_pairwise_generics(self._class_value, py_class), ) return type_var_dict From 78ad06612e0ce0639a21ce64c123268f287399ba Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 May 2020 03:00:47 +0200 Subject: [PATCH 10/15] Remove an unused import --- jedi/inference/gradual/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index 73697a28..e931ba2e 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -4,7 +4,6 @@ from jedi.inference.base_value import ValueSet, NO_VALUES, Value, \ from jedi.inference.compiled import builtin_from_name from jedi.inference.value.klass import ClassFilter from jedi.inference.value.klass import ClassMixin -from jedi.inference.value.instance import AbstractInstanceValue from jedi.inference.utils import to_list from jedi.inference.names import AbstractNameDefinition, ValueName from jedi.inference.context import ClassContext From b57654aed333717c39e1bd08c13c1f62ec9723ed Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 May 2020 03:04:52 +0200 Subject: [PATCH 11/15] Rename some classes to make it clearer that they are classes --- jedi/inference/gradual/base.py | 4 ++-- jedi/inference/gradual/typing.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index e931ba2e..a532d081 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -362,9 +362,9 @@ class BaseTypingValue(LazyValueWrapper): return '%s(%s)' % (self.__class__.__name__, self._tree_name.value) -class BaseTypingValueWithGenerics(DefineGenericBase): +class BaseTypingClassWithGenerics(DefineGenericBase): def __init__(self, parent_context, tree_name, generics_manager): - super(BaseTypingValueWithGenerics, self).__init__(generics_manager) + super(BaseTypingClassWithGenerics, self).__init__(generics_manager) self.inference_state = parent_context.inference_state self.parent_context = parent_context self._tree_name = tree_name diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index eb64c1a9..9d77f6d0 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -18,7 +18,7 @@ from jedi.inference.filters import FilterWrapper from jedi.inference.names import NameWrapper, ValueName from jedi.inference.value.klass import ClassMixin from jedi.inference.gradual.base import BaseTypingValue, \ - BaseTypingValueWithGenerics, BaseTypingInstance + BaseTypingClassWithGenerics, BaseTypingInstance from jedi.inference.gradual.type_var import TypeVarClass from jedi.inference.gradual.generics import LazyGenericManager, TupleGenericManager @@ -101,7 +101,7 @@ class TypingModuleFilterWrapper(FilterWrapper): name_wrapper_class = TypingModuleName -class TypingValueWithIndex(BaseTypingValueWithGenerics): +class TypingClassWithIndex(BaseTypingClassWithGenerics): def execute_annotation(self): string_name = self._tree_name.value @@ -139,7 +139,7 @@ class TypingValueWithIndex(BaseTypingValueWithGenerics): return ValueSet.from_sets(self._generics_manager.to_tuple()) def _create_instance_with_generics(self, generics_manager): - return TypingValueWithIndex( + return TypingClassWithIndex( self.parent_context, self._tree_name, generics_manager @@ -147,7 +147,7 @@ class TypingValueWithIndex(BaseTypingValueWithGenerics): class ProxyTypingValue(BaseTypingValue): - index_class = TypingValueWithIndex + index_class = TypingClassWithIndex def with_generics(self, generics_tuple): return self.index_class.create_cached( @@ -185,7 +185,7 @@ class _TypingClassMixin(ClassMixin): return ValueName(self, self._tree_name) -class TypingClassValueWithIndex(_TypingClassMixin, TypingValueWithIndex): +class TypingClassValueWithIndex(_TypingClassMixin, TypingClassWithIndex): def infer_type_vars(self, value_set): type_var_dict = {} annotation_generics = self.get_generics() From d0270b5e594998f6ffc394dbe4c74f412c4fbed6 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 May 2020 03:07:40 +0200 Subject: [PATCH 12/15] DefineGenericBase -> DefineGenericBaseClass --- jedi/inference/gradual/annotation.py | 8 ++++---- jedi/inference/gradual/base.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index 60eb06bd..7311bfb5 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -12,7 +12,7 @@ from parso import ParserSyntaxError, parse from jedi._compatibility import force_unicode, Parameter from jedi.inference.cache import inference_state_method_cache from jedi.inference.base_value import ValueSet, NO_VALUES -from jedi.inference.gradual.base import DefineGenericBase, GenericClass +from jedi.inference.gradual.base import DefineGenericBaseClass, GenericClass from jedi.inference.gradual.generics import TupleGenericManager from jedi.inference.gradual.type_var import TypeVar from jedi.inference.helpers import is_string @@ -229,7 +229,7 @@ def infer_return_types(function, arguments): return ValueSet.from_sets( ann.define_generics(type_var_dict) - if isinstance(ann, (DefineGenericBase, TypeVar)) else ValueSet({ann}) + if isinstance(ann, (DefineGenericBaseClass, TypeVar)) else ValueSet({ann}) for ann in annotation_values ).execute_annotation() @@ -281,7 +281,7 @@ def infer_return_for_callable(arguments, param_values, result_values): return ValueSet.from_sets( v.define_generics(all_type_vars) - if isinstance(v, (DefineGenericBase, TypeVar)) else ValueSet({v}) + if isinstance(v, (DefineGenericBaseClass, TypeVar)) else ValueSet({v}) for v in result_values ).execute_annotation() @@ -350,7 +350,7 @@ def merge_pairwise_generics(annotation_value, annotated_argument_class): type_var_dict = {} - if not isinstance(annotated_argument_class, DefineGenericBase): + if not isinstance(annotated_argument_class, DefineGenericBaseClass): return type_var_dict annotation_generics = annotation_value.get_generics() diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index a532d081..e33aa63a 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -81,7 +81,7 @@ class _AnnotatedClassContext(ClassContext): yield self._value.get_type_var_filter() -class DefineGenericBase(LazyValueWrapper): +class DefineGenericBaseClass(LazyValueWrapper): def __init__(self, generics_manager): self._generics_manager = generics_manager @@ -99,7 +99,7 @@ class DefineGenericBase(LazyValueWrapper): for generic_set in self.get_generics(): values = NO_VALUES for generic in generic_set: - if isinstance(generic, (DefineGenericBase, TypeVar)): + if isinstance(generic, (DefineGenericBaseClass, TypeVar)): result = generic.define_generics(type_var_dict) values |= result if result != ValueSet({generic}): @@ -119,7 +119,7 @@ class DefineGenericBase(LazyValueWrapper): )]) def is_same_class(self, other): - if not isinstance(other, DefineGenericBase): + if not isinstance(other, DefineGenericBaseClass): return False if self.tree_node != other.tree_node: @@ -151,7 +151,7 @@ class DefineGenericBase(LazyValueWrapper): ) -class GenericClass(ClassMixin, DefineGenericBase): +class GenericClass(ClassMixin, DefineGenericBaseClass): """ A class that is defined with generics, might be something simple like: @@ -362,7 +362,7 @@ class BaseTypingValue(LazyValueWrapper): return '%s(%s)' % (self.__class__.__name__, self._tree_name.value) -class BaseTypingClassWithGenerics(DefineGenericBase): +class BaseTypingClassWithGenerics(DefineGenericBaseClass): def __init__(self, parent_context, tree_name, generics_manager): super(BaseTypingClassWithGenerics, self).__init__(generics_manager) self.inference_state = parent_context.inference_state From e9a0c01af8101ff0a5156fd5a7f935e1608d15e5 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 May 2020 03:17:07 +0200 Subject: [PATCH 13/15] TypedDictBase -> TypedDictClass --- jedi/inference/gradual/typing.py | 4 ++-- jedi/inference/value/klass.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index 9d77f6d0..6ff34286 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -85,7 +85,7 @@ class TypingModuleName(NameWrapper): elif name == 'TypedDict': # TODO doesn't even exist in typeshed/typing.py, yet. But will be # added soon. - yield TypedDictBase.create_cached( + yield TypedDictClass.create_cached( inference_state, self.parent_context, self.tree_name) elif name in ('no_type_check', 'no_type_check_decorator'): # This is not necessary, as long as we are not doing type checking. @@ -416,7 +416,7 @@ class CastFunction(BaseTypingValue): return type_value_set.execute_annotation() -class TypedDictBase(BaseTypingValue): +class TypedDictClass(BaseTypingValue): """ This class has no responsibilities and is just here to make sure that typed dicts can be identified. diff --git a/jedi/inference/value/klass.py b/jedi/inference/value/klass.py index 89bc7925..ec51b24a 100644 --- a/jedi/inference/value/klass.py +++ b/jedi/inference/value/klass.py @@ -241,7 +241,7 @@ class ClassMixin(object): def is_typeddict(self): # TODO Do a proper mro resolution. Currently we are just listing # classes. However, it's a complicated algorithm. - from jedi.inference.gradual.typing import TypedDictBase + from jedi.inference.gradual.typing import TypedDictClass for lazy_cls in self.py__bases__(): if not isinstance(lazy_cls, LazyTreeValue): return False @@ -253,7 +253,7 @@ class ClassMixin(object): return False for cls in lazy_cls.infer(): - if isinstance(cls, TypedDictBase): + if isinstance(cls, TypedDictClass): return True try: method = cls.is_typeddict From e6e43413fff9bd542fcf5f072942efb6380b74d5 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 10 May 2020 03:17:52 +0200 Subject: [PATCH 14/15] Any -> AnyClass --- jedi/inference/gradual/base.py | 4 ++-- jedi/inference/gradual/typing.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index e33aa63a..1143c284 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -23,8 +23,8 @@ class _BoundTypeVarName(AbstractNameDefinition): def iter_(): for value in self._value_set: # Replace any with the constraints if they are there. - from jedi.inference.gradual.typing import Any - if isinstance(value, Any): + from jedi.inference.gradual.typing import AnyClass + if isinstance(value, AnyClass): for constraint in self._type_var.constraints: yield constraint else: diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index 6ff34286..add28177 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -67,7 +67,7 @@ class TypingModuleName(NameWrapper): yield TypeVarClass.create_cached( inference_state, self.parent_context, self.tree_name) elif name == 'Any': - yield Any.create_cached( + yield AnyClass.create_cached( inference_state, self.parent_context, self.tree_name) elif name == 'TYPE_CHECKING': # This is needed for e.g. imports that are only available for type @@ -362,7 +362,7 @@ class Protocol(BaseTypingInstance): pass -class Any(BaseTypingValue): +class AnyClass(BaseTypingValue): def execute_annotation(self): debug.warning('Used Any - returned no results') return NO_VALUES From 7f25e28d890479ce570d8ee3aa60845754f81b29 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Tue, 12 May 2020 23:33:06 +0200 Subject: [PATCH 15/15] Fix tuple issue in 3.6 --- test/test_api/test_interpreter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_api/test_interpreter.py b/test/test_api/test_interpreter.py index b5d601ce..bae881de 100644 --- a/test/test_api/test_interpreter.py +++ b/test/test_api/test_interpreter.py @@ -656,7 +656,8 @@ def bar(): ({'return': 'typing.Optional[str, int]'}, [], ''), # Takes only one arg ({'return': 'typing.Any'}, [], ''), - ({'return': 'typing.Tuple[int, str]'}, ['tuple'], ''), + ({'return': 'typing.Tuple[int, str]'}, + ['Tuple' if sys.version_info[:2] == (3, 6) else 'tuple'], ''), ({'return': 'typing.Tuple[int, str]'}, ['int'], 'x()[0]'), ({'return': 'typing.Tuple[int, str]'}, ['str'], 'x()[1]'), ({'return': 'typing.Tuple[int, str]'}, [], 'x()[2]'),