1
0
forked from VimPlug/jedi

first try at the typing library

This commit is contained in:
Claude
2015-12-29 00:03:08 +01:00
parent beeffd2dcd
commit f5a31ad78e
4 changed files with 95 additions and 4 deletions

View File

@@ -29,6 +29,7 @@ from jedi.evaluate import compiled
from jedi.evaluate import helpers
from jedi.evaluate.cache import CachedMetaClass, memoize_default
from jedi.evaluate import analysis
from jedi.evaluate import pep0484
class IterableWrapper(tree.Base):
@@ -560,12 +561,23 @@ def py__iter__types(evaluator, types, node=None):
def py__getitem__(evaluator, types, index, node):
from jedi.evaluate.representation import Class
result = set()
# Index handling.
if isinstance(index, (compiled.CompiledObject, Slice)):
index = index.obj
# special case: PEP0484 typing module, see
# https://github.com/davidhalter/jedi/issues/663
for typ in list(types):
if isinstance(typ, Class):
replacementclass = \
pep0484.get_typing_replacement_class(evaluator, typ)
if replacementclass:
types.remove(typ)
result |= replacementclass.py__getitem__(index)
if type(index) not in (float, int, str, unicode, slice):
# If the index is not clearly defined, we have to get all the
# possiblities.
@@ -588,7 +600,7 @@ def py__getitem__(evaluator, types, index, node):
except IndexError:
result |= py__iter__types(evaluator, set([typ]))
except KeyError:
# Must be a dict. Lists don't raise IndexErrors.
# Must be a dict. Lists don't raise KeyErrors.
result |= typ.dict_values()
return result

View File

@@ -20,9 +20,10 @@ x support for type hint comments `# type: (int, str) -> int`. See comment from
from itertools import chain
from jedi.parser import Parser, load_grammar, ParseError
from jedi.parser import Parser, load_grammar, ParseError, tree, ParserWithRecovery
from jedi.evaluate.cache import memoize_default
from jedi.evaluate.compiled import CompiledObject
from jedi.evaluate import compiled
from textwrap import dedent
from jedi import debug
@@ -30,7 +31,7 @@ def _evaluate_for_annotation(evaluator, annotation):
if annotation is not None:
definitions = set()
for definition in evaluator.eval_element(annotation):
if (isinstance(definition, CompiledObject) and
if (isinstance(definition, compiled.CompiledObject) and
isinstance(definition.obj, str)):
try:
p = Parser(load_grammar(), definition.obj, start='eval_input')
@@ -60,3 +61,40 @@ def follow_param(evaluator, param):
def find_return_types(evaluator, func):
annotation = func.py__annotations__().get("return", None)
return _evaluate_for_annotation(evaluator, annotation)
# TODO: Memoize
def get_typing_replacement_module():
"""
The idea is to return our jedi replacement for the PEP-0484 typing module
as discussed at https://github.com/davidhalter/jedi/issues/663
"""
code = dedent("""
from collections import abc
class MakeSequence:
def __getitem__(self, indextype):
class Sequence(abc.Sequence):
def __getitem__(self) -> indextype:
pass
return Sequence
""")
p = ParserWithRecovery(load_grammar(), code)
return p.module
def get_typing_replacement_class(evaluator, typ):
if not typ.base.get_parent_until(tree.Module).name.value == "typing":
return None
# we assume that any class using [] in a module called
# "typing" with a name for which we have a replacement
# should be replaced by that class. This is not 100%
# airtight but I don't have a better idea to check that it's
# actually the PEP-0484 typing module and not some other
typing = get_typing_replacement_module()
types = evaluator.find_types(typing, "Make" + typ.name.value)
if not types:
return None
else:
return list(types)[0]

View File

@@ -469,6 +469,24 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
def py__class__(self):
return compiled.create(self._evaluator, type)
def py__getitem__(self, index):
instances = self.py__call__(())
assert len(instances) == 1
instance = list(instances)[0]
try:
method = instance.get_subscope_by_name('__getitem__')
except KeyError:
debug.warning('No __getitem__, cannot access the array.')
return set()
else:
# it feels like this should be handled somewhere else,
# not sure where though
if isinstance(index, type(self)):
index_obj = index
else:
index_obj = compiled.create(self._evaluator, index)
return instance._evaluator.execute_evaluated(method, index_obj)
@property
def params(self):
return self.get_subscope_by_name('__init__').params

View File

@@ -157,3 +157,26 @@ Y = int
def just_because_we_can(x: "flo" + "at"):
#? float()
x
import typing
def we_can_has_sequence(
p: typing.Sequence[int],
q: typing.Sequence[B],
r: "typing.Sequence[int]",
s: typing.Sequence["int"]):
#? ["count"]
p.c
#? int()
p[1]
#? ["count"]
q.c
#? B()
q[1]
#? ["count"]
r.c
#? int()
r[1]
#? ["count"]
s.c
#? int()
s[1]