give the C implementation of TextIOWrapper the errors property #6217
diff --git a/Doc/library/io.rst b/Doc/library/io.rst
index d8a498b..26285b4 100644
--- a/Doc/library/io.rst
+++ b/Doc/library/io.rst
@@ -600,6 +600,10 @@
       The name of the encoding used to decode the stream's bytes into
       strings, and to encode strings into bytes.
 
+   .. attribute:: errors
+
+      The error setting of the decoder or encoder.
+
    .. attribute:: newlines
 
       A string, a tuple of strings, or ``None``, indicating the newlines
@@ -665,13 +669,9 @@
    If *line_buffering* is ``True``, :meth:`flush` is implied when a call to
    write contains a newline character.
 
-   :class:`TextIOWrapper` provides these data attributes in addition to those of
+   :class:`TextIOWrapper` provides one attribute in addition to those of
    :class:`TextIOBase` and its parents:
 
-   .. attribute:: errors
-
-      The encoding and decoding error setting.
-
    .. attribute:: line_buffering
 
       Whether line buffering is enabled.
diff --git a/Lib/_pyio.py b/Lib/_pyio.py
index c1cdf43..bbf65bc 100644
--- a/Lib/_pyio.py
+++ b/Lib/_pyio.py
@@ -1286,6 +1286,13 @@
         """
         return None
 
+    @property
+    def errors(self):
+        """Error setting of the decoder or encoder.
+
+        Subclasses should override."""
+        return None
+
 io.TextIOBase.register(TextIOBase)
 
 
@@ -1933,6 +1940,10 @@
         return object.__repr__(self)
 
     @property
+    def errors(self):
+        return None
+
+    @property
     def encoding(self):
         return None
 
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 1337b7c..4405d99 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -2024,6 +2024,12 @@
             with self.open(filename, 'rb') as f:
                 self.assertEquals(f.read(), 'bbbzzz'.encode(charset))
 
+    def test_errors_property(self):
+        with self.open(support.TESTFN, "w") as f:
+            self.assertEqual(f.errors, "strict")
+        with self.open(support.TESTFN, "w", errors="replace") as f:
+            self.assertEqual(f.errors, "replace")
+
 
 class CTextIOWrapperTest(TextIOWrapperTest):
 
diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py
index d94d9dd..0d044e9 100644
--- a/Lib/test/test_memoryio.py
+++ b/Lib/test/test_memoryio.py
@@ -459,9 +459,9 @@
 
         # These are just dummy values but we nevertheless check them for fear
         # of unexpected breakage.
-        self.assertTrue(memio.encoding is None)
-        self.assertEqual(memio.errors, "strict")
-        self.assertEqual(memio.line_buffering, False)
+        self.assertIsNone(memio.encoding)
+        self.assertIsNone(memio.errors)
+        self.assertFalse(memio.line_buffering)
 
     def test_newline_none(self):
         # newline=None
diff --git a/Misc/NEWS b/Misc/NEWS
index 2c37a80..dd544dd 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -21,6 +21,10 @@
 Library
 -------
 
+- Issue #6217: The C implementation of io.TextIOWrapper didn't include the
+  errors property.  Additionally, the errors and encoding properties of StringIO
+  are always None now.
+
 - Issue #6137: The pickle module now translates module names when loading
   or dumping pickles with a 2.x-compatible protocol, in order to make data
   sharing and migration easier. This behaviour can be disabled using the
diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c
index 136f41d..a0d8a51 100644
--- a/Modules/_io/stringio.c
+++ b/Modules/_io/stringio.c
@@ -661,22 +661,6 @@
 }
 
 static PyObject *
-stringio_encoding(StringIOObject *self, void *context)
-{
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    Py_RETURN_NONE;
-}
-
-static PyObject *
-stringio_errors(StringIOObject *self, void *context)
-{
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    return PyUnicode_FromString("strict");
-}
-
-static PyObject *
 stringio_line_buffering(StringIOObject *self, void *context)
 {
     CHECK_INITIALIZED(self);
@@ -720,8 +704,6 @@
         will be found.
     */
     {"buffer",         (getter)stringio_buffer,         NULL, NULL},
-    {"encoding",       (getter)stringio_encoding,       NULL, NULL},
-    {"errors",         (getter)stringio_errors,         NULL, NULL},
     {"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
     {NULL}
 };
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index c8d2833..3ec8be6 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -104,6 +104,18 @@
     Py_RETURN_NONE;
 }
 
+PyDoc_STRVAR(TextIOBase_errors_doc,
+    "The error setting of the decoder or encoder.\n"
+    "\n"
+    "Subclasses should override.\n"
+    );
+
+static PyObject *
+TextIOBase_errors_get(PyObject *self, void *context)
+{
+    Py_RETURN_NONE;
+}
+
 
 static PyMethodDef TextIOBase_methods[] = {
     {"detach", (PyCFunction)TextIOBase_detach, METH_NOARGS, TextIOBase_detach_doc},
@@ -116,6 +128,7 @@
 static PyGetSetDef TextIOBase_getset[] = {
     {"encoding", (getter)TextIOBase_encoding_get, NULL, TextIOBase_encoding_doc},
     {"newlines", (getter)TextIOBase_newlines_get, NULL, TextIOBase_newlines_doc},
+    {"errors", (getter)TextIOBase_errors_get, NULL, TextIOBase_errors_doc},
     {NULL}
 };
 
@@ -2462,6 +2475,13 @@
 }
 
 static PyObject *
+TextIOWrapper_errors_get(PyTextIOWrapperObject *self, void *context)
+{
+    CHECK_INITIALIZED(self);
+    return PyUnicode_FromString(PyBytes_AS_STRING(self->errors));
+}
+
+static PyObject *
 TextIOWrapper_chunk_size_get(PyTextIOWrapperObject *self, void *context)
 {
     CHECK_INITIALIZED(self);
@@ -2519,6 +2539,7 @@
 /*    {"mode", (getter)TextIOWrapper_mode_get, NULL, NULL},
 */
     {"newlines", (getter)TextIOWrapper_newlines_get, NULL, NULL},
+    {"errors", (getter)TextIOWrapper_errors_get, NULL, NULL},
     {"_CHUNK_SIZE", (getter)TextIOWrapper_chunk_size_get,
                     (setter)TextIOWrapper_chunk_size_set, NULL},
     {NULL}