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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user