def test_subscript_del_ctx(node): """Test visitor of Subscript node within a del statement.""" del_node = astroid.Delete() del_node.postinit([node]) module, _ = cs._parse_text(del_node) for subscript_node in module.nodes_of_class(astroid.Subscript): assert subscript_node.inf_type.getValue() == type(None)
def test_subscript_slice(): program = ''' x = List[:] ''' module, _ = cs._parse_text(program) assign_node = next(module.nodes_of_class(astroid.Assign)) assert isinstance(assign_node.inf_type, TypeFail)
def test_functiondef_annotated_simple_return(functiondef_node): """Test whether type annotations are set properly for a FunctionDef node representing a function definition with type annotations.""" arg_names = [arg.name for arg in functiondef_node.args.args] assume(functiondef_node.name not in arg_names) for arg in functiondef_node.args.args: assume(arg_names.count(arg.name) == 1) module, inferer = cs._parse_text(functiondef_node) functiondef_node = next(module.nodes_of_class(astroid.FunctionDef)) # arguments and annotations are not changing, so test this once. for i in range(len(functiondef_node.args.annotations)): arg_name = functiondef_node.args.args[i].name expected_type = inferer.type_constraints.resolve(functiondef_node.type_environment.lookup_in_env(arg_name)).getValue() # need to do by name because annotations must be name nodes. if isinstance(expected_type, _GenericAlias): assert _gorg(expected_type).__name__ == functiondef_node.args.annotations[i].name else: assert expected_type.__name__ == functiondef_node.args.annotations[i].name # test return type return_node = functiondef_node.body[0].value expected_rtype = inferer.type_constraints.resolve(functiondef_node.type_environment.lookup_in_env(return_node.name)).getValue() if isinstance(expected_rtype, _GenericAlias): assert _gorg(expected_rtype).__name__ == functiondef_node.returns.name else: assert expected_rtype.__name__ == functiondef_node.returns.name
def test_invalid_annassign_and_assign(): src = """ x: List[str] = [1, 2, 3] """ module, inferer = cs._parse_text(src, reset=True) for ann_node in module.nodes_of_class(astroid.AnnAssign): assert isinstance(ann_node.inf_type, TypeFailUnify)
def test_annotation_forward_ref_space(): src = """ x: 'Some Class' """ module, inferer = cs._parse_text(src, reset=True) for ann_node in module.nodes_of_class(astroid.AnnAssign): assert isinstance(ann_node.inf_type, TypeFailAnnotationInvalid)
def test_multi_starred(): src = """ *a, b, *c = [1, 2, 3, 4, 5] """ ast_mod, ti = cs._parse_text(src, reset=True) assign_node = next(ast_mod.nodes_of_class(astroid.Assign)) assert isinstance(assign_node.inf_type, TypeFailStarred)
def test_userdefn_inheritance_multilevel(draw=False): src = """ class A: pass class B(A): pass class C(B): pass a = A() b = B() c = C() """ ast_mod, ti = cs._parse_text(src, reset=True) tc = ti.type_constraints a, b, c = [ti.lookup_typevar(node, node.name) for node in ast_mod.nodes_of_class(astroid.AssignName)] assert tc.unify(b, a).getValue() == ForwardRef('B') assert tc.unify(c, b).getValue() == ForwardRef('C') assert tc.unify(c, a).getValue() == ForwardRef('C') assert isinstance(ti.type_constraints.unify(b, c), TypeFail) if draw: gen_graph_from_nodes(tc._nodes)
def test_userdefn_mro_diamond(draw=False): src = """ class A: pass class B(A): def foo(self): return 'a' class C(A): def foo(self): return 0 class D(B,C): pass d = D() x = d.foo() # this is a call to B.foo() """ ast_mod, ti = cs._parse_text(src, reset=True) _, _, d, x = [ti.lookup_typevar(node, node.name) for node in ast_mod.nodes_of_class(astroid.AssignName)] assert ti.type_constraints.resolve(x).getValue() == str if draw: gen_graph_from_nodes(ti.type_constraints._nodes)
def test_set_name_unassigned(variable_name): """Test visitor for name nodes representing a single unassigned variable in module.""" program = variable_name module, _ = cs._parse_text(program) for name_node in module.nodes_of_class(astroid.Name): name_type_var = name_node.frame().type_environment.lookup_in_env(name_node.name) assert name_node.type_constraints.type == name_type_var
def test_set_comprehension_reproduce_homogeneous(iterable): """Test SetComp node visitor representing a comprehension expression reproducing a set of elements of a homogeneous iterable.""" program = '{elt for elt in ' + repr(iterable) + '}' module, _ = cs._parse_text(program) setcomp_node = list(module.nodes_of_class(astroid.SetComp))[0] assert setcomp_node.type_constraints.type == Set[setcomp_node.generators[0].iter.type_constraints.type.__args__[0]]
def test_homogeneous_lists(lst): """Test List nodes representing a list of values of the same primitive type.""" module, _ = cs._parse_text(lst) list_node = list(module.nodes_of_class(astroid.List))[0] if len(list_node.elts) == 0: assert list_node.type_constraints.type == List[Any] else: cs._verify_type_setting(module, astroid.List, List[type(lst.elts[0].value)])
def test_compare_is_not(): program = """ A = 0 A is not 1 """ module, _ = cs._parse_text(program) compare_node = list(module.nodes_of_class(astroid.Compare))[0] assert compare_node.inf_type.getValue() == bool
def test_compare_equality(left_value, operator_value_tuples): """Test type setting of Compare node representing comparators: ''==', '!=', '>=', '<=', 'is'. """ program = f'{repr(left_value)}' for operator, value in operator_value_tuples: program += ' ' + ' '.join([operator, repr(value)]) module, _ = cs._parse_text(program) compare_node = list(module.nodes_of_class(astroid.Compare))[0] assert compare_node.inf_type.getValue() == bool
def test_annassign_subscript_dict_int_str(): program = """ d: Dict[int, str] """ module, inferer = cs._parse_text(program) ann_node = next(module.nodes_of_class(astroid.AnnAssign)) variable_type = lookup_type(inferer, ann_node, ann_node.target.name) eq_(variable_type, Dict[int, str])
def test_multi_variable(): src = """ lst = [1, 2, 3, 4, 5] *a, b, *c = lst """ ast_mod, ti = cs._parse_text(src, reset=True) assign_node = list(ast_mod.nodes_of_class(astroid.Assign))[1] assert isinstance(assign_node.inf_type, TypeFailStarred)
def test_inference_invalid_slice(node): sub_node = astroid.Subscript() slice = astroid.Slice() slice.postinit(astroid.Const(0), astroid.Const('a')) sub_node.postinit(node, slice) module, _ = cs._parse_text(sub_node) for subscript_node in module.nodes_of_class(astroid.Subscript): assert isinstance(subscript_node.inf_type, TypeFail)
def test_tuple_subscript(): program = """ lst = ['Hello', 'Goodbye'] lst[0], lst[1] = 'Bonjour', 'Au revoir' """ module, _ = cs._parse_text(program) for assign_node in module.nodes_of_class(astroid.Assign): assert not isinstance(assign_node.inf_type, TypeFail)
def test_builtin_generic_inheritance_init(draw=False): src = """ x = set([1,2,3]) """ ast_mod, ti = cs._parse_text(src, reset=True) x = [ti.lookup_typevar(node, node.name) for node in ast_mod.nodes_of_class(astroid.AssignName)][0] assert ti.type_constraints.resolve(x).getValue() == Set[int]
def test_tuple_int_str(): src = """ l = (1, "Hello") """ ast_mod, ti = cs._parse_text(src) actual_set = tc_to_disjoint(ti.type_constraints) expected_set = [{'~_TV0', 'typing.Tuple[int, str]'}] compare_list_sets(actual_set, expected_set)
def test_list_comprehension_single_target_name_homogeneous_iterable(iterable): """Test Comprehension node visitor representing a comprehension expression with a single target and a name expression over a homogeneous list.""" program = f'[num for num in {repr(iterable)}]' module, typeinferrer = cs._parse_text(program) listcomp_node = list(module.nodes_of_class(astroid.ListComp))[0] expected_type = List[listcomp_node.generators[0].iter.type_constraints.type.__args__[0]] assert listcomp_node.type_constraints.type == expected_type
def test_list_int(): src = """ l = [1,2,3] """ ast_mod, ti = cs._parse_text(src) actual_set = tc_to_disjoint(ti.type_constraints) expected_set = [{'~_TV0', 'typing.List[int]'}, {int}] compare_list_sets(actual_set, expected_set)
def test_one_var(): src = """ a = 1 """ ast_mod, ti = cs._parse_text(src) actual_set = tc_to_disjoint(ti.type_constraints) expected_set = [{int, '~_TV0'}] compare_list_sets(actual_set, expected_set)
def test_heterogeneous_binary_boolop(node): """Test type setting of binary BoolOp node(s) representing expression with heterogeneous operands.""" raise SkipTest('Currently fails due to typechecking for inheritance. ' 'Need to figure out if this is expected behavior.') assume(type(node.values[0].value) != type(node.values[1].value)) module, _ = cs._parse_text(node) boolop_node = list(module.nodes_of_class(astroid.BoolOp))[0] assert boolop_node.inf_type.getValue() == Any
def test_annassign_subscript_set(): program = """ s: Set """ module, inferer = cs._parse_text(program) ann_node = next(module.nodes_of_class(astroid.AnnAssign)) variable_type = lookup_type(inferer, ann_node, ann_node.target.name) eq_(variable_type, Set[Any])
def test_dict_comprehension_reproduce_heterogeneous(node): """Test DictComp node visitor representing a comprehension expression reproducing the the key, value pairs of a heterogeneous Dictionary.""" dictionary = node.as_string() program = f"{{key: {dictionary}[key] for key in {dictionary}}}" module, _ = cs._parse_text(program) dictcomp_node = list(module.nodes_of_class(astroid.DictComp))[0] assert dictcomp_node.inf_type.getValue() == dictcomp_node.generators[0].iter.inf_type.getValue()
def test_binop_reverse(): src = """ x = 3 * [1,2,3] """ ast_mod, ti = cs._parse_text(src, reset=True) x = [ti.lookup_typevar(node, node.name) for node in ast_mod.nodes_of_class(astroid.AssignName)][0] assert ti.type_constraints.resolve(x).getValue() == List[int]
def test_any_list(): src = """ l = [1, "string", False] """ ast_mod, ti = cs._parse_text(src) actual_set = tc_to_disjoint(ti.type_constraints) expected_set = [{'~_TV0', 'typing.List[typing.Any]'}, {int}, {str}] compare_list_sets(actual_set, expected_set)
def test_param_annotation_not_type(): src = """ def f(x: [str, int]) -> None: return x """ module, inferer = cs._parse_text(src, reset=True) for arg_node in module.nodes_of_class(astroid.Arguments): assert isinstance(arg_node.inf_type, TypeFailAnnotationInvalid)
def test_annassign_subscript_tuple_int(): program = """ t: Tuple[int, int] """ module, inferer = cs._parse_text(program) ann_node = next(module.nodes_of_class(astroid.AnnAssign)) variable_type = lookup_type(inferer, ann_node, ann_node.target.name) eq_(variable_type, Tuple[int, int])
def test_non_callable(): program = ''' x = 1 x() ''' module, inferer = cs._parse_text(program) call_node = next(module.nodes_of_class(astroid.Call)) assert isinstance(call_node.inf_type, TypeFailFunction)
def test_var_assign(): src = """ A = 1 A = 'One' """ ast_mod, ti = cs._parse_text(src, reset=True) tf = find_type_fail(ast_mod).inf_type verify_typefail_unify(tf, 'A', str, exp_src_type=astroid.Assign, num_reasons=1)
def test_binop_autoconvert(): program = """ x = 1 + 1.0 y = 1 + 1j z = 1.0 + 1j """ module, inferer = cs._parse_text(program, reset=True) x, y, z = [inferer.lookup_typevar(node, node.name) for node in module.nodes_of_class(astroid.AssignName)] assert inferer.type_constraints.resolve(x).getValue() == float assert inferer.type_constraints.resolve(y).getValue() == complex assert inferer.type_constraints.resolve(z).getValue() == complex
def test_binop_non_bool_concrete(node): """Test type setting of BinOp node(s) with non-boolean operands.""" module, inferer = cs._parse_text(node) binop_node = list(module.nodes_of_class(astroid.BinOp))[0] left_type, right_type = binop_node.left.inf_type.getValue(), binop_node.right.inf_type.getValue() exp_func_type = inferer.type_store.lookup_method(BINOP_TO_METHOD[node.op], left_type, right_type, node=binop_node) if not isinstance(exp_func_type, TypeFailFunction): exp_return_type = exp_func_type.__args__[-1] else: exp_return_type = None assume(exp_return_type is not None) assert binop_node.inf_type.getValue() == exp_return_type
def test_function_return_3(): program = """ def foo(x, y): return y foo(1,2) """ module, inferer = cs._parse_text(program) call_node = next(module.nodes_of_class(astroid.Call)) func_type = call_node.func.inf_type.getValue() t1, t2, t3 = func_type.__args__ eq_(t2, t3)
def test_functiondef_staticmethod(): program = \ ''' class A: @staticmethod def method(x): return x + 1 ''' module, inferer = cs._parse_text(program) for func_def in module.nodes_of_class(astroid.FunctionDef): assert lookup_type(inferer, func_def, func_def.argnames()[0]) == int
def test_var_chain(): src = """ a = 1 b = a c = b d = c e = d """ ast_mod, ti = cs._parse_text(src) actual_set = tc_to_disjoint(ti.type_constraints) expected_set = [{int, '~_T0', '~_T1', '~_T2', '~_T3', '~_T4'}] compare_list_sets(actual_set, expected_set)
def test_attribute_self_bind(): """Make sure auto-binding of self persists""" program = \ ''' x = [] f = x.append f(4) ''' module, ti = cs._parse_text(program, reset=True) x = [ti.lookup_typevar(node, node.name) for node in module.nodes_of_class(astroid.AssignName)][0] assert str(ti.type_constraints.resolve(x).getValue()) == "typing.List[int]"
def test_class_without_init(): program = """ class Foo: def fee(self): return 1 foo = Foo() """ ast_mod, ti = cs._parse_text(program) for call_node in ast_mod.nodes_of_class(astroid.Call): assert isinstance(call_node.inf_type.getValue(), ForwardRef) eq_(call_node.inf_type.getValue(), ForwardRef('Foo'))
def test_one_list(): src = """ L1 = [1, 2, 3] L1 = "Hello" """ ast_mod, ti = cs._parse_text(src, reset=True) tf = find_type_fail(ast_mod).inf_type verify_typefail_unify(tf, 'L1', str, exp_src_type=astroid.Assign, num_reasons=1)
def test_annassign_and_assign(): src = """ x: List[int] = [1, 2, 3] """ module, inferer = cs._parse_text(src, reset=True) x = [ inferer.lookup_typevar(node, node.name) for node in module.nodes_of_class(astroid.AssignName) ][0] for ann_node in module.nodes_of_class(astroid.AnnAssign): assert ann_node.inf_type == NoType() assert inferer.type_constraints.resolve(x).getValue() == List[int]
def test_augassign_subscript_target(): program = """ x = ['a', 'b', 'c'] x[0] += 'd' y = x[0] """ module, inferer = cs._parse_text(program, reset=True) x, y = [ inferer.lookup_typevar(node, node.name) for node in module.nodes_of_class(astroid.AssignName) ] assert inferer.type_constraints.resolve(y).getValue() == str
def test_class_defined_later(): program = """ class A: def __init__(self): self.attr = B() class B: pass """ ast_mod, ti = cs._parse_text(program, True) for call_node in ast_mod.nodes_of_class(astroid.Call): assert not isinstance(call_node.inf_type, TypeFail)
def test_for_list_tuple(): program = """ some_list = [('A', 1), ('B', 2)] for elt in some_list: x = elt """ module, ti = cs._parse_text(program) for assign_node in module.nodes_of_class(astroid.AssignName): if assign_node.name == 'x' or assign_node.name == 'elt': eq_(lookup_type(ti, assign_node, assign_node.name), Tuple[str, int])
def test_binop_non_bool_concrete(left_operand, operator, right_operand): """Test type setting of BinOp node(s) with non-boolean operands.""" try: exp_func_type = TYPE_STORE.lookup_function(op_to_dunder(operator), type(left_operand), type(right_operand)) exp_return_type = exp_func_type.__args__[-1] except KeyError: exp_return_type = None assume(exp_return_type is not None) program = f'{repr(left_operand)} {operator} {repr(right_operand)}\n' module = cs._parse_text(program) binop_node = list(module.nodes_of_class(astroid.BinOp))[0] assert binop_node.type_constraints.type == exp_return_type
def test_for_homogeneous_list(iterable): """Test whether visitors properly set the type constraint of the a For node representing for/else statement iterating over a homogeneous list. """ program = f'for elt in {iterable}:\n' \ f' x = elt\n' module, TypeInferrer = cs._parse_text(program) for_node = list(module.nodes_of_class(astroid.For))[0] local_type_var = module.type_environment.lookup_in_env('x') inferred_type = TypeInferrer.type_constraints.resolve( local_type_var).getValue() assert inferred_type == for_node.iter.inf_type.getValue().__args__[0]
def test_multi_var(): src = """ a = 1 b = "Hello" c = False d = 4.0 """ ast_mod, ti = cs._parse_text(src) actual_set = tc_to_disjoint(ti.type_constraints) expected_set = [{int, '~_T0'}, {'~_T1', str}, {'~_T2', bool}, {'~_T3', float}] compare_list_sets(actual_set, expected_set)
def test_bad_attribute_access(): """ User tries to access a non-existing attribute; or misspells the attribute name. """ program = f'x = 1\n' \ f'x.wrong_name\n' try: module, inferer = cs._parse_text(program) except: raise SkipTest() expr_node = next(module.nodes_of_class(astroid.Expr)) expected_msg = 'Attribute wrong_name not found for type int' assert expr_node.inf_type.getValue() == expected_msg
def test_instance_dot_method(): program = \ ''' class A: def foo(self, x): return x + 1 A().foo(0) ''' module, _ = cs._parse_text(program, reset=True) for attribute_node in module.nodes_of_class(astroid.Attribute): assert str(attribute_node.inf_type.getValue()) == "typing.Callable[[int], int]"
def test_compare_inequality(operators, values): """Test type setting of Compare node representing comparators: '<', '>'. """ a = list(zip(operators, values)) pre = [] for operator, value in a: pre.append(str(operator)) pre.append(str(value)) # pre_input_program = [str(elt) for tuple in zip(operator, values) for elt in tuple] program = f'{str(values[0])} ' + ' '.join(pre) module, _ = cs._parse_text(program) compare_node = list(module.nodes_of_class(astroid.Compare))[0] assert compare_node.inf_type.getValue() == bool
def test_builtin_comp_inheritance(draw=False): src = """ x = (3 == 'abc') """ ast_mod, ti = cs._parse_text(src, reset=True) x = [ ti.lookup_typevar(node, node.name) for node in ast_mod.nodes_of_class(astroid.AssignName) ][0] assert ti.type_constraints.resolve(x).getValue() == bool if draw: gen_graph_from_nodes(ti.type_constraints._nodes)
def test_augassign_builtin_autoconvert(): raise SkipTest('TODO: make this test pass (currently a unification fail)') program = """ x = 1 x += 1.0 """ module, inferer = cs._parse_text(program, reset=True) x = [ inferer.lookup_typevar(node, node.name) for node in module.nodes_of_class(astroid.AssignName) ][0] assert inferer.type_constraints.resolve(x).getValue() == float
def test_set_env(variables_dict): """Test environment setting visitors""" program = cs._parse_dictionary_to_program(variables_dict) module, _ = cs._parse_text(program) # get list of variable names in locals local_values = [module.type_environment.locals[name] for name in module.type_environment.locals] global_values = [module.type_environment.globals[name] for name in module.type_environment.globals] # verify the type of the value of each variable in the environment for value in local_values: assert isinstance(value, TypeVar) for value in global_values: assert isinstance(value, TypeVar)
def test_functiondef_method(): program = \ ''' class A: def method(self, x): return x + 1 ''' module, inferer = cs._parse_text(program) for func_def in module.nodes_of_class(astroid.FunctionDef): assert lookup_type(inferer, func_def, func_def.argnames()[0]) == ForwardRef('A')
def test_class_dot_method(): program = \ ''' class A: def foo(self, x): return x + 1 A.foo(A(), 0) ''' module, _ = cs._parse_text(program, reset=True) for attribute_node in module.nodes_of_class(astroid.Attribute): eq_(str(attribute_node.inf_type.getValue()), "typing.Callable[[ForwardRef('A'), int], int]")
def test_incompatible_binop_call(): """ User tries to call a builtin binary operation on arguments of the wrong type. """ program = f'5 + "string"\n' try: module, inferer = cs._parse_text(program) except: raise SkipTest() binop_node = next(module.nodes_of_class(astroid.BinOp)) expected_msg = "You cannot add an int, 5, and a str, 'string'. " \ "Perhaps you wanted to cast the integer into a string or vice versa?" assert binop_node.inf_type.getValue() == expected_msg
def test_tuple_empty(): program = """ def f(x): a = () b = (x,) a = b """ module, ti = cs._parse_text(program) functiondef_node = next(module.nodes_of_class(astroid.FunctionDef)) eq_(lookup_type(ti, functiondef_node, 'a'), Tuple[()]) x_type = lookup_type(ti, functiondef_node, 'x') eq_(lookup_type(ti, functiondef_node, 'b'), Tuple[x_type])
def test_inference_dict_subscript(node): """Note that this test only takes in a dictionary because the subscript index must be the same type as the dictionary's keys in order to type check. """ for key, _ in node.items: new_node = astroid.Subscript() new_node.postinit(node, key) module, _ = cs._parse_text(new_node) for subscript_node in module.nodes_of_class(astroid.Subscript): dict_node = subscript_node.value assert subscript_node.inf_type.getValue() == list( dict_node.items)[0][1].inf_type.getValue()
def test_annassign(variables_annotations_dict): """Test whether types are being properly set for an AnnAssign node. """ program = f'class Student:\n' for variable in variables_annotations_dict: program += f' {variable}: {variables_annotations_dict[variable].__name__}\n' program += f' def __init__(self):\n' \ f' pass\n' module, inferer = cs._parse_text(program) for node in module.nodes_of_class(astroid.AnnAssign): variable_type = lookup_type(inferer, node, node.target.name) annotated_type = variables_annotations_dict[node.target.name] assert variable_type == annotated_type
def test_flagged_builtin_overload(): program = """ x = round(5.5) y = round(5.5, 1) """ ast_mod, ti = cs._parse_text(program) for assgn_node in ast_mod.nodes_of_class(astroid.AssignName): if assgn_node.name == 'x': x = ti.lookup_typevar(assgn_node, assgn_node.name) assert ti.type_constraints.resolve(x).getValue() == int if assgn_node.name == 'y': y = ti.lookup_typevar(assgn_node, assgn_node.name) assert ti.type_constraints.resolve(y).getValue() == float
def test_annassign_subscript_list_int_wrong(): program = """ lst: List[int] lst = ['Hello', 'Goodbye'] """ module, inferer = cs._parse_text(program) ann_node = next(module.nodes_of_class(astroid.AnnAssign)) variable_type = lookup_type(inferer, ann_node, ann_node.target.name) eq_(variable_type, List[int]) assign_node = next(module.nodes_of_class(astroid.Assign)) assert isinstance(assign_node.inf_type, TypeFailUnify)