diff --git a/test/completion/pep0484_generic_parameters.py b/test/completion/pep0484_generic_parameters.py new file mode 100644 index 00000000..f13fafd1 --- /dev/null +++ b/test/completion/pep0484_generic_parameters.py @@ -0,0 +1,151 @@ +# python >= 3.4 +from typing import Iterable, List, Type, TypeVar, Dict, Mapping, Generic + +K = TypeVar('K') +T = TypeVar('T') +T_co = TypeVar('T_co', covariant=True) +V = TypeVar('V') + + +list_of_ints = [42] # type: List[int] + +# Test that simple parameters are handled +def list_t_to_list_t(the_list: List[T]) -> List[T]: + return the_list + +x0 = list_t_to_list_t(list_of_ints)[0] +#? int() +x0 + +for a in list_t_to_list_t(list_of_ints): + #? int() + a + + +list_of_int_type = [int] # type: List[Type[int]] + +# Test that nested parameters are handled +def list_type_t_to_list_t(the_list: List[Type[T]]) -> List[T]: + return [x() for x in the_list] + + +x1 = list_type_t_to_list_t(list_of_int_type)[0] +#? int() +x1 + + +for b in list_type_t_to_list_t(list_of_int_type): + #? int() + b + + +mapping_int_str = {42: 'a'} # type: Dict[int, str] + +# Test that mappings (that have more than one parameter) are handled +def invert_mapping(mapping: Mapping[K, V]) -> Mapping[V, K]: + return {v: k for k, v in mapping.items()} + +#? int() +invert_mapping(mapping_int_str)['a'] + + +# Test that the right type is chosen when a mapping is passed to something with +# only a single parameter. This checks that our inheritance checking picks the +# right thing. +def first(iterable: Iterable[T]) -> T: + return next(iter(iterable)) + +#? int() +first(mapping_int_str) + + +# Test that the right type is chosen when a partially realised mapping is expected +def values(mapping: Mapping[int, T]) -> List[T]: + return list(mapping.values()) + +#? str() +values(mapping_int_str)[0] + +x2 = values(mapping_int_str)[0] +#? str() +x2 + +for b in values(mapping_int_str): + #? str() + b + + +# +# Tests that user-defined generic types are handled +# +list_ints = [42] # type: List[int] + +class CustomGeneric(Generic[T_co]): + def __init__(self, val: T_co) -> None: + self.val = val + + +# Test extraction of type from a custom generic type +def custom(x: CustomGeneric[T]) -> T: + return x.val + +custom_instance = CustomGeneric(42) # type: CustomGeneric[int] + +#? int() +custom(custom_instance) + +x3 = custom(custom_instance) +#? int() +x3 + + +# Test construction of a custom generic type +def wrap_custom(iterable: Iterable[T]) -> List[CustomGeneric[T]]: + return [CustomGeneric(x) for x in iterable] + +#? int() +wrap_custom(list_ints)[0].val + +x4 = wrap_custom(list_ints)[0] +#? int() +x4.val + +for x5 in wrap_custom(list_ints): + #? int() + x5.val + + +# Test extraction of type from a nested custom generic type +list_custom_instances = [CustomGeneric(42)] # type: List[CustomGeneric[int]] + +def unwrap_custom(iterable: Iterable[CustomGeneric[T]]) -> List[T]: + return [x.val for x in iterable] + +#? int() +unwrap_custom(list_custom_instances)[0] + +x6 = unwrap_custom(list_custom_instances)[0] +#? int() +x6 + +for x7 in unwrap_custom(list_custom_instances): + #? int() + x7 + + +# Test extraction of type from type parameer nested within a custom generic type +custom_instance_list_int = CustomGeneric([42]) # type: CustomGeneric[List[int]] + +def unwrap_custom2(instance: CustomGeneric[Iterable[T]]) -> List[T]: + return list(instance.val) + +#? int() +unwrap_custom2(custom_instance_list_int)[0] + +x8 = unwrap_custom2(custom_instance_list_int)[0] +#? int() +x8 + +for x9 in unwrap_custom2(custom_instance_list_int): + #? int() + x9 diff --git a/test/completion/pep0484_generic_passthroughs.py b/test/completion/pep0484_generic_passthroughs.py new file mode 100644 index 00000000..bd13f926 --- /dev/null +++ b/test/completion/pep0484_generic_passthroughs.py @@ -0,0 +1,84 @@ +# python >= 3.4 +from typing import Any, Iterable, List, Tuple, TypeVar + +T = TypeVar('T') +TList = TypeVar('TList', bound=List[Any]) + +untyped_list_str = ['abc', 'def'] +typed_list_str = ['abc', 'def'] # type: List[str] + +untyped_tuple_str = ('abc',) +typed_tuple_str = ('abc',) # type: Tuple[str] + + +def untyped_passthrough(x): + return x + +def typed_list_generic_passthrough(x: List[T]) -> List[T]: + return x + +def typed_tuple_generic_passthrough(x: Tuple[T]) -> Tuple[T]: + return x + +def typed_iterable_generic_passthrough(x: Iterable[T]) -> Iterable[T]: + return x + +def typed_fully_generic_passthrough(x: T) -> T: + return x + +def typed_bound_generic_passthrough(x: TList) -> TList: + return x + + +for a in untyped_passthrough(untyped_list_str): + #? str() + a + +for b in untyped_passthrough(typed_list_str): + #? str() + b + + +for c in typed_list_generic_passthrough(untyped_list_str): + #? str() + c + +for d in typed_list_generic_passthrough(typed_list_str): + #? str() + d + + +for e in typed_iterable_generic_passthrough(untyped_list_str): + #? str() + e + +for f in typed_iterable_generic_passthrough(typed_list_str): + #? str() + f + + +for g in typed_tuple_generic_passthrough(untyped_tuple_str): + #? str() + g + +for h in typed_tuple_generic_passthrough(typed_tuple_str): + #? str() + h + + +for n in typed_fully_generic_passthrough(untyped_list_str): + #? str() + n + +for o in typed_fully_generic_passthrough(typed_list_str): + #? str() + o + + +for p in typed_bound_generic_passthrough(untyped_list_str): + #? str() + p + +for q in typed_bound_generic_passthrough(typed_list_str): + #? str() + q diff --git a/test/test_api/test_api.py b/test/test_api/test_api.py index 841151db..a7337cfe 100644 --- a/test/test_api/test_api.py +++ b/test/test_api/test_api.py @@ -340,8 +340,13 @@ def test_math_fuzzy_completion(Script, environment): def test_file_fuzzy_completion(Script): path = os.path.join(test_dir, 'completion') script = Script('"{}/ep08_i'.format(path)) - assert ['pep0484_basic.py"', 'pep0484_typing.py"'] \ - == [comp.name for comp in script.complete(fuzzy=True)] + expected = [ + 'pep0484_basic.py"', + 'pep0484_generic_parameters.py"', + 'pep0484_generic_passthroughs.py"', + 'pep0484_typing.py"', + ] + assert expected == [comp.name for comp in script.complete(fuzzy=True)] @pytest.mark.parametrize(