Skip to content

Commit bd0339f

Browse files
committed
fix int parsing
1 parent ce55e10 commit bd0339f

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed

src/input/shared.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,25 @@ pub fn int_as_bool<'a>(input: &'a impl Input<'a>, int: i64) -> ValResult<'a, boo
4444
}
4545

4646
pub fn str_as_int<'s, 'l>(input: &'s impl Input<'s>, str: &'l str) -> ValResult<'s, i64> {
47+
let str = strip_decimal_zeros(str);
4748
if let Ok(i) = str.parse::<i64>() {
4849
Ok(i)
49-
} else if let Ok(f) = str.parse::<f64>() {
50-
float_as_int(input, f)
5150
} else {
5251
Err(ValError::new(ErrorType::IntParsing, input))
5352
}
5453
}
5554

55+
/// we don't want to parse as f64 then call `float_as_int` as it can loose precision for large ints, therefore
56+
/// we strip `.0+` manually
57+
fn strip_decimal_zeros(s: &str) -> &str {
58+
if let Some(i) = s.find('.') {
59+
if s[i + 1..].chars().all(|c| c == '0') {
60+
return &s[..i];
61+
}
62+
}
63+
s
64+
}
65+
5666
pub fn float_as_int<'a>(input: &'a impl Input<'a>, float: f64) -> ValResult<'a, i64> {
5767
if float == f64::INFINITY || float == f64::NEG_INFINITY || float.is_nan() {
5868
Err(ValError::new(ErrorType::FiniteNumber, input))

tests/validators/test_int.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
(42.0, 42),
2727
('42.0', 42),
2828
('123456789.0', 123_456_789),
29-
('123456789123456.00001', 123_456_789_123_456),
29+
('123456789123456.00001', Err('Input should be a valid integer, unable to parse string as an integer')),
3030
(int(1e10), int(1e10)),
3131
(i64_max, i64_max),
3232
pytest.param(
@@ -61,12 +61,18 @@ def test_int_py_and_json(py_and_json: PyAndJson, input_value, expected):
6161
(Decimal('1.0'), 1),
6262
(i64_max, i64_max),
6363
(str(i64_max), i64_max),
64-
# (str(i64_max + 1), i64_max + 1),
64+
(
65+
str(i64_max + 1),
66+
Err(
67+
"Input should be a valid integer, unable to parse string as an integer "
68+
"[type=int_parsing, input_value='9223372036854775808', input_type=str]"
69+
),
70+
),
6571
(
6672
str(i64_max * 2),
6773
Err(
68-
"Input integer too large to convert to 64-bit integer "
69-
"[type=int_overflow, input_value='18446744073709551614', input_type=str]"
74+
"Input should be a valid integer, unable to parse string as an integer "
75+
"[type=int_parsing, input_value='18446744073709551614', input_type=str]"
7076
),
7177
),
7278
(i64_max + 1, i64_max + 1),
@@ -87,6 +93,7 @@ def test_int_py_and_json(py_and_json: PyAndJson, input_value, expected):
8793
id='tuple',
8894
),
8995
],
96+
ids=repr,
9097
)
9198
def test_int(input_value, expected):
9299
v = SchemaValidator({'type': 'int'})
@@ -350,24 +357,29 @@ def test_long_int(py_and_json: PyAndJson):
350357
v.validate_test('1' * 400)
351358

352359
assert exc_info.value.errors(include_url=False) == [
353-
{'type': 'finite_number', 'loc': (), 'msg': 'Input should be a finite number', 'input': '1' * 400}
360+
{
361+
'type': 'int_parsing',
362+
'loc': (),
363+
'msg': 'Input should be a valid integer, unable to parse string as an integer',
364+
'input': '1' * 400,
365+
}
354366
]
367+
# insert_assert(repr(exc_info.value))
355368
assert repr(exc_info.value) == (
356-
'1 validation error for int\n'
357-
' Input should be a finite number '
358-
'[type=finite_number, '
359-
"input_value='111111111111111111111111...11111111111111111111111', input_type=str]\n"
360-
f" For further information visit https://errors.pydantic.dev/{__version__}/v/finite_number"
369+
"1 validation error for int\n"
370+
" Input should be a valid integer, unable to parse string as an integer "
371+
"[type=int_parsing, input_value='111111111111111111111111...11111111111111111111111', input_type=str]\n"
372+
f" For further information visit https://errors.pydantic.dev/{__version__}/v/int_parsing"
361373
)
362374

363375

364376
def test_finite_number(py_and_json: PyAndJson):
365377
v = py_and_json({'type': 'int'})
366378

367-
with pytest.raises(ValidationError, match='Input should be a finite number'):
379+
with pytest.raises(ValidationError, match='Input should be a valid integer'):
368380
v.validate_test('-' + '1' * 400)
369381

370-
with pytest.raises(ValidationError, match='Input should be a finite number'):
382+
with pytest.raises(ValidationError, match='Input should be a valid integer'):
371383
v.validate_test('nan')
372384

373385

0 commit comments

Comments
 (0)