[Python-checkins] [3.12] gh-106368: Clean up Argument Clinic tests (#106373) (#106379)

erlend-aasland webhook-mailer at python.org
Mon Jul 3 18:27:37 EDT 2023


https://github.com/python/cpython/commit/38fe0e7c2d0db1bba75bebc7dd5e890a93aa11b0
commit: 38fe0e7c2d0db1bba75bebc7dd5e890a93aa11b0
branch: 3.12
author: Erlend E. Aasland <erlend at python.org>
committer: erlend-aasland <erlend.aasland at protonmail.com>
date: 2023-07-03T22:27:34Z
summary:

[3.12] gh-106368: Clean up Argument Clinic tests (#106373) (#106379)

(cherry picked from commit 3ee8dac7a1b3882aa3aac7703bdae2de7b6402ad)

files:
M Lib/test/test_clinic.py

diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py
index 30e8dcc3e8ef1..b3602887ab635 100644
--- a/Lib/test/test_clinic.py
+++ b/Lib/test/test_clinic.py
@@ -3,7 +3,8 @@
 # Licensed to the PSF under a contributor agreement.
 
 from test import support, test_tools
-from test.support import import_helper, os_helper
+from test.support import os_helper
+from textwrap import dedent
 from unittest import TestCase
 import collections
 import inspect
@@ -171,43 +172,43 @@ def test_solo_newline(self):
     def test_no_substitution(self):
         self._test("""
           abc
-          """, """
+        """, """
           abc
-          """)
+        """)
 
     def test_empty_substitution(self):
         self._test("""
           abc
           {name}
           def
-          """, """
+        """, """
           abc
           def
-          """, name='')
+        """, name='')
 
     def test_single_line_substitution(self):
         self._test("""
           abc
           {name}
           def
-          """, """
+        """, """
           abc
           GARGLE
           def
-          """, name='GARGLE')
+        """, name='GARGLE')
 
     def test_multiline_substitution(self):
         self._test("""
           abc
           {name}
           def
-          """, """
+        """, """
           abc
           bingle
           bungle
 
           def
-          """, name='bingle\nbungle\n')
+        """, name='bingle\nbungle\n')
 
 class InertParser:
     def __init__(self, clinic):
@@ -240,9 +241,9 @@ def round_trip(self, input):
 
     def test_round_trip_1(self):
         self.round_trip("""
-    verbatim text here
-    lah dee dah
-""")
+            verbatim text here
+            lah dee dah
+        """)
     def test_round_trip_2(self):
         self.round_trip("""
     verbatim text here
@@ -286,22 +287,38 @@ def test_clinic_1(self):
 
 
 class ClinicParserTest(TestCase):
+    def checkDocstring(self, fn, expected):
+        self.assertTrue(hasattr(fn, "docstring"))
+        self.assertEqual(fn.docstring.strip(),
+                         dedent(expected).strip())
+
     def test_trivial(self):
         parser = DSLParser(FakeClinic())
-        block = clinic.Block("module os\nos.access")
+        block = clinic.Block("""
+            module os
+            os.access
+        """)
         parser.parse(block)
         module, function = block.signatures
         self.assertEqual("access", function.name)
         self.assertEqual("os", module.name)
 
     def test_ignore_line(self):
-        block = self.parse("#\nmodule os\nos.access")
+        block = self.parse(dedent("""
+            #
+            module os
+            os.access
+        """))
         module, function = block.signatures
         self.assertEqual("access", function.name)
         self.assertEqual("os", module.name)
 
     def test_param(self):
-        function = self.parse_function("module os\nos.access\n   path: int")
+        function = self.parse_function("""
+            module os
+            os.access
+                path: int
+        """)
         self.assertEqual("access", function.name)
         self.assertEqual(2, len(function.parameters))
         p = function.parameters['path']
@@ -309,236 +326,296 @@ def test_param(self):
         self.assertIsInstance(p.converter, clinic.int_converter)
 
     def test_param_default(self):
-        function = self.parse_function("module os\nos.access\n    follow_symlinks: bool = True")
+        function = self.parse_function("""
+            module os
+            os.access
+                follow_symlinks: bool = True
+        """)
         p = function.parameters['follow_symlinks']
         self.assertEqual(True, p.default)
 
     def test_param_with_continuations(self):
-        function = self.parse_function("module os\nos.access\n    follow_symlinks: \\\n   bool \\\n   =\\\n    True")
+        function = self.parse_function(r"""
+            module os
+            os.access
+                follow_symlinks: \
+                bool \
+                = \
+                True
+        """)
         p = function.parameters['follow_symlinks']
         self.assertEqual(True, p.default)
 
     def test_param_default_expression(self):
-        function = self.parse_function("module os\nos.access\n    follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize")
+        function = self.parse_function("""
+            module os
+            os.access
+                follow_symlinks: int(c_default='MAXSIZE') = sys.maxsize
+            """)
         p = function.parameters['follow_symlinks']
         self.assertEqual(sys.maxsize, p.default)
         self.assertEqual("MAXSIZE", p.converter.c_default)
 
-        s = self.parse_function_should_fail("module os\nos.access\n    follow_symlinks: int = sys.maxsize")
-        self.assertEqual(s, "Error on line 0:\nWhen you specify a named constant ('sys.maxsize') as your default value,\nyou MUST specify a valid c_default.\n")
+        expected_msg = (
+            "Error on line 0:\n"
+            "When you specify a named constant ('sys.maxsize') as your default value,\n"
+            "you MUST specify a valid c_default.\n"
+        )
+        out = self.parse_function_should_fail("""
+            module os
+            os.access
+                follow_symlinks: int = sys.maxsize
+        """)
+        self.assertEqual(out, expected_msg)
 
     def test_param_no_docstring(self):
         function = self.parse_function("""
-module os
-os.access
-    follow_symlinks: bool = True
-    something_else: str = ''""")
+            module os
+            os.access
+                follow_symlinks: bool = True
+                something_else: str = ''
+        """)
         p = function.parameters['follow_symlinks']
         self.assertEqual(3, len(function.parameters))
-        self.assertIsInstance(function.parameters['something_else'].converter, clinic.str_converter)
+        conv = function.parameters['something_else'].converter
+        self.assertIsInstance(conv, clinic.str_converter)
 
     def test_param_default_parameters_out_of_order(self):
-        s = self.parse_function_should_fail("""
-module os
-os.access
-    follow_symlinks: bool = True
-    something_else: str""")
-        self.assertEqual(s, """Error on line 0:
-Can't have a parameter without a default ('something_else')
-after a parameter with a default!
-""")
+        expected_msg = (
+            "Error on line 0:\n"
+            "Can't have a parameter without a default ('something_else')\n"
+            "after a parameter with a default!\n"
+        )
+        out = self.parse_function_should_fail("""
+            module os
+            os.access
+                follow_symlinks: bool = True
+                something_else: str""")
+        self.assertEqual(out, expected_msg)
 
     def disabled_test_converter_arguments(self):
-        function = self.parse_function("module os\nos.access\n    path: path_t(allow_fd=1)")
+        function = self.parse_function("""
+            module os
+            os.access
+                path: path_t(allow_fd=1)
+        """)
         p = function.parameters['path']
         self.assertEqual(1, p.converter.args['allow_fd'])
 
     def test_function_docstring(self):
         function = self.parse_function("""
-module os
-os.stat as os_stat_fn
+            module os
+            os.stat as os_stat_fn
 
-   path: str
-       Path to be examined
+               path: str
+                   Path to be examined
 
-Perform a stat system call on the given path.""")
-        self.assertEqual("""
-stat($module, /, path)
---
+            Perform a stat system call on the given path.
+        """)
+        self.checkDocstring(function, """
+            stat($module, /, path)
+            --
 
-Perform a stat system call on the given path.
+            Perform a stat system call on the given path.
 
-  path
-    Path to be examined
-""".strip(), function.docstring)
+              path
+                Path to be examined
+        """)
 
     def test_explicit_parameters_in_docstring(self):
-        function = self.parse_function("""
-module foo
-foo.bar
-  x: int
-     Documentation for x.
-  y: int
+        function = self.parse_function(dedent("""
+            module foo
+            foo.bar
+              x: int
+                 Documentation for x.
+              y: int
 
-This is the documentation for foo.
+            This is the documentation for foo.
 
-Okay, we're done here.
-""")
-        self.assertEqual("""
-bar($module, /, x, y)
---
+            Okay, we're done here.
+        """))
+        self.checkDocstring(function, """
+            bar($module, /, x, y)
+            --
 
-This is the documentation for foo.
+            This is the documentation for foo.
 
-  x
-    Documentation for x.
+              x
+                Documentation for x.
 
-Okay, we're done here.
-""".strip(), function.docstring)
+            Okay, we're done here.
+        """)
 
     def test_parser_regression_special_character_in_parameter_column_of_docstring_first_line(self):
-        function = self.parse_function("""
-module os
-os.stat
-    path: str
-This/used to break Clinic!
-""")
-        self.assertEqual("stat($module, /, path)\n--\n\nThis/used to break Clinic!", function.docstring)
+        function = self.parse_function(dedent("""
+            module os
+            os.stat
+                path: str
+            This/used to break Clinic!
+        """))
+        self.checkDocstring(function, """
+            stat($module, /, path)
+            --
+
+            This/used to break Clinic!
+        """)
 
     def test_c_name(self):
-        function = self.parse_function("module os\nos.stat as os_stat_fn")
+        function = self.parse_function("""
+            module os
+            os.stat as os_stat_fn
+        """)
         self.assertEqual("os_stat_fn", function.c_basename)
 
     def test_return_converter(self):
-        function = self.parse_function("module os\nos.stat -> int")
+        function = self.parse_function("""
+            module os
+            os.stat -> int
+        """)
         self.assertIsInstance(function.return_converter, clinic.int_return_converter)
 
     def test_star(self):
-        function = self.parse_function("module os\nos.access\n    *\n    follow_symlinks: bool = True")
+        function = self.parse_function("""
+            module os
+            os.access
+                *
+                follow_symlinks: bool = True
+        """)
         p = function.parameters['follow_symlinks']
         self.assertEqual(inspect.Parameter.KEYWORD_ONLY, p.kind)
         self.assertEqual(0, p.group)
 
     def test_group(self):
-        function = self.parse_function("module window\nwindow.border\n [\n ls : int\n ]\n /\n")
+        function = self.parse_function("""
+            module window
+            window.border
+                [
+                ls: int
+                ]
+                /
+        """)
         p = function.parameters['ls']
         self.assertEqual(1, p.group)
 
     def test_left_group(self):
         function = self.parse_function("""
-module curses
-curses.addch
-   [
-   y: int
-     Y-coordinate.
-   x: int
-     X-coordinate.
-   ]
-   ch: char
-     Character to add.
-   [
-   attr: long
-     Attributes for the character.
-   ]
-   /
-""")
-        for name, group in (
+            module curses
+            curses.addch
+                [
+                y: int
+                    Y-coordinate.
+                x: int
+                    X-coordinate.
+                ]
+                ch: char
+                    Character to add.
+                [
+                attr: long
+                    Attributes for the character.
+                ]
+                /
+        """)
+        dataset = (
             ('y', -1), ('x', -1),
             ('ch', 0),
             ('attr', 1),
-            ):
-            p = function.parameters[name]
-            self.assertEqual(p.group, group)
-            self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
-        self.assertEqual(function.docstring.strip(), """
-addch([y, x,] ch, [attr])
-
-
-  y
-    Y-coordinate.
-  x
-    X-coordinate.
-  ch
-    Character to add.
-  attr
-    Attributes for the character.
-            """.strip())
+        )
+        for name, group in dataset:
+            with self.subTest(name=name, group=group):
+                p = function.parameters[name]
+                self.assertEqual(p.group, group)
+                self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
+        self.checkDocstring(function, """
+            addch([y, x,] ch, [attr])
+
+
+              y
+                Y-coordinate.
+              x
+                X-coordinate.
+              ch
+                Character to add.
+              attr
+                Attributes for the character.
+        """)
 
     def test_nested_groups(self):
         function = self.parse_function("""
-module curses
-curses.imaginary
-   [
-   [
-   y1: int
-     Y-coordinate.
-   y2: int
-     Y-coordinate.
-   ]
-   x1: int
-     X-coordinate.
-   x2: int
-     X-coordinate.
-   ]
-   ch: char
-     Character to add.
-   [
-   attr1: long
-     Attributes for the character.
-   attr2: long
-     Attributes for the character.
-   attr3: long
-     Attributes for the character.
-   [
-   attr4: long
-     Attributes for the character.
-   attr5: long
-     Attributes for the character.
-   attr6: long
-     Attributes for the character.
-   ]
-   ]
-   /
-""")
-        for name, group in (
+            module curses
+            curses.imaginary
+               [
+               [
+               y1: int
+                 Y-coordinate.
+               y2: int
+                 Y-coordinate.
+               ]
+               x1: int
+                 X-coordinate.
+               x2: int
+                 X-coordinate.
+               ]
+               ch: char
+                 Character to add.
+               [
+               attr1: long
+                 Attributes for the character.
+               attr2: long
+                 Attributes for the character.
+               attr3: long
+                 Attributes for the character.
+               [
+               attr4: long
+                 Attributes for the character.
+               attr5: long
+                 Attributes for the character.
+               attr6: long
+                 Attributes for the character.
+               ]
+               ]
+               /
+        """)
+        dataset = (
             ('y1', -2), ('y2', -2),
             ('x1', -1), ('x2', -1),
             ('ch', 0),
             ('attr1', 1), ('attr2', 1), ('attr3', 1),
             ('attr4', 2), ('attr5', 2), ('attr6', 2),
-            ):
-            p = function.parameters[name]
-            self.assertEqual(p.group, group)
-            self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
-
-        self.assertEqual(function.docstring.strip(), """
-imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
-          attr6]])
-
-
-  y1
-    Y-coordinate.
-  y2
-    Y-coordinate.
-  x1
-    X-coordinate.
-  x2
-    X-coordinate.
-  ch
-    Character to add.
-  attr1
-    Attributes for the character.
-  attr2
-    Attributes for the character.
-  attr3
-    Attributes for the character.
-  attr4
-    Attributes for the character.
-  attr5
-    Attributes for the character.
-  attr6
-    Attributes for the character.
-                """.strip())
+        )
+        for name, group in dataset:
+            with self.subTest(name=name, group=group):
+                p = function.parameters[name]
+                self.assertEqual(p.group, group)
+                self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
+
+        self.checkDocstring(function, """
+            imaginary([[y1, y2,] x1, x2,] ch, [attr1, attr2, attr3, [attr4, attr5,
+                      attr6]])
+
+
+              y1
+                Y-coordinate.
+              y2
+                Y-coordinate.
+              x1
+                X-coordinate.
+              x2
+                X-coordinate.
+              ch
+                Character to add.
+              attr1
+                Attributes for the character.
+              attr2
+                Attributes for the character.
+              attr3
+                Attributes for the character.
+              attr4
+                Attributes for the character.
+              attr5
+                Attributes for the character.
+              attr6
+                Attributes for the character.
+        """)
 
     def parse_function_should_fail(self, s):
         with support.captured_stdout() as stdout:
@@ -547,104 +624,108 @@ def parse_function_should_fail(self, s):
         return stdout.getvalue()
 
     def test_disallowed_grouping__two_top_groups_on_left(self):
-        s = self.parse_function_should_fail("""
-module foo
-foo.two_top_groups_on_left
-    [
-    group1 : int
-    ]
-    [
-    group2 : int
-    ]
-    param: int
-            """)
-        self.assertEqual(s,
-            ('Error on line 0:\n'
-            'Function two_top_groups_on_left has an unsupported group configuration. (Unexpected state 2.b)\n'))
+        expected_msg = (
+            'Error on line 0:\n'
+            'Function two_top_groups_on_left has an unsupported group '
+            'configuration. (Unexpected state 2.b)\n'
+        )
+        out = self.parse_function_should_fail("""
+            module foo
+            foo.two_top_groups_on_left
+                [
+                group1 : int
+                ]
+                [
+                group2 : int
+                ]
+                param: int
+        """)
+        self.assertEqual(out, expected_msg)
 
     def test_disallowed_grouping__two_top_groups_on_right(self):
         self.parse_function_should_fail("""
-module foo
-foo.two_top_groups_on_right
-    param: int
-    [
-    group1 : int
-    ]
-    [
-    group2 : int
-    ]
-            """)
+            module foo
+            foo.two_top_groups_on_right
+                param: int
+                [
+                group1 : int
+                ]
+                [
+                group2 : int
+                ]
+        """)
 
     def test_disallowed_grouping__parameter_after_group_on_right(self):
         self.parse_function_should_fail("""
-module foo
-foo.parameter_after_group_on_right
-    param: int
-    [
-    [
-    group1 : int
-    ]
-    group2 : int
-    ]
-            """)
+            module foo
+            foo.parameter_after_group_on_right
+                param: int
+                [
+                [
+                group1 : int
+                ]
+                group2 : int
+                ]
+        """)
 
     def test_disallowed_grouping__group_after_parameter_on_left(self):
         self.parse_function_should_fail("""
-module foo
-foo.group_after_parameter_on_left
-    [
-    group2 : int
-    [
-    group1 : int
-    ]
-    ]
-    param: int
-            """)
+            module foo
+            foo.group_after_parameter_on_left
+                [
+                group2 : int
+                [
+                group1 : int
+                ]
+                ]
+                param: int
+        """)
 
     def test_disallowed_grouping__empty_group_on_left(self):
         self.parse_function_should_fail("""
-module foo
-foo.empty_group
-    [
-    [
-    ]
-    group2 : int
-    ]
-    param: int
-            """)
+            module foo
+            foo.empty_group
+                [
+                [
+                ]
+                group2 : int
+                ]
+                param: int
+        """)
 
     def test_disallowed_grouping__empty_group_on_right(self):
         self.parse_function_should_fail("""
-module foo
-foo.empty_group
-    param: int
-    [
-    [
-    ]
-    group2 : int
-    ]
-            """)
+            module foo
+            foo.empty_group
+                param: int
+                [
+                [
+                ]
+                group2 : int
+                ]
+        """)
 
     def test_no_parameters(self):
         function = self.parse_function("""
-module foo
-foo.bar
+            module foo
+            foo.bar
 
-Docstring
+            Docstring
 
-""")
+        """)
         self.assertEqual("bar($module, /)\n--\n\nDocstring", function.docstring)
         self.assertEqual(1, len(function.parameters)) # self!
 
     def test_init_with_no_parameters(self):
         function = self.parse_function("""
-module foo
-class foo.Bar "unused" "notneeded"
-foo.Bar.__init__
+            module foo
+            class foo.Bar "unused" "notneeded"
+            foo.Bar.__init__
 
-Docstring
+            Docstring
+
+        """, signatures_in_block=3, function_index=2)
 
-""", signatures_in_block=3, function_index=2)
         # self is not in the signature
         self.assertEqual("Bar()\n--\n\nDocstring", function.docstring)
         # but it *is* a parameter
@@ -652,113 +733,117 @@ class foo.Bar "unused" "notneeded"
 
     def test_illegal_module_line(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar => int
-    /
-""")
+            module foo
+            foo.bar => int
+                /
+        """)
 
     def test_illegal_c_basename(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar as 935
-    /
-""")
+            module foo
+            foo.bar as 935
+                /
+        """)
 
     def test_single_star(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar
-    *
-    *
-""")
+            module foo
+            foo.bar
+                *
+                *
+        """)
 
     def test_parameters_required_after_star_without_initial_parameters_or_docstring(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar
-    *
-""")
+            module foo
+            foo.bar
+                *
+        """)
 
     def test_parameters_required_after_star_without_initial_parameters_with_docstring(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar
-    *
-Docstring here.
-""")
+            module foo
+            foo.bar
+                *
+            Docstring here.
+        """)
 
     def test_parameters_required_after_star_with_initial_parameters_without_docstring(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar
-    this: int
-    *
-""")
+            module foo
+            foo.bar
+                this: int
+                *
+        """)
 
     def test_parameters_required_after_star_with_initial_parameters_and_docstring(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar
-    this: int
-    *
-Docstring.
-""")
+            module foo
+            foo.bar
+                this: int
+                *
+            Docstring.
+        """)
 
     def test_single_slash(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar
-    /
-    /
-""")
+            module foo
+            foo.bar
+                /
+                /
+        """)
 
     def test_mix_star_and_slash(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar
-   x: int
-   y: int
-   *
-   z: int
-   /
-""")
+            module foo
+            foo.bar
+               x: int
+               y: int
+               *
+               z: int
+               /
+        """)
 
     def test_parameters_not_permitted_after_slash_for_now(self):
         self.parse_function_should_fail("""
-module foo
-foo.bar
-    /
-    x: int
-""")
+            module foo
+            foo.bar
+                /
+                x: int
+        """)
 
     def test_parameters_no_more_than_one_vararg(self):
-        s = self.parse_function_should_fail("""
-module foo
-foo.bar
-   *vararg1: object
-   *vararg2: object
-""")
-        self.assertEqual(s, "Error on line 0:\nToo many var args\n")
+        expected_msg = (
+            "Error on line 0:\n"
+            "Too many var args\n"
+        )
+        out = self.parse_function_should_fail("""
+            module foo
+            foo.bar
+               *vararg1: object
+               *vararg2: object
+        """)
+        self.assertEqual(out, expected_msg)
 
     def test_function_not_at_column_0(self):
         function = self.parse_function("""
-  module foo
-  foo.bar
-    x: int
-      Nested docstring here, goeth.
-    *
-    y: str
-  Not at column 0!
-""")
-        self.assertEqual("""
-bar($module, /, x, *, y)
---
+              module foo
+              foo.bar
+                x: int
+                  Nested docstring here, goeth.
+                *
+                y: str
+              Not at column 0!
+        """)
+        self.checkDocstring(function, """
+            bar($module, /, x, *, y)
+            --
 
-Not at column 0!
+            Not at column 0!
 
-  x
-    Nested docstring here, goeth.
-""".strip(), function.docstring)
+              x
+                Nested docstring here, goeth.
+        """)
 
     def test_directive(self):
         c = FakeClinic()
@@ -772,46 +857,39 @@ def test_directive(self):
     def test_legacy_converters(self):
         block = self.parse('module os\nos.access\n   path: "s"')
         module, function = block.signatures
-        self.assertIsInstance((function.parameters['path']).converter, clinic.str_converter)
+        conv = (function.parameters['path']).converter
+        self.assertIsInstance(conv, clinic.str_converter)
 
     def test_legacy_converters_non_string_constant_annotation(self):
-        expected_failure_message = """\
-Error on line 0:
-Annotations must be either a name, a function call, or a string.
-"""
-
-        s = self.parse_function_should_fail('module os\nos.access\n   path: 42')
-        self.assertEqual(s, expected_failure_message)
-
-        s = self.parse_function_should_fail('module os\nos.access\n   path: 42.42')
-        self.assertEqual(s, expected_failure_message)
-
-        s = self.parse_function_should_fail('module os\nos.access\n   path: 42j')
-        self.assertEqual(s, expected_failure_message)
-
-        s = self.parse_function_should_fail('module os\nos.access\n   path: b"42"')
-        self.assertEqual(s, expected_failure_message)
-
-    def test_other_bizarre_things_in_annotations_fail(self):
-        expected_failure_message = """\
-Error on line 0:
-Annotations must be either a name, a function call, or a string.
-"""
-
-        s = self.parse_function_should_fail(
-            'module os\nos.access\n   path: {"some": "dictionary"}'
+        expected_failure_message = (
+            "Error on line 0:\n"
+            "Annotations must be either a name, a function call, or a string.\n"
         )
-        self.assertEqual(s, expected_failure_message)
-
-        s = self.parse_function_should_fail(
-            'module os\nos.access\n   path: ["list", "of", "strings"]'
+        dataset = (
+            'module os\nos.access\n   path: 42',
+            'module os\nos.access\n   path: 42.42',
+            'module os\nos.access\n   path: 42j',
+            'module os\nos.access\n   path: b"42"',
         )
-        self.assertEqual(s, expected_failure_message)
+        for block in dataset:
+            with self.subTest(block=block):
+                out = self.parse_function_should_fail(block)
+                self.assertEqual(out, expected_failure_message)
 
-        s = self.parse_function_should_fail(
-            'module os\nos.access\n   path: (x for x in range(42))'
+    def test_other_bizarre_things_in_annotations_fail(self):
+        expected_failure_message = (
+            "Error on line 0:\n"
+            "Annotations must be either a name, a function call, or a string.\n"
+        )
+        dataset = (
+            'module os\nos.access\n   path: {"some": "dictionary"}',
+            'module os\nos.access\n   path: ["list", "of", "strings"]',
+            'module os\nos.access\n   path: (x for x in range(42))',
         )
-        self.assertEqual(s, expected_failure_message)
+        for block in dataset:
+            with self.subTest(block=block):
+                out = self.parse_function_should_fail(block)
+                self.assertEqual(out, expected_failure_message)
 
     def test_kwarg_splats_disallowed_in_function_call_annotations(self):
         expected_error_msg = (
@@ -945,10 +1023,16 @@ def test_scaffolding(self):
         self.assertEqual(repr(clinic.NULL), '<Null>')
 
         # test that fail fails
+        expected = (
+            'Error in file "clown.txt" on line 69:\n'
+            'The igloos are melting!\n'
+        )
         with support.captured_stdout() as stdout:
             with self.assertRaises(SystemExit):
-                clinic.fail('The igloos are melting!', filename='clown.txt', line_number=69)
-        self.assertEqual(stdout.getvalue(), 'Error in file "clown.txt" on line 69:\nThe igloos are melting!\n')
+                clinic.fail('The igloos are melting!',
+                            filename='clown.txt', line_number=69)
+        actual = stdout.getvalue()
+        self.assertEqual(actual, expected)
 
 
 class ClinicExternalTest(TestCase):



More information about the Python-checkins mailing list