From 5acbb06315c5b1cd353604485f0ca0c7ba2bbeb3 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 8 Dec 2019 23:50:46 +0100 Subject: [PATCH] Refactor so typing uses BaseTypingValueWithGenerics This makes it finally possible to use type vars with Callable and some other classes. Fixes #1413 --- jedi/inference/gradual/base.py | 102 ++++++++++++++++++----------- jedi/inference/gradual/type_var.py | 4 +- jedi/inference/gradual/typing.py | 35 ++++------ 3 files changed, 81 insertions(+), 60 deletions(-) diff --git a/jedi/inference/gradual/base.py b/jedi/inference/gradual/base.py index 7e30d728..8f2d2d23 100644 --- a/jedi/inference/gradual/base.py +++ b/jedi/inference/gradual/base.py @@ -10,43 +10,6 @@ from jedi.inference.context import ClassContext from jedi.inference.gradual.generics import TupleGenericManager -class BaseTypingValue(Value): - def __init__(self, inference_state, parent_context, tree_name): - super(BaseTypingValue, self).__init__(inference_state, parent_context) - self._tree_name = tree_name - - @property - def tree_node(self): - return self._tree_name - - def get_filters(self, *args, **kwargs): - # TODO this is obviously wrong. Is it though? - class EmptyFilter(ClassFilter): - def __init__(self): - pass - - def get(self, name, **kwargs): - return [] - - def values(self, **kwargs): - return [] - - 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') - - @property - def name(self): - return ValueName(self, self._tree_name) - - def __repr__(self): - return '%s(%s)' % (self.__class__.__name__, self._tree_name.value) - - class _BoundTypeVarName(AbstractNameDefinition): """ This type var was bound to a certain type, e.g. int. @@ -264,3 +227,68 @@ class _GenericInstanceWrapper(ValueWrapper): elif cls.py__name__() == 'Iterator': return ValueSet([builtin_from_name(self.inference_state, u'None')]) return self._wrapped_value.py__stop_iteration_returns() + + +class _PseudoTreeNameClass(Value): + def __init__(self, parent_context, tree_name): + super(_PseudoTreeNameClass, self).__init__( + parent_context.inference_state, + parent_context + ) + self._tree_name = tree_name + + @property + def tree_node(self): + return self._tree_name + + def get_filters(self, *args, **kwargs): + # TODO this is obviously wrong. Is it though? + class EmptyFilter(ClassFilter): + def __init__(self): + pass + + def get(self, name, **kwargs): + return [] + + def values(self, **kwargs): + return [] + + 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') + + @property + def name(self): + return ValueName(self, self._tree_name) + + def __repr__(self): + return '%s(%s)' % (self.__class__.__name__, self._tree_name.value) + + +class BaseTypingValue(LazyValueWrapper): + def __init__(self, parent_context, tree_name): + self.inference_state = parent_context.inference_state + self.parent_context = parent_context + self._tree_name = tree_name + + @property + def name(self): + return ValueName(self, self._tree_name) + + def _get_wrapped_value(self): + return _PseudoTreeNameClass(self.parent_context, self._tree_name) + + +class BaseTypingValueWithGenerics(DefineGenericBase): + def __init__(self, parent_context, tree_name, generics_manager): + super(BaseTypingValueWithGenerics, self).__init__(generics_manager) + self.inference_state = parent_context.inference_state + self.parent_context = parent_context + self._tree_name = tree_name + + def _get_wrapped_value(self): + return _PseudoTreeNameClass(self.parent_context, self._tree_name) diff --git a/jedi/inference/gradual/type_var.py b/jedi/inference/gradual/type_var.py index 8684b725..f618b4d8 100644 --- a/jedi/inference/gradual/type_var.py +++ b/jedi/inference/gradual/type_var.py @@ -49,8 +49,8 @@ class TypeVarClass(BaseTypingValue): class TypeVar(BaseTypingValue): - def __init__(self, inference_state, parent_context, tree_name, var_name, unpacked_args): - super(TypeVar, self).__init__(inference_state, parent_context, tree_name) + def __init__(self, parent_context, tree_name, var_name, unpacked_args): + super(TypeVar, self).__init__(parent_context, tree_name) self._var_name = var_name self._constraints_lazy_values = [] diff --git a/jedi/inference/gradual/typing.py b/jedi/inference/gradual/typing.py index 0a70896e..793ef4c9 100644 --- a/jedi/inference/gradual/typing.py +++ b/jedi/inference/gradual/typing.py @@ -15,7 +15,7 @@ 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 +from jedi.inference.gradual.base import BaseTypingValue, BaseTypingValueWithGenerics from jedi.inference.gradual.type_var import TypeVarClass from jedi.inference.gradual.generics import LazyGenericManager @@ -97,20 +97,7 @@ class TypingModuleFilterWrapper(FilterWrapper): name_wrapper_class = TypingModuleName -class _WithIndexBase(BaseTypingValue): - def __init__(self, inference_state, parent_context, name, generics_manager): - super(_WithIndexBase, self).__init__(inference_state, parent_context, name) - self._generics_manager = generics_manager - - def __repr__(self): - return '<%s: %s[%s]>' % ( - self.__class__.__name__, - self._tree_name.value, - self._generics_manager, - ) - - -class TypingValueWithIndex(_WithIndexBase): +class TypingValueWithIndex(BaseTypingValueWithGenerics): def execute_annotation(self): string_name = self._tree_name.value @@ -132,7 +119,6 @@ class TypingValueWithIndex(_WithIndexBase): cls = globals()[string_name] return ValueSet([cls( - self.inference_state, self.parent_context, self._tree_name, generics_manager=self._generics_manager, @@ -141,6 +127,13 @@ class TypingValueWithIndex(_WithIndexBase): def gather_annotation_classes(self): return ValueSet.from_sets(self._generics_manager.to_tuple()) + def _create_instance_with_generics(self, generics_manager): + return TypingValueWithIndex( + self.parent_context, + self._tree_name, + generics_manager + ) + class ProxyTypingValue(BaseTypingValue): index_class = TypingValueWithIndex @@ -219,15 +212,15 @@ class TypeAlias(LazyValueWrapper): return cls -class Callable(_WithIndexBase): +class Callable(BaseTypingValueWithGenerics): def py__call__(self, arguments): # The 0th index are the arguments. return self._generics_manager.get_index_and_execute(1) class Tuple(LazyValueWrapper): - def __init__(self, inference_state, parent_context, name, generics_manager): - self.inference_state = inference_state + def __init__(self, parent_context, name, generics_manager): + self.inference_state = parent_context.inference_state self.parent_context = parent_context self._generics_manager = generics_manager @@ -267,11 +260,11 @@ class Tuple(LazyValueWrapper): return tuple_ -class Generic(_WithIndexBase): +class Generic(BaseTypingValueWithGenerics): pass -class Protocol(_WithIndexBase): +class Protocol(BaseTypingValueWithGenerics): pass