From 5ca69458d4d3c88f8d01cccc7bad33e916f09de7 Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sun, 22 Mar 2020 14:58:18 +0000 Subject: [PATCH] Add testing for mismatch cases This should help catch any errors in our handling of invalid cases. While some of these produce outputs which aren't correct, what we're checking here is that we don't _error_ while producing that output. Also fix a case which this showed up. --- jedi/inference/gradual/annotation.py | 5 + test/completion/pep0484_generic_mismatches.py | 320 ++++++++++++++++++ test/test_api/test_api.py | 1 + 3 files changed, 326 insertions(+) create mode 100644 test/completion/pep0484_generic_mismatches.py diff --git a/jedi/inference/gradual/annotation.py b/jedi/inference/gradual/annotation.py index 79481a45..0d5effbd 100644 --- a/jedi/inference/gradual/annotation.py +++ b/jedi/inference/gradual/annotation.py @@ -494,6 +494,11 @@ def _infer_type_vars(annotation_value, value_set, is_class_value=False): # the elements from the set first, then handle them, even if we put # them back in a set afterwards. for element in value_set: + if element.api_type == u'function': + # Functions & methods don't have an MRO and we're not + # expecting a Callable (those are handled separately above). + continue + if element.is_instance(): py_class = element.get_annotated_class_object() else: diff --git a/test/completion/pep0484_generic_mismatches.py b/test/completion/pep0484_generic_mismatches.py new file mode 100644 index 00000000..bd7d393a --- /dev/null +++ b/test/completion/pep0484_generic_mismatches.py @@ -0,0 +1,320 @@ +# python >= 3.4 +from typing import ( + Callable, + Dict, + Generic, + List, + Sequence, + Tuple, + Type, + TypeVar, +) + +T = TypeVar('T') + + +def foo(x: T) -> T: + return x + + +class CustomGeneric(Generic[T]): + def __init__(self, val: T) -> None: + self.val = val + + +class PlainClass(object): + pass + + +tpl = ("1", 2) +tpl_typed = ("2", 3) # type: Tuple[str, int] + +collection = {"a": 1} +collection_typed = {"a": 1} # type: Dict[str, int] + +list_of_funcs = [foo] # type: List[Callable[[T], T]] + +custom_generic = CustomGeneric(123.45) + +plain_instance = PlainClass() + + +# 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("abc")[0] +#? +x0 + +x1 = list_t_to_list_t(foo)[0] +#? +x1 + +x2 = list_t_to_list_t(tpl)[0] +#? +x2 + +x3 = list_t_to_list_t(tpl_typed)[0] +#? +x3 + +x4 = list_t_to_list_t(collection)[0] +#? +x4 + +x5 = list_t_to_list_t(collection_typed)[0] +#? +x5 + +x6 = list_t_to_list_t(custom_generic)[0] +#? +x6 + +x7 = list_t_to_list_t(plain_instance)[0] +#? +x7 + +for a in list_t_to_list_t(12): + #? + a + + +# Test that simple parameters are handled +def list_type_t_to_list_t(the_list: List[Type[T]]) -> List[T]: + return [x() for x in the_list] + +x0 = list_type_t_to_list_t("abc")[0] +#? +x0 + +x1 = list_type_t_to_list_t(foo)[0] +#? +x1 + +x2 = list_type_t_to_list_t(tpl)[0] +#? +x2 + +x3 = list_type_t_to_list_t(tpl_typed)[0] +#? +x3 + +x4 = list_type_t_to_list_t(collection)[0] +#? +x4 + +x5 = list_type_t_to_list_t(collection_typed)[0] +#? +x5 + +x6 = list_type_t_to_list_t(custom_generic)[0] +#? +x6 + +x7 = list_type_t_to_list_t(plain_instance)[0] +#? +x7 + +for a in list_type_t_to_list_t(12): + #? + a + + +x0 = list_type_t_to_list_t(["abc"])[0] +#? +x0 + +x1 = list_type_t_to_list_t([foo])[0] +#? +x1 + +x2 = list_type_t_to_list_t([tpl])[0] +#? +x2 + +x3 = list_type_t_to_list_t([tpl_typed])[0] +#? +x3 + +x4 = list_type_t_to_list_t([collection])[0] +#? +x4 + +x5 = list_type_t_to_list_t([collection_typed])[0] +#? +x5 + +x6 = list_type_t_to_list_t([custom_generic])[0] +#? +x6 + +x7 = list_type_t_to_list_t([plain_instance])[0] +#? +x7 + +for a in list_type_t_to_list_t([12]): + #? + a + + +def list_func_t_to_list_t(the_list: List[Callable[[T], T]]) -> List[T]: + # Not actually a viable signature, but should be enough to test our handling + # of the generic parameters. + pass + + +x0 = list_func_t_to_list_t("abc")[0] +#? +x0 + +x1 = list_func_t_to_list_t(foo)[0] +#? +x1 + +x2 = list_func_t_to_list_t(tpl)[0] +#? +x2 + +x3 = list_func_t_to_list_t(tpl_typed)[0] +#? +x3 + +x4 = list_func_t_to_list_t(collection)[0] +#? +x4 + +x5 = list_func_t_to_list_t(collection_typed)[0] +#? +x5 + +x6 = list_func_t_to_list_t(custom_generic)[0] +#? +x6 + +x7 = list_func_t_to_list_t(plain_instance)[0] +#? +x7 + +for a in list_func_t_to_list_t(12): + #? + a + + +# The following are all actually wrong, however we're mainly testing here that +# we don't error when processing invalid values, rather than that we get the +# right output. + +x0 = list_func_t_to_list_t(["abc"])[0] +#? str() +x0 + +x2 = list_func_t_to_list_t([tpl])[0] +#? tuple() +x2 + +x3 = list_func_t_to_list_t([tpl_typed])[0] +#? tuple() +x3 + +x4 = list_func_t_to_list_t([collection])[0] +#? dict() +x4 + +x5 = list_func_t_to_list_t([collection_typed])[0] +#? dict() +x5 + +x6 = list_func_t_to_list_t([custom_generic])[0] +#? CustomGeneric() +x6 + +x7 = list_func_t_to_list_t([plain_instance])[0] +#? PlainClass() +x7 + +for a in list_func_t_to_list_t([12]): + #? int() + a + + +def tuple_t(tuple_in: Tuple[T]]) -> Sequence[T]: + return tuple_in + + +x0 = list_t_to_list_t("abc")[0] +#? +x0 + +x1 = list_t_to_list_t(foo)[0] +#? +x1 + +x2 = list_t_to_list_t(tpl)[0] +#? +x2 + +x3 = list_t_to_list_t(tpl_typed)[0] +#? +x3 + +x4 = list_t_to_list_t(collection)[0] +#? +x4 + +x5 = list_t_to_list_t(collection_typed)[0] +#? +x5 + +x6 = list_t_to_list_t(custom_generic)[0] +#? +x6 + +x7 = list_t_to_list_t(plain_instance)[0] +#? +x7 + +for a in list_t_to_list_t(12): + #? + a + + +def tuple_t_elipsis(tuple_in: Tuple[T, ...]]) -> Sequence[T]: + return tuple_in + + +x0 = list_t_to_list_t("abc")[0] +#? +x0 + +x1 = list_t_to_list_t(foo)[0] +#? +x1 + +x2 = list_t_to_list_t(tpl)[0] +#? +x2 + +x3 = list_t_to_list_t(tpl_typed)[0] +#? +x3 + +x4 = list_t_to_list_t(collection)[0] +#? +x4 + +x5 = list_t_to_list_t(collection_typed)[0] +#? +x5 + +x6 = list_t_to_list_t(custom_generic)[0] +#? +x6 + +x7 = list_t_to_list_t(plain_instance)[0] +#? +x7 + +for a in list_t_to_list_t(12): + #? + a diff --git a/test/test_api/test_api.py b/test/test_api/test_api.py index a7337cfe..f8dab6e6 100644 --- a/test/test_api/test_api.py +++ b/test/test_api/test_api.py @@ -342,6 +342,7 @@ def test_file_fuzzy_completion(Script): script = Script('"{}/ep08_i'.format(path)) expected = [ 'pep0484_basic.py"', + 'pep0484_generic_mismatches.py"', 'pep0484_generic_parameters.py"', 'pep0484_generic_passthroughs.py"', 'pep0484_typing.py"',