diff --git a/Include/Python-ast.h b/Include/Python-ast.h index a702dbc2fb2..66d7b52580e 100644 --- a/Include/Python-ast.h +++ b/Include/Python-ast.h @@ -516,4 +516,3 @@ keyword_ty _Py_keyword(identifier arg, expr_ty value, PyArena *arena); alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena); PyObject* PyAST_mod2obj(mod_ty t); - diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 4dee01b7f20..83f6f93627f 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -69,9 +69,11 @@ class BytesTest(unittest.TestCase): self.assertRaises(ValueError, bytes, [10**100]) def test_repr(self): - self.assertEqual(repr(bytes()), "bytes()") - self.assertEqual(repr(bytes([0])), "bytes([0x00])") - self.assertEqual(repr(bytes([0, 1, 254, 255])), "bytes([0x00, 0x01, 0xfe, 0xff])") + self.assertEqual(repr(bytes()), "b''") + self.assertEqual(repr(bytes([0])), "b'\\0'") + self.assertEqual(repr(bytes([0, 1, 254, 255])), "b'\\0\\x01\\xfe\\xff'") + self.assertEqual(repr(bytes('abc')), "b'abc'") + self.assertEqual(repr(bytes("'")), "b'\\''") def test_compare(self): b1 = bytes([1, 2, 3]) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 09abaea97fa..88e65858c6c 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -733,65 +733,63 @@ bytes_init(PyBytesObject *self, PyObject *args, PyObject *kwds) return -1; } +/* Mostly copied from string_repr, but without the + "smart quote" functionality. */ static PyObject * bytes_repr(PyBytesObject *self) { - PyObject *list; - PyObject *str; - PyObject *result; - int err; - int i; - - if (self->ob_size == 0) - return PyString_FromString("bytes()"); - - list = PyList_New(0); - if (list == NULL) + size_t newsize = 3 + 4 * self->ob_size; + PyObject *v; + if (newsize > PY_SSIZE_T_MAX || newsize / 4 != self->ob_size) { + PyErr_SetString(PyExc_OverflowError, + "bytes object is too large to make repr"); return NULL; - - str = PyString_FromString("bytes(["); - if (str == NULL) - goto error; - - err = PyList_Append(list, str); - Py_DECREF(str); - if (err < 0) - goto error; - - for (i = 0; i < self->ob_size; i++) { - char buffer[20]; - sprintf(buffer, ", 0x%02x", (unsigned char) (self->ob_bytes[i])); - str = PyString_FromString((i == 0) ? buffer+2 : buffer); - if (str == NULL) - goto error; - err = PyList_Append(list, str); - Py_DECREF(str); - if (err < 0) - goto error; } + v = PyString_FromStringAndSize((char *)NULL, newsize); + if (v == NULL) { + return NULL; + } + else { + register Py_ssize_t i; + register char c; + register char *p; + int quote = '\''; - str = PyString_FromString("])"); - if (str == NULL) - goto error; - - err = PyList_Append(list, str); - Py_DECREF(str); - if (err < 0) - goto error; - - str = PyString_FromString(""); - if (str == NULL) - goto error; - - result = _PyString_Join(str, list); - Py_DECREF(str); - Py_DECREF(list); - return result; - - error: - /* Error handling when list != NULL */ - Py_DECREF(list); - return NULL; + p = PyString_AS_STRING(v); + *p++ = 'b'; + *p++ = quote; + for (i = 0; i < self->ob_size; i++) { + /* There's at least enough room for a hex escape + and a closing quote. */ + assert(newsize - (p - PyString_AS_STRING(v)) >= 5); + c = self->ob_bytes[i]; + if (c == quote || c == '\\') + *p++ = '\\', *p++ = c; + else if (c == '\t') + *p++ = '\\', *p++ = 't'; + else if (c == '\n') + *p++ = '\\', *p++ = 'n'; + else if (c == '\r') + *p++ = '\\', *p++ = 'r'; + else if (c == 0) + *p++ = '\\', *p++ = '0'; + else if (c < ' ' || c >= 0x7f) { + /* For performance, we don't want to call + PyOS_snprintf here (extra layers of + function call). */ + sprintf(p, "\\x%02x", c & 0xff); + p += 4; + } + else + *p++ = c; + } + assert(newsize - (p - PyString_AS_STRING(v)) >= 1); + *p++ = quote; + *p = '\0'; + _PyString_Resize( + &v, (p - PyString_AS_STRING(v))); + return v; + } } static PyObject * diff --git a/Python/symtable.c b/Python/symtable.c index 5f0290afa1a..1d76e0d025d 100644 --- a/Python/symtable.c +++ b/Python/symtable.c @@ -1177,7 +1177,8 @@ symtable_visit_expr(struct symtable *st, expr_ty e) break; case Num_kind: case Str_kind: - case Ellipsis_kind: + case Bytes_kind: + case Ellipsis_kind: /* Nothing to do here. */ break; /* The following exprs can be assignment targets. */