bpo-31271: Fix an assertion failure in io.TextIOWrapper.write. (#3201)

diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index ab0cbe1..ba95c14 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -3225,6 +3225,14 @@
         t = self.TextIOWrapper(self.StringIO('a'))
         self.assertRaises(TypeError, t.read)
 
+    def test_illegal_encoder(self):
+        # Issue 31271: Calling write() while the return value of encoder's
+        # encode() is invalid shouldn't cause an assertion failure.
+        rot13 = codecs.lookup("rot13")
+        with support.swap_attr(rot13, '_is_text_encoding', True):
+            t = io.TextIOWrapper(io.BytesIO(b'foo'), encoding="rot13")
+        self.assertRaises(TypeError, t.write, 'bar')
+
     def test_illegal_decoder(self):
         # Issue #17106
         # Bypass the early encoding check added in issue 20404
diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-08-25-20-43-22.bpo-31271.YMduKF.rst b/Misc/NEWS.d/next/Core and Builtins/2017-08-25-20-43-22.bpo-31271.YMduKF.rst
new file mode 100644
index 0000000..7bb7880
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2017-08-25-20-43-22.bpo-31271.YMduKF.rst
@@ -0,0 +1,2 @@
+Fix an assertion failure in the write() method of `io.TextIOWrapper`, when
+the encoder doesn't return a bytes object. Patch by Oren Milman.
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 5103ae6..402f743 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -1387,6 +1387,13 @@
     Py_DECREF(text);
     if (b == NULL)
         return NULL;
+    if (!PyBytes_Check(b)) {
+        PyErr_Format(PyExc_TypeError,
+                     "encoder should return a bytes object, not '%.200s'",
+                     Py_TYPE(b)->tp_name);
+        Py_DECREF(b);
+        return NULL;
+    }
 
     if (self->pending_bytes == NULL) {
         self->pending_bytes = PyList_New(0);