Skip to content

Commit

Permalink
fix: keyword only non default argument (#1290)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeanArhancet authored May 18, 2024
1 parent 0f8445e commit b777774
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
7 changes: 6 additions & 1 deletion src/validators/arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ impl BuildValidator for ArgumentsValidator {

let mut positional_params_count = 0;
let mut had_default_arg = false;
let mut had_keyword_only = false;

for (arg_index, arg) in arguments_schema.iter().enumerate() {
let arg = arg.downcast::<PyDict>()?;
Expand All @@ -68,6 +69,10 @@ impl BuildValidator for ArgumentsValidator {
positional_params_count = arg_index + 1;
}

if mode == "keyword_only" {
had_keyword_only = true;
}

let mut kw_lookup_key = None;
let mut kwarg_key = None;
if mode == "keyword_only" || mode == "positional_or_keyword" {
Expand Down Expand Up @@ -98,7 +103,7 @@ impl BuildValidator for ArgumentsValidator {
_ => false,
};

if had_default_arg && !has_default {
if had_default_arg && !has_default && !had_keyword_only {
return py_schema_err!("Non-default argument '{}' follows default argument", name);
} else if has_default {
had_default_arg = true;
Expand Down
77 changes: 77 additions & 0 deletions tests/validators/test_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,83 @@ def test_positional_or_keyword(py_and_json: PyAndJson, input_value, expected):
assert v.validate_test(input_value) == expected


@pytest.mark.parametrize(
'input_value,expected,arguments_schema',
[
(
{'a': 1, 'b': 2, 'e': 3.14},
((), {'a': 1, 'b': 2, 'c': 5, 'd': 'default', 'e': 3.14}),
[
{'name': 'a', 'mode': 'positional_or_keyword', 'schema': {'type': 'int'}},
{'name': 'b', 'mode': 'positional_or_keyword', 'schema': {'type': 'int'}},
{
'name': 'c',
'mode': 'keyword_only',
'schema': {'type': 'default', 'schema': {'type': 'int'}, 'default': 5},
},
{
'name': 'd',
'mode': 'keyword_only',
'schema': {'type': 'default', 'schema': {'type': 'str'}, 'default': 'default'},
},
{'name': 'e', 'mode': 'keyword_only', 'schema': {'type': 'float'}},
],
),
(
{'y': 'test'},
((), {'x': 1, 'y': 'test'}),
[
{
'name': 'x',
'mode': 'keyword_only',
'schema': {'type': 'default', 'schema': {'type': 'int'}, 'default': 1},
},
{'name': 'y', 'mode': 'keyword_only', 'schema': {'type': 'str'}},
],
),
(
{'a': 1, 'd': 3.14},
((), {'a': 1, 'b': 10, 'c': 'hello', 'd': 3.14}),
[
{'name': 'a', 'mode': 'positional_or_keyword', 'schema': {'type': 'int'}},
{
'name': 'b',
'mode': 'positional_or_keyword',
'schema': {'type': 'default', 'schema': {'type': 'int'}, 'default': 10},
},
{
'name': 'c',
'mode': 'keyword_only',
'schema': {'type': 'default', 'schema': {'type': 'str'}, 'default': 'hello'},
},
{'name': 'd', 'mode': 'keyword_only', 'schema': {'type': 'float'}},
],
),
(
{'x': 3, 'y': 'custom', 'z': 4},
((), {'x': 3, 'y': 'custom', 'z': 4}),
[
{'name': 'x', 'mode': 'positional_or_keyword', 'schema': {'type': 'int'}},
{
'name': 'y',
'mode': 'keyword_only',
'schema': {'type': 'default', 'schema': {'type': 'str'}, 'default': 'default'},
},
{'name': 'z', 'mode': 'keyword_only', 'schema': {'type': 'int'}},
],
),
],
)
def test_keyword_only_non_default(py_and_json: PyAndJson, input_value, expected, arguments_schema):
v = py_and_json(
{
'type': 'arguments',
'arguments_schema': arguments_schema,
}
)
assert v.validate_test(input_value) == expected


@pytest.mark.parametrize('input_value,expected', [[(1,), ((1,), {})], [(), ((42,), {})]], ids=repr)
def test_positional_optional(py_and_json: PyAndJson, input_value, expected):
v = py_and_json(
Expand Down

0 comments on commit b777774

Please sign in to comment.