Index: Objects/unicodeobject.c =================================================================== --- Objects/unicodeobject.c (revision 58102) +++ Objects/unicodeobject.c (working copy) @@ -5412,14 +5412,16 @@ item = PySequence_Fast_GET_ITEM(fseq, i); /* Convert item to Unicode. */ - if (! PyUnicode_Check(item) && ! PyString_Check(item)) { - PyErr_Format(PyExc_TypeError, - "sequence item %zd: expected string or Unicode," - " %.80s found", - i, Py_Type(item)->tp_name); - goto onError; + if (!PyString_Check(item) && !PyUnicode_Check(item)) + { + PyObject* sval; + sval = PyObject_Unicode(item); + item = PyUnicode_FromObject(sval); + Py_DECREF(sval); } - item = PyUnicode_FromObject(item); + else + item = PyUnicode_FromObject(item); + if (item == NULL) goto onError; /* We own a reference to item from here on. */ Index: Doc/library/stdtypes.rst =================================================================== --- Doc/library/stdtypes.rst (revision 58102) +++ Doc/library/stdtypes.rst (working copy) @@ -786,8 +786,10 @@ .. method:: str.join(seq) - Return a string which is the concatenation of the strings in the sequence *seq*. - The separator between elements is the string providing this method. + Return a string which is the concatenation of the values in the sequence *seq*. + Non-string values in *seq* will be converted to a string using their respective + implementation of :meth:`__str__`. The separator between elements is the string + providing this method. .. method:: str.ljust(width[, fillchar]) Index: Lib/test/test_descr.py =================================================================== --- Lib/test/test_descr.py (revision 58102) +++ Lib/test/test_descr.py (working copy) @@ -3238,10 +3238,6 @@ except ValueError: pass else: raise TestFailed("''.split('') doesn't raise ValueError") - try: ''.join([0]) - except TypeError: pass - else: raise TestFailed("''.join([0]) doesn't raise TypeError") - try: ''.rindex('5') except ValueError: pass else: raise TestFailed("''.rindex('5') doesn't raise ValueError") Index: Lib/test/test_unicode.py =================================================================== --- Lib/test/test_unicode.py (revision 58102) +++ Lib/test/test_unicode.py (working copy) @@ -178,6 +178,10 @@ def test_join(self): string_tests.MixinStrUnicodeUserStringTest.test_join(self) + class MyWrapper: + def __init__(self, sval): self.sval = sval + def __str__(self): return self.sval + # mixed arguments self.checkequalnofix('a b c d', ' ', 'join', ['a', 'b', 'c', 'd']) self.checkequalnofix('abcd', '', 'join', ('a', 'b', 'c', 'd')) @@ -186,6 +190,7 @@ self.checkequalnofix('a b c d', ' ', 'join', ['a', 'b', 'c', 'd']) self.checkequalnofix('abcd', '', 'join', ('a', 'b', 'c', 'd')) self.checkequalnofix('w x y z', ' ', 'join', string_tests.Sequence('wxyz')) + self.checkequalnofix('1 2 foo you', ' ', 'join', [1, 2, MyWrapper('foo'), 'you']) def test_replace(self): string_tests.CommonTest.test_replace(self) Index: Lib/test/string_tests.py =================================================================== --- Lib/test/string_tests.py (revision 58102) +++ Lib/test/string_tests.py (working copy) @@ -13,6 +13,7 @@ class BadSeq1(Sequence): def __init__(self): self.seq = [7, 'hello', 123] + def __str__(self): return '{0} {1} {2}'.format(*self.seq) class BadSeq2(Sequence): def __init__(self): self.seq = ['a', 'b', 'c'] @@ -987,19 +988,19 @@ self.checkequal('abc', 'a', 'join', ('abc',)) self.checkequal('z', 'a', 'join', UserList(['z'])) self.checkequal('a.b.c', '.', 'join', ['a', 'b', 'c']) - self.checkraises(TypeError, '.', 'join', ['a', 'b', 3]) + self.checkequal('a.b.3', '.', 'join', ['a', 'b', 3]) for i in [5, 25, 125]: self.checkequal(((('a' * i) + '-') * i)[:-1], '-', 'join', ['a' * i] * i) self.checkequal(((('a' * i) + '-') * i)[:-1], '-', 'join', ('a' * i,) * i) - self.checkraises(TypeError, ' ', 'join', BadSeq1()) + self.checkequal(str(BadSeq1()), ' ', 'join', BadSeq1()) self.checkequal('a b c', ' ', 'join', BadSeq2()) self.checkraises(TypeError, ' ', 'join') self.checkraises(TypeError, ' ', 'join', 7) - self.checkraises(TypeError, ' ', 'join', Sequence([7, 'hello', 123])) + self.checkequal(str(BadSeq1()), ' ', 'join', BadSeq1()) try: def f(): yield 4 + ""