Repository: RustPython/RustPython (language: rust)

Issue:
{:d} format should support bool value.
{:d} format is supported to pass a boolean value. See the following test case. CPython can execute it and return expected result, while RustPython report a TypeError.

```
for i in range(12):
    print('{:d}, '.format(chr(i) in "ss"), end='')
    if i % 16 == 1:
        print()
```


Behaviors on CPython:
```
0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
```

Behaviors on RustPython
```
Traceback (most recent call last):
  File "/home/xxm/Desktop/RustPython/test.py", line 169, in <module>
    print('{:d}, '.format(chr(i) in "ss"), end='')
TypeError: unsupported format string passed to bool.__format__
```
Ubuntu 18.04
RustPython 0.2.0 [0284059](https://github.com/RustPython/RustPython/commit/02840593bc56ae416ba2646166628f1712d6cf43)
CPython 3.8.0, 3.9.0, 3.11.3


Discussion / hints:
@JazzGlobal are you interested in trying this one out? I think it's similar to what you contributed recently.
> @JazzGlobal are you interested in trying this one out? I think it's similar to what you contributed recently.

Sure I can take it!

Fix patch:
diff --git a/common/src/format.rs b/common/src/format.rs
index 24f296a764..8b2fa5972b 100644
--- a/common/src/format.rs
+++ b/common/src/format.rs
@@ -416,6 +416,19 @@ impl FormatSpec {
         }
     }
 
+    pub fn format_bool(&self, input: bool) -> Result<String, FormatSpecError> {
+        let x = u8::from(input);
+        let result: Result<String, FormatSpecError> = match &self.format_type {
+            Some(FormatType::Decimal) => Ok(x.to_string()),
+            None => {
+                let first_letter = (input.to_string().as_bytes()[0] as char).to_uppercase();
+                Ok(first_letter.collect::<String>() + &input.to_string()[1..])
+            }
+            _ => Err(FormatSpecError::InvalidFormatSpecifier),
+        };
+        result
+    }
+
     pub fn format_float(&self, num: f64) -> Result<String, FormatSpecError> {
         self.validate_format(FormatType::FixedPoint(Case::Lower))?;
         let precision = self.precision.unwrap_or(6);
diff --git a/vm/src/builtins/bool.rs b/vm/src/builtins/bool.rs
index d70af0f070..9569258479 100644
--- a/vm/src/builtins/bool.rs
+++ b/vm/src/builtins/bool.rs
@@ -1,7 +1,8 @@
 use super::{PyInt, PyStrRef, PyType, PyTypeRef};
 use crate::{
     class::PyClassImpl,
-    convert::{ToPyObject, ToPyResult},
+    common::format::FormatSpec,
+    convert::{IntoPyException, ToPyObject, ToPyResult},
     function::OptionalArg,
     identifier,
     protocol::PyNumberMethods,
@@ -110,12 +111,11 @@ impl Constructor for PyBool {
 #[pyclass(with(Constructor, AsNumber, Representable))]
 impl PyBool {
     #[pymethod(magic)]
-    fn format(obj: PyObjectRef, format_spec: PyStrRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
-        if format_spec.is_empty() {
-            obj.str(vm)
-        } else {
-            Err(vm.new_type_error("unsupported format string passed to bool.__format__".to_owned()))
-        }
+    fn format(obj: PyObjectRef, spec: PyStrRef, vm: &VirtualMachine) -> PyResult<String> {
+        let new_bool = obj.try_to_bool(vm)?;
+        FormatSpec::parse(spec.as_str())
+            .and_then(|format_spec| format_spec.format_bool(new_bool))
+            .map_err(|err| err.into_pyexception(vm))
     }
 
     #[pymethod(name = "__ror__")]


Test patch: