diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst index d4dda7c6939..a171ac7c537 100644 --- a/Doc/c-api/arg.rst +++ b/Doc/c-api/arg.rst @@ -260,9 +260,11 @@ Numbers ``n`` (:class:`int`) [Py_ssize_t] Convert a Python integer to a C :c:type:`Py_ssize_t`. -``c`` (:class:`bytes` of length 1) [char] - Convert a Python byte, represented as a :class:`bytes` object of length 1, - to a C :c:type:`char`. +``c`` (:class:`bytes` or :class:`bytearray` of length 1) [char] + Convert a Python byte, represented as a :class:`bytes` or + :class:`bytearray` object of length 1, to a C :c:type:`char`. + + .. versionchanged:: 3.3 Allow :class:`bytearray` objects ``C`` (:class:`str` of length 1) [int] Convert a Python character, represented as a :class:`str` object of diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 234b56c8b11..d32a44b7b45 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -475,6 +475,27 @@ class BaseBytesTest(unittest.TestCase): self.assertRaises(TypeError, self.type2test(b'abc').lstrip, 'b') self.assertRaises(TypeError, self.type2test(b'abc').rstrip, 'b') + def test_center(self): + # Fill character can be either bytes or bytearray (issue 12380) + b = self.type2test(b'abc') + for fill_type in (bytes, bytearray): + self.assertEqual(b.center(7, fill_type(b'-')), + self.type2test(b'--abc--')) + + def test_ljust(self): + # Fill character can be either bytes or bytearray (issue 12380) + b = self.type2test(b'abc') + for fill_type in (bytes, bytearray): + self.assertEqual(b.ljust(7, fill_type(b'-')), + self.type2test(b'abc----')) + + def test_rjust(self): + # Fill character can be either bytes or bytearray (issue 12380) + b = self.type2test(b'abc') + for fill_type in (bytes, bytearray): + self.assertEqual(b.rjust(7, fill_type(b'-')), + self.type2test(b'----abc')) + def test_ord(self): b = self.type2test(b'\0A\x7f\x80\xff') self.assertEqual([ord(b[i:i+1]) for i in range(len(b))], diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index 3d9c06a4607..768ea8d4865 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -294,6 +294,15 @@ class Keywords_TestCase(unittest.TestCase): self.fail('TypeError should have been raised') class Bytes_TestCase(unittest.TestCase): + def test_c(self): + from _testcapi import getargs_c + self.assertRaises(TypeError, getargs_c, b'abc') # len > 1 + self.assertEqual(getargs_c(b'a'), b'a') + self.assertEqual(getargs_c(bytearray(b'a')), b'a') + self.assertRaises(TypeError, getargs_c, memoryview(b'a')) + self.assertRaises(TypeError, getargs_c, 's') + self.assertRaises(TypeError, getargs_c, None) + def test_s(self): from _testcapi import getargs_s self.assertEqual(getargs_s('abc\xe9'), b'abc\xc3\xa9') diff --git a/Misc/NEWS b/Misc/NEWS index 083b68c0050..c7b36e0cf90 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -238,6 +238,9 @@ Core and Builtins - Issue #11386: bytearray.pop() now throws IndexError when the bytearray is empty, instead of OverflowError. +- Issue #12380: The rjust, ljust and center methods of bytes and bytearray + now accept a bytearray argument. + Library ------- @@ -1282,6 +1285,8 @@ C-API - Issue #12173: The first argument of PyImport_ImportModuleLevel is now `const char *` instead of `char *`. +- Issue #12380: PyArg_ParseTuple now accepts a bytearray for the 'c' format. + Documentation ------------- @@ -6680,4 +6685,4 @@ Docs ---- -**(For information about older versions, consult the HISTORY file.)** \ No newline at end of file +**(For information about older versions, consult the HISTORY file.)** diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 35d25e64893..51c79c9634c 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1002,6 +1002,15 @@ test_k_code(PyObject *self) return Py_None; } +static PyObject * +getargs_c(PyObject *self, PyObject *args) +{ + char c; + if (!PyArg_ParseTuple(args, "c", &c)) + return NULL; + return PyBytes_FromStringAndSize(&c, 1); +} + static PyObject * getargs_s(PyObject *self, PyObject *args) { @@ -2289,6 +2298,7 @@ static PyMethodDef TestMethods[] = { (PyCFunction)test_long_long_and_overflow, METH_NOARGS}, {"test_L_code", (PyCFunction)test_L_code, METH_NOARGS}, #endif + {"getargs_c", getargs_c, METH_VARARGS}, {"getargs_s", getargs_s, METH_VARARGS}, {"getargs_s_star", getargs_s_star, METH_VARARGS}, {"getargs_s_hash", getargs_s_hash, METH_VARARGS}, diff --git a/Python/getargs.c b/Python/getargs.c index 4b57153b888..c3da368604a 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -828,6 +828,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, char *p = va_arg(*p_va, char *); if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) *p = PyBytes_AS_STRING(arg)[0]; + else if (PyByteArray_Check(arg) && PyByteArray_Size(arg) == 1) + *p = PyByteArray_AS_STRING(arg)[0]; else return converterr("a byte string of length 1", arg, msgbuf, bufsize); break;