diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1473,16 +1473,20 @@ class BuiltinTest(unittest.TestCase): for fmt_str in fmt_strs: test_deprecated_format_string(cls(), fmt_str, len(fmt_str) != 0) # -------------------------------------------------------------------- # make sure we can take a subclass of str as a format spec class DerivedFromStr(str): pass self.assertEqual(format(0, DerivedFromStr('10')), ' 0') + for fmt in ['{:a}', '{:b}', '{:c}', '{:s}', '{:d}']: + with self.subTest(format_spec=fmt): + self.assertRaises(ValueError, format, b'spam', fmt) + def test_bin(self): self.assertEqual(bin(0), '0b0') self.assertEqual(bin(1), '0b1') self.assertEqual(bin(-1), '-0b1') self.assertEqual(bin(2**65), '0b1' + '0' * 65) self.assertEqual(bin(2**65-1), '0b' + '1' * 65) self.assertEqual(bin(-(2**65)), '-0b1' + '0' * 65) self.assertEqual(bin(-(2**65-1)), '-0b' + '1' * 65) diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -469,11 +469,25 @@ class FormatTest(unittest.TestCase): f = 1.2 with self.assertRaises(ValueError) as cm: format(f, ".%sf" % (INT_MAX + 1)) c = complex(f) with self.assertRaises(ValueError) as cm: format(c, ".%sf" % (INT_MAX + 1)) + def test_reject_formatting_on_bytes(self): + msg = "Unknown format code '{}' for object of type 'bytes'" + tests = [ + ('{:a}', 'a'), + ('{:b}', 'b'), + ('{:c}', 'c'), + ('{:s}', 's'), + ('{:d}', 'd'), + ] + for fmt, fmt_code in tests: + with self.subTest(format_spec=fmt): + with self.assertRaises(ValueError) as cm: + fmt.format(b'spam') + self.assertEqual(str(cm.exception), msg.format(fmt_code)) if __name__ == "__main__": unittest.main() diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4401,16 +4401,23 @@ object_format(PyObject *self, PyObject * { PyObject *format_spec; PyObject *self_as_str = NULL; PyObject *result = NULL; if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) return NULL; + if (PyBytes_Check(self)) { + PyErr_Format(PyExc_ValueError, + "Unknown format code %R for object of type 'bytes'", + format_spec); + return result; + } + self_as_str = PyObject_Str(self); if (self_as_str != NULL) { /* Issue 7994: If we're converting to a string, we should reject format specifications */ if (PyUnicode_GET_LENGTH(format_spec) > 0) { PyErr_SetString(PyExc_TypeError, "non-empty format string passed to object.__format__"); goto done;