diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e7f13a4e..68e70b0f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: pass_filenames: false - id: clippy name: Clippy - entry: cargo clippy -- -D warnings -A incomplete_features -W clippy::dbg_macro -W clippy::print_stdout + entry: cargo clippy -F python -- -D warnings -A incomplete_features -W clippy::dbg_macro -W clippy::print_stdout types: [rust] language: system pass_filenames: false diff --git a/src/python.rs b/src/python.rs index 68009b47..e2e11af6 100644 --- a/src/python.rs +++ b/src/python.rs @@ -9,7 +9,7 @@ use pyo3::{ffi, AsPyPointer}; use hashbrown::hash_map::{HashMap, RawEntryMut}; use smallvec::SmallVec; -use crate::errors::{json_err, JsonError, JsonResult, DEFAULT_RECURSION_LIMIT}; +use crate::errors::{json_err, json_error, JsonError, JsonResult, DEFAULT_RECURSION_LIMIT}; use crate::number_decoder::{NumberAny, NumberInt}; use crate::parse::{Parser, Peek}; use crate::string_decoder::{StringDecoder, Tape}; @@ -59,6 +59,10 @@ struct PythonParser<'j> { impl<'j> PythonParser<'j> { fn py_take_value(&mut self, py: Python, peek: Peek) -> JsonResult { match peek { + Peek::Null => { + self.parser.consume_null()?; + Ok(py.None()) + } Peek::True => { self.parser.consume_true()?; Ok(true.to_object(py)) @@ -67,10 +71,6 @@ impl<'j> PythonParser<'j> { self.parser.consume_false()?; Ok(false.to_object(py)) } - Peek::Null => { - self.parser.consume_null()?; - Ok(py.None()) - } Peek::String => { let s = self.parser.consume_string::(&mut self.tape)?; Ok(StringCache::get(py, s.as_str())) @@ -120,11 +120,18 @@ impl<'j> PythonParser<'j> { _ => { let n = self .parser - .consume_number::(peek.into_inner(), self.allow_inf_nan)?; + .consume_number::(peek.into_inner(), self.allow_inf_nan); match n { - NumberAny::Int(NumberInt::Int(int)) => Ok(int.to_object(py)), - NumberAny::Int(NumberInt::BigInt(big_int)) => Ok(big_int.to_object(py)), - NumberAny::Float(float) => Ok(float.to_object(py)), + Ok(NumberAny::Int(NumberInt::Int(int))) => Ok(int.to_object(py)), + Ok(NumberAny::Int(NumberInt::BigInt(big_int))) => Ok(big_int.to_object(py)), + Ok(NumberAny::Float(float)) => Ok(float.to_object(py)), + Err(e) => { + if !peek.is_num() { + Err(json_error!(ExpectedSomeValue, self.parser.index)) + } else { + Err(e) + } + } } } } diff --git a/tests/main.rs b/tests/main.rs index 88128d6a..6b3ccb0a 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -230,6 +230,7 @@ single_tests! { second_line: err => "[1\nx]", "ExpectedListCommaOrEnd @ 2:1"; floats_error: err => "06", "InvalidNumber @ 1:2"; unexpect_value: err => "[\u{16}\u{8}", "ExpectedSomeValue @ 1:2"; + unexpect_value_xx: err => "xx", "ExpectedSomeValue @ 1:1"; } #[test] diff --git a/tests/python.rs b/tests/python.rs index 97ac682b..c1a124c9 100644 --- a/tests/python.rs +++ b/tests/python.rs @@ -126,3 +126,15 @@ fn test_recursion_limit_incr() { assert_eq!(v.as_ref(py).len().unwrap(), 2000); }); } + +#[test] +fn test_exected_value_error() { + let json = "xx"; + let bytes = json.as_bytes(); + + Python::with_gil(|py| { + let r = python_parse(py, bytes, false, true); + let e = r.map_err(|e| map_json_error(bytes, &e)).unwrap_err(); + assert_eq!(e.to_string(), "ValueError: expected value at line 1 column 1"); + }) +}