mirror of
https://github.com/davidhalter/jedi.git
synced 2026-05-24 17:28:36 +08:00
Split up the typeshed file
This commit is contained in:
@@ -0,0 +1,384 @@
|
|||||||
|
from jedi.cache import memoize_method
|
||||||
|
from jedi.parser_utils import get_call_signature_for_any
|
||||||
|
from jedi.evaluate.utils import safe_property
|
||||||
|
from jedi.evaluate.base_context import ContextWrapper
|
||||||
|
from jedi.evaluate.context.function import FunctionMixin, FunctionContext, MethodContext
|
||||||
|
from jedi.evaluate.context.klass import ClassMixin, ClassContext
|
||||||
|
from jedi.evaluate.context.module import ModuleMixin, ModuleContext
|
||||||
|
from jedi.evaluate.base_context import iterator_to_context_set
|
||||||
|
from jedi.evaluate.filters import ParserTreeFilter, \
|
||||||
|
NameWrapper, AbstractFilter, TreeNameDefinition
|
||||||
|
from jedi.evaluate.compiled.context import CompiledName
|
||||||
|
from jedi.evaluate.utils import to_list
|
||||||
|
from jedi.evaluate.gradual.typing import TypingModuleFilterWrapper, TypingModuleName
|
||||||
|
|
||||||
|
|
||||||
|
class _StubContextFilterMixin(object):
|
||||||
|
def get_filters(self, search_global=False, until_position=None,
|
||||||
|
origin_scope=None, **kwargs):
|
||||||
|
filters = self._wrapped_context.get_filters(
|
||||||
|
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.
|
||||||
|
non_stub_filters=[next(filters)],
|
||||||
|
search_global=search_global,
|
||||||
|
until_position=until_position,
|
||||||
|
origin_scope=origin_scope,
|
||||||
|
)
|
||||||
|
for f in filters:
|
||||||
|
yield f
|
||||||
|
|
||||||
|
|
||||||
|
class StubModuleContext(_StubContextFilterMixin, ModuleMixin, ContextWrapper):
|
||||||
|
def __init__(self, context, stub_context):
|
||||||
|
super(StubModuleContext, self).__init__(context)
|
||||||
|
self.stub_context = stub_context
|
||||||
|
|
||||||
|
|
||||||
|
class StubClassContext(_StubContextFilterMixin, ClassMixin, ContextWrapper):
|
||||||
|
def __init__(self, parent_context, actual_context, stub_context):
|
||||||
|
super(StubClassContext, self).__init__(actual_context)
|
||||||
|
self.parent_context = parent_context
|
||||||
|
self.stub_context = stub_context
|
||||||
|
|
||||||
|
def __getattribute__(self, name):
|
||||||
|
if name in ('py__getitem__', 'py__simple_getitem__', 'py__bases__',
|
||||||
|
'execute_annotation', 'list_type_vars', 'get_signatures'):
|
||||||
|
# getitem is always done in the stub class.
|
||||||
|
return getattr(self.stub_context, name)
|
||||||
|
return super(StubClassContext, self).__getattribute__(name)
|
||||||
|
|
||||||
|
def define_generics(self, type_var_dict):
|
||||||
|
if not type_var_dict:
|
||||||
|
return self
|
||||||
|
return self.stub_context.define_generics(type_var_dict)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
def get_signatures(self):
|
||||||
|
return self.stub_context.get_signatures()
|
||||||
|
|
||||||
|
|
||||||
|
class StubMethodContext(StubFunctionContext):
|
||||||
|
"""
|
||||||
|
Both of the stub context and the actual context are a stub method.
|
||||||
|
"""
|
||||||
|
@safe_property
|
||||||
|
def class_context(self):
|
||||||
|
return StubClassContext.create_cached(
|
||||||
|
self.evaluator,
|
||||||
|
self.parent_context,
|
||||||
|
actual_context=self._wrapped_context.class_context,
|
||||||
|
stub_context=self.stub_context.class_context
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class _StubOnlyContextMixin(object):
|
||||||
|
_add_non_stubs_in_filter = False
|
||||||
|
|
||||||
|
def _get_stub_only_filters(self, **filter_kwargs):
|
||||||
|
return [StubOnlyFilter(
|
||||||
|
self.evaluator,
|
||||||
|
context=self,
|
||||||
|
**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),
|
||||||
|
add_non_stubs=self._add_non_stubs_in_filter,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_base_filters(self, filters, search_global=False,
|
||||||
|
until_position=None, origin_scope=None):
|
||||||
|
next(filters) # Ignore the first filter and replace it with our own
|
||||||
|
yield self.get_stub_only_filter(
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
for f in filters:
|
||||||
|
yield f
|
||||||
|
|
||||||
|
|
||||||
|
class StubOnlyModuleContext(_StubOnlyContextMixin, ModuleContext):
|
||||||
|
_add_non_stubs_in_filter = True
|
||||||
|
|
||||||
|
def __init__(self, non_stub_context_set, *args, **kwargs):
|
||||||
|
super(StubOnlyModuleContext, self).__init__(*args, **kwargs)
|
||||||
|
self.non_stub_context_set = non_stub_context_set
|
||||||
|
|
||||||
|
def _get_first_non_stub_filters(self):
|
||||||
|
for context in self.non_stub_context_set:
|
||||||
|
yield next(context.get_filters(search_global=False))
|
||||||
|
|
||||||
|
def _get_stub_only_filters(self, search_global, **filter_kwargs):
|
||||||
|
stub_filters = super(StubOnlyModuleContext, self)._get_stub_only_filters(
|
||||||
|
search_global=search_global, **filter_kwargs
|
||||||
|
)
|
||||||
|
stub_filters += self.iter_star_filters(search_global=search_global)
|
||||||
|
return stub_filters
|
||||||
|
|
||||||
|
def get_filters(self, search_global=False, until_position=None,
|
||||||
|
origin_scope=None, **kwargs):
|
||||||
|
filters = super(StubOnlyModuleContext, self).get_filters(
|
||||||
|
search_global, until_position, origin_scope, **kwargs
|
||||||
|
)
|
||||||
|
for f in self._get_base_filters(filters, search_global, until_position, origin_scope):
|
||||||
|
yield f
|
||||||
|
|
||||||
|
|
||||||
|
class StubOnlyClass(_StubOnlyContextMixin, ClassMixin, ContextWrapper):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class _CompiledStubContext(ContextWrapper):
|
||||||
|
def __init__(self, stub_context, compiled_context):
|
||||||
|
super(_CompiledStubContext, self).__init__(stub_context)
|
||||||
|
self._compiled_context = compiled_context
|
||||||
|
|
||||||
|
def py__doc__(self, include_call_signature=False):
|
||||||
|
doc = self._compiled_context.py__doc__()
|
||||||
|
if include_call_signature:
|
||||||
|
call_sig = get_call_signature_for_any(self._wrapped_context.tree_node)
|
||||||
|
if call_sig is not None:
|
||||||
|
doc = call_sig + '\n\n' + doc
|
||||||
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
class CompiledStubFunction(_CompiledStubContext):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CompiledStubClass(_StubOnlyContextMixin, _CompiledStubContext, ClassMixin):
|
||||||
|
def _get_first_non_stub_filters(self):
|
||||||
|
yield next(self._compiled_context.get_filters(search_global=False))
|
||||||
|
|
||||||
|
def get_filters(self, search_global=False, until_position=None,
|
||||||
|
origin_scope=None, **kwargs):
|
||||||
|
filters = self._wrapped_context.get_filters(
|
||||||
|
search_global, until_position, origin_scope, **kwargs
|
||||||
|
)
|
||||||
|
for f in self._get_base_filters(filters, search_global, until_position, origin_scope):
|
||||||
|
yield f
|
||||||
|
|
||||||
|
|
||||||
|
class TypingModuleWrapper(StubOnlyModuleContext):
|
||||||
|
# TODO should use this instead of the isinstance check
|
||||||
|
def get_filterss(self, *args, **kwargs):
|
||||||
|
filters = super(TypingModuleWrapper, self).get_filters(*args, **kwargs)
|
||||||
|
yield TypingModuleFilterWrapper(next(filters))
|
||||||
|
for f in filters:
|
||||||
|
yield f
|
||||||
|
|
||||||
|
|
||||||
|
class StubName(NameWrapper):
|
||||||
|
"""
|
||||||
|
This name is only here to mix stub names with non-stub names. The idea is
|
||||||
|
that the user can goto the actual name, but end up on the definition of the
|
||||||
|
stub when inferring types.
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
@memoize_method
|
||||||
|
@iterator_to_context_set
|
||||||
|
def infer(self):
|
||||||
|
stub_contexts = self._stub_name.infer()
|
||||||
|
if not stub_contexts:
|
||||||
|
for c in self._wrapped_name.infer():
|
||||||
|
yield c
|
||||||
|
return
|
||||||
|
|
||||||
|
typ = self._wrapped_name.tree_name.parent.type
|
||||||
|
if typ in ('classdef', 'funcdef'):
|
||||||
|
actual_context, = self._wrapped_name.infer()
|
||||||
|
for stub_context in stub_contexts:
|
||||||
|
if isinstance(stub_context, MethodContext):
|
||||||
|
assert isinstance(actual_context, MethodContext)
|
||||||
|
cls = StubMethodContext
|
||||||
|
elif isinstance(stub_context, FunctionContext):
|
||||||
|
cls = StubFunctionContext
|
||||||
|
elif isinstance(stub_context, StubOnlyClass):
|
||||||
|
cls = StubClassContext
|
||||||
|
else:
|
||||||
|
yield stub_context
|
||||||
|
continue
|
||||||
|
yield cls.create_cached(
|
||||||
|
actual_context.evaluator,
|
||||||
|
self.parent_context,
|
||||||
|
actual_context,
|
||||||
|
stub_context,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
for c in stub_contexts:
|
||||||
|
yield c
|
||||||
|
|
||||||
|
|
||||||
|
class CompiledStubName(NameWrapper):
|
||||||
|
def __init__(self, parent_context, compiled_name, stub_name):
|
||||||
|
super(CompiledStubName, self).__init__(stub_name)
|
||||||
|
self.parent_context = parent_context
|
||||||
|
self._compiled_name = compiled_name
|
||||||
|
|
||||||
|
@memoize_method
|
||||||
|
@iterator_to_context_set
|
||||||
|
def infer(self):
|
||||||
|
compiled_contexts = self._compiled_name.infer()
|
||||||
|
stub_contexts = self._wrapped_name.infer()
|
||||||
|
|
||||||
|
if not compiled_contexts:
|
||||||
|
for c in stub_contexts:
|
||||||
|
yield c
|
||||||
|
|
||||||
|
for actual_context in compiled_contexts:
|
||||||
|
for stub_context in stub_contexts:
|
||||||
|
if isinstance(stub_context, _CompiledStubContext):
|
||||||
|
# It's already a stub context, e.g. bytes in Python 2
|
||||||
|
# behaves this way.
|
||||||
|
yield stub_context
|
||||||
|
elif stub_context.is_class():
|
||||||
|
assert not isinstance(stub_context, CompiledStubClass), \
|
||||||
|
"%s and %s" % (self._wrapped_name, self._compiled_name)
|
||||||
|
yield CompiledStubClass.create_cached(
|
||||||
|
stub_context.evaluator, stub_context, actual_context)
|
||||||
|
elif stub_context.is_function():
|
||||||
|
yield CompiledStubFunction.create_cached(
|
||||||
|
stub_context.evaluator, stub_context, actual_context)
|
||||||
|
else:
|
||||||
|
yield stub_context
|
||||||
|
if not stub_contexts:
|
||||||
|
yield actual_context
|
||||||
|
|
||||||
|
|
||||||
|
class StubOnlyName(TreeNameDefinition):
|
||||||
|
def infer(self):
|
||||||
|
inferred = super(StubOnlyName, self).infer()
|
||||||
|
if self.string_name == 'version_info' and self.get_root_context().py__name__() == 'sys':
|
||||||
|
return [VersionInfo(c) for c in inferred]
|
||||||
|
|
||||||
|
return [
|
||||||
|
StubOnlyClass.create_cached(c.evaluator, c) if isinstance(c, ClassContext) else c
|
||||||
|
for c in inferred
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class StubOnlyFilter(ParserTreeFilter):
|
||||||
|
name_class = StubOnlyName
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self._search_global = kwargs.pop('search_global') # Python 2 :/
|
||||||
|
super(StubOnlyFilter, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _is_name_reachable(self, name):
|
||||||
|
if not super(StubOnlyFilter, self)._is_name_reachable(name):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not self._search_global:
|
||||||
|
# Imports in stub files are only public if they have an "as"
|
||||||
|
# export.
|
||||||
|
definition = name.get_definition()
|
||||||
|
if definition.type in ('import_from', 'import_name'):
|
||||||
|
if name.parent.type not in ('import_as_name', 'dotted_as_name'):
|
||||||
|
return False
|
||||||
|
n = name.value
|
||||||
|
if n.startswith('_') and not (n.startswith('__') and n.endswith('__')):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class StubFilter(AbstractFilter):
|
||||||
|
"""
|
||||||
|
Merging names from stubs and non-stubs.
|
||||||
|
"""
|
||||||
|
def __init__(self, parent_context, non_stub_filters, stub_filters, add_non_stubs):
|
||||||
|
self._parent_context = parent_context
|
||||||
|
self._non_stub_filters = non_stub_filters
|
||||||
|
self._stub_filters = stub_filters
|
||||||
|
self._add_non_stubs = add_non_stubs
|
||||||
|
|
||||||
|
def get(self, name):
|
||||||
|
non_stub_names = self._get_names_from_filters(self._non_stub_filters, name)
|
||||||
|
stub_names = self._get_names_from_filters(self._stub_filters, name)
|
||||||
|
return self._merge_names(non_stub_names, stub_names)
|
||||||
|
|
||||||
|
def values(self):
|
||||||
|
name_dict = {}
|
||||||
|
for non_stub_filter in self._non_stub_filters:
|
||||||
|
for name in non_stub_filter.values():
|
||||||
|
name_dict.setdefault(name.string_name, []).append(name)
|
||||||
|
|
||||||
|
# Try to match the names of stubs with non-stubs. If there's no
|
||||||
|
# match, just use the stub name. The user will be directed there
|
||||||
|
# for all API accesses. Otherwise the user will be directed to the
|
||||||
|
# non-stub positions (see StubName).
|
||||||
|
for stub_filter in self._stub_filters:
|
||||||
|
for stub_name in stub_filter.values():
|
||||||
|
merged_names = self._merge_names(
|
||||||
|
names=name_dict.get(stub_name.string_name),
|
||||||
|
stub_names=[stub_name]
|
||||||
|
)
|
||||||
|
for merged_name in merged_names:
|
||||||
|
yield merged_name
|
||||||
|
|
||||||
|
def _get_names_from_filters(self, filters, string_name):
|
||||||
|
return [
|
||||||
|
name
|
||||||
|
for filter in filters
|
||||||
|
for name in filter.get(string_name)
|
||||||
|
]
|
||||||
|
|
||||||
|
@to_list
|
||||||
|
def _merge_names(self, names, stub_names):
|
||||||
|
if not stub_names:
|
||||||
|
if self._add_non_stubs:
|
||||||
|
return names
|
||||||
|
return []
|
||||||
|
if not names:
|
||||||
|
if isinstance(self._stub_filters[0].context, TypingModuleWrapper):
|
||||||
|
return [TypingModuleName(n) for n in stub_names]
|
||||||
|
return stub_names
|
||||||
|
|
||||||
|
result = []
|
||||||
|
# The names are contained in both filters.
|
||||||
|
for name in names:
|
||||||
|
for stub_name in stub_names:
|
||||||
|
if isinstance(self._stub_filters[0].context, TypingModuleWrapper):
|
||||||
|
stub_name = TypingModuleName(stub_name)
|
||||||
|
|
||||||
|
if isinstance(name, CompiledName):
|
||||||
|
result.append(CompiledStubName(self._parent_context, name, stub_name))
|
||||||
|
else:
|
||||||
|
result.append(StubName(self._parent_context, name, stub_name))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%s, %s)' % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self._non_stub_filters,
|
||||||
|
self._stub_filters,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VersionInfo(ContextWrapper):
|
||||||
|
pass
|
||||||
@@ -2,22 +2,12 @@ import os
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from jedi._compatibility import FileNotFoundError
|
from jedi._compatibility import FileNotFoundError
|
||||||
|
from jedi.parser_utils import get_cached_code_lines
|
||||||
from jedi.evaluate.cache import evaluator_function_cache
|
from jedi.evaluate.cache import evaluator_function_cache
|
||||||
from jedi.cache import memoize_method
|
from jedi.evaluate.base_context import ContextSet, NO_CONTEXTS
|
||||||
from jedi.parser_utils import get_call_signature_for_any, get_cached_code_lines
|
from jedi.evaluate.context import ModuleContext
|
||||||
from jedi.evaluate.base_context import ContextSet, iterator_to_context_set, \
|
from jedi.evaluate.gradual.stub_context import StubModuleContext, \
|
||||||
ContextWrapper, NO_CONTEXTS
|
TypingModuleWrapper, StubOnlyModuleContext
|
||||||
from jedi.evaluate.filters import ParserTreeFilter, \
|
|
||||||
NameWrapper, AbstractFilter, TreeNameDefinition
|
|
||||||
from jedi.evaluate.context import ModuleContext, FunctionContext, \
|
|
||||||
MethodContext, ClassContext
|
|
||||||
from jedi.evaluate.context.function import FunctionMixin
|
|
||||||
from jedi.evaluate.context.klass import ClassMixin
|
|
||||||
from jedi.evaluate.context.module import ModuleMixin
|
|
||||||
from jedi.evaluate.gradual.typing import TypingModuleFilterWrapper, \
|
|
||||||
TypingModuleName
|
|
||||||
from jedi.evaluate.compiled.context import CompiledName
|
|
||||||
from jedi.evaluate.utils import to_list, safe_property
|
|
||||||
|
|
||||||
_jedi_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
_jedi_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
_TYPESHED_PATH = os.path.join(_jedi_path, 'third_party', 'typeshed')
|
_TYPESHED_PATH = os.path.join(_jedi_path, 'third_party', 'typeshed')
|
||||||
@@ -184,374 +174,3 @@ def import_module_decorator(func):
|
|||||||
# If no stub is found, just return the default.
|
# If no stub is found, just return the default.
|
||||||
return context_set
|
return context_set
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class StubName(NameWrapper):
|
|
||||||
"""
|
|
||||||
This name is only here to mix stub names with non-stub names. The idea is
|
|
||||||
that the user can goto the actual name, but end up on the definition of the
|
|
||||||
stub when inferring types.
|
|
||||||
"""
|
|
||||||
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
|
|
||||||
|
|
||||||
@memoize_method
|
|
||||||
@iterator_to_context_set
|
|
||||||
def infer(self):
|
|
||||||
stub_contexts = self._stub_name.infer()
|
|
||||||
if not stub_contexts:
|
|
||||||
for c in self._wrapped_name.infer():
|
|
||||||
yield c
|
|
||||||
return
|
|
||||||
|
|
||||||
typ = self._wrapped_name.tree_name.parent.type
|
|
||||||
if typ in ('classdef', 'funcdef'):
|
|
||||||
actual_context, = self._wrapped_name.infer()
|
|
||||||
for stub_context in stub_contexts:
|
|
||||||
if isinstance(stub_context, MethodContext):
|
|
||||||
assert isinstance(actual_context, MethodContext)
|
|
||||||
cls = StubMethodContext
|
|
||||||
elif isinstance(stub_context, FunctionContext):
|
|
||||||
cls = StubFunctionContext
|
|
||||||
elif isinstance(stub_context, StubOnlyClass):
|
|
||||||
cls = StubClassContext
|
|
||||||
else:
|
|
||||||
yield stub_context
|
|
||||||
continue
|
|
||||||
yield cls.create_cached(
|
|
||||||
actual_context.evaluator,
|
|
||||||
self.parent_context,
|
|
||||||
actual_context,
|
|
||||||
stub_context,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
for c in stub_contexts:
|
|
||||||
yield c
|
|
||||||
|
|
||||||
|
|
||||||
class CompiledStubName(NameWrapper):
|
|
||||||
def __init__(self, parent_context, compiled_name, stub_name):
|
|
||||||
super(CompiledStubName, self).__init__(stub_name)
|
|
||||||
self.parent_context = parent_context
|
|
||||||
self._compiled_name = compiled_name
|
|
||||||
|
|
||||||
@memoize_method
|
|
||||||
@iterator_to_context_set
|
|
||||||
def infer(self):
|
|
||||||
compiled_contexts = self._compiled_name.infer()
|
|
||||||
stub_contexts = self._wrapped_name.infer()
|
|
||||||
|
|
||||||
if not compiled_contexts:
|
|
||||||
for c in stub_contexts:
|
|
||||||
yield c
|
|
||||||
|
|
||||||
for actual_context in compiled_contexts:
|
|
||||||
for stub_context in stub_contexts:
|
|
||||||
if isinstance(stub_context, _CompiledStubContext):
|
|
||||||
# It's already a stub context, e.g. bytes in Python 2
|
|
||||||
# behaves this way.
|
|
||||||
yield stub_context
|
|
||||||
elif stub_context.is_class():
|
|
||||||
assert not isinstance(stub_context, CompiledStubClass), \
|
|
||||||
"%s and %s" % (self._wrapped_name, self._compiled_name)
|
|
||||||
yield CompiledStubClass.create_cached(
|
|
||||||
stub_context.evaluator, stub_context, actual_context)
|
|
||||||
elif stub_context.is_function():
|
|
||||||
yield CompiledStubFunction.create_cached(
|
|
||||||
stub_context.evaluator, stub_context, actual_context)
|
|
||||||
else:
|
|
||||||
yield stub_context
|
|
||||||
if not stub_contexts:
|
|
||||||
yield actual_context
|
|
||||||
|
|
||||||
|
|
||||||
class VersionInfo(ContextWrapper):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class StubOnlyName(TreeNameDefinition):
|
|
||||||
def infer(self):
|
|
||||||
inferred = super(StubOnlyName, self).infer()
|
|
||||||
if self.string_name == 'version_info' and self.get_root_context().py__name__() == 'sys':
|
|
||||||
return [VersionInfo(c) for c in inferred]
|
|
||||||
|
|
||||||
return [
|
|
||||||
StubOnlyClass.create_cached(c.evaluator, c) if isinstance(c, ClassContext) else c
|
|
||||||
for c in inferred
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class StubOnlyFilter(ParserTreeFilter):
|
|
||||||
name_class = StubOnlyName
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
self._search_global = kwargs.pop('search_global') # Python 2 :/
|
|
||||||
super(StubOnlyFilter, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def _is_name_reachable(self, name):
|
|
||||||
if not super(StubOnlyFilter, self)._is_name_reachable(name):
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not self._search_global:
|
|
||||||
# Imports in stub files are only public if they have an "as"
|
|
||||||
# export.
|
|
||||||
definition = name.get_definition()
|
|
||||||
if definition.type in ('import_from', 'import_name'):
|
|
||||||
if name.parent.type not in ('import_as_name', 'dotted_as_name'):
|
|
||||||
return False
|
|
||||||
n = name.value
|
|
||||||
if n.startswith('_') and not (n.startswith('__') and n.endswith('__')):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class StubFilter(AbstractFilter):
|
|
||||||
"""
|
|
||||||
Merging names from stubs and non-stubs.
|
|
||||||
"""
|
|
||||||
def __init__(self, parent_context, non_stub_filters, stub_filters, add_non_stubs):
|
|
||||||
self._parent_context = parent_context
|
|
||||||
self._non_stub_filters = non_stub_filters
|
|
||||||
self._stub_filters = stub_filters
|
|
||||||
self._add_non_stubs = add_non_stubs
|
|
||||||
|
|
||||||
def get(self, name):
|
|
||||||
non_stub_names = self._get_names_from_filters(self._non_stub_filters, name)
|
|
||||||
stub_names = self._get_names_from_filters(self._stub_filters, name)
|
|
||||||
return self._merge_names(non_stub_names, stub_names)
|
|
||||||
|
|
||||||
def values(self):
|
|
||||||
name_dict = {}
|
|
||||||
for non_stub_filter in self._non_stub_filters:
|
|
||||||
for name in non_stub_filter.values():
|
|
||||||
name_dict.setdefault(name.string_name, []).append(name)
|
|
||||||
|
|
||||||
# Try to match the names of stubs with non-stubs. If there's no
|
|
||||||
# match, just use the stub name. The user will be directed there
|
|
||||||
# for all API accesses. Otherwise the user will be directed to the
|
|
||||||
# non-stub positions (see StubName).
|
|
||||||
for stub_filter in self._stub_filters:
|
|
||||||
for stub_name in stub_filter.values():
|
|
||||||
merged_names = self._merge_names(
|
|
||||||
names=name_dict.get(stub_name.string_name),
|
|
||||||
stub_names=[stub_name]
|
|
||||||
)
|
|
||||||
for merged_name in merged_names:
|
|
||||||
yield merged_name
|
|
||||||
|
|
||||||
def _get_names_from_filters(self, filters, string_name):
|
|
||||||
return [
|
|
||||||
name
|
|
||||||
for filter in filters
|
|
||||||
for name in filter.get(string_name)
|
|
||||||
]
|
|
||||||
|
|
||||||
@to_list
|
|
||||||
def _merge_names(self, names, stub_names):
|
|
||||||
if not stub_names:
|
|
||||||
if self._add_non_stubs:
|
|
||||||
return names
|
|
||||||
return []
|
|
||||||
if not names:
|
|
||||||
if isinstance(self._stub_filters[0].context, TypingModuleWrapper):
|
|
||||||
return [TypingModuleName(n) for n in stub_names]
|
|
||||||
return stub_names
|
|
||||||
|
|
||||||
result = []
|
|
||||||
# The names are contained in both filters.
|
|
||||||
for name in names:
|
|
||||||
for stub_name in stub_names:
|
|
||||||
if isinstance(self._stub_filters[0].context, TypingModuleWrapper):
|
|
||||||
stub_name = TypingModuleName(stub_name)
|
|
||||||
|
|
||||||
if isinstance(name, CompiledName):
|
|
||||||
result.append(CompiledStubName(self._parent_context, name, stub_name))
|
|
||||||
else:
|
|
||||||
result.append(StubName(self._parent_context, name, stub_name))
|
|
||||||
return result
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return '%s(%s, %s)' % (
|
|
||||||
self.__class__.__name__,
|
|
||||||
self._non_stub_filters,
|
|
||||||
self._stub_filters,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class _StubContextFilterMixin(object):
|
|
||||||
def get_filters(self, search_global=False, until_position=None,
|
|
||||||
origin_scope=None, **kwargs):
|
|
||||||
filters = self._wrapped_context.get_filters(
|
|
||||||
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.
|
|
||||||
non_stub_filters=[next(filters)],
|
|
||||||
search_global=search_global,
|
|
||||||
until_position=until_position,
|
|
||||||
origin_scope=origin_scope,
|
|
||||||
)
|
|
||||||
for f in filters:
|
|
||||||
yield f
|
|
||||||
|
|
||||||
|
|
||||||
class StubModuleContext(_StubContextFilterMixin, ModuleMixin, ContextWrapper):
|
|
||||||
def __init__(self, context, stub_context):
|
|
||||||
super(StubModuleContext, self).__init__(context)
|
|
||||||
self.stub_context = stub_context
|
|
||||||
|
|
||||||
|
|
||||||
class StubClassContext(_StubContextFilterMixin, ClassMixin, ContextWrapper):
|
|
||||||
def __init__(self, parent_context, actual_context, stub_context):
|
|
||||||
super(StubClassContext, self).__init__(actual_context)
|
|
||||||
self.parent_context = parent_context
|
|
||||||
self.stub_context = stub_context
|
|
||||||
|
|
||||||
def __getattribute__(self, name):
|
|
||||||
if name in ('py__getitem__', 'py__simple_getitem__', 'py__bases__',
|
|
||||||
'execute_annotation', 'list_type_vars', 'get_signatures'):
|
|
||||||
# getitem is always done in the stub class.
|
|
||||||
return getattr(self.stub_context, name)
|
|
||||||
return super(StubClassContext, self).__getattribute__(name)
|
|
||||||
|
|
||||||
def define_generics(self, type_var_dict):
|
|
||||||
if not type_var_dict:
|
|
||||||
return self
|
|
||||||
return self.stub_context.define_generics(type_var_dict)
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
def get_signatures(self):
|
|
||||||
return self.stub_context.get_signatures()
|
|
||||||
|
|
||||||
|
|
||||||
class StubMethodContext(StubFunctionContext):
|
|
||||||
"""
|
|
||||||
Both of the stub context and the actual context are a stub method.
|
|
||||||
"""
|
|
||||||
@safe_property
|
|
||||||
def class_context(self):
|
|
||||||
return StubClassContext.create_cached(
|
|
||||||
self.evaluator,
|
|
||||||
self.parent_context,
|
|
||||||
actual_context=self._wrapped_context.class_context,
|
|
||||||
stub_context=self.stub_context.class_context
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class _StubOnlyContextMixin(object):
|
|
||||||
_add_non_stubs_in_filter = False
|
|
||||||
|
|
||||||
def _get_stub_only_filters(self, **filter_kwargs):
|
|
||||||
return [StubOnlyFilter(
|
|
||||||
self.evaluator,
|
|
||||||
context=self,
|
|
||||||
**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),
|
|
||||||
add_non_stubs=self._add_non_stubs_in_filter,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _get_base_filters(self, filters, search_global=False,
|
|
||||||
until_position=None, origin_scope=None):
|
|
||||||
next(filters) # Ignore the first filter and replace it with our own
|
|
||||||
yield self.get_stub_only_filter(
|
|
||||||
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,
|
|
||||||
)
|
|
||||||
|
|
||||||
for f in filters:
|
|
||||||
yield f
|
|
||||||
|
|
||||||
|
|
||||||
class StubOnlyModuleContext(_StubOnlyContextMixin, ModuleContext):
|
|
||||||
_add_non_stubs_in_filter = True
|
|
||||||
|
|
||||||
def __init__(self, non_stub_context_set, *args, **kwargs):
|
|
||||||
super(StubOnlyModuleContext, self).__init__(*args, **kwargs)
|
|
||||||
self.non_stub_context_set = non_stub_context_set
|
|
||||||
|
|
||||||
def _get_first_non_stub_filters(self):
|
|
||||||
for context in self.non_stub_context_set:
|
|
||||||
yield next(context.get_filters(search_global=False))
|
|
||||||
|
|
||||||
def _get_stub_only_filters(self, search_global, **filter_kwargs):
|
|
||||||
stub_filters = super(StubOnlyModuleContext, self)._get_stub_only_filters(
|
|
||||||
search_global=search_global, **filter_kwargs
|
|
||||||
)
|
|
||||||
stub_filters += self.iter_star_filters(search_global=search_global)
|
|
||||||
return stub_filters
|
|
||||||
|
|
||||||
def get_filters(self, search_global=False, until_position=None,
|
|
||||||
origin_scope=None, **kwargs):
|
|
||||||
filters = super(StubOnlyModuleContext, self).get_filters(
|
|
||||||
search_global, until_position, origin_scope, **kwargs
|
|
||||||
)
|
|
||||||
for f in self._get_base_filters(filters, search_global, until_position, origin_scope):
|
|
||||||
yield f
|
|
||||||
|
|
||||||
|
|
||||||
class StubOnlyClass(_StubOnlyContextMixin, ClassMixin, ContextWrapper):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class _CompiledStubContext(ContextWrapper):
|
|
||||||
def __init__(self, stub_context, compiled_context):
|
|
||||||
super(_CompiledStubContext, self).__init__(stub_context)
|
|
||||||
self._compiled_context = compiled_context
|
|
||||||
|
|
||||||
def py__doc__(self, include_call_signature=False):
|
|
||||||
doc = self._compiled_context.py__doc__()
|
|
||||||
if include_call_signature:
|
|
||||||
call_sig = get_call_signature_for_any(self._wrapped_context.tree_node)
|
|
||||||
if call_sig is not None:
|
|
||||||
doc = call_sig + '\n\n' + doc
|
|
||||||
return doc
|
|
||||||
|
|
||||||
|
|
||||||
class CompiledStubFunction(_CompiledStubContext):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CompiledStubClass(_StubOnlyContextMixin, _CompiledStubContext, ClassMixin):
|
|
||||||
def _get_first_non_stub_filters(self):
|
|
||||||
yield next(self._compiled_context.get_filters(search_global=False))
|
|
||||||
|
|
||||||
def get_filters(self, search_global=False, until_position=None,
|
|
||||||
origin_scope=None, **kwargs):
|
|
||||||
filters = self._wrapped_context.get_filters(
|
|
||||||
search_global, until_position, origin_scope, **kwargs
|
|
||||||
)
|
|
||||||
for f in self._get_base_filters(filters, search_global, until_position, origin_scope):
|
|
||||||
yield f
|
|
||||||
|
|
||||||
|
|
||||||
class TypingModuleWrapper(StubOnlyModuleContext):
|
|
||||||
# TODO should use this instead of the isinstance check
|
|
||||||
def get_filterss(self, *args, **kwargs):
|
|
||||||
filters = super(TypingModuleWrapper, self).get_filters(*args, **kwargs)
|
|
||||||
yield TypingModuleFilterWrapper(next(filters))
|
|
||||||
for f in filters:
|
|
||||||
yield f
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ from jedi.evaluate.finder import NameFinder
|
|||||||
from jedi.evaluate.helpers import is_string, is_literal, is_number, is_compiled
|
from jedi.evaluate.helpers import is_string, is_literal, is_number, is_compiled
|
||||||
from jedi.evaluate.compiled.access import COMPARISON_OPERATORS
|
from jedi.evaluate.compiled.access import COMPARISON_OPERATORS
|
||||||
from jedi.evaluate.cache import evaluator_method_cache
|
from jedi.evaluate.cache import evaluator_method_cache
|
||||||
from jedi.evaluate.gradual.typeshed import VersionInfo
|
from jedi.evaluate.gradual.stub_context import VersionInfo
|
||||||
from jedi.evaluate.gradual import annotation
|
from jedi.evaluate.gradual import annotation
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from jedi.evaluate.gradual import typeshed
|
from jedi.evaluate.gradual import typeshed, stub_context
|
||||||
from jedi.evaluate.context import TreeInstance, BoundMethod, FunctionContext
|
from jedi.evaluate.context import TreeInstance, BoundMethod, FunctionContext
|
||||||
from parso.utils import PythonVersionInfo
|
from parso.utils import PythonVersionInfo
|
||||||
from jedi.evaluate.filters import TreeNameDefinition
|
from jedi.evaluate.filters import TreeNameDefinition
|
||||||
@@ -48,7 +48,7 @@ def test_function(Script, environment):
|
|||||||
# it's for now a FunctionContext.
|
# it's for now a FunctionContext.
|
||||||
expected = FunctionContext
|
expected = FunctionContext
|
||||||
else:
|
else:
|
||||||
expected = typeshed.StubFunctionContext
|
expected = stub_context.StubFunctionContext
|
||||||
|
|
||||||
code = 'import threading; threading.current_thread'
|
code = 'import threading; threading.current_thread'
|
||||||
def_, = Script(code).goto_definitions()
|
def_, = Script(code).goto_definitions()
|
||||||
@@ -58,10 +58,10 @@ def test_function(Script, environment):
|
|||||||
def_, = Script(code + '()').goto_definitions()
|
def_, = Script(code + '()').goto_definitions()
|
||||||
context = def_._name._context
|
context = def_._name._context
|
||||||
assert isinstance(context, TreeInstance)
|
assert isinstance(context, TreeInstance)
|
||||||
assert isinstance(context.class_context, typeshed.StubOnlyClass), context
|
assert isinstance(context.class_context, stub_context.StubOnlyClass), context
|
||||||
|
|
||||||
def_, = Script('import threading; threading.Thread').goto_definitions()
|
def_, = Script('import threading; threading.Thread').goto_definitions()
|
||||||
assert isinstance(def_._name._context, typeshed.StubClassContext), def_
|
assert isinstance(def_._name._context, stub_context.StubClassContext), def_
|
||||||
|
|
||||||
|
|
||||||
def test_keywords_variable(Script):
|
def test_keywords_variable(Script):
|
||||||
@@ -75,20 +75,20 @@ def test_keywords_variable(Script):
|
|||||||
def test_class(Script):
|
def test_class(Script):
|
||||||
def_, = Script('import threading; threading.Thread').goto_definitions()
|
def_, = Script('import threading; threading.Thread').goto_definitions()
|
||||||
context = def_._name._context
|
context = def_._name._context
|
||||||
assert isinstance(context, typeshed.StubClassContext), context
|
assert isinstance(context, stub_context.StubClassContext), context
|
||||||
|
|
||||||
|
|
||||||
def test_instance(Script):
|
def test_instance(Script):
|
||||||
def_, = Script('import threading; threading.Thread()').goto_definitions()
|
def_, = Script('import threading; threading.Thread()').goto_definitions()
|
||||||
context = def_._name._context
|
context = def_._name._context
|
||||||
assert isinstance(context, TreeInstance)
|
assert isinstance(context, TreeInstance)
|
||||||
assert isinstance(context.class_context, typeshed.StubClassContext), context
|
assert isinstance(context.class_context, stub_context.StubClassContext), context
|
||||||
|
|
||||||
|
|
||||||
def test_class_function(Script):
|
def test_class_function(Script):
|
||||||
def_, = Script('import threading; threading.Thread.getName').goto_definitions()
|
def_, = Script('import threading; threading.Thread.getName').goto_definitions()
|
||||||
context = def_._name._context
|
context = def_._name._context
|
||||||
assert isinstance(context, typeshed.StubFunctionContext), context
|
assert isinstance(context, stub_context.StubFunctionContext), context
|
||||||
|
|
||||||
|
|
||||||
def test_method(Script):
|
def test_method(Script):
|
||||||
@@ -96,7 +96,7 @@ def test_method(Script):
|
|||||||
def_, = Script(code).goto_definitions()
|
def_, = Script(code).goto_definitions()
|
||||||
context = def_._name._context
|
context = def_._name._context
|
||||||
assert isinstance(context, BoundMethod), context
|
assert isinstance(context, BoundMethod), context
|
||||||
assert isinstance(context._wrapped_context, typeshed.StubFunctionContext), context
|
assert isinstance(context._wrapped_context, stub_context.StubFunctionContext), context
|
||||||
|
|
||||||
def_, = Script(code + '()').goto_definitions()
|
def_, = Script(code + '()').goto_definitions()
|
||||||
context = def_._name._context
|
context = def_._name._context
|
||||||
@@ -130,7 +130,7 @@ def test_sys_getwindowsversion(Script, environment):
|
|||||||
def test_sys_hexversion(Script):
|
def test_sys_hexversion(Script):
|
||||||
script = Script('import sys; sys.hexversion')
|
script = Script('import sys; sys.hexversion')
|
||||||
def_, = script.completions()
|
def_, = script.completions()
|
||||||
assert isinstance(def_._name, typeshed.CompiledStubName), def_._name
|
assert isinstance(def_._name, stub_context.CompiledStubName), def_._name
|
||||||
assert isinstance(def_._name._wrapped_name, TreeNameDefinition)
|
assert isinstance(def_._name._wrapped_name, TreeNameDefinition)
|
||||||
assert typeshed._TYPESHED_PATH in def_.module_path
|
assert typeshed._TYPESHED_PATH in def_.module_path
|
||||||
def_, = script.goto_definitions()
|
def_, = script.goto_definitions()
|
||||||
|
|||||||
Reference in New Issue
Block a user