Skip to content

Commit e1ccf02

Browse files
committed
Apply lint, start tests
1 parent 06e8700 commit e1ccf02

File tree

4 files changed

+111
-26
lines changed

4 files changed

+111
-26
lines changed

python/pydantic_core/core_schema.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3594,7 +3594,7 @@ def arguments_v3_schema(
35943594
serialization: Custom serialization schema.
35953595
"""
35963596
return _dict_not_none(
3597-
type='arguments-v2',
3597+
type='arguments-v3',
35983598
arguments_schema=arguments,
35993599
validate_by_name=validate_by_name,
36003600
validate_by_alias=validate_by_alias,
@@ -4031,6 +4031,7 @@ def definition_reference_schema(
40314031
DataclassArgsSchema,
40324032
DataclassSchema,
40334033
ArgumentsSchema,
4034+
ArgumentsV3Schema,
40344035
CallSchema,
40354036
CustomErrorSchema,
40364037
JsonSchema,

src/validators/arguments_v3.rs

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,10 @@ struct Parameter {
5555

5656
impl Parameter {
5757
fn is_variadic(&self) -> bool {
58-
match self.mode {
59-
ParameterMode::VarArgs | ParameterMode::VarKwargsUniform | ParameterMode::VarKwargsUnpackedTypedDict => {
60-
true
61-
}
62-
_ => false,
63-
}
58+
matches!(
59+
self.mode,
60+
ParameterMode::VarArgs | ParameterMode::VarKwargsUniform | ParameterMode::VarKwargsUnpackedTypedDict
61+
)
6462
}
6563
}
6664

@@ -75,7 +73,7 @@ pub struct ArgumentsV3Validator {
7573
}
7674

7775
impl BuildValidator for ArgumentsV3Validator {
78-
const EXPECTED_TYPE: &'static str = "arguments-v2";
76+
const EXPECTED_TYPE: &'static str = "arguments-v3";
7977

8078
fn build(
8179
schema: &Bound<'_, PyDict>,
@@ -195,12 +193,12 @@ impl ArgumentsV3Validator {
195193
let validate_by_alias = state.validate_by_alias_or(self.validate_by_alias);
196194
let validate_by_name = state.validate_by_name_or(self.validate_by_name);
197195

198-
for parameter in self.parameters.iter() {
196+
for parameter in &self.parameters {
199197
let lookup_key = parameter
200198
.lookup_key_collection
201199
.select(validate_by_alias, validate_by_name)?;
202200
// A value is present in the mapping:
203-
if let Some((lookup_path, dict_value)) = mapping.get_item(&lookup_key)? {
201+
if let Some((lookup_path, dict_value)) = mapping.get_item(lookup_key)? {
204202
match parameter.mode {
205203
ParameterMode::PositionalOnly | ParameterMode::PositionalOrKeyword => {
206204
match parameter.validator.validate(py, dict_value.borrow_input(), state) {
@@ -221,15 +219,15 @@ impl ArgumentsV3Validator {
221219
match parameter.validator.validate(py, v.unwrap().borrow_input(), state) {
222220
Ok(tuple_value) => {
223221
output_args.push(tuple_value);
224-
return Ok(());
222+
Ok(())
225223
}
226224
Err(ValError::LineErrors(line_errors)) => {
227225
errors.extend(line_errors.into_iter().map(|err| {
228226
lookup_path.apply_error_loc(err, self.loc_by_alias, &parameter.name)
229227
}));
230-
return Ok(());
228+
Ok(())
231229
}
232-
Err(err) => return Err(err),
230+
Err(err) => Err(err),
233231
}
234232
})?;
235233
}
@@ -241,7 +239,7 @@ impl ArgumentsV3Validator {
241239
ParameterMode::KeywordOnly => {
242240
match parameter.validator.validate(py, dict_value.borrow_input(), state) {
243241
Ok(value) => {
244-
output_kwargs.set_item(PyString::new(py, parameter.name.as_str()).unbind(), value)?
242+
output_kwargs.set_item(PyString::new(py, parameter.name.as_str()).unbind(), value)?;
245243
}
246244
Err(ValError::LineErrors(line_errors)) => {
247245
errors.extend(
@@ -256,7 +254,7 @@ impl ArgumentsV3Validator {
256254
ParameterMode::VarKwargsUniform => match dict_value.borrow_input().as_kwargs(py) {
257255
// We will validate that keys are strings, and values match the validator:
258256
Some(value) => {
259-
for (dict_key, dict_value) in value.into_iter() {
257+
for (dict_key, dict_value) in value {
260258
// Validate keys are strings:
261259
match dict_key.validate_str(true, false).map(ValidationMatch::into_inner) {
262260
Ok(_) => (),
@@ -346,9 +344,9 @@ impl ArgumentsV3Validator {
346344
}
347345

348346
if !errors.is_empty() {
349-
return Err(ValError::LineErrors(errors));
347+
Err(ValError::LineErrors(errors))
350348
} else {
351-
return Ok((PyTuple::new(py, output_args)?, output_kwargs).into_py_any(py)?);
349+
Ok((PyTuple::new(py, output_args)?, output_kwargs).into_py_any(py)?)
352350
}
353351
}
354352

@@ -396,7 +394,7 @@ impl ArgumentsV3Validator {
396394
parameter.mode,
397395
ParameterMode::PositionalOrKeyword | ParameterMode::KeywordOnly
398396
) {
399-
if let Some((lookup_path, value)) = kwargs.get_item(&lookup_key)? {
397+
if let Some((lookup_path, value)) = kwargs.get_item(lookup_key)? {
400398
used_kwargs.insert(lookup_path.first_key());
401399
kw_value = Some((lookup_path, value));
402400
}
@@ -421,7 +419,7 @@ impl ArgumentsV3Validator {
421419
(None, Some((lookup_path, kw_value))) => {
422420
match parameter.validator.validate(py, kw_value.borrow_input(), state) {
423421
Ok(value) => {
424-
output_kwargs.set_item(PyString::new(py, parameter.name.as_str()).unbind(), value)?
422+
output_kwargs.set_item(PyString::new(py, parameter.name.as_str()).unbind(), value)?;
425423
}
426424
Err(ValError::LineErrors(line_errors)) => {
427425
errors.extend(
@@ -442,7 +440,7 @@ impl ArgumentsV3Validator {
442440
parameter.mode,
443441
ParameterMode::PositionalOnly | ParameterMode::PositionalOrKeyword
444442
) {
445-
output_kwargs.set_item(PyString::new(py, parameter.name.as_str()).unbind(), value)?
443+
output_kwargs.set_item(PyString::new(py, parameter.name.as_str()).unbind(), value)?;
446444
} else {
447445
output_args.push(value);
448446
}
@@ -601,9 +599,9 @@ impl ArgumentsV3Validator {
601599
}
602600

603601
if !errors.is_empty() {
604-
return Err(ValError::LineErrors(errors));
602+
Err(ValError::LineErrors(errors))
605603
} else {
606-
return Ok((PyTuple::new(py, output_args)?, output_kwargs).into_py_any(py)?);
604+
Ok((PyTuple::new(py, output_args)?, output_kwargs).into_py_any(py)?)
607605
}
608606
}
609607
}
@@ -622,10 +620,10 @@ impl Validator for ArgumentsV3Validator {
622620

623621
// Validation from a dictionary, mapping parameter names to the values:
624622
if let Ok(dict) = args_dict {
625-
return self.validate_from_mapping(py, input, dict, state);
623+
self.validate_from_mapping(py, input, dict, state)
626624
} else {
627625
let args = input.validate_args_v3()?;
628-
return self.validate_from_argskwargs(py, input, args, state);
626+
self.validate_from_argskwargs(py, input, args, state)
629627
}
630628
}
631629

tests/conftest.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import hypothesis
1515
import pytest
1616

17-
from pydantic_core import ArgsKwargs, SchemaValidator, ValidationError, validate_core_schema
17+
from pydantic_core import ArgsKwargs, CoreSchema, SchemaValidator, ValidationError, validate_core_schema
1818
from pydantic_core.core_schema import CoreConfig
1919

2020
__all__ = 'Err', 'PyAndJson', 'plain_repr', 'infinite_generator'
@@ -52,7 +52,11 @@ def json_default(obj):
5252

5353
class PyAndJsonValidator:
5454
def __init__(
55-
self, schema, config: CoreConfig | None = None, *, validator_type: Literal['json', 'python'] | None = None
55+
self,
56+
schema: CoreSchema,
57+
config: CoreConfig | None = None,
58+
*,
59+
validator_type: Literal['json', 'python'] | None = None,
5660
):
5761
self.validator = SchemaValidator(validate_core_schema(schema), config)
5862
self.validator_type = validator_type

tests/validators/test_arguments_v3.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import pytest
2+
3+
from pydantic_core import ArgsKwargs, ValidationError
4+
from pydantic_core import core_schema as cs
5+
6+
from ..conftest import PyAndJson
7+
8+
9+
@pytest.mark.parametrize(
10+
['input_value', 'expected'],
11+
(
12+
[ArgsKwargs((1, True), {}), ((1, True), {})],
13+
[ArgsKwargs((1,), {}), ((1,), {})],
14+
[{'a': 1, 'b': True}, ((1, True), {})],
15+
[{'a': 1}, ((1,), {})],
16+
),
17+
)
18+
def test_positional_only(py_and_json: PyAndJson, input_value, expected) -> None:
19+
v = py_and_json(
20+
cs.arguments_v3_schema(
21+
[
22+
cs.arguments_v3_parameter(name='a', schema=cs.int_schema(), mode='positional_only'),
23+
cs.arguments_v3_parameter(
24+
name='b', schema=cs.with_default_schema(cs.bool_schema()), mode='positional_only'
25+
),
26+
]
27+
)
28+
)
29+
30+
assert v.validate_test(input_value) == expected
31+
32+
33+
def test_positional_only_validation_error(py_and_json: PyAndJson) -> None:
34+
v = py_and_json(
35+
cs.arguments_v3_schema(
36+
[
37+
cs.arguments_v3_parameter(name='a', schema=cs.int_schema(), mode='positional_only'),
38+
]
39+
)
40+
)
41+
42+
with pytest.raises(ValidationError) as exc_info:
43+
v.validate_test(ArgsKwargs(('not_an_int',), {}))
44+
45+
error = exc_info.value.errors()[0]
46+
47+
assert error['type'] == 'int_parsing'
48+
assert error['loc'] == (0,)
49+
50+
with pytest.raises(ValidationError) as exc_info:
51+
v.validate_test({'a': 'not_an_int'})
52+
53+
error = exc_info.value.errors()[0]
54+
55+
assert error['type'] == 'int_parsing'
56+
assert error['loc'] == ('a',)
57+
58+
59+
def test_positional_only_error_required(py_and_json: PyAndJson) -> None:
60+
v = py_and_json(
61+
cs.arguments_v3_schema(
62+
[
63+
cs.arguments_v3_parameter(name='a', schema=cs.int_schema(), mode='positional_only'),
64+
]
65+
)
66+
)
67+
68+
with pytest.raises(ValidationError) as exc_info:
69+
v.validate_test(ArgsKwargs(tuple(), {}))
70+
71+
error = exc_info.value.errors()[0]
72+
73+
assert error['type'] == 'missing_positional_only_argument'
74+
assert error['loc'] == (0,)
75+
76+
with pytest.raises(ValidationError) as exc_info:
77+
v.validate_test({})
78+
79+
error = exc_info.value.errors()[0]
80+
81+
assert error['type'] == 'missing_positional_only_argument'
82+
assert error['loc'] == ('a',)

0 commit comments

Comments
 (0)