@@ -1627,7 +1627,7 @@ def test_depr_star_invalid_format_1(self):
16271627 Docstring.
16281628 """
16291629 err = (
1630- "Function 'foo.bar': expected format '* [from major.minor]' "
1630+ "Function 'foo.bar': expected format '[from major.minor]' "
16311631 "where 'major' and 'minor' are integers; got '3'"
16321632 )
16331633 self .expect_failure (block , err , lineno = 3 )
@@ -1641,7 +1641,7 @@ def test_depr_star_invalid_format_2(self):
16411641 Docstring.
16421642 """
16431643 err = (
1644- "Function 'foo.bar': expected format '* [from major.minor]' "
1644+ "Function 'foo.bar': expected format '[from major.minor]' "
16451645 "where 'major' and 'minor' are integers; got 'a.b'"
16461646 )
16471647 self .expect_failure (block , err , lineno = 3 )
@@ -1655,7 +1655,7 @@ def test_depr_star_invalid_format_3(self):
16551655 Docstring.
16561656 """
16571657 err = (
1658- "Function 'foo.bar': expected format '* [from major.minor]' "
1658+ "Function 'foo.bar': expected format '[from major.minor]' "
16591659 "where 'major' and 'minor' are integers; got '1.2.3'"
16601660 )
16611661 self .expect_failure (block , err , lineno = 3 )
@@ -1674,6 +1674,22 @@ def test_parameters_required_after_depr_star(self):
16741674 )
16751675 self .expect_failure (block , err , lineno = 4 )
16761676
1677+ def test_parameters_required_after_depr_star2 (self ):
1678+ block = """
1679+ module foo
1680+ foo.bar
1681+ a: int
1682+ * [from 3.14]
1683+ *
1684+ b: int
1685+ Docstring.
1686+ """
1687+ err = (
1688+ "Function 'foo.bar' specifies '* [from ...]' without "
1689+ "any parameters afterwards"
1690+ )
1691+ self .expect_failure (block , err , lineno = 4 )
1692+
16771693 def test_depr_star_must_come_before_star (self ):
16781694 block = """
16791695 module foo
@@ -1697,7 +1713,21 @@ def test_depr_star_duplicate(self):
16971713 c: int
16981714 Docstring.
16991715 """
1700- err = "Function 'foo.bar' uses '[from ...]' more than once"
1716+ err = "Function 'foo.bar' uses '* [from ...]' more than once."
1717+ self .expect_failure (block , err , lineno = 5 )
1718+
1719+ def test_depr_slash_duplicate (self ):
1720+ block = """
1721+ module foo
1722+ foo.bar
1723+ a: int
1724+ / [from 3.14]
1725+ b: int
1726+ / [from 3.14]
1727+ c: int
1728+ Docstring.
1729+ """
1730+ err = "Function 'bar' uses '/ [from ...]' more than once."
17011731 self .expect_failure (block , err , lineno = 5 )
17021732
17031733 def test_single_slash (self ):
@@ -1713,6 +1743,48 @@ def test_single_slash(self):
17131743 )
17141744 self .expect_failure (block , err )
17151745
1746+ def test_parameters_required_before_depr_slash (self ):
1747+ block = """
1748+ module foo
1749+ foo.bar
1750+ / [from 3.14]
1751+ Docstring.
1752+ """
1753+ err = (
1754+ "Function 'bar' specifies '/ [from ...]' without "
1755+ "any parameters beforehead."
1756+ )
1757+ self .expect_failure (block , err , lineno = 2 )
1758+
1759+ def test_parameters_required_before_depr_slash2 (self ):
1760+ block = """
1761+ module foo
1762+ foo.bar
1763+ /
1764+ / [from 3.14]
1765+ Docstring.
1766+ """
1767+ err = (
1768+ "Function 'bar' has an unsupported group configuration. "
1769+ "(Unexpected state 0.d)"
1770+ )
1771+ self .expect_failure (block , err , lineno = 2 )
1772+
1773+ def test_parameters_required_before_depr_slash3 (self ):
1774+ block = """
1775+ module foo
1776+ foo.bar
1777+ a: int
1778+ /
1779+ / [from 3.14]
1780+ Docstring.
1781+ """
1782+ err = (
1783+ "Function 'bar' specifies '/ [from ...]' without "
1784+ "any parameters beforehead."
1785+ )
1786+ self .expect_failure (block , err , lineno = 4 )
1787+
17161788 def test_double_slash (self ):
17171789 block = """
17181790 module foo
@@ -1741,6 +1813,67 @@ def test_mix_star_and_slash(self):
17411813 )
17421814 self .expect_failure (block , err )
17431815
1816+ def test_depr_star_must_come_after_slash (self ):
1817+ block = """
1818+ module foo
1819+ foo.bar
1820+ a: int
1821+ * [from 3.14]
1822+ /
1823+ b: int
1824+ Docstring.
1825+ """
1826+ err = (
1827+ "Function 'bar' mixes keyword-only and positional-only parameters, "
1828+ "which is unsupported."
1829+ )
1830+ self .expect_failure (block , err , lineno = 4 )
1831+
1832+ def test_depr_star_must_come_after_depr_slash (self ):
1833+ block = """
1834+ module foo
1835+ foo.bar
1836+ a: int
1837+ * [from 3.14]
1838+ / [from 3.14]
1839+ b: int
1840+ Docstring.
1841+ """
1842+ err = (
1843+ "Function 'bar' mixes keyword-only and positional-only parameters, "
1844+ "which is unsupported."
1845+ )
1846+ self .expect_failure (block , err , lineno = 4 )
1847+
1848+ def test_star_must_come_after_depr_slash (self ):
1849+ block = """
1850+ module foo
1851+ foo.bar
1852+ a: int
1853+ *
1854+ / [from 3.14]
1855+ b: int
1856+ Docstring.
1857+ """
1858+ err = (
1859+ "Function 'bar' mixes keyword-only and positional-only parameters, "
1860+ "which is unsupported."
1861+ )
1862+ self .expect_failure (block , err , lineno = 4 )
1863+
1864+ def test_depr_slash_must_come_after_slash (self ):
1865+ block = """
1866+ module foo
1867+ foo.bar
1868+ a: int
1869+ / [from 3.14]
1870+ /
1871+ b: int
1872+ Docstring.
1873+ """
1874+ err = "Function 'foo.bar': '/ [from ...]' must come after '/'"
1875+ self .expect_failure (block , err , lineno = 4 )
1876+
17441877 def test_parameters_not_permitted_after_slash_for_now (self ):
17451878 block = """
17461879 module foo
@@ -2537,11 +2670,33 @@ class ClinicFunctionalTest(unittest.TestCase):
25372670 locals ().update ((name , getattr (ac_tester , name ))
25382671 for name in dir (ac_tester ) if name .startswith ('test_' ))
25392672
2540- def check_depr_star (self , pnames , fn , * args , ** kwds ):
2673+ def check_depr_star (self , pnames , fn , * args , name = None , ** kwds ):
2674+ if name is None :
2675+ name = fn .__qualname__
2676+ if isinstance (fn , type ):
2677+ name = f'{ fn .__module__ } .{ name } '
25412678 regex = (
25422679 fr"Passing( more than)?( [0-9]+)? positional argument(s)? to "
2543- fr"{ fn .__name__ } \(\) is deprecated. Parameter(s)? { pnames } will "
2544- fr"become( a)? keyword-only parameter(s)? in Python 3\.14"
2680+ fr"{ re .escape (name )} \(\) is deprecated. Parameters? { pnames } will "
2681+ fr"become( a)? keyword-only parameters? in Python 3\.14"
2682+ )
2683+ with self .assertWarnsRegex (DeprecationWarning , regex ) as cm :
2684+ # Record the line number, so we're sure we've got the correct stack
2685+ # level on the deprecation warning.
2686+ _ , lineno = fn (* args , ** kwds ), sys ._getframe ().f_lineno
2687+ self .assertEqual (cm .filename , __file__ )
2688+ self .assertEqual (cm .lineno , lineno )
2689+
2690+ def check_depr_kwd (self , pnames , fn , * args , name = None , ** kwds ):
2691+ if name is None :
2692+ name = fn .__qualname__
2693+ if isinstance (fn , type ):
2694+ name = f'{ fn .__module__ } .{ name } '
2695+ pl = 's' if ' ' in pnames else ''
2696+ regex = (
2697+ fr"Passing keyword argument{ pl } { pnames } to "
2698+ fr"{ re .escape (name )} \(\) is deprecated. Corresponding parameter{ pl } "
2699+ fr"will become positional-only in Python 3\.14."
25452700 )
25462701 with self .assertWarnsRegex (DeprecationWarning , regex ) as cm :
25472702 # Record the line number, so we're sure we've got the correct stack
@@ -3015,46 +3170,40 @@ def test_cloned_func_with_converter_exception_message(self):
30153170 self .assertEqual (func (), name )
30163171
30173172 def test_depr_star_new (self ):
3018- regex = re .escape (
3019- "Passing positional arguments to _testclinic.DeprStarNew() is "
3020- "deprecated. Parameter 'a' will become a keyword-only parameter "
3021- "in Python 3.14."
3022- )
3023- with self .assertWarnsRegex (DeprecationWarning , regex ) as cm :
3024- ac_tester .DeprStarNew (None )
3025- self .assertEqual (cm .filename , __file__ )
3173+ cls = ac_tester .DeprStarNew
3174+ cls (a = None )
3175+ self .check_depr_star ("'a'" , cls , None )
3176+ self .assertRaises (TypeError , cls )
30263177
30273178 def test_depr_star_new_cloned (self ):
3028- regex = re .escape (
3029- "Passing positional arguments to _testclinic.DeprStarNew.cloned() "
3030- "is deprecated. Parameter 'a' will become a keyword-only parameter "
3031- "in Python 3.14."
3032- )
3033- obj = ac_tester .DeprStarNew (a = None )
3034- with self .assertWarnsRegex (DeprecationWarning , regex ) as cm :
3035- obj .cloned (None )
3036- self .assertEqual (cm .filename , __file__ )
3179+ fn = ac_tester .DeprStarNew (a = None ).cloned
3180+ fn (a = None )
3181+ self .check_depr_star ("'a'" , fn , None , name = '_testclinic.DeprStarNew.cloned' )
3182+ self .assertRaises (TypeError , fn )
30373183
30383184 def test_depr_star_init (self ):
3039- regex = re .escape (
3040- "Passing positional arguments to _testclinic.DeprStarInit() is "
3041- "deprecated. Parameter 'a' will become a keyword-only parameter "
3042- "in Python 3.14."
3043- )
3044- with self .assertWarnsRegex (DeprecationWarning , regex ) as cm :
3045- ac_tester .DeprStarInit (None )
3046- self .assertEqual (cm .filename , __file__ )
3185+ cls = ac_tester .DeprStarInit
3186+ cls (a = None )
3187+ self .check_depr_star ("'a'" , cls , None )
3188+ self .assertRaises (TypeError , cls )
30473189
30483190 def test_depr_star_init_cloned (self ):
3049- regex = re .escape (
3050- "Passing positional arguments to _testclinic.DeprStarInit.cloned() "
3051- "is deprecated. Parameter 'a' will become a keyword-only parameter "
3052- "in Python 3.14."
3053- )
3054- obj = ac_tester .DeprStarInit (a = None )
3055- with self .assertWarnsRegex (DeprecationWarning , regex ) as cm :
3056- obj .cloned (None )
3057- self .assertEqual (cm .filename , __file__ )
3191+ fn = ac_tester .DeprStarInit (a = None ).cloned
3192+ fn (a = None )
3193+ self .check_depr_star ("'a'" , fn , None , name = '_testclinic.DeprStarInit.cloned' )
3194+ self .assertRaises (TypeError , fn )
3195+
3196+ def test_depr_kwd_new (self ):
3197+ cls = ac_tester .DeprKwdNew
3198+ cls (None )
3199+ self .check_depr_kwd ("'a'" , cls , a = None )
3200+ self .assertRaises (TypeError , cls )
3201+
3202+ def test_depr_kwd_init (self ):
3203+ cls = ac_tester .DeprKwdInit
3204+ cls (None )
3205+ self .check_depr_kwd ("'a'" , cls , a = None )
3206+ self .assertRaises (TypeError , cls )
30583207
30593208 def test_depr_star_pos0_len1 (self ):
30603209 fn = ac_tester .depr_star_pos0_len1
@@ -3125,6 +3274,90 @@ def test_depr_star_pos2_len2_with_kwd(self):
31253274 check ("a" , "b" , "c" , d = 0 , e = 0 )
31263275 check ("a" , "b" , "c" , "d" , e = 0 )
31273276
3277+ def test_depr_kwd_required_1 (self ):
3278+ fn = ac_tester .depr_kwd_required_1
3279+ fn ("a" , "b" )
3280+ self .assertRaises (TypeError , fn , "a" )
3281+ self .assertRaises (TypeError , fn , "a" , "b" , "c" )
3282+ check = partial (self .check_depr_kwd , "'b'" , fn )
3283+ check ("a" , b = "b" )
3284+ self .assertRaises (TypeError , fn , a = "a" , b = "b" )
3285+
3286+ def test_depr_kwd_required_2 (self ):
3287+ fn = ac_tester .depr_kwd_required_2
3288+ fn ("a" , "b" , "c" )
3289+ self .assertRaises (TypeError , fn , "a" , "b" )
3290+ self .assertRaises (TypeError , fn , "a" , "b" , "c" , "d" )
3291+ check = partial (self .check_depr_kwd , "'b' and 'c'" , fn )
3292+ check ("a" , "b" , c = "c" )
3293+ check ("a" , b = "b" , c = "c" )
3294+ self .assertRaises (TypeError , fn , a = "a" , b = "b" , c = "c" )
3295+
3296+ def test_depr_kwd_optional_1 (self ):
3297+ fn = ac_tester .depr_kwd_optional_1
3298+ fn ("a" )
3299+ fn ("a" , "b" )
3300+ self .assertRaises (TypeError , fn )
3301+ self .assertRaises (TypeError , fn , "a" , "b" , "c" )
3302+ check = partial (self .check_depr_kwd , "'b'" , fn )
3303+ check ("a" , b = "b" )
3304+ self .assertRaises (TypeError , fn , a = "a" , b = "b" )
3305+
3306+ def test_depr_kwd_optional_2 (self ):
3307+ fn = ac_tester .depr_kwd_optional_2
3308+ fn ("a" )
3309+ fn ("a" , "b" )
3310+ fn ("a" , "b" , "c" )
3311+ self .assertRaises (TypeError , fn )
3312+ self .assertRaises (TypeError , fn , "a" , "b" , "c" , "d" )
3313+ check = partial (self .check_depr_kwd , "'b' and 'c'" , fn )
3314+ check ("a" , b = "b" )
3315+ check ("a" , c = "c" )
3316+ check ("a" , b = "b" , c = "c" )
3317+ check ("a" , c = "c" , b = "b" )
3318+ check ("a" , "b" , c = "c" )
3319+ self .assertRaises (TypeError , fn , a = "a" , b = "b" , c = "c" )
3320+
3321+ def test_depr_kwd_optional_3 (self ):
3322+ fn = ac_tester .depr_kwd_optional_3
3323+ fn ()
3324+ fn ("a" )
3325+ fn ("a" , "b" )
3326+ fn ("a" , "b" , "c" )
3327+ self .assertRaises (TypeError , fn , "a" , "b" , "c" , "d" )
3328+ check = partial (self .check_depr_kwd , "'a', 'b' and 'c'" , fn )
3329+ check ("a" , "b" , c = "c" )
3330+ check ("a" , b = "b" )
3331+ check (a = "a" )
3332+
3333+ def test_depr_kwd_required_optional (self ):
3334+ fn = ac_tester .depr_kwd_required_optional
3335+ fn ("a" , "b" )
3336+ fn ("a" , "b" , "c" )
3337+ self .assertRaises (TypeError , fn )
3338+ self .assertRaises (TypeError , fn , "a" )
3339+ self .assertRaises (TypeError , fn , "a" , "b" , "c" , "d" )
3340+ check = partial (self .check_depr_kwd , "'b' and 'c'" , fn )
3341+ check ("a" , b = "b" )
3342+ check ("a" , b = "b" , c = "c" )
3343+ check ("a" , c = "c" , b = "b" )
3344+ check ("a" , "b" , c = "c" )
3345+ self .assertRaises (TypeError , fn , "a" , c = "c" )
3346+ self .assertRaises (TypeError , fn , a = "a" , b = "b" , c = "c" )
3347+
3348+ def test_depr_kwd_noinline (self ):
3349+ fn = ac_tester .depr_kwd_noinline
3350+ fn ("a" , "b" )
3351+ fn ("a" , "b" , "c" )
3352+ self .assertRaises (TypeError , fn , "a" )
3353+ check = partial (self .check_depr_kwd , "'b' and 'c'" , fn )
3354+ check ("a" , b = "b" )
3355+ check ("a" , b = "b" , c = "c" )
3356+ check ("a" , c = "c" , b = "b" )
3357+ check ("a" , "b" , c = "c" )
3358+ self .assertRaises (TypeError , fn , "a" , c = "c" )
3359+ self .assertRaises (TypeError , fn , a = "a" , b = "b" , c = "c" )
3360+
31283361
31293362class PermutationTests (unittest .TestCase ):
31303363 """Test permutation support functions."""
0 commit comments