-
-
Notifications
You must be signed in to change notification settings - Fork 33.1k
gh-64490: Argument Clinic: Add support for **kwds
#138344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
b051ae8
b6785c4
9e02b3f
8939a89
f2efcbd
b213f62
51add1a
1e1a4b2
26a6b87
c46ed0d
bc2f864
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -357,6 +357,32 @@ def test_vararg_after_star(self): | |
""" | ||
self.expect_failure(block, err, lineno=6) | ||
|
||
def test_double_star_after_var_keyword(self): | ||
err = "Function 'my_test_func' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" | ||
block = """ | ||
/*[clinic input] | ||
my_test_func | ||
|
||
pos_arg: object | ||
**kwds: dict | ||
** | ||
[clinic start generated code]*/ | ||
""" | ||
self.expect_failure(block, err, lineno=5) | ||
|
||
def test_var_keyword_after_star(self): | ||
err = "Function 'my_test_func' has an invalid parameter declaration: '**'" | ||
block = """ | ||
/*[clinic input] | ||
my_test_func | ||
|
||
pos_arg: object | ||
** | ||
**kwds: dict | ||
[clinic start generated code]*/ | ||
""" | ||
self.expect_failure(block, err, lineno=5) | ||
|
||
def test_module_already_got_one(self): | ||
err = "Already defined module 'm'!" | ||
block = """ | ||
|
@@ -748,6 +774,16 @@ def test_ignore_preprocessor_in_comments(self): | |
""") | ||
self.clinic.parse(raw) | ||
|
||
def test_var_keyword_non_dict(self): | ||
err = "'var_keyword_object' is not a valid converter" | ||
block = """ | ||
/*[clinic input] | ||
my_test_func | ||
|
||
**kwds: object | ||
[clinic start generated code]*/ | ||
""" | ||
self.expect_failure(block, err, lineno=4) | ||
|
||
class ParseFileUnitTest(TestCase): | ||
def expect_parsing_failure( | ||
|
@@ -1608,6 +1644,11 @@ def test_disallowed_grouping__must_be_position_only(self): | |
[ | ||
a: object | ||
] | ||
""", """ | ||
with_kwds | ||
[ | ||
**kwds: dict | ||
] | ||
Comment on lines
+1649
to
+1651
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While we are here, could you also add a case with a var-positional parameter inside an optional group? And I think that it would be worth to add a test for different kinds of parameters (keyword-or-positional, keyword-only, var-positional, var-keyword) after a valid optional group (if there are no such tests yet). This may be a separate test method. Some of these cases can be supported in principle in future. We want to know if we enabled them accidentally. |
||
""") | ||
err = ( | ||
"You cannot use optional groups ('[' and ']') unless all " | ||
|
@@ -1991,6 +2032,44 @@ def test_slash_after_vararg(self): | |
err = "Function 'bar': '/' must precede '*'" | ||
self.expect_failure(block, err) | ||
|
||
def test_slash_after_var_keyword(self): | ||
block = """ | ||
module foo | ||
foo.bar | ||
x: int | ||
y: int | ||
**kwds: dict | ||
z: int | ||
/ | ||
AA-Turner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" | ||
err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" | ||
self.expect_failure(block, err) | ||
|
||
def test_star_after_var_keyword(self): | ||
block = """ | ||
module foo | ||
foo.bar | ||
x: int | ||
y: int | ||
**kwds: dict | ||
z: int | ||
* | ||
AA-Turner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" | ||
err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" | ||
self.expect_failure(block, err) | ||
|
||
def test_parameter_after_var_keyword(self): | ||
block = """ | ||
module foo | ||
foo.bar | ||
x: int | ||
y: int | ||
**kwds: dict | ||
z: int | ||
""" | ||
err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" | ||
self.expect_failure(block, err) | ||
|
||
def test_depr_star_must_come_after_slash(self): | ||
block = """ | ||
module foo | ||
|
@@ -2079,6 +2158,16 @@ def test_parameters_no_more_than_one_vararg(self): | |
""" | ||
self.expect_failure(block, err, lineno=3) | ||
|
||
def test_parameters_no_more_than_one_var_keyword(self): | ||
err = "Encountered parameter line when not expecting parameters: **var_keyword_2: dict" | ||
block = """ | ||
module foo | ||
foo.bar | ||
**var_keyword_1: dict | ||
**var_keyword_2: dict | ||
""" | ||
self.expect_failure(block, err, lineno=3) | ||
|
||
def test_function_not_at_column_0(self): | ||
function = self.parse_function(""" | ||
module foo | ||
|
@@ -2513,6 +2602,14 @@ def test_vararg_cannot_take_default_value(self): | |
""" | ||
self.expect_failure(block, err, lineno=1) | ||
|
||
def test_var_keyword_cannot_take_default_value(self): | ||
err = "Function 'fn' has an invalid parameter declaration:" | ||
block = """ | ||
fn | ||
**kwds: dict = None | ||
""" | ||
self.expect_failure(block, err, lineno=1) | ||
|
||
def test_default_is_not_of_correct_type(self): | ||
err = ("int_converter: default value 2.5 for field 'a' " | ||
"is not of type 'int'") | ||
|
@@ -2610,6 +2707,43 @@ def test_disallow_defining_class_at_module_level(self): | |
""" | ||
self.expect_failure(block, err, lineno=2) | ||
|
||
def test_var_keyword_with_pos_or_kw(self): | ||
block = """ | ||
module foo | ||
foo.bar | ||
x: int | ||
**kwds: dict | ||
""" | ||
err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" | ||
self.expect_failure(block, err) | ||
|
||
def test_var_keyword_with_kw_only(self): | ||
block = """ | ||
module foo | ||
foo.bar | ||
x: int | ||
/ | ||
* | ||
y: int | ||
**kwds: dict | ||
""" | ||
err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" | ||
self.expect_failure(block, err) | ||
|
||
def test_var_keyword_with_pos_or_kw_and_kw_only(self): | ||
AA-Turner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
block = """ | ||
module foo | ||
foo.bar | ||
x: int | ||
/ | ||
y: int | ||
* | ||
z: int | ||
**kwds: dict | ||
""" | ||
err = "Function 'bar' has an invalid parameter declaration (**kwargs?): '**kwds: dict'" | ||
self.expect_failure(block, err) | ||
|
||
def test_allow_negative_accepted_by_py_ssize_t_converter_only(self): | ||
errmsg = re.escape("converter_init() got an unexpected keyword argument 'allow_negative'") | ||
unsupported_converters = [converter_name for converter_name in converters.keys() | ||
|
@@ -3954,6 +4088,49 @@ def test_depr_multi(self): | |
check("a", b="b", c="c", d="d", e="e", f="f", g="g") | ||
self.assertRaises(TypeError, fn, a="a", b="b", c="c", d="d", e="e", f="f", g="g") | ||
|
||
def test_lone_kwds(self): | ||
with self.assertRaises(TypeError): | ||
ac_tester.lone_kwds(1, 2) | ||
self.assertEqual(ac_tester.lone_kwds(), ({},)) | ||
self.assertEqual(ac_tester.lone_kwds(y='y'), ({'y': 'y'},)) | ||
kwds = {'y': 'y', 'z': 'z'} | ||
self.assertEqual(ac_tester.lone_kwds(y='y', z='z'), (kwds,)) | ||
self.assertEqual(ac_tester.lone_kwds(**kwds), (kwds,)) | ||
|
||
def test_kwds_with_pos_only(self): | ||
with self.assertRaises(TypeError): | ||
ac_tester.kwds_with_pos_only() | ||
with self.assertRaises(TypeError): | ||
ac_tester.kwds_with_pos_only(y='y') | ||
with self.assertRaises(TypeError): | ||
ac_tester.kwds_with_pos_only(1, y='y') | ||
self.assertEqual(ac_tester.kwds_with_pos_only(1, 2), (1, 2, {})) | ||
self.assertEqual(ac_tester.kwds_with_pos_only(1, 2, y='y'), (1, 2, {'y': 'y'})) | ||
kwds = {'y': 'y', 'z': 'z'} | ||
self.assertEqual(ac_tester.kwds_with_pos_only(1, 2, y='y', z='z'), (1, 2, kwds)) | ||
self.assertEqual(ac_tester.kwds_with_pos_only(1, 2, **kwds), (1, 2, kwds)) | ||
|
||
def test_kwds_with_stararg(self): | ||
self.assertEqual(ac_tester.kwds_with_stararg(), ((), {})) | ||
self.assertEqual(ac_tester.kwds_with_stararg(1, 2), ((1, 2), {})) | ||
self.assertEqual(ac_tester.kwds_with_stararg(y='y'), ((), {'y': 'y'})) | ||
args = (1, 2) | ||
kwds = {'y': 'y', 'z': 'z'} | ||
self.assertEqual(ac_tester.kwds_with_stararg(1, 2, y='y', z='z'), (args, kwds)) | ||
self.assertEqual(ac_tester.kwds_with_stararg(*args, **kwds), (args, kwds)) | ||
|
||
def test_kwds_with_pos_only_and_stararg(self): | ||
with self.assertRaises(TypeError): | ||
ac_tester.kwds_with_pos_only_and_stararg() | ||
with self.assertRaises(TypeError): | ||
ac_tester.kwds_with_pos_only_and_stararg(y='y') | ||
self.assertEqual(ac_tester.kwds_with_pos_only_and_stararg(1, 2), (1, 2, (), {})) | ||
self.assertEqual(ac_tester.kwds_with_pos_only_and_stararg(1, 2, y='y'), (1, 2, (), {'y': 'y'})) | ||
args = ('lobster', 'thermidor') | ||
kwds = {'y': 'y', 'z': 'z'} | ||
self.assertEqual(ac_tester.kwds_with_pos_only_and_stararg(1, 2, 'lobster', 'thermidor', y='y', z='z'), (1, 2, args, kwds)) | ||
self.assertEqual(ac_tester.kwds_with_pos_only_and_stararg(1, 2, *args, **kwds), (1, 2, args, kwds)) | ||
|
||
|
||
class LimitedCAPIOutputTests(unittest.TestCase): | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,6 +84,7 @@ | |
"argsbuf", | ||
"fastargs", | ||
"kwargs", | ||
"kwds", | ||
"kwnames", | ||
"nargs", | ||
"noptargs", | ||
|
Uh oh!
There was an error while loading. Please reload this page.