diff --git a/common/src/format.rs b/common/src/format.rs index b9589ee70..81ae1093f 100644 --- a/common/src/format.rs +++ b/common/src/format.rs @@ -422,10 +422,11 @@ impl FormatSpec { } } - pub fn format_float(&self, num: f64) -> Result { + pub fn format_float(&self, num: f64) -> Result { + self.validate_format(FormatType::FixedPointLower)?; let precision = self.precision.unwrap_or(6); let magnitude = num.abs(); - let raw_magnitude_str: Result = match self.format_type { + let raw_magnitude_str: Result = match self.format_type { Some(FormatType::FixedPointUpper) => Ok(float_ops::format_fixed( precision, magnitude, @@ -436,17 +437,21 @@ impl FormatSpec { magnitude, float_ops::Case::Lower, )), - Some(FormatType::Decimal) => Err("Unknown format code 'd' for object of type 'float'"), - Some(FormatType::Binary) => Err("Unknown format code 'b' for object of type 'float'"), - Some(FormatType::Octal) => Err("Unknown format code 'o' for object of type 'float'"), - Some(FormatType::HexLower) => Err("Unknown format code 'x' for object of type 'float'"), - Some(FormatType::HexUpper) => Err("Unknown format code 'X' for object of type 'float'"), - Some(FormatType::String) => Err("Unknown format code 's' for object of type 'float'"), - Some(FormatType::Character) => { - Err("Unknown format code 'c' for object of type 'float'") + Some(FormatType::Decimal) + | Some(FormatType::Binary) + | Some(FormatType::Octal) + | Some(FormatType::HexLower) + | Some(FormatType::HexUpper) + | Some(FormatType::String) + | Some(FormatType::Character) => { + let ch = char::from(self.format_type.as_ref().unwrap()); + Err(format!( + "Unknown format code '{}' for object of type 'float'", + ch + )) } Some(FormatType::Number) => { - Err("Format code 'n' for object of type 'float' not implemented yet") + Err("Format code 'n' for object of type 'float' not implemented yet".to_owned()) } Some(FormatType::GeneralFormatUpper) => { let precision = if precision == 0 { 1 } else { precision }; @@ -513,6 +518,7 @@ impl FormatSpec { }; let magnitude_str = self.add_magnitude_separators(raw_magnitude_str?, sign_str); self.format_sign_and_align(&magnitude_str, sign_str, FormatAlign::Right) + .map_err(|msg| msg.to_owned()) } #[inline] @@ -574,7 +580,7 @@ impl FormatSpec { | Some(FormatType::ExponentUpper) | Some(FormatType::ExponentLower) | Some(FormatType::Percentage) => match num.to_f64() { - Some(float) => return self.format_float(float).map_err(|msg| msg.to_owned()), + Some(float) => return self.format_float(float), _ => Err("Unable to convert int to float".to_owned()), }, None => self.format_int_radix(magnitude, 10), diff --git a/extra_tests/snippets/builtin_format.py b/extra_tests/snippets/builtin_format.py index 37212bebc..074d9a820 100644 --- a/extra_tests/snippets/builtin_format.py +++ b/extra_tests/snippets/builtin_format.py @@ -68,3 +68,5 @@ assert f"{1234:.3g}" == "1.23e+03" assert f"{1234567:.6G}" == "1.23457E+06" assert_raises(ValueError, "{:,o}".format, 1, _msg="ValueError: Cannot specify ',' with 'o'.") assert_raises(ValueError, "{:_n}".format, 1, _msg="ValueError: Cannot specify '_' with 'n'.") +assert_raises(ValueError, "{:,o}".format, 1.0, _msg="ValueError: Cannot specify ',' with 'o'.") +assert_raises(ValueError, "{:_n}".format, 1.0, _msg="ValueError: Cannot specify '_' with 'n'.") diff --git a/vm/src/builtins/float.rs b/vm/src/builtins/float.rs index 8068c8cd8..54b257908 100644 --- a/vm/src/builtins/float.rs +++ b/vm/src/builtins/float.rs @@ -189,12 +189,11 @@ fn float_from_string(val: PyObjectRef, vm: &VirtualMachine) -> PyResult { impl PyFloat { #[pymethod(magic)] fn format(&self, spec: PyStrRef, vm: &VirtualMachine) -> PyResult { - match FormatSpec::parse(spec.as_str()) - .and_then(|format_spec| format_spec.format_float(self.value)) - { - Ok(string) => Ok(string), - Err(err) => Err(vm.new_value_error(err.to_string())), - } + let format_spec = + FormatSpec::parse(spec.as_str()).map_err(|msg| vm.new_value_error(msg.to_owned()))?; + format_spec + .format_float(self.value) + .map_err(|msg| vm.new_value_error(msg)) } #[pystaticmethod(magic)]