forked from VimPlug/jedi
Fix the first issues with the new typing module implementation
This commit is contained in:
@@ -273,6 +273,7 @@ class GeneratorComprehension(ComprehensionMixin, GeneratorBase):
|
|||||||
|
|
||||||
|
|
||||||
class SequenceLiteralContext(Sequence):
|
class SequenceLiteralContext(Sequence):
|
||||||
|
_TUPLE_LIKE = 'testlist_star_expr', 'testlist', 'subscriptlist'
|
||||||
mapping = {'(': u'tuple',
|
mapping = {'(': u'tuple',
|
||||||
'[': u'list',
|
'[': u'list',
|
||||||
'{': u'set'}
|
'{': u'set'}
|
||||||
@@ -282,7 +283,7 @@ class SequenceLiteralContext(Sequence):
|
|||||||
self.atom = atom
|
self.atom = atom
|
||||||
self._defining_context = defining_context
|
self._defining_context = defining_context
|
||||||
|
|
||||||
if self.atom.type in ('testlist_star_expr', 'testlist'):
|
if self.atom.type in self._TUPLE_LIKE:
|
||||||
self.array_type = u'tuple'
|
self.array_type = u'tuple'
|
||||||
else:
|
else:
|
||||||
self.array_type = SequenceLiteralContext.mapping[atom.children[0]]
|
self.array_type = SequenceLiteralContext.mapping[atom.children[0]]
|
||||||
@@ -336,7 +337,7 @@ class SequenceLiteralContext(Sequence):
|
|||||||
def _items(self):
|
def _items(self):
|
||||||
c = self.atom.children
|
c = self.atom.children
|
||||||
|
|
||||||
if self.atom.type in ('testlist_star_expr', 'testlist'):
|
if self.atom.type in self._TUPLE_LIKE:
|
||||||
return c[::2]
|
return c[::2]
|
||||||
|
|
||||||
array_node = c[1]
|
array_node = c[1]
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ We need to somehow work with the typing objects. Since the typing objects are
|
|||||||
pretty bare we need to add all the Jedi customizations to make them work as
|
pretty bare we need to add all the Jedi customizations to make them work as
|
||||||
contexts.
|
contexts.
|
||||||
"""
|
"""
|
||||||
|
from parso.python import tree
|
||||||
|
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.evaluate.compiled import builtin_from_name
|
from jedi.evaluate.compiled import builtin_from_name
|
||||||
@@ -13,10 +14,30 @@ _PROXY_TYPES = 'Optional Union Callable Type ClassVar Tuple Generic Protocol'.sp
|
|||||||
_TYPE_ALIAS_TYPES = 'List Dict DefaultDict Set FrozenSet Counter Deque ChainMap'.split()
|
_TYPE_ALIAS_TYPES = 'List Dict DefaultDict Set FrozenSet Counter Deque ChainMap'.split()
|
||||||
|
|
||||||
|
|
||||||
def check(context, name):
|
class _TypingBase(object):
|
||||||
|
def __init__(self, name, typing_context):
|
||||||
|
self._name = name
|
||||||
|
self._context = typing_context
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self._context, name)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%s)' % (self.__class__.__name__, self._context)
|
||||||
|
|
||||||
|
|
||||||
|
class TypingModuleWrapper(_TypingBase):
|
||||||
|
def py__getattribute__(self, name_or_str, *args, **kwargs):
|
||||||
|
result = self._context.py__getattribute__(name_or_str)
|
||||||
|
if kwargs.get('is_goto'):
|
||||||
|
return result
|
||||||
|
name = name_or_str.value if isinstance(name_or_str, tree.Name) else name_or_str
|
||||||
|
return ContextSet.from_iterable(_remap(c, name) for c in result)
|
||||||
|
|
||||||
|
|
||||||
|
def _remap(context, name):
|
||||||
if name in _PROXY_TYPES:
|
if name in _PROXY_TYPES:
|
||||||
return TypingProxy(context)
|
return TypingProxy(name, context)
|
||||||
elif name in _TYPE_ALIAS_TYPES:
|
elif name in _TYPE_ALIAS_TYPES:
|
||||||
# TODO
|
# TODO
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@@ -45,31 +66,22 @@ def check(context, name):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class _TypingBase(object):
|
class TypingProxy(_TypingBase):
|
||||||
def __init__(self, typing_context):
|
py__simple_getitem__ = None
|
||||||
self._class_context = typing_context
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self._class_context, name)
|
|
||||||
|
|
||||||
|
|
||||||
class TypingProxy(object):
|
|
||||||
def py__getitem__(self, index_context, contextualized_node):
|
def py__getitem__(self, index_context, contextualized_node):
|
||||||
return TypingProxyWithIndex(self._class_context, index_context)
|
return ContextSet(TypingProxyWithIndex(self._name, self._context, index_context))
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return '%s(%s)' % (self.__class__.__name__, self._class_context)
|
|
||||||
|
|
||||||
|
|
||||||
class _WithIndexBase(_TypingBase):
|
class _WithIndexBase(_TypingBase):
|
||||||
def __init__(self, class_context, index_context):
|
def __init__(self, name, class_context, index_context):
|
||||||
super(_WithIndexBase, self).__init__(class_context)
|
super(_WithIndexBase, self).__init__(name, class_context)
|
||||||
self._index_context = index_context
|
self._index_context = index_context
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s(%s, %s)' % (
|
return '%s(%s, %s)' % (
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
self._class_context,
|
self._context,
|
||||||
self._index_context
|
self._index_context
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -80,12 +92,8 @@ class _WithIndexBase(_TypingBase):
|
|||||||
|
|
||||||
|
|
||||||
class TypingProxyWithIndex(_WithIndexBase):
|
class TypingProxyWithIndex(_WithIndexBase):
|
||||||
def __init__(self, typing_context, index_context):
|
|
||||||
self._class_context = typing_context
|
|
||||||
self._index_context = index_context
|
|
||||||
|
|
||||||
def execute_annotation(self):
|
def execute_annotation(self):
|
||||||
name = self._class_context.py__name__()
|
name = self._name
|
||||||
if name == 'Union':
|
if name == 'Union':
|
||||||
# This is kind of a special case, because we have Unions (in Jedi
|
# This is kind of a special case, because we have Unions (in Jedi
|
||||||
# ContextSets).
|
# ContextSets).
|
||||||
@@ -93,17 +101,17 @@ class TypingProxyWithIndex(_WithIndexBase):
|
|||||||
elif name == 'Optional':
|
elif name == 'Optional':
|
||||||
# Optional is basically just saying it's either None or the actual
|
# Optional is basically just saying it's either None or the actual
|
||||||
# type.
|
# type.
|
||||||
return ContextSet(self._class_context) \
|
return ContextSet(self._context) \
|
||||||
| ContextSet(builtin_from_name(self.evaluator, u'None'))
|
| ContextSet(builtin_from_name(self.evaluator, u'None'))
|
||||||
elif name == 'Type':
|
elif name == 'Type':
|
||||||
# The type is actually already given in the index_context
|
# The type is actually already given in the index_context
|
||||||
return ContextSet(self._index_context)
|
return ContextSet(self._index_context)
|
||||||
elif name == 'ClassVar':
|
elif name == 'ClassVar':
|
||||||
# For now don't do anything here, ClassVars are always used.
|
# For now don't do anything here, ClassVars are always used.
|
||||||
return self._class_context.execute_annotation()
|
return self._context.execute_annotation()
|
||||||
|
|
||||||
cls = globals()[name]
|
cls = globals()[name]
|
||||||
return cls(self._class_context, self._index_context)
|
return ContextSet(cls(name, self._context, self._index_context))
|
||||||
|
|
||||||
|
|
||||||
def _iter_over_arguments(maybe_tuple_context):
|
def _iter_over_arguments(maybe_tuple_context):
|
||||||
@@ -146,14 +154,14 @@ class Tuple(_ContainerBase):
|
|||||||
return self._get_getitem_contexts(0)
|
return self._get_getitem_contexts(0)
|
||||||
else:
|
else:
|
||||||
if isinstance(index, int):
|
if isinstance(index, int):
|
||||||
return self._get_getitem_contexts(index)
|
return self._get_getitem_contexts(index).execute_annotation()
|
||||||
|
|
||||||
debug.dbg('The getitem is')
|
debug.dbg('The getitem type on Tuple was %s' % index)
|
||||||
return NO_CONTEXTS
|
return NO_CONTEXTS
|
||||||
|
|
||||||
def py__getitem__(self):
|
def py__getitem__(self):
|
||||||
if self._is_homogenous():
|
if self._is_homogenous():
|
||||||
return self._get_getitem_contexts(0)
|
return self._get_getitem_contexts(0).execute_annotation()
|
||||||
|
|
||||||
return self._execute_annotations_for_all_indexes()
|
return self._execute_annotations_for_all_indexes()
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ from textwrap import dedent
|
|||||||
from parso import parse, ParserSyntaxError
|
from parso import parse, ParserSyntaxError
|
||||||
|
|
||||||
from jedi._compatibility import u
|
from jedi._compatibility import u
|
||||||
|
from jedi import debug
|
||||||
from jedi.evaluate.utils import indent_block
|
from jedi.evaluate.utils import indent_block
|
||||||
from jedi.evaluate.cache import evaluator_method_cache
|
from jedi.evaluate.cache import evaluator_method_cache
|
||||||
from jedi.evaluate.helpers import execute_evaluated
|
|
||||||
from jedi.evaluate.base_context import iterator_to_context_set, ContextSet, \
|
from jedi.evaluate.base_context import iterator_to_context_set, ContextSet, \
|
||||||
NO_CONTEXTS
|
NO_CONTEXTS
|
||||||
from jedi.evaluate.lazy_context import LazyKnownContexts
|
from jedi.evaluate.lazy_context import LazyKnownContexts
|
||||||
@@ -203,6 +203,7 @@ def _evaluate_for_statement_string(module_context, string):
|
|||||||
# Take the default grammar here, if we load the Python 2.7 grammar here, it
|
# Take the default grammar here, if we load the Python 2.7 grammar here, it
|
||||||
# will be impossible to use `...` (Ellipsis) as a token. Docstring types
|
# will be impossible to use `...` (Ellipsis) as a token. Docstring types
|
||||||
# don't need to conform with the current grammar.
|
# don't need to conform with the current grammar.
|
||||||
|
debug.dbg('Parse docstring code %s', string, color='BLUE')
|
||||||
grammar = module_context.evaluator.latest_grammar
|
grammar = module_context.evaluator.latest_grammar
|
||||||
try:
|
try:
|
||||||
module = grammar.parse(code.format(indent_block(string)), error_recovery=False)
|
module = grammar.parse(code.format(indent_block(string)), error_recovery=False)
|
||||||
@@ -262,7 +263,7 @@ def _execute_array_values(evaluator, array):
|
|||||||
values.append(LazyKnownContexts(objects))
|
values.append(LazyKnownContexts(objects))
|
||||||
return {FakeSequence(evaluator, array.array_type, values)}
|
return {FakeSequence(evaluator, array.array_type, values)}
|
||||||
else:
|
else:
|
||||||
return execute_evaluated(array)
|
return array.execute_annotation()
|
||||||
|
|
||||||
|
|
||||||
@evaluator_method_cache()
|
@evaluator_method_cache()
|
||||||
@@ -288,6 +289,7 @@ def infer_param(execution_context, param):
|
|||||||
class_context = execution_context.var_args.instance.class_context
|
class_context = execution_context.var_args.instance.class_context
|
||||||
types |= eval_docstring(class_context.py__doc__())
|
types |= eval_docstring(class_context.py__doc__())
|
||||||
|
|
||||||
|
debug.dbg('Found param types for docstring %s', types, color='BLUE')
|
||||||
return types
|
return types
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ def eval_trailer(context, base_contexts, trailer):
|
|||||||
# https://github.com/davidhalter/jedi/issues/663
|
# https://github.com/davidhalter/jedi/issues/663
|
||||||
result = ContextSet()
|
result = ContextSet()
|
||||||
for typ in list(foo):
|
for typ in list(foo):
|
||||||
|
continue
|
||||||
if isinstance(typ, (ClassContext, TreeInstance)):
|
if isinstance(typ, (ClassContext, TreeInstance)):
|
||||||
typing_module_types = pep0484.py__simple_getitem__(context, typ, node)
|
typing_module_types = pep0484.py__simple_getitem__(context, typ, node)
|
||||||
if typing_module_types is not None:
|
if typing_module_types is not None:
|
||||||
@@ -678,7 +679,7 @@ def eval_subscript_list(evaluator, context, index):
|
|||||||
|
|
||||||
return ContextSet(iterable.Slice(context, *result))
|
return ContextSet(iterable.Slice(context, *result))
|
||||||
elif index.type == 'subscriptlist':
|
elif index.type == 'subscriptlist':
|
||||||
return NO_CONTEXTS
|
return ContextSet(iterable.SequenceLiteralContext(evaluator, context, index))
|
||||||
|
|
||||||
# No slices
|
# No slices
|
||||||
return context.eval_node(index)
|
return context.eval_node(index)
|
||||||
|
|||||||
@@ -35,5 +35,5 @@ class _PluginCallbacks(object):
|
|||||||
plugin_manager = _PluginManager([
|
plugin_manager = _PluginManager([
|
||||||
StdlibPlugin,
|
StdlibPlugin,
|
||||||
FlaskPlugin,
|
FlaskPlugin,
|
||||||
#TypeshedPlugin,
|
TypeshedPlugin,
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from jedi.evaluate.base_context import ContextSet, iterator_to_context_set
|
|||||||
from jedi.evaluate.filters import AbstractTreeName, ParserTreeFilter, \
|
from jedi.evaluate.filters import AbstractTreeName, ParserTreeFilter, \
|
||||||
TreeNameDefinition
|
TreeNameDefinition
|
||||||
from jedi.evaluate.context import ModuleContext, FunctionContext, ClassContext
|
from jedi.evaluate.context import ModuleContext, FunctionContext, ClassContext
|
||||||
|
from jedi.evaluate.context.typing import TypingModuleWrapper
|
||||||
from jedi.evaluate.compiled import CompiledObject
|
from jedi.evaluate.compiled import CompiledObject
|
||||||
from jedi.evaluate.syntax_tree import tree_name_to_contexts
|
from jedi.evaluate.syntax_tree import tree_name_to_contexts
|
||||||
from jedi.evaluate.utils import to_list
|
from jedi.evaluate.utils import to_list
|
||||||
@@ -133,7 +134,7 @@ class TypeshedPlugin(BasePlugin):
|
|||||||
)
|
)
|
||||||
import_name = import_names[-1]
|
import_name = import_names[-1]
|
||||||
map_ = None
|
map_ = None
|
||||||
if len(import_names) == 1 and import_name != 'typing':
|
if len(import_names) == 1:
|
||||||
map_ = self._cache_stub_file_map(evaluator.grammar.version_info)
|
map_ = self._cache_stub_file_map(evaluator.grammar.version_info)
|
||||||
elif isinstance(parent_module_context, StubModuleContext):
|
elif isinstance(parent_module_context, StubModuleContext):
|
||||||
map_ = _merge_create_stub_map(parent_module_context.py__path__())
|
map_ = _merge_create_stub_map(parent_module_context.py__path__())
|
||||||
@@ -152,9 +153,10 @@ class TypeshedPlugin(BasePlugin):
|
|||||||
stub_module_context = StubOnlyModuleContext(
|
stub_module_context = StubOnlyModuleContext(
|
||||||
context_set, evaluator, stub_module_node, path, code_lines=[]
|
context_set, evaluator, stub_module_node, path, code_lines=[]
|
||||||
)
|
)
|
||||||
return ContextSet.from_iterable(
|
modules = _merge_modules(context_set, stub_module_context)
|
||||||
_merge_modules(context_set, stub_module_context)
|
if import_names == ('typing',):
|
||||||
)
|
modules = [TypingModuleWrapper('typing', m) for m in modules]
|
||||||
|
return ContextSet.from_iterable(modules)
|
||||||
# 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
|
||||||
|
|||||||
Reference in New Issue
Block a user