From 7b9731250975a2b5e2dbf2b11473309091028d0f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 31 Dec 2015 01:29:03 +0100 Subject: [PATCH] tuples and mappings in typing --- jedi/evaluate/iterable.py | 11 ++-- jedi/evaluate/jedi_typing.py | 49 ++++++++++++++++-- jedi/evaluate/pep0484.py | 43 ++++++++++++---- test/completion/pep0484_typing.py | 85 +++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 21 deletions(-) diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index 957f9784..f92d1a97 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -564,13 +564,16 @@ def py__getitem__(evaluator, types, trailer): from jedi.evaluate.representation import Class result = set() + trailer_op, node, trailer_cl = trailer.children + assert trailer_op == "[" + assert trailer_cl == "]" # special case: PEP0484 typing module, see # https://github.com/davidhalter/jedi/issues/663 for typ in list(types): if isinstance(typ, Class): typing_module_types = \ - pep0484.get_types_for_typing_module(evaluator, typ, trailer) + pep0484.get_types_for_typing_module(evaluator, typ, node) if typing_module_types is not None: types.remove(typ) result |= typing_module_types @@ -579,12 +582,6 @@ def py__getitem__(evaluator, types, trailer): # all consumed by special cases return result - trailer_op, node, trailer_cl = trailer.children[:3] - assert trailer_op == "[" - if trailer_cl != "]": - debug.warning("No support for complex indices: %s" % trailer) - return result - for index in create_index_types(evaluator, node): if isinstance(index, (compiled.CompiledObject, Slice)): index = index.obj diff --git a/jedi/evaluate/jedi_typing.py b/jedi/evaluate/jedi_typing.py index 2c547482..62f52fd4 100644 --- a/jedi/evaluate/jedi_typing.py +++ b/jedi/evaluate/jedi_typing.py @@ -10,10 +10,10 @@ except ImportError: import collections as abc -def factory(typing_name, indextype): +def factory(typing_name, indextypes): class Iterable(abc.Iterable): def __iter__(self): - yield indextype() + yield indextypes[0]() class Iterator(Iterable, abc.Iterator): def next(self): @@ -21,11 +21,11 @@ def factory(typing_name, indextype): return self.__next__() def __next__(self): - return indextype() + return indextypes[0]() class Sequence(Iterable, abc.Sequence): def __getitem__(self, index): - return indextype() + return indextypes[0]() class MutableSequence(Sequence, abc.MutableSequence): pass @@ -33,12 +33,46 @@ def factory(typing_name, indextype): class List(MutableSequence, list): pass + class Tuple(Sequence, tuple): + def __getitem__(self, index): + return indextypes[index]() + class AbstractSet(Iterable, abc.Set): pass class MutableSet(AbstractSet, abc.MutableSet): pass + class KeysView(Iterable, abc.KeysView): + pass + + class ValuesView(abc.ValuesView): + def __iter__(self): + yield indextypes[1]() + + class ItemsView(abc.ItemsView): + def __iter__(self): + yield Tuple() + + class Mapping(Iterable, abc.Mapping): + def __getitem__(self, item): + return indextypes[1]() + + def keys(self): + return KeysView() + + def values(self): + return ValuesView() + + def items(self): + return ItemsView() + + class MutableMapping(Mapping, abc.MutableMapping): + pass + + class Dict(MutableMapping, dict): + pass + dct = { "Sequence": Sequence, "MutableSequence": MutableSequence, @@ -47,5 +81,12 @@ def factory(typing_name, indextype): "Iterator": Iterator, "AbstractSet": AbstractSet, "MutableSet": MutableSet, + "Mapping": Mapping, + "MutableMapping": MutableMapping, + "Tuple": Tuple, + "KeysView": KeysView, + "ItemsView": ItemsView, + "ValuesView": ValuesView, + "Dict": Dict, } return dct[typing_name] diff --git a/jedi/evaluate/pep0484.py b/jedi/evaluate/pep0484.py index db80dd79..422ca85f 100644 --- a/jedi/evaluate/pep0484.py +++ b/jedi/evaluate/pep0484.py @@ -18,7 +18,7 @@ x support for type hint comments `# type: (int, str) -> int`. See comment from Guido https://github.com/davidhalter/jedi/issues/662 """ -from itertools import chain +import itertools import os from jedi.parser import \ @@ -32,7 +32,7 @@ def _evaluate_for_annotation(evaluator, annotation): if annotation is not None: dereferenced_annotation = _fix_forward_reference(evaluator, annotation) definitions = evaluator.eval_element(dereferenced_annotation) - return list(chain.from_iterable( + return list(itertools.chain.from_iterable( evaluator.execute(d) for d in definitions)) else: return [] @@ -97,7 +97,8 @@ def _get_typing_replacement_module(): return p.module -def get_types_for_typing_module(evaluator, typ, trailer): +def get_types_for_typing_module(evaluator, typ, node): + from jedi.evaluate.iterable import FakeSequence if not typ.base.get_parent_until().name.value == "typing": return None # we assume that any class using [] in a module called @@ -105,9 +106,10 @@ def get_types_for_typing_module(evaluator, typ, trailer): # 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 - indextypes = evaluator.eval_element(trailer.children[1]) - if not isinstance(indextypes, set): - indextypes = set([indextypes]) + if tree.is_node(node, "subscriptlist"): + nodes = node.children[::2] # skip the commas + else: + nodes = [node] typing = _get_typing_replacement_module() factories = evaluator.find_types(typing, "factory") @@ -123,9 +125,30 @@ def get_types_for_typing_module(evaluator, typ, trailer): compiled_classname = compiled.create(evaluator, typ.name.value) result = set() - for indextyp in indextypes: - result |= \ - evaluator.execute_evaluated(factory, compiled_classname, indextyp) + # don't know what the last parameter is for, this seems to work :) + args = FakeSequence(evaluator, nodes, "x-type") + + result |= evaluator.execute_evaluated(factory, compiled_classname, args) + human_nodes = [] + for node in nodes: + evalled_node = evaluator.eval_element(node) + if len(evalled_node) != 1: + human_nodes.append("???") + continue + evalled_node = list(evalled_node)[0] + try: + human_nodes.append(str(evalled_node.name)) + except AttributeError: + pass + else: + continue + try: + human_nodes.append(evalled_node.obj.__name__) + except AttributeError: + pass + else: + continue + human_nodes.append("???") for singleresult in result: - singleresult.name.value += "[%s]" % indextyp.name + singleresult.name.value += "[%s]" % ", ".join(human_nodes) return result diff --git a/test/completion/pep0484_typing.py b/test/completion/pep0484_typing.py index ef5ff908..8b8ad852 100644 --- a/test/completion/pep0484_typing.py +++ b/test/completion/pep0484_typing.py @@ -69,5 +69,90 @@ def sets( #? ["add"] q.a +def tuple( + p: typing.Tuple[int], + q: typing.Tuple[int, str, float], + r: typing.Tuple[B, ...]): + #? int() + p[0] + #? int() + q[0] + #? str() + q[1] + #? float() + q[2] + #? B() + r[0] + ##? B() --- TODO fix support for arbitrary length + r[1] + #? B() + r[2] + #? B() + r[10000] + i, s, f = q + #? int() + i + ##? str() --- TODO fix support for tuple assignment + s + ##? float() --- TODO fix support for tuple assignment + f + +class Key: + pass + +class Value: + pass + +def mapping( + p: typing.Mapping[Key, Value], + q: typing.MutableMapping[Key, Value], + d: typing.Dict[Key, Value], + r: typing.KeysView[Key], + s: typing.ValuesView[Value], + t: typing.ItemsView[Key, Value]): + #? [] + p.setd + #? ["setdefault"] + q.setd + #? ["setdefault"] + d.setd + #? Value() + p[1] + for key in p: + #? Key() + key + for key in p.keys(): + #? Key() + key + for value in p.values(): + #? Value() + value + for item in p.items(): + #? Key() + item[0] + #? Value() + item[1] + (key, value) = item + #? Key() + key + ##? Value() --- TODO fix support for tuple assignment + value + for key, value in p.items(): + #? Key() + key + ##? Value() --- TODO fix support for tuple assignment + value + for key in r: + #? Key() + key + for value in s: + #? Value() + value + for key, value in t: + #? Key() + key + ##? Value() --- TODO fix support for tuple assignment + value + class ForwardReference: pass