diff --git a/jedi/evaluate/base_context.py b/jedi/evaluate/base_context.py index 7f193632..9bd751c8 100644 --- a/jedi/evaluate/base_context.py +++ b/jedi/evaluate/base_context.py @@ -140,6 +140,9 @@ class Context(HelperContextMixin, BaseContext): def is_function(self): return False + def is_module(self): + return False + def py__bool__(self): """ Since Wrapper is a super class for classes, functions and modules, diff --git a/jedi/evaluate/context/function.py b/jedi/evaluate/context/function.py index ee5774ec..05b4613b 100644 --- a/jedi/evaluate/context/function.py +++ b/jedi/evaluate/context/function.py @@ -132,10 +132,10 @@ class FunctionContext(use_metaclass(CachedMetaClass, FunctionMixin, TreeContext) class MethodContext(FunctionContext): def __init__(self, evaluator, class_context, *args, **kwargs): super(MethodContext, self).__init__(evaluator, *args, **kwargs) - self._class_context = class_context + self.class_context = class_context def get_default_param_context(self): - return self._class_context + return self.class_context class FunctionExecutionContext(TreeContext): diff --git a/jedi/evaluate/context/instance.py b/jedi/evaluate/context/instance.py index d82ad9f5..764b5188 100644 --- a/jedi/evaluate/context/instance.py +++ b/jedi/evaluate/context/instance.py @@ -11,7 +11,7 @@ from jedi.evaluate.cache import evaluator_method_cache from jedi.evaluate.arguments import AbstractArguments, AnonymousArguments, \ ValuesArguments, TreeArgumentsWrapper from jedi.evaluate.context.function import FunctionExecutionContext, \ - FunctionContext, FunctionMixin, OverloadedFunctionContext + FunctionContext, FunctionMixin, OverloadedFunctionContext, MethodContext from jedi.evaluate.context.klass import ClassContext, apply_py__get__, \ py__mro__, ClassFilter from jedi.evaluate.context import iterable @@ -271,7 +271,10 @@ class TreeInstance(AbstractInstanceContext): for func in self._get_annotation_init_functions(): # Just take the first result, it should always be one, because we # control the typeshed code. - bound = BoundMethod(self, self.class_context, func) + c = self.class_context + if isinstance(func, MethodContext): + c = func.class_context + bound = BoundMethod(self, c, func) execution = bound.get_function_execution(self.var_args) if not execution.matches_signature(): # First check if the signature even matches, if not we don't @@ -382,6 +385,11 @@ class BoundMethod(FunctionMixin, ContextWrapper): return super(BoundMethod, self).get_function_execution(arguments) + def get_default_param_context(self): + if isinstance(self._wrapped_context, MethodContext): + return self.class_context + return self._wrapped_context.get_default_param_context() + def py__call__(self, arguments): if isinstance(self._wrapped_context, OverloadedFunctionContext): return self._wrapped_context.py__call__(self._get_arguments(arguments)) diff --git a/jedi/evaluate/context/module.py b/jedi/evaluate/context/module.py index a215d66b..302c41fa 100644 --- a/jedi/evaluate/context/module.py +++ b/jedi/evaluate/context/module.py @@ -52,6 +52,9 @@ class ModuleContext(TreeContext): self._string_names = string_names self.code_lines = code_lines + def is_module(self): + return True + def iter_star_filters(self, search_global=False): for star_module in self.star_imports(): yield next(star_module.get_filters(search_global)) diff --git a/jedi/evaluate/context/typing.py b/jedi/evaluate/context/typing.py index ff3d0f33..93a5f649 100644 --- a/jedi/evaluate/context/typing.py +++ b/jedi/evaluate/context/typing.py @@ -508,6 +508,7 @@ class AbstractAnnotatedClass(ClassMixin, ContextWrapper): return stub_context.get_stub_only_filter( # Take the first filter, which is here to filter module contents # and wrap it. + self.parent_context, [filter_], search_global=False, origin_scope=origin_scope, diff --git a/jedi/plugins/stdlib.py b/jedi/plugins/stdlib.py index e65fede0..8d1a5a05 100644 --- a/jedi/plugins/stdlib.py +++ b/jedi/plugins/stdlib.py @@ -59,10 +59,10 @@ class StdlibPlugin(BasePlugin): else: if context.parent_context == self._evaluator.builtins_module: module_name = 'builtins' - elif isinstance(context.parent_context, ModuleContext): + elif context.parent_context.is_module(): module_name = context.parent_context.name.string_name else: - module_name = '' + return callback(context, arguments=arguments) if isinstance(context, BoundMethod): if module_name == 'builtins': diff --git a/jedi/plugins/typeshed.py b/jedi/plugins/typeshed.py index 7cc63a9c..d88733ad 100644 --- a/jedi/plugins/typeshed.py +++ b/jedi/plugins/typeshed.py @@ -12,6 +12,7 @@ from jedi.evaluate.filters import ParserTreeFilter, \ NameWrapper, AbstractFilter, TreeNameDefinition from jedi.evaluate.context import ModuleContext, FunctionContext, \ ClassContext +from jedi.evaluate.context.function import FunctionMixin from jedi.evaluate.context.klass import ClassMixin from jedi.evaluate.context.typing import TypingModuleFilterWrapper, \ TypingModuleName @@ -197,16 +198,17 @@ class NameWithStubMixin(object): for stub_context in stub_contexts: if isinstance(stub_context, FunctionContext) \ and isinstance(actual_context, FunctionContext): - yield StubFunctionContext( + yield StubFunctionContext.create_cached( actual_context.evaluator, + self.parent_context, + actual_context, stub_context, - actual_context.parent_context, - actual_context.tree_node, ) elif isinstance(stub_context, StubOnlyClass) \ and isinstance(actual_context, ClassContext): yield StubClassContext.create_cached( actual_context.evaluator, + self.parent_context, actual_context, stub_context, ) @@ -227,8 +229,9 @@ class StubOnlyName(TreeNameDefinition): class StubName(NameWithStubMixin, NameWrapper): - def __init__(self, non_stub_name, stub_name): + def __init__(self, parent_context, non_stub_name, stub_name): super(StubName, self).__init__(non_stub_name) + self.parent_context = parent_context self._stub_name = stub_name def _get_actual_contexts(self): @@ -273,7 +276,8 @@ class StubFilter(AbstractFilter): """ Merging names from stubs and non-stubs. """ - def __init__(self, non_stub_filters, stub_filters): + def __init__(self, parent_context, non_stub_filters, stub_filters): + self._parent_context = parent_context self._non_stub_filters = non_stub_filters self._stub_filters = stub_filters @@ -325,9 +329,10 @@ class StubFilter(AbstractFilter): stub_name = TypingModuleName(stub_name) if isinstance(name, CompiledName): + # TODO remove this? result.append(CompiledNameWithStub(name, stub_name)) else: - result.append(StubName(name, stub_name)) + result.append(StubName(self._parent_context, name, stub_name)) return result def __repr__(self): @@ -354,9 +359,10 @@ class _StubContextFilterMixin(object): search_global, until_position, origin_scope, **kwargs ) yield self.stub_context.get_stub_only_filter( + parent_context=self, # Take the first filter, which is here to filter module contents # and wrap it. - [next(filters)], + non_stub_filters=[next(filters)], search_global=search_global, until_position=until_position, origin_scope=origin_scope, @@ -370,8 +376,9 @@ class StubModuleContext(_MixedStubContextMixin, _StubContextFilterMixin, ModuleC class StubClassContext(_StubContextFilterMixin, ClassMixin, ContextWrapper): - def __init__(self, cls, stub_context): + def __init__(self, parent_context, cls, stub_context): super(StubClassContext, self).__init__(cls) + self.parent_context = parent_context self.stub_context = stub_context def __getattribute__(self, name): @@ -383,10 +390,14 @@ class StubClassContext(_StubContextFilterMixin, ClassMixin, ContextWrapper): return super(StubClassContext, self).__getattribute__(name) -class StubFunctionContext(_MixedStubContextMixin, FunctionContext): +class StubFunctionContext(FunctionMixin, ContextWrapper): + def __init__(self, parent_context, actual_context, stub_context): + super(StubFunctionContext, self).__init__(actual_context) + self.parent_context = parent_context + self.stub_context = stub_context + def get_function_execution(self, arguments=None): return self.stub_context.get_function_execution(arguments) - return super().get_function_execution(arguments, tree_node=self.stub_context.tree_node) class _StubOnlyContext(object): @@ -397,10 +408,11 @@ class _StubOnlyContext(object): **filter_kwargs )] - def get_stub_only_filter(self, non_stub_filters, **filter_kwargs): + def get_stub_only_filter(self, parent_context, non_stub_filters, **filter_kwargs): # Here we remap the names from stubs to the actual module. This is # important if type inferences is needed in that module. return StubFilter( + parent_context, non_stub_filters, self._get_stub_only_filters(**filter_kwargs), ) @@ -430,10 +442,12 @@ class StubOnlyModuleContext(_StubOnlyContext, ModuleContext): next(filters) # Ignore the first filter and replace it with our own yield self.get_stub_only_filter( - list(self._get_first_non_stub_filters()), + parent_context=self, + non_stub_filters=list(self._get_first_non_stub_filters()), search_global=search_global, until_position=until_position, origin_scope=origin_scope, + # add_non_stubs=False # TODO add something like this ) for f in filters: yield f diff --git a/test/completion/invalid.py b/test/completion/invalid.py index 7c047e66..0b81cc9a 100644 --- a/test/completion/invalid.py +++ b/test/completion/invalid.py @@ -143,12 +143,12 @@ a3[0] a = [for a in def break(): pass -#? +#? str() a[0] a = [a for a in [1,2] def break(): pass -#? +#? str() a[0] #? []