Commit ad7d8d10 authored by Guido van Rossum's avatar Guido van Rossum

Rough and dirty job -- allow concatenation of bytes and arbitrary

buffer-supporting objects (Unicode always excluded), and also of
str and bytes.
(For some reason u"" + b"" doesn't fail, I'll investigate later.)
parent dc0b1a10
...@@ -34,6 +34,7 @@ PyAPI_DATA(PyTypeObject) PyBytes_Type; ...@@ -34,6 +34,7 @@ PyAPI_DATA(PyTypeObject) PyBytes_Type;
/* Direct API functions */ /* Direct API functions */
PyAPI_FUNC(PyObject *) PyBytes_FromObject(PyObject *); PyAPI_FUNC(PyObject *) PyBytes_FromObject(PyObject *);
PyAPI_FUNC(PyObject *) PyBytes_Concat(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyBytes_FromStringAndSize(const char *, Py_ssize_t); PyAPI_FUNC(PyObject *) PyBytes_FromStringAndSize(const char *, Py_ssize_t);
PyAPI_FUNC(Py_ssize_t) PyBytes_Size(PyObject *); PyAPI_FUNC(Py_ssize_t) PyBytes_Size(PyObject *);
PyAPI_FUNC(char *) PyBytes_AsString(PyObject *); PyAPI_FUNC(char *) PyBytes_AsString(PyObject *);
......
...@@ -225,7 +225,7 @@ class BytesTest(unittest.TestCase): ...@@ -225,7 +225,7 @@ class BytesTest(unittest.TestCase):
# Skip step 0 (invalid) # Skip step 0 (invalid)
for step in indices[1:]: for step in indices[1:]:
self.assertEqual(b[start:stop:step], bytes(L[start:stop:step])) self.assertEqual(b[start:stop:step], bytes(L[start:stop:step]))
def test_regexps(self): def test_regexps(self):
def by(s): def by(s):
return bytes(map(ord, s)) return bytes(map(ord, s))
...@@ -298,7 +298,7 @@ class BytesTest(unittest.TestCase): ...@@ -298,7 +298,7 @@ class BytesTest(unittest.TestCase):
b[3:5] = [3, 4, 5, 6] b[3:5] = [3, 4, 5, 6]
self.assertEqual(b, bytes(range(10))) self.assertEqual(b, bytes(range(10)))
b[3:0] = [42, 42, 42] b[3:0] = [42, 42, 42]
self.assertEqual(b, bytes([0, 1, 2, 42, 42, 42, 3, 4, 5, 6, 7, 8, 9])) self.assertEqual(b, bytes([0, 1, 2, 42, 42, 42, 3, 4, 5, 6, 7, 8, 9]))
...@@ -317,7 +317,7 @@ class BytesTest(unittest.TestCase): ...@@ -317,7 +317,7 @@ class BytesTest(unittest.TestCase):
L[start:stop:step] = data L[start:stop:step] = data
b[start:stop:step] = data b[start:stop:step] = data
self.assertEquals(b, bytes(L)) self.assertEquals(b, bytes(L))
del L[start:stop:step] del L[start:stop:step]
del b[start:stop:step] del b[start:stop:step]
self.assertEquals(b, bytes(L)) self.assertEquals(b, bytes(L))
...@@ -371,8 +371,10 @@ class BytesTest(unittest.TestCase): ...@@ -371,8 +371,10 @@ class BytesTest(unittest.TestCase):
b1 = bytes("abc") b1 = bytes("abc")
b2 = bytes("def") b2 = bytes("def")
self.assertEqual(b1 + b2, bytes("abcdef")) self.assertEqual(b1 + b2, bytes("abcdef"))
self.assertRaises(TypeError, lambda: b1 + "def") self.assertEqual(b1 + "def", bytes("abcdef"))
self.assertRaises(TypeError, lambda: "abc" + b2) self.assertEqual("def" + b1, bytes("defabc"))
self.assertRaises(TypeError, lambda: b1 + u"def")
##self.assertRaises(TypeError, lambda: u"abc" + b2) # XXX FIXME
def test_repeat(self): def test_repeat(self):
b = bytes("abc") b = bytes("abc")
...@@ -393,6 +395,14 @@ class BytesTest(unittest.TestCase): ...@@ -393,6 +395,14 @@ class BytesTest(unittest.TestCase):
self.assertEqual(b, bytes("abcdef")) self.assertEqual(b, bytes("abcdef"))
self.assertEqual(b, b1) self.assertEqual(b, b1)
self.failUnless(b is b1) self.failUnless(b is b1)
b += "xyz"
self.assertEqual(b, b"abcdefxyz")
try:
b += u""
except TypeError:
pass
else:
self.fail("bytes += unicode didn't raise TypeError")
def test_irepeat(self): def test_irepeat(self):
b = bytes("abc") b = bytes("abc")
...@@ -490,7 +500,7 @@ class BytesTest(unittest.TestCase): ...@@ -490,7 +500,7 @@ class BytesTest(unittest.TestCase):
a.extend(a) a.extend(a)
self.assertEqual(a, orig + orig) self.assertEqual(a, orig + orig)
self.assertEqual(a[5:], orig) self.assertEqual(a[5:], orig)
def test_remove(self): def test_remove(self):
b = b'hello' b = b'hello'
b.remove(ord('l')) b.remove(ord('l'))
...@@ -643,14 +653,36 @@ class BytesTest(unittest.TestCase): ...@@ -643,14 +653,36 @@ class BytesTest(unittest.TestCase):
q = pm.loads(ps) q = pm.loads(ps)
self.assertEqual(b, q) self.assertEqual(b, q)
def test_strip(self):
b = b'mississippi'
self.assertEqual(b.strip(b'i'), b'mississipp')
self.assertEqual(b.strip(b'm'), b'ississippi')
self.assertEqual(b.strip(b'pi'), b'mississ')
self.assertEqual(b.strip(b'im'), b'ssissipp')
self.assertEqual(b.strip(b'pim'), b'ssiss')
def test_lstrip(self):
b = b'mississippi'
self.assertEqual(b.lstrip(b'i'), b'mississippi')
self.assertEqual(b.lstrip(b'm'), b'ississippi')
self.assertEqual(b.lstrip(b'pi'), b'mississippi')
self.assertEqual(b.lstrip(b'im'), b'ssissippi')
self.assertEqual(b.lstrip(b'pim'), b'ssissippi')
def test_rstrip(self):
b = b'mississippi'
self.assertEqual(b.rstrip(b'i'), b'mississipp')
self.assertEqual(b.rstrip(b'm'), b'mississippi')
self.assertEqual(b.rstrip(b'pi'), b'mississ')
self.assertEqual(b.rstrip(b'im'), b'mississipp')
self.assertEqual(b.rstrip(b'pim'), b'mississ')
# Optimizations: # Optimizations:
# __iter__? (optimization) # __iter__? (optimization)
# __reversed__? (optimization) # __reversed__? (optimization)
# XXX Some string methods? (Those that don't use character properties) # XXX More string methods? (Those that don't use character properties)
# lstrip, rstrip, strip?? (currently un-pepped)
# join
# There are tests in string_tests.py that are more # There are tests in string_tests.py that are more
# comprehensive for things like split, partition, etc. # comprehensive for things like split, partition, etc.
# Unfortunately they are all bundled with tests that # Unfortunately they are all bundled with tests that
...@@ -675,7 +707,7 @@ class BytesAsStringTest(test.string_tests.BaseTest): ...@@ -675,7 +707,7 @@ class BytesAsStringTest(test.string_tests.BaseTest):
getattr(bytes, methodname), getattr(bytes, methodname),
object, object,
*args *args
) )
# Currently the bytes containment testing uses a single integer # Currently the bytes containment testing uses a single integer
# value. This may not be the final design, but until then the # value. This may not be the final design, but until then the
......
This diff is collapsed.
...@@ -1347,7 +1347,7 @@ merge_class_dict(PyObject* dict, PyObject* aclass) ...@@ -1347,7 +1347,7 @@ merge_class_dict(PyObject* dict, PyObject* aclass)
/* Helper for PyObject_Dir without arguments: returns the local scope. */ /* Helper for PyObject_Dir without arguments: returns the local scope. */
static PyObject * static PyObject *
_dir_locals() _dir_locals(void)
{ {
PyObject *names; PyObject *names;
PyObject *locals = PyEval_GetLocals(); PyObject *locals = PyEval_GetLocals();
...@@ -1892,4 +1892,3 @@ _PyTrash_destroy_chain(void) ...@@ -1892,4 +1892,3 @@ _PyTrash_destroy_chain(void)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
...@@ -948,6 +948,8 @@ string_concat(register PyStringObject *a, register PyObject *bb) ...@@ -948,6 +948,8 @@ string_concat(register PyStringObject *a, register PyObject *bb)
if (PyUnicode_Check(bb)) if (PyUnicode_Check(bb))
return PyUnicode_Concat((PyObject *)a, bb); return PyUnicode_Concat((PyObject *)a, bb);
#endif #endif
if (PyBytes_Check(bb))
return PyBytes_Concat((PyObject *)a, bb);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"cannot concatenate 'str' and '%.200s' objects", "cannot concatenate 'str' and '%.200s' objects",
bb->ob_type->tp_name); bb->ob_type->tp_name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment