Index: Objects/abstract.c =================================================================== --- Objects/abstract.c (revision 41831) +++ Objects/abstract.c (working copy) @@ -1144,6 +1144,15 @@ if (m && m->sq_concat) return m->sq_concat(s, o); + /* Instances of classes defining an __add__() method only + have an nb_add slot (SF patch #1390657), so we fall back to + the latter if both arguments appear to be sequences. */ + if (PySequence_Check(s) && PySequence_Check(o)) { + PyObject *result = binary_op1(s, o, NB_SLOT(nb_add)); + if (result != Py_NotImplemented) + return result; + Py_DECREF(result); + } return type_error("object can't be concatenated"); } @@ -1159,6 +1168,20 @@ if (m && m->sq_repeat) return m->sq_repeat(o, count); + /* Instances of classes defining a __mul__() method only + have an nb_multiply slot (SF patch #1390657), so we fall back to + the latter if o appear to be a sequence. */ + if (PySequence_Check(o)) { + PyObject *n, *result; + n = PyInt_FromLong(count); + if (n == NULL) + return NULL; + result = binary_op1(o, n, NB_SLOT(nb_multiply)); + Py_DECREF(n); + if (result != Py_NotImplemented) + return result; + Py_DECREF(result); + } return type_error("object can't be repeated"); } @@ -1176,6 +1199,13 @@ if (m && m->sq_concat) return m->sq_concat(s, o); + if (PySequence_Check(s) && PySequence_Check(o)) { + PyObject *result = binary_iop1(s, o, NB_SLOT(nb_inplace_add), + NB_SLOT(nb_add)); + if (result != Py_NotImplemented) + return result; + Py_DECREF(result); + } return type_error("object can't be concatenated"); } @@ -1193,6 +1223,18 @@ if (m && m->sq_repeat) return m->sq_repeat(o, count); + if (PySequence_Check(o)) { + PyObject *n, *result; + n = PyInt_FromLong(count); + if (n == NULL) + return NULL; + result = binary_iop1(o, n, NB_SLOT(nb_inplace_multiply), + NB_SLOT(nb_multiply)); + Py_DECREF(n); + if (result != Py_NotImplemented) + return result; + Py_DECREF(result); + } return type_error("object can't be repeated"); } Index: Lib/test/test_operator.py =================================================================== --- Lib/test/test_operator.py (revision 41831) +++ Lib/test/test_operator.py (working copy) @@ -3,7 +3,35 @@ from test import test_support +class Seq1: + def __init__(self, lst): + self.lst = lst + def __len__(self): + return len(self.lst) + def __getitem__(self, i): + return self.lst[i] + def __add__(self, other): + return self.lst + other.lst + def __mul__(self, other): + return self.lst * other + def __rmul__(self, other): + return other * self.lst +class Seq2(object): + def __init__(self, lst): + self.lst = lst + def __len__(self): + return len(self.lst) + def __getitem__(self, i): + return self.lst[i] + def __add__(self, other): + return self.lst + other.lst + def __mul__(self, other): + return self.lst * other + def __rmul__(self, other): + return other * self.lst + + class OperatorTestCase(unittest.TestCase): def test_lt(self): self.failUnlessRaises(TypeError, operator.lt) @@ -92,6 +120,9 @@ self.failUnlessRaises(TypeError, operator.concat, None, None) self.failUnless(operator.concat('py', 'thon') == 'python') self.failUnless(operator.concat([1, 2], [3, 4]) == [1, 2, 3, 4]) + self.failUnless(operator.concat(Seq1([5, 6]), Seq1([7])) == [5, 6, 7]) + self.failUnless(operator.concat(Seq2([5, 6]), Seq2([7])) == [5, 6, 7]) + self.failUnlessRaises(TypeError, operator.concat, 13, 29) def test_countOf(self): self.failUnlessRaises(TypeError, operator.countOf) @@ -246,6 +277,15 @@ self.failUnless(operator.repeat(a, 2) == a+a) self.failUnless(operator.repeat(a, 1) == a) self.failUnless(operator.repeat(a, 0) == '') + a = Seq1([4, 5, 6]) + self.failUnless(operator.repeat(a, 2) == [4, 5, 6, 4, 5, 6]) + self.failUnless(operator.repeat(a, 1) == [4, 5, 6]) + self.failUnless(operator.repeat(a, 0) == []) + a = Seq2([4, 5, 6]) + self.failUnless(operator.repeat(a, 2) == [4, 5, 6, 4, 5, 6]) + self.failUnless(operator.repeat(a, 1) == [4, 5, 6]) + self.failUnless(operator.repeat(a, 0) == []) + self.failUnlessRaises(TypeError, operator.repeat, 6, 7) def test_rshift(self): self.failUnlessRaises(TypeError, operator.rshift)