mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-08 14:54:47 +08:00
First step in working with metaclasses in plugins, see #1090.
This commit is contained in:
@@ -264,6 +264,9 @@ class CompiledObject(Context):
|
|||||||
def negate(self):
|
def negate(self):
|
||||||
return create_from_access_path(self.evaluator, self.access_handle.negate())
|
return create_from_access_path(self.evaluator, self.access_handle.negate())
|
||||||
|
|
||||||
|
def get_metaclasses(self):
|
||||||
|
return NO_CONTEXTS
|
||||||
|
|
||||||
|
|
||||||
class CompiledName(AbstractNameDefinition):
|
class CompiledName(AbstractNameDefinition):
|
||||||
def __init__(self, evaluator, parent_context, name):
|
def __init__(self, evaluator, parent_context, name):
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ from jedi.evaluate.arguments import unpack_arglist, ValuesArguments
|
|||||||
from jedi.evaluate.base_context import ContextSet, iterator_to_context_set, \
|
from jedi.evaluate.base_context import ContextSet, iterator_to_context_set, \
|
||||||
NO_CONTEXTS
|
NO_CONTEXTS
|
||||||
from jedi.evaluate.context.function import FunctionAndClassBase
|
from jedi.evaluate.context.function import FunctionAndClassBase
|
||||||
|
from jedi.plugins import plugin_manager
|
||||||
|
|
||||||
|
|
||||||
def apply_py__get__(context, instance, class_context):
|
def apply_py__get__(context, instance, class_context):
|
||||||
@@ -191,6 +192,11 @@ class ClassMixin(object):
|
|||||||
|
|
||||||
def get_filters(self, search_global=False, until_position=None,
|
def get_filters(self, search_global=False, until_position=None,
|
||||||
origin_scope=None, is_instance=False):
|
origin_scope=None, is_instance=False):
|
||||||
|
metaclasses = self.get_metaclasses()
|
||||||
|
if metaclasses:
|
||||||
|
for f in self.get_metaclass_filters(metaclasses):
|
||||||
|
yield f
|
||||||
|
|
||||||
if search_global:
|
if search_global:
|
||||||
yield ParserTreeFilter(
|
yield ParserTreeFilter(
|
||||||
self.evaluator,
|
self.evaluator,
|
||||||
@@ -247,12 +253,17 @@ class ClassContext(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBa
|
|||||||
found.append(type_var)
|
found.append(type_var)
|
||||||
return found
|
return found
|
||||||
|
|
||||||
@evaluator_method_cache(default=())
|
def _get_bases_arguments(self):
|
||||||
def py__bases__(self):
|
|
||||||
arglist = self.tree_node.get_super_arglist()
|
arglist = self.tree_node.get_super_arglist()
|
||||||
if arglist:
|
if arglist:
|
||||||
from jedi.evaluate import arguments
|
from jedi.evaluate import arguments
|
||||||
args = arguments.TreeArguments(self.evaluator, self.parent_context, arglist)
|
return arguments.TreeArguments(self.evaluator, self.parent_context, arglist)
|
||||||
|
return None
|
||||||
|
|
||||||
|
@evaluator_method_cache(default=())
|
||||||
|
def py__bases__(self):
|
||||||
|
args = self._get_bases_arguments()
|
||||||
|
if args is not None:
|
||||||
lst = [value for key, value in args.unpack() if key is None]
|
lst = [value for key, value in args.unpack() if key is None]
|
||||||
if lst:
|
if lst:
|
||||||
return lst
|
return lst
|
||||||
@@ -303,3 +314,24 @@ class ClassContext(use_metaclass(CachedMetaClass, ClassMixin, FunctionAndClassBa
|
|||||||
def get_signatures(self):
|
def get_signatures(self):
|
||||||
init_funcs = self.py__getattribute__('__init__')
|
init_funcs = self.py__getattribute__('__init__')
|
||||||
return [sig.bind(self) for sig in init_funcs.get_signatures()]
|
return [sig.bind(self) for sig in init_funcs.get_signatures()]
|
||||||
|
|
||||||
|
@plugin_manager.decorate()
|
||||||
|
def get_metaclass_filters(self, metaclass):
|
||||||
|
debug.dbg('Unprocessed metaclass %s', metaclass)
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_metaclasses(self):
|
||||||
|
args = self._get_bases_arguments()
|
||||||
|
if args is not None:
|
||||||
|
m = [value for key, value in args.unpack() if key == 'metaclass']
|
||||||
|
metaclasses = ContextSet.from_sets(lazy_context.infer() for lazy_context in m)
|
||||||
|
metaclasses = ContextSet(m for m in metaclasses if m.is_class())
|
||||||
|
if metaclasses:
|
||||||
|
return metaclasses
|
||||||
|
|
||||||
|
for lazy_base in self.py__bases__():
|
||||||
|
for context in lazy_base.infer():
|
||||||
|
contexts = context.get_metaclasses()
|
||||||
|
if contexts:
|
||||||
|
return contexts
|
||||||
|
return NO_CONTEXTS
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import parso
|
|||||||
|
|
||||||
from jedi._compatibility import force_unicode
|
from jedi._compatibility import force_unicode
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
|
from jedi.evaluate.utils import safe_property
|
||||||
from jedi.evaluate.helpers import get_str_or_none
|
from jedi.evaluate.helpers import get_str_or_none
|
||||||
from jedi.evaluate.arguments import ValuesArguments, \
|
from jedi.evaluate.arguments import ValuesArguments, \
|
||||||
repack_with_argument_clinic, AbstractArguments, TreeArgumentsWrapper
|
repack_with_argument_clinic, AbstractArguments, TreeArgumentsWrapper
|
||||||
@@ -26,8 +27,10 @@ from jedi.evaluate.context import ClassContext, ModuleContext, \
|
|||||||
from jedi.evaluate.context import iterable
|
from jedi.evaluate.context import iterable
|
||||||
from jedi.evaluate.lazy_context import LazyTreeContext, LazyKnownContext, \
|
from jedi.evaluate.lazy_context import LazyTreeContext, LazyKnownContext, \
|
||||||
LazyKnownContexts
|
LazyKnownContexts
|
||||||
|
from jedi.evaluate.names import ContextName
|
||||||
from jedi.evaluate.syntax_tree import is_string
|
from jedi.evaluate.syntax_tree import is_string
|
||||||
from jedi.evaluate.filters import AttributeOverwrite, publish_method
|
from jedi.evaluate.filters import AttributeOverwrite, publish_method, \
|
||||||
|
ParserTreeFilter, DictFilter
|
||||||
|
|
||||||
|
|
||||||
# Copied from Python 3.6's stdlib.
|
# Copied from Python 3.6's stdlib.
|
||||||
@@ -602,3 +605,41 @@ _implemented = {
|
|||||||
'dataclass': lambda obj, arguments: NO_CONTEXTS,
|
'dataclass': lambda obj, arguments: NO_CONTEXTS,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_metaclass_filters(func):
|
||||||
|
def wrapper(cls, metaclasses):
|
||||||
|
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()
|
||||||
|
})]
|
||||||
|
return func(cls, metaclasses)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class EnumInstance(LazyContextWrapper):
|
||||||
|
def __init__(self, cls, name):
|
||||||
|
self.evaluator = cls.evaluator
|
||||||
|
self._cls = cls # Corresponds to super().__self__
|
||||||
|
self._name = name
|
||||||
|
self.tree_node = self._name.tree_name
|
||||||
|
|
||||||
|
@safe_property
|
||||||
|
def name(self):
|
||||||
|
return ContextName(self, self._name.tree_name)
|
||||||
|
|
||||||
|
def _get_wrapped_context(self):
|
||||||
|
obj, = self._cls.execute_evaluated()
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def get_filters(self, search_global=False, position=None, origin_scope=None):
|
||||||
|
yield DictFilter(dict(
|
||||||
|
name=self._name.string_name,
|
||||||
|
value=self._name,
|
||||||
|
))
|
||||||
|
for f in self._get_wrapped_context().get_filters():
|
||||||
|
yield f
|
||||||
|
|||||||
@@ -290,3 +290,31 @@ class Test(metaclass=Meta):
|
|||||||
result = super(Test, self).test_function()
|
result = super(Test, self).test_function()
|
||||||
#? []
|
#? []
|
||||||
result.
|
result.
|
||||||
|
|
||||||
|
# -----------------
|
||||||
|
# Enum
|
||||||
|
# -----------------
|
||||||
|
|
||||||
|
# python >= 3.4
|
||||||
|
import enum
|
||||||
|
|
||||||
|
class X(enum.Enum):
|
||||||
|
attr_x = 3
|
||||||
|
attr_y = 2.0
|
||||||
|
|
||||||
|
#? ['mro']
|
||||||
|
X.mro
|
||||||
|
#? ['attr_x', 'attr_y']
|
||||||
|
X.attr_
|
||||||
|
#? str()
|
||||||
|
X.attr_x.name
|
||||||
|
#? int()
|
||||||
|
X.attr_x.value
|
||||||
|
#? str()
|
||||||
|
X.attr_y.name
|
||||||
|
#? float()
|
||||||
|
X.attr_y.value
|
||||||
|
#? str()
|
||||||
|
X().name
|
||||||
|
#? float()
|
||||||
|
X().attr_x.attr_y.value
|
||||||
|
|||||||
@@ -472,6 +472,6 @@ def test_relative_import_star(Script):
|
|||||||
from . import *
|
from . import *
|
||||||
furl.c
|
furl.c
|
||||||
"""
|
"""
|
||||||
script = jedi.Script(source,3,len("furl.c"), 'export.py')
|
script = jedi.Script(source, 3, len("furl.c"), 'export.py')
|
||||||
|
|
||||||
assert script.completions()
|
assert script.completions()
|
||||||
|
|||||||
Reference in New Issue
Block a user