1
0
forked from VimPlug/jedi

Make it possible to use inheritance on generics without always specifying type vars, see also discussion in #1593

This commit is contained in:
Dave Halter
2020-06-06 01:23:14 +02:00
parent 3870253b56
commit 574b790296
5 changed files with 38 additions and 4 deletions

View File

@@ -174,6 +174,9 @@ class Value(HelperValueMixin):
def is_class(self):
return False
def is_class_mixin(self):
return False
def is_instance(self):
return False

View File

@@ -190,7 +190,7 @@ class GenericClass(ClassMixin, DefineGenericBaseClass):
@to_list
def py__bases__(self):
for base in self._wrapped_value.py__bases__():
yield _LazyGenericBaseClass(self, base)
yield _LazyGenericBaseClass(self, base, self._generics_manager)
def _create_instance_with_generics(self, generics_manager):
return GenericClass(self._class_value, generics_manager)
@@ -241,9 +241,10 @@ class GenericClass(ClassMixin, DefineGenericBaseClass):
class _LazyGenericBaseClass(object):
def __init__(self, class_value, lazy_base_class):
def __init__(self, class_value, lazy_base_class, generics_manager):
self._class_value = class_value
self._lazy_base_class = lazy_base_class
self._generics_manager = generics_manager
@iterator_to_value_set
def infer(self):
@@ -255,6 +256,16 @@ class _LazyGenericBaseClass(object):
base._wrapped_value,
TupleGenericManager(tuple(self._remap_type_vars(base))),
)
else:
if base.is_class_mixin():
# This case basically allows classes like `class Foo(List)`
# to be used like `Foo[int]`. The generics are not
# necessary and can be used later.
yield GenericClass.create_cached(
base.inference_state,
base,
self._generics_manager,
)
else:
yield base

View File

@@ -135,6 +135,9 @@ class ClassMixin(object):
def is_class(self):
return True
def is_class_mixin(self):
return True
def py__call__(self, arguments=None):
from jedi.inference.value import TreeInstance
@@ -314,6 +317,7 @@ class ClassValue(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBase
def py__getitem__(self, index_value_set, contextualized_node):
from jedi.inference.gradual.base import GenericClass
if not index_value_set:
debug.warning('Class indexes inferred to nothing. Returning class instead')
return ValueSet([self])
return ValueSet(
GenericClass(

View File

@@ -102,7 +102,7 @@ def _create_manager_for(cls, manager_cls='BaseManager'):
('django', 'db', 'models', 'manager')
).py__getattribute__(manager_cls)
for m in managers:
if m.is_class() and not m.is_compiled():
if m.is_class_mixin():
generics_manager = TupleGenericManager((ValueSet([cls]),))
for c in GenericClass(m, generics_manager).execute_annotation():
return c

View File

@@ -126,3 +126,19 @@ for p in typed_bound_generic_passthrough(untyped_list_str):
for q in typed_bound_generic_passthrough(typed_list_str):
#? str()
q
class CustomList(List):
def get_first(self):
return self[0]
#? str()
CustomList[str]()[0]
#? str()
CustomList[str]().get_first()
#? str()
typed_fully_generic_passthrough(CustomList[str]())[0]
#?
typed_list_generic_passthrough(CustomList[str])[0]