def type_of_dict_is_determined_by_unifying_types_of_keys_and_values(): assert_equal( types.dict_type(types.str_type, types.int_type), infer(nodes.dict_literal([ (nodes.str_literal("Hello"), nodes.int_literal(42)), (nodes.str_literal("Blah"), nodes.int_literal(16)), ])) )
def test_parse_dict_literal(): _assert_expression_parse( nodes.dict_literal([ (nodes.str_literal("hello"), nodes.int_literal(4)), (nodes.str_literal("there"), nodes.int_literal(5)), ]), "{'hello': 4, 'there': 5}" )
def module_exports_default_to_values_without_leading_underscore_if_all_is_not_specified(): module_node = nodes.module([ nodes.assign(["x"], nodes.str_literal("one")), nodes.assign(["_y"], nodes.str_literal("two")), nodes.assign(["z"], nodes.int_literal(3)), ]) module, type_lookup = _check(LocalModule(None, module_node)) assert_equal(types.str_type, module.attrs.type_of("x")) assert_equal(None, module.attrs.get("_y")) assert_equal(types.int_type, module.attrs.type_of("z"))
def module_exports_are_specified_using_all(): module_node = nodes.module([ nodes.assign(["__all__"], nodes.list_literal([nodes.str_literal("x"), nodes.str_literal("z")])), nodes.assign(["x"], nodes.str_literal("one")), nodes.assign(["y"], nodes.str_literal("two")), nodes.assign(["z"], nodes.int_literal(3)), ]) module, type_lookup = _check(LocalModule(None, module_node)) assert_equal(types.str_type, module.attrs.type_of("x")) assert_equal(None, module.attrs.get("y")) assert_equal(types.int_type, module.attrs.type_of("z"))
def error_if_argument_is_passed_both_by_position_and_keyword(): node = _create_call([nodes.str_literal("Jim")], {"name": nodes.str_literal("Bob")}) func_type = types.func( args=[types.func_arg("name", types.str_type)], return_type=types.bool_type, ) try: _infer_function_call(func_type, node) assert False, "Expected error" except errors.ArgumentsError as error: assert_is(node, error.node) assert_equal("multiple values for argument 'name'", str(error))
def dict_literal_uses_type_hint_when_valid(): assert_equal( types.dict_type(types.object_type, types.int_type), infer(nodes.dict_literal([ (nodes.str_literal("Hello"), nodes.int_literal(42)), ]), hint=types.dict_type(types.object_type, types.int_type)) ) assert_equal( types.dict_type(types.str_type, types.object_type), infer(nodes.dict_literal([ (nodes.str_literal("Hello"), nodes.int_literal(42)), ]), hint=types.dict_type(types.str_type, types.object_type)) )
def dict_literal_type_hint_is_ignored_if_hint_item_type_is_not_super_type_of_actual_item_types(): assert_equal( types.dict_type(types.str_type, types.int_type), infer(nodes.dict_literal([ (nodes.str_literal("Hello"), nodes.int_literal(42)), ]), hint=types.dict_type(types.bottom_type, types.int_type)) ) assert_equal( types.dict_type(types.str_type, types.int_type), infer(nodes.dict_literal([ (nodes.str_literal("Hello"), nodes.int_literal(42)), ]), hint=types.dict_type(types.str_type, types.bottom_type)) )
def attributes_assigned_in_init_can_be_used_in_methods_when_init_method_is_defined_after_other_method(): init_func = nodes.func( name="__init__", args=nodes.args([nodes.arg("self_init")]), body=[ nodes.assign( [nodes.attr(nodes.ref("self_init"), "message")], nodes.str_literal("Hello"), type=nodes.ref("str"), ) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ), ) node = nodes.class_("User", [ nodes.func( name="g", args=nodes.args([nodes.arg("self_g")]), body=[nodes.ret(nodes.attr(nodes.ref("self_g"), "message"))], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("str") ), ), init_func, ]) _infer_class_type(node, ["__init__", "g"], [(init_func, ["self_init"])])
def callee_can_be_overloaded_func_type_where_choice_is_unambiguous_given_args(): type_bindings = {"f": types.overloaded_func( types.func([types.str_type], types.int_type), types.func([types.int_type], types.str_type), )} node = nodes.call(nodes.ref("f"), [nodes.str_literal("")]) assert_equal(types.int_type, infer(node, type_bindings=type_bindings))
def attributes_assigned_in_init_can_be_used_outside_of_class(): init_func = nodes.func( name="__init__", args=nodes.args([nodes.arg("self_init")]), body=[ nodes.assign( [nodes.attr(nodes.ref("self_init"), "message")], nodes.str_literal("Hello"), type=nodes.ref("str"), ) ], type=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("none") ) ) class_node = nodes.class_("User", [init_func]) node = [ class_node, nodes.assign([nodes.ref("x")], nodes.attr(nodes.call(nodes.ref("User"), []), "message")), ] context = _update_context(node, declared_names_in_node=NodeDict([ (class_node, ["Self", "__init__"]), (init_func, ["self_init"]), ])) assert_equal(types.str_type, context.lookup_name("x"))
def only_values_that_are_definitely_bound_are_exported(): module_node = nodes.module([ nodes.if_( nodes.bool_literal(True), [ nodes.assign(["x"], nodes.str_literal("one")), nodes.assign(["y"], nodes.str_literal("two")), ], [ nodes.assign(["y"], nodes.str_literal("three")), ] ) ]) module, type_lookup = _check(LocalModule(None, module_node)) assert_equal(None, module.attrs.get("x")) assert_equal(types.str_type, module.attrs.type_of("y"))
def error_if_extra_positional_argument(): node = _create_call([nodes.str_literal("hello")]) try: _infer_function_call(types.func([], types.int_type), node) assert False, "Expected error" except errors.ArgumentsError as error: assert_is(node, error.node) assert_equal("function takes 0 positional arguments but 1 was given", str(error))
def error_if_extra_keyword_argument(): node = _create_call([], {"message": nodes.str_literal("hello")}) try: _infer_function_call(types.func([], types.int_type), node) assert False, "Expected error" except errors.ArgumentsError as error: assert_is(node, error.node) assert_equal("unexpected keyword argument 'message'", str(error))
def can_infer_type_of_call_with_keyword_arguments(): type_bindings = { "f": types.func( args=[types.func_arg("name", types.str_type), types.func_arg("hats", types.int_type)], return_type=types.bool_type, ) } node = nodes.call(nodes.ref("f"), [], {"name": nodes.str_literal("Bob"), "hats": nodes.int_literal(42)}) assert_equal(types.bool_type, infer(node, type_bindings=type_bindings))
def type_mismatch_if_return_type_is_incorrect(): return_node = nodes.ret(nodes.str_literal("!")) node = nodes.func( "f", args=nodes.arguments([]), body=[return_node], type=nodes.signature(returns=nodes.ref("int")), ) assert_type_mismatch(lambda: _infer_func_type(node), expected=types.int_type, actual=types.str_type, node=return_node)
def can_infer_type_of_call_with_optional_argument_specified(): type_bindings = { "f": types.func( args=[types.func_arg(None, types.str_type, optional=True)], return_type=types.bool_type, ) } node = nodes.call(nodes.ref("f"), [nodes.str_literal("blah")]) assert_equal(types.bool_type, infer(node, type_bindings=type_bindings))
def object_can_be_called_if_it_has_call_magic_method_that_returns_callable(): second_cls = types.class_type("Second", [ types.attr("__call__", types.func([types.str_type], types.int_type)), ]) first_cls = types.class_type("First", [ types.attr("__call__", second_cls), ]) type_bindings = {"f": first_cls} assert_equal(types.int_type, infer(nodes.call(nodes.ref("f"), [nodes.str_literal("")]), type_bindings=type_bindings))
def generic_type_arguments_are_covariant(): type_bindings = {"f": types.generic_func(["T"], lambda T: types.func([T, T], T), )} node = nodes.call(nodes.ref("f"), [nodes.str_literal(""), nodes.none()]) assert_equal( types.common_super_type([types.str_type, types.none_type]), infer(node, type_bindings=type_bindings) )
def return_type_is_common_super_type_of_possible_return_types_of_overloaded_function(): type_bindings = {"f": types.overloaded_func( types.func([types.object_type], types.int_type), types.func([types.str_type], types.str_type), )} node = nodes.call(nodes.ref("f"), [nodes.str_literal("")]) assert_equal( types.common_super_type([types.int_type, types.str_type]), infer(node, type_bindings=type_bindings) )
def error_if_generic_func_is_passed_wrong_arguments(): type_bindings = {"f": types.generic_func(["T"], lambda T: types.func([T, types.int_type], T), )} node = nodes.call(nodes.ref("f"), [nodes.str_literal(""), nodes.none()]) try: infer(node, type_bindings=type_bindings) assert False, "Expected error" except errors.ArgumentsError as error: assert_is(node, error.node) assert_equal("cannot call function of type: T => T, int -> T\nwith arguments: str, NoneType", str(error))
def when_target_has_explicit_type_that_type_is_used_as_type_hint(): node = nodes.assign( [nodes.ref("x")], nodes.list_literal([nodes.str_literal("Hello")]), type=nodes.type_apply(nodes.ref("list"), [nodes.ref("object")]) ) context = update_context(node, type_bindings={ "list": types.meta_type(types.list_type), "object": types.meta_type(types.object_type), }) assert_equal(types.list_type(types.object_type), context.lookup_name("x"))
def cannot_reassign_read_only_attribute(): cls = types.class_type("X", [types.attr("y", types.str_type, read_only=True)]) attr_node = nodes.attr(nodes.ref("x"), "y") node = nodes.assign([attr_node], nodes.str_literal("Hello")) type_bindings = {"x": cls} try: update_context(node, type_bindings=type_bindings) assert False, "Expected error" except errors.ReadOnlyAttributeError as error: assert_equal(attr_node, error.node) assert_equal("'X' attribute 'y' is read-only", str(error))
def init_method_must_return_none(): node = _create_class_with_init( signature=nodes.signature( args=[nodes.signature_arg(nodes.ref("Self"))], returns=nodes.ref("str") ), args=nodes.args([nodes.arg("self")]), body=[nodes.ret(nodes.str_literal(""))], ) try: _infer_meta_type(node, ["__init__"]) assert False, "Expected error" except errors.InitMethodsMustReturnNoneError as error: assert_equal(node.body[0], error.node)
def check_generates_type_lookup_for_all_expressions(): int_ref_node = nodes.ref("a") int_node = nodes.int_literal(3) str_node = nodes.str_literal("Hello") module_node = nodes.module([ nodes.assign(["a"], int_node), nodes.func("f", nodes.args([]), [ nodes.assign("b", int_ref_node), nodes.assign("c", str_node), ], type=None), ]) module, type_lookup = _check(LocalModule(None, module_node)) assert_equal(types.int_type, type_lookup.type_of(int_node)) assert_equal(types.int_type, type_lookup.type_of(int_ref_node)) assert_equal(types.str_type, type_lookup.type_of(str_node))
def type_of_keyword_arguments_must_match(): node = nodes.call(nodes.ref("f"), [], {"name": nodes.str_literal("Bob"), "hats": nodes.int_literal(42)}) type_bindings = { "f": types.func( args=[types.func_arg("name", types.str_type)], return_type=types.bool_type, ) } arg_node = nodes.int_literal(4) node = nodes.call(nodes.ref("f"), [], {"name": arg_node}) assert_type_mismatch( lambda: infer(node, type_bindings=type_bindings), expected=types.str_type, actual=types.int_type, node=arg_node, )
def can_infer_type_of_slice(): node = nodes.slice(nodes.str_literal(""), nodes.int_literal(4), nodes.none()) assert_equal( types.slice_type(types.str_type, types.int_type, types.none_type), infer(node) )
def can_infer_type_of_call_with_positional_arguments(): type_bindings = {"f": types.func([types.str_type], types.int_type)} assert_equal(types.int_type, infer(nodes.call(nodes.ref("f"), [nodes.str_literal("")]), type_bindings=type_bindings))
def object_can_be_called_if_it_has_call_magic_method(): cls = types.class_type("Blah", [ types.attr("__call__", types.func([types.str_type], types.int_type)), ]) type_bindings = {"f": cls} assert_equal(types.int_type, infer(nodes.call(nodes.ref("f"), [nodes.str_literal("")]), type_bindings=type_bindings))
def str_has_no_references(): _assert_no_references(nodes.str_literal(""))
def callee_can_be_generic_func(): type_bindings = {"f": types.generic_func(["T"], lambda T: types.func([T], types.int_type), )} node = nodes.call(nodes.ref("f"), [nodes.str_literal("")]) assert_equal(types.int_type, infer(node, type_bindings=type_bindings))