mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 05:54:25 +08:00
Use class filters in instances differently so metaclass plugins work, fixes #1090
This commit is contained in:
@@ -380,14 +380,14 @@ class CompiledObjectFilter(AbstractFilter):
|
||||
|
||||
def __init__(self, evaluator, compiled_object, is_instance=False):
|
||||
self._evaluator = evaluator
|
||||
self._compiled_object = compiled_object
|
||||
self.compiled_object = compiled_object
|
||||
self.is_instance = is_instance
|
||||
|
||||
def get(self, name):
|
||||
return self._get(
|
||||
name,
|
||||
lambda: self._compiled_object.access_handle.is_allowed_getattr(name),
|
||||
lambda: self._compiled_object.access_handle.dir(),
|
||||
lambda: self.compiled_object.access_handle.is_allowed_getattr(name),
|
||||
lambda: self.compiled_object.access_handle.dir(),
|
||||
check_has_attribute=True
|
||||
)
|
||||
|
||||
@@ -419,7 +419,7 @@ class CompiledObjectFilter(AbstractFilter):
|
||||
def values(self):
|
||||
from jedi.evaluate.compiled import builtin_from_name
|
||||
names = []
|
||||
needs_type_completions, dir_infos = self._compiled_object.access_handle.get_dir_infos()
|
||||
needs_type_completions, dir_infos = self.compiled_object.access_handle.get_dir_infos()
|
||||
for name in dir_infos:
|
||||
names += self._get(
|
||||
name,
|
||||
@@ -434,10 +434,10 @@ class CompiledObjectFilter(AbstractFilter):
|
||||
return names
|
||||
|
||||
def _create_name(self, name):
|
||||
return self.name_class(self._evaluator, self._compiled_object, name)
|
||||
return self.name_class(self._evaluator, self.compiled_object, name)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s: %s>" % (self.__class__.__name__, self._compiled_object)
|
||||
return "<%s: %s>" % (self.__class__.__name__, self.compiled_object)
|
||||
|
||||
|
||||
docstr_defaults = {
|
||||
|
||||
@@ -3,6 +3,7 @@ from abc import abstractproperty
|
||||
from jedi import debug
|
||||
from jedi import settings
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate.compiled.context import CompiledObjectFilter
|
||||
from jedi.evaluate.helpers import contexts_from_qualified_names
|
||||
from jedi.evaluate.filters import AbstractFilter
|
||||
from jedi.evaluate.names import ContextName, TreeNameDefinition
|
||||
@@ -136,11 +137,19 @@ class AbstractInstanceContext(Context):
|
||||
# compiled objects to search for self variables.
|
||||
yield SelfAttributeFilter(self.evaluator, self, cls, origin_scope)
|
||||
|
||||
for cls in class_context.py__mro__():
|
||||
if isinstance(cls, compiled.CompiledObject):
|
||||
yield CompiledInstanceClassFilter(self.evaluator, self, cls)
|
||||
class_filters = class_context.get_filters(
|
||||
search_global=False,
|
||||
origin_scope=origin_scope,
|
||||
is_instance=True,
|
||||
)
|
||||
for f in class_filters:
|
||||
if isinstance(f, ClassFilter):
|
||||
yield InstanceClassFilter(self.evaluator, self, f)
|
||||
elif isinstance(f, CompiledObjectFilter):
|
||||
yield CompiledInstanceClassFilter(self.evaluator, self, f)
|
||||
else:
|
||||
yield InstanceClassFilter(self.evaluator, self, cls, origin_scope)
|
||||
# Propably from the metaclass.
|
||||
yield f
|
||||
|
||||
def py__getitem__(self, index_context_set, contextualized_node):
|
||||
names = self.get_function_slot_names(u'__getitem__')
|
||||
@@ -328,7 +337,6 @@ class CompiledInstanceName(compiled.CompiledName):
|
||||
name.string_name
|
||||
)
|
||||
self._instance = instance
|
||||
self._class = klass
|
||||
self._class_member_name = name
|
||||
|
||||
@iterator_to_context_set
|
||||
@@ -343,11 +351,10 @@ class CompiledInstanceName(compiled.CompiledName):
|
||||
class CompiledInstanceClassFilter(AbstractFilter):
|
||||
name_class = CompiledInstanceName
|
||||
|
||||
def __init__(self, evaluator, instance, klass):
|
||||
def __init__(self, evaluator, instance, f):
|
||||
self._evaluator = evaluator
|
||||
self._instance = instance
|
||||
self._class = klass
|
||||
self._class_filter = next(klass.get_filters(is_instance=True))
|
||||
self._class_filter = f
|
||||
|
||||
def get(self, name):
|
||||
return self._convert(self._class_filter.get(name))
|
||||
@@ -356,8 +363,9 @@ class CompiledInstanceClassFilter(AbstractFilter):
|
||||
return self._convert(self._class_filter.values())
|
||||
|
||||
def _convert(self, names):
|
||||
klass = self._class_filter.compiled_object
|
||||
return [
|
||||
CompiledInstanceName(self._evaluator, self._instance, self._class, n)
|
||||
CompiledInstanceName(self._evaluator, self._instance, klass, n)
|
||||
for n in names
|
||||
]
|
||||
|
||||
@@ -454,15 +462,9 @@ class InstanceClassFilter(AbstractFilter):
|
||||
resulting names in LazyINstanceClassName. The idea is that the class name
|
||||
filtering can be very flexible and always be reflected in instances.
|
||||
"""
|
||||
def __init__(self, evaluator, context, class_context, origin_scope):
|
||||
self._instance = context
|
||||
self._class_context = class_context
|
||||
self._class_filter = next(class_context.get_filters(
|
||||
search_global=False,
|
||||
origin_scope=origin_scope,
|
||||
is_instance=True,
|
||||
))
|
||||
assert isinstance(self._class_filter, ClassFilter), self._class_filter
|
||||
def __init__(self, evaluator, instance, class_filter):
|
||||
self._instance = instance
|
||||
self._class_filter = class_filter
|
||||
|
||||
def get(self, name):
|
||||
return self._convert(self._class_filter.get(name, from_instance=True))
|
||||
@@ -471,10 +473,10 @@ class InstanceClassFilter(AbstractFilter):
|
||||
return self._convert(self._class_filter.values(from_instance=True))
|
||||
|
||||
def _convert(self, names):
|
||||
return [LazyInstanceClassName(self._instance, self._class_context, n) for n in names]
|
||||
return [LazyInstanceClassName(self._instance, self._class_filter.context, n) for n in names]
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s for %s>' % (self.__class__.__name__, self._class_context)
|
||||
return '<%s for %s>' % (self.__class__.__name__, self._class_filter.context)
|
||||
|
||||
|
||||
class SelfAttributeFilter(ClassFilter):
|
||||
|
||||
@@ -331,7 +331,8 @@ class ClassContext(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBa
|
||||
|
||||
for lazy_base in self.py__bases__():
|
||||
for context in lazy_base.infer():
|
||||
contexts = context.get_metaclasses()
|
||||
if contexts:
|
||||
return contexts
|
||||
if context.is_class():
|
||||
contexts = context.get_metaclasses()
|
||||
if contexts:
|
||||
return contexts
|
||||
return NO_CONTEXTS
|
||||
|
||||
@@ -209,6 +209,9 @@ class _TypingClassMixin(object):
|
||||
self.evaluator.builtins_module.py__getattribute__('object')
|
||||
)]
|
||||
|
||||
def get_metaclasses(self):
|
||||
return []
|
||||
|
||||
|
||||
class TypingClassContextWithIndex(_TypingClassMixin, TypingContextWithIndex, ClassMixin):
|
||||
pass
|
||||
|
||||
@@ -612,7 +612,6 @@ def get_metaclass_filters(func):
|
||||
for metaclass in metaclasses:
|
||||
if metaclass.py__name__() == 'EnumMeta' \
|
||||
and metaclass.get_root_context().py__name__() == 'enum':
|
||||
print('cont', cls)
|
||||
filter_ = ParserTreeFilter(cls.evaluator, context=cls)
|
||||
return [DictFilter({
|
||||
name.string_name: EnumInstance(cls, name).name for name in filter_.values()
|
||||
@@ -638,7 +637,7 @@ class EnumInstance(LazyContextWrapper):
|
||||
|
||||
def get_filters(self, search_global=False, position=None, origin_scope=None):
|
||||
yield DictFilter(dict(
|
||||
name=self._name.string_name,
|
||||
name=compiled.create_simple_object(self.evaluator, self._name.string_name).name,
|
||||
value=self._name,
|
||||
))
|
||||
for f in self._get_wrapped_context().get_filters():
|
||||
|
||||
Reference in New Issue
Block a user