diff --git a/CHANGELOG b/CHANGELOG index 96b871d3f..88072e77b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +Version 2020.04.01 +* Do some test restructuring and cleanup. + Version 2020.03.19 * Fix a couple of pytype crashes. * Do not allow mixing string types in IO.write() in Python 3. diff --git a/README.md b/README.md index f5287840a..34ebae220 100755 --- a/README.md +++ b/README.md @@ -93,11 +93,18 @@ interpreter in `$PATH` for the Python version of the code you're analyzing. Platform support: -* Pytype is currently developed and tested on Linux, which is the main supported +* Pytype is currently developed and tested on Linux\*, which is the main supported platform. * Installation on MacOSX requires OSX 10.7 or higher and Xcode v8 or higher. * Windows is currently not supported unless you use [WSL][wsl]. +\* +Note: On Alpine Linux, installing may fail due to issues with upstream +dependencies. See the details of + +this issue for a possible fix. + + ## Installing Pytype can be installed via pip. Note that the installation requires `wheel` diff --git a/docs/faq.md b/docs/faq.md index 5addcbfb6..5911508f3 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -127,7 +127,7 @@ class LoggerMixin(LoggerMixinInterface): def log(self, msg: str): self._log.print(f"{self.name()}: {msg}") -class Person(Logger): +class Person(LoggerMixinInterface): ... # Other initialization def name(self): return self._name diff --git a/docs/index.md b/docs/index.md index 1d8e58fb3..54c911deb 100755 --- a/docs/index.md +++ b/docs/index.md @@ -91,11 +91,18 @@ interpreter in `$PATH` for the Python version of the code you're analyzing. Platform support: -* Pytype is currently developed and tested on Linux, which is the main supported +* Pytype is currently developed and tested on Linux\*, which is the main supported platform. * Installation on MacOSX requires OSX 10.7 or higher and Xcode v8 or higher. * Windows is currently not supported unless you use [WSL][wsl]. +\* +Note: On Alpine Linux, installing may fail due to issues with upstream +dependencies. See the details of + +this issue for a possible fix. + + ## Installing Pytype can be installed via pip. Note that the installation requires `wheel` diff --git a/pytype/__version__.py b/pytype/__version__.py index 2b5b23692..5fbc2c6ef 100644 --- a/pytype/__version__.py +++ b/pytype/__version__.py @@ -1,2 +1,2 @@ # pylint: skip-file -__version__ = '2020.03.19' +__version__ = '2020.04.01' diff --git a/pytype/abstract.py b/pytype/abstract.py index 055b15c89..7431f3ae0 100644 --- a/pytype/abstract.py +++ b/pytype/abstract.py @@ -2491,7 +2491,7 @@ def update_sig(method): if nitem in self.template: raise abstract_utils.GenericTypeError( self, ("Generic class [%s] and its nested generic class [%s] " - "cannot use same type variable %s.") + "cannot use the same type variable %s.") % (self.full_name, cls.full_name, item.name)) self._load_all_formal_type_parameters() # Throw exception if there is error @@ -3010,7 +3010,8 @@ def _inner_cls_check(self, last_frame): inner_cls_types = value.collect_inner_cls_types() inner_cls_types.update([(value, item.with_module(None)) for item in value.template]) - for cls, item in inner_cls_types: + # Report errors in a deterministic order. + for cls, item in sorted(inner_cls_types, key=lambda typ: typ[1].name): if item in all_type_parameters: self.vm.errorlog.invalid_annotation( self.vm.simple_stack(self.get_first_opcode()), item, diff --git a/pytype/abstract_test.py b/pytype/abstract_test.py index e53664584..11789e8e9 100644 --- a/pytype/abstract_test.py +++ b/pytype/abstract_test.py @@ -119,7 +119,7 @@ def test_call_wrong_argcount(self): self.assertEqual(self._node, node) self.assertIsInstance(abstract_utils.get_atomic_value(result), abstract.Unsolvable) - self.assertRegexpMatches(str(self._vm.errorlog), "missing-parameter") + six.assertRegex(self, str(self._vm.errorlog), "missing-parameter") def test_call_wrong_keywords(self): self._vm.push_frame(frame_state.SimpleFrame()) @@ -130,9 +130,8 @@ def test_call_wrong_keywords(self): self.assertEqual(self._node, node) self.assertIsInstance(abstract_utils.get_atomic_value(result), abstract.Unsolvable) - self.assertRegexpMatches( - str(self._vm.errorlog), - r"foo.*isinstance.*\[wrong-keyword-args\]") + six.assertRegex(self, str(self._vm.errorlog), + r"foo.*isinstance.*\[wrong-keyword-args\]") def test_is_instance(self): def check(expected, left, right): diff --git a/pytype/annotations_util.py b/pytype/annotations_util.py index e208ef51e..2979c4131 100644 --- a/pytype/annotations_util.py +++ b/pytype/annotations_util.py @@ -1,5 +1,7 @@ """Utilities for inline type annotations.""" +import sys + from pytype import abstract from pytype import abstract_utils from pytype import mixin @@ -157,7 +159,11 @@ def convert_annotations_list(self, node, annotations_list): def convert_class_annotations(self, node, raw_annotations): """Convert a name -> raw_annot dict to annotations.""" annotations = {} - for name, t in raw_annotations.items(): + raw_items = raw_annotations.items() + if sys.version_info[:2] < (3, 6): + # Make sure annotation errors are reported in a deterministic order. + raw_items = sorted(raw_items, key=str) + for name, t in raw_items: # Don't use the parameter name, since it's often something unhelpful # like `0`. annot = self._process_one_annotation( diff --git a/pytype/debug_test.py b/pytype/debug_test.py index f6fd61f53..852ac6690 100644 --- a/pytype/debug_test.py +++ b/pytype/debug_test.py @@ -43,7 +43,7 @@ def testAsciiTree(self): n7 = Node("n7", n5) del n4, n6 # make pylint happy s = debug.ascii_tree(n1, lambda n: n.outgoing) - self.assertMultiLineEqual(textwrap.dedent("""\ + self.assertMultiLineEqual(textwrap.dedent(""" Node(n1) | +-Node(n2) @@ -57,15 +57,15 @@ def testAsciiTree(self): +-Node(n6) | +-Node(n7) - """), s) + """).lstrip(), s) s = debug.ascii_tree(n7, lambda n: n.incoming) - self.assertMultiLineEqual(textwrap.dedent("""\ + self.assertMultiLineEqual(textwrap.dedent(""" Node(n7) | +-Node(n5) | +-Node(n1) - """), s) + """).lstrip(), s) def testAsciiGraph(self): n1 = Node("n1") @@ -73,7 +73,7 @@ def testAsciiGraph(self): n3 = Node("n3", n2) n3.connect_to(n1) s = debug.ascii_tree(n1, lambda n: n.outgoing) - self.assertMultiLineEqual(textwrap.dedent("""\ + self.assertMultiLineEqual(textwrap.dedent(""" Node(n1) | +-Node(n2) @@ -81,7 +81,7 @@ def testAsciiGraph(self): +-Node(n3) | +-[Node(n1)] - """), s) + """).lstrip(), s) def testAsciiGraphWithCustomText(self): n1 = Node("n1") @@ -89,7 +89,7 @@ def testAsciiGraphWithCustomText(self): n3 = Node("n3", n2) n3.connect_to(n1) s = debug.ascii_tree(n1, lambda n: n.outgoing, lambda n: n.name.upper()) - self.assertMultiLineEqual(textwrap.dedent("""\ + self.assertMultiLineEqual(textwrap.dedent(""" N1 | +-N2 @@ -97,7 +97,7 @@ def testAsciiGraphWithCustomText(self): +-N3 | +-[N1] - """), s) + """).lstrip(), s) def testRootCause(self): n1 = self.prog.NewCFGNode() diff --git a/pytype/directors_test.py b/pytype/directors_test.py index f022ca592..583f90521 100644 --- a/pytype/directors_test.py +++ b/pytype/directors_test.py @@ -3,6 +3,7 @@ from pytype import directors from pytype import errors +import six import unittest _TEST_FILENAME = "my_file.py" @@ -99,6 +100,7 @@ class DirectorTest(unittest.TestCase): @classmethod def setUpClass(cls): + super(DirectorTest, cls).setUpClass() # Invoking the _error_name decorator will register the name as a valid # error name. for name in ["test-error", "test-other-error"]: @@ -296,7 +298,7 @@ def check_warning(message_regex, text): error = list(self._errorlog)[0] self.assertEqual(_TEST_FILENAME, error._filename) self.assertEqual(1, error.lineno) - self.assertRegexpMatches(str(error), message_regex) + six.assertRegex(self, str(error), message_regex) check_warning("Unknown pytype directive.*disalbe.*", "# pytype: disalbe=test-error") @@ -349,7 +351,7 @@ def test_strings_that_look_like_directives(self): }, self._director.type_comments) def test_type_comment_on_multiline_value(self): - self._create("""\ + self._create(""" v = [ ("hello", "world", # type: should_be_ignored @@ -358,11 +360,11 @@ def test_type_comment_on_multiline_value(self): ] # type: dict """) self.assertEqual({ - 3: ("]", "dict"), + 4: ("]", "dict"), }, self._director.type_comments) def test_type_comment_with_trailing_comma(self): - self._create("""\ + self._create(""" v = [ ("hello", "world" @@ -375,8 +377,8 @@ def test_type_comment_with_trailing_comma(self): ] # type: dict """) self.assertEqual({ - 3: ("]", "dict"), - 9: ("]", "dict"), + 4: ("]", "dict"), + 10: ("]", "dict"), }, self._director.type_comments) diff --git a/pytype/errors_test.py b/pytype/errors_test.py index 64859779a..a54ffec27 100644 --- a/pytype/errors_test.py +++ b/pytype/errors_test.py @@ -73,21 +73,21 @@ def test_no_traceback_no_opcode(self): def test_traceback(self): stack = test_utils.fake_stack(errors.MAX_TRACEBACK_LENGTH + 1) error = errors.Error.with_stack(stack, errors.SEVERITY_ERROR, "") - self.assertMultiLineEqual(error._traceback, textwrap.dedent("""\ + self.assertMultiLineEqual(error._traceback, textwrap.dedent(""" Called from (traceback): line 0, in function0 line 1, in function1 - line 2, in function2""")) + line 2, in function2""").lstrip()) @errors._error_name(_TEST_ERROR) def test_truncated_traceback(self): stack = test_utils.fake_stack(errors.MAX_TRACEBACK_LENGTH + 2) error = errors.Error.with_stack(stack, errors.SEVERITY_ERROR, "") - self.assertMultiLineEqual(error._traceback, textwrap.dedent("""\ + self.assertMultiLineEqual(error._traceback, textwrap.dedent(""" Called from (traceback): line 0, in function0 ... - line 3, in function3""")) + line 3, in function3""").lstrip()) def test__error_name(self): # This should be true as long as at least one method is annotated with @@ -119,7 +119,7 @@ def test_write_to_csv(self): errorlog.print_to_csv_file(filename) with open(filename, "r") as fi: rows = list(csv.reader(fi, delimiter=",")) - self.assertEqual(2, len(rows)) + self.assertEqual(len(rows), 2) for i, row in enumerate(rows): filename, lineno, name, actual_message, actual_details = row self.assertEqual(filename, "foo.py") @@ -138,12 +138,12 @@ def test_write_to_csv_with_traceback(self): errorlog.print_to_csv_file(filename) with open(filename, "r") as fi: (_, _, _, _, actual_details), = list(csv.reader(fi, delimiter=",")) - self.assertMultiLineEqual(actual_details, textwrap.dedent("""\ + self.assertMultiLineEqual(actual_details, textwrap.dedent(""" some details Called from (traceback): - line 0, in function0""")) + line 0, in function0""").lstrip()) class ErrorLogBaseTest(unittest.TestCase): @@ -153,7 +153,7 @@ def test_error(self): errorlog = errors.ErrorLog() op = test_utils.FakeOpcode("foo.py", 123, "foo") errorlog.error(op.to_stack(), "unknown attribute %s" % "xyz") - self.assertEqual(1, len(errorlog)) + self.assertEqual(len(errorlog), 1) e = list(errorlog)[0] # iterate the log and save the first error. self.assertEqual(errors.SEVERITY_ERROR, e._severity) self.assertEqual("unknown attribute xyz", e._message) @@ -164,18 +164,18 @@ def test_error(self): def test_error_with_details(self): errorlog = errors.ErrorLog() errorlog.error(None, "My message", "one\ntwo") - self.assertEqual(textwrap.dedent("""\ + self.assertEqual(textwrap.dedent(""" My message [test-error] one two - """), str(errorlog)) + """).lstrip(), str(errorlog)) @errors._error_name(_TEST_ERROR) def test_warn(self): errorlog = errors.ErrorLog() op = test_utils.FakeOpcode("foo.py", 123, "foo") errorlog.warn(op.to_stack(), "unknown attribute %s", "xyz") - self.assertEqual(1, len(errorlog)) + self.assertEqual(len(errorlog), 1) e = list(errorlog)[0] # iterate the log and save the first error. self.assertEqual(errors.SEVERITY_WARNING, e._severity) self.assertEqual("unknown attribute xyz", e._message) @@ -188,11 +188,11 @@ def test_has_error(self): self.assertFalse(errorlog.has_error()) # A warning is part of the error log, but isn't severe. errorlog.warn(None, "A warning") - self.assertEqual(1, len(errorlog)) + self.assertEqual(len(errorlog), 1) self.assertFalse(errorlog.has_error()) # An error is severe. errorlog.error(None, "An error") - self.assertEqual(2, len(errorlog)) + self.assertEqual(len(errorlog), 2) self.assertTrue(errorlog.has_error()) @errors._error_name(_TEST_ERROR) @@ -203,7 +203,7 @@ def test_duplicate_error_no_traceback(self): errorlog.error(stack[-1:], "error") # no traceback # Keep the error with no traceback. unique_errors = errorlog.unique_sorted_errors() - self.assertEqual(1, len(unique_errors)) + self.assertEqual(len(unique_errors), 1) self.assertIsNone(unique_errors[0]._traceback) @errors._error_name(_TEST_ERROR) @@ -230,10 +230,10 @@ def test_duplicate_error_shorter_traceback(self): errorlog.error(stack[-2:], "error") # shorter traceback # Keep the error with a shorter traceback. unique_errors = errorlog.unique_sorted_errors() - self.assertEqual(1, len(unique_errors)) - self.assertMultiLineEqual(unique_errors[0]._traceback, textwrap.dedent("""\ + self.assertEqual(len(unique_errors), 1) + self.assertMultiLineEqual(unique_errors[0]._traceback, textwrap.dedent(""" Called from (traceback): - line 1, in function1""")) + line 1, in function1""").lstrip()) @errors._error_name(_TEST_ERROR) def test_unique_errors(self): @@ -248,7 +248,7 @@ def test_unique_errors(self): errorlog.error([backframe2, current_frame], "error") # Keep both errors, since the tracebacks are different. unique_errors = errorlog.unique_sorted_errors() - self.assertEqual(2, len(unique_errors)) + self.assertEqual(len(unique_errors), 2) self.assertSetEqual(set(errorlog), set(unique_errors)) diff --git a/pytype/load_pytd_test.py b/pytype/load_pytd_test.py index 01e63393b..36d20a6e4 100644 --- a/pytype/load_pytd_test.py +++ b/pytype/load_pytd_test.py @@ -415,10 +415,10 @@ def testStarImport(self): loaded_ast = self._LoadPickledModule(d, bar) loaded_ast.Visit(visitors.VerifyLookup()) self.assertMultiLineEqual(pytd_utils.Print(loaded_ast), - textwrap.dedent("""\ + textwrap.dedent(""" import foo - bar.A = foo.A""")) + bar.A = foo.A""").lstrip()) def testFunctionAlias(self): with file_utils.Tempdir() as d: @@ -482,7 +482,7 @@ def testPython3Builtins(self): # Test that we read python3 builtins from builtin.pytd if we pass a (3, 6) # version to the loader. with file_utils.Tempdir() as d: - d.create_file("a.pyi", """\ + d.create_file("a.pyi", """ from typing import AsyncGenerator class A(AsyncGenerator[str]): ...""") loader = load_pytd.Loader("base", diff --git a/pytype/matcher_test.py b/pytype/matcher_test.py index e2e508298..f3f6708a2 100644 --- a/pytype/matcher_test.py +++ b/pytype/matcher_test.py @@ -302,7 +302,7 @@ def testPyTDFunctionAgainstCallableBadArgType(self): self.assertNoMatch(f, callable_bad_arg2) def testBoundPyTDFunctionAgainstCallable(self): - instance = self._convert("""\ + instance = self._convert(""" class A(object): def f(self, x: int) -> bool: ... """, "A", as_instance=True) @@ -389,7 +389,7 @@ def testAnyStrInstanceAgainstAnyStr(self): def testProtocol(self): left1 = self._convert_type("str", as_instance=True) - left2 = self._convert("""\ + left2 = self._convert(""" class A(object): def lower(self) : ... """, "A", as_instance=True) @@ -401,7 +401,7 @@ def lower(self) : ... def testProtocolIterator(self): left1 = self._convert_type("Iterator", as_instance=True) - left2 = self._convert("""\ + left2 = self._convert(""" class A(object): def next(self): ... def __iter__(self): ... @@ -414,7 +414,7 @@ def __iter__(self): ... def testProtocolSequence(self): left1 = self._convert_type("list", as_instance=True) - left2 = self._convert("""\ + left2 = self._convert(""" class A(object): def __getitem__(self, i) : ... def __len__(self): ... @@ -427,7 +427,7 @@ def __len__(self): ... @unittest.skip("Needs to be fixed, tries to match protocol against A") def testParameterizedProtocol(self): - left1 = self._convert("""\ + left1 = self._convert(""" from typing import Iterator class A(object): def __iter__(self) -> Iterator[int] : ... diff --git a/pytype/pyi/lexer_test.py b/pytype/pyi/lexer_test.py index 701064c23..3d8390800 100644 --- a/pytype/pyi/lexer_test.py +++ b/pytype/pyi/lexer_test.py @@ -6,9 +6,6 @@ import unittest -# We use '\' to make test code more readable: -# pylint: disable=g-backslash-continuation - # Map from token code to name. TOKEN_NAMES = {code: name for name, code in parser_ext.TOKENS.items()} @@ -160,44 +157,44 @@ def test_triplequoted(self): ("TRIPLEQUOTED", None, 1, 3, 3, 5), ("NUMBER", 2, 4), ("TRIPLEQUOTED", None, 4, 3, 4, 58), - ("NUMBER", 3, 5)], """\ + ("NUMBER", 3, 5)], """ 1 ''' one quote is allowed ' newlines and two quotes are allowed '', end on next line ''' 2 '''this shoulnd't be swallowed by the previous string''' - 3""") + 3""".lstrip("\n")) # Double quotes. - # pylint: disable=g-inconsistent-quotes,g-backslash-continuation + # pylint: disable=g-inconsistent-quotes self.check([ ("NUMBER", 1, 1), ("TRIPLEQUOTED", None, 1, 3, 3, 5), ("NUMBER", 2, 4), ("TRIPLEQUOTED", None, 4, 3, 4, 58), - ("NUMBER", 3, 5)], '''\ + ("NUMBER", 3, 5)], ''' 1 """ one quote is allowed " newlines and two quotes are allowed "", end on next line """ 2 """this shoulnd't be swallowed by the previous string""" - 3''') + 3'''.lstrip("\n")) def test_typecomment(self): - self.check([1, "TYPECOMMENT", 2, "TYPECOMMENT", 3, "TYPECOMMENT", 4], """\ + self.check([1, "TYPECOMMENT", 2, "TYPECOMMENT", 3, "TYPECOMMENT", 4], """ 1 # type: 2 #type: 3 # type: 4""") def test_comments_are_ignored(self): - self.check([("NUMBER", 1, 1), ("NUMBER", 2, 5)], """\ + self.check([("NUMBER", 1, 1), ("NUMBER", 2, 5)], """ 1 # comment until end of line # type not quite a type comment, no colon! # # The preceding line had a # followed immediately by newline. - 2""") + 2""".lstrip("\n")) def test_indent(self): self.check( [1, "INDENT", 2, "INDENT", 3, "INDENT", 4, "DEDENT", "DEDENT", 5, - "DEDENT", 6], """\ + "DEDENT", 6], """ 1 2 3 @@ -207,7 +204,7 @@ def test_indent(self): def test_indent_ignore_blank_line2(self): self.check( - [1, "INDENT", 2, 3, "DEDENT"], """\ + [1, "INDENT", 2, 3, "DEDENT"], """ 1 2 @@ -216,14 +213,14 @@ def test_indent_ignore_blank_line2(self): def test_indent_dedents_at_eof(self): self.check( - [1, "INDENT", 2, "INDENT", 3, "DEDENT", "DEDENT"], """\ + [1, "INDENT", 2, "INDENT", 3, "DEDENT", "DEDENT"], """ 1 2 3""") def test_indent_not_inside_brackets(self): self.check( - [1, "[", 2, "[", "]", 3, "]", 4, "INDENT", 5, "DEDENT"], """\ + [1, "[", 2, "[", "]", 3, "]", 4, "INDENT", 5, "DEDENT"], """ 1 [2 [ ] 3] 4 @@ -231,7 +228,7 @@ def test_indent_not_inside_brackets(self): def test_indent_not_inside_parens(self): self.check( - [1, "(", 2, "(", ")", 3, ")", 4, "INDENT", 5, "DEDENT"], """\ + [1, "(", 2, "(", ")", 3, ")", 4, "INDENT", 5, "DEDENT"], """ 1 (2 ( ) 3) 4 @@ -240,7 +237,7 @@ def test_indent_not_inside_parens(self): def test_indent_legacy_bug(self): # The legacy lexer was not properly handling 3 dedents in a row. self.check([1, "INDENT", 2, "INDENT", 3, "INDENT", 4, "DEDENT", "DEDENT", - "DEDENT", 99], """\ + "DEDENT", 99], """ 1 2 3 @@ -250,7 +247,7 @@ def test_indent_legacy_bug(self): def test_indent_mismatch(self): self.check([1, "INDENT", 2, ("LEXERROR", "Invalid indentation"), 3, - "DEDENT"], """\ + "DEDENT"], """ 1 2 3""") @@ -268,15 +265,15 @@ def test_column(self): "INDENT", ("NAME", "hello", 2, 3, 2, 7), ("NAME", "goodbye", 4, 3, 4, 9), - "DEDENT"], """\ + "DEDENT"], """ foo bar hello goodbye - """) + """.lstrip("\n")) def test_ignore_comment_indentation(self): - self.check([1, "TYPECOMMENT", 2, 3], """\ + self.check([1, "TYPECOMMENT", 2, 3], """ 1 # comment 0 # type: 2 diff --git a/pytype/pyi/parser_memleak_test.py b/pytype/pyi/parser_memleak_test.py index 98091df62..e9c658ba0 100644 --- a/pytype/pyi/parser_memleak_test.py +++ b/pytype/pyi/parser_memleak_test.py @@ -65,19 +65,19 @@ def test_builtins(self): self.check(get_builtins_source(self.PYTHON_VERSION)) def test_error_in_class(self): - self.check("""\ + self.check(""" class Foo: def m(): pass an error""") def test_error_in_function(self): - self.check("""\ + self.check(""" def m(): pass def n(x: int, y: str) -> -> """) def test_error_within_if(self): - self.check("""\ + self.check(""" if sys.version_info == (1, 2, 3): x = ... # type: int this is an error diff --git a/pytype/pyi/parser_test.py b/pytype/pyi/parser_test.py index 1af3b7e03..4a045888d 100644 --- a/pytype/pyi/parser_test.py +++ b/pytype/pyi/parser_test.py @@ -11,9 +11,6 @@ import unittest -# We use backslashes to avoid unwanted newlines in test code. -# pylint: disable=g-backslash-continuation - IGNORE = object() @@ -51,12 +48,15 @@ def check(self, src, expected=None, prologue=None, name=None, The parsed pytd.TypeDeclUnit. """ version = version or self.PYTHON_VERSION - src = textwrap.dedent(src) + src = textwrap.dedent(src).lstrip() ast = parser.parse_string(src, name=name, python_version=version, platform=platform) actual = pytd_utils.Print(ast) if expected != IGNORE: - expected = src if expected is None else textwrap.dedent(expected) + if expected is None: + expected = src + else: + expected = textwrap.dedent(expected).lstrip() if prologue: expected = "%s\n\n%s" % (textwrap.dedent(prologue), expected) # Allow blank lines at the end of `expected` for prettier tests. @@ -66,7 +66,7 @@ def check(self, src, expected=None, prologue=None, name=None, def check_error(self, src, expected_line, message): """Check that parsing the src raises the expected error.""" with self.assertRaises(parser.ParseError) as e: - parser.parse_string(textwrap.dedent(src), + parser.parse_string(textwrap.dedent(src).lstrip(), python_version=self.PYTHON_VERSION) six.assertRegex(self, utils.message(e.exception), re.escape(message)) self.assertEqual(expected_line, e.exception.line) @@ -76,14 +76,14 @@ class ParseErrorTest(unittest.TestCase): def check(self, expected, *args, **kwargs): e = parser.ParseError(*args, **kwargs) - self.assertMultiLineEqual(textwrap.dedent(expected), str(e)) + self.assertMultiLineEqual(textwrap.dedent(expected).lstrip("\n"), str(e)) def test_plain_error(self): - self.check("""\ + self.check(""" ParseError: my message""", "my message") def test_full_error(self): - self.check("""\ + self.check(""" File: "foo.py", line 123 this is a test ^ @@ -91,7 +91,7 @@ def test_full_error(self): text="this is a test", column=6) def test_indented_text(self): - self.check("""\ + self.check(""" File: "foo.py", line 123 this is a test ^ @@ -99,22 +99,21 @@ def test_indented_text(self): text=" this is a test", column=16) def test_line_without_filename(self): - self.check("""\ + self.check(""" File: "None", line 1 ParseError: my message""", "my message", line=1) def test_filename_without_line(self): - self.check("""\ + self.check(""" File: "foo.py", line None ParseError: my message""", "my message", filename="foo.py") def test_text_without_column(self): - self.check("""\ + self.check(""" ParseError: my message""", "my message", text="this is a test") def test_column_without_text(self): - self.check("""\ - ParseError: my message""", "my message", column=5) + self.check(" ParseError: my message", "my message", column=5) class ParserTest(_ParserTestBase): @@ -126,7 +125,7 @@ def test_illegal_character(self): self.check_error("^", 1, "Illegal character '^'") def test_invalid_indentation(self): - self.check_error("""\ + self.check_error(""" class Foo: x = ... # type: int y""", 3, "Invalid indentation") @@ -134,10 +133,10 @@ class Foo: def test_type_on_next_line(self): # TODO(dbaum): This probably should be an error. Current behavior matches # legacy parser. Consider changing to an error. - self.check("""\ + self.check(""" a = ... # type: int""", - """\ + """ a: int""") def test_constant(self): @@ -145,10 +144,10 @@ def test_constant(self): self.check("x: str") self.check("x = 0", "x: int") self.check("x = 0.0", "x: float") - self.check_error("\nx = 123", 2, + self.check_error("x = 123", 1, "Only '0' allowed as int literal") self.check("x = 0.0", "x: float") - self.check_error("\nx = 12.3", 2, + self.check_error("x = 12.3", 1, "Only '0.0' allowed as float literal") def test_string_constant(self): @@ -173,17 +172,17 @@ def test_alias_or_constant(self): self.check("x = True", "x: bool") self.check("x = False", "x: bool") self.check("x = Foo") - self.check("""\ + self.check(""" class A: - x = True""", """\ + x = True""", """ class A: x: bool """) - self.check("""\ + self.check(""" class A: x = ... # type: int y = x - z = y""", """\ + z = y""", """ class A: x: int y: int @@ -191,7 +190,7 @@ class A: """) def test_method_aliases(self): - self.check("""\ + self.check(""" class A: def x(self) -> int y = x @@ -199,7 +198,7 @@ def x(self) -> int @classmethod def a(cls) -> str b = a - c = b""", """\ + c = b""", """ class A: def x(self) -> int: ... @classmethod @@ -213,49 +212,49 @@ def c(cls) -> str: ... """) def test_slots(self): - self.check("""\ + self.check(""" class A: __slots__ = ... # type: tuple - """, """\ + """, """ class A: ... """) - self.check("""\ + self.check(""" class A: __slots__ = ["foo", "bar", "baz"] """) - self.check("""\ + self.check(""" class A: __slots__ = [] """) - self.check_error("""\ + self.check_error(""" __slots__ = ["foo", "bar"] """, 1, "__slots__ only allowed on the class level") - self.check_error("""\ + self.check_error(""" class A: __slots__ = ["foo", "bar"] __slots__ = ["foo", "bar", "baz"] """, 1, "Duplicate __slots__ declaration") - self.check_error("""\ + self.check_error(""" class A: __slots__ = ["foo", ?] """, 2, "syntax error") - self.check_error("""\ + self.check_error(""" class A: __slots__ = int """, 2, "__slots__ must be a list of strings") def test_nested_class(self): - self.check("""\ + self.check(""" class A: class B: ... """) def test_nested_class_alias(self): - self.check("""\ + self.check(""" class A: class B: ... C = A.B - """, """\ + """, """ from typing import Type class A: @@ -264,11 +263,11 @@ class B: ... """) def test_nested_class_module_alias(self): - self.check("""\ + self.check(""" class A: class B: ... C = A.B - """, """\ + """, """ from typing import Type C: Type[A.B] @@ -278,7 +277,7 @@ class B: ... """) def test_conditional_nested_class(self): - self.check("""\ + self.check(""" if sys.version_info >= (3, 6): class A: class B: ... @@ -305,37 +304,37 @@ def test_from_import(self): self.assertEqual(parent, pytd.NamedType("foo.c.X")) def test_duplicate_names(self): - self.check_error("""\ + self.check_error(""" def foo() -> int: ... foo = ... # type: int""", None, "Duplicate top-level identifier(s): foo") - self.check_error("""\ + self.check_error(""" from x import foo def foo() -> int: ...""", None, "Duplicate top-level identifier(s): foo") - self.check_error("""\ + self.check_error(""" X = ... # type: int class X: ...""", None, "Duplicate top-level identifier(s): X") - self.check_error("""\ + self.check_error(""" X = ... # type: int X = TypeVar('X')""", None, "Duplicate top-level identifier(s): X") # A function is allowed to appear multiple times. - self.check("""\ + self.check(""" def foo(x: int) -> int: ... def foo(x: str) -> str: ...""", - """\ + """ @overload def foo(x: int) -> int: ... @overload def foo(x: str) -> str: ...""") # @overload decorators should be properly round-tripped. - self.check("""\ + self.check(""" @overload def foo(x: int) -> int: ... @overload @@ -348,11 +347,11 @@ def test_type(self): self.check("x = ... # type: ?", "x: Any", prologue="from typing import Any") self.check("x: nothing") - self.check("x = ... # type: int or str or float", """\ + self.check("x = ... # type: int or str or float", """ from typing import Union x: Union[int, str, float]""") - self.check("x = ... # type: int and str and float", """\ + self.check("x = ... # type: int and str and float", """ x: int and str and float""") def test_empty_union_or_intersection_or_optional(self): @@ -368,10 +367,10 @@ def test_optional_extra_parameters(self): "Too many options to typing.Optional") def test_alias_lookup(self): - self.check("""\ + self.check(""" from somewhere import Foo x = ... # type: Foo - """, """\ + """, """ import somewhere from somewhere import Foo @@ -379,7 +378,7 @@ def test_alias_lookup(self): x: somewhere.Foo""") def test_type_params(self): - ast = self.check("""\ + ast = self.check(""" from typing import TypeVar T = TypeVar('T') @@ -403,44 +402,44 @@ def func(x: T) -> T: ...""") "Unrecognized keyword") def test_type_param_arguments(self): - self.check("""\ + self.check(""" from typing import List, TypeVar T = TypeVar('T', List[int], List[str])""") - self.check("""\ + self.check(""" from typing import List, TypeVar T = TypeVar('T', bound=List[str])""") # 'covariant' and 'contravariant' are ignored for now. - self.check("""\ + self.check(""" from typing import TypeVar - T = TypeVar('T', str, unicode, covariant=True)""", """\ + T = TypeVar('T', str, unicode, covariant=True)""", """ from typing import TypeVar T = TypeVar('T', str, unicode)""") - self.check("""\ + self.check(""" import other_mod from typing import TypeVar T = TypeVar('T', other_mod.A, other_mod.B)""") def test_error_formatting(self): - src = """\ + src = """ class Foo: this is not valid""" with self.assertRaises(parser.ParseError) as e: - parser.parse_string(textwrap.dedent(src), filename="foo.py", + parser.parse_string(textwrap.dedent(src).lstrip(), filename="foo.py", python_version=self.PYTHON_VERSION) - self.assertMultiLineEqual(textwrap.dedent("""\ + self.assertMultiLineEqual(textwrap.dedent(""" File: "foo.py", line 2 this is not valid ^ - ParseError: syntax error, unexpected NAME, expecting ':' or '='""" - ), str(e.exception)) + ParseError: syntax error, unexpected NAME, expecting ':' or '=' + """).strip("\n"), str(e.exception)) def test_pep484_translations(self): - ast = self.check("""\ + ast = self.check(""" x: None""") self.assertEqual(pytd.NamedType("NoneType"), ast.constants[0].type) @@ -466,7 +465,7 @@ def test_pep84_aliasing(self): name="typing") def test_module_class_clash(self): - ast = parser.parse_string(textwrap.dedent("""\ + ast = parser.parse_string(textwrap.dedent(""" from bar import X class bar: X = ... # type: ? @@ -477,7 +476,7 @@ class bar: self.assertEqual("bar.X.Baz", ast.Lookup("foo.z").type.name) def test_trailing_list_comma(self): - self.check("""\ + self.check(""" from typing import Any, Callable x: Callable[ @@ -487,7 +486,7 @@ def test_trailing_list_comma(self): ], Any, ] - """, """\ + """, """ from typing import Any, Callable x: Callable[[int, int], Any] @@ -497,47 +496,47 @@ def test_trailing_list_comma(self): class HomogeneousTypeTest(_ParserTestBase): def test_callable_parameters(self): - self.check("""\ + self.check(""" from typing import Callable x: Callable[[int, str], bool]""") - self.check("""\ + self.check(""" from typing import Callable - x = ... # type: Callable[..., bool]""", """\ + x = ... # type: Callable[..., bool]""", """ from typing import Any, Callable x: Callable[Any, bool]""") - self.check("""\ + self.check(""" from typing import Any, Callable x: Callable[Any, bool]""") - self.check("""\ + self.check(""" from typing import Any, Callable x: Callable[[Any], bool]""") - self.check("""\ + self.check(""" from typing import Callable x: Callable[[], bool]""") - self.check("""\ + self.check(""" from typing import Callable - x = ... # type: Callable[[nothing], bool]""", """\ + x = ... # type: Callable[[nothing], bool]""", """ from typing import Callable x: Callable[[], bool]""") - self.check("""\ + self.check(""" from typing import Callable - x = ... # type: Callable[[int]]""", """\ + x = ... # type: Callable[[int]]""", """ from typing import Any, Callable x: Callable[[int], Any]""") - self.check("""\ + self.check(""" from typing import Callable - x = ... # type: Callable[[], ...]""", """\ + x = ... # type: Callable[[], ...]""", """ from typing import Any, Callable x: Callable[[], Any]""") @@ -562,29 +561,29 @@ def test_ellipsis(self): "from typing import Tuple\n\nx: Tuple[int, ...]") def test_tuple(self): - self.check("""\ + self.check(""" from typing import Tuple x = ... # type: Tuple[int, str]""", - """\ + """ from typing import Tuple x: Tuple[int, str]""") - self.check("""\ + self.check(""" from typing import Tuple x = ... # type: Tuple[int, str, ...]""", - """\ + """ from typing import Any, Tuple x: Tuple[int, str, Any]""") def test_empty_tuple(self): - self.check("""\ + self.check(""" from typing import Tuple def f() -> Tuple[()]: ... - """, """\ + """, """ from typing import Tuple def f() -> Tuple[nothing, ...]: ... @@ -607,7 +606,7 @@ def test_type_tuple(self): class NamedTupleTest(_ParserTestBase): def test_no_fields(self): - self.check("x = ... # type: NamedTuple('foo', [])", """\ + self.check("x = ... # type: NamedTuple('foo', [])", """ from typing import Any, Tuple, Type, TypeVar x: `namedtuple-foo-0` @@ -628,7 +627,7 @@ def __init__(self, *args, **kwargs) -> None: ... """) def test_multiple_fields(self): - expected = """\ + expected = """ from typing import Any, Tuple, Type, TypeVar x: `namedtuple-foo-0` @@ -658,10 +657,10 @@ def __init__(self, *args, **kwargs) -> None: ... def test_dedup_basename(self): # pylint: disable=line-too-long - self.check("""\ + self.check(""" x = ... # type: NamedTuple('foo', [('a', int,)]) y = ... # type: NamedTuple('foo', [('b', str,)])""", - """\ + """ from typing import Any, Tuple, Type, TypeVar x: `namedtuple-foo-0` @@ -698,7 +697,7 @@ def __init__(self, *args, **kwargs) -> None: ... """) def test_assign_namedtuple(self): - self.check("X = NamedTuple('X', [])", """\ + self.check("X = NamedTuple('X', [])", """ from typing import Any, Tuple, Type, TypeVar X = `namedtuple-X-0` @@ -719,7 +718,7 @@ def __init__(self, *args, **kwargs) -> None: ... """) def test_subclass_namedtuple(self): - self.check("class X(NamedTuple('X', [])): ...", """\ + self.check("class X(NamedTuple('X', [])): ...", """ from typing import Any, Tuple, Type, TypeVar _Tnamedtuple-X-0 = TypeVar('_Tnamedtuple-X-0', bound=`namedtuple-X-0`) @@ -740,7 +739,7 @@ class X(`namedtuple-X-0`): ... """) def test_trailing_comma(self): - self.check("""\ + self.check(""" from typing import NamedTuple Foo = NamedTuple( "Foo", @@ -749,7 +748,7 @@ def test_trailing_comma(self): ("b", str), ], ) - """, """\ + """, """ from typing import Any, Tuple, Type, TypeVar Foo = `namedtuple-Foo-0` @@ -772,7 +771,7 @@ def __init__(self, *args, **kwargs) -> None: ... """) def test_collections_trailing_comma(self): - self.check("""\ + self.check(""" from collections import namedtuple Foo = namedtuple( "Foo", @@ -781,7 +780,7 @@ def test_collections_trailing_comma(self): "b", ], ) - """, """\ + """, """ from typing import Any, Tuple, Type, TypeVar from collections import namedtuple @@ -805,7 +804,7 @@ def __init__(self, *args, **kwargs) -> None: ... """) def test_collections_namedtuple(self): - expected = """\ + expected = """ from typing import Any, Tuple, Type, TypeVar from collections import namedtuple @@ -841,7 +840,7 @@ def test_typing_namedtuple_class(self): class X(NamedTuple): y: int z: str - """, """\ + """, """ from typing import Any, Tuple, Type, TypeVar _Tnamedtuple-X-0 = TypeVar('_Tnamedtuple-X-0', bound=`namedtuple-X-0`) @@ -870,7 +869,7 @@ class X(NamedTuple): y: int z: str def foo(self) -> None: ... - """, """\ + """, """ from typing import Any, Tuple, Type, TypeVar _Tnamedtuple-X-0 = TypeVar('_Tnamedtuple-X-0', bound=`namedtuple-X-0`) @@ -899,7 +898,7 @@ def test_typing_namedtuple_class_multi_inheritance(self): class X(dict, NamedTuple): y: int z: str - """, """\ + """, """ from typing import Any, Tuple, Type, TypeVar _Tnamedtuple-X-0 = TypeVar('_Tnamedtuple-X-0', bound=`namedtuple-X-0`) @@ -922,7 +921,7 @@ class X(dict, `namedtuple-X-0`): ... """) def test_multi_namedtuple_parent(self): - self.check_error("""\ + self.check_error(""" from typing import NamedTuple class X(NamedTuple, NamedTuple): ... """, 2, "cannot inherit from bare NamedTuple more than once") @@ -990,28 +989,28 @@ def test_typeignore(self): "def foo() -> int: ...") self.check("def foo(x) -> int: # type: ignore\n x=List[int]", "def foo(x) -> int:\n x = List[int]") - self.check("""\ + self.check(""" def foo(x: int, # type: ignore y: str) -> bool: ...""", "def foo(x: int, y: str) -> bool: ...") - self.check("""\ + self.check(""" class Foo: bar: str # type: ignore - """, """\ + """, """ class Foo: bar: str """) - self.check("""\ + self.check(""" class Foo: bar = ... # type: str # type: ignore - """, """\ + """, """ class Foo: bar: str """) - self.check("""\ + self.check(""" class Foo: bar: str = ... # type: ignore - """, """\ + """, """ class Foo: bar: str """) @@ -1021,65 +1020,65 @@ def test_decorators(self): # make sense for methods of classes. But this at least gives us some # coverage of the decorator logic. More sensible tests can be created once # classes are implemented. - self.check("""\ + self.check(""" @overload def foo() -> int: ...""", - """\ + """ def foo() -> int: ...""") # Accept and disregard type: ignore comments on a decorator - self.check("""\ + self.check(""" @overload def foo() -> int: ... @overload # type: ignore # unsupported signature def foo(bool) -> int: ...""", - """\ + """ @overload def foo() -> int: ... @overload def foo(bool) -> int: ...""") - self.check("""\ + self.check(""" @abstractmethod def foo() -> int: ...""", - """\ + """ @abstractmethod def foo() -> int: ...""") - self.check("""\ + self.check(""" @abc.abstractmethod def foo() -> int: ...""", - """\ + """ @abstractmethod def foo() -> int: ...""") - self.check("""\ + self.check(""" @staticmethod def foo() -> int: ...""") - self.check("""\ + self.check(""" @classmethod def foo() -> int: ...""") - self.check("""\ + self.check(""" @coroutine def foo() -> int: ...""") - self.check("""\ + self.check(""" @asyncio.coroutine def foo() -> int: ...""", - """\ + """ @coroutine def foo() -> int: ...""") - self.check("""\ + self.check(""" @asyncio.coroutine def foo() -> int: ... @coroutines.coroutine def foo() -> int: ... @coroutine def foo() -> str: ...""", - """\ + """ @coroutine @overload def foo() -> int: ... @@ -1090,7 +1089,7 @@ def foo() -> int: ... @overload def foo() -> str: ...""") - self.check_error("""\ + self.check_error(""" def foo() -> str: ... @coroutine def foo() -> int: ...""", @@ -1098,19 +1097,19 @@ def foo() -> int: ...""", "Overloaded signatures for foo disagree on " "coroutine decorators") - self.check_error("""\ + self.check_error(""" @property def foo(self) -> int""", None, "Module-level functions with property decorators: foo") - self.check_error("""\ + self.check_error(""" @foo.setter def foo(self, x) -> int: ...""", None, "Module-level functions with property decorators: foo") - self.check_error("""\ + self.check_error(""" @classmethod @staticmethod def foo() -> int: ...""", @@ -1118,21 +1117,21 @@ def foo() -> int: ...""", "Too many decorators for foo") def test_type_check_only(self): - self.check("""\ + self.check(""" from typing import type_check_only @type_check_only def f() -> None: ... """, "def f() -> None: ...") def test_type_check_only_class(self): - self.check("""\ + self.check(""" from typing import type_check_only @type_check_only class Foo: ... """, "class Foo: ...") def test_bad_decorated_class(self): - self.check_error("""\ + self.check_error(""" @classmethod class Foo: ... """, 2, "Unsupported class decorators: classmethod") @@ -1143,46 +1142,46 @@ def test_empty_body(self): "def foo() -> int: ...") self.check("def foo() -> int: pass", "def foo() -> int: ...") - self.check("""\ + self.check(""" def foo() -> int: ...""", - """\ + """ def foo() -> int: ...""") - self.check("""\ + self.check(""" def foo() -> int: pass""", - """\ + """ def foo() -> int: ...""") - self.check("""\ + self.check(""" def foo() -> int: '''doc string'''""", - """\ + """ def foo() -> int: ...""") def test_mutators(self): # Mutators. - self.check("""\ + self.check(""" def foo(x) -> int: x = int""") - self.check_error("""\ + self.check_error(""" def foo(x) -> int: y = int""", 1, "No parameter named y") def test_exceptions(self): - self.check("""\ + self.check(""" def foo(x) -> int: raise Error""", - """\ + """ def foo(x) -> int: raise Error()""") - self.check("""\ + self.check(""" def foo(x) -> int: raise Error()""") - self.check("""\ + self.check(""" def foo() -> int: raise RuntimeError() raise TypeError()""") - self.check("""\ + self.check(""" def foo() -> int: raise Bar.Error()""", prologue="import Bar") @@ -1201,83 +1200,83 @@ def test_async(self): class ClassTest(_ParserTestBase): def test_no_parents(self): - canonical = """\ + canonical = """ class Foo: ... """ self.check(canonical, canonical) - self.check("""\ + self.check(""" class Foo(): pass """, canonical) def test_parents(self): - self.check("""\ + self.check(""" class Foo(Bar): ... """) - self.check("""\ + self.check(""" class Foo(Bar, Baz): ... """) def test_parent_remove_nothingtype(self): - self.check("""\ + self.check(""" class Foo(nothing): ... - """, """\ + """, """ class Foo: ... """) - self.check("""\ + self.check(""" class Foo(Bar, nothing): ... - """, """\ + """, """ class Foo(Bar): ... """) def test_class_type_ignore(self): - canonical = """\ + canonical = """ class Foo: # type: ignore pass class Bar(Foo): # type: ignore pass """ - self.check(canonical, """\ + self.check(canonical, """ class Foo: ... class Bar(Foo): ... """) def test_metaclass(self): - self.check("""\ + self.check(""" class Foo(metaclass=Meta): ... """) - self.check("""\ + self.check(""" class Foo(Bar, metaclass=Meta): ... """) - self.check_error("""\ + self.check_error(""" class Foo(badkeyword=Meta): ... """, 1, "Only 'metaclass' allowed as classdef kwarg") - self.check_error("""\ + self.check_error(""" class Foo(metaclass=Meta, Bar): ... """, 1, "metaclass must be last argument") def test_shadow_pep484(self): - self.check("""\ + self.check(""" class List: def bar(self) -> List: ... """) def test_no_body(self): - canonical = """\ + canonical = """ class Foo: ... """ # There are numerous ways to indicate an empty body. self.check(canonical, canonical) - self.check("""\ + self.check(""" class Foo(): pass """, canonical) - self.check("""\ + self.check(""" class Foo(): pass """, canonical) - self.check("""\ + self.check(""" class Foo(): ... """, canonical) @@ -1292,49 +1291,49 @@ class Foo(): """docstring""" ''', canonical) # Accept type: ignore with empty body - self.check("""\ + self.check(""" class Foo: ... # type: ignore """, canonical) - self.check("""\ + self.check(""" class Foo: # type: ignore pass """, canonical) def test_attribute(self): - self.check("""\ + self.check(""" class Foo: a: int """) def test_method(self): - self.check("""\ + self.check(""" class Foo: def a(self, x: int) -> str: ... """) def test_property(self): - self.check("""\ + self.check(""" class Foo: @property def a(self) -> int - """, """\ + """, """ class Foo: a: int """) def test_duplicate_name(self): - self.check_error("""\ + self.check_error(""" class Foo: bar = ... # type: int bar = ... # type: str """, 1, "Duplicate identifier(s): bar") - self.check_error("""\ + self.check_error(""" class Foo: def bar(self) -> int: ... bar = ... # type: str """, 1, "Duplicate identifier(s): bar") # Multiple method defs are ok (needed for variant signatures). - self.check("""\ + self.check(""" class Foo: @overload def x(self) -> int: ... @@ -1343,20 +1342,20 @@ def x(self) -> str: ... """) def test_protocol_parent(self): - self.check("""\ + self.check(""" from typing import Protocol class Foo(Protocol): ... """) def test_parameterized_protocol_parent(self): - self.check("""\ + self.check(""" from typing import Protocol, TypeVar T = TypeVar('T') class Foo(Protocol[T]): ... - """, """\ + """, """ from typing import Generic, Protocol, TypeVar T = TypeVar('T') @@ -1365,7 +1364,7 @@ class Foo(Protocol, Generic[T]): ... """) def test_bad_typevar_in_mutation(self): - self.check_error("""\ + self.check_error(""" from typing import Generic, TypeVar S = TypeVar('S') @@ -1382,71 +1381,71 @@ def __init__(self, x: S): class IfTest(_ParserTestBase): def test_if_true(self): - self.check("""\ + self.check(""" if sys.version_info == (2, 7, 6): x = ... # type: int - """, """\ + """, """ x: int""") def test_if_false(self): - self.check("""\ + self.check(""" if sys.version_info == (1, 2, 3): x = ... # type: int """, "") def test_else_used(self): - self.check("""\ + self.check(""" if sys.version_info == (1, 2, 3): x = ... # type: int else: y = ... # type: str - """, """\ + """, """ y: str""") def test_else_ignored(self): - self.check("""\ + self.check(""" if sys.version_info == (2, 7, 6): x = ... # type: int else: y = ... # type: str - """, """\ + """, """ x: int""") def test_elif_used(self): - self.check("""\ + self.check(""" if sys.version_info == (1, 2, 3): x = ... # type: int elif sys.version_info == (2, 7, 6): y = ... # type: float else: z = ... # type: str - """, """\ + """, """ y: float""") def test_elif_preempted(self): - self.check("""\ + self.check(""" if sys.version_info > (1, 2, 3): x = ... # type: int elif sys.version_info == (2, 7, 6): y = ... # type: float else: z = ... # type: str - """, """\ + """, """ x: int""") def test_elif_ignored(self): - self.check("""\ + self.check(""" if sys.version_info == (1, 2, 3): x = ... # type: int elif sys.version_info == (4, 5, 6): y = ... # type: float else: z = ... # type: str - """, """\ + """, """ z: str""") def test_nested_if(self): - self.check("""\ + self.check(""" if sys.version_info >= (2, 0): if sys.platform == "linux": a = ... # type: int @@ -1460,7 +1459,7 @@ def test_nested_if(self): """, "a: int") def test_if_or(self): - self.check("""\ + self.check(""" if sys.version_info >= (2, 0) or sys.version_info < (0, 0, 0): a = ... # type: int if sys.version_info < (0, 0, 0) or sys.version_info >= (2, 0): @@ -1472,26 +1471,26 @@ def test_if_or(self): if (sys.platform == "windows" or sys.version_info < (0,) or sys.version_info >= (2, 7)): e = ... # type: int - """, """\ + """, """ a: int b: int d: int e: int""") def test_if_and(self): - self.check("""\ + self.check(""" if sys.version_info >= (2, 0) and sys.version_info < (3, 0): a = ... # type: int if sys.version_info >= (2, 0) and sys.version_info >= (3, 0): b = ... # type: int - """, """\ + """, """ a: int""") # The remaining tests verify that actions with side effects only take effect # within a true block. def test_conditional_import(self): - self.check("""\ + self.check(""" if sys.version_info == (2, 7, 6): from foo import Processed else: @@ -1499,7 +1498,7 @@ def test_conditional_import(self): """, "from foo import Processed") def test_conditional_alias_or_constant(self): - self.check("""\ + self.check(""" if sys.version_info == (2, 7, 6): x = Processed else: @@ -1507,12 +1506,12 @@ def test_conditional_alias_or_constant(self): """, "x = Processed") def test_conditional_class(self): - self.check("""\ + self.check(""" if sys.version_info == (2, 7, 6): class Processed: ... else: class Ignored: ... - """, """\ + """, """ class Processed: ... """) @@ -1525,7 +1524,7 @@ def test_conditional_class_registration(self): # Dict should be registered, List should not be registered. Thus after # the "if" statement Dict refers to the local Dict class and List refers # to the PEP 484 list class. - self.check("""\ + self.check(""" from typing import List if sys.version_info == (2, 7, 6): class Dict: ... @@ -1534,7 +1533,7 @@ class List: ... x = ... # type: Dict y = ... # type: List - """, """\ + """, """ x: Dict y: list @@ -1544,12 +1543,12 @@ class Dict: ... def test_conditional_typevar(self): # The legacy parser did not handle this correctly - typevars are added # regardless of any conditions. - self.check("""\ + self.check(""" if sys.version_info == (2, 7, 6): T = TypeVar('T') else: F = TypeVar('F') - """, """\ + """, """ from typing import TypeVar T = TypeVar('T')""") @@ -1564,7 +1563,7 @@ class ClassIfTest(_ParserTestBase): # etc). def test_conditional_constant(self): - self.check("""\ + self.check(""" class Foo: if sys.version_info == (2, 7, 0): x = ... # type: int @@ -1572,13 +1571,13 @@ class Foo: y = ... # type: str else: z = ... # type: float - """, """\ + """, """ class Foo: y: str """) def test_conditional_method(self): - self.check("""\ + self.check(""" class Foo: if sys.version_info == (2, 7, 0): def a(self, x: int) -> str: ... @@ -1586,47 +1585,47 @@ def a(self, x: int) -> str: ... def b(self, x: int) -> str: ... else: def c(self, x: int) -> str: ... - """, """\ + """, """ class Foo: def b(self, x: int) -> str: ... """) def test_nested(self): - self.check("""\ + self.check(""" class Foo: if sys.version_info > (2, 7, 0): if sys.version_info == (2, 7, 6): def b(self, x: int) -> str: ... - """, """\ + """, """ class Foo: def b(self, x: int) -> str: ... """) def test_no_import(self): - self.check_error("""\ + self.check_error(""" class Foo: if sys.version_info > (2, 7, 0): import foo """, 3, "syntax error") def test_bad_alias(self): - self.check_error("""\ + self.check_error(""" class Foo: if sys.version_info > (2, 7, 0): a = b """, 1, "Illegal value for alias 'a'") def test_no_class(self): - self.check("""\ + self.check(""" class Foo: if sys.version_info <= (2, 7, 0): class Bar: ... - """, """\ + """, """ class Foo: ... """) def test_no_typevar(self): - self.check_error("""\ + self.check_error(""" class Foo: if sys.version_info > (2, 7, 0): T = TypeVar('T') @@ -1637,13 +1636,13 @@ class ConditionTest(_ParserTestBase): def check_cond(self, condition, expected, **kwargs): out = "x: int" if expected else "" - self.check("""\ + self.check(""" if %s: x = ... # type: int """ % condition, out, **kwargs) def check_cond_error(self, condition, message): - self.check_error("""\ + self.check_error(""" if %s: x = ... # type: int """ % condition, 1, message) @@ -1772,7 +1771,7 @@ class PropertyDecoratorTest(_ParserTestBase): """Tests that cover _parse_signature_as_property().""" def test_property_with_type(self): - expected = """\ + expected = """ class A(object): name: str """ @@ -1788,7 +1787,7 @@ def name(self) -> str:... class A(object): @name.setter def name(self, value: str) -> None: ... - """, """\ + """, """ from typing import Any class A(object): @@ -1823,7 +1822,7 @@ def name(self, value: int) -> None: ... """, expected) def test_property_decorator_any_type(self): - expected = """\ + expected = """ from typing import Any class A(object): @@ -1862,32 +1861,32 @@ def test_property_decorator_bad_syntax(self): class A(object): @property def name(self, bad_arg): ... - """, 2, "Unhandled decorator: property") + """, 1, "Unhandled decorator: property") self.check_error(""" class A(object): @name.setter def name(self): ... - """, 2, "Unhandled decorator: name.setter") + """, 1, "Unhandled decorator: name.setter") self.check_error(""" class A(object): @name.foo def name(self): ... - """, 2, "Unhandled decorator: name.foo") + """, 1, "Unhandled decorator: name.foo") self.check_error(""" class A(object): @notname.deleter def name(self): ... - """, 2, "Unhandled decorator: notname.deleter") + """, 1, "Unhandled decorator: notname.deleter") self.check_error(""" class A(object): @property @staticmethod def name(self): ... - """, 5, "Too many decorators for name") + """, 4, "Too many decorators for name") self.check_error(""" @property @@ -1902,7 +1901,7 @@ def name(self) -> str: ... @name.getter def name(self) -> int: ... - """, """\ + """, """ from typing import Union class A(object): @@ -1917,7 +1916,7 @@ def test_property(self): class A(object): @property def name(self) -> str: ... - """, """\ + """, """ class A(object): name: str """) @@ -1930,7 +1929,7 @@ def name(self) -> str: ... @property def name(self) -> int: ... - """, """\ + """, """ from typing import Union class A(object): @@ -1944,7 +1943,7 @@ def name(self) -> str: ... @property def name(self): ... - """, """\ + """, """ from typing import Any class A(object): @@ -1952,16 +1951,16 @@ class A(object): """) def test_method(self): - self.check("""\ + self.check(""" class A(object): def name(self) -> str: ... """) def test_merged_method(self): - ast = self.check("""\ + ast = self.check(""" def foo(x: int) -> str: ... def foo(x: str) -> str: ...""", - """\ + """ @overload def foo(x: int) -> str: ... @overload @@ -1977,7 +1976,7 @@ class A(object): def name(self): ... def name(self): ... - """, 2, "Overloaded signatures for name disagree on decorators") + """, 1, "Overloaded signatures for name disagree on decorators") def test_overloaded_signatures_disagree(self): self.check_error(""" @@ -1986,10 +1985,10 @@ class A(object): def foo(x: int): ... @classmethod def foo(x: str): ... - """, 2, "Overloaded signatures for foo disagree on decorators") + """, 1, "Overloaded signatures for foo disagree on decorators") def test_classmethod(self): - ast = self.check("""\ + ast = self.check(""" class A(object): @classmethod def foo(x: int) -> str: ... @@ -1997,7 +1996,7 @@ def foo(x: int) -> str: ... self.assertEqual("classmethod", ast.classes[0].methods[0].kind) def test_staticmethod(self): - ast = self.check("""\ + ast = self.check(""" class A(object): @staticmethod def foo(x: int) -> str: ... @@ -2005,14 +2004,14 @@ def foo(x: int) -> str: ... self.assertEqual("staticmethod", ast.classes[0].methods[0].kind) def test_new(self): - ast = self.check("""\ + ast = self.check(""" class A(object): def __new__(self) -> A: ... """) self.assertEqual("staticmethod", ast.classes[0].methods[0].kind) def test_abstractmethod(self): - ast = self.check("""\ + ast = self.check(""" class A(object): @abstractmethod def foo(x: int) -> str: ... @@ -2021,7 +2020,7 @@ def foo(x: int) -> str: ... self.assertEqual(True, ast.Lookup("A").Lookup("foo").is_abstract) def test_abstractmethod_manysignatures(self): - ast = self.check("""\ + ast = self.check(""" class A(object): @abstractmethod def foo(x: int) -> str: ... @@ -2029,7 +2028,7 @@ def foo(x: int) -> str: ... def foo(x: int, y: int) -> str: ... @abstractmethod def foo(x: int, y: int, z: int) -> str: ... - """, """\ + """, """ class A(object): @abstractmethod @overload @@ -2045,7 +2044,7 @@ def foo(x: int, y: int, z: int) -> str: ... self.assertEqual(True, ast.Lookup("A").Lookup("foo").is_abstract) def test_abstractmethod_conflict(self): - self.check_error("""\ + self.check_error(""" class A(object): @abstractmethod def foo(x: int) -> str: ... @@ -2063,21 +2062,21 @@ def test_builtins(self): class AnyTest(_ParserTestBase): def test_generic_any(self): - self.check("""\ + self.check(""" from typing import Any x = ... # type: Any[int]""", - """\ + """ from typing import Any x: Any""") def test_generic_any_alias(self): - self.check("""\ + self.check(""" from typing import Any Foo = Any Bar = Foo[int] x = ... # type: Bar[int, str]""", - """\ + """ from typing import Any Foo = Any @@ -2094,13 +2093,14 @@ def testCanonicalVersion(self): def foo(x: int = 0) -> Any: ... def foo(x: str) -> Any: ... """) - expected = textwrap.dedent("""\ + expected = textwrap.dedent(""" from typing import Any @overload def foo(x: int = ...) -> Any: ... @overload - def foo(x: str) -> Any: ...""") + def foo(x: str) -> Any: ... + """).strip() self.assertMultiLineEqual( parser.canonical_pyi(src, self.PYTHON_VERSION), expected) @@ -2108,13 +2108,13 @@ def foo(x: str) -> Any: ...""") class TypeMacroTest(_ParserTestBase): def test_simple(self): - self.check("""\ + self.check(""" from typing import List, TypeVar Alias = List[List[T]] T = TypeVar('T') S = TypeVar('S') def f(x: Alias[S]) -> S: ... - def g(x: Alias[str]) -> str: ...""", """\ + def g(x: Alias[str]) -> str: ...""", """ from typing import List, TypeVar Alias = List[List[T]] @@ -2126,11 +2126,11 @@ def f(x: List[List[S]]) -> S: ... def g(x: List[List[str]]) -> str: ...""") def test_partial_replacement(self): - self.check("""\ + self.check(""" from typing import Dict, TypeVar DictAlias = Dict[int, V] V = TypeVar('V') - def f(x: DictAlias[str]) -> None: ...""", """\ + def f(x: DictAlias[str]) -> None: ...""", """ from typing import Dict, TypeVar DictAlias = Dict[int, V] @@ -2140,12 +2140,12 @@ def f(x: DictAlias[str]) -> None: ...""", """\ def f(x: Dict[int, str]) -> None: ...""") def test_multiple_parameters(self): - self.check("""\ + self.check(""" from typing import Dict, List, TypeVar Alias = List[Dict[K, V]] K = TypeVar('K') V = TypeVar('V') - def f(x: Alias[K, V]) -> Dict[K, V]: ...""", """\ + def f(x: Alias[K, V]) -> Dict[K, V]: ...""", """ from typing import Dict, List, TypeVar Alias = List[Dict[K, V]] @@ -2156,11 +2156,11 @@ def f(x: Alias[K, V]) -> Dict[K, V]: ...""", """\ def f(x: List[Dict[K, V]]) -> Dict[K, V]: ...""") def test_no_parameters(self): - self.check("""\ + self.check(""" from typing import List, TypeVar Alias = List[List[T]] T = TypeVar('T') - def f(x: Alias) -> None: ...""", """\ + def f(x: Alias) -> None: ...""", """ from typing import Any, List, TypeVar Alias = List[List[T]] @@ -2170,12 +2170,12 @@ def f(x: Alias) -> None: ...""", """\ def f(x: List[List[Any]]) -> None: ...""") def test_union(self): - self.check("""\ + self.check(""" from typing import List, TypeVar, Union Alias = Union[List[T], List[S]] T = TypeVar('T') S = TypeVar('S') - def f(x: Alias[S, T]) -> Union[S, T]: ...""", """\ + def f(x: Alias[S, T]) -> Union[S, T]: ...""", """ from typing import List, TypeVar, Union Alias = Union[List[T], List[S]] @@ -2186,11 +2186,11 @@ def f(x: Alias[S, T]) -> Union[S, T]: ...""", """\ def f(x: Union[List[S], List[T]]) -> Union[S, T]: ...""") def test_repeated_type_parameter(self): - self.check("""\ + self.check(""" from typing import Dict, TypeVar Alias = Dict[T, T] T = TypeVar('T') - def f(x: Alias[str]) -> None: ...""", """\ + def f(x: Alias[str]) -> None: ...""", """ from typing import Dict, TypeVar Alias = Dict[T, T] @@ -2200,7 +2200,7 @@ def f(x: Alias[str]) -> None: ...""", """\ def f(x: Dict[str, str]) -> None: ...""") def test_wrong_parameter_count(self): - self.check_error("""\ + self.check_error(""" from typing import List, TypeVar Alias = List[List[T]] T = TypeVar('T') @@ -2208,11 +2208,11 @@ def f(x: Alias[T, T]) -> T: ... """, 4, "List[List[T]] expected 1 parameters, got 2") def test_anystr(self): - self.check("""\ + self.check(""" from typing import AnyStr, List Alias = List[AnyStr] def f(x: Alias[str]) -> None: ... - """, """\ + """, """ from typing import AnyStr, List Alias = List[AnyStr] @@ -2227,7 +2227,7 @@ def test_import(self): self.check(""" import mod # type: ignore def f(x: mod.attr) -> None: ... - """, """\ + """, """ import mod def f(x: mod.attr) -> None: ...""") @@ -2263,7 +2263,7 @@ def f(x: attr) -> None: ... class LiteralTest(_ParserTestBase): def test_bool(self): - self.check("""\ + self.check(""" from typing import Literal x: Literal[False] @@ -2271,14 +2271,14 @@ def test_bool(self): """) def test_int(self): - self.check("""\ + self.check(""" from typing import Literal x: Literal[42] """) def test_string(self): - self.check("""\ + self.check(""" from typing import Literal x: Literal["x"] @@ -2286,7 +2286,7 @@ def test_string(self): """) def test_bytestring(self): - self.check("""\ + self.check(""" from typing import Literal x: Literal[b""] @@ -2295,7 +2295,7 @@ def test_bytestring(self): """) def test_unicodestring(self): - self.check("""\ + self.check(""" from typing import Literal x: Literal[u""] @@ -2304,7 +2304,7 @@ def test_unicodestring(self): """) def test_none(self): - self.check("""\ + self.check(""" from typing import Literal x: Literal[None] @@ -2312,7 +2312,7 @@ def test_none(self): def test_enum(self): # TODO(b/123775699): support enums. - self.check("""\ + self.check(""" import enum from typing import Literal @@ -2320,7 +2320,7 @@ def test_enum(self): class Color(enum.Enum): RED: str - """, """\ + """, """ import enum from typing import Any @@ -2331,46 +2331,46 @@ class Color(enum.Enum): """) def test_multiple_parameters(self): - self.check("""\ + self.check(""" from typing import Literal x: Literal[True, 0, b"", u"", None] - """, """\ + """, """ from typing import Literal, Optional, Union x: Optional[Union[Literal[True], Literal[0], Literal[b""], Literal[u""]]] """) def test_stray_number(self): - self.check_error("""\ + self.check_error(""" from typing import Tuple x: Tuple[int, int, 0, int] """, 3, "Tuple[_, _, 0, _] not supported") def test_stray_string(self): - self.check_error("""\ + self.check_error(""" from typing import Tuple x: Tuple[str, str, '', str] """, 3, "Tuple[_, _, '', _] not supported") def test_stray_bytestring(self): - self.check_error("""\ + self.check_error(""" from typing import Tuple x: Tuple[str, b'', str, str] """, 3, "Tuple[_, b'', _, _] not supported") def test_stray_unicodestring(self): - self.check_error("""\ + self.check_error(""" from typing import Tuple x: Tuple[str, u'', str, str] """, 3, "Tuple[_, u'', _, _] not supported") def test_typing_extensions(self): - self.check("""\ + self.check(""" from typing_extensions import Literal x: Literal[42] diff --git a/pytype/pytd/optimize_test.py b/pytype/pytd/optimize_test.py index cb4438011..d3db843a4 100644 --- a/pytype/pytd/optimize_test.py +++ b/pytype/pytd/optimize_test.py @@ -769,10 +769,10 @@ class B(A): ast = visitors.LookupClasses(ast, self.builtins) ast = ast.Visit(optimize.AddInheritedMethods()) self.assertMultiLineEqual(pytd_utils.Print(ast.Lookup("B")), - textwrap.dedent("""\ + textwrap.dedent(""" class B(A): def f(self) -> float: ... - """)) + """).lstrip()) def testRemoveInheritedMethodsWithLateType(self): src = textwrap.dedent(""" diff --git a/pytype/pytd/parse/parser_constants.py b/pytype/pytd/parse/parser_constants.py index 81e656b9d..295ce86cf 100644 --- a/pytype/pytd/parse/parser_constants.py +++ b/pytype/pytd/parse/parser_constants.py @@ -49,7 +49,7 @@ 'yield', ] -# parser.t_NAME's regexp allows a few extra characters in the name. +# parser.t_NAME's regex allows a few extra characters in the name. # A less-pedantic RE is r'[-~]'. # See visitors._EscapedName and parser.PyLexer.t_NAME BACKTICK_NAME = re.compile(r'[-]|^~') diff --git a/pytype/pytd/parse/preconditions_test.py b/pytype/pytd/parse/preconditions_test.py index fdf30976e..9bff3029a 100644 --- a/pytype/pytd/parse/preconditions_test.py +++ b/pytype/pytd/parse/preconditions_test.py @@ -14,6 +14,7 @@ from pytype.pytd.parse import preconditions +import six import unittest @@ -29,8 +30,8 @@ class SubClass(BaseClass): class PreconditionsTest(unittest.TestCase): def assertError(self, regex, condition, value): - self.assertRaisesRegexp( - preconditions.PreconditionError, regex, condition.check, value) + six.assertRaisesRegex( + self, preconditions.PreconditionError, regex, condition.check, value) def testClassNamePrecondition(self): c = preconditions._ClassNamePrecondition("str") @@ -69,6 +70,7 @@ def testIsInstancePrecondition(self): class CallCheckerTest(unittest.TestCase): def setUp(self): + super(CallCheckerTest, self).setUp() self.checker = preconditions.CallChecker([ ("x", preconditions._ClassNamePrecondition("int")), ("s", preconditions._ClassNamePrecondition("str"))]) @@ -77,8 +79,8 @@ def testAllowedTypes(self): self.assertEqual({"int", "str"}, self.checker.allowed_types()) def assertError(self, regex, *args, **kwargs): - self.assertRaisesRegexp( - preconditions.PreconditionError, regex, self.checker.check, *args, + six.assertRaisesRegex( + self, preconditions.PreconditionError, regex, self.checker.check, *args, **kwargs) def testPositionalArgs(self): diff --git a/pytype/pytd/pytd_utils_test.py b/pytype/pytd/pytd_utils_test.py index 2cd4ad505..75f6471d8 100644 --- a/pytype/pytd/pytd_utils_test.py +++ b/pytype/pytd/pytd_utils_test.py @@ -445,22 +445,22 @@ def foo(a: str or int) -> C self.assertTrue(pytd_utils.ASTeq(tree2, tree2)) def testASTdiff(self): - src1 = textwrap.dedent("""\ + src1 = textwrap.dedent(""" a: int - b: str""") - src2 = textwrap.dedent("""\ + b: str""").lstrip() + src2 = textwrap.dedent(""" a: int - b: float""") + b: float""").lstrip() tree1 = parser.parse_string(src1, python_version=self.PYTHON_VERSION) tree2 = parser.parse_string(src2, python_version=self.PYTHON_VERSION) normalize = lambda diff: textwrap.dedent("\n".join(diff)) self.assertEqual(normalize(pytd_utils.ASTdiff(tree1, tree1)), src1) self.assertEqual(normalize(pytd_utils.ASTdiff(tree2, tree2)), src2) diff_pattern = r"(?s)- b.*\+ b" - self.assertRegexpMatches(normalize(pytd_utils.ASTdiff(tree1, tree2)), - diff_pattern) - self.assertRegexpMatches(normalize(pytd_utils.ASTdiff(tree2, tree1)), - diff_pattern) + six.assertRegex(self, normalize(pytd_utils.ASTdiff(tree1, tree2)), + diff_pattern) + six.assertRegex(self, normalize(pytd_utils.ASTdiff(tree2, tree1)), + diff_pattern) class TestDataFiles(parser_test_base.ParserTest): @@ -477,8 +477,8 @@ def testGetPredefinedFileBasic(self): def testGetPredefinedFileThrows(self): # smoke test, only checks that it does throw - with self.assertRaisesRegexp( - IOError, + with six.assertRaisesRegex( + self, IOError, r"File not found|Resource not found|No such file or directory"): pytd_utils.GetPredefinedFile(self.BUILTINS, "-this-file-does-not-exist") diff --git a/pytype/pytd/serialize_ast_test.py b/pytype/pytd/serialize_ast_test.py index e43bcd46f..d2fa60f0f 100644 --- a/pytype/pytd/serialize_ast_test.py +++ b/pytype/pytd/serialize_ast_test.py @@ -89,8 +89,8 @@ def testNodeIndexVisitorUsage(self): serialized_ast.class_type_nodes)[1:]) loaded_ast = serialize_ast.ProcessAst(serialized_ast, module_map) - with self.assertRaisesRegexp( - ValueError, "Unresolved class: '__builtin__.NoneType'"): + with six.assertRaisesRegex( + self, ValueError, "Unresolved class: '__builtin__.NoneType'"): loaded_ast.Visit(visitors.VerifyLookup()) def testPickle(self): diff --git a/pytype/pytd/visitors_test.py b/pytype/pytd/visitors_test.py index 1401baa00..966ddf805 100644 --- a/pytype/pytd/visitors_test.py +++ b/pytype/pytd/visitors_test.py @@ -299,10 +299,11 @@ class A(object): ... ast2 = ast2.Visit(visitors.LookupExternalTypes( {"foo": ast1}, self_name=None)) self.assertEqual(name, ast2.name) - self.assertMultiLineEqual(pytd_utils.Print(ast2), textwrap.dedent("""\ + self.assertMultiLineEqual(pytd_utils.Print(ast2), textwrap.dedent(""" import foo - A = foo.A""")) + A = foo.A + """).strip()) def testLookupTwoStarAliases(self): src1 = "class A(object): ..." @@ -359,10 +360,11 @@ def testLookupTwoStarAliasesWithDefaultPyi(self): ast3 = self.Parse(src3).Replace(name="baz").Visit(visitors.AddNamePrefix()) ast3 = ast3.Visit(visitors.LookupExternalTypes( {"foo": ast1, "bar": ast2, "baz": ast3}, self_name="baz")) - self.assertMultiLineEqual(pytd_utils.Print(ast3), textwrap.dedent("""\ + self.assertMultiLineEqual(pytd_utils.Print(ast3), textwrap.dedent(""" from typing import Any - def baz.__getattr__(name) -> Any: ...""")) + def baz.__getattr__(name) -> Any: ... + """).strip()) def testLookupStarAliasWithDuplicateGetAttr(self): src1 = "def __getattr__(name) -> ?" @@ -374,10 +376,11 @@ def __getattr__(name) -> ? ast2 = self.Parse(src2).Replace(name="bar").Visit(visitors.AddNamePrefix()) ast2 = ast2.Visit(visitors.LookupExternalTypes( {"foo": ast1, "bar": ast2}, self_name="bar")) - self.assertMultiLineEqual(pytd_utils.Print(ast2), textwrap.dedent("""\ + self.assertMultiLineEqual(pytd_utils.Print(ast2), textwrap.dedent(""" from typing import Any - def bar.__getattr__(name) -> Any: ...""")) + def bar.__getattr__(name) -> Any: ... + """).strip()) def testLookupTwoStarAliasesWithDifferentGetAttrs(self): src1 = "def __getattr__(name) -> int" @@ -402,8 +405,9 @@ def __getattr__(name) -> str ast2 = self.Parse(src2).Replace(name="bar").Visit(visitors.AddNamePrefix()) ast2 = ast2.Visit(visitors.LookupExternalTypes( {"foo": ast1, "bar": ast2}, self_name="bar")) - self.assertMultiLineEqual(pytd_utils.Print(ast2), textwrap.dedent("""\ - def bar.__getattr__(name) -> str: ...""")) + self.assertMultiLineEqual(pytd_utils.Print(ast2), textwrap.dedent(""" + def bar.__getattr__(name) -> str: ... + """).strip()) def testCollectDependencies(self): src = textwrap.dedent(""" @@ -446,12 +450,13 @@ def testPrintImports(self): def f(x: Union[int, slice]) -> List[?]: ... def g(x: foo.C.C2) -> None: ... """) - expected = textwrap.dedent("""\ + expected = textwrap.dedent(""" import foo.C from typing import Any, List, Union def f(x: Union[int, slice]) -> List[Any]: ... - def g(x: foo.C.C2) -> None: ...""") + def g(x: foo.C.C2) -> None: ... + """).strip() tree = self.Parse(src) res = pytd_utils.Print(tree) self.AssertSourceEquals(res, src) @@ -712,7 +717,7 @@ class D: b: A.B def f(self, x: A.B) -> A.B: ... """) - expected = textwrap.dedent("""\ + expected = textwrap.dedent(""" from typing import Type foo.b: foo.A.B @@ -725,7 +730,8 @@ class foo.D: b: foo.A.B def f(self, x: foo.A.B) -> foo.A.B: ... - def foo.f(x: foo.A.B) -> foo.A.B: ...""") + def foo.f(x: foo.A.B) -> foo.A.B: ... + """).strip() self.assertMultiLineEqual(expected, pytd_utils.Print( self.Parse(src).Replace(name="foo").Visit(visitors.AddNamePrefix()))) @@ -735,10 +741,11 @@ class A: class B: def copy(self) -> A.B: ... """) - expected = textwrap.dedent("""\ + expected = textwrap.dedent(""" class foo.A: class foo.A.B: - def copy(self) -> foo.A.B: ...""") + def copy(self) -> foo.A.B: ... + """).strip() self.assertMultiLineEqual(expected, pytd_utils.Print( self.Parse(src).Replace(name="foo").Visit(visitors.AddNamePrefix()))) @@ -988,10 +995,10 @@ def testPrintTypeParameterBound(self): T = TypeVar("T", bound=str) """) self.assertMultiLineEqual(pytd_utils.Print(self.Parse(src)), - textwrap.dedent("""\ + textwrap.dedent(""" from typing import TypeVar - T = TypeVar('T', bound=str)""")) + T = TypeVar('T', bound=str)""").lstrip()) def testPrintCls(self): src = textwrap.dedent(""" @@ -1009,10 +1016,10 @@ def testPrintNoReturn(self): def f() -> nothing """) self.assertMultiLineEqual(pytd_utils.Print(self.Parse(src)), - textwrap.dedent("""\ + textwrap.dedent(""" from typing import NoReturn - def f() -> NoReturn: ...""")) + def f() -> NoReturn: ...""").lstrip()) def testPrintMultilineSignature(self): src = textwrap.dedent(""" @@ -1021,14 +1028,15 @@ def f(x: int, y: str, z: bool) -> list[str]: """) self.assertMultiLineEqual( pytd_utils.Print(self.Parse(src), multiline_args=True), - textwrap.dedent("""\ + textwrap.dedent(""" from typing import List def f( x: int, y: str, z: bool - ) -> List[str]: ...""")) + ) -> List[str]: ... + """).strip()) def testRenameBuiltinsPrefix(self): """builtins.foo should get rewritten to __builtin__.foo and then to foo.""" diff --git a/pytype/single_test.py b/pytype/single_test.py index ef06b31bd..a530ab92a 100644 --- a/pytype/single_test.py +++ b/pytype/single_test.py @@ -351,13 +351,13 @@ def testCheck(self): self._CheckTypesAndErrors("simple.py", []) def testReturnType(self): - self._CheckTypesAndErrors(self._MakePyFile("""\ + self._CheckTypesAndErrors(self._MakePyFile(""" def f() -> int: return "foo" """), ["bad-return-type"]) def testUsageError(self): - self._SetUpChecking(self._MakePyFile("""\ + self._SetUpChecking(self._MakePyFile(""" def f(): pass """)) @@ -368,7 +368,7 @@ def f(): self.assertOutputStateMatches(stdout=False, stderr=True, returncode=True) def testSkipFile(self): - filename = self._MakePyFile("""\ + filename = self._MakePyFile(""" # pytype: skip-file """) self.pytype_args[self._DataPath(filename)] = self.INCLUDE @@ -395,7 +395,7 @@ def testInferComplex(self): self.assertInferredPyiEquals(filename="complex.pyi") def testCheckMain(self): - self._SetUpChecking(self._MakePyFile("""\ + self._SetUpChecking(self._MakePyFile(""" def f(): name_error def g(): @@ -441,14 +441,14 @@ def testPytree(self): [c.name for c in ast.classes]) def testNoAnalyzeAnnotated(self): - filename = self._MakePyFile("""\ + filename = self._MakePyFile(""" def f() -> str: return 42 """) self._InferTypesAndCheckErrors(self._DataPath(filename), []) def testAnalyzeAnnotated(self): - filename = self._MakePyFile("""\ + filename = self._MakePyFile(""" def f() -> str: return 42 """) @@ -476,7 +476,7 @@ def testGenerateAndUseBuiltins(self): self._RunPytype(self.pytype_args) self.assertOutputStateMatches(stdout=False, stderr=False, returncode=False) self.assertTrue(os.path.isfile(filename)) - src = self._MakePyFile("""\ + src = self._MakePyFile(""" import __future__ import sys import collections @@ -499,7 +499,7 @@ def testUseBuiltinsAndImportMap(self): self.assertTrue(os.path.isfile(filename)) # input files canary = "import pytypecanary" if typeshed.Typeshed.MISSING_FILE else "" - src = self._MakePyFile("""\ + src = self._MakePyFile(""" import __future__ import sys import collections @@ -514,7 +514,7 @@ def testUseBuiltinsAndImportMap(self): y = csv.writer z = md5.new """ % canary) - pyi = self._MakeFile("""\ + pyi = self._MakeFile(""" import datetime x = ... # type: datetime.tzinfo """, extension=".pyi") @@ -522,7 +522,7 @@ def testUseBuiltinsAndImportMap(self): self._ResetPytypeArgs() self._SetUpChecking(src) self.pytype_args["--precompiled-builtins"] = filename - self.pytype_args["--imports_info"] = self._MakeFile("""\ + self.pytype_args["--imports_info"] = self._MakeFile(""" typing /dev/null foo %s """ % pyi, extension="") diff --git a/pytype/tests/CMakeLists.txt b/pytype/tests/CMakeLists.txt index 4b99ebecc..34fd13064 100644 --- a/pytype/tests/CMakeLists.txt +++ b/pytype/tests/CMakeLists.txt @@ -18,6 +18,7 @@ py_test( test_base_test.py DEPS .test_base + pytype.utils ) py_test( diff --git a/pytype/tests/py2/test_abc.py b/pytype/tests/py2/test_abc.py index e396f67f2..f58045301 100644 --- a/pytype/tests/py2/test_abc.py +++ b/pytype/tests/py2/test_abc.py @@ -7,27 +7,26 @@ class AbstractMethodTests(test_base.TargetPython27FeatureTest): """Tests for @abc.abstractmethod.""" def test_name_error(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" import abc class Example(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def foo(self): - name_error + name_error # name-error """) - self.assertErrorLogIs(errors, [(6, "name-error", r"name_error")]) def test_instantiate_abstract_class(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import abc class Example(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def foo(self): pass - Example() # line 7 + Example() # not-instantiable[e] """) - self.assertErrorLogIs(errors, [(7, "not-instantiable", r"Example.*foo")]) + self.assertErrorRegexes(errors, {"e": r"Example.*foo"}) def test_multiple_inheritance_implementation(self): self.Check(""" @@ -48,7 +47,7 @@ class Foo(X, Implementation): """) def test_multiple_inheritance_error(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import abc class X(object): pass @@ -59,9 +58,9 @@ def foo(self): pass class Foo(X, Interface): pass - Foo().foo() # line 11 + Foo().foo() # not-instantiable[e] """) - self.assertErrorLogIs(errors, [(11, "not-instantiable", r"Foo.*foo")]) + self.assertErrorRegexes(errors, {"e": r"Foo.*foo"}) def test_multiple_inheritance_builtins(self): self.Check(""" diff --git a/pytype/tests/py2/test_attributes.py b/pytype/tests/py2/test_attributes.py index b48803837..6d5198342 100644 --- a/pytype/tests/py2/test_attributes.py +++ b/pytype/tests/py2/test_attributes.py @@ -14,14 +14,14 @@ def testEmptyTypeParameterInstance(self): """) def testTypeParameterInstanceMultipleBindings(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): values = 42 args = {A() if __random__ else True: ""} for x, y in sorted(args.iteritems()): - x.values # line 5 + x.values # attribute-error[e] """) - self.assertErrorLogIs(errors, [(5, "attribute-error", r"'values' on bool")]) + self.assertErrorRegexes(errors, {"e": r"'values' on bool"}) def testTypeParameterInstanceSetAttr(self): ty = self.Infer(""" @@ -60,12 +60,12 @@ class A(object): # TODO(sivachandra): Add an Python 3 equivalent after b/78645527 is fixed. def testIter(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(): x = None - return [y for y in x] + return [y for y in x] # attribute-error[e] """) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"__iter__.*None")]) + self.assertErrorRegexes(errors, {"e": r"__iter__.*None"}) @test_base.skip("Needs vm._get_iter() to iterate over individual bindings.") def testMetaclassIter(self): diff --git a/pytype/tests/py2/test_basic.py b/pytype/tests/py2/test_basic.py index 9241ad606..247946fc7 100644 --- a/pytype/tests/py2/test_basic.py +++ b/pytype/tests/py2/test_basic.py @@ -7,7 +7,7 @@ class TestExec(test_base.TargetPython27FeatureTest): """The exec statement tests.""" def test_exec_statement(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ g = {} exec "a = 11" in g, g assert g['a'] == 11 @@ -26,7 +26,7 @@ def test_printing(self): """) def test_printing_in_a_function(self): - self.Check("""\ + self.Check(""" def fn(): print "hello" fn() @@ -34,7 +34,7 @@ def fn(): """) def test_printing_to_a_file(self): - self.Check("""\ + self.Check(""" import sys print >>sys.stdout, 'hello', 'there' """) diff --git a/pytype/tests/py2/test_builtins.py b/pytype/tests/py2/test_builtins.py index e9eddb389..5a572e0c0 100644 --- a/pytype/tests/py2/test_builtins.py +++ b/pytype/tests/py2/test_builtins.py @@ -69,7 +69,7 @@ def testDictIterators(self): from typing import Any, Iterator def need_iterator(x: Iterator[Any]) -> None: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo d = {"a": 1} foo.need_iterator(d.iterkeys()) @@ -348,11 +348,10 @@ def testIterItems(self): """) def testIntInit(self): - _, errors = self.InferWithErrors("""\ - int(0, 1) # line 8: expected str or unicode, got int for first arg + _, errors = self.InferWithErrors(""" + int(0, 1) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", - r"Union\[str, unicode\].*int")]) + self.assertErrorRegexes(errors, {"e": r"Union\[str, unicode\].*int"}) def testAddStrAndBytearray(self): ty = self.Infer(""" diff --git a/pytype/tests/py2/test_classes.py b/pytype/tests/py2/test_classes.py index 19659f1c1..688e59720 100644 --- a/pytype/tests/py2/test_classes.py +++ b/pytype/tests/py2/test_classes.py @@ -25,7 +25,7 @@ class A(object): """) def testInitTestClassInSetup(self): - ty = self.Infer("""\ + ty = self.Infer(""" import unittest class A(unittest.TestCase): def setUp(self): @@ -42,7 +42,7 @@ def fooTest(self) -> int: ... """) def testInitInheritedTestClassInSetup(self): - ty = self.Infer("""\ + ty = self.Infer(""" import unittest class A(unittest.TestCase): def setUp(self): diff --git a/pytype/tests/py2/test_decorators.py b/pytype/tests/py2/test_decorators.py index c8f401978..ce57763d7 100644 --- a/pytype/tests/py2/test_decorators.py +++ b/pytype/tests/py2/test_decorators.py @@ -8,15 +8,15 @@ class DecoratorsTest(test_base.TargetPython27FeatureTest): def testAttributeErrorUnderClassDecorator(self): # This does not detect the error under target python3 (b/78591647) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def decorate(cls): return __any_object__ @decorate class Foo(object): def Hello(self): - return self.Goodbye() # line 6 + return self.Goodbye() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(6, "attribute-error", r"Goodbye")]) + self.assertErrorRegexes(errors, {"e": r"Goodbye"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py2/test_errors.py b/pytype/tests/py2/test_errors.py index cda165a2d..79a33f468 100644 --- a/pytype/tests/py2/test_errors.py +++ b/pytype/tests/py2/test_errors.py @@ -7,29 +7,29 @@ class ErrorTest(test_base.TargetPython27FeatureTest): """Tests for errors.""" def testProtocolMismatch(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): pass - next(Foo()) + next(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [ - (2, "wrong-arg-types", "__iter__, next") - ]) + self.assertErrorRegexes(errors, {"e": r"__iter__, next"}) def testProtocolMismatchPartial(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __iter__(self): return self - next(Foo()) + next(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [( - 4, "wrong-arg-types", r"\n\s*next\s*$")]) # `next` on its own line + self.assertErrorRegexes( + errors, {"e": r"\n\s*next\s*$"}) # `next` on its own line def testGetSlice(self): - errors = self.CheckWithErrors("def f(): v = []; return v[:'foo']") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"slicing.*List.*str.*__getslice__ on List.*Optional\[int\]")]) + errors = self.CheckWithErrors(""" + def f(): v = []; return v[:'foo'] # unsupported-operands[e] + """) + self.assertErrorRegexes( + errors, + {"e": r"slicing.*List.*str.*__getslice__ on List.*Optional\[int\]"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py2/test_exceptions.py b/pytype/tests/py2/test_exceptions.py index 5774fb37a..f972c765b 100644 --- a/pytype/tests/py2/test_exceptions.py +++ b/pytype/tests/py2/test_exceptions.py @@ -12,7 +12,7 @@ def test_raise_exception_2args(self): self.Check("raise ValueError, 'bad'") def test_raise_exception_3args(self): - self.Check("""\ + self.Check(""" from sys import exc_info try: raise Exception diff --git a/pytype/tests/py2/test_import.py b/pytype/tests/py2/test_import.py index 0aeda953a..c0ff864a9 100644 --- a/pytype/tests/py2/test_import.py +++ b/pytype/tests/py2/test_import.py @@ -8,7 +8,7 @@ class ImportTest(test_base.TargetPython27FeatureTest): """Tests for import.""" def testModuleAttributes(self): - ty = self.Infer("""\ + ty = self.Infer(""" import os f = os.__file__ n = os.__name__ diff --git a/pytype/tests/py2/test_list.py b/pytype/tests/py2/test_list.py index f58dfc088..b9b9d7497 100644 --- a/pytype/tests/py2/test_list.py +++ b/pytype/tests/py2/test_list.py @@ -8,7 +8,7 @@ class ListTest(test_base.TargetPython27FeatureTest): # __getslice__ is py2 only def test_getslice_slot(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" a = [1, '2', 3, 4] b = a[:] c = 1 if __random__ else 2 @@ -18,13 +18,13 @@ def test_getslice_slot(self): g = a[2:None] h = a[None:2] i = a[None:None] - j = a[int:str] - k = a["s":] + j = a[int:str] # unsupported-operands[e1] + k = a["s":] # unsupported-operands[e2] l = a[1:-1] m = a[0:0] n = a[1:1] """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any, List, Union a = ... # type: List[Union[int, str]] b = ... # type: List[Union[int, str]] @@ -41,9 +41,8 @@ def test_getslice_slot(self): m = ... # type: List[nothing] n = ... # type: List[nothing] """) - self.assertErrorLogIs(errors, [ - (10, "unsupported-operands", r"__getslice__ on List"), - (11, "unsupported-operands", r"__getslice__ on List")]) + self.assertErrorRegexes(errors, { + "e1": r"__getslice__ on List", "e2": r"__getslice__ on List"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py2/test_namedtuple.py b/pytype/tests/py2/test_namedtuple.py index e1336c4ba..272051b5a 100644 --- a/pytype/tests/py2/test_namedtuple.py +++ b/pytype/tests/py2/test_namedtuple.py @@ -23,18 +23,14 @@ def test_calls(self): """) def test_bad_call(self): - _, errorlog = self.InferWithErrors("""\ + self.InferWithErrors(""" import collections - collections.namedtuple() - collections.namedtuple("_") - collections.namedtuple("_", "", True, True, True) - collections.namedtuple("_", "", True, verbose=True) + collections.namedtuple() # missing-parameter + collections.namedtuple("_") # missing-parameter + collections.namedtuple("_", "", True, True, True) # wrong-arg-count + collections.namedtuple( + "_", "", True, verbose=True) # duplicate-keyword-argument """) - self.assertErrorLogIs(errorlog, - [(2, "missing-parameter"), - (3, "missing-parameter"), - (4, "wrong-arg-count"), - (5, "duplicate-keyword-argument")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py2/test_pyi.py b/pytype/tests/py2/test_pyi.py index 392028cd4..d9869f232 100644 --- a/pytype/tests/py2/test_pyi.py +++ b/pytype/tests/py2/test_pyi.py @@ -27,7 +27,7 @@ def testVarargs(self): T = TypeVar("T") def get_varargs(x: int, *args: T, z: int, **kws: int) -> T: ... """) - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Union import a l1 = None # type: list[str] @@ -35,8 +35,10 @@ def get_varargs(x: int, *args: T, z: int, **kws: int) -> T: ... v1 = a.get_varargs(1, *l1) v2 = a.get_varargs(1, *l2, z=5) v3 = a.get_varargs(1, True, 2.0, z=5) - v4 = a.get_varargs(1, 2j, "foo", z=5) # bad: conflicting args types - v5 = a.get_varargs(1, *None) # bad: None not iterable + # bad: conflicting args types + v4 = a.get_varargs(1, 2j, "foo", z=5) # wrong-arg-types[e1] + # bad: None not iterable + v5 = a.get_varargs(1, *None) # wrong-arg-types[e2] """, deep=True, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ from typing import Any @@ -53,8 +55,7 @@ def get_varargs(x: int, *args: T, z: int, **kws: int) -> T: ... r"Actually passed: \(x, _, _2: str, \.\.\.\)") msg2 = (r"Expected: \(x, \*args: Iterable, \.\.\.\).*" r"Actually passed: \(x, args: None\)") - self.assertErrorLogIs(errors, [(8, "wrong-arg-types", msg1), - (9, "wrong-arg-types", msg2)]) + self.assertErrorRegexes(errors, {"e1": msg1, "e2": msg2}) # TODO(sivachandra): Make this a target independent test after # after b/78785264 is fixed. @@ -64,16 +65,17 @@ def testKwargs(self): T = TypeVar("T") def get_kwargs(x: int, *args: int, z: int, **kws: T) -> T: ... """) - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Mapping, Union import a d1 = None # type: dict[int, int] d2 = None # type: Mapping[str, Union[str, complex]] - v1 = a.get_kwargs(1, 2, 3, z=5, **d1) # bad: K must be str + # bad: K must be str + v1 = a.get_kwargs(1, 2, 3, z=5, **d1) # wrong-arg-types[e1] v2 = a.get_kwargs(1, 2, 3, z=5, **d2) v3 = a.get_kwargs(1, 2, 3, z=5, v=0, u=3j) # bad: conflicting kwargs types - v4 = a.get_kwargs(1, 2, 3, z=5, v="", u=3j) + v4 = a.get_kwargs(1, 2, 3, z=5, v="", u=3j) # wrong-arg-types[e2] """, deep=True, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ from typing import Any, Mapping @@ -89,8 +91,7 @@ def get_kwargs(x: int, *args: int, z: int, **kws: T) -> T: ... r"Actually passed: \(x, _, _, z, kws: Dict\[int, int\]\)") msg2 = (r"Expected: \(x, _, _, u, v: complex, \.\.\.\).*" r"Actually passed: \(x, _, _, u, v: str, \.\.\.\)") - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", msg1), - (9, "wrong-arg-types", msg2)]) + self.assertErrorRegexes(errors, {"e1": msg1, "e2": msg2}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py2/test_reingest.py b/pytype/tests/py2/test_reingest.py index 7da3d2717..389f6ca02 100644 --- a/pytype/tests/py2/test_reingest.py +++ b/pytype/tests/py2/test_reingest.py @@ -22,12 +22,12 @@ def foo(self): """) with file_utils.Tempdir() as d: d.create_file("foo.pyi", pytd_utils.Print(foo)) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.Foo() + foo.Foo() # not-instantiable[e] foo.Bar() """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "not-instantiable", r"foo\.Foo.*foo")]) + self.assertErrorRegexes(errors, {"e": r"foo\.Foo.*foo"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py2/test_slots.py b/pytype/tests/py2/test_slots.py index 125c83611..be995a94d 100644 --- a/pytype/tests/py2/test_slots.py +++ b/pytype/tests/py2/test_slots.py @@ -7,24 +7,23 @@ class SlotsTest(test_base.TargetPython27FeatureTest): """Tests for __slots__.""" def testBuiltinAttr(self): - _, errors = self.InferWithErrors("""\ - buffer("foo").bar = 16 + self.InferWithErrors(""" + buffer("foo").bar = 16 # not-writable """) - self.assertErrorLogIs(errors, [(1, "not-writable")]) def testSlotWithBytes(self): - _ = self.Check("""\ + self.Check(""" class Foo(object): __slots__ = (b"x",) """) def testSlotWithUnicode(self): - errors = self.CheckWithErrors("""\ - class Foo(object): + errors = self.CheckWithErrors(""" + class Foo(object): # bad-slots[e] __slots__ = (u"fo\\xf6", u"b\\xe4r", "baz") Foo().baz = 3 """) - self.assertErrorLogIs(errors, [(1, "bad-slots", r"fo\\xc3\\xb6")]) + self.assertErrorRegexes(errors, {"e": r"fo\\xc3\\xb6"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py2/test_stdlib.py b/pytype/tests/py2/test_stdlib.py index 4f5390829..6a00d6b8c 100644 --- a/pytype/tests/py2/test_stdlib.py +++ b/pytype/tests/py2/test_stdlib.py @@ -39,7 +39,7 @@ def testStringTypes(self): """) def testDefaultDict(self): - self.Check("""\ + self.Check(""" import collections import itertools ids = collections.defaultdict(itertools.count(17).next) diff --git a/pytype/tests/py2/test_super.py b/pytype/tests/py2/test_super.py index 2b8b92cd1..41b40415a 100644 --- a/pytype/tests/py2/test_super.py +++ b/pytype/tests/py2/test_super.py @@ -9,17 +9,16 @@ class SuperTest(test_base.TargetPython27FeatureTest): def testSuperMissingArg(self): # Python 2 super call does not implicitly infer the class and self # arguments. At least the class argument should be specified. - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __new__(cls): - return super(cls).__new__(cls) + return super(cls).__new__(cls) # wrong-arg-types[e1] class Bar(object): def __new__(cls): - return super().__new__(cls) + return super().__new__(cls) # wrong-arg-count[e2] """) - self.assertErrorLogIs(errors, [ - (3, "wrong-arg-types", r"Type\[super\].*Type\[Foo\]"), - (6, "wrong-arg-count", r"2.*0")]) + self.assertErrorRegexes( + errors, {"e1": r"Type\[super\].*Type\[Foo\]", "e2": r"2.*0"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py2/test_tuple.py b/pytype/tests/py2/test_tuple.py index 02bccbdf8..91b424dad 100644 --- a/pytype/tests/py2/test_tuple.py +++ b/pytype/tests/py2/test_tuple.py @@ -7,7 +7,7 @@ class TupleTest(test_base.TargetPython27FeatureTest): """Tests for __builtin__.tuple.""" def testIteration(self): - ty = self.Infer("""\ + ty = self.Infer(""" class Foo(object): mytuple = (1, "foo", 3j) def __getitem__(self, pos): diff --git a/pytype/tests/py2/test_typevar.py b/pytype/tests/py2/test_typevar.py index fc3b447e0..257b85e44 100644 --- a/pytype/tests/py2/test_typevar.py +++ b/pytype/tests/py2/test_typevar.py @@ -9,33 +9,31 @@ class Test(test_base.TargetPython27FeatureTest): def testUseConstraintsFromPyi(self): with file_utils.Tempdir() as d: - d.create_file("foo.pyi", """\ + d.create_file("foo.pyi", """ from typing import AnyStr, TypeVar T = TypeVar("T", int, float) def f(x: T) -> T: ... def g(x: AnyStr) -> AnyStr: ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.f("") - foo.g(0) + foo.f("") # wrong-arg-types[e1] + foo.g(0) # wrong-arg-types[e2] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (2, "wrong-arg-types", r"Union\[float, int\].*str"), - (3, "wrong-arg-types", r"Union\[str, unicode\].*int")]) + self.assertErrorRegexes(errors, { + "e1": r"Union\[float, int\].*str", + "e2": r"Union\[str, unicode\].*int"}) def testExtraArguments(self): # TODO(b/78905523): Make this a target-independent test. - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar - T = TypeVar("T", extra_arg=42) - S = TypeVar("S", *__any_object__) - U = TypeVar("U", **__any_object__) + T = TypeVar("T", extra_arg=42) # invalid-typevar[e1] + S = TypeVar("S", *__any_object__) # invalid-typevar[e2] + U = TypeVar("U", **__any_object__) # invalid-typevar[e3] """) - self.assertErrorLogIs(errors, [ - (2, "invalid-typevar", r"extra_arg"), - (3, "invalid-typevar", r"\*args"), - (4, "invalid-typevar", r"\*\*kwargs")]) + self.assertErrorRegexes(errors, { + "e1": r"extra_arg", "e2": r"\*args", "e3": r"\*\*kwargs"}) def testSimplifyArgsAndKwargs(self): # TODO(b/78905523): Make this a target-independent test. diff --git a/pytype/tests/py2/test_typing_methods.py b/pytype/tests/py2/test_typing_methods.py index 6658361d0..f1d933196 100644 --- a/pytype/tests/py2/test_typing_methods.py +++ b/pytype/tests/py2/test_typing_methods.py @@ -16,7 +16,7 @@ def test_mapping(self): class MyDict(Mapping[K, V]): ... def f() -> MyDict[str, int] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo m = foo.f() a = m.copy() diff --git a/pytype/tests/py2/test_typing_namedtuple.py b/pytype/tests/py2/test_typing_namedtuple.py index 6ea0f9385..f26f1acdd 100644 --- a/pytype/tests/py2/test_typing_namedtuple.py +++ b/pytype/tests/py2/test_typing_namedtuple.py @@ -7,7 +7,7 @@ class NamedTupleTest(test_base.TargetPython27FeatureTest): """Tests for the typing.NamedTuple overlay.""" def test_basic_namedtuple(self): - ty = self.Infer("""\ + ty = self.Infer(""" import typing X = typing.NamedTuple("X", [("a", int), ("b", str)]) x = X(1, "hello") @@ -15,7 +15,7 @@ def test_basic_namedtuple(self): b = x.b """) self.assertTypesMatchPytd( - ty, """\ + ty, """ import collections from typing import Callable, Iterable, Sized, Tuple, Type, TypeVar, Union typing: module @@ -47,14 +47,14 @@ def _replace(self: _TX, **kwds: Union[int, str]) -> _TX: ... """) def test_namedtuple_unicode(self): - ty = self.Infer("""\ + ty = self.Infer(""" import typing X = typing.NamedTuple(u"X", [(u"a", int)]) x = X(1) a = x.a """) self.assertTypesMatchPytd( - ty, """\ + ty, """ import collections from typing import Callable, Iterable, Sized, Tuple, Type, TypeVar, Union typing: module diff --git a/pytype/tests/py3/test_abc.py b/pytype/tests/py3/test_abc.py index a0ad0dd34..7d274bf3c 100644 --- a/pytype/tests/py3/test_abc.py +++ b/pytype/tests/py3/test_abc.py @@ -53,7 +53,7 @@ class BarA(Foo, range): """) def test_abstractproperty(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" import abc class Foo(metaclass=abc.ABCMeta): @abc.abstractproperty @@ -63,7 +63,7 @@ class Bar(Foo): @property def foo(self): return super(Bar, self).foo - v1 = Foo().foo + v1 = Foo().foo # not-instantiable[e] v2 = Bar().foo """) self.assertTypesMatchPytd(ty, """ @@ -77,7 +77,7 @@ class Bar(Foo): class Foo(metaclass=abc.ABCMeta): foo = ... # type: Any """) - self.assertErrorLogIs(errors, [(10, "not-instantiable", r"Foo.*foo")]) + self.assertErrorRegexes(errors, {"e": r"Foo.*foo"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_annotations.py b/pytype/tests/py3/test_annotations.py index f995c2c7a..19bf94382 100644 --- a/pytype/tests/py3/test_annotations.py +++ b/pytype/tests/py3/test_annotations.py @@ -59,16 +59,16 @@ def foo(x: Union[int, float], y:int) -> Union[int, float]: ... """) def testCallError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" s = {1} def foo(x: int): s.intersection(x) - foo(3.0) + foo(3.0) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"x: int.*x: float")]) + self.assertErrorRegexes(errors, {"e": r"x: int.*x: float"}) def testAmbiguousArg(self): - self.Check("""\ + self.Check(""" def f(x: int): return x def g(y, z): @@ -82,11 +82,11 @@ def g(y, z): """) def testInnerError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def foo(x: int): - return x.upper() + return x.upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(2, "attribute-error", r"upper.*int")]) + self.assertErrorRegexes(errors, {"e": r"upper.*int"}) def testList(self): ty = self.Infer(""" @@ -107,7 +107,7 @@ def foo(l1: List[int], l2: List[str], b) -> None: ... """) def testAnalyzeInit(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List class Foo: def f(self, x: List[int]): @@ -120,7 +120,7 @@ def f(self, x: List[int]) -> None: ... """) def testStringAnnotation(self): - ty = self.Infer("""\ + ty = self.Infer(""" def f(c: "int") -> "None": c += 1 return @@ -130,7 +130,7 @@ def f(c: int) -> None: ... """) def testUnicodeAnnotation(self): - ty = self.Infer("""\ + ty = self.Infer(""" def f(c: u"int") -> u"None": c += 1 return @@ -140,7 +140,7 @@ def f(c: int) -> None: ... """) def testFutureUnicodeLiteralAnnotation(self): - ty = self.Infer("""\ + ty = self.Infer(""" from __future__ import unicode_literals def f(c: "int") -> "None": c += 1 @@ -155,7 +155,7 @@ def f(c: int) -> None: ... """) def testTypingOnlyImport(self): - ty = self.Infer("""\ + ty = self.Infer(""" import typing if typing.TYPE_CHECKING: import calendar @@ -169,63 +169,56 @@ def f(c: calendar.Calendar) -> int: ... """) def testAmbiguousAnnotation(self): - _, errors = self.InferWithErrors("""\ - def foo(x: int if __random__ else float): + _, errors = self.InferWithErrors(""" + def foo(x: int if __random__ else float): # invalid-annotation[e1] return x - def foo(x: "int if __random__ else float"): + def foo(x: "int if __random__ else float"): # invalid-annotation[e2] return x """) - self.assertErrorLogIs(errors, { - (1, "invalid-annotation", r"float or int.*x.*constant"), - # For a late annotation, we print the string literal, which is why - # the types below are not in alphabetical order. - (3, "invalid-annotation", r"int.*float.*x.*constant")}) + self.assertErrorRegexes(errors, { + "e1": r"float or int.*x.*constant", + # For a late annotation, we print the string literal, which is why the + # types below are not in alphabetical order. + "e2": r"int.*float.*x.*constant"}) def testBadStringAnnotation(self): - _, errors = self.InferWithErrors("""\ - def foo(x: str()): + _, errors = self.InferWithErrors(""" + def foo(x: str()): # invalid-annotation[e] return x """) - self.assertErrorLogIs(errors, { - (1, "invalid-annotation", r"x.*constant")}) + self.assertErrorRegexes(errors, {"e": r"x.*constant"}) def testBadReturn(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def foo(x: str, y: str) -> int: - return "foo" + return "foo" # bad-return-type """) - self.assertErrorLogIs(errors, { - (2, "bad-return-type")}) def testMultipleReturns(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def foo(x: str, y: str) -> int: if x: - return "foo" + return "foo" # bad-return-type[e1] else: - return 3j + return 3j # bad-return-type[e2] """) - self.assertErrorLogIs(errors, { - (3, "bad-return-type", r"Expected.*int.*Actual.*str"), - (5, "bad-return-type", r"Expected.*int.*Actual.*complex") - }) + self.assertErrorRegexes(errors, {"e1": r"Expected.*int.*Actual.*str", + "e2": r"Expected.*int.*Actual.*complex"}) def testAmbiguousReturn(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def foo(x: str) -> int: if x: y = "foo" else: y = 3j - return y + return y # bad-return-type[e] """) - self.assertErrorLogIs(errors, { - (6, "bad-return-type", - r"Expected.*int.*Actual.*Union(?=.*complex).*str"), - }) + self.assertErrorRegexes( + errors, {"e": r"Expected.*int.*Actual.*Union(?=.*complex).*str"}) def testDefaultReturn(self): - ty = self.Infer("""\ + ty = self.Infer(""" class Foo(object): def bar(self, x: float, default="") -> str: default.upper @@ -237,14 +230,14 @@ def bar(self, x: float, default=...) -> str: ... """) def testCompatBool(self): - self.Check("""\ + self.Check(""" def bar(x: bool) -> bool: return None bar(None) """) def testCompatFloat(self): - self.Check("""\ + self.Check(""" def bar(x: float) -> float: return 1 bar(42) @@ -252,7 +245,7 @@ def bar(x: float) -> float: def testCompatUnicodeStr(self): # Use str to be identical in py2 and py3 - self.Check("""\ + self.Check(""" from typing import Text def bar(x: Text) -> Text: return str("foo") @@ -260,14 +253,14 @@ def bar(x: Text) -> Text: """) def testUnsolvable(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ import unknown_module def f(x: unknown_module.Iterable): pass """) def testAny(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Any def f(x: Any): pass @@ -279,76 +272,59 @@ def f(x) -> None: ... """) def testDict(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import Dict, List def keys(d: Dict[str, int]): return keys({"foo": 3}) keys({}) # ok - keys({3: 3}) # not allowed + keys({3: 3}) # wrong-arg-types """, deep=True) - self.assertErrorLogIs(errors, [ - (6, "wrong-arg-types"), - ]) def testSequence(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import Sequence def f(s: Sequence): return s f([1,2,3]) f((1,2,3)) - f({1,2,3}) - f(1) + f({1,2,3}) # wrong-arg-types + f(1) # wrong-arg-types """, deep=True) - self.assertErrorLogIs(errors, [ - (6, "wrong-arg-types"), - (7, "wrong-arg-types"), - ]) def testOptional(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import Optional def f(s: Optional[int]): return s f(1) f(None) - f("foo") + f("foo") # wrong-arg-types """, deep=True) - self.assertErrorLogIs(errors, [ - (6, "wrong-arg-types"), - ]) def testSet(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import Set def f(d: Set[str]): return f({"foo"}) # ok f(set()) # ok - f({}) # not allowed, {} isn't a set - f({3}) # not allowed + f({}) # {} isn't a set # wrong-arg-types + f({3}) # wrong-arg-types """, deep=True) - self.assertErrorLogIs(errors, [ - (6, "wrong-arg-types"), - (7, "wrong-arg-types"), - ]) def testFrozenSet(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import FrozenSet def f(d: FrozenSet[str]): return f(frozenset(["foo"])) # ok f(frozenset()) # ok - f(frozenset([3])) # not allowed + f(frozenset([3])) # wrong-arg-types """, deep=True) - self.assertErrorLogIs(errors, [ - (6, "wrong-arg-types"), - ]) def testGenericAndTypeVar(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ import typing _T = typing.TypeVar("_T") class A(typing.Generic[_T]): @@ -356,7 +332,7 @@ class A(typing.Generic[_T]): """) def testJumpIntoClassThroughAnnotation(self): - self.Check("""\ + self.Check(""" class Foo(object): def __init__(self) -> None: self.myset = set() @@ -384,14 +360,14 @@ class B(object): """) def testWithoutForwardDecl(self): - _, errorlog = self.InferWithErrors("""\ - def f(a) -> Bar: + _, errorlog = self.InferWithErrors(""" + def f(a) -> Bar: # name-error[e] return Bar() class Bar(object): pass """) - self.assertErrorLogIs(errorlog, [(1, "name-error", r"Bar")]) + self.assertErrorRegexes(errorlog, {"e": r"Bar"}) def testInvalidForwardDecl(self): self.Check(""" @@ -401,29 +377,28 @@ def f(a) -> "Foo": class Foo(object): pass """) - _, errorlog = self.InferWithErrors("""\ - def f(a: "Foo"): + _, errorlog = self.InferWithErrors(""" + def f(a: "Foo"): # name-error[e] return B() class B(object): pass """) - self.assertErrorLogIs(errorlog, [(1, "name-error", r"Foo")]) + self.assertErrorRegexes(errorlog, {"e": r"Foo"}) def testForwardDeclBadReturn(self): - _, errorlog = self.InferWithErrors("""\ + _, errorlog = self.InferWithErrors(""" def f() -> "Foo": - return 1 + return 1 # bad-return-type[e] class Foo(object): pass """) # Error message along the lines: No attribute 'bar' on Foo - self.assertErrorLogIs( - errorlog, [(2, "bad-return-type", r"return type.*int")]) + self.assertErrorRegexes(errorlog, {"e": r"return type.*int"}) def testConfusingForwardDecl(self): - _, errorlog = self.InferWithErrors("""\ + _, errorlog = self.InferWithErrors(""" class Foo(object): def foo(self): return 4 @@ -436,27 +411,25 @@ def bar(self): return 2 def g(): - return f().bar() + return f().bar() # attribute-error[e] """) # Error message along the lines: No attribute 'bar' on Foo - self.assertErrorLogIs( - errorlog, [(13, "attribute-error", r"\'bar\'.*Foo")]) + self.assertErrorRegexes(errorlog, {"e": r"\'bar\'.*Foo"}) def testReturnTypeError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class FooBar(object): pass def f() -> FooBar: - return 3 + return 3 # bad-return-type[e] """, deep=True) - self.assertErrorLogIs(errors, [( - 3, "bad-return-type", r"Expected: FooBar")]) + self.assertErrorRegexes(errors, {"e": r"Expected: FooBar"}) def testUnknownArgument(self): with file_utils.Tempdir() as d: d.create_file("a.pyi", """ def factory() -> type """) - ty = self.Infer("""\ + ty = self.Infer(""" import a A = a.factory() def f(x: A): @@ -470,14 +443,14 @@ def f(x) -> Any """) def testBadCallNoKwarg(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" def foo(): labels = { 'baz': None } labels['baz'] = bar( - labels['baz']) + labels['baz']) # wrong-arg-types[e] def bar(path: str, **kwargs): return path @@ -488,17 +461,17 @@ def foo() -> None def bar(path: str, **kwargs) -> str """) error = r"Actually passed:.*path: None" - self.assertErrorLogIs(errors, [(7, "wrong-arg-types", error)]) + self.assertErrorRegexes(errors, {"e": error}) def testBadCallWithKwarg(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" def foo(): labels = { 'baz': None } labels['baz'] = bar( - labels['baz'], x=42) + labels['baz'], x=42) # wrong-arg-types[e] def bar(path: str, **kwargs): return path @@ -509,10 +482,10 @@ def foo() -> None def bar(path: str, **kwargs) -> str """) error = r"Actually passed:.*path: None" - self.assertErrorLogIs(errors, [(7, "wrong-arg-types", error)]) + self.assertErrorRegexes(errors, {"e": error}) def testSkipFunctionsWithAnnotations(self): - ty = self.Infer("""\ + ty = self.Infer(""" _analyzed_baz = None class Foo(object): def __init__(self): @@ -573,7 +546,7 @@ class A: pass class B: x = 42 def f(v: Union[A, B]): - return v.x + return v.x # attribute-error[e] f(A()) """) self.assertTypesMatchPytd(ty, """ @@ -583,7 +556,7 @@ class B: x = ... # type: int def f(v: Union[A, B]) -> int: ... """) - self.assertErrorLogIs(errors, [(7, "attribute-error", "x.*A")]) + self.assertErrorRegexes(errors, {"e": r"x.*A"}) def testTuple(self): ty = self.Infer(""" @@ -616,7 +589,7 @@ def f(x: List[Any]): """) def testInnerString(self): - self.Check("""\ + self.Check(""" from typing import List, Union def f(x: List["int"]): pass @@ -625,21 +598,21 @@ def g(x: Union["int"]): """) def testAmbiguousInnerAnnotation(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import List, Union - def f(x: List[int if __random__ else str]): + def f(x: List[int if __random__ else str]): # invalid-annotation[e1] pass - def g(x: Union[int if __random__ else str]): + def g(x: Union[int if __random__ else str]): # invalid-annotation[e2] pass def h(x: List[Union[int, str]]): # okay pass """) - self.assertErrorLogIs(errors, [ - (2, "invalid-annotation", r"List\[int\] or List\[str\].*constant"), - (4, "invalid-annotation", r"int or str.*constant")]) + self.assertErrorRegexes(errors, { + "e1": r"List\[int\] or List\[str\].*constant", + "e2": r"int or str.*constant"}) def testKwargs(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Dict def f(x, **kwargs: int): return kwargs @@ -650,8 +623,8 @@ def h() -> Dict[float, int]: f("", y=42) f("", **{}) f("", **{"y": 42}) - f("", **g()) - f("", **h()) + f("", **g()) # wrong-arg-types[e1] + f("", **h()) # wrong-arg-types[e2] """) self.assertTypesMatchPytd(ty, """ from typing import Dict @@ -663,24 +636,21 @@ def h() -> Dict[float, int] r"Actually passed.*Dict\[str, float\]") error2 = (r"Expected.*Mapping\[str, int\].*" r"Actually passed.*Dict\[float, int\]") - self.assertErrorLogIs(errors, [(11, "wrong-arg-types", error1), - (12, "wrong-arg-types", error2)]) + self.assertErrorRegexes(errors, {"e1": error1, "e2": error2}) @test_base.skip("Types not checked due to function.Args.simplify") def testSimplifiedVarargsAndKwargs(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x, *args: int): pass def g(x, **kwargs: int): pass - f("", 42.0) - g("", y=42.0) - g("", **{"y": 42.0}) + f("", 42.0) # wrong-arg-types[e1] + g("", y=42.0) # wrong-arg-types[e2] + g("", **{"y": 42.0}) # wrong-arg-types[e3] """) error = r"Expected.*int.*Actually passed.*float" - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", error), - (6, "wrong-arg-types", error), - (7, "wrong-arg-types", error)]) + self.assertErrorRegexes(errors, {"e1": error, "e2": error, "e3": error}) def testUseVarargsAndKwargs(self): ty = self.Infer(""" @@ -714,7 +684,7 @@ def Bar(): """) def testNestedNoneType(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import List, Union class A: x = 42 @@ -722,7 +692,7 @@ def f() -> Union[A, None]: pass def g() -> List[None]: return [None] - v1 = f().x # line 8 + v1 = f().x # attribute-error[e] v2 = g()[0] """, deep=False) self.assertTypesMatchPytd(ty, """ @@ -734,42 +704,41 @@ def g() -> List[None]: ... v1 = ... # type: int v2 = ... # type: None """) - self.assertErrorLogIs(errors, [(8, "attribute-error", r"x.*None")]) + self.assertErrorRegexes(errors, {"e": r"x.*None"}) def testMatchLateAnnotation(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): def f(self, x: "A"): pass def f(): - A().f(42) + A().f(42) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", r"A.*int")]) + self.assertErrorRegexes(errors, {"e": r"A.*int"}) def testRecursiveForwardReference(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): def __init__(self, x: "A"): self.foo = x.foo - f(x) + f(x) # wrong-arg-types[e1] def method1(self): self.foo def method2(self): - self.bar + self.bar # attribute-error[e2] def f(x: int): pass """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"int.*A"), - (8, "attribute-error", r"bar")]) + self.assertErrorRegexes(errors, {"e1": r"int.*A", "e2": r"bar"}) def testModuleLevelForwardReferenceError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class A(object): def f(self, x: "A"): pass - A().f(42) + A().f(42) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"A.*int")]) + self.assertErrorRegexes(errors, {"e": r"A.*int"}) def testReturnAnnotation1(self): ty = self.Infer(""" @@ -809,7 +778,7 @@ def f() -> int: ... """) def testDeeplyNestedAnnotation(self): - self.Check("""\ + self.Check(""" from typing import Any, Dict, List, Optional def G(x: Optional[List[Dict[str, Any]]]): if x: @@ -819,7 +788,7 @@ def F(x: Optional[List[Dict[str, Any]]]): """) def testNestedLateAnnotation(self): - self.Check("""\ + self.Check(""" from typing import List Type = "int" def f(x: "List[Type]"): @@ -827,7 +796,7 @@ def f(x: "List[Type]"): """) def testLateAnnotation(self): - ty = self.Infer("""\ + ty = self.Infer(""" def new_x() -> 'X': return X() class X(object): @@ -845,7 +814,7 @@ class X(object): """) def testChangeAnnotatedArg(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Dict def f(x: Dict[str, str]): x[True] = 42 @@ -859,7 +828,7 @@ def f(x: Dict[str, str]) -> Dict[str or bool, str or int]: ... """) def testInnerStringAnnotation(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List def f(x: List["A"]) -> int: pass @@ -876,7 +845,7 @@ class A(object): ... """) def testTypeAliasAnnotation(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List TypeA = "A" ListA = "List[A]" @@ -896,7 +865,7 @@ class A(object): """) def testDoubleString(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List def f(x: "List[\\"int\\"]") -> int: pass @@ -907,7 +876,7 @@ def f(x: List[int]) -> int: ... """) def testDuplicateIdentifier(self): - ty = self.Infer("""\ + ty = self.Infer(""" t = int def f(x: t) -> int: pass def g(x: "t") -> int: pass @@ -921,11 +890,11 @@ def g(x: int) -> int: ... """) def testEllipsis(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Dict, Tuple - def f(x: ...): pass + def f(x: ...): pass # invalid-annotation[e1] def g(x: Tuple[str, ...]): pass - def h(x: Dict[..., int]): pass + def h(x: Dict[..., int]): pass # invalid-annotation[e2] """) self.assertTypesMatchPytd(ty, """ from typing import Any, Dict, Tuple @@ -933,9 +902,8 @@ def f(x) -> None: ... def g(x: Tuple[str, ...]) -> None: ... def h(x: Dict[Any, int]) -> None: ... """) - self.assertErrorLogIs( - errors, [(2, "invalid-annotation", r"Ellipsis.*x"), - (4, "invalid-annotation", r"Ellipsis.*Dict")]) + self.assertErrorRegexes( + errors, {"e1": r"Ellipsis.*x", "e2": r"Ellipsis.*Dict"}) def testCustomContainer(self): with file_utils.Tempdir() as d: @@ -947,18 +915,17 @@ class Foo(Generic[T]): def __init__(self, x: T2): self = Foo[T2] """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo def f(x: foo.Foo[int]): pass f(foo.Foo(42)) - f(foo.Foo("")) + f(foo.Foo("")) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", - r"Foo\[int\].*Foo\[str\]")]) + self.assertErrorRegexes(errors, {"e": r"Foo\[int\].*Foo\[str\]"}) def testNoImplicitOptional(self): - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" from typing import Optional, Union def f1(x: str = None): pass @@ -968,10 +935,10 @@ def f3(x: Union[str, None] = None): pass def f4(x: Union[str, int] = None): pass - f1(None) + f1(None) # wrong-arg-types f2(None) f3(None) - f4(None) + f4(None) # wrong-arg-types """) self.assertTypesMatchPytd(ty, """ from typing import Optional, Union @@ -980,8 +947,6 @@ def f2(x: Optional[str] = ...) -> None: ... def f3(x: Optional[str] = ...) -> None: ... def f4(x: Union[str, int] = ...) -> None: ... """) - self.assertErrorLogIs(errors, [(10, "wrong-arg-types"), - (13, "wrong-arg-types")]) def testInferReturn(self): ty = self.Infer(""" @@ -1004,14 +969,13 @@ def h(): """) def testRecursiveTypeAlias(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import List, Union Foo = Union[str, List['Foo']] - def f(x: Foo): + def f(x: Foo): # not-supported-yet[e] pass """) - self.assertErrorLogIs(errors, [(3, "not-supported-yet", - r"Recursive.*Foo")]) + self.assertErrorRegexes(errors, {"e": r"Recursive.*Foo"}) def testFullyQuotedAnnotation(self): self.Check(""" @@ -1034,25 +998,23 @@ def f(x: List[Callable[[int], str]]) -> None: ... """) def testLateAnnotationNonNameError(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" class Foo(object): pass - def f(x: "Foo.Bar"): + def f(x: "Foo.Bar"): # attribute-error pass """) - self.assertErrorLogIs(errors, [(3, "attribute-error")]) def testKeepContainerWithError(self): - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" from typing import Dict - def f(x: "Dict[str, int.error]"): + def f(x: "Dict[str, int.error]"): # attribute-error pass """) self.assertTypesMatchPytd(ty, """ from typing import Any, Dict def f(x: Dict[str, Any]) -> None: ... """) - self.assertErrorLogIs(errors, [(2, "attribute-error")]) class TestAnnotationsPython3Feature(test_base.TargetPython3FeatureTest): diff --git a/pytype/tests/py3/test_anystr.py b/pytype/tests/py3/test_anystr.py index 63177cd69..e600d48a1 100644 --- a/pytype/tests/py3/test_anystr.py +++ b/pytype/tests/py3/test_anystr.py @@ -75,12 +75,12 @@ def f(x: AnyStr) -> AnyStr """) def testUseAnyStrConstraints(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import AnyStr, TypeVar def f(x: AnyStr, y: AnyStr) -> AnyStr: return __any_object__ v1 = f(__any_object__, u"") # ok - v2 = f(__any_object__, 42) + v2 = f(__any_object__, 42) # wrong-arg-types[e] """) self.assertTypesMatchPytd(ty, """ from typing import Any, TypeVar @@ -89,19 +89,18 @@ def f(x: AnyStr, y: AnyStr) -> AnyStr: ... v1 = ... # type: str v2 = ... # type: Any """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", - r"Union\[bytes, str\].*int")]) + self.assertErrorRegexes(errors, {"e": r"Union\[bytes, str\].*int"}) def testConstraintMismatch(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import AnyStr def f(x: AnyStr, y: AnyStr): ... f("", "") # ok - f("", b"") + f("", b"") # wrong-arg-types[e] f(b"", b"") # ok """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", - r"Expected.*y: str.*Actual.*y: bytes")]) + self.assertErrorRegexes( + errors, {"e": r"Expected.*y: str.*Actual.*y: bytes"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_async_generators.py b/pytype/tests/py3/test_async_generators.py index e2fd72ac8..91814bc35 100644 --- a/pytype/tests/py3/test_async_generators.py +++ b/pytype/tests/py3/test_async_generators.py @@ -74,35 +74,32 @@ def gen() -> AsyncGenerator[Union[int, str], Any]: ... """) def testAnnotationError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import AsyncGenerator, AsyncIterator, AsyncIterable, Any, Union async def gen1() -> AsyncGenerator[bool, int]: - yield 1 + yield 1 # bad-return-type[e1] async def gen2() -> AsyncIterator[bool]: - yield 1 + yield 1 # bad-return-type[e2] async def gen3() -> AsyncIterable[bool]: - yield 1 + yield 1 # bad-return-type[e3] - async def gen4() -> int: + async def gen4() -> int: # invalid-annotation[e4] yield 1 async def fun(): g = gen1() - await g.asend("str") + await g.asend("str") # wrong-arg-types[e5] """) - self.assertErrorLogIs(errors, [ - (4, "bad-return-type", r"bool.*int"), - (7, "bad-return-type", r"bool.*int"), - (10, "bad-return-type", r"bool.*int"), - (12, "invalid-annotation", - r"AsyncGenerator.*AsyncIterable.*AsyncIterator"), - (17, "wrong-arg-types", r"int.*str"),]) + self.assertErrorRegexes(errors, { + "e1": r"bool.*int", "e2": r"bool.*int", "e3": r"bool.*int", + "e4": r"AsyncGenerator.*AsyncIterable.*AsyncIterator", + "e5": r"int.*str"}) def testMatchBaseClassError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import AsyncGenerator, AsyncIterator, AsyncIterable, Union, Any async def func(): @@ -134,16 +131,15 @@ def f6(x: AsyncGenerator[bool, Any]): pass f1(gen()) - f2(gen()) + f2(gen()) # wrong-arg-types[e1] f3(gen()) - f4(gen()) + f4(gen()) # wrong-arg-types[e2] f5(gen()) - f6(gen()) + f6(gen()) # wrong-arg-types[e3] """) - self.assertErrorLogIs(errors, [ - (32, "wrong-arg-types", r"bool.*Union\[int, str\]"), - (34, "wrong-arg-types", r"bool.*Union\[int, str\]"), - (36, "wrong-arg-types", r"bool.*Union\[int, str\]"),]) + self.assertErrorRegexes(errors, { + "e1": r"bool.*Union\[int, str\]", "e2": r"bool.*Union\[int, str\]", + "e3": r"bool.*Union\[int, str\]"}) def testProtocol(self): ty = self.Infer(""" diff --git a/pytype/tests/py3/test_attr.py b/pytype/tests/py3/test_attr.py index 688e75bf2..0ababc98f 100644 --- a/pytype/tests/py3/test_attr.py +++ b/pytype/tests/py3/test_attr.py @@ -81,13 +81,12 @@ def __init__(self, x: int, y: str) -> None: ... """) def test_type_clash(self): - errors = self.CheckWithErrors(""" + self.CheckWithErrors(""" import attr @attr.s - class Foo(object): + class Foo(object): # invalid-annotation x : int = attr.ib(type=str) """) - self.assertErrorLogIs(errors, [(4, "invalid-annotation")]) def test_defaults_with_annotation(self): ty = self.Infer(""" @@ -218,14 +217,13 @@ def foo(cls) -> None: ... """) def test_bad_default_param_order(self): - err = self.CheckWithErrors(""" + self.CheckWithErrors(""" import attr @attr.s(auto_attribs=True) - class Foo(object): + class Foo(object): # invalid-function-definition x: int = 10 y: str """) - self.assertErrorLogIs(err, [(4, "invalid-function-definition")]) def test_subclass_auto_attribs(self): ty = self.Infer(""" diff --git a/pytype/tests/py3/test_attributes.py b/pytype/tests/py3/test_attributes.py index c78771962..f5496f387 100644 --- a/pytype/tests/py3/test_attributes.py +++ b/pytype/tests/py3/test_attributes.py @@ -7,12 +7,12 @@ class TestStrictNone(test_base.TargetPython3BasicTest): """Tests for strict attribute checking on None.""" def testExplicitNone(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Optional def f(x: Optional[str]): - return x.upper() + return x.upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testClosure(self): self.Check(""" @@ -26,41 +26,39 @@ def testClosure(self): """) def testOverwriteGlobal(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Optional d = ... # type: Optional[dict] if d: - formatter = lambda x: d.get(x, '') # line 4 + formatter = lambda x: d.get(x, '') # attribute-error[e] else: formatter = lambda x: '' d = None formatter('key') # line 8 """) - self.assertErrorLogIs( - errors, [(4, "attribute-error", r"get.*None.*traceback.*line 8")]) + self.assertErrorRegexes(errors, {"e": r"get.*None.*traceback.*line 8"}) class TestAttributes(test_base.TargetPython3BasicTest): """Tests for attributes.""" def testAttrOnOptional(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Optional def f(x: Optional[str]): - return x.upper() + return x.upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testErrorInAny(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Any def f(x: Any): if __random__: x = 42 - x.upper() # line 5 + x.upper() # attribute-error[e] """) - self.assertErrorLogIs( - errors, [(5, "attribute-error", r"upper.*int.*Union\[Any, int\]")]) + self.assertErrorRegexes(errors, {"e": r"upper.*int.*Union\[Any, int\]"}) class TestAttributesPython3FeatureTest(test_base.TargetPython3FeatureTest): @@ -74,14 +72,14 @@ def testEmptyTypeParameterInstance(self): """) def testTypeParameterInstanceMultipleBindings(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): values = 42 args = {A() if __random__ else True: ""} for x, y in sorted(args.items()): - x.values # line 5 + x.values # attribute-error[e] """) - self.assertErrorLogIs(errors, [(5, "attribute-error", r"'values' on bool")]) + self.assertErrorRegexes(errors, {"e": r"'values' on bool"}) def testTypeParameterInstanceSetAttr(self): ty = self.Infer(""" diff --git a/pytype/tests/py3/test_basic.py b/pytype/tests/py3/test_basic.py index 14ba09ee0..3f948ff9b 100644 --- a/pytype/tests/py3/test_basic.py +++ b/pytype/tests/py3/test_basic.py @@ -7,7 +7,7 @@ class TestExec(test_base.TargetPython3FeatureTest): """Basic tests.""" def test_exec_function(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ g = {} exec("a = 11", g, g) assert g['a'] == 11 diff --git a/pytype/tests/py3/test_builtins.py b/pytype/tests/py3/test_builtins.py index 207c6e3de..8a3d91a8e 100644 --- a/pytype/tests/py3/test_builtins.py +++ b/pytype/tests/py3/test_builtins.py @@ -115,21 +115,19 @@ def testBuiltins(self): """) def testUnicode(self): - errors = self.CheckWithErrors("""\ - unicode("foo") + self.CheckWithErrors(""" + unicode("foo") # name-error """) - self.assertErrorLogIs(errors, [(1, "name-error")]) def testBytesIteration(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" def f(): for x in bytes(): - return bytes() + x + return bytes() + x # unsupported-operands """) - self.assertErrorLogIs(errors, [(3, "unsupported-operands")]) def test_inplace_division(self): - self.Check("""\ + self.Check(""" x, y = 24, 3 x /= y assert x == 8.0 and y == 3 @@ -140,18 +138,14 @@ def test_inplace_division(self): """) def test_removed_dict_methods(self): - errors = self.CheckWithErrors("""\ - {}.iteritems - {}.iterkeys - {}.itervalues - {}.viewitems - {}.viewkeys - {}.viewvalues - """) - self.assertErrorLogIs( - errors, [(1, "attribute-error"), (2, "attribute-error"), - (3, "attribute-error"), (4, "attribute-error"), - (5, "attribute-error"), (6, "attribute-error")]) + self.CheckWithErrors(""" + {}.iteritems # attribute-error + {}.iterkeys # attribute-error + {}.itervalues # attribute-error + {}.viewitems # attribute-error + {}.viewkeys # attribute-error + {}.viewvalues # attribute-error + """) def test_dict_views(self): self.Check(""" @@ -423,22 +417,20 @@ def testItems(self): """) def testIntInit(self): - _, errors = self.InferWithErrors("""\ - int(0, 1) # line 8: expected str or unicode, got int for first arg + _, errors = self.InferWithErrors(""" + int(0, 1) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", - r"Union\[bytes, str\].*int")]) + self.assertErrorRegexes(errors, {"e": r"Union\[bytes, str\].*int"}) def testRemovedBuiltins(self): - errors = self.CheckWithErrors("""\ - long - {}.has_key + self.CheckWithErrors(""" + long # name-error + {}.has_key # attribute-error """) - self.assertErrorLogIs(errors, [(1, "name-error"), (2, "attribute-error")]) def testRange(self): - ty, errors = self.InferWithErrors("""\ - xrange(3) + ty, _ = self.InferWithErrors(""" + xrange(3) # name-error v = range(3) v[0] v[:] @@ -450,7 +442,6 @@ def testRange(self): y: int z: int """) - self.assertErrorLogIs(errors, [(1, "name-error")]) def testCreateStr(self): self.Check(""" @@ -569,8 +560,7 @@ def testOSErrorSubclasses(self): def testRawInput(self): # Removed in Python 3: - errors = self.CheckWithErrors("raw_input") - self.assertErrorLogIs(errors, [(1, "name-error")]) + self.CheckWithErrors("raw_input # name-error") def testClear(self): # new in Python 3 @@ -630,20 +620,18 @@ def testMinMax(self): """) def testStrIsNotInt(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" from typing import SupportsInt def f(x: SupportsInt): pass - f("") + f("") # wrong-arg-types """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types")]) def testStrIsNotFloat(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" from typing import SupportsFloat def f(x: SupportsFloat): pass - f("") + f("") # wrong-arg-types """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_checker.py b/pytype/tests/py3/test_checker.py index 19cb8ba81..f218fe232 100644 --- a/pytype/tests/py3/test_checker.py +++ b/pytype/tests/py3/test_checker.py @@ -17,27 +17,26 @@ def g(data: Set[str]): """) def testRecursiveForwardReference(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" class X(object): def __init__(self, val: "X"): pass def f(): - X(42) + X(42) # wrong-arg-types[e] """) - self.assertErrorLogIs(errorlog, [(5, "wrong-arg-types", r"X.*int")]) + self.assertErrorRegexes(errorlog, {"e": r"X.*int"}) def testBadReturnTypeInline(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" from typing import List def f() -> List[int]: - return [object()] + return [object()] # bad-return-type[e] f()[0] += 1 """) - self.assertErrorLogIs(errorlog, [(3, "bad-return-type", - r"List\[int\].*List\[object\]")]) + self.assertErrorRegexes(errorlog, {"e": r"List\[int\].*List\[object\]"}) def testUseVarargsAndKwargs(self): - self.Check("""\ + self.Check(""" class A(object): pass def f(*args: A, **kwargs: A): @@ -48,7 +47,7 @@ def f(*args: A, **kwargs: A): """) def testNestedNoneType(self): - self.Check("""\ + self.Check(""" from typing import List, Union def f1() -> Union[None]: pass @@ -61,7 +60,7 @@ def g2(x: List[None]): """) def testInnerClassInit(self): - self.Check("""\ + self.Check(""" from typing import List class A: def __init__(self): @@ -75,7 +74,7 @@ def h(): """) def testRecursion(self): - self.Check("""\ + self.Check(""" class A: def __init__(self, x: "B"): pass @@ -86,84 +85,81 @@ def __init__(self): """) def testBadDictValue(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" from typing import Dict def f() -> Dict[str, int]: - return {"x": 42.0} + return {"x": 42.0} # bad-return-type[e] """) - self.assertErrorLogIs(errorlog, [(3, "bad-return-type", r"int.*float")]) + self.assertErrorRegexes(errorlog, {"e": r"int.*float"}) def testInstanceAsAnnotation(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" def f(): pass - def g(x: f): + def g(x: f): # invalid-annotation[e1] pass - def h(x: 3): + def h(x: 3): # invalid-annotation[e2] pass """) - self.assertErrorLogIs(errorlog, [(3, "invalid-annotation", - r"instance of Callable.*x"), - (5, "invalid-annotation", - r"3.*x")]) + self.assertErrorRegexes( + errorlog, {"e1": r"instance of Callable.*x", "e2": r"3.*x"}) def testBadGenerator(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" from typing import Generator def f() -> Generator[str, None, None]: for i in range(3): - yield i + yield i # bad-return-type[e] """) - self.assertErrorLogIs(errorlog, [(4, "bad-return-type", r"str.*int")]) + self.assertErrorRegexes(errorlog, {"e": r"str.*int"}) def testMultipleParameterBindings(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" from typing import List def f(x) -> List[int]: - return ["", x] + return ["", x] # bad-return-type[e] """) - self.assertErrorLogIs(errorlog, [(3, "bad-return-type", - r"List\[int\].*List\[str\]")]) + self.assertErrorRegexes(errorlog, {"e": r"List\[int\].*List\[str\]"}) def testNoParamBinding(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" def f() -> None: x = [] - return x + return x # bad-return-type[e] """) - self.assertErrorLogIs(errorlog, [(3, "bad-return-type", - r"None.*List\[nothing\]")]) + self.assertErrorRegexes(errorlog, {"e": r"None.*List\[nothing\]"}) def testAttributeInIncompleteInstance(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" from typing import List class Foo(object): def __init__(self, other: "List[Foo]"): self.x = other[0].x # okay - self.y = other.y # No "y" on List[Foo] - self.z = Foo.z # No "z" on Type[Foo] + # No "y" on List[Foo] + self.y = other.y # attribute-error[e1] + # No "z" on Type[Foo] + self.z = Foo.z # attribute-error[e2] """) - self.assertErrorLogIs(errorlog, [(5, "attribute-error", r"y.*List\[Foo\]"), - (6, "attribute-error", r"z.*Type\[Foo\]")]) + self.assertErrorRegexes(errorlog, {"e1": r"y.*List\[Foo\]", + "e2": r"z.*Type\[Foo\]"}) def testBadGetItem(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" def f(x: int): - return x[0] + return x[0] # unsupported-operands[e] """) - self.assertErrorLogIs(errorlog, [(2, "unsupported-operands", r"int.*int")]) + self.assertErrorRegexes(errorlog, {"e": r"int.*int"}) def testBadAnnotationContainer(self): - errorlog = self.CheckWithErrors("""\ + errorlog = self.CheckWithErrors(""" class A(object): pass - def f(x: int[str]): + def f(x: int[str]): # not-indexable[e1] pass - def g(x: A[str]): + def g(x: A[str]): # not-indexable[e2] pass """) - self.assertErrorLogIs(errorlog, [(3, "not-indexable", r"Generic"), - (5, "not-indexable", r"Generic")]) + self.assertErrorRegexes(errorlog, {"e1": r"Generic", "e2": r"Generic"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_classes.py b/pytype/tests/py3/test_classes.py index 16e2a2860..ecbab92f4 100644 --- a/pytype/tests/py3/test_classes.py +++ b/pytype/tests/py3/test_classes.py @@ -61,7 +61,7 @@ def Create(self, x: MyType): """) def testRecursiveConstructorBadAttribute(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import List MyType = List['Foo'] class Foo(object): @@ -70,9 +70,9 @@ def __init__(self, x): def Create(self, x: MyType): self.x = x def Convert(self): - self.y + self.y # attribute-error[e] """) - self.assertErrorLogIs(errors, [(9, "attribute-error", r"y.*Foo")]) + self.assertErrorRegexes(errors, {"e": r"y.*Foo"}) def testRecursiveConstructorSubclass(self): self.Check(""" @@ -118,7 +118,7 @@ class Foo(List[str]): ... """) def testMakeGenericClass(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List, TypeVar, Union T1 = TypeVar("T1") T2 = TypeVar("T2") @@ -132,7 +132,7 @@ class Foo(List[Union[T1, T2]]): ... """) def testMakeGenericClassWithConcreteValue(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Dict, TypeVar V = TypeVar("V") class Foo(Dict[str, V]): ... @@ -150,7 +150,7 @@ def testGenericReinstantiated(self): """Makes sure the result of foo.f() isn't used by both a() and b().""" with file_utils.Tempdir() as d: d.create_file("foo.pyi", "def f() -> list: ...") - self.Check("""\ + self.Check(""" import foo from typing import List def a() -> List[str]: @@ -162,24 +162,23 @@ def b() -> List[int]: """, pythonpath=[d.path]) def testParentInit(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Sequence class X(object): def __init__(self, obj: Sequence): pass class Y(X): def __init__(self, obj: int): - X.__init__(self, obj) # line 7 + X.__init__(self, obj) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(7, "wrong-arg-types", r"Sequence.*int")]) + self.assertErrorRegexes(errors, {"e": r"Sequence.*int"}) def testParameterizedClassBinaryOperator(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import Sequence def f(x: Sequence[str], y: Sequence[str]) -> None: - a = x + y + a = x + y # unsupported-operands """) - self.assertErrorLogIs(errors, [(3, "unsupported-operands")]) def testInstanceAttribute(self): ty = self.Infer(""" @@ -229,7 +228,7 @@ def foo(self) -> int: def testBuildClassQuick(self): # A() hits maximum stack depth in python3.6 - ty = self.Infer("""\ + ty = self.Infer(""" def f(): class A(object): pass return {A: A()} @@ -276,7 +275,7 @@ def f(x: Foo): """) def testInitTestClassInSetup(self): - ty = self.Infer("""\ + ty = self.Infer(""" import unittest class A(unittest.TestCase): def setUp(self): @@ -293,7 +292,7 @@ def fooTest(self) -> int: ... """) def testInitInheritedTestClassInSetup(self): - ty = self.Infer("""\ + ty = self.Infer(""" import unittest class A(unittest.TestCase): def setUp(self): @@ -313,7 +312,7 @@ def fooTest(self) -> int: ... """) def testInitTestClassInInitAndSetup(self): - ty = self.Infer("""\ + ty = self.Infer(""" import unittest class A(unittest.TestCase): def __init__(self, foo: str): @@ -413,15 +412,14 @@ def bar(cls): """) def testPy2Metaclass(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import abc - class Foo(object): + class Foo(object): # ignored-metaclass[e] __metaclass__ = abc.ABCMeta @abc.abstractmethod def f(self) -> int: ... """) - self.assertErrorLogIs( - errors, [(2, "ignored-metaclass", r"abc\.ABCMeta.*Foo")]) + self.assertErrorRegexes(errors, {"e": r"abc\.ABCMeta.*Foo"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_coroutine.py b/pytype/tests/py3/test_coroutine.py index c1348ea1b..eed7d2855 100644 --- a/pytype/tests/py3/test_coroutine.py +++ b/pytype/tests/py3/test_coroutine.py @@ -69,9 +69,9 @@ def caller() -> Coroutine[Any, Any, Union[int, str]]: ... """) def testNativeCoroutineError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" async def f1() -> str: - return 1 + return 1 # bad-return-type[e1] async def f2() -> int: return 1 @@ -84,13 +84,11 @@ def f4(x: str): async def caller(): f4(await f1()) - f4(await f2()) - f4(await f3()) + f4(await f2()) # wrong-arg-types[e2] + f4(await f3()) # wrong-arg-types[e3] """) - self.assertErrorLogIs(errors, [ - (2, "bad-return-type", r"str.*int"), - (15, "wrong-arg-types", r"str.*int"), - (16, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes( + errors, {"e1": r"str.*int", "e2": r"str.*int", "e3": r"str.*int"}) def testGeneratorBasedCoroutinePyi(self): ty = self.Infer(""" @@ -132,7 +130,7 @@ def f3() -> Coroutine[Any, Any, Union[int, str]]: ... """) def testGeneratorBasedCoroutineError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Generator import types @@ -149,13 +147,12 @@ def f3(x, y: str): pass async def caller(): - x = await f1() + x = await f1() # bad-return-type[e1] y = await f2() - f3(x, y) + f3(x, y) # wrong-arg-types[e2] """) - self.assertErrorLogIs(errors, [ - (17, "bad-return-type", r"Awaitable.*int"), - (19, "wrong-arg-types", r"y: str.*y: int")]) + self.assertErrorRegexes( + errors, {"e1": r"Awaitable.*int", "e2": r"y: str.*y: int"}) def testAwaitablePyi(self): ty = self.Infer(""" @@ -215,15 +212,14 @@ def f3() -> Coroutine[Any, Any, None]: ... """) def testInvalidAwaitable(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class A(object): pass async def fun(): - await A() + await A() # bad-return-type[e] """) - self.assertErrorLogIs(errors, [ - (5, "bad-return-type", r"Awaitable.*A")]) + self.assertErrorRegexes(errors, {"e": r"Awaitable.*A"}) def testAsyncForPyi(self): ty = self.Infer(""" @@ -262,7 +258,7 @@ def caller() -> Coroutine[Any, Any, List[Union[int, str]]]: ... """) def testAsyncForError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Iter1(object): pass @@ -298,21 +294,19 @@ async def __anext__(self): async def caller(): res = [] - async for i in Iter1(): + async for i in Iter1(): # attribute-error[e1] res.append(i) - async for i in Iter2(): + async for i in Iter2(): # attribute-error[e2] res.append(i) - async for i in Iter3(): + async for i in Iter3(): # bad-return-type[e3] res.append(i) async for i in Iter4(): res.append(i) return res """) - self.assertErrorLogIs(errors, [ - (36, "attribute-error", r"No attribute.*__aiter__"), - (38, "attribute-error", r"No attribute.*__anext__"), - (40, "bad-return-type", r"Awaitable.*Union\[int, str]"), - ]) + self.assertErrorRegexes(errors, {"e1": r"No attribute.*__aiter__", + "e2": r"No attribute.*__anext__", + "e3": r"Awaitable.*Union\[int, str\]"}) def testAsyncWithPyi(self): ty = self.Infer(""" @@ -355,7 +349,8 @@ def log(s: _T0) -> Coroutine[Any, Any, _T0]: ... """) def testAsyncWithError(self): - errors = self.CheckWithErrors("""\ + # pylint: disable=anomalous-backslash-in-string + errors = self.CheckWithErrors(""" class AsyncCtx1(object): pass @@ -367,15 +362,15 @@ def __aexit__(self, exc_type, exc, tb): return "str" async def caller(): - async with AsyncCtx1() as var1, AsyncCtx2() as var2: - pass + ctx1 = AsyncCtx1() + ctx2 = AsyncCtx2() + async with ctx1 as var1: # attribute-error[e1] # attribute-error[e2] + async with ctx2 as var2: # bad-return-type[e3] + pass # bad-return-type[e4] """) - self.assertErrorLogIs(errors, [ - (12, "attribute-error", r"No attribute.*__aexit__"), - (12, "attribute-error", r"No attribute.*__aenter__"), - (12, "bad-return-type", r"Awaitable.*AsyncCtx2"), - (13, "bad-return-type", r"Awaitable.*str"), - ]) + self.assertErrorRegexes(errors, { + "e1": r"No attribute.*__aexit__", "e2": r"No attribute.*__aenter__", + "e3": r"Awaitable.*AsyncCtx2", "e4": r"Awaitable.*str"}) def testLoadPyi(self): with file_utils.Tempdir() as d: diff --git a/pytype/tests/py3/test_dataclasses.py b/pytype/tests/py3/test_dataclasses.py index 3e812f420..42e9ecef5 100644 --- a/pytype/tests/py3/test_dataclasses.py +++ b/pytype/tests/py3/test_dataclasses.py @@ -135,31 +135,28 @@ def __init__(self, x: bool = ..., y: List[int] = ...) -> None: ... """) def test_type_mismatch(self): - err = self.CheckWithErrors(""" + self.CheckWithErrors(""" import dataclasses @dataclasses.dataclass() - class Foo(object): + class Foo(object): # annotation-type-mismatch x: bool = 10 """) - self.assertErrorLogIs(err, [(4, "annotation-type-mismatch")]) def test_field_type_mismatch(self): - err = self.CheckWithErrors(""" + self.CheckWithErrors(""" import dataclasses @dataclasses.dataclass() - class Foo(object): + class Foo(object): # annotation-type-mismatch x: bool = dataclasses.field(default=10) """) - self.assertErrorLogIs(err, [(4, "annotation-type-mismatch")]) def test_factory_type_mismatch(self): - err = self.CheckWithErrors(""" + self.CheckWithErrors(""" import dataclasses @dataclasses.dataclass() - class Foo(object): + class Foo(object): # annotation-type-mismatch x: bool = dataclasses.field(default_factory=set) """) - self.assertErrorLogIs(err, [(4, "annotation-type-mismatch")]) def test_field_no_init(self): ty = self.Infer(""" @@ -194,14 +191,13 @@ def __init__(self, x: bool, y: int) -> None: ... """) def test_bad_default_param_order(self): - err = self.CheckWithErrors(""" + self.CheckWithErrors(""" import dataclasses @dataclasses.dataclass() - class Foo(object): + class Foo(object): # invalid-function-definition x: int = 10 y: str """) - self.assertErrorLogIs(err, [(4, "invalid-function-definition")]) def test_any(self): self.Check(""" diff --git a/pytype/tests/py3/test_decorators.py b/pytype/tests/py3/test_decorators.py index f21339cec..870aa7016 100644 --- a/pytype/tests/py3/test_decorators.py +++ b/pytype/tests/py3/test_decorators.py @@ -7,20 +7,19 @@ class DecoratorsTest(test_base.TargetPython3BasicTest): """Test decorators.""" def testAnnotatedSuperCallUnderBadDecorator(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" class Foo(object): def Run(self) -> None: ... class Bar(Foo): - @bad_decorator # line 4 + @bad_decorator # name-error def Run(self): return super(Bar, self).Run() """) - self.assertErrorLogIs(errors, [(4, "name-error", r"bad_decorator")]) def testReplaceSelfToStarArg(self): # Without decorator, `self` will be in `signature.param_names`. # But after replacing, `*args` won't be in `signature.param_names`. - self.Check("""\ + self.Check(""" from typing import TypeVar T = TypeVar('T') diff --git a/pytype/tests/py3/test_dict.py b/pytype/tests/py3/test_dict.py index 2f89f742b..6c102391d 100644 --- a/pytype/tests/py3/test_dict.py +++ b/pytype/tests/py3/test_dict.py @@ -21,16 +21,15 @@ def foo(x: Union[int, None]) -> Any """) def testObjectInDict(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" from typing import Any, Dict def objectIsStr() -> Dict[str, Any]: - return {object(): ""} + return {object(): ""} # bad-return-type """) - self.assertErrorLogIs(errors, [(3, "bad-return-type")]) def testBigConcreteDict(self): # Test that we don't timeout. - errorlog = self.CheckWithErrors("""\ + self.CheckWithErrors(""" from typing import Dict, Tuple, Union # A concrete dictionary with lots of concrete keys and a complicated # value type. @@ -50,9 +49,8 @@ def testBigConcreteDict(self): def f() -> Dict[Union[str, Tuple[str, None]], ValueType]: return d def g() -> Dict[int, int]: - return d # line 20 + return d # bad-return-type """) - self.assertErrorLogIs(errorlog, [(20, "bad-return-type")]) def testDictOfTuple(self): # utils.deep_variable_product(group_dict) generates a lot of combinations. diff --git a/pytype/tests/py3/test_errors.py b/pytype/tests/py3/test_errors.py index 6293dc2aa..04ad1e054 100644 --- a/pytype/tests/py3/test_errors.py +++ b/pytype/tests/py3/test_errors.py @@ -10,7 +10,7 @@ class ErrorTest(test_base.TargetPython3BasicTest): """Tests for errors.""" def testUnion(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x: int): pass if __random__: @@ -18,176 +18,160 @@ def f(x: int): else: i = 1 x = (3.14, "") - f(x[i]) + f(x[i]) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(8, "wrong-arg-types", - r"Actually passed:.*Union\[float, str\]")]) + self.assertErrorRegexes( + errors, {"e": r"Actually passed:.*Union\[float, str\]"}) def testInvalidAnnotations(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Dict, List, Union def f1(x: Dict): # okay pass - def f2(x: Dict[str]): + def f2(x: Dict[str]): # invalid-annotation[e1] pass - def f3(x: List[int, str]): + def f3(x: List[int, str]): # invalid-annotation[e2] pass - def f4(x: Union): + def f4(x: Union): # invalid-annotation[e3] pass """) - self.assertErrorLogIs(errors, [ - (4, "invalid-annotation", r"typing.Dict\[_K, _V].*2.*1"), - (6, "invalid-annotation", r"typing.List\[_T].*1.*2"), - (8, "invalid-annotation", r"Union.*x")]) + self.assertErrorRegexes(errors, {"e1": r"typing.Dict\[_K, _V].*2.*1", + "e2": r"typing.List\[_T].*1.*2", + "e3": r"Union.*x"}) def testPrintUnsolvable(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import List - def f(x: List[nonsense], y: str, z: float): + def f(x: List[nonsense], y: str, z: float): # name-error pass - f({nonsense}, "", "") + f({nonsense}, "", "") # name-error # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [ - (2, "name-error", r"nonsense"), - (4, "name-error", r"nonsense"), - (4, "wrong-arg-types", r"Expected:.*x: list.*Actual.*x: set")]) + self.assertErrorRegexes( + errors, {"e": r"Expected:.*x: list.*Actual.*x: set"}) def testPrintUnionOfContainers(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x: str): pass if __random__: x = dict else: x = [float] - f(x) + f(x) # wrong-arg-types[e] """) error = r"Actual.*Union\[List\[Type\[float\]\], Type\[dict\]\]" - self.assertErrorLogIs(errors, [(7, "wrong-arg-types", error)]) + self.assertErrorRegexes(errors, {"e": error}) def testWrongBrackets(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import List - def f(x: List(str)): + def f(x: List(str)): # not-callable[e] pass """) - self.assertErrorLogIs(errors, [(2, "not-callable", r"List")]) + self.assertErrorRegexes(errors, {"e": r"List"}) def testInterpreterClassPrinting(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): pass def f(x: str): pass - f(Foo()) + f(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types", r"str.*Foo")]) + self.assertErrorRegexes(errors, {"e": r"str.*Foo"}) def testPrintDictAndTuple(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Tuple tup = None # type: Tuple[int, ...] dct = None # type: dict[str, int] - def f1(x: (int, str)): # line 4 + def f1(x: (int, str)): # invalid-annotation[e1] pass - def f2(x: tup): # line 6 + def f2(x: tup): # invalid-annotation[e2] pass - def g1(x: {"a": 1}): # line 8 + def g1(x: {"a": 1}): # invalid-annotation[e3] pass - def g2(x: dct): # line 10 + def g2(x: dct): # invalid-annotation[e4] pass """) - self.assertErrorLogIs(errors, [ - (4, "invalid-annotation", r"(int, str).*Not a type"), - (6, "invalid-annotation", - r"instance of Tuple\[int, \.\.\.\].*Not a type"), - (8, "invalid-annotation", r"{'a': '1'}.*Not a type"), - (10, "invalid-annotation", r"instance of Dict\[str, int\].*Not a type") - ]) + self.assertErrorRegexes(errors, { + "e1": r"(int, str).*Not a type", + "e2": r"instance of Tuple\[int, \.\.\.\].*Not a type", + "e3": r"{'a': '1'}.*Not a type", + "e4": r"instance of Dict\[str, int\].*Not a type"}) def testMoveUnionInward(self): - _, errors = self.InferWithErrors("""\ - def f() -> str: + _, errors = self.InferWithErrors(""" + def f() -> str: # invalid-annotation[e] y = "hello" if __random__ else 42 yield y """) - self.assertErrorLogIs(errors, [( - 1, "invalid-annotation", r"Generator, Iterable or Iterator")]) + self.assertErrorRegexes(errors, {"e": r"Generator, Iterable or Iterator"}) def testInnerClassError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x: str): pass def g(): class Foo(object): pass - f(Foo()) + f(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"x: str.*x: Foo")]) + self.assertErrorRegexes(errors, {"e": r"x: str.*x: Foo"}) def testInnerClassError2(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(): class Foo(object): pass def g(x: Foo): pass - g("") + g("") # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"x: Foo.*x: str")]) + self.assertErrorRegexes(errors, {"e": r"x: Foo.*x: str"}) def testCleanNamedtupleNames(self): # Make sure the namedtuple renaming in _pytd_print correctly extracts type # names and doesn't erase other types accidentally. - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import collections X = collections.namedtuple("X", "a b c d") Y = collections.namedtuple("Z", "") W = collections.namedtuple("W", "abc def ghi abc", rename=True) def bar(x: str): return x - bar(X(1,2,3,4)) # 7 - bar(Y()) # 8 - bar(W(1,2,3,4)) # 9 - bar({1: 2}.__iter__()) # 10 + bar(X(1,2,3,4)) # wrong-arg-types[e1] + bar(Y()) # wrong-arg-types[e2] + bar(W(1,2,3,4)) # wrong-arg-types[e3] + bar({1: 2}.__iter__()) # wrong-arg-types[e4] if __random__: a = X(1,2,3,4) else: a = 1 - bar(a) # 15 + bar(a) # wrong-arg-types[e5] """) - self.assertErrorLogIs(errors, - [(7, "wrong-arg-types", r"`X`"), - (8, "wrong-arg-types", r"`Z`"), - (9, "wrong-arg-types", r"`W`"), - (10, "wrong-arg-types", r"`dictionary-keyiterator`"), - (15, "wrong-arg-types", r"Union\[int, `X`\]") - ]) + self.assertErrorRegexes(errors, { + "e1": r"`X`", "e2": r"`Z`", "e3": r"`W`", + "e4": r"`dictionary-keyiterator`", "e5": r"Union\[int, `X`\]"}) def testArgumentOrder(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def g(f: str, a, b, c, d, e,): pass - g(a=1, b=2, c=3, d=4, e=5, f=6) + g(a=1, b=2, c=3, d=4, e=5, f=6) # wrong-arg-types[e] """) - self.assertErrorLogIs( - errors, - [(3, "wrong-arg-types", - r"Expected.*f: str, \.\.\..*Actual.*f: int, \.\.\.")] - ) + self.assertErrorRegexes(errors, { + "e": r"Expected.*f: str, \.\.\..*Actual.*f: int, \.\.\."}) def testConversionOfGeneric(self): - _, errors = self.InferWithErrors(""" + self.InferWithErrors(""" import os def f() -> None: - return os.walk("/tmp") + return os.walk("/tmp") # bad-return-type """) - self.assertErrorLogIs(errors, [ - (4, "bad-return-type") - ]) def testInnerClass(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f() -> int: class Foo(object): pass - return Foo() # line 4 + return Foo() # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(4, "bad-return-type", r"int.*Foo")]) + self.assertErrorRegexes(errors, {"e": r"int.*Foo"}) def testNestedProtoClass(self): with file_utils.Tempdir() as d: @@ -197,35 +181,32 @@ class _Foo_DOT_Bar: ... class Foo: Bar = ... # type: Type[_Foo_DOT_Bar] """) - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import foo_bar def f(x: foo_bar.Foo.Bar): ... - f(42) + f(42) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs( - errors, [(3, "wrong-arg-types", r"foo_bar\.Foo\.Bar")]) + self.assertErrorRegexes(errors, {"e": r"foo_bar\.Foo\.Bar"}) def testStaticmethodInError(self): with file_utils.Tempdir() as d: - d.create_file("foo.pyi", """\ + d.create_file("foo.pyi", """ class A(object): @staticmethod def t(a: str) -> None: ... """) - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Callable import foo def f(x: Callable[[int], None], y: int) -> None: return x(y) - f(foo.A.t, 1) + f(foo.A.t, 1) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs( - errors, - [(5, "wrong-arg-types", - r"Actually passed: \(x: Callable\[\[str\], None\]")]) + self.assertErrorRegexes( + errors, {"e": r"Actually passed: \(x: Callable\[\[str\], None\]"}) def testGeneratorSend(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Generator, Any def f(x) -> Generator[Any, int, Any]: if x == 1: @@ -234,43 +215,41 @@ def f(x) -> Generator[Any, int, Any]: yield "1" x = f(2) - x.send("123") + x.send("123") # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(9, "wrong-arg-types", - r"\(self, value: int\)")]) + self.assertErrorRegexes(errors, {"e": r"\(self, value: int\)"}) def testGeneratorIteratorRetType(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Iterator def f() -> Iterator[str]: - yield 1 + yield 1 # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(3, "bad-return-type", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) def testGeneratorIterableRetType(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Iterable def f() -> Iterable[str]: - yield 1 + yield 1 # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(3, "bad-return-type", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) class InPlaceOperationsTest(test_base.TargetPython3BasicTest): """Test in-place operations.""" def _testOp(self, op, symbol): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class A(object): def __%s__(self, x: "A"): return None def f(): v = A() - v %s 3 # line 6 + v %s 3 # unsupported-operands[e] """ % (op, symbol)) - self.assertErrorLogIs(errors, [ - (6, "unsupported-operands", - r"%s.*A.*int.*__%s__ on A.*A" % (re.escape(symbol), op))]) + self.assertErrorRegexes(errors, { + "e": r"%s.*A.*int.*__%s__ on A.*A" % (re.escape(symbol), op)}) def testISub(self): self._testOp("isub", "-=") @@ -279,7 +258,7 @@ def testIMul(self): self._testOp("imul", "*=") def testIDiv(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class A(object): def __idiv__(self, x: "A"): return None @@ -287,10 +266,10 @@ def __itruediv__(self, x: "A"): return None def f(): v = A() - v /= 3 # line 8 + v /= 3 # unsupported-operands[e] """) - self.assertErrorLogIs(errors, [ - (8, "unsupported-operands", r"\/\=.*A.*int.*__i(true)?div__ on A.*A")]) + self.assertErrorRegexes( + errors, {"e": r"\/\=.*A.*int.*__i(true)?div__ on A.*A"}) def testIMod(self): self._testOp("imod", "%=") @@ -321,54 +300,53 @@ class ErrorTestPy3(test_base.TargetPython3FeatureTest): """Tests for errors.""" def testProtocolMismatch(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): pass - next(Foo()) + next(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [ - (2, "wrong-arg-types", "__iter__, __next__") - ]) + self.assertErrorRegexes(errors, {"e": r"__iter__, __next__"}) def testProtocolMismatchPartial(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __iter__(self): return self - next(Foo()) + next(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [( - 4, "wrong-arg-types", r"\n\s*__next__\s*$")]) # `next` on its own line + self.assertErrorRegexes( + errors, {"e": r"\n\s*__next__\s*$"}) # `next` on its own line def testGeneratorSendRetType(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generator def f() -> Generator[int, str, int]: x = yield 1 - return x + return x # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(4, "bad-return-type", r"int.*str")]) + self.assertErrorRegexes(errors, {"e": r"int.*str"}) class MatrixOperationsTest(test_base.TargetPython3FeatureTest): """Test matrix operations.""" def testMatMul(self): - errors = self.CheckWithErrors("def f(): return 'foo' @ 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\@.*str.*int.*'__matmul__' on str.*'__rmatmul__' on int")]) + errors = self.CheckWithErrors(""" + def f(): + return 'foo' @ 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\@.*str.*int.*'__matmul__' on str.*'__rmatmul__' on int"}) def testIMatMul(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class A(object): def __imatmul__(self, x: "A"): pass def f(): v = A() - v @= 3 # line 6 + v @= 3 # unsupported-operands[e] """) - self.assertErrorLogIs(errors, [ - (6, "unsupported-operands", r"\@.*A.*int.*__imatmul__ on A.*A")]) + self.assertErrorRegexes(errors, {"e": r"\@.*A.*int.*__imatmul__ on A.*A"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_exceptions.py b/pytype/tests/py3/test_exceptions.py index c9f9de5f9..97e3de9d9 100644 --- a/pytype/tests/py3/test_exceptions.py +++ b/pytype/tests/py3/test_exceptions.py @@ -18,8 +18,7 @@ def test_raise_exception_from(self): def test_exception_message(self): # This attribute was removed in Python 3. - errors = self.CheckWithErrors("ValueError().message") - self.assertErrorLogIs(errors, [(1, "attribute-error")]) + self.CheckWithErrors("ValueError().message # attribute-error") def test_suppress_context(self): self.Check("ValueError().__suppress_context__") diff --git a/pytype/tests/py3/test_flow.py b/pytype/tests/py3/test_flow.py index 32de2ccaf..3df62e873 100644 --- a/pytype/tests/py3/test_flow.py +++ b/pytype/tests/py3/test_flow.py @@ -27,7 +27,7 @@ def foo() -> str: """) def test_cfg_cycle_singlestep(self): - self.Check("""\ + self.Check(""" import typing class Foo(object): x = ... # type: typing.Optional[int] diff --git a/pytype/tests/py3/test_functions.py b/pytype/tests/py3/test_functions.py index 1ad2c39b7..4cdd67a39 100644 --- a/pytype/tests/py3/test_functions.py +++ b/pytype/tests/py3/test_functions.py @@ -8,19 +8,19 @@ class TestClosures(test_base.TargetPython3BasicTest): """Tests for closures.""" def test_error(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(x: int): def g(): - return x.upper() + return x.upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(3, "attribute-error", "upper.*int")]) + self.assertErrorRegexes(errors, {"e": r"upper.*int"}) class TestClosuresPy3(test_base.TargetPython3FeatureTest): """Tests for closures in Python 3.""" def test_if_split_delete_deref(self): - ty = self.Infer("""\ + ty = self.Infer(""" def f(a: int): x = "hello" def g(): @@ -37,19 +37,18 @@ def f(a: int) -> Optional[str] """) def test_closures_delete_deref(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def f(): x = "hello" def g(): nonlocal x # force x to be stored in a closure cell x = 10 del x - return x + return x # name-error """) - self.assertErrorLogIs(errors, [(7, "name-error")]) def test_nonlocal(self): - ty = self.Infer("""\ + ty = self.Infer(""" def f(): x = "hello" def g(): @@ -63,19 +62,18 @@ def f() -> int """) def test_nonlocal_delete_deref(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def f(): x = True def g(): nonlocal x del x g() - return x + return x # name-error """) - self.assertErrorLogIs(errors, [(7, "name-error")]) def test_reuse_after_delete_deref(self): - ty = self.Infer("""\ + ty = self.Infer(""" def f(): x = True def g(): @@ -90,18 +88,18 @@ def f() -> int """) def test_closure_annotations(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(): a = 1 def g(x: int) -> int: a # makes sure g is a closure - return "hello" + return "hello" # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(5, "bad-return-type", "int.*str")]) + self.assertErrorRegexes(errors, {"e": r"int.*str"}) def test_filter_before_delete(self): # TODO(b/117463644): Remove the disable on line 7. - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" from typing import Optional def f(x: Optional[str]): if x is None: @@ -111,9 +109,8 @@ def nested(): print(x.upper()) # pytype: disable=name-error del x nested() - return x # line 10 + return x # name-error """) - self.assertErrorLogIs(errors, [(10, "name-error")]) class PreciseReturnTest(test_base.TargetPython3BasicTest): @@ -124,38 +121,38 @@ def setUp(self): self.options.tweak(precise_return=True) def test_interpreter_return(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" def f(x: str) -> str: return x - x = f(0) + x = f(0) # wrong-arg-types[e] """) self.assertTypesMatchPytd(ty, """ def f(x: str) -> str: ... x: str """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) def test_interpreter_unknown_return(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" def f(x: str): return x - x = f(0) + x = f(0) # wrong-arg-types[e] """) self.assertTypesMatchPytd(ty, """ from typing import Any def f(x: str) -> str: ... x: Any """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) def test_interpreter_overload(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import overload @overload def f(x: str) -> str: ... def f(x): return x - x = f(0) + x = f(0) # wrong-arg-types[e] """) self.assertTypesMatchPytd(ty, """ from typing import overload @@ -163,14 +160,14 @@ def f(x): def f(x: str) -> str: ... x: str """) - self.assertErrorLogIs(errors, [(6, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) class TestFunctions(test_base.TargetPython3BasicTest): """Tests for functions.""" def test_function_to_callable(self): - ty = self.Infer("""\ + ty = self.Infer(""" def f(): def g1(x: int, y: bool) -> str: return "hello world" @@ -184,7 +181,7 @@ def f() -> Tuple[Callable[[int, bool], str], Callable[[], int]] """) def test_function_to_callable_return_only(self): - ty = self.Infer("""\ + ty = self.Infer(""" def f(): def g1(x=None) -> int: return 42 @@ -198,7 +195,7 @@ def f() -> Tuple[Callable[..., int], Callable[..., str]] """) def test_fake_arguments(self): - self.Check("""\ + self.Check(""" class Foo(object): def __init__(self, x: int): @@ -238,24 +235,20 @@ def f( """) def test_typecheck_varargs(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" def f(*args: int) -> int: return args[0] - f(*['value']) - f(1, 'hello', 'world') + f(*['value']) # wrong-arg-types + f(1, 'hello', 'world') # wrong-arg-types """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types"), - (4, "wrong-arg-types")]) def test_typecheck_kwargs(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" def f(**kwargs: int) -> int: return len(kwargs.values()) - f(**{'arg': 'value'}) - f(arg='value', arg2=3) - """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types"), - (4, "wrong-arg-types")]) + f(**{'arg': 'value'}) # wrong-arg-types + f(arg='value', arg2=3) # wrong-arg-types + """) def test_pass_func_to_complex_func(self): # This test gets an unsolvable binding added to the variable containing the @@ -301,17 +294,14 @@ def bar(*y: int): """) def text_varargs_errors(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def foo(x: str, *y: int): pass - foo(*[1, 2, 3]) + foo(*[1, 2, 3]) # wrong-arg-types[e1] def bar(*z: int): - foo(*z) + foo(*z) # wrong-arg-types[e2] """) - self.assertErrorLogIs( - errors, - [(3, "wrong-arg-types", "str.*int"), - (5, "wrong-arg-types", "str.*int")]) + self.assertErrorRegexes(errors, {"e1": r"str.*int", "e2": r"str.*int"}) def test_varargs_in_pyi(self): with file_utils.Tempdir() as d: @@ -329,12 +319,12 @@ def test_varargs_in_pyi_error(self): d.create_file("foo.pyi", """ def f(x: int, *args): ... """) - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import foo def g(*args): - foo.f("", *args) + foo.f("", *args) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types", "int.*str")]) + self.assertErrorRegexes(errors, {"e": r"int.*str"}) class TestFunctionsPython3Feature(test_base.TargetPython3FeatureTest): @@ -593,13 +583,13 @@ def foo(x: int, *args: int, z: int) -> None: """) def test_varargs_with_missing_kwonly(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def foo(x: int, *args: int, z: int) -> None: pass - foo(1, 2, 5) + foo(1, 2, 5) # missing-parameter[e] """) - self.assertErrorLogIs(errors, [(4, "missing-parameter", r"\bz\b")]) + self.assertErrorRegexes(errors, {"e": r"\bz\b"}) def test_multiple_varargs_packs(self): self.Check(""" @@ -616,17 +606,14 @@ def bar(y: Tuple[int], *z: int): """) def text_multiple_varargs_packs_errors(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def foo(x: str, *y: int): pass - foo(*[1, 2, 3], *[4, 5, 6]) + foo(*[1, 2, 3], *[4, 5, 6]) # wrong-arg-types[e1] def bar(*z: int): - foo(*z, *z) + foo(*z, *z) # wrong-arg-types[e2] """) - self.assertErrorLogIs( - errors, - [(3, "wrong-arg-types", "str.*int"), - (5, "wrong-arg-types", "str.*int")]) + self.assertErrorRegexes(errors, {"e1": r"str.*int", "e2": r"str.*int"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_generators.py b/pytype/tests/py3/test_generators.py index 60bc4f4a7..b9bcd6512 100644 --- a/pytype/tests/py3/test_generators.py +++ b/pytype/tests/py3/test_generators.py @@ -30,12 +30,12 @@ def f() -> Iterable: """) def testNoReturn(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generator def f() -> Generator[str, None, None]: - yield 42 + yield 42 # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(3, "bad-return-type", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) class GeneratorFeatureTest(test_base.TargetPython3FeatureTest): @@ -90,24 +90,22 @@ def f() -> Generator[str, int, Any] """) def testParameterCount(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generator def func1() -> Generator[int, int, int]: x = yield 5 return x - def func2() -> Generator[int, int]: + def func2() -> Generator[int, int]: # invalid-annotation[e1] x = yield 5 - def func3() -> Generator[int]: + def func3() -> Generator[int]: # invalid-annotation[e2] yield 5 """) - self.assertErrorLogIs(errors, [ - (7, "invalid-annotation", - r"typing.Generator\[_T, _T2, _V].*3.*2"), - (10, "invalid-annotation", - r"typing.Generator\[_T, _T2, _V].*3.*1")]) + self.assertErrorRegexes(errors, { + "e1": r"typing.Generator\[_T, _T2, _V].*3.*2", + "e2": r"typing.Generator\[_T, _T2, _V].*3.*1"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_generic.py b/pytype/tests/py3/test_generic.py index 07cdcd212..a157b91fc 100644 --- a/pytype/tests/py3/test_generic.py +++ b/pytype/tests/py3/test_generic.py @@ -8,28 +8,27 @@ class GenericBasicTest(test_base.TargetPython3BasicTest): """Tests for User-defined Generic Type.""" def testGenericTypeParamsError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generic - class A(Generic[int]): + class A(Generic[int]): # invalid-annotation[e] pass """) - self.assertErrorLogIs(errors, [ - (3, "invalid-annotation", "Parameters.*Generic.*must.*type variables")]) + self.assertErrorRegexes( + errors, {"e": r"Parameters.*Generic.*must.*type variables"}) def testMroError(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import Generic, Iterator, Generator, TypeVar T = TypeVar('T') - class A(Generic[T], Iterator[T], Generator): + class A(Generic[T], Iterator[T], Generator): # mro-error pass """) - self.assertErrorLogIs(errors, [(5, "mro-error")]) def testTemplateOrderError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generic, TypeVar T1 = TypeVar('T1') @@ -60,16 +59,15 @@ def func(self, x: K1, y: K2): A = ClassA[int, str, int, int]() B = ClassB[int, str, int, int]() - A.func(5, "5") # Error + A.func(5, "5") # wrong-arg-types[e1] A.func("5", 5) # OK B.func(5, "5") # OK - B.func("5", 5) # Error + B.func("5", 5) # wrong-arg-types[e2] """) - self.assertErrorLogIs(errors, [(31, "wrong-arg-types", r"str.*int"), - (34, "wrong-arg-types", r"int.*str")]) + self.assertErrorRegexes(errors, {"e1": r"str.*int", "e2": r"int.*str"}) def testTypeErasureError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar, Generic T = TypeVar('T', int, float) @@ -82,25 +80,23 @@ def __init__(self, x: T = None, y: S = None): def fun(self, x: T, y: S): pass - o1 = MyClass[str, str]() + o1 = MyClass[str, str]() # bad-concrete-type[e1] o2 = MyClass[int, int]() - o2.fun("5", 5) - o2.fun(5, "5") + o2.fun("5", 5) # wrong-arg-types[e2] + o2.fun(5, "5") # wrong-arg-types[e3] """) - self.assertErrorLogIs(errors, [ - (13, "bad-concrete-type", r"Union\[float, int\].*str"), - (15, "wrong-arg-types", r"x: int.*x: str"), - (16, "wrong-arg-types", r"y: int.*y: str")]) + self.assertErrorRegexes(errors, {"e1": r"Union\[float, int\].*str", + "e2": r"x: int.*x: str", + "e3": r"y: int.*y: str"}) def testInhericPlainGenericError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generic - class A(Generic): + class A(Generic): # invalid-annotation[e] pass """) - self.assertErrorLogIs( - errors, [(3, "invalid-annotation", r"Cannot inherit.*plain Generic")]) + self.assertErrorRegexes(errors, {"e": r"Cannot inherit.*plain Generic"}) def testGenericWithDupTypeError(self): with file_utils.Tempdir() as d: @@ -110,11 +106,10 @@ def testGenericWithDupTypeError(self): T = TypeVar('T') class A(Generic[T, T]): ... """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs( - errors, [(1, "pyi-error", "Duplicate.*T.*a.A")]) + self.assertErrorRegexes(errors, {"e": r"Duplicate.*T.*a.A"}) def testMultiGenericError(self): with file_utils.Tempdir() as d: @@ -125,12 +120,11 @@ def testMultiGenericError(self): V = TypeVar('V') class A(Generic[T], Generic[V]): ... """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs( - errors, [(1, "pyi-error", - r"Cannot inherit.*Generic.*multiple times")]) + self.assertErrorRegexes( + errors, {"e": r"Cannot inherit.*Generic.*multiple times"}) def testGenericWithTypeMissError(self): with file_utils.Tempdir() as d: @@ -141,38 +135,37 @@ def testGenericWithTypeMissError(self): V = TypeVar('V') class A(Dict[K, V], Generic[K]): ... """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs( - errors, [(1, "pyi-error", r"V.*are not listed in Generic.*a.A")]) + self.assertErrorRegexes( + errors, {"e": r"V.*are not listed in Generic.*a.A"}) def testClassInFuncError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar, Generic, Union T = TypeVar('T') S = TypeVar('S') def func(x: T, y: S) -> Union[T, S]: - class InnerCls1(Generic[T]): + class InnerCls1(Generic[T]): # invalid-annotation[e1] # invalid-annotation[e2] class InnerCls2(Generic[S]): pass return x + y """) - self.assertErrorLogIs( - errors, [(7, "invalid-annotation", r"func.*InnerCls1.*T"), - (7, "invalid-annotation", r"func.*InnerCls2.*S")]) + self.assertErrorRegexes(errors, {"e1": r"func.*InnerCls2.*S", + "e2": r"func.*InnerCls1.*T"}) def testClassInClassError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar, Generic, Iterator T = TypeVar('T', int, float, str) S = TypeVar('S') - class MyClass(Generic[T, S]): + class MyClass(Generic[T, S]): # invalid-annotation[e1] def __init__(self, x: T = None, y: S = None): pass @@ -182,17 +175,16 @@ def f(self, x: T, y: S): class InnerClass1(Iterator[T]): pass - class A(Generic[T]): + class A(Generic[T]): # invalid-annotation[e2] class B(Generic[S]): class C(Generic[T]): pass """) - self.assertErrorLogIs(errors, [ - (6, "invalid-annotation", r"MyClass.*InnerClass1.*T"), - (16, "invalid-annotation", r"A.*C.*T")]) + self.assertErrorRegexes(errors, {"e1": r"MyClass.*InnerClass1.*T", + "e2": r"A.*C.*T"}) def testSignatureTypeParam(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar, Generic T = TypeVar('T', int, float, str) @@ -205,18 +197,17 @@ def __init__(self, x: T = None, y: S = None): def func1(self, x: T, y: S): pass - def func2(self, x: V): pass + def func2(self, x: V): pass # invalid-annotation[e1] - def func1(x: S): pass + def func1(x: S): pass # invalid-annotation[e2] def func2(x: S) -> S: return x def func3(x: T): pass """) - self.assertErrorLogIs( - errors, [(13, "invalid-annotation", r"Invalid type annotation 'V'"), - (15, "invalid-annotation", r"Invalid type annotation 'S'")]) + self.assertErrorRegexes(errors, {"e1": r"Invalid type annotation 'V'", + "e2": r"Invalid type annotation 'S'"}) def testPyiOutput(self): ty = self.Infer(""" @@ -285,18 +276,18 @@ def fun(self, x: T, y: S) -> None: ... """) def testSignatureTypeError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generic, TypeVar T = TypeVar('T') V = TypeVar('V') class MyClass(Generic[T]): - def __init__(self, x: T, y: V): + def __init__(self, x: T, y: V): # invalid-annotation[e] pass """) - self.assertErrorLogIs(errors, [ - (7, "invalid-annotation", r"V.*Appears only once in the signature")]) + self.assertErrorRegexes( + errors, {"e": r"V.*Appears only once in the signature"}) def testTypeParameterWithoutSubstitution(self): with file_utils.Tempdir() as d: @@ -338,7 +329,7 @@ def put(self, elem: T): ... """) def testFuncMatchForInterpreterClassError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar, Generic T1 = TypeVar('T1') @@ -361,14 +352,12 @@ def fun3(self, x: T, y: S): pass o = C[int, int]() - o.fun1("5", "5") - o.fun2("5", "5") - o.fun3("5", "5") + o.fun1("5", "5") # wrong-arg-types[e1] + o.fun2("5", "5") # wrong-arg-types[e2] + o.fun3("5", "5") # wrong-arg-types[e3] """) - self.assertErrorLogIs(errors, [ - (23, "wrong-arg-types", r"int.*str"), - (24, "wrong-arg-types", r"int.*str"), - (25, "wrong-arg-types", r"int.*str")]) + self.assertErrorRegexes( + errors, {"e1": r"int.*str", "e2": r"int.*str", "e3": r"int.*str"}) def testFuncMatchForPytdClassError(self): with file_utils.Tempdir() as d: @@ -391,22 +380,20 @@ def fun2(self, x: T2, y: S2): ... class C(A[T, S], B[T, S], Generic[T, S]): def fun3(self, x: T, y: S): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import a o = a.C[int, int]() - o.fun1("5", "5") - o.fun2("5", "5") - o.fun3("5", "5") + o.fun1("5", "5") # wrong-arg-types[e1] + o.fun2("5", "5") # wrong-arg-types[e2] + o.fun3("5", "5") # wrong-arg-types[e3] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (5, "wrong-arg-types", r"int.*str"), - (6, "wrong-arg-types", r"int.*str"), - (7, "wrong-arg-types", r"int.*str")]) + self.assertErrorRegexes( + errors, {"e1": r"int.*str", "e2": r"int.*str", "e3": r"int.*str"}) def testTypeRenamingError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generic, TypeVar T = TypeVar('T', int, float) @@ -416,22 +403,21 @@ def testTypeRenamingError(self): W = TypeVar('W') class A(Generic[T]): pass - class B(A[V]): pass + class B(A[V]): pass # not-supported-yet[e1] class C(Generic[V]): pass class D(C[T]): pass - class E(D[S]): pass + class E(D[S]): pass # not-supported-yet[e2] class F(Generic[U]): pass - class G(F[W]): pass + class G(F[W]): pass # not-supported-yet[e3] """) - self.assertErrorLogIs(errors, [ - (10, "not-supported-yet", r"Renaming TypeVar `T`.*"), - (14, "not-supported-yet", r"Renaming TypeVar `T`.*"), - (17, "not-supported-yet", r"Renaming TypeVar `U`.*")]) + self.assertErrorRegexes(errors, {"e1": r"Renaming TypeVar `T`.*", + "e2": r"Renaming TypeVar `T`.*", + "e3": r"Renaming TypeVar `U`.*"}) def testTypeParameterConflictError(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Generic, TypeVar T = TypeVar('T') @@ -443,9 +429,9 @@ class A(Generic[T]): pass class B(A[V]): pass class D(B[S], A[U]): pass - class E(D[int, str]): pass + class E(D[int, str]): pass # invalid-annotation[e1] - d = D[int, str]() + d = D[int, str]() # invalid-annotation[e2] e = E() """) self.assertTypesMatchPytd(ty, """ @@ -471,12 +457,11 @@ class D(B[S], A[U]): class E(Any): pass """) - self.assertErrorLogIs(errors, [ - (12, "invalid-annotation", r"Conflicting value for TypeVar"), - (14, "invalid-annotation", r"Conflicting value for TypeVar")]) + self.assertErrorRegexes(errors, {"e1": r"Conflicting value for TypeVar", + "e2": r"Conflicting value for TypeVar"}) def testUnboundTypeParameterError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Generic, TypeVar T = TypeVar('T') @@ -484,10 +469,9 @@ def testUnboundTypeParameterError(self): class A(Generic[T]): pass class B(A): pass - class D(B, A[U]): pass + class D(B, A[U]): pass # invalid-annotation[e] """) - self.assertErrorLogIs(errors, [ - (8, "invalid-annotation", r"Conflicting value for TypeVar D.U")]) + self.assertErrorRegexes(errors, {"e": r"Conflicting value for TypeVar D.U"}) def testSelfTypeParameter(self): # The purpose is to verify there is no infinite recursion @@ -519,7 +503,7 @@ class G(Sequence[G[int]], Generic[T]): ... """, pythonpath=[d.path]) def testAnyMatchAllTypes(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import collections, typing class DictA(collections.OrderedDict, typing.MutableMapping[int, int]): @@ -535,11 +519,10 @@ class DictC(collections.OrderedDict, DictB): d2 = DictA() d3 = DictC() x = d1["123"] - y = d2["123"] - z = d3["123"] + y = d2["123"] # unsupported-operands[e1] + z = d3["123"] # unsupported-operands[e2] """) - self.assertErrorLogIs(errors, [(16, "unsupported-operands", r"str.*int"), - (17, "unsupported-operands", r"str.*int")]) + self.assertErrorRegexes(errors, {"e1": r"str.*int", "e2": r"str.*int"}) def testNoSelfAnnot(self): self.Check(""" @@ -551,15 +534,14 @@ def __init__(self, children: List['Foo[Any]']): """) def testIllegalSelfAnnot(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Any, Generic, List, TypeVar T = TypeVar('T') class Foo(Generic[T]): def __init__(self: 'Foo', children: List['Foo[Any]']): - pass + pass # invalid-annotation[e] """) - self.assertErrorLogIs( - errors, [(5, "invalid-annotation", r"self.*__init__")]) + self.assertErrorRegexes(errors, {"e": r"self.*__init__"}) def testParameterizedForwardReference(self): ty = self.Infer(""" @@ -579,19 +561,19 @@ class Foo(Generic[T]): ... """) def testBadParameterizedForwardReference(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Generic, TypeVar T = TypeVar('T') - v = None # type: "Foo[int, str]" + v = None # type: "Foo[int, str]" # invalid-annotation[e] class Foo(Generic[T]): pass """) - self.assertErrorLogIs(errors, [(4, "invalid-annotation", r"1.*2")]) + self.assertErrorRegexes(errors, {"e": r"1.*2"}) def testRecursiveClass(self): - self.Check("""\ + self.Check(""" from typing import List class Foo(List["Foo"]): pass diff --git a/pytype/tests/py3/test_import.py b/pytype/tests/py3/test_import.py index 4528a59a0..ef6a7883d 100644 --- a/pytype/tests/py3/test_import.py +++ b/pytype/tests/py3/test_import.py @@ -8,7 +8,7 @@ class ImportTest(test_base.TargetPython3FeatureTest): """Tests for import.""" def testModuleAttributes(self): - ty = self.Infer("""\ + ty = self.Infer(""" import os f = os.__file__ n = os.__name__ @@ -48,7 +48,7 @@ def testRelativePriority(self): with file_utils.Tempdir() as d: d.create_file("a.pyi", "x = ... # type: int") d.create_file("b/a.pyi", "x = ... # type: complex") - ty = self.Infer("""\ + ty = self.Infer(""" import a x = a.x """, deep=False, pythonpath=[d.path], module_name="b.main") diff --git a/pytype/tests/py3/test_list.py b/pytype/tests/py3/test_list.py index b45ca56fe..924425b88 100644 --- a/pytype/tests/py3/test_list.py +++ b/pytype/tests/py3/test_list.py @@ -10,16 +10,15 @@ class ListTestBasic(test_base.TargetPython3BasicTest): def test_repeated_add(self): # At the time of this writing, this test completes in <5s. If it takes # significantly longer, there's been a performance regression. - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" from typing import List, Text, Tuple def f() -> Tuple[List[Text]]: x = ( ['' % __any_object__, ''] + [''] + [''] + [''.format()] + [''] + [['' % __any_object__, '', '']] ) - return ([__any_object__] + [''] + x,) + return ([__any_object__] + [''] + x,) # bad-return-type """) - self.assertErrorLogIs(errors, [(7, "bad-return-type")]) class ListTest(test_base.TargetPython3FeatureTest): @@ -64,15 +63,15 @@ def test_byte_unpack_ex(self): """) def test_getitem_slot(self): - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" a = [1, '2', 3, 4] p = a[1] q = 1 if __random__ else 2 r = a[q] - s = a["s"] + s = a["s"] # unsupported-operands t = a[-1] """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any, List, Union a = ... # type: List[Union[int, str]] p = ... # type: str @@ -81,14 +80,13 @@ def test_getitem_slot(self): s = ... # type: Any t = ... # type: int """) - self.assertErrorLogIs(errors, [(5, "unsupported-operands")]) @test_base.skip("Requires more precise slice objects") def test_getitem_slice(self): # Python 3 uses __getitem__ with slice objects instead of __getslice__. # Pytype doesn't support slice objects well, so a lot of results here are # imprecise. It also means wrong-arg-types won't be detected. - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" a = [1, '2', 3, 4] b = a[:] c = 1 if __random__ else 2 @@ -98,14 +96,14 @@ def test_getitem_slice(self): g = a[2:None] h = a[None:2] i = a[None:None] - j = a[int:str] - k = a["s":] + j = a[int:str] # wrong-arg-types + k = a["s":] # wrong-arg-types m = a[1:-1] n = a[0:0] o = a[1:1] p = a[1:2] """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any, List, Union a = ... # type: List[Union[int, str]] b = ... # type: List[Union[int, str]] @@ -123,9 +121,6 @@ def test_getitem_slice(self): o = ... # type: List[nothing] p = ... # type: List[str] """) - self.assertErrorLogIs(errors, [ - (10, "wrong-arg-types"), - (11, "wrong-arg-types")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_match.py b/pytype/tests/py3/test_match.py index 0fcc9353b..b34edd504 100644 --- a/pytype/tests/py3/test_match.py +++ b/pytype/tests/py3/test_match.py @@ -12,7 +12,7 @@ def testNoArgumentPyTDFunctionAgainstCallable(self): d.create_file("foo.pyi", """ def bar() -> bool """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Callable import foo @@ -20,11 +20,10 @@ def f(x: Callable[[], int]): ... def g(x: Callable[[], str]): ... f(foo.bar) # ok - g(foo.bar) + g(foo.bar) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(8, "wrong-arg-types", - r"\(x: Callable\[\[\], str\]\).*" - r"\(x: Callable\[\[\], bool\]\)")]) + self.assertErrorRegexes(errors, { + "e": r"\(x: Callable\[\[\], str\]\).*\(x: Callable\[\[\], bool\]\)"}) def testPyTDFunctionAgainstCallableWithTypeParameters(self): with file_utils.Tempdir() as d: @@ -33,7 +32,7 @@ def f1(x: int) -> int: ... def f2(x: int) -> bool: ... def f3(x: int) -> str: ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Callable, TypeVar import foo @@ -44,25 +43,22 @@ def f2(x: Callable[[T_constrained], T_constrained]): ... f1(foo.f1) # ok f1(foo.f2) # ok - f1(foo.f3) + f1(foo.f3) # wrong-arg-types[e1] f2(foo.f1) # ok - f2(foo.f2) - f2(foo.f3) + f2(foo.f2) # wrong-arg-types[e2] + f2(foo.f3) # wrong-arg-types[e3] """, pythonpath=[d.path]) expected = r"Callable\[\[Union\[bool, int\]\], Union\[bool, int\]\]" - self.assertErrorLogIs(errors, [ - (11, "wrong-arg-types", - r"Expected.*Callable\[\[str\], str\].*" - r"Actual.*Callable\[\[int\], str\]"), - (13, "wrong-arg-types", - r"Expected.*Callable\[\[bool\], bool\].*" - r"Actual.*Callable\[\[int\], bool\]"), - (14, "wrong-arg-types", - r"Expected.*" + expected + ".*" - r"Actual.*Callable\[\[int\], str\]")]) + self.assertErrorRegexes(errors, { + "e1": (r"Expected.*Callable\[\[str\], str\].*" + r"Actual.*Callable\[\[int\], str\]"), + "e2": (r"Expected.*Callable\[\[bool\], bool\].*" + r"Actual.*Callable\[\[int\], bool\]"), + "e3": (r"Expected.*" + expected + ".*" + r"Actual.*Callable\[\[int\], str\]")}) def testInterpreterFunctionAgainstCallable(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Callable def f(x: Callable[[bool], int]): ... def g1(x: int) -> bool: @@ -70,14 +66,14 @@ def g1(x: int) -> bool: def g2(x: str) -> int: return __any_object__ f(g1) # ok - f(g2) + f(g2) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(8, "wrong-arg-types", - r"Expected.*Callable\[\[bool\], int\].*" - r"Actual.*Callable\[\[str\], int\]")]) + self.assertErrorRegexes(errors, { + "e": (r"Expected.*Callable\[\[bool\], int\].*" + r"Actual.*Callable\[\[str\], int\]")}) def testBoundInterpreterFunctionAgainstCallable(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Callable class A(object): @@ -91,20 +87,18 @@ def f2(x: Callable[[A, bool], int]): ... def f3(x: Callable[[bool], str]): ... f1(bound) # ok - f2(bound) - f3(bound) - f1(unbound) + f2(bound) # wrong-arg-types[e1] + f3(bound) # wrong-arg-types[e2] + f1(unbound) # wrong-arg-types[e3] f2(unbound) # ok """) - self.assertErrorLogIs(errors, [(14, "wrong-arg-types", - r"Expected.*Callable\[\[A, bool\], int\].*" - r"Actual.*Callable\[\[int\], bool\]"), - (15, "wrong-arg-types", - r"Expected.*Callable\[\[bool\], str\].*" - r"Actual.*Callable\[\[int\], bool\]"), - (16, "wrong-arg-types", - r"Expected.*Callable\[\[bool\], int\].*" - r"Actual.*Callable\[\[Any, int\], bool\]")]) + self.assertErrorRegexes(errors, { + "e1": (r"Expected.*Callable\[\[A, bool\], int\].*" + r"Actual.*Callable\[\[int\], bool\]"), + "e2": (r"Expected.*Callable\[\[bool\], str\].*" + r"Actual.*Callable\[\[int\], bool\]"), + "e3": (r"Expected.*Callable\[\[bool\], int\].*" + r"Actual.*Callable\[\[Any, int\], bool\]")}) def testCallableParameters(self): with file_utils.Tempdir() as d: @@ -114,7 +108,7 @@ def testCallableParameters(self): def f1(x: Callable[..., T]) -> List[T]: ... def f2(x: Callable[[T], Any]) -> List[T]: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Any, Callable import foo @@ -143,32 +137,32 @@ def g4(x: int) -> Any: ... """) def testVariableLengthFunctionAgainstCallable(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Any, Callable def f(x: Callable[[int], Any]): pass def g1(x: int=0): pass def g2(x: str=""): pass f(g1) # ok - f(g2) + f(g2) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(6, "wrong-arg-types", - r"Expected.*Callable\[\[int\], Any\].*" - r"Actual.*Callable\[\[str\], Any\]")]) + self.assertErrorRegexes(errors, { + "e": (r"Expected.*Callable\[\[int\], Any\].*" + r"Actual.*Callable\[\[str\], Any\]")}) def testCallableInstanceAgainstCallableWithTypeParameters(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Callable, TypeVar T = TypeVar("T") def f(x: Callable[[T], T]): ... def g() -> Callable[[int], str]: return __any_object__ - f(g()) + f(g()) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", - r"Expected.*Callable\[\[str\], str\].*" - r"Actual.*Callable\[\[int\], str\]")]) + self.assertErrorRegexes(errors, { + "e": (r"Expected.*Callable\[\[str\], str\].*" + r"Actual.*Callable\[\[int\], str\]")}) def testFunctionWithTypeParameterReturnAgainstCallable(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import Callable, AnyStr, TypeVar T = TypeVar("T") def f(x: Callable[..., AnyStr]): ... @@ -176,9 +170,8 @@ def g1(x: AnyStr) -> AnyStr: return x def g2(x: T) -> T: return x f(g1) # ok - f(g2) + f(g2) # wrong-arg-types """) - self.assertErrorLogIs(errors, [(8, "wrong-arg-types")]) def testUnionInTypeParameter(self): with file_utils.Tempdir() as d: @@ -208,23 +201,19 @@ def bar(self, x: Dict[Tuple[AnyStr], AnyStr]): ... """) def testFormalType(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import AnyStr, List, NamedTuple def f(x: str): pass - f(AnyStr) + f(AnyStr) # invalid-typevar def g(x: List[str]): pass - g([AnyStr]) - H = NamedTuple("H", [('a', AnyStr)]) + g([AnyStr]) # invalid-typevar + H = NamedTuple("H", [('a', AnyStr)]) # invalid-typevar """) - self.assertErrorLogIs(errors, [ - (4, "invalid-typevar"), - (7, "invalid-typevar"), - (8, "invalid-typevar")]) def testTypeVarWithBound(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Callable, TypeVar T1 = TypeVar("T1", bound=int) T2 = TypeVar("T2") @@ -232,10 +221,9 @@ def f(x: T1) -> T1: return __any_object__ def g(x: Callable[[T2], T2]) -> None: pass - g(f) # line 8 + g(f) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(8, "wrong-arg-types", - r"Expected.*T2.*Actual.*T1")]) + self.assertErrorRegexes(errors, {"e": r"Expected.*T2.*Actual.*T1"}) def testCallableBaseClass(self): with file_utils.Tempdir() as d: @@ -272,33 +260,31 @@ def g(f: Callable[[T], Any], x: T): def testAnyStrAgainstBoundedCallable(self): # Constraints and bounds should still be enforced when a type parameter # appears only once in a callable. - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Any, AnyStr, Callable, TypeVar IntVar = TypeVar('IntVar', bound=int) def f(x: AnyStr) -> AnyStr: return x def g(f: Callable[[IntVar], Any], x: IntVar): pass - g(f, 0) + g(f, 0) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [ - (7, "wrong-arg-types", - r"Callable\[\[IntVar\], Any\].*Callable\[\[AnyStr\], AnyStr\]")]) + self.assertErrorRegexes(errors, { + "e": r"Callable\[\[IntVar\], Any\].*Callable\[\[AnyStr\], AnyStr\]"}) def testAnyStrAgainstMultipleParamCallable(self): # Callable[[T], T] needs to accept any argument, so AnyStr cannot match it. - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Any, AnyStr, Callable, TypeVar T = TypeVar('T') def f(x: AnyStr) -> AnyStr: return x def g(f: Callable[[T], T]): pass - g(f) + g(f) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [ - (7, "wrong-arg-types", - r"Callable\[\[T\], T\].*Callable\[\[AnyStr\], AnyStr\]")]) + self.assertErrorRegexes(errors, { + "e": r"Callable\[\[T\], T\].*Callable\[\[AnyStr\], AnyStr\]"}) class MatchTestPy3(test_base.TargetPython3FeatureTest): diff --git a/pytype/tests/py3/test_methods.py b/pytype/tests/py3/test_methods.py index e0e415a2d..32ec8f9af 100644 --- a/pytype/tests/py3/test_methods.py +++ b/pytype/tests/py3/test_methods.py @@ -4,7 +4,7 @@ class TestMethods(test_base.TargetPython3BasicTest): - """Tests for class methods""" + """Tests for class methods.""" def testFunctionInit(self): ty = self.Infer(""" @@ -16,42 +16,42 @@ def __init__(self: int) -> int """) def testAnnotatedSelf(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __init__(x: int): - pass + pass # invalid-annotation[e] """) - self.assertErrorLogIs(errors, [(3, "invalid-annotation", r"int.*x")]) + self.assertErrorRegexes(errors, {"e": r"int.*x"}) def testLateAnnotatedSelf(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __init__(x: "X"): - pass + pass # invalid-annotation[e] class X(object): pass """) - self.assertErrorLogIs(errors, [(3, "invalid-annotation", r"X.*x")]) + self.assertErrorRegexes(errors, {"e": r"X.*x"}) def testAttributeWithAnnotatedSelf(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __init__(self: int): - self.x = 3 + self.x = 3 # invalid-annotation[e] def foo(self): return self.x """) - self.assertErrorLogIs(errors, [(3, "invalid-annotation", r"int.*self")]) + self.assertErrorRegexes(errors, {"e": r"int.*self"}) def testAttributeWithAnnotatedSelfAndFunctionInit(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __init__(self: int): - self.x = 3 + self.x = 3 # invalid-annotation[e] def __init__(self: int): pass """) - self.assertErrorLogIs(errors, [(3, "invalid-annotation", r"int.*self")]) + self.assertErrorRegexes(errors, {"e": r"int.*self"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_namedtuple.py b/pytype/tests/py3/test_namedtuple.py index 145f427b4..71cc03e8b 100644 --- a/pytype/tests/py3/test_namedtuple.py +++ b/pytype/tests/py3/test_namedtuple.py @@ -7,7 +7,7 @@ class NamedtupleTests(test_base.TargetPython3BasicTest): """Tests for collections.namedtuple.""" def test_namedtuple_match(self): - self.Check("""\ + self.Check(""" import collections from typing import Any, Dict @@ -23,20 +23,14 @@ class NamedtupleTestsPy3(test_base.TargetPython3FeatureTest): def test_bad_call(self): """The last two arguments are kwonly in 3.6.""" - _, errorlog = self.InferWithErrors("""\ + self.InferWithErrors(""" import collections - collections.namedtuple() - collections.namedtuple("_") - collections.namedtuple("_", "", True) - collections.namedtuple("_", "", True, True) - collections.namedtuple("_", "", True, True, True) + collections.namedtuple() # missing-parameter + collections.namedtuple("_") # missing-parameter + collections.namedtuple("_", "", True) # wrong-arg-count + collections.namedtuple("_", "", True, True) # wrong-arg-count + collections.namedtuple("_", "", True, True, True) # wrong-arg-count """) - self.assertErrorLogIs(errorlog, - [(2, "missing-parameter"), - (3, "missing-parameter"), - (4, "wrong-arg-count"), - (5, "wrong-arg-count"), - (6, "wrong-arg-count")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_overload.py b/pytype/tests/py3/test_overload.py index 11f755f7e..d2047ec2b 100644 --- a/pytype/tests/py3/test_overload.py +++ b/pytype/tests/py3/test_overload.py @@ -19,27 +19,27 @@ def f(x): """) def test_bad_implementation(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import overload @overload def f(x: int) -> str: pass def f(x): - return x + return x # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(6, "bad-return-type", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) def test_bad_call(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import overload @overload def f(x: int) -> int: pass def f(x): return x - f("") + f("") # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(7, "wrong-arg-types", r"int.*str")]) + self.assertErrorRegexes(errors, {"e": r"int.*str"}) def test_sub_return(self): ty = self.Infer(""" @@ -72,7 +72,7 @@ def f(x=None): """) def test_multiple_overload_bad_implementation(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import overload @overload def f(x: int) -> int: @@ -81,12 +81,12 @@ def f(x: int) -> int: def f(x: str) -> int: pass def f(x): - return x + return x # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(9, "bad-return-type", "int.*str")]) + self.assertErrorRegexes(errors, {"e": r"int.*str"}) def test_multiple_overload_bad_call(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import overload @overload def f(x: int) -> int: @@ -96,11 +96,10 @@ def f(x: int, y: str) -> str: pass def f(x, y=None): return x if y is None else y - f("") - f(0, 0) + f("") # wrong-arg-types[e1] + f(0, 0) # wrong-arg-types[e2] """) - self.assertErrorLogIs(errors, [(10, "wrong-arg-types", r"int.*str"), - (11, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes(errors, {"e1": r"int.*str", "e2": r"str.*int"}) def test_pyi(self): src = """ @@ -129,16 +128,16 @@ def g() -> Callable: ... """) with file_utils.Tempdir() as d: d.create_file("foo.pyi", pytd_utils.Print(ty)) - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import foo foo.f(0) # ok foo.f("") # ok - foo.f(0.0) # error + foo.f(0.0) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"int.*float")]) + self.assertErrorRegexes(errors, {"e": r"int.*float"}) def test_method_bad_implementation(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import overload class Foo(object): @overload @@ -148,9 +147,9 @@ def f(self, x: int) -> int: def f(self, x: str) -> int: pass def f(self, x): - return x + return x # bad-return-type[e] """) - self.assertErrorLogIs(errors, [(10, "bad-return-type", r"int.*str")]) + self.assertErrorRegexes(errors, {"e": r"int.*str"}) def test_method_pyi(self): src = """ @@ -177,14 +176,14 @@ def f(self, x: str) -> str: ... """) def test_call_overload(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import overload @overload def f(x: int) -> int: pass - f(0) + f(0) # not-callable[e] """) - self.assertErrorLogIs(errors, [(5, "not-callable", r"overload")]) + self.assertErrorRegexes(errors, {"e": r"overload"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_protocols.py b/pytype/tests/py3/test_protocols.py index 629517091..7709a4085 100644 --- a/pytype/tests/py3/test_protocols.py +++ b/pytype/tests/py3/test_protocols.py @@ -30,18 +30,18 @@ def __len__(self): """) def test_check_protocol_error(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import protocols def f(x: protocols.SupportsAbs): return x.__abs__() - f(["foo"]) + f(["foo"]) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", - r"\(x: SupportsAbs\).*\(x: List\[str\]\)")]) + self.assertErrorRegexes( + errors, {"e": r"\(x: SupportsAbs\).*\(x: List\[str\]\)"}) def test_check_iterator_error(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Iterator def f(x: Iterator[int]): return None @@ -50,13 +50,12 @@ def next(self) -> str: return '' def __iter__(self): return self - f(Foo()) # line 9 + f(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs( - errors, [(9, "wrong-arg-types", r"Iterator\[int\].*Foo")]) + self.assertErrorRegexes(errors, {"e": r"Iterator\[int\].*Foo"}) def test_check_protocol_match_unknown(self): - self.Check("""\ + self.Check(""" from typing import Sized def f(x: Sized): pass @@ -69,7 +68,7 @@ def g(x): """) def test_check_parameterized_protocol(self): - self.Check("""\ + self.Check(""" from typing import Iterator, Iterable class Foo(object): @@ -85,7 +84,7 @@ def f(x: Iterable[int]): """) def test_check_parameterized_protocol_error(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Iterator, Iterable class Foo(object): @@ -96,13 +95,13 @@ def f(x: Iterable[int]): pass foo = Foo() - f(foo) + f(foo) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(11, "wrong-arg-types", - r"\(x: Iterable\[int\]\).*\(x: Foo\)")]) + self.assertErrorRegexes( + errors, {"e": r"\(x: Iterable\[int\]\).*\(x: Foo\)"}) def test_check_parameterized_protocol_multi_signature(self): - self.Check("""\ + self.Check(""" from typing import Sequence, Union class Foo(object): @@ -119,7 +118,7 @@ def f(x: Sequence[int]): """) def test_check_parameterized_protocol_error_multi_signature(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Sequence, Union class Foo(object): @@ -132,10 +131,10 @@ def f(x: Sequence[int]): pass foo = Foo() - f(foo) + f(foo) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(13, "wrong-arg-types", - r"\(x: Sequence\[int\]\).*\(x: Foo\)")]) + self.assertErrorRegexes( + errors, {"e": r"\(x: Sequence\[int\]\).*\(x: Foo\)"}) def test_construct_dict_with_protocol(self): self.Check(""" @@ -257,7 +256,7 @@ def f(s: Iterable[T]) -> T: ... """, pythonpath=[d.path]) def test_inherited_abstract_method_error(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Iterator class Foo(object): def __iter__(self) -> Iterator[str]: @@ -266,10 +265,9 @@ def next(self): return __any_object__ def f(x: Iterator[int]): pass - f(Foo()) # line 9 + f(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs( - errors, [(9, "wrong-arg-types", r"Iterator\[int\].*Foo")]) + self.assertErrorRegexes(errors, {"e": r"Iterator\[int\].*Foo"}) def test_reversible(self): self.Check(""" @@ -316,26 +314,24 @@ def f(x: Hashable): """) def test_list_hash(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Hashable def f(x: Hashable): pass - f([]) # line 4 + f([]) # wrong-arg-types[e] """) - self.assertErrorLogIs( - errors, [(4, "wrong-arg-types", r"Hashable.*List.*__hash__")]) + self.assertErrorRegexes(errors, {"e": r"Hashable.*List.*__hash__"}) def test_hash_constant(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Hashable class Foo(object): __hash__ = None def f(x: Hashable): pass - f(Foo()) # line 6 + f(Foo()) # wrong-arg-types[e] """) - self.assertErrorLogIs( - errors, [(6, "wrong-arg-types", r"Hashable.*Foo.*__hash__")]) + self.assertErrorRegexes(errors, {"e": r"Hashable.*Foo.*__hash__"}) def test_generic_callable(self): with file_utils.Tempdir() as d: @@ -392,7 +388,7 @@ def f(x: Appendable): """) def test_custom_protocol_error(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing_extensions import Protocol class Appendable(Protocol): def append(self): @@ -401,12 +397,12 @@ class NotAppendable(object): pass def f(x: Appendable): pass - f(42) # error - f(NotAppendable()) # error + f(42) # wrong-arg-types[e1] + f(NotAppendable()) # wrong-arg-types[e2] """) - self.assertErrorLogIs(errors, [ - (9, "wrong-arg-types", r"Appendable.*int.*append"), - (10, "wrong-arg-types", r"Appendable.*NotAppendable.*append")]) + self.assertErrorRegexes(errors, { + "e1": r"Appendable.*int.*append", + "e2": r"Appendable.*NotAppendable.*append"}) def test_reingest_custom_protocol(self): ty = self.Infer(""" @@ -437,18 +433,18 @@ def append(self) -> None: """) with file_utils.Tempdir() as d: d.create_file("foo.pyi", pytd_utils.Print(ty)) - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import foo class NotAppendable(object): pass def f(x: foo.Appendable): pass - f(42) # error - f(NotAppendable()) # error + f(42) # wrong-arg-types[e1] + f(NotAppendable()) # wrong-arg-types[e2] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (6, "wrong-arg-types", r"Appendable.*int.*append"), - (7, "wrong-arg-types", r"Appendable.*NotAppendable.*append")]) + self.assertErrorRegexes(errors, { + "e1": r"Appendable.*int.*append", + "e2": r"Appendable.*NotAppendable.*append"}) def test_reingest_custom_protocol_inherit_method(self): ty = self.Infer(""" @@ -462,7 +458,7 @@ def remove(self): """) with file_utils.Tempdir() as d: d.create_file("foo.pyi", pytd_utils.Print(ty)) - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from foo import Mutable class NotMutable(object): def remove(self): @@ -470,10 +466,9 @@ def remove(self): def f(x: Mutable): pass f([]) # ok - f(NotMutable()) # error + f(NotMutable()) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (8, "wrong-arg-types", r"Mutable.*NotMutable.*append")]) + self.assertErrorRegexes(errors, {"e": r"Mutable.*NotMutable.*append"}) def test_reingest_custom_protocol_implement_method(self): ty = self.Infer(""" @@ -509,17 +504,16 @@ def count(self) -> int: """) def test_check_method_body(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing_extensions import Protocol class Countable(Protocol): def count(self) -> int: - ... + ... # bad-return-type[e] class MyCountable(Countable): def count(self): return super(MyCountable, self).count() """) - self.assertErrorLogIs( - errors, [(4, "bad-return-type", r"int.*None.*line 7")]) + self.assertErrorRegexes(errors, {"e": r"int.*None.*line 7"}) class ProtocolsTestPython3Feature(test_base.TargetPython3FeatureTest): diff --git a/pytype/tests/py3/test_pyi.py b/pytype/tests/py3/test_pyi.py index af897d7f6..7d68b92a7 100644 --- a/pytype/tests/py3/test_pyi.py +++ b/pytype/tests/py3/test_pyi.py @@ -8,12 +8,12 @@ class PYITest(test_base.TargetPython3BasicTest): """Tests for PYI.""" def testUnneccessaryAnyImport(self): - ty = self.Infer("""\ + ty = self.Infer(""" import typing def foo(**kwargs: typing.Any) -> int: return 1 def bar(*args: typing.Any) -> int: return 2 """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ typing = ... # type: module def foo(**kwargs) -> int: ... def bar(*args) -> int: ... diff --git a/pytype/tests/py3/test_recovery.py b/pytype/tests/py3/test_recovery.py index d2f7a8e60..5888ad7d8 100644 --- a/pytype/tests/py3/test_recovery.py +++ b/pytype/tests/py3/test_recovery.py @@ -7,24 +7,19 @@ class RecoveryTests(test_base.TargetPython3BasicTest): """Tests for recovering after errors.""" def testFunctionWithUnknownDecorator(self): - _, errors = self.InferWithErrors("""\ - from nowhere import decorator + self.InferWithErrors(""" + from nowhere import decorator # import-error @decorator def f(): - name_error + name_error # name-error @decorator def g(x: int) -> None: - x.upper() + x.upper() # attribute-error """, deep=True) - self.assertErrorLogIs(errors, [ - (1, "import-error"), - (4, "name-error"), - (7, "attribute-error"), - ]) def testComplexInit(self): """Test that we recover when __init__ triggers a utils.TooComplexError.""" - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import AnyStr class X(object): def __init__(self, @@ -37,10 +32,10 @@ def __init__(self, string_ref: AnyStr = None, type_ref: AnyStr = None) -> None: pass - def foo(self, x: other_module.X) -> None: # line 13 + def foo(self, x: other_module.X) -> None: # name-error[e] pass """, deep=True) - self.assertErrorLogIs(errors, [(13, "name-error", r"other_module")]) + self.assertErrorRegexes(errors, {"e": r"other_module"}) class RecoveryTestsPython3(test_base.TargetPython3FeatureTest): diff --git a/pytype/tests/py3/test_reingest.py b/pytype/tests/py3/test_reingest.py index a8a7089ab..50823b877 100644 --- a/pytype/tests/py3/test_reingest.py +++ b/pytype/tests/py3/test_reingest.py @@ -16,11 +16,11 @@ def f(x: T) -> T: return x """, deep=False) with file_utils.Tempdir() as d: d.create_file("foo.pyi", pytd_utils.Print(foo)) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.f("") + foo.f("") # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", r"float.*str")]) + self.assertErrorRegexes(errors, {"e": r"float.*str"}) def testDefaultArgumentType(self): foo = self.Infer(""" @@ -54,12 +54,12 @@ def foo(self): """) with file_utils.Tempdir() as d: d.create_file("foo.pyi", pytd_utils.Print(foo)) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.Foo() + foo.Foo() # not-instantiable[e] foo.Bar() """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "not-instantiable", r"foo\.Foo.*foo")]) + self.assertErrorRegexes(errors, {"e": r"foo\.Foo.*foo"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_slots.py b/pytype/tests/py3/test_slots.py index f0c39d834..91ab8b517 100644 --- a/pytype/tests/py3/test_slots.py +++ b/pytype/tests/py3/test_slots.py @@ -14,11 +14,10 @@ class Foo(object): """) def testSlotWithBytes(self): - errors = self.CheckWithErrors("""\ - class Foo(object): + self.CheckWithErrors(""" + class Foo(object): # bad-slots __slots__ = (b"x",) """) - self.assertErrorLogIs(errors, [(1, "bad-slots")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_stdlib.py b/pytype/tests/py3/test_stdlib.py index d67c8918a..1dfa91821 100644 --- a/pytype/tests/py3/test_stdlib.py +++ b/pytype/tests/py3/test_stdlib.py @@ -11,18 +11,18 @@ class StdLibTestsBasic(test_base.TargetPython3BasicTest, def testCollectionsDeque(self): # This method is different from the preceding ones because we model # collections.deque as a subclass, rather than an alias, of typing.Deque. - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Deque import collections def f1(x: Deque): ... def f2(x: int): ... f1(collections.deque()) - f2(collections.deque()) # line 6 + f2(collections.deque()) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(6, "wrong-arg-types", r"int.*deque")]) + self.assertErrorRegexes(errors, {"e": r"int.*deque"}) def testCollectionsDequeInit(self): - ty = self.Infer("""\ + ty = self.Infer(""" import collections x = collections.deque([1, 2, 3], maxlen=10) """) @@ -32,7 +32,7 @@ def testCollectionsDequeInit(self): """) def testPartial(self): - self.Check("""\ + self.Check(""" import functools from typing import TypeVar T = TypeVar('T', float, str) @@ -150,7 +150,7 @@ def f(fi: typing.IO) -> Union[bytes, str]: ... """) def testDefaultDict(self): - self.Check("""\ + self.Check(""" import collections import itertools ids = collections.defaultdict(itertools.count(17).__next__) @@ -247,7 +247,6 @@ def testSysVersionInfoNamedAttribute(self): v: str """) - @test_utils.skipIn37("https://github.com/google/pytype/issues/203") def test_async(self): """Test various asyncio features.""" ty = self.Infer(""" @@ -288,12 +287,11 @@ def my_coroutine(seconds_to_sleep = ...) -> Coroutine[Any, Any, None]: ... def test_with(x) -> Coroutine[Any, Any, None]: ... """) - @test_utils.skipIn37("https://github.com/google/pytype/issues/203") def test_async_iter(self): ty = self.Infer(""" import asyncio class AsyncIterable: - async def __aiter__(self): + def __aiter__(self): return self async def __anext__(self): data = await self.fetch_data() @@ -311,10 +309,11 @@ async def iterate(x): iterate(AsyncIterable()) """) self.assertTypesMatchPytd(ty, """ - from typing import Any, Coroutine + from typing import Any, Coroutine, TypeVar asyncio: module + _TAsyncIterable = TypeVar('_TAsyncIterable', bound=AsyncIterable) class AsyncIterable: - def __aiter__(self) -> Coroutine[Any, Any, AsyncIterable]: ... + def __aiter__(self: _TAsyncIterable) -> _TAsyncIterable: ... def __anext__(self) -> Coroutine[Any, Any, int]: ... def fetch_data(self) -> Coroutine[Any, Any, int]: ... def iterate(x) -> Coroutine[Any, Any, None]: ... diff --git a/pytype/tests/py3/test_super.py b/pytype/tests/py3/test_super.py index 47bfe7115..fd4059bc3 100644 --- a/pytype/tests/py3/test_super.py +++ b/pytype/tests/py3/test_super.py @@ -73,17 +73,13 @@ def m(self): class B(A): def m(self): def f(): - super().m() + super().m() # invalid-super-call[e1] f() def func(x: int): - super().m() + super().m() # invalid-super-call[e2] """) - self.assertErrorLogIs( - errors, - [(8, "invalid-super-call", - r".*Missing 'self' argument.*"), - (11, "invalid-super-call", - r".*Missing __class__ closure.*")]) + self.assertErrorRegexes(errors, {"e1": r".*Missing 'self' argument.*", + "e2": r".*Missing __class__ closure.*"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_tracebacks.py b/pytype/tests/py3/test_tracebacks.py index cca593b4f..3e872fb4c 100644 --- a/pytype/tests/py3/test_tracebacks.py +++ b/pytype/tests/py3/test_tracebacks.py @@ -7,12 +7,12 @@ class TracebackTest(test_base.TargetPython3BasicTest): """Tests for tracebacks in error messages.""" def test_build_class(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): - def f(self, x: Bar): + def f(self, x: Bar): # name-error[e] pass """) - self.assertErrorLogIs(errors, [(2, "name-error", r"Bar.*not defined$")]) + self.assertErrorRegexes(errors, {"e": r"Bar.*not defined$"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_tuple.py b/pytype/tests/py3/test_tuple.py index 1e44a54da..c6c5eda09 100644 --- a/pytype/tests/py3/test_tuple.py +++ b/pytype/tests/py3/test_tuple.py @@ -8,7 +8,7 @@ class TupleTest(test_base.TargetPython3BasicTest): """Tests for __builtin__.tuple.""" def testUnpackInlineTuple(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Tuple def f(x: Tuple[str, int]): return x @@ -53,17 +53,17 @@ def f() -> tuple: """) def testTuplePrinting(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Tuple def f(x: Tuple[str, ...]): pass def g(y: Tuple[str]): pass - f((42,)) - f(tuple([42])) + f((42,)) # wrong-arg-types[e1] + f(tuple([42])) # wrong-arg-types[e2] f(("", "")) # okay - g((42,)) - g(("", "")) + g((42,)) # wrong-arg-types[e3] + g(("", "")) # wrong-arg-types[e4] g(("",)) # okay g(tuple([""])) # okay """) @@ -72,15 +72,11 @@ def g(y: Tuple[str]): tuple_int = r"Tuple\[int\]" tuple_ints = r"Tuple\[int, \.\.\.\]" tuple_str_str = r"Tuple\[str, str\]" - self.assertErrorLogIs(errors, [(6, "wrong-arg-types", - r"%s.*%s" % (x, tuple_int)), - (7, "wrong-arg-types", - r"%s.*%s" % (x, tuple_ints)), - (9, "wrong-arg-types", - r"%s.*%s" % (y, tuple_int)), - (10, "wrong-arg-types", - r"%s.*%s" % (y, tuple_str_str)) - ]) + self.assertErrorRegexes(errors, { + "e1": r"%s.*%s" % (x, tuple_int), + "e2": r"%s.*%s" % (x, tuple_ints), + "e3": r"%s.*%s" % (y, tuple_int), + "e4": r"%s.*%s" % (y, tuple_str_str)}) def testInlineTuple(self): with file_utils.Tempdir() as d: @@ -106,24 +102,23 @@ def testInlineTupleError(self): from typing import Tuple class A(Tuple[str, int]): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Tuple, Type import foo def f(x: Type[Tuple[int, str]]): pass def g(x: Tuple[int, str]): pass - f(type(("", 1))) - g(("", 1)) - g(foo.A()) + f(type(("", 1))) # wrong-arg-types[e1] + g(("", 1)) # wrong-arg-types[e2] + g(foo.A()) # wrong-arg-types[e3] """, pythonpath=[d.path]) expected = r"Tuple\[int, str\]" actual = r"Tuple\[str, int\]" - self.assertErrorLogIs(errors, [ - (7, "wrong-arg-types", - r"Type\[%s\].*Type\[%s\]" % (expected, actual)), - (8, "wrong-arg-types", r"%s.*%s" % (expected, actual)), - (9, "wrong-arg-types", r"%s.*foo\.A" % expected)]) + self.assertErrorRegexes(errors, { + "e1": r"Type\[%s\].*Type\[%s\]" % (expected, actual), + "e2": r"%s.*%s" % (expected, actual), + "e3": r"%s.*foo\.A" % expected}) def testTupleCombinationExplosion(self): self.Check(""" @@ -150,20 +145,20 @@ def testMismatchedPyiTuple(self): d.create_file("bar.pyi", """ class Bar(tuple): ... """) - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Tuple import bar def foo() -> Tuple[bar.Bar, bar.Bar]: - return bar.Bar(None, None) # line 4 + return bar.Bar(None, None) # wrong-arg-count[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(4, "wrong-arg-count", "1.*3")]) + self.assertErrorRegexes(errors, {"e": r"1.*3"}) class TupleTestPython3Feature(test_base.TargetPython3FeatureTest): """Tests for __builtin__.tuple.""" def testIteration(self): - ty = self.Infer("""\ + ty = self.Infer(""" class Foo(object): mytuple = (1, "foo", 3j) def __getitem__(self, pos): @@ -179,11 +174,10 @@ def __getitem__(self, pos: int) -> int or str or complex """) def testBadUnpackingWithSlurp(self): - _, errors = self.InferWithErrors("""\ - a, *b, c = (1,) + _, errors = self.InferWithErrors(""" + a, *b, c = (1,) # bad-unpacking[e] """) - self.assertErrorLogIs( - errors, [(1, "bad-unpacking", "1 value.*3 variables")]) + self.assertErrorRegexes(errors, {"e": r"1 value.*3 variables"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/py3/test_type_comments.py b/pytype/tests/py3/test_type_comments.py index bb6c41993..e3e0b24d1 100644 --- a/pytype/tests/py3/test_type_comments.py +++ b/pytype/tests/py3/test_type_comments.py @@ -7,15 +7,14 @@ class FunctionCommentWithAnnotationsTest(test_base.TargetPython3BasicTest): """Tests for type comments that require annotations.""" def testFunctionTypeCommentPlusAnnotations(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def foo(x: int) -> float: - # type: (int) -> float + # type: (int) -> float # redundant-function-type-comment return x """) - self.assertErrorLogIs(errors, [(2, "redundant-function-type-comment")]) def testListComprehensionComments(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List def f(x: str): pass @@ -23,7 +22,7 @@ def g(xs: List[str]) -> List[str]: ys = [f(x) for x in xs] # type: List[str] return ys """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import List def f(x: str) -> None: ... def g(xs: List[str]) -> List[str]: ... diff --git a/pytype/tests/py3/test_typevar.py b/pytype/tests/py3/test_typevar.py index 44f2eecaa..a33291d60 100644 --- a/pytype/tests/py3/test_typevar.py +++ b/pytype/tests/py3/test_typevar.py @@ -68,20 +68,17 @@ def testImportTypeVarNameChange(self): T = TypeVar("T") X = TypeVar("X") """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" # This is illegal: A TypeVar("T") needs to be stored under the name "T". - from a import T as T2 + from a import T as T2 # invalid-typevar[e1] from a import X - Y = X + Y = X # invalid-typevar[e2] def f(x: T2) -> T2: ... """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (2, "invalid-typevar", "T.*T2"), - (4, "invalid-typevar", "X.*Y"), - ]) + self.assertErrorRegexes(errors, {"e1": r"T.*T2", "e2": r"X.*Y"}) def testMultipleSubstitution(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Dict, Tuple, TypeVar K = TypeVar("K") V = TypeVar("V") @@ -100,7 +97,7 @@ def f(x: Dict[K, V]) -> Tuple[V, K]: ... """) def testUnion(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import TypeVar, Union S = TypeVar("S") T = TypeVar("T") @@ -119,37 +116,35 @@ def f(x: S, y: T) -> Union[S, T]: ... """) def testBadSubstitution(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import List, TypeVar S = TypeVar("S") T = TypeVar("T") def f1(x: S) -> List[S]: - return {x} + return {x} # bad-return-type[e1] def f2(x: S) -> S: return 42 # no error because never called def f3(x: S) -> S: - return 42 + return 42 # bad-return-type[e2] # bad-return-type[e3] def f4(x: S, y: T, z: T) -> List[S]: - return [y] + return [y] # bad-return-type[e4] f3("") f3(16) # ok f3(False) f4(True, 3.14, 0) f4("hello", "world", "domination") # ok """) - self.assertErrorLogIs(errors, [ - (5, "bad-return-type", r"List\[S\].*set"), - (9, "bad-return-type", r"str.*int"), - (9, "bad-return-type", r"bool.*int"), - (11, "bad-return-type", r"List\[bool\].*List\[Union\[float, int\]\]")]) + self.assertErrorRegexes(errors, { + "e1": r"List\[S\].*set", "e2": r"str.*int", "e3": r"bool.*int", + "e4": r"List\[bool\].*List\[Union\[float, int\]\]"}) def testUseConstraints(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import TypeVar T = TypeVar("T", int, float) def f(x: T) -> T: return __any_object__ - v = f("") + v = f("") # wrong-arg-types[e] w = f(True) # ok u = f(__any_object__) # ok """) @@ -161,11 +156,10 @@ def f(x: T) -> T: ... w = ... # type: bool u = ... # type: int or float """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", - r"Union\[float, int\].*str")]) + self.assertErrorRegexes(errors, {"e": r"Union\[float, int\].*str"}) def testTypeParameterType(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Type, TypeVar T = TypeVar("T") def f(x: Type[T]) -> T: @@ -180,41 +174,40 @@ def f(x: Type[T]) -> T: ... """) def testPrintNestedTypeParameter(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import List, TypeVar T = TypeVar("T", int, float) def f(x: List[T]): ... - f([""]) + f([""]) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [ - (4, "wrong-arg-types", r"List\[Union\[float, int\]\].*List\[str\]")]) + self.assertErrorRegexes(errors, { + "e": r"List\[Union\[float, int\]\].*List\[str\]"}) def testConstraintSubtyping(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar T = TypeVar("T", int, float) def f(x: T, y: T): ... f(True, False) # ok - f(True, 42) + f(True, 42) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", - r"Expected.*y: bool.*Actual.*y: int")]) + self.assertErrorRegexes(errors, {"e": r"Expected.*y: bool.*Actual.*y: int"}) def testFilterValue(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar T = TypeVar("T", int, float) def f(x: T, y: T): ... x = 3 x = 42.0 - f(x, 3) + f(x, 3) # wrong-arg-types[e] f(x, 42.0) # ok """) - self.assertErrorLogIs(errors, [(6, "wrong-arg-types", - r"Expected.*y: float.*Actual.*y: int")]) + self.assertErrorRegexes( + errors, {"e": r"Expected.*y: float.*Actual.*y: int"}) def testFilterClass(self): - self.Check("""\ + self.Check(""" from typing import TypeVar class A(object): pass class B(object): pass @@ -228,7 +221,7 @@ def f(x: T, y: T): ... """) def testSplit(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import TypeVar T = TypeVar("T", int, type(None)) def f(x: T) -> T: @@ -249,44 +242,39 @@ def f(x: T) -> T: ... """) def testEnforceNonConstrainedTypeVar(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar T = TypeVar("T") def f(x: T, y: T): ... f(42, True) # ok - f(42, "") + f(42, "") # wrong-arg-types[e1] f(42, 16j) # ok f(object(), 42) # ok f(42, object()) # ok - f(42.0, "") + f(42.0, "") # wrong-arg-types[e2] """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", - r"Expected.*y: int.*Actual.*y: str"), - (9, "wrong-arg-types", - r"Expected.*y: float.*Actual.*y: str")]) + self.assertErrorRegexes(errors, { + "e1": r"Expected.*y: int.*Actual.*y: str", + "e2": r"Expected.*y: float.*Actual.*y: str"}) def testUselessTypeVar(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import Tuple, TypeVar T = TypeVar("T") S = TypeVar("S", int, float) - def f1(x: T): ... - def f2() -> T: ... - def f3(x: Tuple[T]): ... + def f1(x: T): ... # invalid-annotation + def f2() -> T: ... # invalid-annotation + def f3(x: Tuple[T]): ... # invalid-annotation def f4(x: Tuple[T, T]): ... # ok def f5(x: S): ... # ok - def f6(x: "U"): ... + def f6(x: "U"): ... # invalid-annotation def f7(x: T, y: "T"): ... # ok def f8(x: "U") -> "U": ... # ok U = TypeVar("U") """) - self.assertErrorLogIs(errors, [(4, "invalid-annotation"), - (5, "invalid-annotation"), - (6, "invalid-annotation"), - (9, "invalid-annotation")]) def testUseBound(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import TypeVar T = TypeVar("T", bound=float) def f(x: T) -> T: @@ -295,7 +283,7 @@ def f(x: T) -> T: v2 = f(True) # ok v3 = f(42) # ok v4 = f(3.14) # ok - v5 = f("") + v5 = f("") # wrong-arg-types[e] """) self.assertTypesMatchPytd(ty, """ from typing import Any, TypeVar @@ -307,11 +295,10 @@ def f(x: T) -> T v4 = ... # type: float v5 = ... # type: Any """) - self.assertErrorLogIs( - errors, [(9, "wrong-arg-types", r"x: float.*x: str")]) + self.assertErrorRegexes(errors, {"e": r"x: float.*x: str"}) def testBadReturn(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ from typing import AnyStr, Dict class Foo(object): @@ -321,14 +308,13 @@ def g(self) -> Dict[AnyStr, Dict[AnyStr, AnyStr]]: """) def testOptionalTypeVar(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Optional, TypeVar T = TypeVar("T", bound=str) def f() -> Optional[T]: - return 42 if __random__ else None + return 42 if __random__ else None # bad-return-type[e] """, deep=True) - self.assertErrorLogIs( - errors, [(4, "bad-return-type", r"Optional\[T\].*int")]) + self.assertErrorRegexes(errors, {"e": r"Optional\[T\].*int"}) def testUnicodeLiterals(self): ty = self.Infer(""" @@ -411,22 +397,20 @@ class TypeVarTestPy3(test_base.TargetPython3FeatureTest): def testUseConstraintsFromPyi(self): with file_utils.Tempdir() as d: - # pylint: disable=g-backslash-continuation - d.create_file("foo.pyi", """\ + d.create_file("foo.pyi", """ from typing import AnyStr, TypeVar T = TypeVar("T", int, float) def f(x: T) -> T: ... def g(x: AnyStr) -> AnyStr: ... """) - # pylint: enable=g-backslash-continuation - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.f("") - foo.g(0) + foo.f("") # wrong-arg-types[e1] + foo.g(0) # wrong-arg-types[e2] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (2, "wrong-arg-types", r"Union\[float, int\].*str"), - (3, "wrong-arg-types", r"Union\[bytes, str\].*int")]) + self.assertErrorRegexes(errors, { + "e1": r"Union\[float, int\].*str", + "e2": r"Union\[bytes, str\].*int"}) def testSubprocess(self): ty = self.Infer(""" diff --git a/pytype/tests/py3/test_typing.py b/pytype/tests/py3/test_typing.py index 443e7e075..9381a7bd6 100644 --- a/pytype/tests/py3/test_typing.py +++ b/pytype/tests/py3/test_typing.py @@ -20,8 +20,8 @@ def _test_match(self, arg, annotation, disables=""): self.Check(self._TEMPLATE % locals()) def _test_no_match(self, arg, annotation, disables=""): - _, errors = self.InferWithErrors(self._TEMPLATE % locals()) - self.assertNotEqual(0, len(errors)) + code = (self._TEMPLATE % locals()).rstrip() + " # wrong-arg-types" + self.InferWithErrors(code) def test_list_match(self): self._test_match("[1, 2, 3]", "typing.List") @@ -36,7 +36,7 @@ def test_sequence_match(self): self._test_no_match("[1.1, 2.1, 3.1]", "typing.Sequence[int]") def test_generator(self): - self.Check("""\ + self.Check(""" from typing import Generator def f() -> Generator[int, None, None]: for i in range(3): @@ -44,14 +44,14 @@ def f() -> Generator[int, None, None]: """) def test_type(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Type class Foo: x = 1 def f1(foo: Type[Foo]): return foo.x def f2(foo: Type[Foo]): - return foo.y # bad + return foo.y # attribute-error[e] def f3(foo: Type[Foo]): return foo.mro() def f4(foo: Type[Foo]): @@ -61,7 +61,7 @@ def f4(foo: Type[Foo]): v3 = f3(Foo) v4 = f4(Foo) """) - self.assertErrorLogIs(errors, [(7, "attribute-error", r"y.*Foo")]) + self.assertErrorRegexes(errors, {"e": r"y.*Foo"}) self.assertTypesMatchPytd(ty, """ from typing import Any, Type class Foo: @@ -77,7 +77,7 @@ def f4(foo: Type[Foo]) -> Foo """) def test_type_union(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Type, Union class Foo: bar = ... # type: int @@ -86,13 +86,13 @@ def f1(x: Type[Union[int, Foo]]): # differently. See get_attribute() in attribute.py. x.bar def f2(x: Union[Type[int], Type[Foo]]): - x.bar + x.bar # attribute-error[e] f1(x) def f3(x: Type[Union[int, Foo]]): f1(x) f2(x) """) - self.assertErrorLogIs(errors, [(9, "attribute-error", "bar.*int")]) + self.assertErrorRegexes(errors, {"e": r"bar.*int"}) def test_use_type_alias(self): with file_utils.Tempdir() as d: @@ -113,7 +113,7 @@ def test_callable(self): from typing import Callable def f() -> Callable """) - self.Check("""\ + self.Check(""" from typing import Callable import foo def f() -> Callable: @@ -123,7 +123,7 @@ def g() -> Callable: """, pythonpath=[d.path]) def test_callable_parameters(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Any, Callable # The below are all valid. @@ -131,19 +131,19 @@ def f1(x: Callable[[int, str], bool]): ... def f2(x: Callable[..., bool]): ... def f3(x: Callable[[], bool]): ... - def g1(x: Callable[int, bool]): ... # bad: _ARGS not a list + def g1(x: Callable[int, bool]): ... # _ARGS not a list # invalid-annotation[e1] lst = [int] if __random__ else [str] - def g2(x: Callable[lst, bool]): ... # bad: _ARGS ambiguous + def g2(x: Callable[lst, bool]): ... # _ARGS ambiguous # invalid-annotation[e2] # invalid-annotation[e3] # bad: _RET ambiguous - def g3(x: Callable[[], bool if __random__ else str]): ... + def g3(x: Callable[[], bool if __random__ else str]): ... # invalid-annotation[e4] # bad: _ARGS[0] ambiguous - def g4(x: Callable[[int if __random__ else str], bool]): ... + def g4(x: Callable[[int if __random__ else str], bool]): ... # invalid-annotation[e5] lst = None # type: list[int] - def g5(x: Callable[lst, bool]): ... # bad: _ARGS not a constant - def g6(x: Callable[[42], bool]): ... # bad: _ARGS[0] not a type - def g7(x: Callable[[], bool, int]): ... # bad: Too many params - def g8(x: Callable[Any, bool]): ... # bad: Any is not allowed - def g9(x: Callable[[]]) -> None: ... + def g5(x: Callable[lst, bool]): ... # _ARGS not a constant # invalid-annotation[e6] + def g6(x: Callable[[42], bool]): ... # _ARGS[0] not a type # invalid-annotation[e7] + def g7(x: Callable[[], bool, int]): ... # Too many params # invalid-annotation[e8] + def g8(x: Callable[Any, bool]): ... # Any is not allowed # invalid-annotation[e9] + def g9(x: Callable[[]]) -> None: ... # invalid-annotation[e10] """) self.assertTypesMatchPytd(ty, """ from typing import Any, Callable, List, Type @@ -163,32 +163,28 @@ def g7(x: Callable[[], bool]) -> None: ... def g8(x: Callable[Any, bool]) -> None: ... def g9(x: Callable[[], Any]) -> None: ... """) - self.assertErrorLogIs(errors, [ - (8, "invalid-annotation", - r"'int'.*must be a list of argument types or ellipsis"), - (10, "invalid-annotation", r"\[int\] or \[str\].*Must be constant"), - (10, "invalid-annotation", - r"'Any'.*must be a list of argument types or ellipsis"), - (12, "invalid-annotation", r"bool or str.*Must be constant"), - (14, "invalid-annotation", r"int or str.*Must be constant"), - (16, "invalid-annotation", - r"instance of List\[int\].*Must be constant"), - (17, "invalid-annotation", r"instance of int"), - (18, "invalid-annotation", r"Callable.*Expected 2.*got 3"), - (19, "invalid-annotation", - r"'Any'.*must be a list of argument types or ellipsis"), - (20, "invalid-annotation", r"Callable\[_ARGS, _RET].*2.*1"),]) + self.assertErrorRegexes(errors, { + "e1": r"'int'.*must be a list of argument types or ellipsis", + "e2": r"\[int\] or \[str\].*Must be constant", + "e3": r"'Any'.*must be a list of argument types or ellipsis", + "e4": r"bool or str.*Must be constant", + "e5": r"int or str.*Must be constant", + "e6": r"instance of List\[int\].*Must be constant", + "e7": r"instance of int", + "e8": r"Callable.*Expected 2.*got 3", + "e9": r"'Any'.*must be a list of argument types or ellipsis", + "e10": r"Callable\[_ARGS, _RET].*2.*1"}) def test_callable_bad_args(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Callable lst1 = [str] lst1[0] = int - def g1(x: Callable[lst1, bool]): ... # line 4 + def g1(x: Callable[lst1, bool]): ... # invalid-annotation[e1] lst2 = [str] while __random__: lst2.append(int) - def g2(x: Callable[lst2, bool]): ... # line 8 + def g2(x: Callable[lst2, bool]): ... # invalid-annotation[e2] """) self.assertTypesMatchPytd(ty, """ from typing import Callable, List, Type, Union @@ -200,11 +196,11 @@ def g2(x: Callable[..., bool]) -> None: ... # For the first error, it would be more precise to say [str or int], since # the mutation is simple enough that we could keep track of the change to # the constant, but we don't do that yet. - self.assertErrorLogIs(errors, [ - (4, "invalid-annotation", - r"instance of List\[Type\[Union\[int, str\]\]\].*Must be constant"), - (8, "invalid-annotation", - r"instance of List\[Type\[Union\[int, str\]\]\].*Must be constant"),]) + self.assertErrorRegexes(errors, { + "e1": (r"instance of List\[Type\[Union\[int, str\]\]\].*" + r"Must be constant"), + "e2": r"instance of List\[Type\[Union\[int, str\]\]\].*Must be constant" + }) def test_generics(self): with file_utils.Tempdir() as d: @@ -214,7 +210,7 @@ def test_generics(self): V = TypeVar("V") class CustomDict(Dict[K, V]): ... """) - self.Check("""\ + self.Check(""" import typing import foo def f(x: typing.Callable[..., int]): pass @@ -273,13 +269,13 @@ class Any(object): """) def test_callable_call(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Callable f = ... # type: Callable[[int], str] - v1 = f() + v1 = f() # wrong-arg-count[e1] v2 = f(True) # ok - v3 = f(42.0) - v4 = f(1, 2) + v3 = f(42.0) # wrong-arg-types[e2] + v4 = f(1, 2) # wrong-arg-count[e3] """) self.assertTypesMatchPytd(ty, """ from typing import Any, Callable @@ -289,16 +285,15 @@ def test_callable_call(self): v3 = ... # type: Any v4 = ... # type: Any """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-count", "1.*0"), - (5, "wrong-arg-types", "int.*float"), - (6, "wrong-arg-count", "1.*2")]) + self.assertErrorRegexes( + errors, {"e1": r"1.*0", "e2": r"int.*float", "e3": r"1.*2"}) def test_callable_call_with_type_parameters(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Callable, TypeVar T = TypeVar("T") def f(g: Callable[[T, T], T], y, z): - return g(y, z) + return g(y, z) # wrong-arg-types[e] v1 = f(__any_object__, 42, 3.14) # ok v2 = f(__any_object__, 42, "hello world") """, deep=True) @@ -309,7 +304,7 @@ def f(g: Callable[[T, T], T], y, z): ... v1 = ... # type: int or float v2 = ... # type: Any """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"int.*str")]) + self.assertErrorRegexes(errors, {"e": r"int.*str"}) def test_callable_call_with_return_only(self): ty = self.Infer(""" @@ -324,21 +319,19 @@ def test_callable_call_with_return_only(self): """) def test_callable_call_with_varargs_and_kwargs(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Callable f = ... # type: Callable[[], int] - f(x=3) - f(*(42,)) - f(**{"x": "hello", "y": "world"}) - f(*(42,), **{"hello": "world"}) + f(x=3) # wrong-keyword-args[e1] + f(*(42,)) # wrong-arg-count[e2] + f(**{"x": "hello", "y": "world"}) # wrong-keyword-args[e3] + f(*(42,), **{"hello": "world"}) # wrong-keyword-args[e4] """) - self.assertErrorLogIs(errors, [(3, "wrong-keyword-args", r"x"), - (4, "wrong-arg-count", r"0.*1"), - (5, "wrong-keyword-args", r"x, y"), - (6, "wrong-keyword-args", r"hello")]) + self.assertErrorRegexes(errors, {"e1": r"x", "e2": r"0.*1", "e3": r"x, y", + "e4": r"hello"}) def test_callable_attribute(self): - self.Check("""\ + self.Check(""" from typing import Any, Callable def foo(fn: Callable[[Any], Any]): fn.foo # pytype: disable=attribute-error @@ -423,20 +416,16 @@ def test_new_type_error(self): def func1(i: MyInt) -> MyInt: return i def func2(i: int) -> MyInt: - return i + return i # bad-return-type[e1] def func3(s: MyStr) -> MyStr: return s - func1(123) - func3(MyStr(123)) - """) - self.assertErrorLogIs( - errors, - [(8, "bad-return-type", - r"Expected: MyInt\nActually returned: int"), - (11, "wrong-arg-types", - r".*Expected: \(i: MyInt\)\nActually passed: \(i: int\)"), - (12, "wrong-arg-types", - r".*Expected:.*val: str\)\nActually passed:.*val: int\)"),]) + func1(123) # wrong-arg-types[e2] + func3(MyStr(123)) # wrong-arg-types[e3] + """) + self.assertErrorRegexes(errors, { + "e1": r"Expected: MyInt\nActually returned: int", + "e2": r".*Expected: \(i: MyInt\)\nActually passed: \(i: int\)", + "e3": r".*Expected:.*val: str\)\nActually passed:.*val: int\)"}) def test_maybe_return(self): self.Check(""" @@ -468,102 +457,95 @@ def g() -> str: """) def test_union_ellipsis(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Union - MyUnion = Union[int, ...] + MyUnion = Union[int, ...] # invalid-annotation[e] """) - self.assertErrorLogIs( - errors, [(2, "invalid-annotation", r"Ellipsis.*index 1.*Union")]) + self.assertErrorRegexes(errors, {"e": r"Ellipsis.*index 1.*Union"}) def test_list_ellipsis(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import List - MyList = List[int, ...] + MyList = List[int, ...] # invalid-annotation[e] """) - self.assertErrorLogIs( - errors, [(2, "invalid-annotation", r"Ellipsis.*index 1.*List")]) + self.assertErrorRegexes(errors, {"e": r"Ellipsis.*index 1.*List"}) def test_multiple_ellipses(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Union - MyUnion = Union[..., int, ..., str, ...] + MyUnion = Union[..., int, ..., str, ...] # invalid-annotation[e] """) - self.assertErrorLogIs(errors, [ - (2, "invalid-annotation", r"Ellipsis.*indices 0, 2, 4.*Union")]) + self.assertErrorRegexes(errors, {"e": r"Ellipsis.*indices 0, 2, 4.*Union"}) def test_bad_tuple_ellipsis(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Tuple - MyTuple1 = Tuple[..., ...] - MyTuple2 = Tuple[...] + MyTuple1 = Tuple[..., ...] # invalid-annotation[e1] + MyTuple2 = Tuple[...] # invalid-annotation[e2] """) - self.assertErrorLogIs( - errors, [(2, "invalid-annotation", r"Ellipsis.*index 0.*Tuple"), - (3, "invalid-annotation", r"Ellipsis.*index 0.*Tuple")]) + self.assertErrorRegexes(errors, {"e1": r"Ellipsis.*index 0.*Tuple", + "e2": r"Ellipsis.*index 0.*Tuple"}) def test_bad_callable_ellipsis(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Callable - MyCallable1 = Callable[..., ...] - MyCallable2 = Callable[[int], ...] - MyCallable3 = Callable[[...], int] - MyCallable4 = Callable[[int], int, int] + MyCallable1 = Callable[..., ...] # invalid-annotation[e1] + MyCallable2 = Callable[[int], ...] # invalid-annotation[e2] + MyCallable3 = Callable[[...], int] # invalid-annotation[e3] + MyCallable4 = Callable[[int], int, int] # invalid-annotation[e4] """) - self.assertErrorLogIs( - errors, [(2, "invalid-annotation", r"Ellipsis.*index 1.*Callable"), - (3, "invalid-annotation", r"Ellipsis.*index 1.*Callable"), - (4, "invalid-annotation", r"Ellipsis.*index 0.*list"), - (5, "invalid-annotation", r"Callable\[_ARGS, _RET].*2.*3")]) + self.assertErrorRegexes(errors, { + "e1": r"Ellipsis.*index 1.*Callable", + "e2": r"Ellipsis.*index 1.*Callable", + "e3": r"Ellipsis.*index 0.*list", + "e4": r"Callable\[_ARGS, _RET].*2.*3"}) def test_optional_parameters(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import Optional def func1(x: Optional[int]): pass - def func2(x: Optional): + def func2(x: Optional): # invalid-annotation[e1] pass - def func3(x: Optional[int, float, str]): + def func3(x: Optional[int, float, str]): # invalid-annotation[e2] pass """) - self.assertErrorLogIs( - errors, [(6, "invalid-annotation", r"Not a type"), - (9, "invalid-annotation", - r"typing.Optional can only contain one type parameter")]) + self.assertErrorRegexes( + errors, {"e1": r"Not a type", + "e2": r"typing\.Optional can only contain one type parameter"}) def test_noreturn_parameters(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import NoReturn, List def func0() -> NoReturn: raise ValueError() - def func1() -> List[NoReturn]: + def func1() -> List[NoReturn]: # invalid-annotation[e1] raise ValueError() def func2(x) -> NoReturn: if x > 1: - raise ValueError() + raise ValueError() # bad-return-type[e2] - def func3(x: NoReturn): + def func3(x: NoReturn): # invalid-annotation[e3] pass - def func4(x: List[NoReturn]): + def func4(x: List[NoReturn]): # invalid-annotation[e4] pass - bad = None # type: NoReturn + bad = None # type: NoReturn # invalid-annotation[e5] """) - self.assertErrorLogIs( - errors, [(6, "invalid-annotation", r"NoReturn is not allowed"), - (11, "bad-return-type", r"NoReturn.*None"), - (13, "invalid-annotation", r"NoReturn is not allowed"), - (16, "invalid-annotation", r"NoReturn is not allowed"), - (19, "invalid-annotation", r"NoReturn is not allowed")]) + self.assertErrorRegexes(errors, { + "e1": r"NoReturn is not allowed", "e2": r"NoReturn.*None", + "e3": r"NoReturn is not allowed", "e4": r"NoReturn is not allowed", + "e5": r"NoReturn is not allowed"}) def test_SupportsComplex(self): - self.Check("""\ + self.Check(""" from typing import SupportsComplex def foo(x: SupportsComplex): pass @@ -575,7 +557,7 @@ class CounterTest(test_base.TargetPython3BasicTest): """Tests for typing.Counter.""" def test_counter_generic(self): - ty, errors = self.InferWithErrors(""" + ty, _ = self.InferWithErrors(""" import collections import typing def freqs(s: str) -> typing.Counter[str]: @@ -587,8 +569,8 @@ def freqs(s: str) -> typing.Counter[str]: x + y x | y x & y - x - z # line 13 error: unsupported-operands - x.most_common(1, 2, 3) # line 14 error: wrong-arg-count + x - z # unsupported-operands + x.most_common(1, 2, 3) # wrong-arg-count a = x.most_common() b = x.most_common(1) c = x.elements() @@ -614,8 +596,6 @@ def freqs(s: str) -> typing.Counter[str]: def freqs(s: str) -> Counter[str]: ... """) - self.assertErrorLogIs( - errors, [(13, "unsupported-operands"), (14, "wrong-arg-count")]) class TypingTestPython3Feature(test_base.TargetPython3FeatureTest): @@ -650,14 +630,14 @@ def test_import_all(self): self.assertTypesMatchPytd(ty, "") def test_callable_func_name(self): - self.Check("""\ + self.Check(""" from typing import Any, Callable def foo(fn: Callable[[Any], Any]) -> str: return fn.__qualname__ """) def test_classvar(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import ClassVar class A(object): x: ClassVar[int] = 5 diff --git a/pytype/tests/py3/test_typing_methods.py b/pytype/tests/py3/test_typing_methods.py index a75ae230b..3323e6d6d 100644 --- a/pytype/tests/py3/test_typing_methods.py +++ b/pytype/tests/py3/test_typing_methods.py @@ -16,7 +16,7 @@ def test_mapping(self): class MyDict(Mapping[K, V]): ... def f() -> MyDict[str, int] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo m = foo.f() a = m.copy() diff --git a/pytype/tests/py3/test_typing_namedtuple.py b/pytype/tests/py3/test_typing_namedtuple.py index 603c5e736..a224fc224 100644 --- a/pytype/tests/py3/test_typing_namedtuple.py +++ b/pytype/tests/py3/test_typing_namedtuple.py @@ -8,22 +8,19 @@ class NamedTupleTest(test_base.TargetPython3BasicTest): """Tests for the typing.NamedTuple overlay.""" def test_make(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import typing A = typing.NamedTuple("A", [("b", str), ("c", str)]) a = A._make(["hello", "world"]) b = A._make(["hello", "world"], len=len) - c = A._make([1, 2]) # Should fail - d = A._make(A) # Should fail + c = A._make([1, 2]) # wrong-arg-types + d = A._make(A) # wrong-arg-types def f(e: A) -> None: pass f(a) """) - self.assertErrorLogIs(errors, [ - (5, "wrong-arg-types"), - (6, "wrong-arg-types")]) def test_subclass(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import typing A = typing.NamedTuple("A", [("b", str), ("c", int)]) class B(A): @@ -36,15 +33,12 @@ def take_b(b: B) -> None: pass take_a(x) take_b(x) take_b(y) - take_b(A("", 0)) # Should fail - B() # Should fail + take_b(A("", 0)) # wrong-arg-types + B() # missing-parameter # _make and _replace should return instances of the subclass. take_b(B._make(["hello", 0])) take_b(y._replace(b="world")) """) - self.assertErrorLogIs(errors, [ - (13, "wrong-arg-types"), - (14, "missing-parameter")]) def test_callable_attribute(self): ty = self.Infer(""" @@ -57,22 +51,22 @@ def foo(x: X): "def foo(x: X) -> Callable: ...") def test_bare_union_attribute(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import NamedTuple, Union - X = NamedTuple("X", [("x", Union)]) + X = NamedTuple("X", [("x", Union)]) # invalid-annotation[e] def foo(x: X): return x.x """) self.assertMultiLineEqual(pytd_utils.Print(ty.Lookup("foo")), "def foo(x: X) -> Any: ...") - self.assertErrorLogIs(errors, [(2, "invalid-annotation", r"Union.*x")]) + self.assertErrorRegexes(errors, {"e": r"Union.*x"}) class NamedTupleTestPy3(test_base.TargetPython3FeatureTest): """Tests for the typing.NamedTuple overlay in Python 3.6.""" def test_basic_namedtuple(self): - ty = self.Infer("""\ + ty = self.Infer(""" import typing X = typing.NamedTuple("X", [("a", int), ("b", str)]) x = X(1, "hello") @@ -81,7 +75,7 @@ def test_basic_namedtuple(self): """) self.assertTypesMatchPytd( ty, - """\ + """ import collections from typing import Callable, Iterable, Sized, Tuple, Type, TypeVar, Union typing = ... # type: module @@ -121,54 +115,50 @@ def foo(x: X): "def foo(x: X) -> Union[bytes, str]: ...") def test_bad_call(self): - _, errorlog = self.InferWithErrors("""\ + _, errorlog = self.InferWithErrors(""" from typing import NamedTuple E2 = NamedTuple('Employee2', [('name', str), ('id', int)], - birth=str, gender=bool) + birth=str, gender=bool) # invalid-namedtuple-arg[e1] # wrong-keyword-args[e2] """) - self.assertErrorLogIs(errorlog, [ - (3, "invalid-namedtuple-arg", "Either list of fields or keywords.*"), - (3, "wrong-keyword-args", ".*(birth, gender).*NamedTuple")]) + self.assertErrorRegexes(errorlog, { + "e1": r"Either list of fields or keywords.*", + "e2": r".*(birth, gender).*NamedTuple"}) def test_bad_attribute(self): - _, errorlog = self.InferWithErrors("""\ + _, errorlog = self.InferWithErrors(""" from typing import NamedTuple - class SubCls(NamedTuple): + class SubCls(NamedTuple): # not-writable[e] def __init__(self): pass """) - self.assertErrorLogIs(errorlog, [ - (3, "not-writable", ".*'__init__'.*[SubCls]")]) + self.assertErrorRegexes(errorlog, {"e": r".*'__init__'.*[SubCls]"}) def test_bad_arg_count(self): - _, errorlog = self.InferWithErrors("""\ + _, errorlog = self.InferWithErrors(""" from typing import NamedTuple class SubCls(NamedTuple): a: int b: int - cls1 = SubCls(5) + cls1 = SubCls(5) # missing-parameter[e] """) - self.assertErrorLogIs(errorlog, [ - (7, "missing-parameter", "Missing.*'b'.*__new__")]) + self.assertErrorRegexes(errorlog, {"e": r"Missing.*'b'.*__new__"}) def test_bad_arg_name(self): - _, errorlog = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import NamedTuple - class SubCls(NamedTuple): + class SubCls(NamedTuple): # invalid-namedtuple-arg _a: int b: int cls1 = SubCls(5) """) - self.assertErrorLogIs(errorlog, [ - (3, "invalid-namedtuple-arg")]) def test_namedtuple_class(self): - self.Check("""\ + self.Check(""" from typing import NamedTuple class SubNamedTuple(NamedTuple): @@ -191,7 +181,7 @@ def func(): """) def test_baseclass(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import NamedTuple class baseClass(object): @@ -203,7 +193,7 @@ class SubNamedTuple(baseClass, NamedTuple): """) self.assertTypesMatchPytd( ty, - """\ + """ import collections from typing import Callable, Iterable, Sized, Tuple, Type, TypeVar @@ -235,7 +225,7 @@ class baseClass(object): """) def test_namedtuple_class_pyi(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import NamedTuple class SubNamedTuple(NamedTuple): @@ -257,7 +247,7 @@ def func(): """) self.assertTypesMatchPytd( ty, - """\ + """ import collections from typing import Callable, Iterable, Sized, Tuple, Type, TypeVar, Union diff --git a/pytype/tests/py3/test_variable_annotations.py b/pytype/tests/py3/test_variable_annotations.py index 74be589cb..8f2ddb1d9 100644 --- a/pytype/tests/py3/test_variable_annotations.py +++ b/pytype/tests/py3/test_variable_annotations.py @@ -17,26 +17,24 @@ class A(object): a: int b: str """) - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import foo def f(x: int) -> None: pass obj = foo.A() f(foo.x) - f(foo.y) + f(foo.y) # wrong-arg-types[e1] f(obj.a) - f(obj.b) + f(obj.b) # wrong-arg-types[e2] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (6, "wrong-arg-types", r"int.*List"), - (8, "wrong-arg-types", r"int.*str")]) + self.assertErrorRegexes(errors, {"e1": r"int.*List", "e2": r"int.*str"}) class VariableAnnotationsFeatureTest(test_base.TargetPython3FeatureTest): """Tests for PEP526 variable annotations.""" def testInferTypes(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List lst: List[int] = [] @@ -48,7 +46,7 @@ class A(object): a: int = 1 b = 2 """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import List lst: List[int] @@ -61,26 +59,24 @@ class A(object): """) def testIllegalAnnotations(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import List, TypeVar, NoReturn T = TypeVar('T') - a: "abc" = "1" - b: 123 = "2" - c: NoReturn = "3" + a: "abc" = "1" # name-error[e1] + b: 123 = "2" # invalid-annotation[e2] + c: NoReturn = "3" # invalid-annotation[e3] d: List[int] = [] - e: List[T] = [] - f: int if __random__ else str = 123 - h: NoReturn = None - """) - self.assertErrorLogIs(errors, [ - (5, "name-error", "Name \'abc\' is not defined"), - (6, "invalid-annotation", "Not a type"), - (7, "invalid-annotation", "NoReturn is not allowed"), - (9, "not-supported-yet", r"type parameter.*variable annotation"), - (10, "invalid-annotation", r"Type must be constant"), - (11, "invalid-annotation", r"NoReturn is not allowed")]) + e: List[T] = [] # not-supported-yet[e4] + f: int if __random__ else str = 123 # invalid-annotation[e5] + h: NoReturn = None # invalid-annotation[e6] + """) + self.assertErrorRegexes(errors, { + "e1": r"Name \'abc\' is not defined", "e2": r"Not a type", + "e3": r"NoReturn is not allowed", + "e4": r"type parameter.*variable annotation", + "e5": r"Type must be constant", "e6": r"NoReturn is not allowed"}) def testUninitializedClassAnnotation(self): ty = self.Infer(""" @@ -106,12 +102,11 @@ def testUninitializedModuleAnnotation(self): """) def testOverwriteAnnotationsDict(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" __annotations__ = None - foo: int + foo: int # unsupported-operands[e] """) - self.assertErrorLogIs( - errors, [(2, "unsupported-operands", r"None.*__setitem__")]) + self.assertErrorRegexes(errors, {"e": r"None.*__setitem__"}) def testShadowNone(self): ty = self.Infer(""" @@ -140,12 +135,12 @@ class Foo: """) def testClassVariableForwardReference(self): - ty = self.Infer("""\ + ty = self.Infer(""" class A(object): a: 'A' = ... x = 42 """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ class A(object): a: A x: int @@ -154,13 +149,13 @@ class A(object): def testCallableForwardReference(self): # Callable[['A']...] creates an instance of A during output generation, # which previously caused a crash when iterating over existing instances. - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Callable class A(object): def __init__(self, fn: Callable[['A'], bool]): self.fn = fn """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Callable class A(object): fn: Callable[[A], bool] diff --git a/pytype/tests/test_abc.py b/pytype/tests/test_abc.py index 6b1a82006..6a1ece664 100644 --- a/pytype/tests/test_abc.py +++ b/pytype/tests/test_abc.py @@ -15,23 +15,21 @@ class Example(metaclass=abc.ABCMeta): @abc.abstractmethod def foo(self) -> None: ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.Example() + foo.Example() # not-instantiable[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "not-instantiable", - r"foo\.Example.*foo")]) + self.assertErrorRegexes(errors, {"e": r"foo\.Example.*foo"}) def test_stray_abstractmethod(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import abc - class Example(object): + class Example(object): # ignored-abstractmethod[e] @abc.abstractmethod def foo(self): pass """) - self.assertErrorLogIs(errors, [(2, "ignored-abstractmethod", - r"foo.*Example")]) + self.assertErrorRegexes(errors, {"e": r"foo.*Example"}) def test_multiple_inheritance_implementation_pyi(self): with file_utils.Tempdir() as d: @@ -60,11 +58,11 @@ class Interface(metaclass=abc.ABCMeta): def foo(self): ... class Foo(X, Interface): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.Foo().foo() + foo.Foo().foo() # not-instantiable[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "not-instantiable", r"foo\.Foo.*foo")]) + self.assertErrorRegexes(errors, {"e": r"foo\.Foo.*foo"}) def test_abc_metaclass_from_decorator(self): with file_utils.Tempdir() as d: @@ -103,15 +101,14 @@ def foo(self): """, pythonpath=[d.path]) def test_misplaced_abstractproperty(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import abc @abc.abstractproperty class Example(object): pass - Example() + Example() # not-callable[e] """) - self.assertErrorLogIs(errors, - [(5, "not-callable", r"'abstractproperty' object")]) + self.assertErrorRegexes(errors, {"e": r"'abstractproperty' object"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_attr.py b/pytype/tests/test_attr.py index 7c0435ff3..69a2fe0e6 100644 --- a/pytype/tests/test_attr.py +++ b/pytype/tests/test_attr.py @@ -140,24 +140,22 @@ def __init__(self, x: int, y: str) -> None: ... """) def test_type_clash(self): - errors = self.CheckWithErrors(""" + self.CheckWithErrors(""" import attr @attr.s - class Foo(object): + class Foo(object): # invalid-annotation x = attr.ib(type=str) # type: int y = attr.ib(type=str, default="") # type: int Foo(x="") # should not report an error """) - self.assertErrorLogIs(errors, [(4, "invalid-annotation")]) def test_bad_type(self): - errors = self.CheckWithErrors(""" + self.CheckWithErrors(""" import attr @attr.s class Foo(object): - x = attr.ib(type=10) + x = attr.ib(type=10) # invalid-annotation """) - self.assertErrorLogIs(errors, [(5, "invalid-annotation")]) def test_name_mangling(self): # NOTE: Python itself mangles names starting with two underscores. @@ -272,25 +270,24 @@ def __init__(self, x: list = ...) -> None: ... """) def test_bad_factory(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import attr @attr.s class Foo(object): - x = attr.ib(default=attr.Factory(42)) - y = attr.ib(factory=42) + x = attr.ib(default=attr.Factory(42)) # wrong-arg-types[e1] + y = attr.ib(factory=42) # wrong-arg-types[e2] """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"Callable.*int"), - (5, "wrong-arg-types", r"Callable.*int")]) + self.assertErrorRegexes(errors, {"e1": r"Callable.*int", + "e2": r"Callable.*int"}) def test_default_factory_clash(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import attr @attr.s class Foo(object): - x = attr.ib(default=None, factory=list) + x = attr.ib(default=None, factory=list) # duplicate-keyword-argument[e] """) - self.assertErrorLogIs( - errors, [(4, "duplicate-keyword-argument", r"default")]) + self.assertErrorRegexes(errors, {"e": r"default"}) def test_takes_self(self): ty = self.Infer(""" @@ -384,22 +381,21 @@ def __init__(self, y: int) -> None: ... """) def test_init_bad_constant(self): - err = self.CheckWithErrors("""\ + err = self.CheckWithErrors(""" import attr @attr.s class Foo(object): - x = attr.ib(init=0) + x = attr.ib(init=0) # wrong-arg-types[e] """) - self.assertErrorLogIs(err, [(4, "wrong-arg-types", r"bool.*int")]) + self.assertErrorRegexes(err, {"e": r"bool.*int"}) def test_init_bad_kwarg(self): - err = self.CheckWithErrors(""" + self.CheckWithErrors(""" import attr @attr.s class Foo: - x = attr.ib(init=__random__) # type: str + x = attr.ib(init=__random__) # type: str # not-supported-yet """) - self.assertErrorLogIs(err, [(5, "not-supported-yet")]) def test_class(self): self.assertNoCrash(self.Check, """ @@ -603,22 +599,21 @@ class Foo(object): """) def test_init_bad_constant(self): - err = self.CheckWithErrors("""\ + err = self.CheckWithErrors(""" import attr - @attr.s(init=0) + @attr.s(init=0) # wrong-arg-types[e] class Foo: pass """) - self.assertErrorLogIs(err, [(2, "wrong-arg-types", r"bool.*int")]) + self.assertErrorRegexes(err, {"e": r"bool.*int"}) def test_bad_kwarg(self): - err = self.CheckWithErrors(""" + self.CheckWithErrors(""" import attr - @attr.s(init=__random__) + @attr.s(init=__random__) # not-supported-yet class Foo: pass """) - self.assertErrorLogIs(err, [(3, "not-supported-yet")]) def test_depth(self): self.Check(""" diff --git a/pytype/tests/test_attributes.py b/pytype/tests/test_attributes.py index 5cd63d923..91a819abe 100644 --- a/pytype/tests/test_attributes.py +++ b/pytype/tests/test_attributes.py @@ -23,22 +23,22 @@ def f(self): """) def testClassConstantError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" x = None class Foo(object): - x = x.upper() + x = x.upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testMultiplePaths(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" x = None def f(): z = None if __random__ else x y = z - return y.upper() + return y.upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(5, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testLateInitialization(self): ty = self.Infer(""" @@ -82,42 +82,42 @@ def f(): """, pythonpath=[d.path]) def testReturnValue(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(): pass def g(): - return f().upper() + return f().upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(4, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testMethodReturnValue(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def f(self): pass def g(): - return Foo().f().upper() + return Foo().f().upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(5, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testPyiReturnValue(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", "def f() -> None: ...") - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import foo def g(): - return foo.f().upper() + return foo.f().upper() # attribute-error[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testPassThroughNone(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(x): return x def g(): - return f(None).upper() + return f(None).upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(4, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testShadowedLocalOrigin(self): self.Check(""" @@ -144,7 +144,7 @@ def g(): """) def testReturnConstant(self): - self.Check("""\ + self.Check(""" x = None def f(): return x @@ -153,22 +153,21 @@ def g(): """) def testUnpackedNone(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" _, a = 42, None - b = a.upper() + b = a.upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(2, "attribute-error", r"upper.*None")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None"}) def testFunctionDefault(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __init__(self, v=None): - v.upper() + v.upper() # attribute-error[e] def f(): Foo() """) - self.assertErrorLogIs( - errors, [(3, "attribute-error", r"upper.*None.*traceback.*line 5")]) + self.assertErrorRegexes(errors, {"e": r"upper.*None.*traceback.*line 5"}) def testKeepNoneReturn(self): ty = self.Infer(""" @@ -249,13 +248,12 @@ def f() -> Any """) def testGetItem(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(): x = None - return x[0] + return x[0] # unsupported-operands[e] """) - self.assertErrorLogIs( - errors, [(3, "unsupported-operands", r"item retrieval.*None.*int")]) + self.assertErrorRegexes(errors, {"e": r"item retrieval.*None.*int"}) def testIgnoreGetItem(self): self.Check(""" @@ -272,13 +270,12 @@ def f(): """) def testContains(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(): x = None - return 42 in x + return 42 in x # unsupported-operands[e] """) - self.assertErrorLogIs( - errors, [(3, "unsupported-operands", r"'in'.*None.*int")]) + self.assertErrorRegexes(errors, {"e": r"'in'.*None.*int"}) def testIgnoreContains(self): self.Check(""" @@ -500,13 +497,13 @@ def f(x) -> Any @test_base.skip("TODO(b/63407497): implement strict checking for __setitem__") def testUnionSetAttribute(self): - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" class A(object): x = "Hello world" def f(i): t = A() l = [t] - l[i].x = 1 # line 6 + l[i].x = 1 # not-writable return l[i].x """) self.assertTypesMatchPytd(ty, """ @@ -515,7 +512,6 @@ class A(object): x = ... # type: str def f(i) -> Any """) - self.assertErrorLogIs(errors, [(6, "not-writable")]) def testSetClass(self): ty = self.Infer(""" @@ -564,7 +560,7 @@ def __getattribute__(self, name) -> int """) def testHasDynamicAttributes(self): - self.Check("""\ + self.Check(""" class Foo1(object): has_dynamic_attributes = True class Foo2(object): @@ -577,7 +573,7 @@ class Foo3(object): """) def testHasDynamicAttributesSubClass(self): - self.Check("""\ + self.Check(""" class Foo(object): _HAS_DYNAMIC_ATTRIBUTES = True class Bar(Foo): @@ -588,12 +584,12 @@ class Bar(Foo): def testHasDynamicAttributesClassAttr(self): # Only instance attributes are dynamic. - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): _HAS_DYNAMIC_ATTRIBUTES = True - Foo.CONST + Foo.CONST # attribute-error[e] """) - self.assertErrorLogIs(errors, [(3, "attribute-error", "CONST.*Foo")]) + self.assertErrorRegexes(errors, {"e": r"CONST.*Foo"}) def testHasDynamicAttributesMetaclass(self): # Since class attributes of Foo are instance attributes for the metaclass, @@ -619,7 +615,7 @@ def testHasDynamicAttributesPYI(self): class Foo(object): has_dynamic_attributes = True """) - self.Check("""\ + self.Check(""" import mod mod.Foo().baz """, pythonpath=[d.path]) @@ -642,7 +638,7 @@ class Bar(mod.Foo): """, pythonpath=[d.path]) def testAttrOnStaticMethod(self): - self.Check("""\ + self.Check(""" import collections X = collections.namedtuple("X", "a b") @@ -657,21 +653,19 @@ def testModuleTypeAttribute(self): """) def testAttrOnNone(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def f(arg): x = "foo" if arg else None if not x: - x.upper() + x.upper() # attribute-error """) - self.assertErrorLogIs(errors, [(4, "attribute-error")]) def testIteratorOnNone(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def f(): pass - a, b = f() + a, b = f() # attribute-error """) - self.assertErrorLogIs(errors, [(3, "attribute-error")]) def testOverloadedBuiltin(self): self.Check(""" @@ -720,46 +714,43 @@ def __init__(self) -> None: ... @test_base.skip("Needs vm._get_iter() to iterate over individual bindings.") def testBadIter(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" v = [] if __random__ else 42 - for _ in v: + for _ in v: # attribute-error[e] pass """) - self.assertErrorLogIs(errors, [(2, "attribute-error", r"__iter__.*int")]) + self.assertErrorRegexes(errors, {"e": r"__iter__.*int"}) def testBadGetItem(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __getitem__(self, x): return 0 v = Foo() if __random__ else 42 - for _ in v: # line 5 + for _ in v: # attribute-error[e] pass """) - self.assertErrorLogIs(errors, [(5, "attribute-error", - r"__iter__.*int.*Union\[Foo, int\]")]) + self.assertErrorRegexes(errors, {"e": r"__iter__.*int.*Union\[Foo, int\]"}) def testBadContains(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __iter__(self): return iter([]) v = Foo() if __random__ else 42 - if 42 in v: # line 5 + if 42 in v: # unsupported-operands[e] pass """) - self.assertErrorLogIs( - errors, [(5, "unsupported-operands", - r"'in'.*'Union\[Foo, int\]' and 'int'")]) + self.assertErrorRegexes( + errors, {"e": r"'in'.*'Union\[Foo, int\]' and 'int'"}) def testSubclassShadowing(self): with file_utils.Tempdir() as d: - # pylint: disable=g-backslash-continuation - d.create_file("foo.pyi", """\ + d.create_file("foo.pyi", """ class X: b = ... # type: int """) - self.Check("""\ + self.Check(""" import foo a = foo.X() a.b # The attribute exists diff --git a/pytype/tests/test_base.py b/pytype/tests/test_base.py index 13ba05531..283f50a64 100644 --- a/pytype/tests/test_base.py +++ b/pytype/tests/test_base.py @@ -1,13 +1,13 @@ """Common methods for tests of analyze.py.""" import logging +import re import sys import textwrap from pytype import analyze from pytype import config from pytype import directors -from pytype import errors from pytype import load_pytd from pytype import utils from pytype.pyi import parser @@ -52,7 +52,10 @@ def _Wrapper(self, code, *args, **kwargs): def _IncrementLineNumbersPy2(func): def _Wrapper(self, errorlog, expected_errors): if self.options.python_version == (2, 7): - expected_errors = errorlog.increment_line_numbers(expected_errors) + for mark in expected_errors: + expected_errors[mark] = re.sub( + r"line (\d+)", + lambda m: "line %d" % (int(m.group(1)) + 1), expected_errors[mark]) return func(self, errorlog, expected_errors) return _Wrapper @@ -71,6 +74,19 @@ def _MatchLoaderConfig(options, loader): return True +def _Format(code): + # Removes the leading newline introduced by writing, e.g., + # self.Check(""" + # code + # """) + if test_utils.ANNOTATIONS_IMPORT + "\n\n" in code: + code = code.replace(test_utils.ANNOTATIONS_IMPORT + "\n\n", + test_utils.ANNOTATIONS_IMPORT + "\n") + elif code.startswith("\n"): + code = code[1:] + return textwrap.dedent(code) + + class BaseTest(unittest.TestCase): """Base class for implementing tests that check PyTD output.""" @@ -169,20 +185,20 @@ def ConfigureOptions(self, **kwargs): python_exe=utils.get_python_exe(self.options.python_version)) # For historical reasons (byterun), this method name is snakecase: - # TODO(kramm): Rename this function. # pylint: disable=invalid-name def Check(self, code, pythonpath=(), skip_repeat_calls=True, report_errors=True, filename=None, quick=False, **kwargs): """Run an inference smoke test for the given code.""" self.ConfigureOptions(skip_repeat_calls=skip_repeat_calls, pythonpath=pythonpath, quick=quick) - errorlog = errors.ErrorLog() try: - src = "" if six.PY3: - src = textwrap.dedent(code) + src = _Format(code) else: - src = textwrap.dedent(code.decode("utf-8")) + src = _Format(code.decode("utf-8")) + errorlog = test_utils.TestErrorLog(code) + if errorlog.expected: + self.fail("Cannot assert errors with Check(); use CheckWithErrors()") analyze.check_types( src, filename, loader=self.loader, errorlog=errorlog, options=self.options, **kwargs) @@ -196,7 +212,7 @@ def assertNoCrash(self, method, code, **kwargs): method(code, report_errors=False, **kwargs) def _SetUpErrorHandling(self, code, pythonpath, analyze_annotated, quick): - code = textwrap.dedent(code) + code = _Format(code) errorlog = test_utils.TestErrorLog(code) self.ConfigureOptions( pythonpath=pythonpath, analyze_annotated=analyze_annotated, quick=quick) @@ -211,19 +227,26 @@ def InferWithErrors(self, code, deep=True, pythonpath=(), unit.Visit(visitors.VerifyVisitor()) unit = optimize.Optimize(unit, builtins_pytd, lossy=False, use_abcs=False, max_union=7, remove_mutable=False) - return pytd_utils.CanonicalOrdering(unit), kwargs["errorlog"] + errorlog = kwargs["errorlog"] + errorlog.assert_errors_match_expected() + return pytd_utils.CanonicalOrdering(unit), errorlog def CheckWithErrors(self, code, deep=True, pythonpath=(), analyze_annotated=True, quick=False, **kwargs): kwargs.update( self._SetUpErrorHandling(code, pythonpath, analyze_annotated, quick)) analyze.check_types(filename="", deep=deep, **kwargs) - return kwargs["errorlog"] + errorlog = kwargs["errorlog"] + errorlog.assert_errors_match_expected() + return errorlog def InferFromFile(self, filename, pythonpath): with open(filename, "r") as fi: code = fi.read() - errorlog = errors.ErrorLog() + errorlog = test_utils.TestErrorLog(code) + if errorlog.expected: + self.fail( + "Cannot assert errors with InferFromFile(); use InferWithErrors()") self.ConfigureOptions( module_name=load_pytd.get_module_name(filename, pythonpath), pythonpath=pythonpath) @@ -329,12 +352,8 @@ def assertIsIdentity(self, func): self.assertEqual(param1.type, sig.return_type, "Not identity: %r" % pytd_utils.Print(func)) - def assertErrorsMatch(self, errorlog, expected_errors): - expected = errorlog.make_expected_errors(expected_errors) - self.assertErrorLogIs(errorlog, expected) - - def assertErrorLogIs(self, errorlog, expected_errors): - errorlog.assert_expected_errors(expected_errors) + def assertErrorRegexes(self, errorlog, expected_errors): + errorlog.assert_error_regexes(expected_errors) def _Pickle(self, ast, module_name): assert module_name @@ -345,7 +364,7 @@ def Infer(self, srccode, pythonpath=(), deep=True, report_errors=True, analyze_annotated=True, pickle=False, module_name=None, **kwargs): types, builtins_pytd = self._InferAndVerify( - textwrap.dedent(srccode), pythonpath=pythonpath, deep=deep, + _Format(srccode), pythonpath=pythonpath, deep=deep, analyze_annotated=analyze_annotated, module_name=module_name, report_errors=report_errors, **kwargs) types = optimize.Optimize(types, builtins_pytd, lossy=False, use_abcs=False, @@ -383,7 +402,9 @@ def _InferAndVerify( module_name=module_name, quick=quick, use_pickled_files=True, pythonpath=[""] if (not pythonpath and imports_map) else pythonpath, imports_map=imports_map, analyze_annotated=analyze_annotated) - errorlog = errors.ErrorLog() + errorlog = test_utils.TestErrorLog(src) + if errorlog.expected: + self.fail("Cannot assert errors with Infer(); use InferWithErrors()") unit, builtins_pytd = analyze.infer_types( src, errorlog, self.options, loader=self.loader, **kwargs) unit.Visit(visitors.VerifyVisitor()) @@ -427,7 +448,7 @@ def assertTypesMatchPytd(self, ty, pytd_src): CheckWithErrors = _AddAnnotationsImportPy2(CheckWithErrors) Infer = _AddAnnotationsImportPy2(Infer) InferWithErrors = _AddAnnotationsImportPy2(InferWithErrors) - assertErrorLogIs = _IncrementLineNumbersPy2(assertErrorLogIs) + assertErrorRegexes = _IncrementLineNumbersPy2(assertErrorRegexes) class TargetIndependentTest(BaseTest): diff --git a/pytype/tests/test_base_test.py b/pytype/tests/test_base_test.py index 42f26df2e..2e4d7b325 100644 --- a/pytype/tests/test_base_test.py +++ b/pytype/tests/test_base_test.py @@ -1,31 +1,124 @@ """Tests for our test framework.""" +from pytype import file_utils +from pytype import utils from pytype.tests import test_base +from pytype.tests import test_utils import six class ErrorLogTest(test_base.TargetIndependentTest): + def _lineno(self, line): + if self.options.python_version == (2, 7) and utils.USE_ANNOTATIONS_BACKPORT: + return line + 1 + return line + def test_error_comments(self): - err = self.CheckWithErrors("""\ + err = self.CheckWithErrors(""" a = 10 # a random comment - b = "hello" # .mark - c = a + b # some-error - d = a + b # .another_mark + b = "hello" + 3 # unsupported-operands[.mark] + c = (10).foo # attribute-error + d = int(int) # wrong-arg-types[.another_mark] + """) + self.assertEqual( + {mark: (e.lineno, e.name) for mark, e in err.marks.items()}, + {".mark": (self._lineno(2), "unsupported-operands"), + ".another_mark": (self._lineno(4), "wrong-arg-types")}) + self.assertEqual(err.expected, { + self._lineno(2): [("unsupported-operands", ".mark")], + self._lineno(3): [("attribute-error", None)], + self._lineno(4): [("wrong-arg-types", ".another_mark")]}) + + def test_multiple_errors_one_line(self): + err = self.CheckWithErrors(""" + x = (10).foo, "hello".foo # attribute-error[e1] # attribute-error[e2] """) - six.assertCountEqual(self, err.marks.keys(), [".mark", ".another_mark"]) - self.assertEqual(err.marks[".mark"], 2) - six.assertCountEqual(self, err.expected.keys(), [3]) - six.assertCountEqual(self, err.expected[3], "some-error") + line = self._lineno(1) + self.assertEqual(err.expected, {line: [("attribute-error", "e1"), + ("attribute-error", "e2")]}) + six.assertCountEqual(self, err.marks, ["e1", "e2"]) + self.assertIn("on int", err.marks["e1"].message) + self.assertIn("on str", err.marks["e2"].message) + + def test_populate_marks(self): + # Test that assert_error_regexes populates self.marks if not already done. + errorlog = test_utils.TestErrorLog("x = 0") + self.assertIsNone(errorlog.marks) + self.assertErrorRegexes(errorlog, {}) + self.assertIsNotNone(errorlog.marks) + + def test_duplicate_mark(self): + with self.assertRaises(AssertionError) as ctx: + self.CheckWithErrors("x = 0 # attribute-error[e] # attribute-error[e]") + self.assertEqual(str(ctx.exception), "Mark e already used") def test_error_matching(self): - err = self.CheckWithErrors("""\ + err = self.CheckWithErrors(""" a = 10 b = "hello" c = a + b # unsupported-operands - d = a.foo() # .mark + d = a.foo() # attribute-error[.mark] """) - self.assertErrorsMatch(err, [(".mark", "attribute-error", ".*foo.*")]) + self.assertErrorRegexes(err, {".mark": ".*foo.*"}) + + def test_mismatched_error(self): + with self.assertRaises(AssertionError) as ctx: + self.CheckWithErrors("(10).foo # wrong-arg-types") + self.assertIn("Error does not match", str(ctx.exception)) + + def test_unexpected_error(self): + with self.assertRaises(AssertionError) as ctx: + self.CheckWithErrors(""" + (10).foo # attribute-error + "hello".foo + """) + self.assertIn("Unexpected error", str(ctx.exception)) + + def test_leftover_error(self): + with self.assertRaises(AssertionError) as ctx: + self.CheckWithErrors("x = 0 # attribute-error") + self.assertIn("Errors not found", str(ctx.exception)) + + def test_misspelled_leftover_error(self): + with self.assertRaises(AssertionError) as ctx: + self.CheckWithErrors("x = 0 # misspelled-error") + self.assertIn("Errors not found", str(ctx.exception)) + + def test_mismatched_regex(self): + err = self.CheckWithErrors("(10).foo # attribute-error[e]") + with self.assertRaises(AssertionError) as ctx: + self.assertErrorRegexes(err, {"e": r"does not match error message"}) + self.assertIn("Bad error message", str(ctx.exception)) + + def test_missing_regex(self): + err = self.CheckWithErrors("(10).foo # attribute-error[e]") + with self.assertRaises(AssertionError) as ctx: + self.assertErrorRegexes(err, {}) + self.assertEqual(str(ctx.exception), "No regex for mark e") + + def test_leftover_regex(self): + err = self.CheckWithErrors("x = 0") + with self.assertRaises(AssertionError) as ctx: + self.assertErrorRegexes(err, {"e": ""}) + self.assertEqual(str(ctx.exception), "Marks not found in code: e") + + def test_bad_check(self): + with self.assertRaises(AssertionError) as ctx: + self.Check("name_error # name-error") + self.assertIn("Cannot assert errors", str(ctx.exception)) + + def test_bad_infer(self): + with self.assertRaises(AssertionError) as ctx: + self.Infer("name_error # name-error") + self.assertIn("Cannot assert errors", str(ctx.exception)) + + def test_bad_infer_from_file(self): + with file_utils.Tempdir() as d: + d.create_file("some_file.py", "name_error # name-error") + with self.assertRaises(AssertionError) as ctx: + self.InferFromFile(filename=d["some_file.py"], pythonpath=[]) + self.assertIn("Cannot assert errors", str(ctx.exception)) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_basic.py b/pytype/tests/test_basic.py index 17ee2304e..ebd82df70 100644 --- a/pytype/tests/test_basic.py +++ b/pytype/tests/test_basic.py @@ -10,7 +10,7 @@ def test_constant(self): self.Check("17") def test_for_loop(self): - self.Check("""\ + self.Check(""" out = "" for i in range(5): out = out + str(i) @@ -18,7 +18,7 @@ def test_for_loop(self): """) def test_inplace_operators(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ x, y = 2, 3 x **= y assert x == 8 and y == 3 @@ -47,7 +47,7 @@ def test_inplace_operators(self): """) def test_inplace_division(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ x, y = 24, 3 x /= y assert x == 8 and y == 3 @@ -84,83 +84,83 @@ def f6() -> str """) def test_slice_assignment(self): - self.Check("""\ + self.Check(""" l = list(range(10)) l[3:8] = ["x"] print(l) """) - self.Check("""\ + self.Check(""" l = list(range(10)) l[:8] = ["x"] print(l) """) - self.Check("""\ + self.Check(""" l = list(range(10)) l[3:] = ["x"] print(l) """) - self.Check("""\ + self.Check(""" l = list(range(10)) l[:] = ["x"] print(l) """) def test_slice_deletion(self): - self.Check("""\ + self.Check(""" l = list(range(10)) del l[3:8] print(l) """) - self.Check("""\ + self.Check(""" l = list(range(10)) del l[:8] print(l) """) - self.Check("""\ + self.Check(""" l = list(range(10)) del l[3:] print(l) """) - self.Check("""\ + self.Check(""" l = list(range(10)) del l[:] print(l) """) - self.Check("""\ + self.Check(""" l = list(range(10)) del l[::2] print(l) """) def test_building_stuff(self): - self.Check("""\ + self.Check(""" print((1+1, 2+2, 3+3)) """) - self.Check("""\ + self.Check(""" print([1+1, 2+2, 3+3]) """) - self.Check("""\ + self.Check(""" print({1:1+1, 2:2+2, 3:3+3}) """) def test_subscripting(self): - self.Check("""\ + self.Check(""" l = list(range(10)) print("%s %s %s" % (l[0], l[3], l[9])) """) - self.Check("""\ + self.Check(""" l = list(range(10)) l[5] = 17 print(l) """) - self.Check("""\ + self.Check(""" l = list(range(10)) del l[5] print(l) """) def test_generator_expression(self): - self.Check("""\ + self.Check(""" x = "-".join(str(z) for z in range(5)) assert x == "0-1-2-3-4" """) @@ -169,7 +169,7 @@ def test_generator_expression2(self): # From test_regr.py # This failed a different way than the previous join when genexps were # broken: - self.Check("""\ + self.Check(""" from textwrap import fill x = set(['test_str']) width = 70 @@ -181,31 +181,31 @@ def test_generator_expression2(self): """) def test_list_comprehension(self): - self.Check("""\ + self.Check(""" x = [z*z for z in range(5)] assert x == [0, 1, 4, 9, 16] """) def test_dict_comprehension(self): - self.Check("""\ + self.Check(""" x = {z:z*z for z in range(5)} assert x == {0:0, 1:1, 2:4, 3:9, 4:16} """) def test_set_comprehension(self): - self.Check("""\ + self.Check(""" x = {z*z for z in range(5)} assert x == {0, 1, 4, 9, 16} """) def test_list_slice(self): - self.Check("""\ + self.Check(""" [1, 2, 3][1:2] """) def test_strange_sequence_ops(self): # from stdlib: test/test_augassign.py - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ x = [1,2] x += [3,4] x *= 2 @@ -222,13 +222,13 @@ def test_strange_sequence_ops(self): """) def test_unary_operators(self): - self.Check("""\ + self.Check(""" x = 8 print(-x, ~x, not x) """) def test_attributes(self): - self.Check("""\ + self.Check(""" l = lambda: 1 # Just to have an object... l.foo = 17 print(hasattr(l, "foo"), l.foo) @@ -237,7 +237,7 @@ def test_attributes(self): """) def test_attribute_inplace_ops(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ l = lambda: 1 # Just to have an object... l.foo = 17 l.foo -= 3 @@ -245,27 +245,25 @@ def test_attribute_inplace_ops(self): """) def test_deleting_names(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" g = 17 assert g == 17 del g - g + g # name-error """) - self.assertErrorLogIs(errors, [(4, "name-error")]) def test_deleting_local_names(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def f(): l = 23 assert l == 23 del l - l + l # name-error f() """) - self.assertErrorLogIs(errors, [(5, "name-error")]) def test_import(self): - self.Check("""\ + self.Check(""" import math print(math.pi, math.e) from math import sqrt @@ -275,7 +273,7 @@ def test_import(self): """) def test_classes(self): - self.Check("""\ + self.Check(""" class Thing(object): def __init__(self, x): self.x = x @@ -288,7 +286,7 @@ def meth(self, y): """) def test_class_mros(self): - self.Check("""\ + self.Check(""" class A(object): pass class B(A): pass class C(A): pass @@ -299,7 +297,7 @@ class E(C, B): pass """) def test_class_mro_method_calls(self): - self.Check("""\ + self.Check(""" class A(object): def f(self): return 'A' class B(A): pass @@ -310,19 +308,19 @@ class D(B, C): pass """) def test_calling_methods_wrong(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Thing(object): def __init__(self, x): self.x = x def meth(self, y): return self.x * y thing1 = Thing(2) - print(Thing.meth(14)) + print(Thing.meth(14)) # missing-parameter[e] """) - self.assertErrorLogIs(errors, [(7, "missing-parameter", r"self")]) + self.assertErrorRegexes(errors, {"e": r"self"}) def test_calling_subclass_methods(self): - self.Check("""\ + self.Check(""" class Thing(object): def foo(self): return 17 @@ -335,7 +333,7 @@ class SubThing(Thing): """) def test_other_class_methods(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Thing(object): def foo(self): return 17 @@ -345,12 +343,12 @@ def bar(self): return 9 st = SubThing() - print(st.foo()) + print(st.foo()) # attribute-error[e] """) - self.assertErrorLogIs(errors, [(10, "attribute-error", r"foo.*SubThing")]) + self.assertErrorRegexes(errors, {"e": r"foo.*SubThing"}) def test_attribute_access(self): - self.Check("""\ + self.Check(""" class Thing(object): z = 17 def __init__(self): @@ -362,18 +360,18 @@ def __init__(self): """) def test_attribute_access_error(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Thing(object): z = 17 def __init__(self): self.x = 23 t = Thing() - print(t.xyzzy) + print(t.xyzzy) # attribute-error[e] """) - self.assertErrorLogIs(errors, [(6, "attribute-error", r"xyzzy.*Thing")]) + self.assertErrorRegexes(errors, {"e": r"xyzzy.*Thing"}) def test_staticmethods(self): - self.Check("""\ + self.Check(""" class Thing(object): @staticmethod def smeth(x): @@ -387,7 +385,7 @@ def cmeth(cls, x): """) def test_unbound_methods(self): - self.Check("""\ + self.Check(""" class Thing(object): def meth(self, x): print(x) @@ -396,7 +394,7 @@ def meth(self, x): """) def test_callback(self): - self.Check("""\ + self.Check(""" def lcase(s): return s.lower() l = ["xyz", "ABC"] @@ -406,7 +404,7 @@ def lcase(s): """) def test_unpacking(self): - self.Check("""\ + self.Check(""" a, b, c = (1, 2, 3) assert a == 1 assert b == 2 @@ -414,7 +412,7 @@ def test_unpacking(self): """) def test_jump_if_true_or_pop(self): - self.Check("""\ + self.Check(""" def f(a, b): return a or b assert f(17, 0) == 17 @@ -423,7 +421,7 @@ def f(a, b): """) def test_jump_if_false_or_pop(self): - self.Check("""\ + self.Check(""" def f(a, b): return not(a and b) assert f(17, 0) is True @@ -433,7 +431,7 @@ def f(a, b): """) def test_pop_jump_if_true(self): - self.Check("""\ + self.Check(""" def f(a): if not a: return 'foo' @@ -444,7 +442,7 @@ def f(a): """) def test_decorator(self): - self.Check("""\ + self.Check(""" def verbose(func): def _wrapper(*args, **kwargs): return func(*args, **kwargs) @@ -462,7 +460,7 @@ def test_multiple_classes(self): # across classes. This test would fail because A.__init__ would be # over-written with B.__init__, and A(1, 2, 3) would complain about # too many arguments. - self.Check("""\ + self.Check(""" class A(object): def __init__(self, a, b, c): self.sum = a + b + c @@ -488,15 +486,14 @@ def baz(): """) def test_delete_global(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" a = 3 def f(): global a del a f() - x = a + x = a # name-error """) - self.assertErrorLogIs(errors, [(6, "name-error")]) def test_string(self): self.Check("v = '\\xff'") @@ -509,14 +506,14 @@ class TestLoops(test_base.TargetIndependentTest): """Loop tests.""" def test_for(self): - self.Check("""\ + self.Check(""" for i in range(10): print(i) print("done") """) def test_break(self): - self.Check("""\ + self.Check(""" for i in range(10): print(i) if i == 7: @@ -526,7 +523,7 @@ def test_break(self): def test_continue(self): # fun fact: this doesn't use CONTINUE_LOOP - self.Check("""\ + self.Check(""" for i in range(10): if i % 3 == 0: continue @@ -535,7 +532,7 @@ def test_continue(self): """) def test_continue_in_try_except(self): - self.Check("""\ + self.Check(""" for i in range(10): try: if i % 3 == 0: @@ -547,7 +544,7 @@ def test_continue_in_try_except(self): """) def test_continue_in_try_finally(self): - self.Check("""\ + self.Check(""" for i in range(10): try: if i % 3 == 0: @@ -563,7 +560,7 @@ class TestComparisons(test_base.TargetIndependentTest): """Comparison tests.""" def test_in(self): - self.Check("""\ + self.Check(""" assert "x" in "xyz" assert "x" not in "abc" assert "x" in ("x", "y", "z") @@ -571,7 +568,7 @@ def test_in(self): """) def test_less(self): - self.Check("""\ + self.Check(""" assert 1 < 3 assert 1 <= 2 and 1 <= 1 assert "a" < "b" @@ -579,7 +576,7 @@ def test_less(self): """) def test_greater(self): - self.Check("""\ + self.Check(""" assert 3 > 1 assert 3 >= 1 and 3 >= 3 assert "z" > "a" @@ -590,12 +587,12 @@ def test_greater(self): class TestSlices(test_base.TargetIndependentTest): def test_slice_with_step(self): - self.Check("""\ + self.Check(""" [0][1:-2:2] """) def test_slice_on_unknown(self): - self.Check("""\ + self.Check(""" __any_object__[1:-2:2] """) diff --git a/pytype/tests/test_builtins1.py b/pytype/tests/test_builtins1.py index 05fc2c3ad..381d5760c 100644 --- a/pytype/tests/test_builtins1.py +++ b/pytype/tests/test_builtins1.py @@ -114,8 +114,8 @@ def t_testMax2(x, y) -> ? """) def testZipError(self): - errors = self.CheckWithErrors("zip([], [], [], 42)") - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", "Iterable.*int")]) + errors = self.CheckWithErrors("zip([], [], [], 42) # wrong-arg-types[e]") + self.assertErrorRegexes(errors, {"e": r"Iterable.*int"}) def testDictDefaults(self): ty = self.Infer(""" @@ -316,9 +316,8 @@ def f(x) -> str """) def testOpenError(self): - src = "open(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)" - errors = self.CheckWithErrors(src) - self.assertErrorLogIs(errors, [(1, "wrong-arg-count")]) + src = "open(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) # wrong-arg-count" + self.CheckWithErrors(src) def testSignal(self): ty = self.Infer(""" diff --git a/pytype/tests/test_builtins2.py b/pytype/tests/test_builtins2.py index 6569594d2..c2595c461 100644 --- a/pytype/tests/test_builtins2.py +++ b/pytype/tests/test_builtins2.py @@ -177,7 +177,7 @@ def testModule(self): d.create_file("foo.pyi", """ x = ... # type: module """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo foo.x.bar() x = foo.__name__ @@ -196,7 +196,7 @@ def testClassMethod(self): class A(object): x = ... # type: classmethod """) - ty = self.Infer("""\ + ty = self.Infer(""" from foo import A y = A.x() z = A().x() @@ -214,7 +214,7 @@ def testStaticMethod(self): class A(object): x = ... # type: staticmethod """) - ty = self.Infer("""\ + ty = self.Infer(""" from foo import A y = A.x() z = A().x() @@ -344,14 +344,14 @@ def testSum(self): """) def testReversed(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" x1 = reversed(range(42)) x2 = reversed([42]) x3 = reversed((4, 2)) x4 = reversed("hello") - x5 = reversed({42}) - x6 = reversed(frozenset([42])) - x7 = reversed({True: 42}) + x5 = reversed({42}) # wrong-arg-types[e1] + x6 = reversed(frozenset([42])) # wrong-arg-types[e2] + x7 = reversed({True: 42}) # wrong-arg-types[e3] x8 = next(reversed([42])) x9 = list(reversed([42])) """) @@ -367,10 +367,9 @@ def testReversed(self): x8 = ... # type: int x9 = ... # type: List[int] """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-types", r"Set\[int\]"), - (6, "wrong-arg-types", r"FrozenSet\[int\]"), - (7, "wrong-arg-types", - r"Dict\[bool, int\]")]) + self.assertErrorRegexes(errors, {"e1": r"Set\[int\]", + "e2": r"FrozenSet\[int\]", + "e3": r"Dict\[bool, int\]"}) def testStrJoin(self): ty = self.Infer(""" @@ -395,16 +394,14 @@ def testBytearrayJoin(self): """) def testReduce(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" reduce(lambda x, y: x+y, [1,2,3]).real reduce(lambda x, y: x+y, ["foo"]).upper() - reduce(lambda x, y: 4, "foo").real + reduce(lambda x, y: 4, "foo").real # attribute-error[e] reduce(lambda x, y: 4, [], "foo").upper() reduce(lambda x, y: "s", [1,2,3], 0).upper() """) - self.assertErrorLogIs(errors, [ - (3, "attribute-error", "real.*str") - ]) + self.assertErrorRegexes(errors, {"e": r"real.*str"}) def testDictPopItem(self): ty = self.Infer(""" @@ -511,7 +508,7 @@ def testTupleInit(self): """) def testEmptyTuple(self): - self.Check("""\ + self.Check(""" isinstance(42, ()) issubclass(int, ()) type("X", (), {"foo": 42}) @@ -519,7 +516,7 @@ def testEmptyTuple(self): """) def testListExtend(self): - ty = self.Infer("""\ + ty = self.Infer(""" x1 = [42] x1.extend([""]) x2 = [42] @@ -627,7 +624,7 @@ def testSetDefaultOneArg(self): """) def testSetDefaultVarargs(self): - ty = self.Infer("""\ + ty = self.Infer(""" x1 = {} y1 = x1.setdefault(*("foo", 42)) @@ -685,7 +682,7 @@ def testExec(self): d.create_file("foo.pyi", """ x = exec """) - self.Check("""\ + self.Check(""" import foo foo.x("a = 2") """, pythonpath=[d.path]) diff --git a/pytype/tests/test_builtins3.py b/pytype/tests/test_builtins3.py index e3c9ec948..df5c1746b 100644 --- a/pytype/tests/test_builtins3.py +++ b/pytype/tests/test_builtins3.py @@ -66,12 +66,13 @@ def testNextFunction(self): """) def testImplicitTypeVarImport(self): - ty, errors = self.InferWithErrors("v = " + abstract_utils.T) + ty, _ = self.InferWithErrors(""" + v = %s # name-error + """ % abstract_utils.T) self.assertTypesMatchPytd(ty, """ from typing import Any v = ... # type: Any """) - self.assertErrorLogIs(errors, [(1, "name-error")]) def testExplicitTypeVarImport(self): self.Check(""" @@ -90,7 +91,7 @@ def testClassOfType(self): @test_base.skip("broken") def testClear(self): - ty = self.Infer("""\ + ty = self.Infer(""" x = {1, 2} x.clear() y = {"foo": 1} @@ -121,26 +122,25 @@ def testRepr(self): """) def testIntInit(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" int() int(0) int("0") int("0", 10) int(u"0") int(u"0", 10) - int(0, 1, 2) # line 7: wrong argcount + int(0, 1, 2) # wrong-arg-count[e] """) - self.assertErrorLogIs(errors, [(7, "wrong-arg-count", r"1.*4")]) + self.assertErrorRegexes(errors, {"e": r"1.*4"}) def testNewlines(self): with file_utils.Tempdir() as d: - # pylint: disable=g-backslash-continuation - d.create_file("newlines.txt", """\ + d.create_file("newlines.txt", """ 1 2 3 """) - self.Check("""\ + self.Check(""" l = [] with open("newlines.txt", "rU") as f: for line in f: @@ -171,7 +171,7 @@ def testHasAttrNone(self): self.assertNoCrash(self.Check, "hasattr(int, None)") def testNumberAttrs(self): - ty = self.Infer("""\ + ty = self.Infer(""" a = (42).denominator b = (42).numerator c = (42).real @@ -206,21 +206,15 @@ def testBuiltins(self): """) def testSpecialBuiltinTypes(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" isinstance(1, int) - isinstance(1, "no") + isinstance(1, "no") # wrong-arg-types issubclass(int, object) - issubclass(0, 0) - issubclass(int, 0) + issubclass(0, 0) # wrong-arg-types + issubclass(int, 0) # wrong-arg-types hasattr(str, "upper") - hasattr(int, int) + hasattr(int, int) # wrong-arg-types """) - self.assertErrorLogIs(errors, [ - (2, "wrong-arg-types"), - (4, "wrong-arg-types"), - (5, "wrong-arg-types"), - (7, "wrong-arg-types"), - ]) def testUnpackList(self): ty = self.Infer(""" @@ -278,8 +272,8 @@ def testFromHex(self): """) def testNoneLength(self): - errors = self.CheckWithErrors("len(None)") - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", r"Sized.*None")]) + errors = self.CheckWithErrors("len(None) # wrong-arg-types[e]") + self.assertErrorRegexes(errors, {"e": r"Sized.*None"}) def testSequenceLength(self): self.Check(""" @@ -349,10 +343,10 @@ def testInput(self): """) def testSetDefaultError(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" x = {} - y = x.setdefault() - z = x.setdefault(1, 2, 3, *[]) + y = x.setdefault() # wrong-arg-count[e1] + z = x.setdefault(1, 2, 3, *[]) # wrong-arg-count[e2] """) self.assertTypesMatchPytd(ty, """ from typing import Any, Dict @@ -360,8 +354,7 @@ def testSetDefaultError(self): y = ... # type: Any z = ... # type: Any """) - self.assertErrorLogIs(errors, [(2, "wrong-arg-count", "2.*0"), - (3, "wrong-arg-count", "2.*3")]) + self.assertErrorRegexes(errors, {"e1": r"2.*0", "e2": r"2.*3"}) def testTuple(self): ty = self.Infer(""" diff --git a/pytype/tests/test_calls.py b/pytype/tests/test_calls.py index e319b30ce..fbef81793 100644 --- a/pytype/tests/test_calls.py +++ b/pytype/tests/test_calls.py @@ -12,7 +12,7 @@ def testOptional(self): d.create_file("mod.pyi", """ def foo(x: int, y: int = ..., z: int = ...) -> int """) - self.Check("""\ + self.Check(""" import mod mod.foo(1) mod.foo(1, 2) @@ -24,44 +24,41 @@ def testMissing(self): d.create_file("mod.pyi", """ def foo(x, y) -> int """) - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" import mod - mod.foo(1) + mod.foo(1) # missing-parameter """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "missing-parameter")]) def testExtraneous(self): with file_utils.Tempdir() as d: d.create_file("mod.pyi", """ def foo(x, y) -> int """) - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" import mod - mod.foo(1, 2, 3) + mod.foo(1, 2, 3) # wrong-arg-count """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "wrong-arg-count")]) def testMissingKwOnly(self): with file_utils.Tempdir() as d: d.create_file("mod.pyi", """ def foo(x, y, *, z) -> int """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import mod - mod.foo(1, 2) + mod.foo(1, 2) # missing-parameter[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "missing-parameter", r"\bz\b")]) + self.assertErrorRegexes(errors, {"e": r"\bz\b"}) def testExtraKeyword(self): with file_utils.Tempdir() as d: d.create_file("mod.pyi", """ def foo(x, y) -> int """) - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" import mod - mod.foo(1, 2, z=3) + mod.foo(1, 2, z=3) # wrong-keyword-args """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "wrong-keyword-args")]) def testVarArgsWithKwOnly(self): with file_utils.Tempdir() as d: @@ -69,7 +66,7 @@ def testVarArgsWithKwOnly(self): def foo(*args: int, z: int) -> int """) self.Check( - """\ + """ import mod mod.foo(1, 2, z=3) """, pythonpath=[d.path]) @@ -79,12 +76,11 @@ def testVarArgsWithMissingKwOnly(self): d.create_file("mod.pyi", """ def foo(*args: int, z: int) -> int """) - _, errors = self.InferWithErrors( - """\ + _, errors = self.InferWithErrors(""" import mod - mod.foo(1, 2, 3) + mod.foo(1, 2, 3) # missing-parameter[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "missing-parameter", r"\bz\b")]) + self.assertErrorRegexes(errors, {"e": r"\bz\b"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_classes.py b/pytype/tests/test_classes.py index b691c65e7..8a30e3ed9 100644 --- a/pytype/tests/test_classes.py +++ b/pytype/tests/test_classes.py @@ -209,15 +209,15 @@ def __init__(self, x) -> NoneType """) def testSuperError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Base(object): def __init__(self, x, y, z): pass class Foo(Base): def __init__(self, x): - super(Foo, self).__init__() + super(Foo, self).__init__() # missing-parameter[e] """) - self.assertErrorLogIs(errors, [(6, "missing-parameter", r"x")]) + self.assertErrorRegexes(errors, {"e": r"x"}) def testSuperInInit(self): ty = self.Infer(""" @@ -779,7 +779,7 @@ class X(int, object, metaclass=A): """) def testUnionBaseClass(self): - self.Check("""\ + self.Check(""" import typing class A(tuple): pass class B(tuple): pass @@ -897,27 +897,26 @@ class B(A[T]): ... class C(A[T], B[T]): ... def f() -> C[int]: ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.f() + foo.f() # mro-error[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "mro-error", r"C")]) + self.assertErrorRegexes(errors, {"e": r"C"}) def testCallParameterizedClass(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import List - List[str]() - """) - self.assertErrorLogIs(errors, [(2, "not-callable")]) + List[str]() # not-callable + """) def testErrorfulConstructors(self): - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" class Foo(object): attr = 42 def __new__(cls): - return name_error + return name_error # name-error def __init__(self): - self.attribute_error + self.attribute_error # attribute-error self.instance_attr = self.attr def f(self): return self.instance_attr @@ -930,10 +929,9 @@ class Foo(object): def __new__(cls) -> Any: ... def f(self) -> int: ... """) - self.assertErrorLogIs(errors, [(4, "name-error"), (6, "attribute-error")]) def testNewFalse(self): - ty = self.Infer("""\ + ty = self.Infer(""" class Foo(object): def __new__(cls): return False @@ -950,7 +948,7 @@ def f(self) -> str: ... """) def testNewAmbiguous(self): - ty = self.Infer("""\ + ty = self.Infer(""" class Foo(object): def __new__(cls): if __random__: @@ -1029,34 +1027,34 @@ def __init__(self, a, b): """, pythonpath=[d.path]) def testSuperNewWrongArgCount(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __new__(cls, x): - return super(Foo, cls).__new__(cls, x) + return super(Foo, cls).__new__(cls, x) # wrong-arg-count[e] """, deep=True) - self.assertErrorLogIs(errors, [(3, "wrong-arg-count", "1.*2")]) + self.assertErrorRegexes(errors, {"e": r"1.*2"}) def testSuperInitWrongArgCount(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __init__(self, x): - super(Foo, self).__init__(x) + super(Foo, self).__init__(x) # wrong-arg-count[e] """, deep=True) - self.assertErrorLogIs(errors, [(3, "wrong-arg-count", "1.*2")]) + self.assertErrorRegexes(errors, {"e": r"1.*2"}) def testSuperNewMissingParameter(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __new__(cls, x): # Even when __init__ is defined, too few args is an error. - return super(Foo, cls).__new__() + return super(Foo, cls).__new__() # missing-parameter[e] def __init__(self, x): pass """, deep=True) - self.assertErrorLogIs(errors, [(4, "missing-parameter", r"cls.*__new__")]) + self.assertErrorRegexes(errors, {"e": r"cls.*__new__"}) def testNewKwarg(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __new__(cls): # ok because __init__ is defined. @@ -1065,12 +1063,12 @@ def __init__(self): pass class Bar(object): def __new__(cls): - return super(Bar, cls).__new__(cls, x=42) # bad! + return super(Bar, cls).__new__(cls, x=42) # wrong-keyword-args[e] """, deep=True) - self.assertErrorLogIs(errors, [(9, "wrong-keyword-args", r"x.*__new__")]) + self.assertErrorRegexes(errors, {"e": r"x.*__new__"}) def testInitKwarg(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __init__(self): # ok because __new__ is defined. @@ -1079,9 +1077,9 @@ def __new__(cls): return super(Foo, cls).__new__(cls) class Bar(object): def __init__(self): - super(Bar, self).__init__(x=42) # bad! + super(Bar, self).__init__(x=42) # wrong-keyword-args[e] """, deep=True) - self.assertErrorLogIs(errors, [(9, "wrong-keyword-args", r"x.*__init__")]) + self.assertErrorRegexes(errors, {"e": r"x.*__init__"}) def testAliasInnerClass(self): ty = self.Infer(""" @@ -1115,7 +1113,7 @@ def __new__(cls, x): """, pythonpath=[d.path]) def testInitWithNoParams(self): - self.Check("""\ + self.Check(""" class Foo(object): def __init__(): pass @@ -1130,14 +1128,13 @@ def testInstantiateWithAbstractDict(self): """) def testNotInstantiable(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" class Foo(object): def __new__(cls): assert cls is not Foo, "not instantiable" def foo(self): - name_error + name_error # name-error """) - self.assertErrorLogIs(errors, [(5, "name-error")]) def testMetaclassOnUnknownClass(self): self.Check(""" @@ -1153,7 +1150,7 @@ class Bar(object): """) def testSubclassContainsBase(self): - ty = self.Infer("""\ + ty = self.Infer(""" def get_c(): class C(object): def __init__(self, z): @@ -1168,7 +1165,7 @@ def __init__(self, z): def bar(self, x): pass x = DC(1) """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any class DC(object): a = ... # type: int @@ -1182,7 +1179,7 @@ def get_c() -> type: ... """) def testSubclassMultipleBaseOptions(self): - ty = self.Infer("""\ + ty = self.Infer(""" class A(object): pass def get_base(): class B(object): pass @@ -1190,7 +1187,7 @@ class B(object): pass Base = A if __random__ else get_base() class C(Base): pass """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any, Union def get_base() -> type: ... class A(object): pass @@ -1199,7 +1196,7 @@ class C(Any): pass """) def testSubclassContainsGenericBase(self): - ty = self.Infer("""\ + ty = self.Infer(""" import typing def get_base(): class C(typing.List[str]): @@ -1207,7 +1204,7 @@ def get_len(self): return len(self) return C class DL(get_base()): pass """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import List typing = ... # type: module class DL(List[str]): @@ -1216,7 +1213,7 @@ def get_base() -> type: ... """) def testSubclassOverridesBaseAttributes(self): - ty = self.Infer("""\ + ty = self.Infer(""" def get_base(): class B(object): def __init__(self): @@ -1232,7 +1229,7 @@ def __init__(self): self.c = "world" def bar(self, x): pass """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ def get_base() -> type: ... class C(object): a = ... # type: int @@ -1251,14 +1248,14 @@ def __init__(self): return C class BX(make_base(list)): pass """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ def make_base(x) -> type: ... class BX(list): x = ... # type: int """) def testSubclassBasesOverlap(self): - ty = self.Infer("""\ + ty = self.Infer(""" def make_a(): class A(object): def __init__(self): diff --git a/pytype/tests/test_cmp.py b/pytype/tests/test_cmp.py index ecbc1af20..d096182a3 100644 --- a/pytype/tests/test_cmp.py +++ b/pytype/tests/test_cmp.py @@ -8,9 +8,9 @@ class InTest(test_base.TargetIndependentTest): """Test for "x in y". Also test overloading of this operator.""" def test_concrete(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" def f(x, y): - return x in y + return x in y # unsupported-operands[e] f(1, [1]) f(1, [2]) f("x", "x") @@ -19,8 +19,7 @@ def f(x, y): f("y", object()) """, deep=False, show_library_calls=True) self.assertOnlyHasReturnType(ty.Lookup("f"), self.bool) - self.assertErrorLogIs(errors, [(2, "unsupported-operands", - r"'in'.*object")]) + self.assertErrorRegexes(errors, {"e": r"'in'.*object"}) def test_deep(self): ty = self.Infer(""" @@ -48,23 +47,22 @@ def g() -> bool """) def test_none(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" x = None - if "" in x: - del x[""] + if "" in x: # unsupported-operands[e1] + del x[""] # unsupported-operands[e2] """) - self.assertErrorLogIs(errors, [ - (2, "unsupported-operands", r"'in'.*None"), - (3, "unsupported-operands", r"item deletion.*None")]) + self.assertErrorRegexes( + errors, {"e1": r"'in'.*None", "e2": r"item deletion.*None"}) class NotInTest(test_base.TargetIndependentTest): """Test for "x not in y". Also test overloading of this operator.""" def test_concrete(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" def f(x, y): - return x not in y + return x not in y # unsupported-operands[e] f(1, [1]) f(1, [2]) f("x", "x") @@ -73,8 +71,7 @@ def f(x, y): f("y", object()) """, deep=False, show_library_calls=True) self.assertOnlyHasReturnType(ty.Lookup("f"), self.bool) - self.assertErrorLogIs(errors, [(2, "unsupported-operands", - r"'in'.*object")]) + self.assertErrorRegexes(errors, {"e": r"'in'.*object"}) # "not in" maps to the inverse of __contains__ def test_overloaded(self): @@ -96,14 +93,13 @@ def g() -> bool """) def test_none(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" x = None - if "" not in x: - x[""] = 42 + if "" not in x: # unsupported-operands[e1] + x[""] = 42 # unsupported-operands[e2] """) - self.assertErrorLogIs(errors, [ - (2, "unsupported-operands", r"'in'.*None"), - (3, "unsupported-operands", r"item assignment.*None")]) + self.assertErrorRegexes( + errors, {"e1": r"'in'.*None", "e2": r"item assignment.*None"}) class IsTest(test_base.TargetIndependentTest): diff --git a/pytype/tests/test_compile_to_pyc.py b/pytype/tests/test_compile_to_pyc.py index 93af1f606..8a859e092 100644 --- a/pytype/tests/test_compile_to_pyc.py +++ b/pytype/tests/test_compile_to_pyc.py @@ -5,6 +5,7 @@ class CompileToPycTest(test_base.TargetIndependentTest): + """Tests for compilation to bytecode.""" def testCompilationOfUnicodeSource(self): self.Check("print('←↑→↓')") @@ -14,20 +15,18 @@ def testCompilationOfUnicodeSourceWithEncoding(self): self.Check("#! my/python\n# encoding: utf-8\nprint('←↑→↓')") def testErrorLineNumbersWithEncoding1(self): - errorlog = self.CheckWithErrors("""\ + self.CheckWithErrors(""" # coding: utf-8 def foo(): - return "1".hello + return "1".hello # attribute-error """) - self.assertErrorLogIs(errorlog, [(3, "attribute-error")]) def testErrorLineNumbersWithEncoding2(self): - errorlog = self.CheckWithErrors("""\ + self.CheckWithErrors(""" #! /bin/python # coding: utf-8 def foo(): - return "1".hello + return "1".hello # attribute-error """) - self.assertErrorLogIs(errorlog, [(4, "attribute-error")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_containers.py b/pytype/tests/test_containers.py index 0b3dc9f30..48ac24bfb 100644 --- a/pytype/tests/test_containers.py +++ b/pytype/tests/test_containers.py @@ -548,7 +548,7 @@ def testDict(self): mymap = {'a': 3.14, 'b':1} a = mymap['a'] b1 = mymap['b'] - c = mymap['foobar'] + c = mymap['foobar'] # key-error[e] mymap[str()] = 3j b2 = mymap['b'] """, deep=True) @@ -560,9 +560,7 @@ def testDict(self): c = ... # type: Any b2 = ... # type: Union[int, float, complex] """) - self.assertErrorLogIs(errors, [ - (5, "key-error", "foobar") - ]) + self.assertErrorRegexes(errors, {"e": r"foobar"}) def testDictOrAny(self): self.Check(""" @@ -575,11 +573,11 @@ def testDictOrAny(self): """) def testDictGetItem(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" v = {} - v.__getitem__("a") + v.__getitem__("a") # key-error[e] """) - self.assertErrorLogIs(errors, [(2, "key-error", r"'a'")]) + self.assertErrorRegexes(errors, {"e": r"'a'"}) def testEmptyList(self): ty = self.Infer(""" diff --git a/pytype/tests/test_decorators.py b/pytype/tests/test_decorators.py index dd914c264..24336086f 100644 --- a/pytype/tests/test_decorators.py +++ b/pytype/tests/test_decorators.py @@ -82,15 +82,15 @@ class Foo(object): """) def testBadKeyword(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __init__(self): self._bar = 1 def _SetBar(self, value): self._bar = value - bar = property(should_fail=_SetBar) + bar = property(should_fail=_SetBar) # wrong-keyword-args[e] """) - self.assertErrorLogIs(errors, [(6, "wrong-keyword-args", r"should_fail")]) + self.assertErrorRegexes(errors, {"e": r"should_fail"}) def testFgetIsOptional(self): self.Check(""" @@ -296,35 +296,35 @@ def bar(cls): """) def testInstanceAsDecoratorError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Decorate(object): def __call__(self, func): return func class Foo(object): @classmethod - @Decorate # forgot to instantiate Decorate + @Decorate # forgot to instantiate Decorate # wrong-arg-count[e] def bar(cls): pass Foo.bar() """) - self.assertErrorLogIs(errors, [(6, "wrong-arg-count", r"Decorate.*1.*2")]) + self.assertErrorRegexes(errors, {"e": r"Decorate.*1.*2"}) def testUncallableInstanceAsDecorator(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Decorate(object): pass # forgot to define __call__ class Foo(object): @classmethod - @Decorate # forgot to instantiate Decorate + @Decorate # forgot to instantiate Decorate # wrong-arg-count[e1] def bar(cls): pass - Foo.bar() + Foo.bar() # not-callable[e2] """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-count", r"Decorate.*1.*2"), - (8, "not-callable", r"Decorate")]) + self.assertErrorRegexes( + errors, {"e1": r"Decorate.*1.*2", "e2": r"Decorate"}) def testAmbiguousClassMethod(self): - self.Check("""\ + self.Check(""" class Foo(): def __init__(self): pass diff --git a/pytype/tests/test_dict.py b/pytype/tests/test_dict.py index 2a9a543c2..fc80b21d4 100644 --- a/pytype/tests/test_dict.py +++ b/pytype/tests/test_dict.py @@ -22,16 +22,16 @@ def testPop(self): """) def testBadPop(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" d = {"a": 42} - v = d.pop("b") + v = d.pop("b") # key-error[e] """) self.assertTypesMatchPytd(ty, """ from typing import Any, Dict d = ... # type: Dict[str, int] v = ... # type: Any """) - self.assertErrorLogIs(errors, [(2, "key-error", r"b")]) + self.assertErrorRegexes(errors, {"e": r"b"}) def testAmbiguousPop(self): ty = self.Infer(""" diff --git a/pytype/tests/test_disables.py b/pytype/tests/test_disables.py index b7d80f846..a9e5fbdad 100644 --- a/pytype/tests/test_disables.py +++ b/pytype/tests/test_disables.py @@ -7,35 +7,32 @@ class DisableTest(test_base.TargetIndependentTest): """Test error disabling.""" def testInvalidDirective(self): - _, errors = self.InferWithErrors("""\ - x = 1 # pytype: this is not a valid pytype directive. + _, errors = self.InferWithErrors(""" + x = 1 # pytype: this is not a valid pytype directive. # invalid-directive """) - self.assertErrorLogIs(errors, [(1, "invalid-directive")]) # Invalid directives are just a warning, so has_error() should still # return False. self.assertFalse(errors.has_error()) def testInvalidDisableErrorName(self): - _, errors = self.InferWithErrors("""\ - x = 1 # pytype: disable=not-an-error. + _, errors = self.InferWithErrors(""" + x = 1 # pytype: disable=not-an-error. # invalid-directive[e] """) - self.assertErrorLogIs(errors, [(1, "invalid-directive", - r"Invalid error name.*not-an-error")]) + self.assertErrorRegexes(errors, {"e": r"Invalid error name.*not-an-error"}) # Invalid directives are just a warning, so has_error() should still # return False. self.assertFalse(errors.has_error()) def testDisableError(self): - _, errors = self.InferWithErrors("""\ - x = a + self.InferWithErrors(""" + x = a # name-error x = b # pytype: disable=name-error - x = c + x = c # name-error """) - self.assertErrorLogIs(errors, [(1, "name-error"), (3, "name-error")]) def testOpenEndedDirective(self): """Test that disables in the middle of the file can't be left open-ended.""" - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" '''This is a docstring. def f(x): pass @@ -47,21 +44,21 @@ class A(object): CONSTANT = 42 # pytype: disable=not-callable # ok (before first class/function def) def f(x): - # type: ignore # bad + # type: ignore # late-directive[e1] pass def g(): pass x = y # pytype: disable=name-error # ok (single line) # pytype: disable=attribute-error # ok (re-enabled) - # pytype: disable=wrong-arg-types # bad + # pytype: disable=wrong-arg-types # late-directive[e2] # pytype: enable=attribute-error """) - self.assertErrorLogIs(errors, [(12, "late-directive", "Type checking"), - (17, "late-directive", "wrong-arg-types")]) + self.assertErrorRegexes( + errors, {"e1": r"Type checking", "e2": r"wrong-arg-types"}) # late-directive is a warning self.assertFalse(errors.has_error()) def testSkipFile(self): - self.Check("""\ + self.Check(""" # pytype: skip-file name_error """) diff --git a/pytype/tests/test_errors.py b/pytype/tests/test_errors.py index 886e101f9..89358322b 100644 --- a/pytype/tests/test_errors.py +++ b/pytype/tests/test_errors.py @@ -8,28 +8,28 @@ class ErrorTest(test_base.TargetIndependentTest): """Tests for errors.""" def testDeduplicate(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x): y = 42 - y.foobar + y.foobar # attribute-error[e] f(3) f(4) """) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"'foobar' on int$")]) + self.assertErrorRegexes(errors, {"e": r"'foobar' on int$"}) def testUnknownGlobal(self): _, errors = self.InferWithErrors(""" def f(): - return foobar() + return foobar() # name-error[e] """) - self.assertErrorLogIs(errors, [(3, "name-error", r"foobar")]) + self.assertErrorRegexes(errors, {"e": r"foobar"}) def testInvalidAttribute(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" class A(object): pass def f(): - (3).parrot + (3).parrot # attribute-error[e] return "foo" """) self.assertTypesMatchPytd(ty, """ @@ -38,116 +38,97 @@ class A(object): def f() -> str """) - self.assertErrorLogIs(errors, [(4, "attribute-error", r"parrot.*int")]) + self.assertErrorRegexes(errors, {"e": r"parrot.*int"}) def testImportError(self): - _, errors = self.InferWithErrors("""\ - import rumplestiltskin + self.InferWithErrors(""" + import rumplestiltskin # import-error """) - self.assertErrorLogIs(errors, [(1, "import-error", r"rumplestiltskin")]) def testImportFromError(self): - _, errors = self.InferWithErrors("""\ - from sys import foobar + _, errors = self.InferWithErrors(""" + from sys import foobar # import-error[e] """) - self.assertErrorLogIs(errors, [(1, "import-error", r"sys\.foobar")]) + self.assertErrorRegexes(errors, {"e": r"sys\.foobar"}) def testNameError(self): - _, errors = self.InferWithErrors("""\ - foobar + self.InferWithErrors(""" + foobar # name-error """) - self.assertErrorLogIs(errors, [(1, "name-error", r"foobar")]) def testWrongArgCount(self): - _, errors = self.InferWithErrors("""\ - hex(1, 2, 3, 4) + _, errors = self.InferWithErrors(""" + hex(1, 2, 3, 4) # wrong-arg-count[e] """) - self.assertErrorLogIs(errors, [(1, "wrong-arg-count", r"expects 1.*got 4")]) + self.assertErrorRegexes(errors, {"e": r"expects 1.*got 4"}) def testWrongArgTypes(self): - _, errors = self.InferWithErrors("""\ - hex(3j) + _, errors = self.InferWithErrors(""" + hex(3j) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", r"int.*complex")]) + self.assertErrorRegexes(errors, {"e": r"int.*complex"}) def testInterpreterFunctionNameInMsg(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(list): pass - A.append(3) + A.append(3) # missing-parameter[e] """) - self.assertErrorLogIs( - errors, - [(2, "missing-parameter", r"function list.append")] - ) + self.assertErrorRegexes(errors, {"e": r"function list\.append"}) def testPyTDFunctionNameInMsg(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", "class A(list): pass") - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.A.append(3) + foo.A.append(3) # missing-parameter[e] """, pythonpath=[d.path]) - self.assertErrorLogIs( - errors, - [(2, "missing-parameter", r"function list.append")] - ) + self.assertErrorRegexes(errors, {"e": r"function list\.append"}) def testBuiltinFunctionNameInMsg(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" x = list - x += (1,2) + x += (1,2) # missing-parameter[e] """) - self.assertErrorLogIs( - errors, - [(2, "missing-parameter", r"function list.__iadd__")] - ) + self.assertErrorRegexes(errors, {"e": r"function list\.__iadd__"}) def testRewriteBuiltinFunctionName(self): """Should rewrite `function __builtin__.len` to `built-in function len`.""" - _, errors = self.InferWithErrors("x = len(None)") - self.assertErrorLogIs( - errors, - [(1, "wrong-arg-types", r"Built-in function len")] - ) + _, errors = self.InferWithErrors("x = len(None) # wrong-arg-types[e]") + self.assertErrorRegexes(errors, {"e": r"Built-in function len"}) def testBoundMethodNameInMsg(self): - _, errors = self.InferWithErrors("""\ - "".join(1) + _, errors = self.InferWithErrors(""" + "".join(1) # wrong-arg-types[e] """) - self.assertErrorLogIs( - errors, - [(1, "wrong-arg-types", r"Function str.join")] - ) + self.assertErrorRegexes(errors, {"e": r"Function str\.join"}) def testNestedClassMethodNameIsMsg(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class A(object): class B(object): def f(self): pass - A.B().f("oops") + A.B().f("oops") # wrong-arg-count[e] """) - self.assertErrorLogIs(errors, [(5, "wrong-arg-count", r"Function B.f")]) + self.assertErrorRegexes(errors, {"e": r"Function B.f"}) def testPrettyPrintWrongArgs(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ def f(a: int, b: int, c: int, d: int, e: int): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.f(1, 2, 3, "four", 5) + foo.f(1, 2, 3, "four", 5) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (2, "wrong-arg-types", ("a, b, c, d: int, [.][.][.].*" - "a, b, c, d: str, [.][.][.]"))]) + self.assertErrorRegexes(errors, { + "e": r"a, b, c, d: int, [.][.][.].*a, b, c, d: str, [.][.][.]"}) def testInvalidBaseClass(self): - _, errors = self.InferWithErrors("""\ - class Foo(3): + self.InferWithErrors(""" + class Foo(3): # base-class-error pass """) - self.assertErrorLogIs(errors, [(1, "base-class-error")]) def testInvalidIteratorFromImport(self): with file_utils.Tempdir() as d: @@ -158,30 +139,29 @@ def __init__(self) -> None: ... _, errors = self.InferWithErrors(""" import mod def f(): - for row in mod.Codec(): + for row in mod.Codec(): # attribute-error[e] pass """, pythonpath=[d.path]) error = r"No attribute.*__iter__.*on mod\.Codec" - self.assertErrorLogIs(errors, [(4, "attribute-error", error)]) + self.assertErrorRegexes(errors, {"e": error}) def testInvalidIteratorFromClass(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): pass def f(): - for row in A(): + for row in A(): # attribute-error[e] pass """) - self.assertErrorLogIs(errors, [(4, "attribute-error", r"__iter__.*A")]) + self.assertErrorRegexes(errors, {"e": r"__iter__.*A"}) def testIterOnModule(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import sys - for _ in sys: + for _ in sys: # module-attr[e] pass """) - self.assertErrorLogIs( - errors, [(2, "module-attr", r"__iter__.*module 'sys'")]) + self.assertErrorRegexes(errors, {"e": r"__iter__.*module 'sys'"}) def testInheritFromGeneric(self): with file_utils.Tempdir() as d: @@ -191,157 +171,149 @@ def testInheritFromGeneric(self): class Foo(Generic[T]): ... class Bar(Foo[int]): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import mod - chr(mod.Bar()) + chr(mod.Bar()) # wrong-arg-types[e] """, pythonpath=[d.path]) # "Line 3, in f: Can't retrieve item out of dict. Empty?" - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", r"int.*mod\.Bar")]) + self.assertErrorRegexes(errors, {"e": r"int.*mod\.Bar"}) def testWrongKeywordArg(self): with file_utils.Tempdir() as d: d.create_file("mycgi.pyi", """ def escape(x: str or int) -> str or int """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import mycgi def foo(s): - return mycgi.escape(s, quote=1) + return mycgi.escape(s, quote=1) # wrong-keyword-args[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(3, "wrong-keyword-args", - r"quote.*mycgi\.escape")]) + self.assertErrorRegexes(errors, {"e": r"quote.*mycgi\.escape"}) def testMissingParameter(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ def bar(xray, yankee, zulu) -> str """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.bar(1, 2) + foo.bar(1, 2) # missing-parameter[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "missing-parameter", - r"zulu.*foo\.bar")]) + self.assertErrorRegexes(errors, {"e": r"zulu.*foo\.bar"}) def testBadInheritance(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" class X: pass class Bar(X): pass - class Baz(X, Bar): + class Baz(X, Bar): # mro-error pass """) - self.assertErrorLogIs(errors, [(5, "mro-error")]) def testBadCall(self): with file_utils.Tempdir() as d: d.create_file("other.pyi", """ def foo(x: int, y: str) -> str: ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import other - other.foo(1.2, []) + other.foo(1.2, []) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (2, "wrong-arg-types", r"\(x: int")]) + self.assertErrorRegexes(errors, {"e": r"\(x: int"}) def testCallUncallable(self): - _, errors = self.InferWithErrors("""\ - 0() + _, errors = self.InferWithErrors(""" + 0() # not-callable[e] """) - self.assertErrorLogIs(errors, [(1, "not-callable", r"int")]) + self.assertErrorRegexes(errors, {"e": r"int"}) def testSuperError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): def __init__(self): - super(A, self, "foo").__init__() + super(A, self, "foo").__init__() # wrong-arg-count[e] """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-count", "2.*3")]) + self.assertErrorRegexes(errors, {"e": r"2.*3"}) def testAttributeError(self): with file_utils.Tempdir() as d: d.create_file("modfoo.pyi", "") - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __getattr__(self, name): return "attr" def f(): - return Foo.foo # line 5 + return Foo.foo # attribute-error[e1] def g(x): if x: y = None else: y = 1 - return y.bar # line 11 + return y.bar # attribute-error[e2] # attribute-error[e3] def h(): return Foo().foo # No error import modfoo - modfoo.baz # line 15 + modfoo.baz # module-attr[e4] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (5, "attribute-error", r"No attribute 'foo' on Type\[Foo\]"), - (11, "attribute-error", - r"No attribute 'bar' on None\nIn Optional\[int\]"), - (11, "attribute-error", - r"No attribute 'bar' on int\nIn Optional\[int\]"), - (15, "module-attr", - "No attribute 'baz' on module 'modfoo'")]) + self.assertErrorRegexes(errors, { + "e1": r"No attribute 'foo' on Type\[Foo\]", + "e2": r"No attribute 'bar' on int\nIn Optional\[int\]", + "e3": r"No attribute 'bar' on None\nIn Optional\[int\]", + "e4": r"No attribute 'baz' on module 'modfoo'"}) def testAttributeErrorGetAttribute(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __getattribute__(self, name): return "attr" def f(): return Foo().x # There should be no error on this line. def g(): - return Foo.x + return Foo.x # attribute-error[e] """) - self.assertErrorLogIs(errors, [(7, "attribute-error", r"x")]) + self.assertErrorRegexes(errors, {"e": r"x"}) def testNoneAttribute(self): - _, errors = self.InferWithErrors("""\ - None.foo + _, errors = self.InferWithErrors(""" + None.foo # attribute-error[e] """) - self.assertErrorLogIs(errors, [(1, "attribute-error", r"foo")]) + self.assertErrorRegexes(errors, {"e": r"foo"}) def testPyiType(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ def f(x: list[int]) -> int: ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.f([""]) + foo.f([""]) # wrong-arg-types[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", - r"List\[int\].*List\[str\]")]) + self.assertErrorRegexes(errors, {"e": r"List\[int\].*List\[str\]"}) def testTooManyArgs(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(): pass - f(3) + f(3) # wrong-arg-count[e] """, deep=True) - self.assertErrorLogIs(errors, [(3, "wrong-arg-count", r"0.*1")]) + self.assertErrorRegexes(errors, {"e": r"0.*1"}) def testTooFewArgs(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x): pass - f() + f() # missing-parameter[e] """, deep=True) - self.assertErrorLogIs(errors, [(3, "missing-parameter", r"x.*f")]) + self.assertErrorRegexes(errors, {"e": r"x.*f"}) def testDuplicateKeyword(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x, y): pass - f(3, x=3) + f(3, x=3) # duplicate-keyword-argument[e] """, deep=True) - self.assertErrorLogIs(errors, [(3, "duplicate-keyword-argument", r"f.*x")]) + self.assertErrorRegexes(errors, {"e": r"f.*x"}) def testBadImport(self): with file_utils.Tempdir() as d: @@ -349,10 +321,9 @@ def testBadImport(self): def f() -> int: ... class f: ... """) - _, errors = self.InferWithErrors("""\ - import a + self.InferWithErrors(""" + import a # pyi-error """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error")]) def testBadImportDependency(self): with file_utils.Tempdir() as d: @@ -360,10 +331,9 @@ def testBadImportDependency(self): from b import X class Y(X): ... """) - _, errors = self.InferWithErrors("""\ - import a + self.InferWithErrors(""" + import a # pyi-error """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error")]) def testBadImportFrom(self): with file_utils.Tempdir() as d: @@ -372,10 +342,10 @@ def f() -> int: ... class f: ... """) d.create_file("foo/__init__.pyi", "") - _, errors = self.InferWithErrors("""\ - from foo import a + _, errors = self.InferWithErrors(""" + from foo import a # pyi-error[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"foo\.a")]) + self.assertErrorRegexes(errors, {"e": r"foo\.a"}) def testBadImportFromDependency(self): with file_utils.Tempdir() as d: @@ -384,10 +354,10 @@ def testBadImportFromDependency(self): class Y(X): ... """) d.create_file("foo/__init__.pyi", "") - _, errors = self.InferWithErrors("""\ - from foo import a + _, errors = self.InferWithErrors(""" + from foo import a # pyi-error[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"foo\.a")]) + self.assertErrorRegexes(errors, {"e": r"foo\.a"}) def testBadContainer(self): with file_utils.Tempdir() as d: @@ -395,11 +365,10 @@ def testBadContainer(self): from typing import SupportsInt class A(SupportsInt[int]): pass """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", - r"SupportsInt is not a container")]) + self.assertErrorRegexes(errors, {"e": r"SupportsInt is not a container"}) def testBadTypeParameterOrder(self): with file_utils.Tempdir() as d: @@ -411,10 +380,10 @@ class A(Generic[K, V]): pass class B(Generic[K, V]): pass class C(A[K, V], B[V, K]): pass """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"Illegal.*order.*a\.C")]) + self.assertErrorRegexes(errors, {"e": r"Illegal.*order.*a\.C"}) def testDuplicateTypeParameter(self): with file_utils.Tempdir() as d: @@ -423,10 +392,10 @@ def testDuplicateTypeParameter(self): T = TypeVar("T") class A(Generic[T, T]): pass """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"T")]) + self.assertErrorRegexes(errors, {"e": r"T"}) def testDuplicateGenericBaseClass(self): with file_utils.Tempdir() as d: @@ -436,10 +405,10 @@ def testDuplicateGenericBaseClass(self): V = TypeVar("V") class A(Generic[T], Generic[V]): pass """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"inherit.*Generic")]) + self.assertErrorRegexes(errors, {"e": r"inherit.*Generic"}) def testTypeParameterInModuleConstant(self): with file_utils.Tempdir() as d: @@ -448,10 +417,10 @@ def testTypeParameterInModuleConstant(self): T = TypeVar("T") x = ... # type: T """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"a.*T.*a\.x")]) + self.assertErrorRegexes(errors, {"e": r"a.*T.*a\.x"}) def testTypeParameterInClassAttribute(self): with file_utils.Tempdir() as d: @@ -461,12 +430,12 @@ def testTypeParameterInClassAttribute(self): class A(Generic[T]): x = ... # type: T """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import a def f(): - return a.A.x + return a.A.x # unbound-type-param[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(3, "unbound-type-param", r"x.*A.*T")]) + self.assertErrorRegexes(errors, {"e": r"x.*A.*T"}) def testUnboundTypeParameterInInstanceAttribute(self): with file_utils.Tempdir() as d: @@ -476,47 +445,45 @@ def testUnboundTypeParameterInInstanceAttribute(self): class A(object): x = ... # type: T """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"a.*T.*a\.A\.x")]) + self.assertErrorRegexes(errors, {"e": r"a.*T.*a\.A\.x"}) def testPrintUnionArg(self): with file_utils.Tempdir() as d: d.create_file("a.pyi", """ def f(x: int or str) -> None """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import a - x = a.f(4.2) + x = a.f(4.2) # wrong-arg-types[e] """, deep=True, pythonpath=[d.path]) pattern = r"Expected.*Union\[int, str\].*Actually passed" - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", pattern)]) + self.assertErrorRegexes(errors, {"e": pattern}) def testPrintTypeArg(self): - _, errors = self.InferWithErrors("""\ - hex(int) + _, errors = self.InferWithErrors(""" + hex(int) # wrong-arg-types[e] """, deep=True) - self.assertErrorLogIs( - errors, [(1, "wrong-arg-types", r"Actually passed.*Type\[int\]")]) + self.assertErrorRegexes(errors, {"e": r"Actually passed.*Type\[int\]"}) def testDeleteFromSet(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" s = {1} - del s[1] + del s[1] # unsupported-operands[e] """, deep=True) - self.assertErrorLogIs( - errors, [(2, "unsupported-operands", r"item deletion")]) + self.assertErrorRegexes(errors, {"e": r"item deletion"}) def testBadReference(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" def main(): - x = foo + x = foo # name-error[e] for foo in []: pass return x """, deep=True) - self.assertErrorLogIs(errors, [(2, "name-error", r"foo")]) + self.assertErrorRegexes(errors, {"e": r"foo"}) # Make sure we recovered from the error and got the right return type self.assertTypesMatchPytd(ty, """ from typing import Any @@ -524,11 +491,11 @@ def main() -> Any """) def testSetIntAttribute(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" x = 42 - x.y = 42 + x.y = 42 # not-writable[e] """, deep=True) - self.assertErrorLogIs(errors, [(2, "not-writable", r"y.*int")]) + self.assertErrorRegexes(errors, {"e": r"y.*int"}) def testInvalidParametersOnMethod(self): with file_utils.Tempdir() as d: @@ -536,81 +503,68 @@ def testInvalidParametersOnMethod(self): class A(object): def __init__(self, x: int) -> None """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import a - x = a.A("") - x = a.A("", 42) - x = a.A(42, y="") - x = a.A(42, x=42) - x = a.A() + x = a.A("") # wrong-arg-types[e1] + x = a.A("", 42) # wrong-arg-count[e2] + x = a.A(42, y="") # wrong-keyword-args[e3] + x = a.A(42, x=42) # duplicate-keyword-argument[e4] + x = a.A() # missing-parameter[e5] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", r"A\.__init__"), - (3, "wrong-arg-count", r"A\.__init__"), - (4, "wrong-keyword-args", r"A\.__init__"), - (5, "duplicate-keyword-argument", - r"A\.__init__"), - (6, "missing-parameter", r"A\.__init__")]) + self.assertErrorRegexes(errors, { + "e1": r"A\.__init__", "e2": r"A\.__init__", "e3": r"A\.__init__", + "e4": r"A\.__init__", "e5": r"A\.__init__"}) def testDuplicateKeywords(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ def f(x, *args, y) -> None """) - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" import foo foo.f(1, y=2) foo.f(1, 2, y=3) - foo.f(1, x=1) + foo.f(1, x=1) # duplicate-keyword-argument # foo.f(y=1, y=2) # caught by compiler """, deep=True, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (4, "duplicate-keyword-argument"), - ]) def testInvalidParametersDetails(self): - _, errors = self.InferWithErrors("""\ - float(list()) - float(1, list(), foobar=str) - float(1, foobar=list()) - float(1, x="") - hex() + _, errors = self.InferWithErrors(""" + float(list()) # wrong-arg-types[e1] + float(1, list(), foobar=str) # wrong-arg-count[e2] + float(1, foobar=list()) # wrong-keyword-args[e3] + float(1, x="") # duplicate-keyword-argument[e4] + hex() # missing-parameter[e5] """) - self.assertErrorLogIs(errors, [ - (1, "wrong-arg-types", - r"Actually passed:.*self, x: List\[nothing\]"), - (2, "wrong-arg-count", r"Actually passed:.*self, x, " - r"_, foobar"), - (3, "wrong-keyword-args", - r"Actually passed:.*self, x, foobar"), - (4, "duplicate-keyword-argument", - r"Actually passed:.*self, x, x"), - (5, "missing-parameter", r"Actually passed: \(\)") - ]) + self.assertErrorRegexes(errors, { + "e1": r"Actually passed:.*self, x: List\[nothing\]", + "e2": r"_, foobar", "e3": r"Actually passed:.*self, x, foobar", + "e4": r"Actually passed:.*self, x, x", "e5": r"Actually passed: \(\)", + }) def testBadSuperClass(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): def f(self): return "foo" class B(A): def f(self): - return super(self, B).f() # should be super(B, self) + return super(self, B).f() # should be super(B, self) # wrong-arg-types[e] """, deep=True) - self.assertErrorLogIs(errors, [ - (7, "wrong-arg-types", r"cls: type.*cls: B")]) + self.assertErrorRegexes(errors, {"e": r"cls: type.*cls: B"}) @test_base.skip("Need to type-check second argument to super") def testBadSuperInstance(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): pass class B(A): def __init__(self): - super(B, A).__init__() # A cannot be the second argument to super + super(B, A).__init__() # A cannot be the second argument to super # wrong-arg-types[e] """, deep=True) - self.assertErrorLogIs( - errors, [(5, "wrong-arg-types", r"Type\[B\].*Type\[A\]")]) + self.assertErrorRegexes( + errors, {"e": r"Type\[B\].*Type\[A\]"}) def testBadNameImport(self): with file_utils.Tempdir() as d: @@ -618,11 +572,11 @@ def testBadNameImport(self): import typing x = ... # type: typing.Rumpelstiltskin """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] x = a.x """, pythonpath=[d.path], deep=True) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"Rumpelstiltskin")]) + self.assertErrorRegexes(errors, {"e": r"Rumpelstiltskin"}) def testBadNameImportFrom(self): with file_utils.Tempdir() as d: @@ -630,11 +584,11 @@ def testBadNameImportFrom(self): from typing import Rumpelstiltskin x = ... # type: Rumpelstiltskin """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] x = a.x """, pythonpath=[d.path], deep=True) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"Rumpelstiltskin")]) + self.assertErrorRegexes(errors, {"e": r"Rumpelstiltskin"}) def testMatchType(self): with file_utils.Tempdir() as d: @@ -645,14 +599,14 @@ class B(A): ... class C(object): ... def f(x: Type[A]) -> bool """) - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" import a x = a.f(a.A) y = a.f(a.B) - z = a.f(a.C) + z = a.f(a.C) # wrong-arg-types[e] """, pythonpath=[d.path], deep=True) error = r"Expected.*Type\[a\.A\].*Actual.*Type\[a\.C\]" - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", error)]) + self.assertErrorRegexes(errors, {"e": error}) self.assertTypesMatchPytd(ty, """ from typing import Any a = ... # type: module @@ -670,12 +624,12 @@ class A(Generic[T]): ... class B(A[str]): ... def f(x: Type[A[int]]): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import a - x = a.f(a.B) + x = a.f(a.B) # wrong-arg-types[e] """, pythonpath=[d.path], deep=True) expected_error = r"Expected.*Type\[a\.A\[int\]\].*Actual.*Type\[a\.B\]" - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", expected_error)]) + self.assertErrorRegexes(errors, {"e": expected_error}) def testMROError(self): with file_utils.Tempdir() as d: @@ -686,23 +640,23 @@ class C(A, B): ... class D(B, A): ... class E(C, D): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import a - x = a.E() + x = a.E() # mro-error[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "mro-error", r"E")]) + self.assertErrorRegexes(errors, {"e": r"E"}) def testBadMRO(self): with file_utils.Tempdir() as d: d.create_file("a.pyi", """ class A(BaseException, ValueError): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import a - class B(a.A): pass + class B(a.A): pass # mro-error[e] raise a.A() """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "mro-error", r"A")]) + self.assertErrorRegexes(errors, {"e": r"A"}) def testUnsolvableAsMetaclass(self): with file_utils.Tempdir() as d: @@ -714,18 +668,18 @@ def __getattr__(name) -> Any from a import A class B(metaclass=A): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import b class C(b.B): def __init__(self): - f = open(self.x, 'r') + f = open(self.x, 'r') # attribute-error[e] """, pythonpath=[d.path], deep=True) - self.assertErrorLogIs(errors, [(4, "attribute-error", r"x.*C")]) + self.assertErrorRegexes(errors, {"e": r"x.*C"}) def testDontTimeoutOnComplex(self): # Tests that we can solve a complex file without timing out. # Useful for catching large performance regressions. - ty = self.Infer("""\ + ty = self.Infer(""" if __random__: x = [1] else: @@ -749,12 +703,10 @@ def testFailedFunctionCall(self): def f(x: str, y: int) -> bool def f(x: str) -> bool """) - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" import a - x = a.f(0, "") + x = a.f(0, "") # wrong-arg-types """, pythonpath=[d.path]) - # Tests that [wrong-arg-types] rather than [wrong-arg-count] is reported - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", r"")]) def testNoncomputableMethod(self): with file_utils.Tempdir() as d: @@ -762,41 +714,39 @@ def testNoncomputableMethod(self): T = TypeVar("T") def copy(x: T) -> T """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import a class A(object): def __getattribute__(self, name): return a.copy(self) - x = A()() + x = A()() # not-callable[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(5, "not-callable", r"A")]) + self.assertErrorRegexes(errors, {"e": r"A"}) def testBadTypeName(self): - _, errors = self.InferWithErrors("""\ - X = type(3, (int, object), {"a": 1}) + _, errors = self.InferWithErrors(""" + X = type(3, (int, object), {"a": 1}) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", r"Actual.*int")]) + self.assertErrorRegexes(errors, {"e": r"Actual.*int"}) def testBadTypeBases(self): - _, errors = self.InferWithErrors("""\ - X = type("X", (42,), {"a": 1}) + _, errors = self.InferWithErrors(""" + X = type("X", (42,), {"a": 1}) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", - r"Actual.*Tuple\[int\]")]) + self.assertErrorRegexes(errors, {"e": r"Actual.*Tuple\[int\]"}) def testHalfBadTypeBases(self): - _, errors = self.InferWithErrors("""\ - X = type("X", (42, object), {"a": 1}) + _, errors = self.InferWithErrors(""" + X = type("X", (42, object), {"a": 1}) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", - r"Actual.*Tuple\[int, Type\[object\]\]")]) + self.assertErrorRegexes( + errors, {"e": r"Actual.*Tuple\[int, Type\[object\]\]"}) def testBadTypeMembers(self): - _, errors = self.InferWithErrors("""\ - X = type("X", (int, object), {0: 1}) + _, errors = self.InferWithErrors(""" + X = type("X", (int, object), {0: 1}) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", - r"Actual.*Dict\[int, int\]")]) + self.assertErrorRegexes(errors, {"e": r"Actual.*Dict\[int, int\]"}) def testRecursion(self): with file_utils.Tempdir() as d: @@ -804,9 +754,9 @@ def testRecursion(self): class A(B): ... class B(A): ... """) - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" import a - v = a.A() + v = a.A() # recursion-error[e] x = v.x # No error because there is an Unsolvable in the MRO of a.A """, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ @@ -815,30 +765,29 @@ class B(A): ... v = ... # type: a.A x = ... # type: Any """) - self.assertErrorLogIs(errors, [(2, "recursion-error", r"a\.A")]) + self.assertErrorRegexes(errors, {"e": r"a\.A"}) def testEmptyUnionOrOptional(self): with file_utils.Tempdir() as d: - d.create_file("f1.pyi", """\ + d.create_file("f1.pyi", """ def f(x: Union): ... """) - d.create_file("f2.pyi", """\ + d.create_file("f2.pyi", """ def f(x: Optional): ... """) - _, errors = self.InferWithErrors("""\ - import f1 - import f2 + _, errors = self.InferWithErrors(""" + import f1 # pyi-error[e1] + import f2 # pyi-error[e2] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"f1.*Union"), - (2, "pyi-error", r"f2.*Optional")]) + self.assertErrorRegexes( + errors, {"e1": r"f1.*Union", "e2": r"f2.*Optional"}) def testBadDictAttribute(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" x = {"a": 1} - y = x.a + y = x.a # attribute-error[e] """) - self.assertErrorLogIs(errors, [(2, "attribute-error", - r"a.*Dict\[str, int\]")]) + self.assertErrorRegexes(errors, {"e": r"a.*Dict\[str, int\]"}) def testBadPyiDict(self): with file_utils.Tempdir() as d: @@ -846,61 +795,56 @@ def testBadPyiDict(self): from typing import Dict x = ... # type: Dict[str, int, float] """) - _, errors = self.InferWithErrors("""\ - import a + _, errors = self.InferWithErrors(""" + import a # pyi-error[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"2.*3")]) + self.assertErrorRegexes(errors, {"e": r"2.*3"}) def testCallNone(self): - _, errors = self.InferWithErrors("""\ - None() + self.InferWithErrors(""" + None() # not-callable """) - self.assertErrorLogIs(errors, [(1, "not-callable")]) def testInNone(self): - _, errors = self.InferWithErrors("""\ - 3 in None + self.InferWithErrors(""" + 3 in None # unsupported-operands """) - self.assertErrorLogIs(errors, [(1, "unsupported-operands")]) def testNoAttrError(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" if __random__: y = 42 else: y = "foo" - y.upper + y.upper # attribute-error """) - self.assertErrorLogIs(errors, [(5, "attribute-error")]) def testAttrError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" if __random__: y = 42 else: y = "foo" - y.upper + y.upper # attribute-error[e] """) - self.assertErrorLogIs(errors, [(5, "attribute-error", "upper.*int")]) + self.assertErrorRegexes(errors, {"e": r"upper.*int"}) def testPrintCallableInstance(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import Callable v = None # type: Callable[[int], str] - hex(v) + hex(v) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-types", - r"Actual.*Callable\[\[int\], str\]")]) + self.assertErrorRegexes(errors, {"e": r"Actual.*Callable\[\[int\], str\]"}) def testSameNameAndLine(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x): - return x + 42 + return x + 42 # unsupported-operands[e1] # unsupported-operands[e2] f("hello") f([]) """) - self.assertErrorLogIs(errors, [(2, "unsupported-operands", r"str.*int"), - (2, "unsupported-operands", r"List.*int")]) + self.assertErrorRegexes(errors, {"e1": r"str.*int", "e2": r"List.*int"}) def testKwargOrder(self): with file_utils.Tempdir() as d: @@ -908,32 +852,30 @@ def testKwargOrder(self): def f(*args, y, x, z: int): ... def g(x): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.f(x=1, y=2, z="3") - foo.g(42, v4="the", v3="quick", v2="brown", v1="fox") + foo.f(x=1, y=2, z="3") # wrong-arg-types[e1] + foo.g(42, v4="the", v3="quick", v2="brown", v1="fox") # wrong-keyword-args[e2] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (2, "wrong-arg-types", r"x, y, z.*x, y, z"), - (3, "wrong-keyword-args", r"v1, v2, v3, v4")]) + self.assertErrorRegexes( + errors, {"e1": r"x, y, z.*x, y, z", "e2": r"v1, v2, v3, v4"}) def testBadBaseClass(self): - _, errors = self.InferWithErrors("""\ - class Foo(None): pass - class Bar(None if __random__ else 42): pass + _, errors = self.InferWithErrors(""" + class Foo(None): pass # base-class-error[e1] + class Bar(None if __random__ else 42): pass # base-class-error[e2] """) - self.assertErrorLogIs(errors, [ - (1, "base-class-error", r"Invalid base class: None"), - (2, "base-class-error", r"Optional\[\]")]) + self.assertErrorRegexes(errors, {"e1": r"Invalid base class: None", + "e2": r"Optional\[\]"}) def testCallableInUnsupportedOperands(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x, y=None): pass - f in f + f in f # unsupported-operands[e] """) - self.assertErrorLogIs(errors, [(2, "unsupported-operands", - r"Callable\[\[Any, Any\], Any\].*" - r"Callable\[\[Any, Any\], Any\]")]) + self.assertErrorRegexes( + errors, {"e": (r"Callable\[\[Any, Any\], Any\].*" + r"Callable\[\[Any, Any\], Any\]")}) def testCleanPyiNamedtupleNames(self): with file_utils.Tempdir() as d: @@ -942,201 +884,218 @@ def testCleanPyiNamedtupleNames(self): X = NamedTuple("X", []) def f(x: int): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.f(foo.X()) + foo.f(foo.X()) # wrong-arg-types[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", r"`X`")]) + self.assertErrorRegexes(errors, {"e": r"`X`"}) def testBadAnnotation(self): - _, errors = self.InferWithErrors("""\ - tuple[0] - dict[1, 2] + _, errors = self.InferWithErrors(""" + tuple[0] # not-indexable[e1] + dict[1, 2] # invalid-annotation[e2] # invalid-annotation[e3] class A(object): pass - A[3] + A[3] # not-indexable[e4] """) - self.assertErrorLogIs(errors, [ - (1, "not-indexable", r"class tuple"), - (2, "invalid-annotation", r"1.*Not a type"), - (2, "invalid-annotation", r"2.*Not a type"), - (4, "not-indexable", r"class A"), - ]) + self.assertErrorRegexes(errors, { + "e1": r"class tuple", "e2": r"1.*Not a type", "e3": r"2.*Not a type", + "e4": r"class A"}) def testRevealType(self): - _, errors = self.InferWithErrors("""\ - reveal_type(42 or "foo") + _, errors = self.InferWithErrors(""" + reveal_type(42 or "foo") # reveal-type[e1] class Foo(object): pass - reveal_type(Foo) - reveal_type(Foo()) - reveal_type([1,2,3]) + reveal_type(Foo) # reveal-type[e2] + reveal_type(Foo()) # reveal-type[e3] + reveal_type([1,2,3]) # reveal-type[e4] """) - self.assertErrorLogIs(errors, [ - (1, "reveal-type", r"^Union\[int, str\]$"), - (4, "reveal-type", r"^Type\[Foo\]$"), - (5, "reveal-type", r"^Foo$"), - (6, "reveal-type", r"^List\[int\]$"), - ]) + self.assertErrorRegexes(errors, { + "e1": r"^Union\[int, str\]$", "e2": r"^Type\[Foo\]$", "e3": r"^Foo$", + "e4": r"^List\[int\]$"}) def testNotProtocol(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" a = [] a.append(1) - a = "".join(a) + a = "".join(a) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [( - 3, "wrong-arg-types", r"\(.*List\[int\]\)$")]) # no protocol details + self.assertErrorRegexes( + errors, {"e": r"\(.*List\[int\]\)$"}) # no protocol details def testHiddenError(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" use_option = False def f(): if use_option: - name_error + name_error # name-error """) - self.assertErrorLogIs(errors, [(4, "name-error")]) def testUnknownInError(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(x): y = x if __random__ else None - return y.groups() + return y.groups() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"Optional\[Any\]")]) + self.assertErrorRegexes(errors, {"e": r"Optional\[Any\]"}) class OperationsTest(test_base.TargetIndependentTest): """Test operations.""" def testXor(self): - errors = self.CheckWithErrors("def f(): return 'foo' ^ 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\^.*str.*int.*'__xor__' on str.*'__rxor__' on int")]) + errors = self.CheckWithErrors(""" + def f(): return 'foo' ^ 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\^.*str.*int.*'__xor__' on str.*'__rxor__' on int"}) def testAdd(self): - errors = self.CheckWithErrors("def f(): return 'foo' + 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", r"\+.*str.*int.*__add__ on str.*str")]) + errors = self.CheckWithErrors(""" + def f(): return 'foo' + 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\+.*str.*int.*__add__ on str.*str"}) def testInvert(self): - errors = self.CheckWithErrors("def f(): return ~None") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", r"\~.*None.*'__invert__' on None")]) + errors = self.CheckWithErrors(""" + def f(): return ~None # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, {"e": r"\~.*None.*'__invert__' on None"}) def testSub(self): - errors = self.CheckWithErrors("def f(): return 'foo' - 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\-.*str.*int.*'__sub__' on str.*'__rsub__' on int")]) + errors = self.CheckWithErrors(""" + def f(): return 'foo' - 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\-.*str.*int.*'__sub__' on str.*'__rsub__' on int"}) def testMul(self): - errors = self.CheckWithErrors("def f(): return 'foo' * None") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", r"\*.*str.*None.*__mul__ on str.*int")]) + errors = self.CheckWithErrors(""" + def f(): return 'foo' * None # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\*.*str.*None.*__mul__ on str.*int"}) def testDiv(self): - errors = self.CheckWithErrors("def f(): return 'foo' / 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\/.*str.*int.*'__(true)?div__' on str.*'__r(true)?div__' on int")]) + errors = self.CheckWithErrors(""" + def f(): return 'foo' / 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\/.*str.*int.*'__(true)?div__' on str.*'__r(true)?div__' on int" + }) def testMod(self): - errors = self.CheckWithErrors("def f(): return None % 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", r"\%.*None.*int.*'__mod__' on None")]) + errors = self.CheckWithErrors(""" + def f(): return None % 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, {"e": r"\%.*None.*int.*'__mod__' on None"}) def testLShift(self): - errors = self.CheckWithErrors("def f(): return 3 << None") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\<\<.*int.*None.*__lshift__ on int.*int")]) + errors = self.CheckWithErrors(""" + def f(): return 3 << None # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\<\<.*int.*None.*__lshift__ on int.*int"}) def testRShift(self): - errors = self.CheckWithErrors("def f(): return 3 >> None") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\>\>.*int.*None.*__rshift__ on int.*int")]) + errors = self.CheckWithErrors(""" + def f(): return 3 >> None # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\>\>.*int.*None.*__rshift__ on int.*int"}) def testAnd(self): - errors = self.CheckWithErrors("def f(): return 'foo' & 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\&.*str.*int.*'__and__' on str.*'__rand__' on int")]) + errors = self.CheckWithErrors(""" + def f(): return 'foo' & 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\&.*str.*int.*'__and__' on str.*'__rand__' on int"}) def testOr(self): - errors = self.CheckWithErrors("def f(): return 'foo' | 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\|.*str.*int.*'__or__' on str.*'__ror__' on int")]) + errors = self.CheckWithErrors(""" + def f(): return 'foo' | 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\|.*str.*int.*'__or__' on str.*'__ror__' on int"}) def testFloorDiv(self): - errors = self.CheckWithErrors("def f(): return 3 // 'foo'") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\/\/.*int.*str.*__floordiv__ on int.*int")]) + errors = self.CheckWithErrors(""" + def f(): return 3 // 'foo' # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\/\/.*int.*str.*__floordiv__ on int.*int"}) def testPow(self): - errors = self.CheckWithErrors("def f(): return 3 ** 'foo'") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", r"\*\*.*int.*str.*__pow__ on int.*int")]) + errors = self.CheckWithErrors(""" + def f(): return 3 ** 'foo' # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\*\*.*int.*str.*__pow__ on int.*int"}) def testNeg(self): - errors = self.CheckWithErrors("def f(): return -None") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", r"\-.*None.*'__neg__' on None")]) + errors = self.CheckWithErrors(""" + def f(): return -None # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, {"e": r"\-.*None.*'__neg__' on None"}) def testPos(self): - errors = self.CheckWithErrors("def f(): return +None") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", r"\+.*None.*'__pos__' on None")]) + errors = self.CheckWithErrors(""" + def f(): return +None # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, {"e": r"\+.*None.*'__pos__' on None"}) class InPlaceOperationsTest(test_base.TargetIndependentTest): """Test in-place operations.""" def testIAdd(self): - errors = self.CheckWithErrors("def f(): v = []; v += 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"\+\=.*List.*int.*__iadd__ on List.*Iterable")]) + errors = self.CheckWithErrors(""" + def f(): v = []; v += 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"\+\=.*List.*int.*__iadd__ on List.*Iterable"}) class NoSymbolOperationsTest(test_base.TargetIndependentTest): """Test operations with no native symbol.""" def testGetItem(self): - errors = self.CheckWithErrors("def f(): v = []; return v['foo']") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"item retrieval.*List.*str.*__getitem__ on List.*int")]) + errors = self.CheckWithErrors(""" + def f(): v = []; return v['foo'] # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"item retrieval.*List.*str.*__getitem__ on List.*int"}) def testDelItem(self): - errors = self.CheckWithErrors("def f(): v = {'foo': 3}; del v[3]") + errors = self.CheckWithErrors(""" + def f(): v = {'foo': 3}; del v[3] # unsupported-operands[e] + """) d = r"Dict\[str, int\]" - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"item deletion.*{d}.*int.*__delitem__ on {d}.*str".format(d=d))]) + self.assertErrorRegexes(errors, { + "e": r"item deletion.*{d}.*int.*__delitem__ on {d}.*str".format(d=d)}) def testSetItem(self): - errors = self.CheckWithErrors("def f(): v = []; v['foo'] = 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", - r"item assignment.*List.*str.*__setitem__ on List.*int")]) + errors = self.CheckWithErrors(""" + def f(): v = []; v['foo'] = 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"item assignment.*List.*str.*__setitem__ on List.*int"}) def testContains(self): - errors = self.CheckWithErrors("def f(): return 'foo' in 3") - self.assertErrorLogIs(errors, [ - (1, "unsupported-operands", r"'in'.*int.*str.*'__contains__' on int")]) + errors = self.CheckWithErrors(""" + def f(): return 'foo' in 3 # unsupported-operands[e] + """) + self.assertErrorRegexes(errors, { + "e": r"'in'.*int.*str.*'__contains__' on int"}) def testRecursion(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" def f(): if __random__: f() - name_error + name_error # name-error """) - self.assertErrorLogIs(errors, [(4, "name-error")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_exceptions.py b/pytype/tests/test_exceptions.py index ed8575d9a..642c0b5fe 100644 --- a/pytype/tests/test_exceptions.py +++ b/pytype/tests/test_exceptions.py @@ -25,7 +25,7 @@ def f() -> int def test_catching_exceptions(self): # TODO(kramm): Don't warn about NameErrors that are being caught. # Catch the exception precisely - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ try: x[1] print("Shouldn't be here...") @@ -33,7 +33,7 @@ def test_catching_exceptions(self): print("caught it!") """) # Catch the exception by a parent class - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ try: x[1] print("Shouldn't be here...") @@ -41,7 +41,7 @@ def test_catching_exceptions(self): print("caught it!") """) # Catch all exceptions - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ try: x[1] print("Shouldn't be here...") @@ -56,7 +56,7 @@ def test_raise_exception_class(self): self.Check("raise ValueError") def test_raise_and_catch_exception(self): - self.Check("""\ + self.Check(""" try: raise ValueError("oops") except ValueError as e: @@ -65,7 +65,7 @@ def test_raise_and_catch_exception(self): """) def test_raise_and_catch_exception_in_function(self): - self.Check("""\ + self.Check(""" def fn(): raise ValueError("oops") @@ -77,10 +77,9 @@ def fn(): """) def test_global_name_error(self): - errors = self.CheckWithErrors("fooey") - self.assertErrorLogIs(errors, [(1, "name-error", r"fooey")]) + self.CheckWithErrors("fooey # name-error") # TODO(kramm): Don't warn about NameErrors that are being caught. - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ try: fooey print("Yes fooey?") @@ -89,15 +88,14 @@ def test_global_name_error(self): """) def test_local_name_error(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" def fn(): - fooey + fooey # name-error fn() """) - self.assertErrorLogIs(errors, [(2, "name-error", r"fooey")]) def test_catch_local_name_error(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ def fn(): try: fooey @@ -108,20 +106,19 @@ def fn(): """) def test_reraise(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" def fn(): try: - fooey + fooey # name-error print("Yes fooey?") except NameError: print("No fooey") raise fn() """) - self.assertErrorLogIs(errors, [(3, "name-error", r"fooey")]) def test_reraise_explicit_exception(self): - self.Check("""\ + self.Check(""" def fn(): try: raise ValueError("ouch") @@ -132,7 +129,7 @@ def fn(): """) def test_finally_while_throwing(self): - self.Check("""\ + self.Check(""" def fn(): try: print("About to..") @@ -144,7 +141,7 @@ def fn(): """) def test_coverage_issue_92(self): - self.Check("""\ + self.Check(""" l = [] for i in range(3): try: @@ -158,7 +155,7 @@ def test_coverage_issue_92(self): """) def test_continue_in_except(self): - self.Check("""\ + self.Check(""" for i in range(3): try: pass @@ -312,7 +309,7 @@ def f() -> int """) def test_return_or_raise_set_attribute(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" def f(): raise ValueError() def g(): @@ -320,17 +317,16 @@ def g(): def h(): func = f if __random__ else g v = func() - v.attr = None + v.attr = None # not-writable """) - self.assertErrorLogIs(errors, [(8, "not-writable")]) def test_bad_type_self(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __init__(self): - type(42, self) + type(42, self) # wrong-arg-count[e] """) - self.assertErrorLogIs(errors, [(3, "wrong-arg-count", r"2.*3")]) + self.assertErrorRegexes(errors, {"e": r"2.*3"}) def test_value(self): ty = self.Infer(""" @@ -372,19 +368,18 @@ def h() -> KeyError: ... """) def test_bad_type(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" try: pass - except None: + except None: # mro-error[e1] pass try: pass - except type(None): + except type(None): # mro-error[e2] pass """) - self.assertErrorLogIs( - errors, [(3, "mro-error", r"Not a class"), - (7, "mro-error", r"None.*BaseException")]) + self.assertErrorRegexes( + errors, {"e1": r"Not a class", "e2": r"None.*BaseException"}) def test_unknown_type(self): self.Check(""" diff --git a/pytype/tests/test_flow.py b/pytype/tests/test_flow.py index 56d3ea19e..5649bc7b1 100644 --- a/pytype/tests/test_flow.py +++ b/pytype/tests/test_flow.py @@ -334,14 +334,14 @@ def test_loop_over_list_of_lists(self): """) def test_call_undefined(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(): try: func = None except: - func() + func() # name-error[e] """, deep=True) - self.assertErrorLogIs(errors, [(5, "name-error", r"func")]) + self.assertErrorRegexes(errors, {"e": r"func"}) def test_nested_break(self): self.assertNoCrash(self.Infer, """ diff --git a/pytype/tests/test_functions.py b/pytype/tests/test_functions.py index 7fca59b60..5e209db58 100644 --- a/pytype/tests/test_functions.py +++ b/pytype/tests/test_functions.py @@ -3,15 +3,12 @@ from pytype import file_utils from pytype.tests import test_base -# We use backslashes to correct the line numbers in test code: -# pylint: disable=g-backslash-continuation - class TestClosures(test_base.TargetIndependentTest): """Tests for closures.""" def test_closures(self): - self.Check("""\ + self.Check(""" def make_adder(x): def add(y): return x+y @@ -22,7 +19,7 @@ def add(y): """) def test_closures_store_deref(self): - self.Check("""\ + self.Check(""" def make_adder(x): z = x+1 def add(y): @@ -34,7 +31,7 @@ def add(y): """) def test_empty_vs_deleted(self): - self.Check("""\ + self.Check(""" import collections Foo = collections.namedtuple('Foo', 'x') def f(): @@ -44,7 +41,7 @@ def g(): """) def test_closures_in_loop(self): - self.Check("""\ + self.Check(""" def make_fns(x): fns = [] for i in range(x): @@ -57,7 +54,7 @@ def make_fns(x): """) def test_closures_with_defaults(self): - self.Check("""\ + self.Check(""" def make_adder(x, y=13, z=43): def add(q, r=11): return x+y+z+q+r @@ -68,7 +65,7 @@ def add(q, r=11): """) def test_deep_closures(self): - self.Check("""\ + self.Check(""" def f1(a): b = 2*a def f2(c): @@ -108,21 +105,20 @@ def g(y): """) def test_unbound_closure_variable(self): - err = self.CheckWithErrors("""\ + self.CheckWithErrors(""" def foo(): def bar(): return tuple(xs) # name-error xs = bar() foo() """) - self.assertErrorsMatch(err, []) class TestGenerators(test_base.TargetIndependentTest): """Tests for generators.""" def test_first(self): - self.Check("""\ + self.Check(""" def two(): yield 1 yield 2 @@ -131,7 +127,7 @@ def two(): """) def test_partial_generator(self): - self.Check("""\ + self.Check(""" from functools import partial def f(a,b): @@ -146,13 +142,13 @@ def f(a,b): """) def test_unsolvable(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ assert list(three) == [3,2,1] """) def test_yield_multiple_values(self): # TODO(kramm): The generator doesn't have __iter__? - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ def triples(): yield 1, 2, 3 yield 4, 5, 6 @@ -162,14 +158,14 @@ def triples(): """) def test_generator_reuse(self): - self.Check("""\ + self.Check(""" g = (x*x for x in range(5)) print(list(g)) print(list(g)) """) def test_generator_from_generator2(self): - self.Check("""\ + self.Check(""" g = (x*x for x in range(3)) print(list(g)) @@ -180,7 +176,7 @@ def test_generator_from_generator2(self): def test_generator_from_generator(self): # TODO(kramm): The generator doesn't have __iter__? - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ class Thing(object): RESOURCES = ('abc', 'def') def get_abc(self): @@ -209,9 +205,11 @@ def setUp(self): self.options.tweak(precise_return=True) def test_pytd_return(self): - ty, errors = self.InferWithErrors("x = 'hello'.startswith(0)") + ty, errors = self.InferWithErrors(""" + x = 'hello'.startswith(0) # wrong-arg-types[e] + """) self.assertTypesMatchPytd(ty, "x: bool") - self.assertErrorLogIs(errors, [(1, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) def test_param_return(self): with file_utils.Tempdir() as d: @@ -220,39 +218,36 @@ def test_param_return(self): T = TypeVar("T") def f(x: T) -> T: ... """) - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" import foo - x = foo.f() + x = foo.f() # missing-parameter """, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ from typing import Any foo: module x: Any """) - self.assertErrorLogIs(errors, [(2, "missing-parameter")]) def test_binop(self): - ty, errors = self.InferWithErrors("x = 'oops' + 0") + ty, _ = self.InferWithErrors("x = 'oops' + 0 # unsupported-operands") self.assertTypesMatchPytd(ty, "x: str") - self.assertErrorLogIs(errors, [(1, "unsupported-operands")]) def test_inplace_op(self): - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" x = [] - x += 0 + x += 0 # unsupported-operands """) self.assertTypesMatchPytd(ty, """ from typing import List x: List[nothing] """) - self.assertErrorLogIs(errors, [(2, "unsupported-operands")]) class TestFunctions(test_base.TargetIndependentTest): """Tests for functions.""" def test_functions(self): - self.Check("""\ + self.Check(""" def fn(a, b=17, c="Hello", d=[]): d.append(99) print(a, b, c, d) @@ -264,7 +259,7 @@ def fn(a, b=17, c="Hello", d=[]): """) def test_function_locals(self): - self.Check("""\ + self.Check(""" def f(): x = "Spite" print(x) @@ -279,7 +274,7 @@ def g(): """) def test_recursion(self): - self.Check("""\ + self.Check(""" def fact(n): if n <= 1: return 1 @@ -291,7 +286,7 @@ def fact(n): """) def test_calling_functions_with_args_kwargs(self): - self.Check("""\ + self.Check(""" def fn(a, b=17, c="Hello", d=[]): d.append(99) print(a, b, c, d) @@ -301,7 +296,7 @@ def fn(a, b=17, c="Hello", d=[]): """) def test_calling_functions_with_generator_args(self): - self.Check("""\ + self.Check(""" class A(object): def next(self): raise StopIteration() @@ -313,23 +308,23 @@ def f(*args): """) def test_defining_functions_with_args_kwargs(self): - self.Check("""\ + self.Check(""" def fn(*args): print("args is %r" % (args,)) fn(1, 2) """) - self.Check("""\ + self.Check(""" def fn(**kwargs): print("kwargs is %r" % (kwargs,)) fn(red=True, blue=False) """) - self.Check("""\ + self.Check(""" def fn(*args, **kwargs): print("args is %r" % (args,)) print("kwargs is %r" % (kwargs,)) fn(1, 2, red=True, blue=False) """) - self.Check("""\ + self.Check(""" def fn(x, y, *args, **kwargs): print("x is %r, y is %r" % (x, y)) print("args is %r" % (args,)) @@ -338,24 +333,24 @@ def fn(x, y, *args, **kwargs): """) def test_defining_functions_with_empty_args_kwargs(self): - self.Check("""\ + self.Check(""" def fn(*args): print("args is %r" % (args,)) fn() """) - self.Check("""\ + self.Check(""" def fn(**kwargs): print("kwargs is %r" % (kwargs,)) fn() """) - self.Check("""\ + self.Check(""" def fn(*args, **kwargs): print("args is %r, kwargs is %r" % (args, kwargs)) fn() """) def test_partial(self): - self.Check("""\ + self.Check(""" from functools import partial def f(a,b): @@ -367,7 +362,7 @@ def f(a,b): """) def test_partial_with_kwargs(self): - self.Check("""\ + self.Check(""" from functools import partial def f(a,b,c=0,d=0): @@ -386,7 +381,7 @@ def test_wraps(self): _AnyCallable = Callable[..., Any] def wraps(wrapped: _AnyCallable, assigned: Sequence[str] = ..., updated: Sequence[str] = ...) -> Callable[[_AnyCallable], _AnyCallable]: ... """) - self.Check("""\ + self.Check(""" from myfunctools import wraps def my_decorator(f): dec = wraps(f) @@ -436,11 +431,11 @@ def f(elements) -> str def test_named_arg_unsolvable_max_depth(self): # Main test here is for this not to throw a KeyError exception upon hitting # maximum depth. - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x): - return max(foo=repr(__any_object__)) + return max(foo=repr(__any_object__)) # wrong-keyword-args[e] """, deep=True, maximum_depth=1) - self.assertErrorLogIs(errors, [(2, "wrong-keyword-args", r"foo.*max")]) + self.assertErrorRegexes(errors, {"e": r"foo.*max"}) def test_multiple_signatures_with_type_parameter(self): with file_utils.Tempdir() as d: @@ -560,7 +555,7 @@ class MyMatch(Generic[T]): pass def compile() -> MyPattern[T]: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo x = foo.compile().match("") """, pythonpath=[d.path]) @@ -654,15 +649,15 @@ def h() -> Callable[[Any, Union[Tuple[Union[Tuple[type, ...], type], ...], type] """) def test_wrong_keyword(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x): pass - f("", y=42) + f("", y=42) # wrong-keyword-args[e] """) - self.assertErrorLogIs(errors, [(3, "wrong-keyword-args", r"y")]) + self.assertErrorRegexes(errors, {"e": r"y"}) def test_staticmethod_class(self): - ty = self.Infer("""\ + ty = self.Infer(""" v1, = (object.__new__,) v2 = type(object.__new__) """, deep=False) @@ -726,23 +721,23 @@ def f(self): """, pythonpath=[d.path]) def test_interpreter_function_in_class(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): bar = lambda x: x def f(self): - self.bar(42) + self.bar(42) # wrong-arg-count[e] """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-count", "1.*2")]) + self.assertErrorRegexes(errors, {"e": r"1.*2"}) def test_nested_lambda(self): # Inspired by b/37869955 - self.Check("""\ + self.Check(""" def f(c): return lambda c: f(c) """) def test_nested_lambda2(self): - self.Check("""\ + self.Check(""" def f(d): return lambda c: f(c) """) @@ -754,7 +749,7 @@ def f(t): """) def test_set_defaults(self): - self.Check("""\ + self.Check(""" import collections X = collections.namedtuple("X", "a b c d") X.__new__.__defaults__ = (3, 4) @@ -765,27 +760,26 @@ def test_set_defaults(self): def test_set_defaults_non_new(self): with file_utils.Tempdir() as d: - d.create_file("a.pyi", """\ + d.create_file("a.pyi", """ def b(x: int, y: int, z: int): ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import a a.b.__defaults__ = ('3',) a.b(1, 2) c = a.b """, deep=False, pythonpath=[d.path]) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ a = ... # type: module def c(x: int, y: int, z: int = ...): ... """) def test_bad_defaults(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" import collections X = collections.namedtuple("X", "a b c") - X.__new__.__defaults__ = (1) + X.__new__.__defaults__ = (1) # bad-function-defaults """) - self.assertErrorLogIs(errors, [(3, "bad-function-defaults")]) def test_multiple_valid_defaults(self): self.Check(""" @@ -807,12 +801,11 @@ def test_set_defaults_to_expression(self): def test_set_defaults_non_tuple_instance(self): # Test that get_atomic_python_constant fails and get_atomic_value pulls out # a non-tuple Instance. - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" import collections X = collections.namedtuple("X", "a b c") - X.__new__.__defaults__ = (lambda x: x)(0) - """) - self.assertErrorLogIs(errors, [(3, "bad-function-defaults")]) + X.__new__.__defaults__ = (lambda x: x)(0) # bad-function-defaults + """) def test_set_builtin_defaults(self): self.assertNoCrash(self.Check, """ @@ -835,33 +828,27 @@ def test(a, b, c = 4): z = test(1, 2) z = test(1, 2, 3) """) - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def test(a, b, c): return a + b + c - x = test(1, 2) # should fail + x = test(1, 2) # missing-parameter test.__defaults__ = (3,) x = test(1, 2) - x = test(1) # should fail + x = test(1) # missing-parameter """) - self.assertErrorLogIs(errors, - [(3, "missing-parameter"), - (6, "missing-parameter")]) def test_interpreter_function_defaults_on_class(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" class Foo(object): def __init__(self, a, b, c): self.a = a self.b = b self.c = c - a = Foo() # should fail + a = Foo() # missing-parameter Foo.__init__.__defaults__ = (1, 2) b = Foo(0) - c = Foo() # should fail + c = Foo() # missing-parameter """) - self.assertErrorLogIs(errors, - [(6, "missing-parameter"), - (9, "missing-parameter")]) def test_split_on_kwargs(self): ty = self.Infer(""" @@ -883,11 +870,10 @@ def test_pyi_starargs(self): d.create_file("foo.pyi", """ def f(x: str, ...) -> None: ... """) - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import foo - foo.f(True, False) + foo.f(True, False) # wrong-arg-types """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "wrong-arg-types")]) def test_infer_bound_pytd_func(self): ty = self.Infer(""" @@ -969,26 +955,22 @@ def __init__(self, a, b=None): """) def test_functools_partial_bad_call(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import functools - functools.partial() - functools.partial(42) + functools.partial() # missing-parameter + functools.partial(42) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [ - (2, "missing-parameter"), - (3, "wrong-arg-types", r"Callable.*int")]) + self.assertErrorRegexes(errors, {"e": r"Callable.*int"}) def test_bad_comprehensions(self): # Test that we report errors in comprehensions and generators only once # while still reporting errors in lambdas. - errors = self.CheckWithErrors("""\ - [name_error1 for x in ()] - {name_error2 for x in ()} - (name_error3 for x in ()) - lambda x: name_error4 + self.CheckWithErrors(""" + [name_error1 for x in ()] # name-error + {name_error2 for x in ()} # name-error + (name_error3 for x in ()) # name-error + lambda x: name_error4 # name-error """) - self.assertErrorLogIs(errors, [(1, "name-error"), (2, "name-error"), - (3, "name-error"), (4, "name-error")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_future_overlay.py b/pytype/tests/test_future_overlay.py index 2c38aefb3..744d756d1 100644 --- a/pytype/tests/test_future_overlay.py +++ b/pytype/tests/test_future_overlay.py @@ -33,11 +33,10 @@ def get_foo(self): """, pythonpath=[d.path]) def test_missing_import(self): - errors = self.CheckWithErrors("""\ - from future.utils import iteritems - from future.utils import with_metaclass + self.CheckWithErrors(""" + from future.utils import iteritems # import-error + from future.utils import with_metaclass # import-error """) - self.assertErrorLogIs(errors, [(1, "import-error"), (2, "import-error")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_import.py b/pytype/tests/test_import.py index 7988c3f86..6b8a2502c 100644 --- a/pytype/tests/test_import.py +++ b/pytype/tests/test_import.py @@ -10,7 +10,7 @@ class ImportTest(test_base.TargetIndependentTest): """Tests for import.""" def testBasicImport(self): - ty = self.Infer("""\ + ty = self.Infer(""" import sys """) self.assertTypesMatchPytd(ty, """ @@ -18,7 +18,7 @@ def testBasicImport(self): """) def testBasicImport2(self): - ty = self.Infer("""\ + ty = self.Infer(""" import bad_import # doesn't exist """, report_errors=False) self.assertTypesMatchPytd(ty, """ @@ -26,7 +26,7 @@ def testBasicImport2(self): """) def testFromImportSmoke(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ from sys import exit from path.to.module import bar, baz """) @@ -35,7 +35,7 @@ def testLongFrom(self): with file_utils.Tempdir() as d: d.create_file("path/to/my_module.pyi", "def foo() -> str") - ty = self.Infer("""\ + ty = self.Infer(""" from path.to import my_module def foo(): return my_module.foo() @@ -46,12 +46,12 @@ def foo() -> str """) def testStarImportSmoke(self): - self.Check("""\ + self.Check(""" from sys import * """) def testStarImportUnknownSmoke(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ from unknown_module import * """) @@ -63,7 +63,7 @@ class A(object): pass a = ... # type: A """) - ty = self.Infer("""\ + ty = self.Infer(""" from my_module import * """, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ @@ -96,7 +96,7 @@ class X: ... from a import * class Y(X): ... """) - ty = self.Infer("""\ + ty = self.Infer(""" from b import * """, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ @@ -108,9 +108,9 @@ class Y(X): ... """) def testBadStarImport(self): - ty, errors = self.InferWithErrors(""" - from nonsense import * - from other_nonsense import * + ty, _ = self.InferWithErrors(""" + from nonsense import * # import-error + from other_nonsense import * # import-error x = foo.bar() """) self.assertTypesMatchPytd(ty, """ @@ -118,8 +118,6 @@ def testBadStarImport(self): def __getattr__(name) -> Any x = ... # type: Any """) - self.assertErrorLogIs(errors, [(2, "import-error", r"nonsense"), - (3, "import-error", r"other_nonsense")]) def testPathImport(self): with file_utils.Tempdir() as d: @@ -127,7 +125,7 @@ def testPathImport(self): "def qqsv() -> str") d.create_file("path/to/__init__.pyi", "") d.create_file("path/__init__.pyi", "") - ty = self.Infer("""\ + ty = self.Infer(""" import path.to.my_module def foo(): return path.to.my_module.qqsv() @@ -143,7 +141,7 @@ def testPathImport2(self): "def qqsv() -> str") d.create_file("path/to/__init__.pyi", "") d.create_file("path/__init__.pyi", "") - ty = self.Infer("""\ + ty = self.Infer(""" import nonexistant_path.to.my_module # doesn't exist def foo(): return path.to.my_module.qqsv() @@ -155,13 +153,13 @@ def foo() -> ? """) def testImportAll(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ from module import * from path.to.module import * """) def testAssignMember(self): - self.Check("""\ + self.Check(""" import sys sys.path = [] """) @@ -426,7 +424,7 @@ def testDotDotPackageInPyi(self): from ..bar import X """) d.create_file("up2/bar.pyi", "class X: ...") - d.create_file("top.py", """\ + d.create_file("top.py", """ from up2.baz.foo import X x = X() """) @@ -442,13 +440,13 @@ def testDotDotInPyi(self): # Similar to testDotDot except in a pyi file. with file_utils.Tempdir() as d: d.create_file("foo/baz.pyi", "x: int") - d.create_file("foo/deep/bar.py", """\ + d.create_file("foo/deep/bar.py", """ from .. import baz a = baz.x """) ty = self.InferFromFile(filename=d["foo/deep/bar.py"], pythonpath=[d.path]) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ baz = ... # type: module a: int """) @@ -459,18 +457,18 @@ def testTooManyDotsInPackageInPyi(self): d.create_file("up/foo.pyi", "from ..bar import X") d.create_file("up/bar.pyi", "class X: ...") _, err = self.InferWithErrors( - "from up.foo import X", pythonpath=[d.path]) - self.assertErrorLogIs( - err, [(1, "pyi-error", "Cannot resolve relative import ..bar")]) + "from up.foo import X # pyi-error[e]", pythonpath=[d.path]) + self.assertErrorRegexes( + err, {"e": r"Cannot resolve relative import \.\.bar"}) def testFromDotInPyi(self): # from . import module with file_utils.Tempdir() as d: d.create_file("foo/a.pyi", "class X: ...") - d.create_file("foo/b.pyi", """\ + d.create_file("foo/b.pyi", """ from . import a Y = a.X""") - d.create_file("top.py", """\ + d.create_file("top.py", """ import foo.b x = foo.b.Y() """) ty = self.InferFromFile(filename=d["top.py"], pythonpath=[d.path]) @@ -496,7 +494,7 @@ def testFileImport1(self): d.create_file("path/to/some/__init__.pyi", "") d.create_file("path/to/__init__.pyi", "") d.create_file("path/__init__.pyi", "") - ty = self.Infer("""\ + ty = self.Infer(""" import path.to.some.module def my_foo(x): return path.to.some.module.foo(x) @@ -513,7 +511,7 @@ def testFileImport2(self): d.create_file("path/to/some/__init__.pyi", "") d.create_file("path/to/__init__.pyi", "") d.create_file("path/__init__.pyi", "") - ty = self.Infer("""\ + ty = self.Infer(""" from path.to.some import module def my_foo(x): return module.foo(x) @@ -525,7 +523,7 @@ def my_foo(x) -> str @test_base.skip("flaky") def testSolveForImported(self): - ty = self.Infer("""\ + ty = self.Infer(""" import StringIO def my_foo(x): return x.read() @@ -542,7 +540,7 @@ def my_foo(x:StringIO.StringIO[object] or typing.IO[object] or """) def testImportBuiltins(self): - ty = self.Infer("""\ + ty = self.Infer(""" import __builtin__ as builtins def f(): @@ -576,7 +574,7 @@ def f1(self, x: Foo) -> Baz class Baz(object): pass """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo def f(x, y): return x.f1(y) @@ -605,7 +603,7 @@ def testImportedConstants(self): class Foo(object): x = ... # type: float """) - ty = self.Infer("""\ + ty = self.Infer(""" import module def f(): return module.x @@ -639,7 +637,7 @@ class Z(object): pass x = ... # type: x.X """) - ty = self.Infer("""\ + ty = self.Infer(""" import x xx = x.X() yy = x.y @@ -657,7 +655,7 @@ def testReimport(self): d.create_file("foo.pyi", """ from collections import OrderedDict as MyOrderedDict """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo d = foo.MyOrderedDict() """, deep=False, pythonpath=[d.path]) @@ -671,7 +669,7 @@ def testImportFunction(self): d.create_file("foo.pyi", """ from math import pow as mypow """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo d = foo.mypow """, deep=False, pythonpath=[d.path]) @@ -687,7 +685,7 @@ def testImportConstant(self): d.create_file("mymath.pyi", """ from math import pi as half_tau """) - ty = self.Infer("""\ + ty = self.Infer(""" import mymath from mymath import half_tau as x y = mymath.half_tau @@ -708,7 +706,7 @@ def testImportMap(self): """ % foo_filename) imports_map = imports_map_loader.build_imports_map( imports_map_filename) - ty = self.Infer("""\ + ty = self.Infer(""" from foo import bar """, deep=False, imports_map=imports_map, pythonpath=[""]) @@ -726,7 +724,7 @@ def __getattr__(name) -> Any: ... from a import Foo def f(x: Foo) -> Foo: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import b foo = b.Foo() bar = b.f(foo) @@ -748,11 +746,11 @@ def testTwoLevel(self): class B(a.A): pass """) - _, errors = self.InferWithErrors("""\ - import b + _, errors = self.InferWithErrors(""" + import b # pyi-error[e] x = b.B() """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"a\.pyi")]) + self.assertErrorRegexes(errors, {"e": r"a\.pyi"}) def testSubdirAndModuleWithSameNameAsPackage(self): with file_utils.Tempdir() as d: @@ -781,7 +779,7 @@ def testRedefinedBuiltin(self): object = ... # type: Any def f(x) -> Any """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo x = foo.f("") """, deep=False, pythonpath=[d.path]) @@ -798,27 +796,24 @@ class object: def foo(self) -> None: ... def f(x: object) -> object """) - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" import foo x = foo.f(foo.object()) y = foo.f(foo.object()) - foo.f(object()) # error + foo.f(object()) # wrong-arg-types """, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ foo = ... # type: module x = ... # type: foo.object y = ... # type: foo.object """) - self.assertErrorLogIs(errors, [ - (4, "wrong-arg-types"), - ]) def testNoFailOnBadSymbolLookup(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ def f(x: FooBar) -> FooBar """) - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ import foo """, pythonpath=[d.path]) @@ -828,7 +823,7 @@ def testImportTypeFactory(self): d.create_file("a.pyi", """ def factory() -> type """) - ty = self.Infer("""\ + ty = self.Infer(""" import a A = a.factory() """, deep=False, pythonpath=[d.path]) @@ -847,7 +842,7 @@ def testGetBadSubmoduleAsAttribute(self): """, pythonpath=[d.path]) def testIgnoredImport(self): - ty = self.Infer("""\ + ty = self.Infer(""" import sys # type: ignore import foobar # type: ignore from os import path # type: ignore @@ -872,15 +867,12 @@ def testAttributeOnModule(self): d.create_file("a.pyi", """ foo = ... # type: int """) - _, errors = self.InferWithErrors("""\ - from a import foo, bar + _, errors = self.InferWithErrors(""" + from a import foo, bar # import-error[e1] import a - a.baz + a.baz # module-attr[e2] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [ - (1, "import-error", r"bar"), - (3, "module-attr", r"baz"), - ]) + self.assertErrorRegexes(errors, {"e1": r"bar", "e2": r"baz"}) def testFromImport(self): with file_utils.Tempdir() as d: @@ -891,7 +883,7 @@ class bar(c.X): ... d.create_file("foo/c.pyi", """ class X(object): ... """) - self.Check("""\ + self.Check(""" from foo import b class Foo(b.bar): pass @@ -900,13 +892,13 @@ class Foo(b.bar): def testImportMapFilter(self): with file_utils.Tempdir() as d: imp_path = ".".join(d.path[1:].split("/")) - init_body = """\ + init_body = """ from {0}.foo import bar from {0}.foo import baz Qux = bar.Quack """.format(imp_path) init_fn = d.create_file("foo/__init__.py", init_body) - initpyi_fn = d.create_file("foo/__init__.pyi~", """\ + initpyi_fn = d.create_file("foo/__init__.pyi~", """ from typing import Any bar = ... # type: Any baz = ... # type: Any @@ -914,17 +906,17 @@ def testImportMapFilter(self): """) bar_fn = d.create_file("foo/bar.py", "class Quack(object): pass") barpyi_fn = d.create_file("foo/bar.pyi", "class Quack(object): pass") - imports_fn = d.create_file("imports_info", """\ + imports_fn = d.create_file("imports_info", """ {0} {1} {2} {3} """.format(init_fn[1:-3], initpyi_fn, bar_fn[1:-3], barpyi_fn)) imports_map = imports_map_loader.build_imports_map(imports_fn, init_fn) - ty = self.Infer("""\ + ty = self.Infer(""" from {0}.foo import bar Adz = bar.Quack """.format(imp_path), deep=False, imports_map=imports_map, pythonpath=[""]) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any, Type bar = ... # type: module Adz = ... # type: Type[{0}.foo.bar.Quack] @@ -947,7 +939,7 @@ class Foo(): ... class Quux(Baz[T], Generic[T]): ... """) ty = self.Infer("""from pkg.a import *""", pythonpath=[d.path]) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ import pkg.a import pkg.b from typing import Type, TypeVar @@ -975,14 +967,14 @@ class Y: ... d.create_file("pkg/g.pyi", """ class Z: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import pkg.a s = pkg.a.c.X() t = pkg.a.f() u = pkg.a.x v = u.Y() """, pythonpath=[d.path]) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ import pkg.b import pkg.d import pkg.g @@ -1130,28 +1122,27 @@ def testUnimportedSubmoduleFailure(self): d.create_file("sub/bar/quux.pyi", "class B: ...") d.create_file("sub/__init__.pyi", "") d.create_file("sub/bar/__init__.pyi", "") - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import sub.bar.baz x = sub.bar.baz.A() - y = sub.bar.quux.B() + y = sub.bar.quux.B() # module-attr[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(3, "module-attr", r"quux.*sub\.bar")]) + self.assertErrorRegexes(errors, {"e": r"quux.*sub\.bar"}) def testSubmoduleAttributeError(self): with file_utils.Tempdir() as d: d.create_file("package/__init__.pyi", "submodule: module") d.create_file("package/submodule.pyi", "") - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" from package import submodule - submodule.asd + submodule.asd # module-attr """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "module-attr")]) def testInitOnlySubmodule(self): """Test a submodule without its own stub file.""" with file_utils.Tempdir() as d: d.create_file("package/__init__.pyi", "submodule: module") - self.Check("""\ + self.Check(""" from package import submodule submodule.asd """, pythonpath=[d.path]) diff --git a/pytype/tests/test_list.py b/pytype/tests/test_list.py index 6839db1a1..ded75d4fc 100644 --- a/pytype/tests/test_list.py +++ b/pytype/tests/test_list.py @@ -70,16 +70,16 @@ def test_extend_with_empty(self): """) def test_getitem_slot(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" a = [1, '2', 3, 4] b = a[1] c = 1 if __random__ else 2 d = a[c] - e = a["s"] + e = a["s"] # unsupported-operands[e] f = a[-1] g = a[slice(1,2)] # should be List[str] """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any, List, Union a = ... # type: List[Union[int, str]] b = ... # type: str @@ -89,8 +89,7 @@ def test_getitem_slot(self): f = ... # type: int g = ... # type: List[Union[int, str]] """) - self.assertErrorLogIs(errors, [(5, "unsupported-operands", - r"__getitem__ on List")]) + self.assertErrorRegexes(errors, {"e": r"__getitem__ on List"}) def test_index_out_of_range(self): ty = self.Infer(""" diff --git a/pytype/tests/test_namedtuple.py b/pytype/tests/test_namedtuple.py index 6c22dadbf..77a5796f1 100644 --- a/pytype/tests/test_namedtuple.py +++ b/pytype/tests/test_namedtuple.py @@ -79,22 +79,15 @@ def test_str_args2(self): """) def test_bad_fieldnames(self): - _, errorlog = self.InferWithErrors("""\ + self.InferWithErrors(""" import collections - collections.namedtuple("_", ["abc", "def", "ghi"]) - collections.namedtuple("_", "_") - collections.namedtuple("_", "a, 1") - collections.namedtuple("_", "a, !") - collections.namedtuple("_", "a, b, c, a") - collections.namedtuple("1", "") + collections.namedtuple("_", ["abc", "def", "ghi"]) # invalid-namedtuple-arg + collections.namedtuple("_", "_") # invalid-namedtuple-arg + collections.namedtuple("_", "a, 1") # invalid-namedtuple-arg + collections.namedtuple("_", "a, !") # invalid-namedtuple-arg + collections.namedtuple("_", "a, b, c, a") # invalid-namedtuple-arg + collections.namedtuple("1", "") # invalid-namedtuple-arg """) - self.assertErrorLogIs(errorlog, - [(2, "invalid-namedtuple-arg"), - (3, "invalid-namedtuple-arg"), - (4, "invalid-namedtuple-arg"), - (5, "invalid-namedtuple-arg"), - (6, "invalid-namedtuple-arg"), - (7, "invalid-namedtuple-arg")]) def test_rename(self): ty = self.Infer(""" @@ -106,23 +99,19 @@ def test_rename(self): ty, self._namedtuple_def(S=("S", ["abc", "_1", "ghi", "_3"]))) def test_bad_initialize(self): - _, errlog = self.InferWithErrors("""\ + self.InferWithErrors(""" from collections import namedtuple X = namedtuple("X", "y z") - a = X(1) - b = X(y = 2) - c = X(w = 3) + a = X(1) # missing-parameter + b = X(y = 2) # missing-parameter + c = X(w = 3) # wrong-keyword-args d = X(y = "hello", z = 4j) # works """) - self.assertErrorLogIs(errlog, [ - (4, "missing-parameter"), - (5, "missing-parameter"), - (6, "wrong-keyword-args")]) def test_class_name(self): ty = self.Infer( - """\ + """ import collections F = collections.namedtuple("S", ['a', 'b', 'c']) """) @@ -153,29 +142,28 @@ def test_instantiate_pyi_namedtuple(self): d.create_file("foo.pyi", """ class X(NamedTuple('X', [('y', str), ('z', int)])): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo - foo.X() # wrong arg count - foo.X(0, "") # wrong types - foo.X(z="", y=0) # wrong types + foo.X() # missing-parameter[e1] + foo.X(0, "") # wrong-arg-types[e2] + foo.X(z="", y=0) # wrong-arg-types[e3] foo.X("", 0) foo.X(y="", z=0) """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(2, "missing-parameter", r"y"), - (3, "wrong-arg-types", r"str.*int"), - (4, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes( + errors, {"e1": r"y", "e2": r"str.*int", "e3": r"str.*int"}) def test_use_pyi_namedtuple(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ class X(NamedTuple("X", [])): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo foo.X()._replace() - foo.X().nonsense + foo.X().nonsense # attribute-error[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"nonsense.*X")]) + self.assertErrorRegexes(errors, {"e": r"nonsense.*X"}) def test_subclass_pyi_namedtuple(self): with file_utils.Tempdir() as d: diff --git a/pytype/tests/test_operators.py b/pytype/tests/test_operators.py index 217570b40..89ff45524 100644 --- a/pytype/tests/test_operators.py +++ b/pytype/tests/test_operators.py @@ -324,13 +324,13 @@ def __rsub__(self, other): def test_unknown_right(self): # Reverse operators are rare enough that it makes sense to assume that the # regular operator was called when the right side is ambiguous. - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __sub__(self, other): return "" - (Foo() - __any_object__).real + (Foo() - __any_object__).real # attribute-error[e] """) - self.assertErrorLogIs(errors, [(4, "attribute-error", r"real.*str")]) + self.assertErrorRegexes(errors, {"e": r"real.*str"}) class InplaceTest(test_base.TargetIndependentTest, @@ -368,12 +368,12 @@ def test_sub(self): self.check_inplace("isub", "-=") def test_list_add(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class A(object): pass v = [] - v += A() + v += A() # unsupported-operands[e] """) - self.assertErrorLogIs(errors, [(3, "unsupported-operands", r"A.*Iterable")]) + self.assertErrorRegexes(errors, {"e": r"A.*Iterable"}) class BindingsTest(test_base.TargetIndependentTest): diff --git a/pytype/tests/test_pyi.py b/pytype/tests/test_pyi.py index 60c32c0e8..ac103d532 100644 --- a/pytype/tests/test_pyi.py +++ b/pytype/tests/test_pyi.py @@ -26,7 +26,7 @@ def testOptional(self): d.create_file("mod.pyi", """ def f(x: int = ...) -> None """) - ty = self.Infer("""\ + ty = self.Infer(""" import mod def f(): return mod.f() @@ -44,7 +44,7 @@ def testSolve(self): d.create_file("mod.pyi", """ def f(node: int, *args, **kwargs) -> str """) - ty = self.Infer("""\ + ty = self.Infer(""" import mod def g(x): return mod.f(x) @@ -60,7 +60,7 @@ def testTyping(self): from typing import Any, IO, List, Optional def split(s: Optional[int]) -> List[str, ...]: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import mod def g(x): return mod.split(x) @@ -79,7 +79,7 @@ def foo(self) -> A class B(A): pass """) - ty = self.Infer("""\ + ty = self.Infer(""" import classes x = classes.B().foo() """, deep=False, pythonpath=[d.path]) @@ -94,7 +94,7 @@ def testEmptyModule(self): from typing import Any def __getattr__(name) -> Any """) - ty = self.Infer("""\ + ty = self.Infer(""" import vague x = vague.foo + vague.bar """, deep=False, pythonpath=[d.path]) @@ -114,7 +114,7 @@ def u(a, b) -> int: ... def v(cls, a, b) -> int: ... def w(self, a, b) -> int: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import decorated u = decorated.A.u(1, 2) v = decorated.A.v(1, 2) @@ -141,7 +141,7 @@ class A(object): def v(cls) -> float: ... def w(self, x: classmethod) -> int: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import a u = a.A().w(a.A.v) """, deep=False, pythonpath=[d.path]) @@ -155,7 +155,7 @@ def testOptionalParameters(self): d.create_file("a.pyi", """ def parse(source, filename = ..., mode = ..., *args, **kwargs) -> int: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import a u = a.parse("True") """, deep=False, pythonpath=[d.path]) @@ -169,7 +169,7 @@ def testOptimize(self): d.create_file("a.pyi", """ class Bar(dict[?, int]): ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import a def f(foo, bar): return __any_object__[1] @@ -190,7 +190,7 @@ def testIterable(self): from typing import Iterable def f(l: Iterable[int]) -> int: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import a u = a.f([1, 2, 3]) """, deep=False, pythonpath=[d.path]) @@ -204,7 +204,7 @@ def testObject(self): d.create_file("a.pyi", """ def make_object() -> object """) - ty = self.Infer("""\ + ty = self.Infer(""" import a def f(x=None): x = a.make_object() @@ -224,7 +224,7 @@ def testCallable(self): from typing import Callable def process_function(func: Callable[..., Any]) -> None: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo def bar(): pass @@ -238,7 +238,7 @@ def bar() -> Any: ... # 'Any' because deep=False """) def testHex(self): - ty = self.Infer("""\ + ty = self.Infer(""" x = hex(4) """, deep=False) self.assertTypesMatchPytd(ty, """ @@ -258,7 +258,7 @@ class C(A[int]): ... class D(object): def baz(self) -> int """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo def f(x): return x.bar("foo") @@ -300,7 +300,7 @@ def testIdentity(self): T = TypeVar("T") def f(x: T) -> T """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo x = foo.f(3) """, pythonpath=[d.path]) @@ -338,13 +338,13 @@ def __getattr__(name) -> Any """) ty, errors = self.InferWithErrors(""" from foo import * - from bar import * # Nonsense import generates a top-level __getattr__ + from bar import * # Nonsense import generates a top-level __getattr__ # import-error[e] """, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ from typing import Any def __getattr__(name) -> Any """) - self.assertErrorLogIs(errors, [(3, "import-error", r"bar")]) + self.assertErrorRegexes(errors, {"e": r"bar"}) def testPyiListItem(self): with file_utils.Tempdir() as d: @@ -368,7 +368,7 @@ def testDubiousFunctionReference(self): def DubiousType() -> None x = ... # type: DubiousType """) - ty = self.Infer("""\ + ty = self.Infer(""" import a x = a.x """, pythonpath=[d.path]) @@ -383,7 +383,7 @@ def testKeywordOnlyArgs(self): from typing import Any def foo(x: str, *y: Any, z: complex = ...) -> int: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import a x = a.foo("foo %d %d", 3, 3) """, pythonpath=[d.path]) @@ -432,12 +432,12 @@ def testStarArgs(self): V = TypeVar("V") def foo(a: K, *b, c: V, **d) -> Dict[K, V]: ... """) - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" import foo a = foo.foo(*tuple(), **dict()) b = foo.foo(*(1,), **{"c": 3j}) - c = foo.foo(*(1,)) - d = foo.foo(*(), **{"d": 3j}) + c = foo.foo(*(1,)) # missing-parameter[e1] + d = foo.foo(*(), **{"d": 3j}) # missing-parameter[e2] """, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ from typing import Any, Dict @@ -447,10 +447,7 @@ def foo(a: K, *b, c: V, **d) -> Dict[K, V]: ... c = ... # type: Any d = ... # type: Any """) - self.assertErrorLogIs(errors, [ - (4, "missing-parameter", r"\bc\b"), - (5, "missing-parameter", r"\ba\b"), - ]) + self.assertErrorRegexes(errors, {"e1": r"\bc\b", "e2": r"\ba\b"}) def testUnionWithSuperclass(self): with file_utils.Tempdir() as d: @@ -521,8 +518,8 @@ def testTypeVarConflict(self): from typing import List, Sequence class A(List[int], Sequence[str]): ... """) - ty, errors = self.InferWithErrors("""\ - import foo + ty, _ = self.InferWithErrors(""" + import foo # pyi-error x = [] + foo.A() """, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ @@ -530,7 +527,6 @@ class A(List[int], Sequence[str]): ... foo = ... # type: Any x = ... # type: list """) - self.assertErrorLogIs(errors, [(1, "pyi-error")]) def testSameTypeVarName(self): with file_utils.Tempdir() as d: @@ -561,7 +557,7 @@ class Bar(Generic[T]): def bar(self, x:T2): self = Bar[T2] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo x = foo.Bar() x.bar(10) @@ -584,12 +580,12 @@ def bar(self): self = Bar[T2] """) # We should get an error at import time rather than at use time here. - _, errors = self.InferWithErrors("""\ - import foo + _, errors = self.InferWithErrors(""" + import foo # pyi-error[e] x = foo.Bar() x.bar() """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", "T2")]) + self.assertErrorRegexes(errors, {"e": r"T2"}) def testStarImport(self): with file_utils.Tempdir() as d: @@ -725,12 +721,12 @@ def f(x: foo.Foo) -> None: ... def testAliasStaticMethod(self): with file_utils.Tempdir() as d: - d.create_file("foo.pyi", """\ + d.create_file("foo.pyi", """ class A: @staticmethod def t(a: str) -> None: ... """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo ta = foo.A.t """, pythonpath=[d.path]) diff --git a/pytype/tests/test_quick.py b/pytype/tests/test_quick.py index 78390ae32..45e157dff 100644 --- a/pytype/tests/test_quick.py +++ b/pytype/tests/test_quick.py @@ -75,13 +75,13 @@ def f() -> Any def testAnalyzeAnnotatedMaxDepth(self): # --output with --analyze-annotated has the same max depth as --check. - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def make_greeting(user_id): - return 'hello, user' + user_id + return 'hello, user' + user_id # unsupported-operands[e] def print_greeting(): print(make_greeting(0)) """, quick=True) - self.assertErrorLogIs(errors, [(2, "unsupported-operands", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_recovery.py b/pytype/tests/test_recovery.py index 1a42b674b..7d4465c2a 100644 --- a/pytype/tests/test_recovery.py +++ b/pytype/tests/test_recovery.py @@ -99,20 +99,16 @@ class A(object): """) def testMethodWithUnknownDecorator(self): - _, errors = self.InferWithErrors("""\ - from nowhere import decorator + self.InferWithErrors(""" + from nowhere import decorator # import-error class Foo(object): @decorator def f(): - name_error + name_error # name-error """, deep=True) - self.assertErrorLogIs(errors, [ - (1, "import-error"), - (5, "name-error"), - ]) def testAssertInConstructor(self): - self.Check("""\ + self.Check(""" class Foo(object): def __init__(self): self._bar = "foo" @@ -123,7 +119,7 @@ def __str__(self): @test_base.skip("Line 7, in __str__: No attribute '_bar' on Foo'") def testConstructorInfiniteLoop(self): - self.Check("""\ + self.Check(""" class Foo(object): def __init__(self): self._bar = "foo" @@ -133,27 +129,21 @@ def __str__(self): """) def testAttributeAccessInImpossiblePath(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" x = 3.14 if __random__ else 42 if isinstance(x, int): if isinstance(x, float): x.upper # not reported - 3 in x + 3 in x # unsupported-operands """) - self.assertErrorLogIs(errors, [ - (5, "unsupported-operands"), - ]) def testBinaryOperatorOnImpossiblePath(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" x = "" if __random__ else [] if isinstance(x, list): if isinstance(x, str): - x / x + x / x # unsupported-operands """) - self.assertErrorLogIs(errors, [ - (4, "unsupported-operands"), - ]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_reingest.py b/pytype/tests/test_reingest.py index cedd50b3b..5c644d1f7 100644 --- a/pytype/tests/test_reingest.py +++ b/pytype/tests/test_reingest.py @@ -120,12 +120,12 @@ def __new__(cls, a, b): """) with file_utils.Tempdir() as d: d.create_file("foo.pyi", pytd_utils.Print(foo)) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo foo.X("hello", "world") - foo.X(42) # missing parameters + foo.X(42) # missing-parameter[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(3, "missing-parameter", "b.*__new__")]) + self.assertErrorRegexes(errors, {"e": r"b.*__new__"}) def testAlias(self): foo = self.Infer(""" @@ -151,7 +151,7 @@ def testDynamicAttributes(self): with file_utils.Tempdir() as d: d.create_file("foo1.pyi", pytd_utils.Print(foo1)) d.create_file("foo2.pyi", pytd_utils.Print(foo2)) - d.create_file("bar.pyi", """\ + d.create_file("bar.pyi", """ from foo1 import xyz from foo2 import zyx """) diff --git a/pytype/tests/test_slots.py b/pytype/tests/test_slots.py index 1f6f5a16d..ad6a99ec6 100644 --- a/pytype/tests/test_slots.py +++ b/pytype/tests/test_slots.py @@ -65,13 +65,10 @@ class Foo(object): def testSlotWithNonStrings(self): _, errors = self.InferWithErrors(""" - class Foo(object): + class Foo(object): # bad-slots[e] __slots__ = (1, 2, 3) """) - self.assertErrorLogIs( - errors, - [(2, "bad-slots", r"Invalid __slot__ entry: '1'")] - ) + self.assertErrorRegexes(errors, {"e": r"Invalid __slot__ entry: '1'"}) def testSetSlot(self): self.Check(""" @@ -111,20 +108,15 @@ class Foo(object): foo = Foo() foo.x = 1 # ok foo.y = 2 # ok - foo.z = 3 # error + foo.z = 3 # not-writable[e] """) - self.assertErrorLogIs( - errors, - [(7, "not-writable", r"z")] - ) + self.assertErrorRegexes(errors, {"e": r"z"}) def testObject(self): - _, errors = self.InferWithErrors("""\ - object().foo = 42 + _, errors = self.InferWithErrors(""" + object().foo = 42 # not-writable[e] """) - self.assertErrorLogIs(errors, [ - (1, "not-writable", r"object") - ]) + self.assertErrorRegexes(errors, {"e": r"object"}) def testAnyBaseClass(self): self.Check(""" @@ -134,79 +126,65 @@ class Foo(__any_object__): """) def testParameterizedBaseClass(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import List class Foo(List[int]): __slots__ = () - Foo().foo = 42 + Foo().foo = 42 # not-writable[e] """) - self.assertErrorLogIs(errors, [ - (4, "not-writable", r"foo") - ]) + self.assertErrorRegexes(errors, {"e": r"foo"}) def testEmptySlots(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): __slots__ = () - Foo().foo = 42 + Foo().foo = 42 # not-writable[e] """) - self.assertErrorLogIs( - errors, - [(3, "not-writable", r"foo")] - ) + self.assertErrorRegexes(errors, {"e": r"foo"}) def testNamedTuple(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import collections Foo = collections.namedtuple("_", ["a", "b", "c"]) foo = Foo(None, None, None) foo.a = 1 foo.b = 2 foo.c = 3 - foo.d = 4 # error + foo.d = 4 # not-writable[e] """) - self.assertErrorLogIs(errors, [ - (7, "not-writable", r"d") - ]) + self.assertErrorRegexes(errors, {"e": r"d"}) def testBuiltinAttr(self): - _, errors = self.InferWithErrors("""\ - "foo".bar = 1 - u"foo".bar = 2 - ().bar = 3 - [].bar = 4 - {}.bar = 5 - set().bar = 6 - frozenset().bar = 7 - frozenset().bar = 8 - Ellipsis.bar = 9 - bytearray().bar = 10 - enumerate([]).bar = 11 - True.bar = 12 - (42).bar = 13 - (3.14).bar = 14 - (3j).bar = 15 - slice(1,10).bar = 17 - memoryview(b"foo").bar = 18 - range(10).bar = 19 - """) - self.assertErrorLogIs( - errors, - [(line, "not-writable") for line in range(1, 19)] - ) + self.InferWithErrors(""" + "foo".bar = 1 # not-writable + u"foo".bar = 2 # not-writable + ().bar = 3 # not-writable + [].bar = 4 # not-writable + {}.bar = 5 # not-writable + set().bar = 6 # not-writable + frozenset().bar = 7 # not-writable + frozenset().bar = 8 # not-writable + Ellipsis.bar = 9 # not-writable + bytearray().bar = 10 # not-writable + enumerate([]).bar = 11 # not-writable + True.bar = 12 # not-writable + (42).bar = 13 # not-writable + (3.14).bar = 14 # not-writable + (3j).bar = 15 # not-writable + slice(1,10).bar = 16 # not-writable + memoryview(b"foo").bar = 17 # not-writable + range(10).bar = 18 # not-writable + """) def testGeneratorAttr(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(): yield 42 - f().foo = 42 + f().foo = 42 # not-writable[e] """) - self.assertErrorLogIs( - errors, - [(2, "not-writable", r"foo")] - ) + self.assertErrorRegexes(errors, {"e": r"foo"}) def testSetAttr(self): - self.Check("""\ + self.Check(""" class Foo(object): __slots__ = () def __setattr__(self, name, value): @@ -218,7 +196,7 @@ class Bar(Foo): """) def testDescriptors(self): - self.Check("""\ + self.Check(""" class Descriptor(object): def __set__(self, obj, cls): pass @@ -232,7 +210,7 @@ class Bar(Foo): """) def testNameMangling(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Bar(object): __slots__ = ["__baz"] def __init__(self): @@ -241,12 +219,9 @@ class Foo(Bar): __slots__ = ["__foo"] def __init__(self): self.__foo = 42 - self.__baz = 42 # __baz is class-private + self.__baz = 42 # __baz is class-private # not-writable[e] """) - self.assertErrorLogIs( - errors, - [(9, "not-writable", "__baz")] - ) + self.assertErrorRegexes(errors, {"e": r"__baz"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_solver.py b/pytype/tests/test_solver.py index a2693c574..e53a0894b 100644 --- a/pytype/tests/test_solver.py +++ b/pytype/tests/test_solver.py @@ -265,7 +265,7 @@ def testMatchAgainstFunctionWithoutSelf(self): class myclass: def bad_method() -> bool """) - ty = self.Infer("""\ + ty = self.Infer(""" import bad_mod def f(date): return date.bad_method() @@ -277,7 +277,7 @@ def f(date) -> Any """) def testExternalName(self): - ty = self.Infer("""\ + ty = self.Infer(""" import collections def bar(l): l.append(collections.defaultdict(int, [(0, 0)])) @@ -290,7 +290,7 @@ def bar(l) -> NoneType """) def testNameConflictWithBuiltin(self): - ty = self.Infer("""\ + ty = self.Infer(""" class LookupError(KeyError): pass def f(x): @@ -327,7 +327,7 @@ def testDuplicateKeyword(self): T = TypeVar("T") def f(x, *args, y: T) -> T """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo x = foo.f(1, y=2j) """, deep=False, pythonpath=[d.path]) @@ -337,7 +337,7 @@ def f(x, *args, y: T) -> T """) def test_store_name_cfg(self): - ty = self.Infer("""\ + ty = self.Infer(""" a = 1 a = a + 1 """) @@ -346,14 +346,14 @@ def test_store_name_cfg(self): def test_store_global_cfg(self): # STORE_GLOBAL didn't advance the cfg, so it required additional statements # in between in order to show the bug. - ty = self.Infer("""\ + ty = self.Infer(""" global a b = 1 a = 1 b = 1 + b a = 1 + a """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ a = ... # type: int b = ... # type: int """) diff --git a/pytype/tests/test_special_builtins.py b/pytype/tests/test_special_builtins.py index 3a01be077..74ab67eac 100644 --- a/pytype/tests/test_special_builtins.py +++ b/pytype/tests/test_special_builtins.py @@ -191,7 +191,7 @@ def f() -> Tuple[int, str] """) def testDifferentPropertyInstances(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" class Foo(object): def __init__(self): self._foo = 42 if __random__ else "hello world" @@ -201,9 +201,9 @@ def foo(self): foo1 = Foo() foo2 = Foo() if isinstance(foo1.foo, str): - x = foo2.foo.upper() # line 10 + x = foo2.foo.upper() # attribute-error[e] """) - self.assertErrorLogIs(errors, [(10, "attribute-error", r"upper.*int")]) + self.assertErrorRegexes(errors, {"e": r"upper.*int"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_splits.py b/pytype/tests/test_splits.py index 4e74f19a8..c05fd6377 100644 --- a/pytype/tests/test_splits.py +++ b/pytype/tests/test_splits.py @@ -309,7 +309,7 @@ def a2(x) -> Union[int, str]: ... """) def testIsSubclass(self): - ty = self.Infer("""\ + ty = self.Infer(""" # Always return a bool def sig(x): return issubclass(x, object) # Classes for testing @@ -326,7 +326,7 @@ def d6(): return "y" if issubclass(B, ((C, str), int, (float, A))) else 0 # Ambiguous results def a1(x): return "y" if issubclass(x, A) else 0 """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Union def sig(x) -> bool: ... def d1() -> str: ... @@ -519,7 +519,7 @@ def testDictDoesNotContain(self): def testDictMaybeContains(self): """Test that we can handle more complex cases involving dict membership.""" - ty = self.Infer("""\ + ty = self.Infer(""" if __random__: x = {"a": 1, "b": 2} else: @@ -537,7 +537,7 @@ def testDictMaybeContains(self): """) def testContainsCoerceToBool(self): - ty = self.Infer("""\ + ty = self.Infer(""" class A(object): def __contains__(self, x): return 1 @@ -655,14 +655,13 @@ def testPrimitiveNotEq(self): def testBuiltinFullNameCheck(self): # Don't get confused by a class named int - _, errorlog = self.InferWithErrors(""" + self.InferWithErrors(""" class int(): pass x = "foo" if __random__ else int() if x == "foo": - x.upper() + x.upper() # attribute-error """) - self.assertNotEqual(len(errorlog), 0) def testTypeParameterInBranch(self): ty = self.Infer(""" @@ -678,7 +677,7 @@ def testTypeParameterInBranch(self): def testNoneOrTuple(self): # This tests the attribute retrieval code in vm.py:_get_iter - self.Check("""\ + self.Check(""" foo = (0, 0) if __random__: foo = None @@ -761,12 +760,11 @@ class Value(int): value1 = ... # type: int value2 = ... # type: Value """) - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import foo if foo.value1 == foo.value2: - name_error + name_error # name-error """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(3, "name-error")]) def testListElement(self): ty = self.Infer(""" diff --git a/pytype/tests/test_stdlib.py b/pytype/tests/test_stdlib.py index 05dd8f115..7abe757f5 100644 --- a/pytype/tests/test_stdlib.py +++ b/pytype/tests/test_stdlib.py @@ -95,7 +95,7 @@ def testStdlib(self): """) def testNamedtuple(self): - self.Check("""\ + self.Check(""" import collections collections.namedtuple(u"_", "") collections.namedtuple("_", u"") @@ -103,7 +103,7 @@ def testNamedtuple(self): """) def testDefaultdict(self): - ty = self.Infer("""\ + ty = self.Infer(""" import collections a = collections.defaultdict(int, one = 1, two = 2) b = collections.defaultdict(int, {'one': 1, 'two': 2}) @@ -112,7 +112,7 @@ def testDefaultdict(self): e = collections.defaultdict(int) f = collections.defaultdict(default_factory = int) """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ collections = ... # type: module a = ... # type: collections.defaultdict[str, int] b = ... # type: collections.defaultdict[str, int] @@ -123,7 +123,7 @@ def testDefaultdict(self): """) def testDefaultdictNoFactory(self): - ty = self.Infer("""\ + ty = self.Infer(""" import collections a = collections.defaultdict() b = collections.defaultdict(None) @@ -134,7 +134,7 @@ def testDefaultdictNoFactory(self): g = collections.defaultdict(one = 1, two = 2) h = collections.defaultdict(default_factory = None) """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any collections = ... # type: module a = ... # type: collections.defaultdict[nothing, nothing] @@ -148,14 +148,14 @@ def testDefaultdictNoFactory(self): """) def testDefaultdictDiffDefaults(self): - ty = self.Infer("""\ + ty = self.Infer(""" import collections a = collections.defaultdict(int, one = '1') b = collections.defaultdict(str, one = 1) c = collections.defaultdict(None, one = 1) d = collections.defaultdict(int, {1: 'one'}) """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Union collections = ... # type: module a = ... # type: collections.defaultdict[str, Union[int, str]] @@ -195,7 +195,7 @@ def testCsv(self): """) def testFuture(self): - self.Check("""\ + self.Check(""" import __future__ """) diff --git a/pytype/tests/test_super.py b/pytype/tests/test_super.py index 5ec5e237f..595bd5004 100644 --- a/pytype/tests/test_super.py +++ b/pytype/tests/test_super.py @@ -72,12 +72,12 @@ class Baz(object): """) def testSet(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def foo(self, name, value): - super(Foo, self).__set__(name, value) + super(Foo, self).__set__(name, value) # attribute-error[e] """) - self.assertErrorLogIs(errors, [(3, "attribute-error", r"__set__.*super")]) + self.assertErrorRegexes(errors, {"e": r"__set__.*super"}) def testInheritedSet(self): self.Check(""" @@ -143,15 +143,15 @@ def hello(self): """) def testCallSuper(self): - _, errorlog = self.InferWithErrors("""\ + _, errorlog = self.InferWithErrors(""" class Y(object): pass class Foo(Y): def hello(self): - return super(Foo, self)() + return super(Foo, self)() # not-callable[e] """) - self.assertErrorLogIs(errorlog, [(6, "not-callable", r"super")]) + self.assertErrorRegexes(errorlog, {"e": r"super"}) def testSuperType(self): ty = self.Infer(""" @@ -194,30 +194,28 @@ def testSuperWithAny(self): """) def testSingleArgumentSuper(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" super(object) - super(object()) + super(object()) # wrong-arg-types[e] """) - self.assertErrorLogIs( - errors, [(2, "wrong-arg-types", r"cls: type.*cls: object")]) + self.assertErrorRegexes(errors, {"e": r"cls: type.*cls: object"}) def testMethodOnSingleArgumentSuper(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" sup = super(object) - sup.foo - sup.__new__(object) + sup.foo # attribute-error[e1] + sup.__new__(object) # wrong-arg-types[e2] v = sup.__new__(super) """) self.assertTypesMatchPytd(ty, """ sup = ... # type: super v = ... # type: super """) - self.assertErrorLogIs(errors, [ - (2, "attribute-error", r"'foo' on super"), - (3, "wrong-arg-types", r"Type\[super\].*Type\[object\]")]) + self.assertErrorRegexes(errors, {"e1": r"'foo' on super", + "e2": r"Type\[super\].*Type\[object\]"}) def testSuperUnderDecorator(self): - self.Check("""\ + self.Check(""" def decorate(cls): return __any_object__ class Parent(object): @@ -230,42 +228,42 @@ def Hello(self): """) def testSuperSetAttr(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): def __init__(self): - super(Foo, self).foo = 42 + super(Foo, self).foo = 42 # not-writable[e] """) - self.assertErrorLogIs(errors, [(3, "not-writable", r"super")]) + self.assertErrorRegexes(errors, {"e": r"super"}) def testSuperSubclassSetAttr(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(object): pass class Bar(Foo): def __init__(self): - super(Bar, self).foo = 42 + super(Bar, self).foo = 42 # not-writable[e] """) - self.assertErrorLogIs(errors, [(4, "not-writable", r"super")]) + self.assertErrorRegexes(errors, {"e": r"super"}) def testSuperNothingSetAttr(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ class Foo(nothing): ... """) - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import foo class Bar(foo.Foo): def __init__(self): - super(foo.Foo, self).foo = 42 + super(foo.Foo, self).foo = 42 # not-writable[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(4, "not-writable", r"super")]) + self.assertErrorRegexes(errors, {"e": r"super"}) def testSuperAnySetAttr(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" class Foo(__any_object__): def __init__(self): - super(Foo, self).foo = 42 + super(Foo, self).foo = 42 # not-writable[e] """) - self.assertErrorLogIs(errors, [(3, "not-writable", r"super")]) + self.assertErrorRegexes(errors, {"e": r"super"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_tracebacks.py b/pytype/tests/test_tracebacks.py index 8ea8407f8..96635445a 100644 --- a/pytype/tests/test_tracebacks.py +++ b/pytype/tests/test_tracebacks.py @@ -7,80 +7,72 @@ class TracebackTest(test_base.TargetIndependentTest): """Tests for tracebacks in error messages.""" def test_no_traceback(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x): - "hello" + 42 + "hello" + 42 # unsupported-operands[e] f("world") """) - self.assertErrorLogIs(errors, [(2, "unsupported-operands", - r"expects str$")]) + self.assertErrorRegexes(errors, {"e": r"expects str$"}) def test_same_traceback(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x, _): - x + 42 + x + 42 # unsupported-operands[e] def g(x): f("hello", x) g("world") """, deep=True) - self.assertErrorLogIs(errors, [(2, "unsupported-operands", - r"Called from.*:\n" - r" line 4, in g")]) + self.assertErrorRegexes(errors, {"e": r"Called from.*:\n line 4, in g"}) def test_different_tracebacks(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x): - x + 42 + x + 42 # unsupported-operands[e1] # unsupported-operands[e2] f("hello") f("world") """) - self.assertErrorLogIs(errors, [(2, "unsupported-operands", - r"Called from.*:\n" - r" line 3, in current file"), - (2, "unsupported-operands", - r"Called from.*:\n" - r" line 4, in current file")]) + self.assertErrorRegexes(errors, { + "e1": r"Called from.*:\n line 3, in current file", + "e2": r"Called from.*:\n line 4, in current file"}) def test_comprehension(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(): - return {x.upper() for x in range(10)} + return {x.upper() for x in range(10)} # attribute-error[e] """) - self.assertErrorLogIs(errors, [(2, "attribute-error", r"upper.*int$")]) + self.assertErrorRegexes(errors, {"e": r"upper.*int$"}) error, = errors self.assertEqual(error.methodname, "f") def test_comprehension_in_traceback(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(x): - return x.upper() + return x.upper() # attribute-error[e] def g(): return {f(x) for x in range(10)} """) - self.assertErrorLogIs(errors, [(2, "attribute-error", - r"Called from.*:\n line 4, in g$")]) + self.assertErrorRegexes(errors, {"e": r"Called from.*:\n line 4, in g$"}) def test_no_argument_function(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(): - return None.attr + return None.attr # attribute-error[e] f() """) - self.assertErrorLogIs(errors, [(2, "attribute-error", r"attr.*None$")]) + self.assertErrorRegexes(errors, {"e": r"attr.*None$"}) def test_max_callsites(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" def f(s): - return "hello, " + s + return "hello, " + s # unsupported-operands[e1] # unsupported-operands[e2] # unsupported-operands[e3] f(0) f(1) f(2) f(3) """) # We limit the number of tracebacks shown for the same error. - self.assertErrorLogIs(errors, [(2, "unsupported-operands", r"line 3"), - (2, "unsupported-operands", r"line 4"), - (2, "unsupported-operands", r"line 5")]) + self.assertErrorRegexes( + errors, {"e1": r"line 3", "e2": r"line 4", "e3": r"line 5"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_tuple.py b/pytype/tests/test_tuple.py index 5fea56993..923f9940e 100644 --- a/pytype/tests/test_tuple.py +++ b/pytype/tests/test_tuple.py @@ -7,7 +7,7 @@ class TupleTest(test_base.TargetIndependentTest): """Tests for __builtin__.tuple.""" def testGetItemInt(self): - ty = self.Infer("""\ + ty = self.Infer(""" t = ("", 42) v1 = t[0] v2 = t[1] @@ -25,7 +25,7 @@ def testGetItemInt(self): @test_base.skip("Needs better slice support in abstract.Tuple, convert.py.") def testGetItemSlice(self): - ty = self.Infer("""\ + ty = self.Infer(""" t = ("", 42) v1 = t[:] v2 = t[:1] @@ -46,7 +46,7 @@ def testGetItemSlice(self): """) def testUnpackTuple(self): - ty = self.Infer("""\ + ty = self.Infer(""" v1, v2 = ("", 42) _, w = ("", 42) x, (y, z) = ("", (3.14, True)) @@ -62,10 +62,10 @@ def testUnpackTuple(self): """) def testBadUnpacking(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" tup = (1, "") - a, = tup - b, c, d = tup + a, = tup # bad-unpacking[e1] + b, c, d = tup # bad-unpacking[e2] """) self.assertTypesMatchPytd(ty, """ from typing import Tuple @@ -75,9 +75,8 @@ def testBadUnpacking(self): c = ... # type: int or str d = ... # type: int or str """) - self.assertErrorLogIs(errors, [ - (2, "bad-unpacking", "2 values.*1 variable"), - (3, "bad-unpacking", "2 values.*3 variables")]) + self.assertErrorRegexes( + errors, {"e1": r"2 values.*1 variable", "e2": r"2 values.*3 variables"}) def testMutableItem(self): ty = self.Infer(""" @@ -93,11 +92,11 @@ def testMutableItem(self): """) def testBadTupleClassGetItem(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" v = type((3, "")) - w = v[0] + w = v[0] # not-indexable[e] """) - self.assertErrorLogIs(errors, [(2, "not-indexable", r"tuple")]) + self.assertErrorRegexes(errors, {"e": r"tuple"}) def testTupleIsInstance(self): ty = self.Infer(""" diff --git a/pytype/tests/test_type_comments.py b/pytype/tests/test_type_comments.py index a0885ec8f..11d3f3771 100644 --- a/pytype/tests/test_type_comments.py +++ b/pytype/tests/test_type_comments.py @@ -73,22 +73,20 @@ def foo(x: int, y: str, z: float) -> None """) def testFunctionCommentOnColon(self): - _, errors = self.InferWithErrors(""" + self.InferWithErrors(""" def f(x) \\ : # type: (None) -> None - return True + return True # bad-return-type """) - self.assertErrorLogIs(errors, [(4, "bad-return-type")]) def testMultipleFunctionComments(self): _, errors = self.InferWithErrors(""" def f(x): # type: (None) -> bool - # type: (str) -> str + # type: (str) -> str # ignored-type-comment[e] return True """) - self.assertErrorLogIs(errors, [(4, "ignored-type-comment", - r"Stray type comment:.*str")]) + self.assertErrorRegexes(errors, {"e": r"Stray type comment:.*str"}) def testFunctionNoneInArgs(self): ty = self.Infer(""" @@ -183,85 +181,75 @@ class A: def testTypeCommentAfterDocstring(self): """Type comments after the docstring should not be picked up.""" - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def foo(x, y): '''Ceci n'est pas une type.''' - # type: (int, str) -> None + # type: (int, str) -> None # ignored-type-comment """) - self.assertErrorLogIs(errors, [(3, "ignored-type-comment")]) def testFunctionNoReturn(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def foo(): - # type: () -> + # type: () -> # invalid-function-type-comment pass """) - self.assertErrorLogIs(errors, [(2, "invalid-function-type-comment")]) def testFunctionTooManyArgs(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def foo(x): - # type: (int, str) -> None + # type: (int, str) -> None # invalid-function-type-comment[e] y = x return x """) - self.assertErrorLogIs(errors, [(2, "invalid-function-type-comment", - r"Expected 1 args, 2 given")]) + self.assertErrorRegexes(errors, {"e": r"Expected 1 args, 2 given"}) def testFunctionTooFewArgs(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def foo(x, y, z): - # type: (int, str) -> None + # type: (int, str) -> None # invalid-function-type-comment[e] y = x return x """) - self.assertErrorLogIs(errors, [(2, "invalid-function-type-comment", - r"Expected 3 args, 2 given")]) + self.assertErrorRegexes(errors, {"e": r"Expected 3 args, 2 given"}) def testFunctionTooFewArgsDoNotCountSelf(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def foo(self, x, y, z): - # type: (int, str) -> None + # type: (int, str) -> None # invalid-function-type-comment[e] y = x return x """) - self.assertErrorLogIs(errors, [(2, "invalid-function-type-comment", - r"Expected 3 args, 2 given")]) + self.assertErrorRegexes(errors, {"e": r"Expected 3 args, 2 given"}) def testFunctionMissingArgs(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def foo(x): - # type: () -> int + # type: () -> int # invalid-function-type-comment return x """) - self.assertErrorLogIs(errors, [(2, "invalid-function-type-comment")]) def testInvalidFunctionTypeComment(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" def foo(x): - # type: blah blah blah + # type: blah blah blah # invalid-function-type-comment return x """) - self.assertErrorLogIs(errors, [(2, "invalid-function-type-comment", - r"blah blah blah")]) def testInvalidFunctionArgs(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def foo(x): - # type: (abc def) -> int + # type: (abc def) -> int # invalid-function-type-comment[e] return x """) - self.assertErrorLogIs(errors, [(2, "invalid-function-type-comment", - r"abc def.*unexpected EOF")]) + self.assertErrorRegexes(errors, {"e": r"abc def.*unexpected EOF"}) def testAmbiguousAnnotation(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def foo(x): - # type: (int if __random__ else str) -> None + # type: (int if __random__ else str) -> None # invalid-function-type-comment[e] pass """) - self.assertErrorLogIs(errors, [(2, "invalid-function-type-comment", - r"int.*str.*constant")]) + self.assertErrorRegexes(errors, {"e": r"int.*str.*constant"}) class AssignmentCommentTest(test_base.TargetIndependentTest): @@ -333,41 +321,38 @@ def f() -> Tuple[Mapping, dict]: ... """) def testBadComment(self): - ty, errors = self.InferWithErrors("""\ - X = None # type: abc def + ty, errors = self.InferWithErrors(""" + X = None # type: abc def # invalid-type-comment[e] """, deep=True) - self.assertErrorLogIs(errors, [(1, "invalid-type-comment", - r"abc def.*unexpected EOF")]) + self.assertErrorRegexes(errors, {"e": r"abc def.*unexpected EOF"}) self.assertTypesMatchPytd(ty, """ from typing import Any X = ... # type: Any """) def testConversionError(self): - ty, errors = self.InferWithErrors("""\ - X = None # type: 1 if __random__ else 2 + ty, errors = self.InferWithErrors(""" + X = None # type: 1 if __random__ else 2 # invalid-type-comment[e] """, deep=True) - self.assertErrorLogIs(errors, [(1, "invalid-type-comment", - r"1 if __random__ else 2.*constant")]) + self.assertErrorRegexes(errors, {"e": r"1 if __random__ else 2.*constant"}) self.assertTypesMatchPytd(ty, """ from typing import Any X = ... # type: Any """) def testNameErrorInsideComment(self): - _, errors = self.InferWithErrors("""\ - X = None # type: Foo + _, errors = self.InferWithErrors(""" + X = None # type: Foo # invalid-type-comment[e] """, deep=True) - self.assertErrorLogIs(errors, [(1, "invalid-type-comment", r"Foo")]) + self.assertErrorRegexes(errors, {"e": r"Foo"}) def testWarnOnIgnoredTypeComment(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" X = [] - X[0] = None # type: str - # type: int + X[0] = None # type: str # ignored-type-comment[e1] + # type: int # ignored-type-comment[e2] """, deep=True) - self.assertErrorLogIs(errors, [(2, "ignored-type-comment", r"str"), - (3, "ignored-type-comment", r"int")]) + self.assertErrorRegexes(errors, {"e1": r"str", "e2": r"int"}) def testAttributeInitialization(self): ty = self.Infer(""" @@ -393,17 +378,16 @@ def testNoneToNoneType(self): """) def testModuleInstanceAsBadTypeComment(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" import sys - x = None # type: sys + x = None # type: sys # invalid-annotation[e] """) - self.assertErrorLogIs(errors, [(2, "invalid-annotation", - r"instance of module.*x")]) + self.assertErrorRegexes(errors, {"e": r"instance of module.*x"}) def testForwardReference(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" a = None # type: "A" - b = None # type: "Nonexistent" + b = None # type: "Nonexistent" # name-error[e] class A(object): def __init__(self): self.x = 42 @@ -418,30 +402,30 @@ def f(self) -> int a = ... # type: A b = ... # type: Any """) - self.assertErrorLogIs(errors, [(2, "name-error", r"Nonexistent")]) + self.assertErrorRegexes(errors, {"e": r"Nonexistent"}) def testClassVariableForwardReference(self): - ty = self.Infer("""\ + ty = self.Infer(""" class A(object): a = None # type: 'A' def __init__(self): self.x = 42 """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ class A(object): a: A x: int """) def testUseForwardReference(self): - ty = self.Infer("""\ + ty = self.Infer(""" a = None # type: "A" x = a.x class A(object): def __init__(self): self.x = 42 """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any class A(object): x = ... # type: int @@ -451,7 +435,7 @@ class A(object): def testUseClassVariableForwardReference(self): # Attribute accesses for A().a all get resolved to Any (b/134706992) - ty = self.Infer("""\ + ty = self.Infer(""" class A(object): a = None # type: 'A' def f(self): @@ -461,7 +445,7 @@ def g(): return A().a y = g() """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any, TypeVar _TA = TypeVar('_TA', bound=A) class A(object): @@ -473,32 +457,30 @@ def g() -> A: ... """) def testClassVariableForwardReferenceError(self): - _, err = self.InferWithErrors("""\ + self.InferWithErrors(""" class A(object): a = None # type: 'A' - g = A().a.foo() + g = A().a.foo() # attribute-error """) - self.assertErrorLogIs(err, [(3, "attribute-error")]) def testMultilineValue(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" v = [ { - "a": 1 # type: complex + "a": 1 # type: complex # ignored-type-comment[e1] - } # type: dict[str, int] + } # type: dict[str, int] # ignored-type-comment[e2] ] # type: list[dict[str, float]] """) self.assertTypesMatchPytd(ty, """ v = ... # type: list[dict[str, float]] """) - self.assertErrorLogIs(errors, [(3, "ignored-type-comment", - r"Stray type comment: complex"), - (5, "ignored-type-comment", - r"Stray type comment: dict\[str, int\]")]) + self.assertErrorRegexes(errors, { + "e1": r"Stray type comment: complex", + "e2": r"Stray type comment: dict\[str, int\]"}) def testMultilineValueWithBlankLines(self): - ty = self.Infer("""\ + ty = self.Infer(""" a = [[ ] @@ -510,24 +492,22 @@ def testMultilineValueWithBlankLines(self): """) def testTypeCommentNameError(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(): - x = None # type: Any + x = None # type: Any # invalid-type-comment[e] """, deep=True) - self.assertErrorLogIs( - errors, [(2, "invalid-type-comment", r"not defined$")]) + self.assertErrorRegexes(errors, {"e": r"not defined$"}) def testTypeCommentInvalidSyntax(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" def f(): - x = None # type: y = 1 + x = None # type: y = 1 # invalid-type-comment[e] """, deep=True) - self.assertErrorLogIs( - errors, [(2, "invalid-type-comment", r"invalid syntax$")]) + self.assertErrorRegexes(errors, {"e": r"invalid syntax$"}) def testDiscardedTypeComment(self): """Discard the first whole-line comment, keep the second.""" - ty = self.Infer("""\ + ty = self.Infer(""" # We want either # type: ignore or # type: int def hello_world(): # type: () -> str @@ -539,15 +519,14 @@ def hello_world() -> str: ... def testMultipleTypeComments(self): """We should not allow multiple type comments on one line.""" - _, errors = self.InferWithErrors("""\ - a = 42 # type: int # type: float + _, errors = self.InferWithErrors(""" + a = 42 # type: int # type: float # invalid-directive[e] """) - self.assertErrorLogIs( - errors, [(1, "invalid-directive", r"Multiple")]) + self.assertErrorRegexes(errors, {"e": r"Multiple"}) def testMultipleDirectives(self): """We should support multiple directives on one line.""" - self.Check("""\ + self.Check(""" a = list() # type: list[int, str] # pytype: disable=invalid-type-comment b = list() # pytype: disable=invalid-type-comment # type: list[int, str] def foo(x): pass @@ -555,13 +534,13 @@ def foo(x): pass """) def testNestedCommentAlias(self): - ty = self.Infer("""\ + ty = self.Infer(""" class A(object): pass class B(object): C = A x = None # type: C """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Type class A(object): pass class B(object): @@ -570,12 +549,12 @@ class B(object): """) def testNestedClassesComments(self): - ty = self.Infer("""\ + ty = self.Infer(""" class A(object): class B(object): pass x = None # type: B """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import Any class A(object): B = ... # type: type @@ -583,7 +562,7 @@ class A(object): """) def testListComprehensionComments(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List def f(x): # type: (str) -> None @@ -593,38 +572,37 @@ def g(xs): ys = [f(x) for x in xs] # type: List[str] return ys """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ from typing import List def f(x: str) -> None: ... def g(xs: List[str]) -> List[str]: ... """) def testMultipleAssignments(self): - ty = self.Infer("""\ + ty = self.Infer(""" a = 1; b = 2; c = 4 # type: float """) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ a = ... # type: int b = ... # type: int c = ... # type: float """) def testRecursiveTypeAlias(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import List, Union Foo = Union[str, List['Foo']] - x = 'hello' # type: Foo + x = 'hello' # type: Foo # not-supported-yet[e] """) - self.assertErrorLogIs(errors, [(3, "not-supported-yet", - r"Recursive.*Foo")]) + self.assertErrorRegexes(errors, {"e": r"Recursive.*Foo"}) def testInstantiateFullyQuotedType(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import Optional x = None # type: "Optional[A]" class A(object): a = 0 - y = x.a + y = x.a # attribute-error[e] """) self.assertTypesMatchPytd(ty, """ from typing import Optional @@ -633,7 +611,7 @@ class A(object): a: int y: int """) - self.assertErrorLogIs(errors, [(5, "attribute-error", r"a.*None")]) + self.assertErrorRegexes(errors, {"e": r"a.*None"}) def testDoNotResolveLateTypeToFunction(self): ty = self.Infer(""" @@ -649,19 +627,17 @@ def A(self) -> None: ... """) def testIllegalFunctionLateType(self): - errors = self.CheckWithErrors("""\ - v = None # type: "F" + self.CheckWithErrors(""" + v = None # type: "F" # invalid-annotation def F(): pass """) - self.assertErrorLogIs(errors, [(1, "invalid-annotation")]) def testBadTypeCommentInConstructor(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" class Foo(object): def __init__(self): - self.x = None # type: "Bar" + self.x = None # type: "Bar" # name-error """) - self.assertErrorLogIs(errors, [(3, "name-error")]) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_typevar.py b/pytype/tests/test_typevar.py index ace53ac3f..b8f1b2f42 100644 --- a/pytype/tests/test_typevar.py +++ b/pytype/tests/test_typevar.py @@ -20,7 +20,7 @@ def testUnusedTypeVar(self): def testImportTypeVar(self): with file_utils.Tempdir() as d: d.create_file("a.pyi", """T = TypeVar("T")""") - ty = self.Infer("""\ + ty = self.Infer(""" from a import T """, deep=False, pythonpath=[d.path]) self.assertTypesMatchPytd(ty, """ @@ -29,16 +29,16 @@ def testImportTypeVar(self): """) def testInvalidTypeVar(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" from typing import TypeVar typevar = TypeVar - T = typevar() + T = typevar() # invalid-typevar[e1] T = typevar("T") # ok - T = typevar(42) - T = typevar(str()) - T = typevar("T", str, int if __random__ else float) - T = typevar("T", 0, float) - T = typevar("T", str) + T = typevar(42) # invalid-typevar[e2] + T = typevar(str()) # invalid-typevar[e3] + T = typevar("T", str, int if __random__ else float) # invalid-typevar[e4] + T = typevar("T", 0, float) # invalid-typevar[e5] + T = typevar("T", str) # invalid-typevar[e6] # pytype: disable=not-supported-yet S = typevar("S", covariant=False) # ok T = typevar("T", covariant=False) # duplicate ok @@ -50,14 +50,11 @@ def testInvalidTypeVar(self): S = TypeVar("S") T = TypeVar("T") """) - self.assertErrorLogIs(errors, [ - (3, "invalid-typevar", r"wrong arguments"), - (5, "invalid-typevar", r"Expected.*str.*Actual.*int"), - (6, "invalid-typevar", r"constant str"), - (7, "invalid-typevar", r"must be constant"), - (8, "invalid-typevar", r"Expected.*_1:.*type.*Actual.*_1: int"), - (9, "invalid-typevar", r"0 or more than 1"), - ]) + self.assertErrorRegexes(errors, { + "e1": r"wrong arguments", "e2": r"Expected.*str.*Actual.*int", + "e3": r"constant str", "e4": r"must be constant", + "e5": r"Expected.*_1:.*type.*Actual.*_1: int", "e6": r"0 or more than 1" + }) def testPrintConstraints(self): ty = self.Infer(""" @@ -114,17 +111,15 @@ def return_arg_or_42(x: _T0) -> Union[_T0, int] """) def testTypeVarInTypeComment(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import List, TypeVar T = TypeVar("T") - x = None # type: T - y = None # type: List[T] + x = None # type: T # not-supported-yet + y = None # type: List[T] # not-supported-yet """) - self.assertErrorLogIs(errors, [(3, "not-supported-yet"), - (4, "not-supported-yet")]) def testBaseClassWithTypeVar(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import List, TypeVar T = TypeVar("T") class A(List[T]): pass @@ -145,41 +140,33 @@ class X(l): pass """) def testBound(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import TypeVar - T = TypeVar("T", int, float, bound=str) - S = TypeVar("S", bound="") + T = TypeVar("T", int, float, bound=str) # invalid-typevar + S = TypeVar("S", bound="") # invalid-typevar U = TypeVar("U", bound=str) # ok - V = TypeVar("V", bound=int if __random__ else float) + V = TypeVar("V", bound=int if __random__ else float) # invalid-typevar """) - self.assertErrorLogIs(errors, [ - (2, "invalid-typevar", r"mutually exclusive"), - (3, "invalid-typevar", r"empty string"), - (5, "invalid-typevar", r"must be constant")]) def testCovariant(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar - T = TypeVar("T", covariant=True) - S = TypeVar("S", covariant=42) - U = TypeVar("U", covariant=True if __random__ else False) + T = TypeVar("T", covariant=True) # not-supported-yet + S = TypeVar("S", covariant=42) # invalid-typevar[e1] + U = TypeVar("U", covariant=True if __random__ else False) # invalid-typevar[e2] """) - self.assertErrorLogIs(errors, [ - (2, "not-supported-yet"), - (3, "invalid-typevar", r"Expected.*bool.*Actual.*int"), - (4, "invalid-typevar", r"constant")]) + self.assertErrorRegexes( + errors, {"e1": r"Expected.*bool.*Actual.*int", "e2": r"constant"}) def testContravariant(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar - T = TypeVar("T", contravariant=True) - S = TypeVar("S", contravariant=42) - U = TypeVar("U", contravariant=True if __random__ else False) + T = TypeVar("T", contravariant=True) # not-supported-yet + S = TypeVar("S", contravariant=42) # invalid-typevar[e1] + U = TypeVar("U", contravariant=True if __random__ else False) # invalid-typevar[e2] """) - self.assertErrorLogIs(errors, [ - (2, "not-supported-yet"), - (3, "invalid-typevar", r"Expected.*bool.*Actual.*int"), - (4, "invalid-typevar", r"constant")]) + self.assertErrorRegexes( + errors, {"e1": r"Expected.*bool.*Actual.*int", "e2": r"constant"}) def testDontPropagatePyval(self): # in functions like f(x: T) -> T, if T has constraints we should not copy @@ -379,22 +366,20 @@ def testStoreTypeVarInDict(self): """) def testLateBound(self): - _, errors = self.InferWithErrors("""\ + _, errors = self.InferWithErrors(""" from typing import TypeVar, Union - T = TypeVar("T", int, float, bound="str") - S = TypeVar("S", bound="") + T = TypeVar("T", int, float, bound="str") # invalid-typevar[e1] + S = TypeVar("S", bound="") # invalid-typevar[e2] U = TypeVar("U", bound="str") # ok - V = TypeVar("V", bound="int if __random__ else float") + V = TypeVar("V", bound="int if __random__ else float") # invalid-typevar[e3] W = TypeVar("W", bound="Foo") # ok, forward reference - X = TypeVar("X", bound="Bar") + X = TypeVar("X", bound="Bar") # name-error[e4] class Foo: pass """) - self.assertErrorLogIs(errors, [ - (2, "invalid-typevar", r"mutually exclusive"), - (3, "invalid-typevar", r"empty string"), - (5, "invalid-typevar", r"Must be constant"), - (7, "name-error", r"Name.*Bar")]) + self.assertErrorRegexes(errors, { + "e1": r"mutually exclusive", "e2": r"empty string", + "e3": r"Must be constant", "e4": r"Name.*Bar"}) def testLateConstraints(self): ty = self.Infer(""" diff --git a/pytype/tests/test_typing.py b/pytype/tests/test_typing.py index e937a94f8..342ec5e53 100644 --- a/pytype/tests/test_typing.py +++ b/pytype/tests/test_typing.py @@ -38,10 +38,10 @@ def test_cast2(self): """) def test_process_annotation_for_cast(self): - ty, errors = self.InferWithErrors("""\ + ty, _ = self.InferWithErrors(""" import typing v1 = typing.cast(None, __any_object__) - v2 = typing.cast(typing.Union, __any_object__) + v2 = typing.cast(typing.Union, __any_object__) # invalid-annotation v3 = typing.cast("A", __any_object__) class A(object): pass @@ -53,24 +53,20 @@ class A(object): v3: A class A(object): ... """) - self.assertErrorLogIs(errors, [(3, "invalid-annotation")]) def test_no_typevars_for_cast(self): - _, errors = self.InferWithErrors("""\ + self.InferWithErrors(""" from typing import cast, AnyStr, Type, TypeVar, _T def f(x): - return cast(AnyStr, x) + return cast(AnyStr, x) # invalid-typevar f("hello") def g(x): - return cast(AnyStr if __random__ else int, x) + return cast(AnyStr if __random__ else int, x) # invalid-typevar g("quack") """) - self.assertErrorLogIs(errors, - [(3, "invalid-typevar"), - (6, "invalid-typevar")]) def test_cast_args(self): - self.assertNoCrash(self.Check, """\ + self.assertNoCrash(self.Check, """ import typing typing.cast(typing.AnyStr) typing.cast("str") @@ -93,7 +89,7 @@ def test_generate_type_alias(self): """) def test_protocol(self): - self.Check("""\ + self.Check(""" from typing_extensions import Protocol class Foo(Protocol): pass """) @@ -104,13 +100,13 @@ def test_recursive_tuple(self): from typing import Tuple class Foo(Tuple[Foo]): ... """) - self.Check("""\ + self.Check(""" import foo foo.Foo() """, pythonpath=[d.path]) def test_base_class(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import Iterable class Foo(Iterable): pass @@ -121,7 +117,7 @@ class Foo(Iterable): ... """) def test_type_checking(self): - self.Check("""\ + self.Check(""" import typing if typing.TYPE_CHECKING: pass @@ -130,7 +126,7 @@ def test_type_checking(self): """) def test_not_type_checking(self): - self.Check("""\ + self.Check(""" import typing if not typing.TYPE_CHECKING: name_error @@ -141,24 +137,19 @@ def test_not_type_checking(self): def test_new_type_arg_error(self): _, errors = self.InferWithErrors(""" from typing import NewType - MyInt = NewType(int, 'MyInt') - MyStr = NewType(tp='str', name='MyStr') - MyFunnyNameType = NewType(name=123 if __random__ else 'Abc', tp=int) - MyFunnyType = NewType(name='Abc', tp=int if __random__ else 'int') + MyInt = NewType(int, 'MyInt') # wrong-arg-types[e1] + MyStr = NewType(tp='str', name='MyStr') # wrong-arg-types[e2] + MyFunnyNameType = NewType(name=123 if __random__ else 'Abc', tp=int) # wrong-arg-types[e3] + MyFunnyType = NewType(name='Abc', tp=int if __random__ else 'int') # wrong-arg-types[e4] """) - self.assertErrorLogIs( - errors, - [(3, "wrong-arg-types", - r".*Expected:.*str.*\nActually passed:.*Type\[int\].*"), - (4, "wrong-arg-types", - r".*Expected:.*type.*\nActually passed:.*str.*"), - (5, "wrong-arg-types", - r".*Expected:.*str.*\nActually passed:.*Union.*"), - (6, "wrong-arg-types", - r".*Expected:.*type.*\nActually passed:.*Union.*"),]) + self.assertErrorRegexes(errors, { + "e1": r".*Expected:.*str.*\nActually passed:.*Type\[int\].*", + "e2": r".*Expected:.*type.*\nActually passed:.*str.*", + "e3": r".*Expected:.*str.*\nActually passed:.*Union.*", + "e4": r".*Expected:.*type.*\nActually passed:.*Union.*"}) def test_classvar(self): - ty = self.Infer("""\ + ty = self.Infer(""" from typing import ClassVar class A(object): x = 5 # type: ClassVar[int] @@ -187,18 +178,19 @@ def test_pyi_classvar_argcount(self): class X: v: ClassVar[int, int] """) - errors = self.CheckWithErrors("""\ - import foo + errors = self.CheckWithErrors(""" + import foo # pyi-error[e] """, pythonpath=[d.path]) - self.assertErrorLogIs(errors, [(1, "pyi-error", r"ClassVar.*1.*2")]) + self.assertErrorRegexes(errors, {"e": r"ClassVar.*1.*2"}) class LiteralTest(test_base.TargetIndependentTest): """Tests for typing.Literal.""" def test_py(self): - errors = self.CheckWithErrors("from typing import Literal") - self.assertErrorLogIs(errors, [(1, "not-supported-yet")]) + self.CheckWithErrors(""" + from typing import Literal # not-supported-yet + """) def test_pyi_parameter(self): with file_utils.Tempdir() as d: diff --git a/pytype/tests/test_typing_methods.py b/pytype/tests/test_typing_methods.py index b918e0782..287b5ca66 100644 --- a/pytype/tests/test_typing_methods.py +++ b/pytype/tests/test_typing_methods.py @@ -16,7 +16,7 @@ def _check_call(self, t, expr): # pylint: disable=invalid-name def f() -> %(type)s """ % {"type": t}) indented_expr = textwrap.dedent(expr).replace("\n", "\n" + " "*8) - self.Check("""\ + self.Check(""" import foo x = foo.f() %(expr)s @@ -64,7 +64,7 @@ def test_io(self): from typing import IO def f() -> IO[str] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo x = foo.f() with x as fi: @@ -120,7 +120,7 @@ def test_sequence_and_tuple(self): def seq() -> Sequence[str] def tpl() -> Tuple[str] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo for seq in [foo.seq(), foo.tpl()]: a = seq[0] @@ -150,7 +150,7 @@ def test_mutablesequence_and_list(self): def seq() -> MutableSequence[str] def lst() -> List[str] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo for seq in [foo.seq(), foo.lst()]: seq[0] = 3 @@ -184,7 +184,7 @@ def test_deque(self): from typing import Deque def deq() -> Deque[int] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo q = foo.deq() q[0] = 3 @@ -197,7 +197,7 @@ def deq() -> Deque[int] cl = q.popleft() d = q.rotate(3) """, deep=False, pythonpath=[d.path]) - self.assertTypesMatchPytd(ty, """\ + self.assertTypesMatchPytd(ty, """ foo = ... # type: module from typing import Deque q = ... # type: Deque[int] @@ -219,7 +219,7 @@ def test_mutablemapping(self): class MyDict(MutableMapping[K, V]): ... def f() -> MyDict[str, int] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo m = foo.f() m.clear() @@ -252,7 +252,7 @@ def test_abstractset(self): from typing import AbstractSet def f() -> AbstractSet[str] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo x = foo.f() a = "bar" in x @@ -284,7 +284,7 @@ def test_mutableset(self): from typing import MutableSet def f() -> MutableSet[str] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo x = foo.f() x.add(1) @@ -330,7 +330,7 @@ def test_pattern_and_match(self): from typing import Pattern def f() -> Pattern[str] """) - ty = self.Infer("""\ + ty = self.Infer(""" import foo pattern = foo.f() m1 = pattern.search("foo") diff --git a/pytype/tests/test_typing_namedtuple.py b/pytype/tests/test_typing_namedtuple.py index 983006382..1bb8177f7 100644 --- a/pytype/tests/test_typing_namedtuple.py +++ b/pytype/tests/test_typing_namedtuple.py @@ -7,104 +7,82 @@ class NamedTupleTest(test_base.TargetIndependentTest): """Tests for the typing.NamedTuple overlay.""" def test_basic_calls(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import typing Basic = typing.NamedTuple("Basic", [('a', str)]) ex = Basic("hello world") ea = ex.a - ey = Basic() # Should fail - ez = Basic("a", "b") # Should fail + ey = Basic() # missing-parameter + ez = Basic("a", "b") # wrong-arg-count """) - self.assertErrorLogIs(errors, [ - (5, "missing-parameter"), - (6, "wrong-arg-count")]) def test_optional_field_type(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import typing X = typing.NamedTuple("X", [('a', str), ('b', typing.Optional[int])]) xa = X('hello', None) xb = X('world', 2) - xc = X('nope', '2') # Should fail - xd = X() # Should fail - xe = X(1, "nope") # Should fail + xc = X('nope', '2') # wrong-arg-types + xd = X() # missing-parameter + xe = X(1, "nope") # wrong-arg-types """) - self.assertErrorLogIs(errors, [ - (5, "wrong-arg-types"), - (6, "missing-parameter"), - (7, "wrong-arg-types")]) def test_class_field_type(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import typing class Foo(object): pass Y = typing.NamedTuple("Y", [('a', str), ('b', Foo)]) ya = Y('a', Foo()) - yb = Y('a', 1) # Should fail - yc = Y(Foo()) # Should fail - yd = Y(1) # Should fail + yb = Y('a', 1) # wrong-arg-types + yc = Y(Foo()) # missing-parameter + yd = Y(1) # missing-parameter """) - self.assertErrorLogIs(errors, [ - (6, "wrong-arg-types"), - (7, "missing-parameter"), - (8, "missing-parameter")]) def test_late_annotation(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" import typing class Foo(object): pass X = typing.NamedTuple("X", [('a', 'Foo')]) # should be fine - Y = typing.NamedTuple("Y", [('a', 'Bar')]) # should fail + Y = typing.NamedTuple("Y", [('a', 'Bar')]) # should fail # name-error[e] """) - self.assertErrorLogIs(errors, [(5, "name-error", "Bar")]) + self.assertErrorRegexes(errors, {"e": r"Bar"}) def test_nested_containers(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import typing Z = typing.NamedTuple("Z", [('a', typing.List[typing.Optional[int]])]) za = Z([1]) zb = Z([None, 2]) - zc = Z(1) # Should fail + zc = Z(1) # wrong-arg-types import typing A = typing.NamedTuple("A", [('a', typing.Dict[int, str]), ('b', typing.Tuple[int, int])]) aa = A({1: '1'}, (1, 2)) ab = A({}, (1, 2)) - ac = A(1, 2) # Should fail + ac = A(1, 2) # wrong-arg-types """) - self.assertErrorLogIs(errors, [ - (5, "wrong-arg-types"), - (11, "wrong-arg-types")]) def test_pytd_field(self): - errors = self.CheckWithErrors("""\ + self.CheckWithErrors(""" import typing import datetime B = typing.NamedTuple("B", [('a', datetime.date)]) ba = B(datetime.date(1,2,3)) - bb = B() # Should fail - bc = B(1) # Should fail + bb = B() # missing-parameter + bc = B(1) # wrong-arg-types """) - self.assertErrorLogIs(errors, [ - (5, "missing-parameter"), - (6, "wrong-arg-types")]) def test_bad_calls(self): - _, errorlog = self.InferWithErrors("""\ + self.InferWithErrors(""" import typing - typing.NamedTuple("_", ["abc", "def", "ghi"]) + typing.NamedTuple("_", ["abc", "def", "ghi"]) # wrong-arg-types # "def" is a keyword, so the call on the next line fails. - typing.NamedTuple("_", [("abc", int), ("def", int), ("ghi", int)]) - typing.NamedTuple("1", [("a", int)]) - typing.NamedTuple("_", [[int, "a"]]) + typing.NamedTuple("_", [("abc", int), ("def", int), ("ghi", int)]) # invalid-namedtuple-arg + typing.NamedTuple("1", [("a", int)]) # invalid-namedtuple-arg + typing.NamedTuple("_", [[int, "a"]]) # wrong-arg-types """) - self.assertErrorLogIs(errorlog, - [(2, "wrong-arg-types"), - (4, "invalid-namedtuple-arg"), - (5, "invalid-namedtuple-arg"), - (6, "wrong-arg-types")]) def test_empty_args(self): self.Check( @@ -114,31 +92,30 @@ def test_empty_args(self): """) def test_tuple_fields(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import NamedTuple X = NamedTuple("X", (("a", str),)) X(a="") - X(a=42) + X(a=42) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) def test_list_field(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import NamedTuple X = NamedTuple("X", [["a", str]]) X(a="") - X(a=42) + X(a=42) # wrong-arg-types[e] """) - self.assertErrorLogIs(errors, [(4, "wrong-arg-types", r"str.*int")]) + self.assertErrorRegexes(errors, {"e": r"str.*int"}) def test_str_fields_error(self): - errors = self.CheckWithErrors("""\ + errors = self.CheckWithErrors(""" from typing import NamedTuple - X = NamedTuple("X", "a b") - Y = NamedTuple("Y", ["ab"]) + X = NamedTuple("X", "a b") # wrong-arg-types[e1] + Y = NamedTuple("Y", ["ab"]) # wrong-arg-types[e2] """) - self.assertErrorLogIs(errors, [(2, "wrong-arg-types", r"List.*str"), - (3, "wrong-arg-types", r"Tuple.*str")]) + self.assertErrorRegexes(errors, {"e1": r"List.*str", "e2": r"Tuple.*str"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_unions.py b/pytype/tests/test_unions.py index 006aaf7ba..f5e6550b8 100644 --- a/pytype/tests/test_unions.py +++ b/pytype/tests/test_unions.py @@ -24,22 +24,19 @@ def f(b, x, y) -> int or float """) def testCall(self): - ty, errors = self.InferWithErrors("""\ + ty, errors = self.InferWithErrors(""" def f(): x = 42 if __random__: # Should not appear in output - x.__class__ = float - x.__class__ = str + x.__class__ = float # not-writable[e1] + x.__class__ = str # not-writable[e2] return type(x)() """, deep=True) self.assertTypesMatchPytd(ty, """ def f() -> int """) - self.assertErrorLogIs(errors, [ - (5, "not-writable", "int"), - (6, "not-writable", "int"), - ]) + self.assertErrorRegexes(errors, {"e1": r"int", "e2": r"int"}) test_base.main(globals(), __name__ == "__main__") diff --git a/pytype/tests/test_utils.py b/pytype/tests/test_utils.py index 7c5e4172b..96ca3b4b8 100644 --- a/pytype/tests/test_utils.py +++ b/pytype/tests/test_utils.py @@ -1,6 +1,7 @@ """Utility class and function for tests.""" import collections +import itertools import re import subprocess import tokenize @@ -158,13 +159,13 @@ class TestCollectionsMixin(object): """Mixin providing utils for tests on the collections module.""" def _testCollectionsObject(self, obj, good_arg, bad_arg, error): # pylint: disable=invalid-name - result = self.CheckWithErrors("""\ + result = self.CheckWithErrors(""" import collections def f(x: collections.{obj}): ... f({good_arg}) - f({bad_arg}) # line 5 + f({bad_arg}) # wrong-arg-types[e] """.format(obj=obj, good_arg=good_arg, bad_arg=bad_arg)) - self.assertErrorLogIs(result, [(4, "wrong-arg-types", error)]) + self.assertErrorRegexes(result, {"e": error}) class MakeCodeMixin(object): @@ -187,8 +188,8 @@ class TestErrorLog(errors.ErrorLog): holding parsed comment directives. Attributes: - marks: { mark_name : line number } - expected: { line number : expected error code } + marks: { mark_name : errors.Error object } + expected: { line number : sequence of expected error codes and mark names } Also adds an assertion matcher to match self.errors against a list of expected errors of the form [(line number, error code, message regex)]. @@ -196,104 +197,79 @@ class TestErrorLog(errors.ErrorLog): See tests/test_base_test.py for usage examples. """ - MARK_RE = re.compile(r"^[.]\w+$") - ERROR_RE = re.compile(r"^\w[\w-]+\w$") + ERROR_RE = re.compile(r"^(?P(\w+-)+\w+)(\[(?P.+)\])?$") def __init__(self, src): super(TestErrorLog, self).__init__() - self.marks, self.expected = self._parse_comments(src) + self.marks = None # set by assert_errors_match_expected() + self.expected = self._parse_comments(src) - def assert_expected_errors(self, expected_errors): - expected_errors = collections.Counter(expected_errors) - # This is O(|errorlog| * |expected_errors|), which is okay because error - # lists in tests are short. - for error in self.unique_sorted_errors(): - almost_matches = set() - for (pattern, count) in expected_errors.items(): - line, name, regexp = self._parse_expected_error(pattern) - # We should only call this function after resolving marks - assert isinstance(line, int), "Unresolved mark %s" % line - if line == error.lineno and name == error.name: - if not regexp or re.search(regexp, error.message, flags=re.DOTALL): - if count == 1: - del expected_errors[pattern] - else: - expected_errors[pattern] -= 1 - break - else: - almost_matches.add(regexp) - else: - self.print_to_stderr() - if almost_matches: - raise AssertionError("Bad error message: expected %r, got %r" % ( - almost_matches.pop(), error.message)) - else: - raise AssertionError("Unexpected error:\n%s" % error) - if expected_errors: + def _fail(self, msg): + if self.marks: self.print_to_stderr() - leftover_errors = [ - self._parse_expected_error(pattern) for pattern in expected_errors] - raise AssertionError("Errors not found:\n" + "\n".join( - "Line %d: %r [%s]" % (e[0], e[2], e[1]) for e in leftover_errors)) - - def make_expected_errors(self, expected_errors): - """Rewrite expected_errors, resolving marks and adding comments.""" - expected = [] - - for line, error in self.expected.items(): - expected.append((line, error)) + raise AssertionError(msg) + + def assert_errors_match_expected(self): + # TODO(rechen): The sorted() call can be removed once we stop supporting + # host Python 2, since dictionaries preserve insertion order in Python 3.6+. + expected_errors = itertools.chain.from_iterable( + [(line, code, mark) for (code, mark) in errors] + for line, errors in sorted(self.expected.items())) + self.marks = {} + + def _format_error(line, code, mark=None): + formatted = "Line %d: %s" % (line, code) + if mark: + formatted += "[%s]" % mark + return formatted - for pattern in expected_errors: - line, name, regexp = self._parse_expected_error(pattern) - line = self.marks.get(line, line) - expected.append((line, name, regexp)) - - return expected - - def increment_line_numbers(self, expected_errors): - """Adjust line numbers to account for an ANNOTATIONS_IMPORT line.""" - incremented_expected_errors = [] - for pattern in expected_errors: - line, name, regexp = self._parse_expected_error(pattern) - # We should only call this function after resolving marks - assert isinstance(line, int), "Unresolved mark %s" % line - # Increments the expected line number of the error. - line += 1 - # Increments line numbers in the text of the expected error message. - regexp = re.sub( - r"line (\d+)", lambda m: "line %d" % (int(m.group(1)) + 1), regexp) - incremented_expected_error = (line, name) - if regexp: - incremented_expected_error += (regexp,) - incremented_expected_errors.append(incremented_expected_error) - return incremented_expected_errors - - def _parse_expected_error(self, pattern): - assert 2 <= len(pattern) <= 3, ( - "Bad expected error format. Use: (, [, ])") - line = pattern[0] - name = pattern[1] - regexp = pattern[2] if len(pattern) > 2 else "" - return line, name, regexp + for error in self.unique_sorted_errors(): + try: + line, code, mark = next(expected_errors) + except StopIteration: + self._fail("Unexpected error:\n%s" % error) + if line != error.lineno or code != error.name: + self._fail("Error does not match:\nExpected: %s\nActual: %s" % + (_format_error(line, code, mark), + _format_error(error.lineno, error.name))) + elif mark: + self.marks[mark] = error + leftover_errors = [_format_error(*error) for error in expected_errors] + if leftover_errors: + self._fail("Errors not found:\n" + "\n".join(leftover_errors)) + + def assert_error_regexes(self, expected_regexes): + if self.marks is None: + self.assert_errors_match_expected() # populates self.marks + for mark, error in self.marks.items(): + try: + regex = expected_regexes.pop(mark) + except KeyError: + self._fail("No regex for mark %s" % mark) + if not re.search(regex, error.message, flags=re.DOTALL): + self._fail("Bad error message for mark %s: expected %r, got %r" % + (mark, regex, error.message)) + if expected_regexes: + self._fail("Marks not found in code: %s" % ", ".join(expected_regexes)) def _parse_comments(self, src): - # Strip out the "google type annotations" line if we have added it - we - # already have an assertion in test_base that this is not added manually. - offset = -1 if ANNOTATIONS_IMPORT in src else 0 - src = six.moves.StringIO(src) - marks = {} - expected = {} + expected = collections.defaultdict(list) + used_marks = set() for tok, s, (line, _), _, _ in tokenize.generate_tokens(src.readline): - line = line + offset if tok == tokenize.COMMENT: - comment = s.lstrip("# ").rstrip() - if self.MARK_RE.match(comment): - assert comment not in marks, "Mark %s already used" % comment - marks[comment] = line - elif self.ERROR_RE.match(comment): - expected[line] = comment - return marks, expected + for comment in s.split("#"): + comment = comment.strip() + match = self.ERROR_RE.match(comment) + if not match: + continue + mark = match.group("mark") + if mark: + if mark in used_marks: + self._fail("Mark %s already used" % mark) + used_marks.add(mark) + expected[line].append((match.group("code"), mark)) + return expected class Py2Opcodes(object): diff --git a/pytype/tests/test_with.py b/pytype/tests/test_with.py index 73b2e0e3b..c85f73410 100644 --- a/pytype/tests/test_with.py +++ b/pytype/tests/test_with.py @@ -7,7 +7,7 @@ class TestWithStatement(test_base.TargetIndependentTest): """Tests for the with statement.""" def test_simple_context_manager(self): - self.Check("""\ + self.Check(""" class NullContext(object): def __enter__(self): l.append('i') @@ -31,7 +31,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): """) def test_raise_in_context_manager(self): - self.Check("""\ + self.Check(""" class NullContext(object): def __enter__(self): l.append('i') @@ -58,7 +58,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): """) def test_suppressed_raise_in_context_manager(self): - self.Check("""\ + self.Check(""" class SuppressingContext(object): def __enter__(self): l.append('i') @@ -85,7 +85,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): """) def test_return_in_with(self): - self.Check("""\ + self.Check(""" class NullContext(object): def __enter__(self): l.append('i') @@ -110,7 +110,7 @@ def use_with(val): """) def test_continue_in_with(self): - self.Check("""\ + self.Check(""" class NullContext(object): def __enter__(self): l.append('i') @@ -136,7 +136,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): """) def test_break_in_with(self): - self.Check("""\ + self.Check(""" class NullContext(object): def __enter__(self): l.append('i') @@ -162,7 +162,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): """) def test_raise_in_with(self): - self.Check("""\ + self.Check(""" class NullContext(object): def __enter__(self): l.append('i') @@ -189,7 +189,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): """) def test_at_context_manager_simplified(self): - self.Check("""\ + self.Check(""" import sys class GeneratorContextManager(object): def __init__(self, gen): @@ -239,7 +239,7 @@ def my_context_manager(val): def test_at_context_manager_complete(self): # The complete code for an @contextmanager example, lifted from # the stdlib. - self.Check("""\ + self.Check(""" from functools import partial import sys @@ -311,7 +311,7 @@ def my_context_manager(val): """) def test_tempfile(self): - self.Infer("""\ + self.Infer(""" import tempfile def f(): with tempfile.NamedTemporaryFile(dir="bla", delete=False) as fi: diff --git a/pytype/tools/analyze_project/pytype_runner_test.py b/pytype/tools/analyze_project/pytype_runner_test.py index 3ec3f302a..f3599b608 100644 --- a/pytype/tools/analyze_project/pytype_runner_test.py +++ b/pytype/tools/analyze_project/pytype_runner_test.py @@ -8,6 +8,7 @@ from pytype import module_utils from pytype.tools.analyze_project import parse_args from pytype.tools.analyze_project import pytype_runner +import six import unittest @@ -375,13 +376,13 @@ def test_write(self): # Check that the lines cycle through these patterns. for i, line in enumerate(preamble): if not i % 3: - self.assertRegexpMatches(line, r'rule \w*') + six.assertRegex(self, line, r'rule \w*') elif i % 3 == 1: expected = r' command = {} .* \$in'.format( ' '.join(pytype_runner.PYTYPE_SINGLE)) - self.assertRegexpMatches(line, expected) + six.assertRegex(self, line, expected) else: - self.assertRegexpMatches(line, r' description = \w* \$module') + six.assertRegex(self, line, r' description = \w* \$module') class TestNinjaBuildStatement(TestBase): diff --git a/pytype/tools/traces/source_test.py b/pytype/tools/traces/source_test.py index 75d3c0c3b..bf2ad37a3 100644 --- a/pytype/tools/traces/source_test.py +++ b/pytype/tools/traces/source_test.py @@ -55,20 +55,20 @@ def test_get_offset(self): def test_get_offset_multibyte(self): # With single-byte characters - src = source.Code("""\ + src = source.Code(""" # coding=utf-8 line1 # a line2 """, [], _FakeTrace, "") - self.assertEqual(src.get_offset(source.Location(3, 3)), 40) + self.assertEqual(src.get_offset(source.Location(4, 3)), 41) # With a multibyte character the byte offset should change - src = source.Code("""\ + src = source.Code(""" # coding=utf-8 line1 # ツ line2 """, [], _FakeTrace, "") - self.assertEqual(src.get_offset(source.Location(3, 3)), 42) + self.assertEqual(src.get_offset(source.Location(4, 3)), 43) def test_line(self): src = source.Code("line1\nline2", [], _FakeTrace, "") diff --git a/pytype/tools/traces/traces_test.py b/pytype/tools/traces/traces_test.py index 219ea6c2b..6da13aa0f 100644 --- a/pytype/tools/traces/traces_test.py +++ b/pytype/tools/traces/traces_test.py @@ -76,10 +76,10 @@ def test_external_type(self): self.assertEqual(pyval.cls.name, "foo.Foo") def test_py3_class(self): - src = traces.trace(textwrap.dedent("""\ + src = traces.trace(textwrap.dedent(""" class Foo(object): pass - """), config.Options.create(python_version=(3, 6))) + """).lstrip(), config.Options.create(python_version=(3, 6))) trace, = (x for x in src.traces[1] if x.op == "LOAD_BUILD_CLASS") pyval, = trace.types self.assertEqual(pyval.name, "typing.Callable") @@ -97,7 +97,7 @@ class MatchAstTestCase(unittest.TestCase): """Base class for testing traces.MatchAstVisitor.""" def _parse(self, text, options=None): - text = textwrap.dedent(text) + text = textwrap.dedent(text).lstrip() return ast.parse(text), traces.trace(text, options) def _get_traces(self, text, node_type, options=None): @@ -147,7 +147,7 @@ class MatchAttributeTest(MatchAstTestCase): """Tests for traces.MatchAstVisit.match_Attribute.""" def test_basic(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" x = 0 print(x.real) """, ast.Attribute) @@ -155,7 +155,7 @@ def test_basic(self): ((2, 8), "LOAD_ATTR", "real", ("int", "int"))]) def test_multi(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" class Foo(object): real = True x = 0 @@ -169,7 +169,7 @@ class Foo(object): ((4, 5), "LOAD_ATTR", "real", ("int", "int"))]) def test_property(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" class Foo(object): @property def x(self): @@ -188,14 +188,14 @@ def test_basic(self): self.assertTracesEqual(matches, [((1, 0), "STORE_NAME", "x", ("int",))]) def test_multiline(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" x = (1 + 2) """, ast.Name) self.assertTracesEqual(matches, [((1, 0), "STORE_NAME", "x", ("int",))]) def test_multiline_subscr(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" x = [0] x[0] = (1, 2) @@ -209,7 +209,7 @@ class MatchCallTest(MatchAstTestCase): """Tests for traces.MatchAstVisitor.match_Call.""" def test_basic(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" def f(x): return x + 1.0 f(42) @@ -218,7 +218,7 @@ def f(x): ((3, 0), "CALL_FUNCTION", "f", ("Callable[[Any], Any]", "float"))]) def _test_chain(self, call_method_op): - matches = self._get_traces("""\ + matches = self._get_traces(""" class Foo(object): def f(self, x): return x @@ -237,7 +237,7 @@ def test_chain_37(self): self._test_chain("CALL_METHOD") def test_multiple_bindings(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" class Foo(object): @staticmethod def f(x): @@ -254,7 +254,7 @@ def f(x): ("Callable[[Any], Any]", "Union[int, float]"))]) def test_bad_call(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" def f(): pass f(42) """, ast.Call) @@ -275,7 +275,7 @@ def test_literal_37(self): self._test_literal("CALL_METHOD") def test_lookahead(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" def f(x, y, z): return x + y + z f( @@ -340,7 +340,7 @@ def test_ellipsis(self): class MatchSubscriptTest(MatchAstTestCase): def test_index(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" v = "hello" print(v[0]) """, ast.Subscript) @@ -348,7 +348,7 @@ def test_index(self): matches, [((2, 6), "BINARY_SUBSCR", "__getitem__", ("str",))]) def _test_simple_slice(self, slice_op, method): - matches = self._get_traces("""\ + matches = self._get_traces(""" v = "hello" print(v[:-1]) """, ast.Subscript) @@ -363,7 +363,7 @@ def test_simple_slice_3(self): self._test_simple_slice("BINARY_SUBSCR", "__getitem__") def test_complex_slice(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" v = "hello" print(v[0:4:2]) """, ast.Subscript) @@ -374,7 +374,7 @@ def test_complex_slice(self): class MatchBinOpTest(MatchAstTestCase): def test_modulo(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" v = "hello %s" print(v % "world") """, ast.BinOp) @@ -382,7 +382,7 @@ def test_modulo(self): matches, [((2, 6), "BINARY_MODULO", "__mod__", ("str",))]) def test_modulo_multiline_string(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" ('%s' '%s' % (__any_object__, @@ -401,7 +401,7 @@ def test_basic(self): matches, [((1, 0), "MAKE_FUNCTION", sym, ("Callable[[Any], Any]",))]) def test_function_locals(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" def f(): return lambda x: x.upper() """, ast.Lambda) @@ -412,7 +412,7 @@ def f(): # py2 doesn't have symbol names to distinguish between and . @py3 def test_multiple_functions(self): - matches = self._get_traces("""\ + matches = self._get_traces(""" def f(): return (w for w in range(3)), lambda x: x.upper(), lambda y, z: (y, z) """, ast.Lambda) diff --git a/pytype/tools/xref/callgraph_test.py b/pytype/tools/xref/callgraph_test.py index a4558606f..30df7196d 100644 --- a/pytype/tools/xref/callgraph_test.py +++ b/pytype/tools/xref/callgraph_test.py @@ -43,7 +43,7 @@ def assertHasFunctions(self, fns, expected): self.assertCountEqual(actual, expected) def test_basic(self): - ix = self.index_code("""\ + ix = self.index_code(""" def f(x: str): y = x.strip() return y @@ -77,7 +77,7 @@ def g(y): self.assertParamsEqual(g.params, [("y", "typing.Any")]) def test_remote(self): - code = """\ + code = """ import foo def f(a, b): @@ -111,7 +111,7 @@ def bar() -> int: ... def test_no_outgoing_calls(self): """Capture a function with no outgoing calls.""" - ix = self.index_code("""\ + ix = self.index_code(""" def f(x: int): return "hello" """) @@ -125,7 +125,7 @@ def f(x: int): def test_call_records(self): """Use a function's call records to infer param types.""" - ix = self.index_code("""\ + ix = self.index_code(""" class A: def foo(self, x): return x + "1" diff --git a/pytype/tools/xref/indexer_test.py b/pytype/tools/xref/indexer_test.py index 2ef38e147..389dca8ad 100644 --- a/pytype/tools/xref/indexer_test.py +++ b/pytype/tools/xref/indexer_test.py @@ -58,10 +58,10 @@ class IndexerTest(test_base.TargetIndependentTest, IndexerTestMixin): """Tests for the indexer.""" def test_param_reuse(self): - ix = self.index_code("""\ + ix = self.index_code(""" def f(x): x = 1 # reuse param variable - """) + """.lstrip("\n")) self.assertDef(ix, "module.f", "f", "FunctionDef") self.assertDef(ix, "module.f.x", "x", "Param") self.assertDefLocs(ix, "module.f", [(1, 0)]) @@ -71,7 +71,7 @@ def f(x): "a/b.py, f.py, p/q.py, x/y.py not found") def test_resolved_imports(self): # We need all imports to be valid for pytype - code = """\ + code = """ import f import x.y import a.b as c @@ -202,7 +202,7 @@ def test_literal_attr(self): def test_def_types(self): # Basic sanity test of definition data - ix = self.index_code("""\ + ix = self.index_code(""" def f(): x = 42 return x @@ -219,7 +219,7 @@ def assert_data_type(fqname, cls): assert_data_type("module.f.x", abstract.Instance) def test_make_serializable(self): - ix = self.index_code("""\ + ix = self.index_code(""" def f(): x = 42 y = x @@ -251,10 +251,10 @@ def assertDefLocs(self, index, fqname, locs): return super(IndexerTestPy3, self).assertDefLocs(index, fqname, locs) def test_type_annotations(self): - ix = self.index_code("""\ + ix = self.index_code(""" def f(x: int) -> int: return x - """) + """.lstrip("\n")) self.assertDef(ix, "module.f", "f", "FunctionDef") self.assertDef(ix, "module.f.x", "x", "Param") self.assertDefLocs(ix, "module.f", [(1, 0)]) diff --git a/pytype/vm_test.py b/pytype/vm_test.py index f76214833..efb67b45c 100644 --- a/pytype/vm_test.py +++ b/pytype/vm_test.py @@ -202,10 +202,10 @@ def test_empty_data(self): self.assertEqual(self.trace_vm.opcode_traces, [(op, "x", (None,))]) def test_const(self): - src = textwrap.dedent("""\ + src = textwrap.dedent(""" x = 1 # line 1 y = x # line 2 - """) + """).lstrip() # Compiles to: # 0 LOAD_CONST 0 (1) # 3 STORE_NAME 0 (x)