diff options
Diffstat (limited to 'Lib/test/test_clinic.py')
-rw-r--r-- | Lib/test/test_clinic.py | 373 |
1 files changed, 324 insertions, 49 deletions
diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 38eabd2..934c1e3 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -1611,7 +1611,7 @@ class ClinicParserTest(TestCase): "module foo\nfoo.bar\n this: int\n *", "module foo\nfoo.bar\n this: int\n *\nDocstring.", ) - err = "Function 'foo.bar' specifies '*' without any parameters afterwards." + err = "Function 'bar' specifies '*' without following parameters." for block in dataset: with self.subTest(block=block): self.expect_failure(block, err) @@ -1679,7 +1679,7 @@ class ClinicParserTest(TestCase): Docstring. """ err = ( - "Function 'foo.bar': expected format '* [from major.minor]' " + "Function 'bar': expected format '[from major.minor]' " "where 'major' and 'minor' are integers; got '3'" ) self.expect_failure(block, err, lineno=3) @@ -1693,7 +1693,7 @@ class ClinicParserTest(TestCase): Docstring. """ err = ( - "Function 'foo.bar': expected format '* [from major.minor]' " + "Function 'bar': expected format '[from major.minor]' " "where 'major' and 'minor' are integers; got 'a.b'" ) self.expect_failure(block, err, lineno=3) @@ -1707,7 +1707,7 @@ class ClinicParserTest(TestCase): Docstring. """ err = ( - "Function 'foo.bar': expected format '* [from major.minor]' " + "Function 'bar': expected format '[from major.minor]' " "where 'major' and 'minor' are integers; got '1.2.3'" ) self.expect_failure(block, err, lineno=3) @@ -1721,8 +1721,24 @@ class ClinicParserTest(TestCase): Docstring. """ err = ( - "Function 'foo.bar' specifies '* [from ...]' without " - "any parameters afterwards" + "Function 'bar' specifies '* [from ...]' without " + "following parameters." + ) + self.expect_failure(block, err, lineno=4) + + def test_parameters_required_after_depr_star2(self): + block = """ + module foo + foo.bar + a: int + * [from 3.14] + * + b: int + Docstring. + """ + err = ( + "Function 'bar' specifies '* [from ...]' without " + "following parameters." ) self.expect_failure(block, err, lineno=4) @@ -1735,7 +1751,7 @@ class ClinicParserTest(TestCase): * [from 3.14] Docstring. """ - err = "Function 'foo.bar': '* [from ...]' must come before '*'" + err = "Function 'bar': '* [from ...]' must come before '*'" self.expect_failure(block, err, lineno=4) def test_depr_star_duplicate(self): @@ -1749,7 +1765,49 @@ class ClinicParserTest(TestCase): c: int Docstring. """ - err = "Function 'foo.bar' uses '[from ...]' more than once" + err = "Function 'bar' uses '* [from ...]' more than once." + self.expect_failure(block, err, lineno=5) + + def test_depr_star_duplicate2(self): + block = """ + module foo + foo.bar + a: int + * [from 3.14] + b: int + * [from 3.15] + c: int + Docstring. + """ + err = "Function 'bar' uses '* [from ...]' more than once." + self.expect_failure(block, err, lineno=5) + + def test_depr_slash_duplicate(self): + block = """ + module foo + foo.bar + a: int + / [from 3.14] + b: int + / [from 3.14] + c: int + Docstring. + """ + err = "Function 'bar' uses '/ [from ...]' more than once." + self.expect_failure(block, err, lineno=5) + + def test_depr_slash_duplicate2(self): + block = """ + module foo + foo.bar + a: int + / [from 3.14] + b: int + / [from 3.15] + c: int + Docstring. + """ + err = "Function 'bar' uses '/ [from ...]' more than once." self.expect_failure(block, err, lineno=5) def test_single_slash(self): @@ -1765,6 +1823,34 @@ class ClinicParserTest(TestCase): ) self.expect_failure(block, err) + def test_parameters_required_before_depr_slash(self): + block = """ + module foo + foo.bar + / [from 3.14] + Docstring. + """ + err = ( + "Function 'bar' specifies '/ [from ...]' without " + "preceding parameters." + ) + self.expect_failure(block, err, lineno=2) + + def test_parameters_required_before_depr_slash2(self): + block = """ + module foo + foo.bar + a: int + / + / [from 3.14] + Docstring. + """ + err = ( + "Function 'bar' specifies '/ [from ...]' without " + "preceding parameters." + ) + self.expect_failure(block, err, lineno=4) + def test_double_slash(self): block = """ module foo @@ -1787,12 +1873,61 @@ class ClinicParserTest(TestCase): z: int / """ - err = ( - "Function 'bar' mixes keyword-only and positional-only parameters, " - "which is unsupported." - ) + err = "Function 'bar': '/' must precede '*'" self.expect_failure(block, err) + def test_depr_star_must_come_after_slash(self): + block = """ + module foo + foo.bar + a: int + * [from 3.14] + / + b: int + Docstring. + """ + err = "Function 'bar': '/' must precede '* [from ...]'" + self.expect_failure(block, err, lineno=4) + + def test_depr_star_must_come_after_depr_slash(self): + block = """ + module foo + foo.bar + a: int + * [from 3.14] + / [from 3.14] + b: int + Docstring. + """ + err = "Function 'bar': '/ [from ...]' must precede '* [from ...]'" + self.expect_failure(block, err, lineno=4) + + def test_star_must_come_after_depr_slash(self): + block = """ + module foo + foo.bar + a: int + * + / [from 3.14] + b: int + Docstring. + """ + err = "Function 'bar': '/ [from ...]' must precede '*'" + self.expect_failure(block, err, lineno=4) + + def test_depr_slash_must_come_after_slash(self): + block = """ + module foo + foo.bar + a: int + / [from 3.14] + / + b: int + Docstring. + """ + err = "Function 'bar': '/' must precede '/ [from ...]'" + self.expect_failure(block, err, lineno=4) + def test_parameters_not_permitted_after_slash_for_now(self): block = """ module foo @@ -2589,11 +2724,33 @@ class ClinicFunctionalTest(unittest.TestCase): locals().update((name, getattr(ac_tester, name)) for name in dir(ac_tester) if name.startswith('test_')) - def check_depr_star(self, pnames, fn, *args, **kwds): + def check_depr_star(self, pnames, fn, *args, name=None, **kwds): + if name is None: + name = fn.__qualname__ + if isinstance(fn, type): + name = f'{fn.__module__}.{name}' regex = ( fr"Passing( more than)?( [0-9]+)? positional argument(s)? to " - fr"{fn.__name__}\(\) is deprecated. Parameter(s)? {pnames} will " - fr"become( a)? keyword-only parameter(s)? in Python 3\.14" + fr"{re.escape(name)}\(\) is deprecated. Parameters? {pnames} will " + fr"become( a)? keyword-only parameters? in Python 3\.14" + ) + with self.assertWarnsRegex(DeprecationWarning, regex) as cm: + # Record the line number, so we're sure we've got the correct stack + # level on the deprecation warning. + _, lineno = fn(*args, **kwds), sys._getframe().f_lineno + self.assertEqual(cm.filename, __file__) + self.assertEqual(cm.lineno, lineno) + + def check_depr_kwd(self, pnames, fn, *args, name=None, **kwds): + if name is None: + name = fn.__qualname__ + if isinstance(fn, type): + name = f'{fn.__module__}.{name}' + pl = 's' if ' ' in pnames else '' + regex = ( + fr"Passing keyword argument{pl} {pnames} to " + fr"{re.escape(name)}\(\) is deprecated. Corresponding parameter{pl} " + fr"will become positional-only in Python 3\.14." ) with self.assertWarnsRegex(DeprecationWarning, regex) as cm: # Record the line number, so we're sure we've got the correct stack @@ -3067,46 +3224,67 @@ class ClinicFunctionalTest(unittest.TestCase): self.assertEqual(func(), name) def test_depr_star_new(self): - regex = re.escape( - "Passing positional arguments to _testclinic.DeprStarNew() is " - "deprecated. Parameter 'a' will become a keyword-only parameter " - "in Python 3.14." - ) - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - ac_tester.DeprStarNew(None) - self.assertEqual(cm.filename, __file__) + cls = ac_tester.DeprStarNew + cls() + cls(a=None) + self.check_depr_star("'a'", cls, None) def test_depr_star_new_cloned(self): - regex = re.escape( - "Passing positional arguments to _testclinic.DeprStarNew.cloned() " - "is deprecated. Parameter 'a' will become a keyword-only parameter " - "in Python 3.14." - ) - obj = ac_tester.DeprStarNew(a=None) - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - obj.cloned(None) - self.assertEqual(cm.filename, __file__) + fn = ac_tester.DeprStarNew().cloned + fn() + fn(a=None) + self.check_depr_star("'a'", fn, None, name='_testclinic.DeprStarNew.cloned') def test_depr_star_init(self): - regex = re.escape( - "Passing positional arguments to _testclinic.DeprStarInit() is " - "deprecated. Parameter 'a' will become a keyword-only parameter " - "in Python 3.14." - ) - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - ac_tester.DeprStarInit(None) - self.assertEqual(cm.filename, __file__) + cls = ac_tester.DeprStarInit + cls() + cls(a=None) + self.check_depr_star("'a'", cls, None) def test_depr_star_init_cloned(self): - regex = re.escape( - "Passing positional arguments to _testclinic.DeprStarInit.cloned() " - "is deprecated. Parameter 'a' will become a keyword-only parameter " - "in Python 3.14." - ) - obj = ac_tester.DeprStarInit(a=None) - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - obj.cloned(None) - self.assertEqual(cm.filename, __file__) + fn = ac_tester.DeprStarInit().cloned + fn() + fn(a=None) + self.check_depr_star("'a'", fn, None, name='_testclinic.DeprStarInit.cloned') + + def test_depr_star_init_noinline(self): + cls = ac_tester.DeprStarInitNoInline + self.assertRaises(TypeError, cls, "a") + cls(a="a", b="b") + cls(a="a", b="b", c="c") + cls("a", b="b") + cls("a", b="b", c="c") + check = partial(self.check_depr_star, "'b' and 'c'", cls) + check("a", "b") + check("a", "b", "c") + check("a", "b", c="c") + self.assertRaises(TypeError, cls, "a", "b", "c", "d") + + def test_depr_kwd_new(self): + cls = ac_tester.DeprKwdNew + cls() + cls(None) + self.check_depr_kwd("'a'", cls, a=None) + + def test_depr_kwd_init(self): + cls = ac_tester.DeprKwdInit + cls() + cls(None) + self.check_depr_kwd("'a'", cls, a=None) + + def test_depr_kwd_init_noinline(self): + cls = ac_tester.DeprKwdInitNoInline + cls = ac_tester.depr_star_noinline + self.assertRaises(TypeError, cls, "a") + cls(a="a", b="b") + cls(a="a", b="b", c="c") + cls("a", b="b") + cls("a", b="b", c="c") + check = partial(self.check_depr_star, "'b' and 'c'", cls) + check("a", "b") + check("a", "b", "c") + check("a", "b", c="c") + self.assertRaises(TypeError, cls, "a", "b", "c", "d") def test_depr_star_pos0_len1(self): fn = ac_tester.depr_star_pos0_len1 @@ -3177,6 +3355,103 @@ class ClinicFunctionalTest(unittest.TestCase): check("a", "b", "c", d=0, e=0) check("a", "b", "c", "d", e=0) + def test_depr_star_noinline(self): + fn = ac_tester.depr_star_noinline + self.assertRaises(TypeError, fn, "a") + fn(a="a", b="b") + fn(a="a", b="b", c="c") + fn("a", b="b") + fn("a", b="b", c="c") + check = partial(self.check_depr_star, "'b' and 'c'", fn) + check("a", "b") + check("a", "b", "c") + check("a", "b", c="c") + self.assertRaises(TypeError, fn, "a", "b", "c", "d") + + def test_depr_kwd_required_1(self): + fn = ac_tester.depr_kwd_required_1 + fn("a", "b") + self.assertRaises(TypeError, fn, "a") + self.assertRaises(TypeError, fn, "a", "b", "c") + check = partial(self.check_depr_kwd, "'b'", fn) + check("a", b="b") + self.assertRaises(TypeError, fn, a="a", b="b") + + def test_depr_kwd_required_2(self): + fn = ac_tester.depr_kwd_required_2 + fn("a", "b", "c") + self.assertRaises(TypeError, fn, "a", "b") + self.assertRaises(TypeError, fn, "a", "b", "c", "d") + check = partial(self.check_depr_kwd, "'b' and 'c'", fn) + check("a", "b", c="c") + check("a", b="b", c="c") + self.assertRaises(TypeError, fn, a="a", b="b", c="c") + + def test_depr_kwd_optional_1(self): + fn = ac_tester.depr_kwd_optional_1 + fn("a") + fn("a", "b") + self.assertRaises(TypeError, fn) + self.assertRaises(TypeError, fn, "a", "b", "c") + check = partial(self.check_depr_kwd, "'b'", fn) + check("a", b="b") + self.assertRaises(TypeError, fn, a="a", b="b") + + def test_depr_kwd_optional_2(self): + fn = ac_tester.depr_kwd_optional_2 + fn("a") + fn("a", "b") + fn("a", "b", "c") + self.assertRaises(TypeError, fn) + self.assertRaises(TypeError, fn, "a", "b", "c", "d") + check = partial(self.check_depr_kwd, "'b' and 'c'", fn) + check("a", b="b") + check("a", c="c") + check("a", b="b", c="c") + check("a", c="c", b="b") + check("a", "b", c="c") + self.assertRaises(TypeError, fn, a="a", b="b", c="c") + + def test_depr_kwd_optional_3(self): + fn = ac_tester.depr_kwd_optional_3 + fn() + fn("a") + fn("a", "b") + fn("a", "b", "c") + self.assertRaises(TypeError, fn, "a", "b", "c", "d") + check = partial(self.check_depr_kwd, "'a', 'b' and 'c'", fn) + check("a", "b", c="c") + check("a", b="b") + check(a="a") + + def test_depr_kwd_required_optional(self): + fn = ac_tester.depr_kwd_required_optional + fn("a", "b") + fn("a", "b", "c") + self.assertRaises(TypeError, fn) + self.assertRaises(TypeError, fn, "a") + self.assertRaises(TypeError, fn, "a", "b", "c", "d") + check = partial(self.check_depr_kwd, "'b' and 'c'", fn) + check("a", b="b") + check("a", b="b", c="c") + check("a", c="c", b="b") + check("a", "b", c="c") + self.assertRaises(TypeError, fn, "a", c="c") + self.assertRaises(TypeError, fn, a="a", b="b", c="c") + + def test_depr_kwd_noinline(self): + fn = ac_tester.depr_kwd_noinline + fn("a", "b") + fn("a", "b", "c") + self.assertRaises(TypeError, fn, "a") + check = partial(self.check_depr_kwd, "'b' and 'c'", fn) + check("a", b="b") + check("a", b="b", c="c") + check("a", c="c", b="b") + check("a", "b", c="c") + self.assertRaises(TypeError, fn, "a", c="c") + self.assertRaises(TypeError, fn, a="a", b="b", c="c") + class PermutationTests(unittest.TestCase): """Test permutation support functions.""" |