[Python-checkins] cpython: Issue #20175: Converted the _io module to Argument Clinic.

serhiy.storchaka python-checkins at python.org
Thu Apr 16 10:26:39 CEST 2015


https://hg.python.org/cpython/rev/49007ed1a1a5
changeset:   95686:49007ed1a1a5
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Thu Apr 16 11:19:43 2015 +0300
summary:
  Issue #20175: Converted the _io module to Argument Clinic.

files:
  Lib/test/test_fileio.py  |    16 +-
  Lib/test/test_io.py      |    13 +-
  Modules/_io/_iomodule.c  |   278 +-
  Modules/_io/bufferedio.c |   997 ++++---
  Modules/_io/bytesio.c    |   429 ++-
  Modules/_io/_iomodule.c  |   745 +-----
  Modules/_io/bufferedio.c |  3032 +++---------------------
  Modules/_io/bytesio.c    |  1284 ++--------
  Modules/_io/fileio.c     |  1448 ++---------
  Modules/_io/iobase.c     |  1102 +-------
  Modules/_io/stringio.c   |  1210 +--------
  Modules/_io/textio.c     |  3113 +++----------------------
  Modules/_io/fileio.c     |   359 +-
  Modules/_io/iobase.c     |   248 +-
  Modules/_io/stringio.c   |   267 +-
  Modules/_io/textio.c     |   472 ++-
  16 files changed, 3636 insertions(+), 11377 deletions(-)


diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -190,9 +190,9 @@
         self.assertTrue(f.closed)
 
     def testMethods(self):
-        methods = ['fileno', 'isatty', 'read',
-                   'tell', 'truncate', 'seekable',
-                   'readable', 'writable']
+        methods = ['fileno', 'isatty', 'seekable', 'readable', 'writable',
+                   'read', 'readall', 'readline', 'readlines',
+                   'tell', 'truncate', 'flush']
 
         self.f.close()
         self.assertTrue(self.f.closed)
@@ -201,9 +201,15 @@
             method = getattr(self.f, methodname)
             # should raise on closed file
             self.assertRaises(ValueError, method)
-        self.assertRaises(ValueError, self.f.readinto, bytearray())
-        self.assertRaises(ValueError, self.f.seek, 0, os.SEEK_CUR)
+
+        self.assertRaises(TypeError, self.f.readinto)
+        self.assertRaises(ValueError, self.f.readinto, bytearray(1))
+        self.assertRaises(TypeError, self.f.seek)
+        self.assertRaises(ValueError, self.f.seek, 0)
+        self.assertRaises(TypeError, self.f.write)
         self.assertRaises(ValueError, self.f.write, b'')
+        self.assertRaises(TypeError, self.f.writelines)
+        self.assertRaises(ValueError, self.f.writelines, b'')
 
     def testOpendir(self):
         # Issue 3703: opening a directory should fill the errno
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -2163,6 +2163,17 @@
         self.assertRaises(TypeError, t.__init__, b, newline=42)
         self.assertRaises(ValueError, t.__init__, b, newline='xyzzy')
 
+    def test_uninitialized(self):
+        t = self.TextIOWrapper.__new__(self.TextIOWrapper)
+        del t
+        t = self.TextIOWrapper.__new__(self.TextIOWrapper)
+        self.assertRaises(Exception, repr, t)
+        self.assertRaisesRegex((ValueError, AttributeError),
+                               'uninitialized|has no attribute',
+                               t.read, 0)
+        t.__init__(self.MockRawIO())
+        self.assertEqual(t.read(0), '')
+
     def test_non_text_encoding_codecs_are_rejected(self):
         # Ensure the constructor complains if passed a codec that isn't
         # marked as a text encoding
@@ -3024,8 +3035,6 @@
         r = self.BytesIO(b"\xc3\xa9\n\n")
         b = self.BufferedReader(r, 1000)
         t = self.TextIOWrapper(b)
-        self.assertRaises(TypeError, t.__init__, b, newline=42)
-        self.assertRaises(ValueError, t.read)
         self.assertRaises(ValueError, t.__init__, b, newline='xyzzy')
         self.assertRaises(ValueError, t.read)
 
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -93,140 +93,145 @@
 /*
  * The main open() function
  */
-PyDoc_STRVAR(open_doc,
-"open(file, mode='r', buffering=-1, encoding=None,\n"
-"     errors=None, newline=None, closefd=True, opener=None) -> file object\n"
-"\n"
-"Open file and return a stream.  Raise IOError upon failure.\n"
-"\n"
-"file is either a text or byte string giving the name (and the path\n"
-"if the file isn't in the current working directory) of the file to\n"
-"be opened or an integer file descriptor of the file to be\n"
-"wrapped. (If a file descriptor is given, it is closed when the\n"
-"returned I/O object is closed, unless closefd is set to False.)\n"
-"\n"
-"mode is an optional string that specifies the mode in which the file\n"
-"is opened. It defaults to 'r' which means open for reading in text\n"
-"mode.  Other common values are 'w' for writing (truncating the file if\n"
-"it already exists), 'x' for creating and writing to a new file, and\n"
-"'a' for appending (which on some Unix systems, means that all writes\n"
-"append to the end of the file regardless of the current seek position).\n"
-"In text mode, if encoding is not specified the encoding used is platform\n"
-"dependent: locale.getpreferredencoding(False) is called to get the\n"
-"current locale encoding. (For reading and writing raw bytes use binary\n"
-"mode and leave encoding unspecified.) The available modes are:\n"
-"\n"
-"========= ===============================================================\n"
-"Character Meaning\n"
-"--------- ---------------------------------------------------------------\n"
-"'r'       open for reading (default)\n"
-"'w'       open for writing, truncating the file first\n"
-"'x'       create a new file and open it for writing\n"
-"'a'       open for writing, appending to the end of the file if it exists\n"
-"'b'       binary mode\n"
-"'t'       text mode (default)\n"
-"'+'       open a disk file for updating (reading and writing)\n"
-"'U'       universal newline mode (deprecated)\n"
-"========= ===============================================================\n"
-"\n"
-"The default mode is 'rt' (open for reading text). For binary random\n"
-"access, the mode 'w+b' opens and truncates the file to 0 bytes, while\n"
-"'r+b' opens the file without truncation. The 'x' mode implies 'w' and\n"
-"raises an `FileExistsError` if the file already exists.\n"
-"\n"
-"Python distinguishes between files opened in binary and text modes,\n"
-"even when the underlying operating system doesn't. Files opened in\n"
-"binary mode (appending 'b' to the mode argument) return contents as\n"
-"bytes objects without any decoding. In text mode (the default, or when\n"
-"'t' is appended to the mode argument), the contents of the file are\n"
-"returned as strings, the bytes having been first decoded using a\n"
-"platform-dependent encoding or using the specified encoding if given.\n"
-"\n"
-"'U' mode is deprecated and will raise an exception in future versions\n"
-"of Python.  It has no effect in Python 3.  Use newline to control\n"
-"universal newlines mode.\n"
-"\n"
-"buffering is an optional integer used to set the buffering policy.\n"
-"Pass 0 to switch buffering off (only allowed in binary mode), 1 to select\n"
-"line buffering (only usable in text mode), and an integer > 1 to indicate\n"
-"the size of a fixed-size chunk buffer.  When no buffering argument is\n"
-"given, the default buffering policy works as follows:\n"
-"\n"
-"* Binary files are buffered in fixed-size chunks; the size of the buffer\n"
-"  is chosen using a heuristic trying to determine the underlying device's\n"
-"  \"block size\" and falling back on `io.DEFAULT_BUFFER_SIZE`.\n"
-"  On many systems, the buffer will typically be 4096 or 8192 bytes long.\n"
-"\n"
-"* \"Interactive\" text files (files for which isatty() returns True)\n"
-"  use line buffering.  Other text files use the policy described above\n"
-"  for binary files.\n"
-"\n"
-"encoding is the name of the encoding used to decode or encode the\n"
-"file. This should only be used in text mode. The default encoding is\n"
-"platform dependent, but any encoding supported by Python can be\n"
-"passed.  See the codecs module for the list of supported encodings.\n"
-"\n"
-"errors is an optional string that specifies how encoding errors are to\n"
-"be handled---this argument should not be used in binary mode. Pass\n"
-"'strict' to raise a ValueError exception if there is an encoding error\n"
-"(the default of None has the same effect), or pass 'ignore' to ignore\n"
-"errors. (Note that ignoring encoding errors can lead to data loss.)\n"
-"See the documentation for codecs.register or run 'help(codecs.Codec)'\n"
-"for a list of the permitted encoding error strings.\n"
-"\n"
-"newline controls how universal newlines works (it only applies to text\n"
-"mode). It can be None, '', '\\n', '\\r', and '\\r\\n'.  It works as\n"
-"follows:\n"
-"\n"
-"* On input, if newline is None, universal newlines mode is\n"
-"  enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n"
-"  these are translated into '\\n' before being returned to the\n"
-"  caller. If it is '', universal newline mode is enabled, but line\n"
-"  endings are returned to the caller untranslated. If it has any of\n"
-"  the other legal values, input lines are only terminated by the given\n"
-"  string, and the line ending is returned to the caller untranslated.\n"
-"\n"
-"* On output, if newline is None, any '\\n' characters written are\n"
-"  translated to the system default line separator, os.linesep. If\n"
-"  newline is '' or '\\n', no translation takes place. If newline is any\n"
-"  of the other legal values, any '\\n' characters written are translated\n"
-"  to the given string.\n"
-"\n"
-"If closefd is False, the underlying file descriptor will be kept open\n"
-"when the file is closed. This does not work when a file name is given\n"
-"and must be True in that case.\n"
-"\n"
-"A custom opener can be used by passing a callable as *opener*. The\n"
-"underlying file descriptor for the file object is then obtained by\n"
-"calling *opener* with (*file*, *flags*). *opener* must return an open\n"
-"file descriptor (passing os.open as *opener* results in functionality\n"
-"similar to passing None).\n"
-"\n"
-"open() returns a file object whose type depends on the mode, and\n"
-"through which the standard file operations such as reading and writing\n"
-"are performed. When open() is used to open a file in a text mode ('w',\n"
-"'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open\n"
-"a file in a binary mode, the returned class varies: in read binary\n"
-"mode, it returns a BufferedReader; in write binary and append binary\n"
-"modes, it returns a BufferedWriter, and in read/write mode, it returns\n"
-"a BufferedRandom.\n"
-"\n"
-"It is also possible to use a string or bytearray as a file for both\n"
-"reading and writing. For strings StringIO can be used like a file\n"
-"opened in a text mode, and for bytes a BytesIO can be used like a file\n"
-"opened in a binary mode.\n"
-    );
+/*[clinic input]
+module _io
+
+_io.open
+    file: object
+    mode: str = "r"
+    buffering: int = -1
+    encoding: str(nullable=True) = NULL
+    errors: str(nullable=True) = NULL
+    newline: str(nullable=True) = NULL
+    closefd: int(c_default="1") = True
+    opener: object = None
+
+Open file and return a stream.  Raise IOError upon failure.
+
+file is either a text or byte string giving the name (and the path
+if the file isn't in the current working directory) of the file to
+be opened or an integer file descriptor of the file to be
+wrapped. (If a file descriptor is given, it is closed when the
+returned I/O object is closed, unless closefd is set to False.)
+
+mode is an optional string that specifies the mode in which the file
+is opened. It defaults to 'r' which means open for reading in text
+mode.  Other common values are 'w' for writing (truncating the file if
+it already exists), 'x' for creating and writing to a new file, and
+'a' for appending (which on some Unix systems, means that all writes
+append to the end of the file regardless of the current seek position).
+In text mode, if encoding is not specified the encoding used is platform
+dependent: locale.getpreferredencoding(False) is called to get the
+current locale encoding. (For reading and writing raw bytes use binary
+mode and leave encoding unspecified.) The available modes are:
+
+========= ===============================================================
+Character Meaning
+--------- ---------------------------------------------------------------
+'r'       open for reading (default)
+'w'       open for writing, truncating the file first
+'x'       create a new file and open it for writing
+'a'       open for writing, appending to the end of the file if it exists
+'b'       binary mode
+'t'       text mode (default)
+'+'       open a disk file for updating (reading and writing)
+'U'       universal newline mode (deprecated)
+========= ===============================================================
+
+The default mode is 'rt' (open for reading text). For binary random
+access, the mode 'w+b' opens and truncates the file to 0 bytes, while
+'r+b' opens the file without truncation. The 'x' mode implies 'w' and
+raises an `FileExistsError` if the file already exists.
+
+Python distinguishes between files opened in binary and text modes,
+even when the underlying operating system doesn't. Files opened in
+binary mode (appending 'b' to the mode argument) return contents as
+bytes objects without any decoding. In text mode (the default, or when
+'t' is appended to the mode argument), the contents of the file are
+returned as strings, the bytes having been first decoded using a
+platform-dependent encoding or using the specified encoding if given.
+
+'U' mode is deprecated and will raise an exception in future versions
+of Python.  It has no effect in Python 3.  Use newline to control
+universal newlines mode.
+
+buffering is an optional integer used to set the buffering policy.
+Pass 0 to switch buffering off (only allowed in binary mode), 1 to select
+line buffering (only usable in text mode), and an integer > 1 to indicate
+the size of a fixed-size chunk buffer.  When no buffering argument is
+given, the default buffering policy works as follows:
+
+* Binary files are buffered in fixed-size chunks; the size of the buffer
+  is chosen using a heuristic trying to determine the underlying device's
+  "block size" and falling back on `io.DEFAULT_BUFFER_SIZE`.
+  On many systems, the buffer will typically be 4096 or 8192 bytes long.
+
+* "Interactive" text files (files for which isatty() returns True)
+  use line buffering.  Other text files use the policy described above
+  for binary files.
+
+encoding is the name of the encoding used to decode or encode the
+file. This should only be used in text mode. The default encoding is
+platform dependent, but any encoding supported by Python can be
+passed.  See the codecs module for the list of supported encodings.
+
+errors is an optional string that specifies how encoding errors are to
+be handled---this argument should not be used in binary mode. Pass
+'strict' to raise a ValueError exception if there is an encoding error
+(the default of None has the same effect), or pass 'ignore' to ignore
+errors. (Note that ignoring encoding errors can lead to data loss.)
+See the documentation for codecs.register or run 'help(codecs.Codec)'
+for a list of the permitted encoding error strings.
+
+newline controls how universal newlines works (it only applies to text
+mode). It can be None, '', '\n', '\r', and '\r\n'.  It works as
+follows:
+
+* On input, if newline is None, universal newlines mode is
+  enabled. Lines in the input can end in '\n', '\r', or '\r\n', and
+  these are translated into '\n' before being returned to the
+  caller. If it is '', universal newline mode is enabled, but line
+  endings are returned to the caller untranslated. If it has any of
+  the other legal values, input lines are only terminated by the given
+  string, and the line ending is returned to the caller untranslated.
+
+* On output, if newline is None, any '\n' characters written are
+  translated to the system default line separator, os.linesep. If
+  newline is '' or '\n', no translation takes place. If newline is any
+  of the other legal values, any '\n' characters written are translated
+  to the given string.
+
+If closefd is False, the underlying file descriptor will be kept open
+when the file is closed. This does not work when a file name is given
+and must be True in that case.
+
+A custom opener can be used by passing a callable as *opener*. The
+underlying file descriptor for the file object is then obtained by
+calling *opener* with (*file*, *flags*). *opener* must return an open
+file descriptor (passing os.open as *opener* results in functionality
+similar to passing None).
+
+open() returns a file object whose type depends on the mode, and
+through which the standard file operations such as reading and writing
+are performed. When open() is used to open a file in a text mode ('w',
+'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open
+a file in a binary mode, the returned class varies: in read binary
+mode, it returns a BufferedReader; in write binary and append binary
+modes, it returns a BufferedWriter, and in read/write mode, it returns
+a BufferedRandom.
+
+It is also possible to use a string or bytearray as a file for both
+reading and writing. For strings StringIO can be used like a file
+opened in a text mode, and for bytes a BytesIO can be used like a file
+opened in a binary mode.
+[clinic start generated code]*/
 
 static PyObject *
-io_open(PyObject *self, PyObject *args, PyObject *kwds)
+_io_open_impl(PyModuleDef *module, PyObject *file, const char *mode,
+              int buffering, const char *encoding, const char *errors,
+              const char *newline, int closefd, PyObject *opener)
+/*[clinic end generated code: output=7615d0d746eb14d2 input=0541ce15691a82f2]*/
 {
-    char *kwlist[] = {"file", "mode", "buffering",
-                      "encoding", "errors", "newline",
-                      "closefd", "opener", NULL};
-    PyObject *file, *opener = Py_None;
-    char *mode = "r";
-    int buffering = -1, closefd = 1;
-    char *encoding = NULL, *errors = NULL, *newline = NULL;
     unsigned i;
 
     int creating = 0, reading = 0, writing = 0, appending = 0, updating = 0;
@@ -242,13 +247,6 @@
     _Py_IDENTIFIER(mode);
     _Py_IDENTIFIER(close);
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzziO:open", kwlist,
-                                     &file, &mode, &buffering,
-                                     &encoding, &errors, &newline,
-                                     &closefd, &opener)) {
-        return NULL;
-    }
-
     if (!PyUnicode_Check(file) &&
 	!PyBytes_Check(file) &&
 	!PyNumber_Check(file)) {
@@ -611,8 +609,10 @@
  * Module definition
  */
 
+#include "clinic/_iomodule.c.h"
+
 static PyMethodDef module_methods[] = {
-    {"open", (PyCFunction)io_open, METH_VARARGS|METH_KEYWORDS, open_doc},
+    _IO_OPEN_METHODDEF
     {NULL, NULL}
 };
 
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -13,6 +13,24 @@
 #include "pythread.h"
 #include "_iomodule.h"
 
+/*[clinic input]
+module _io
+class _io._BufferedIOBase "PyObject *" "&PyBufferedIOBase_Type"
+class _io._Buffered "buffered *" "&PyBufferedIOBase_Type"
+class _io.BufferedReader "buffered *" "&PyBufferedReader_Type"
+class _io.BufferedWriter "buffered *" "&PyBufferedWriter_Type"
+class _io.BufferedRWPair "rwpair *" "&PyBufferedRWPair_Type"
+class _io.BufferedRandom "buffered *" "&PyBufferedRandom_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=59460b9c5639984d]*/
+
+/*[python input]
+class io_ssize_t_converter(CConverter):
+    type = 'Py_ssize_t'
+    converter = '_PyIO_ConvertSsize_t'
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/
+
 _Py_IDENTIFIER(close);
 _Py_IDENTIFIER(_dealloc_warn);
 _Py_IDENTIFIER(flush);
@@ -48,61 +66,63 @@
     );
 
 static PyObject *
-_bufferediobase_readinto_generic(PyObject *self, PyObject *args, char readinto1)
+_bufferediobase_readinto_generic(PyObject *self, Py_buffer *buffer, char readinto1)
 {
-    Py_buffer buf;
     Py_ssize_t len;
     PyObject *data;
 
-    if (!PyArg_ParseTuple(args,
-                          readinto1 ? "w*:readinto1" : "w*:readinto",
-                          &buf)) {
-        return NULL;
-    }
-
     data = _PyObject_CallMethodId(self,
                                   readinto1 ? &PyId_read1 : &PyId_read,
-                                  "n", buf.len);
+                                  "n", buffer->len);
     if (data == NULL)
-        goto error;
+        return NULL;
 
     if (!PyBytes_Check(data)) {
         Py_DECREF(data);
         PyErr_SetString(PyExc_TypeError, "read() should return bytes");
-        goto error;
+        return NULL;
     }
 
     len = Py_SIZE(data);
-    if (len > buf.len) {
+    if (len > buffer->len) {
         PyErr_Format(PyExc_ValueError,
                      "read() returned too much data: "
                      "%zd bytes requested, %zd returned",
-                     buf.len, len);
+                     buffer->len, len);
         Py_DECREF(data);
-        goto error;
+        return NULL;
     }
-    memcpy(buf.buf, PyBytes_AS_STRING(data), len);
+    memcpy(buffer->buf, PyBytes_AS_STRING(data), len);
 
-    PyBuffer_Release(&buf);
     Py_DECREF(data);
 
     return PyLong_FromSsize_t(len);
-
-  error:
-    PyBuffer_Release(&buf);
-    return NULL;
 }
 
+/*[clinic input]
+_io._BufferedIOBase.readinto
+    buffer: Py_buffer(types={'rwbuffer'})
+    /
+[clinic start generated code]*/
+
 static PyObject *
-bufferediobase_readinto(PyObject *self, PyObject *args)
+_io__BufferedIOBase_readinto_impl(PyObject *self, Py_buffer *buffer)
+/*[clinic end generated code: output=8c8cda6684af8038 input=f8242a06c21763a0]*/
 {
-    return _bufferediobase_readinto_generic(self, args, 0);
+    return _bufferediobase_readinto_generic(self, buffer, 0);
 }
 
+/*[clinic input]
+_io._BufferedIOBase.readinto1
+    buffer: Py_buffer(types={'rwbuffer'})
+    /
+[clinic start generated code]*/
+
 static PyObject *
-bufferediobase_readinto1(PyObject *self, PyObject *args)
+_io__BufferedIOBase_readinto1_impl(PyObject *self, Py_buffer *buffer)
+/*[clinic end generated code: output=358623e4fd2b69d3 input=2003e706c730bd21]*/
 {
-    return _bufferediobase_readinto_generic(self, args, 1);
+    return _bufferediobase_readinto_generic(self, buffer, 1);
 }
 
 static PyObject *
@@ -114,14 +134,18 @@
     return NULL;
 }
 
-PyDoc_STRVAR(bufferediobase_detach_doc,
-    "Disconnect this buffer from its underlying raw stream and return it.\n"
-    "\n"
-    "After the raw stream has been detached, the buffer is in an unusable\n"
-    "state.\n");
+/*[clinic input]
+_io._BufferedIOBase.detach
+
+Disconnect this buffer from its underlying raw stream and return it.
+
+After the raw stream has been detached, the buffer is in an unusable
+state.
+[clinic start generated code]*/
 
 static PyObject *
-bufferediobase_detach(PyObject *self)
+_io__BufferedIOBase_detach_impl(PyObject *self)
+/*[clinic end generated code: output=754977c8d10ed88c input=822427fb58fe4169]*/
 {
     return bufferediobase_unsupported("detach");
 }
@@ -179,69 +203,6 @@
 }
 
 
-static PyMethodDef bufferediobase_methods[] = {
-    {"detach", (PyCFunction)bufferediobase_detach, METH_NOARGS, bufferediobase_detach_doc},
-    {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc},
-    {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc},
-    {"readinto", bufferediobase_readinto, METH_VARARGS, NULL},
-    {"readinto1", bufferediobase_readinto1, METH_VARARGS, NULL},
-    {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc},
-    {NULL, NULL}
-};
-
-PyTypeObject PyBufferedIOBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io._BufferedIOBase",      /*tp_name*/
-    0,                          /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    0,                          /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_FINALIZE,  /*tp_flags*/
-    bufferediobase_doc,         /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    bufferediobase_methods,     /* tp_methods */
-    0,                          /* tp_members */
-    0,                          /* tp_getset */
-    &PyIOBase_Type,             /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    0,                          /* tp_dictoffset */
-    0,                          /* tp_init */
-    0,                          /* tp_alloc */
-    0,                          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
-
-
 typedef struct {
     PyObject_HEAD
 
@@ -896,17 +857,20 @@
     return res;
 }
 
+/*[clinic input]
+_io._Buffered.peek
+    size: Py_ssize_t = 0
+    /
+
+[clinic start generated code]*/
+
 static PyObject *
-buffered_peek(buffered *self, PyObject *args)
+_io__Buffered_peek_impl(buffered *self, Py_ssize_t size)
+/*[clinic end generated code: output=ba7a097ca230102b input=37ffb97d06ff4adb]*/
 {
-    Py_ssize_t n = 0;
     PyObject *res = NULL;
 
     CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
-        return NULL;
-    }
-
     if (!ENTER_BUFFERED(self))
         return NULL;
 
@@ -923,16 +887,19 @@
     return res;
 }
 
+/*[clinic input]
+_io._Buffered.read
+    size as n: io_ssize_t = -1
+    /
+[clinic start generated code]*/
+
 static PyObject *
-buffered_read(buffered *self, PyObject *args)
+_io__Buffered_read_impl(buffered *self, Py_ssize_t n)
+/*[clinic end generated code: output=f41c78bb15b9bbe9 input=c0939ec7f9e9354f]*/
 {
-    Py_ssize_t n = -1;
     PyObject *res;
 
     CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) {
-        return NULL;
-    }
     if (n < -1) {
         PyErr_SetString(PyExc_ValueError,
                         "read length must be positive or -1");
@@ -961,17 +928,20 @@
     return res;
 }
 
+/*[clinic input]
+_io._Buffered.read1
+    size as n: Py_ssize_t
+    /
+[clinic start generated code]*/
+
 static PyObject *
-buffered_read1(buffered *self, PyObject *args)
+_io__Buffered_read1_impl(buffered *self, Py_ssize_t n)
+/*[clinic end generated code: output=bcc4fb4e54d103a3 input=8d2869c18b983184]*/
 {
-    Py_ssize_t n, have, r;
+    Py_ssize_t have, r;
     PyObject *res = NULL;
 
     CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "n:read1", &n)) {
-        return NULL;
-    }
-
     if (n < 0) {
         PyErr_SetString(PyExc_ValueError,
                         "read length must be positive");
@@ -1012,34 +982,27 @@
 }
 
 static PyObject *
-_buffered_readinto_generic(buffered *self, PyObject *args, char readinto1)
+_buffered_readinto_generic(buffered *self, Py_buffer *buffer, char readinto1)
 {
-    Py_buffer buf;
     Py_ssize_t n, written = 0, remaining;
     PyObject *res = NULL;
 
     CHECK_INITIALIZED(self)
 
-    if (!PyArg_ParseTuple(args,
-                          readinto1 ? "w*:readinto1" : "w*:readinto",
-                          &buf))
-        return NULL;
-
     n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
     if (n > 0) {
-        if (n >= buf.len) {
-            memcpy(buf.buf, self->buffer + self->pos, buf.len);
-            self->pos += buf.len;
-            res = PyLong_FromSsize_t(buf.len);
-            goto end_unlocked;
+        if (n >= buffer->len) {
+            memcpy(buffer->buf, self->buffer + self->pos, buffer->len);
+            self->pos += buffer->len;
+            return PyLong_FromSsize_t(buffer->len);
         }
-        memcpy(buf.buf, self->buffer + self->pos, n);
+        memcpy(buffer->buf, self->buffer + self->pos, n);
         self->pos += n;
         written = n;
     }
 
     if (!ENTER_BUFFERED(self))
-        goto end_unlocked;
+        return NULL;
 
     if (self->writable) {
         res = buffered_flush_and_rewind_unlocked(self);
@@ -1051,13 +1014,13 @@
     _bufferedreader_reset_buf(self);
     self->pos = 0;
 
-    for (remaining = buf.len - written;
+    for (remaining = buffer->len - written;
          remaining > 0;
          written += n, remaining -= n) {
         /* If remaining bytes is larger than internal buffer size, copy
          * directly into caller's buffer. */
         if (remaining > self->buffer_size) {
-            n = _bufferedreader_raw_read(self, (char *) buf.buf + written,
+            n = _bufferedreader_raw_read(self, (char *) buffer->buf + written,
                                          remaining);
         }
 
@@ -1068,7 +1031,7 @@
             if (n > 0) {
                 if (n > remaining)
                     n = remaining;
-                memcpy((char *) buf.buf + written,
+                memcpy((char *) buffer->buf + written,
                        self->buffer + self->pos, n);
                 self->pos += n;
                 continue; /* short circuit */
@@ -1097,21 +1060,33 @@
 
 end:
     LEAVE_BUFFERED(self);
-end_unlocked:
-    PyBuffer_Release(&buf);
     return res;
 }
 
+/*[clinic input]
+_io._Buffered.readinto
+    buffer: Py_buffer(types={'rwbuffer'})
+    /
+[clinic start generated code]*/
+
 static PyObject *
-buffered_readinto(buffered *self, PyObject *args)
+_io__Buffered_readinto_impl(buffered *self, Py_buffer *buffer)
+/*[clinic end generated code: output=bcb376580b1d8170 input=962b7496eac38b3a]*/
 {
-    return _buffered_readinto_generic(self, args, 0);
+    return _buffered_readinto_generic(self, buffer, 0);
 }
 
+/*[clinic input]
+_io._Buffered.readinto1
+    buffer: Py_buffer(types={'rwbuffer'})
+    /
+[clinic start generated code]*/
+
 static PyObject *
-buffered_readinto1(buffered *self, PyObject *args)
+_io__Buffered_readinto1_impl(buffered *self, Py_buffer *buffer)
+/*[clinic end generated code: output=6e5c6ac5868205d6 input=834614d93f0adeb5]*/
 {
-    return _buffered_readinto_generic(self, args, 1);
+    return _buffered_readinto_generic(self, buffer, 1);
 }
 
 
@@ -1226,15 +1201,18 @@
     return res;
 }
 
+/*[clinic input]
+_io._Buffered.readline
+    size: io_ssize_t = -1
+    /
+[clinic start generated code]*/
+
 static PyObject *
-buffered_readline(buffered *self, PyObject *args)
+_io__Buffered_readline_impl(buffered *self, Py_ssize_t size)
+/*[clinic end generated code: output=24dd2aa6e33be83c input=ff1e0df821cb4e5c]*/
 {
-    Py_ssize_t limit = -1;
-
     CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit))
-        return NULL;
-    return _buffered_readline(self, limit);
+    return _buffered_readline(self, size);
 }
 
 
@@ -1252,17 +1230,21 @@
     return PyLong_FromOff_t(pos);
 }
 
+/*[clinic input]
+_io._Buffered.seek
+    target as targetobj: object
+    whence: int = 0
+    /
+[clinic start generated code]*/
+
 static PyObject *
-buffered_seek(buffered *self, PyObject *args)
+_io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence)
+/*[clinic end generated code: output=7ae0e8dc46efdefb input=a9c4920bfcba6163]*/
 {
     Py_off_t target, n;
-    int whence = 0;
-    PyObject *targetobj, *res = NULL;
+    PyObject *res = NULL;
 
     CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "O|i:seek", &targetobj, &whence)) {
-        return NULL;
-    }
 
     /* Do some error checking instead of trusting OS 'seek()'
     ** error detection, just in case.
@@ -1344,17 +1326,19 @@
     return res;
 }
 
+/*[clinic input]
+_io._Buffered.truncate
+    pos: object = None
+    /
+[clinic start generated code]*/
+
 static PyObject *
-buffered_truncate(buffered *self, PyObject *args)
+_io__Buffered_truncate_impl(buffered *self, PyObject *pos)
+/*[clinic end generated code: output=667ca03c60c270de input=8a1be34d57cca2d3]*/
 {
-    PyObject *pos = Py_None;
     PyObject *res = NULL;
 
     CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
-        return NULL;
-    }
-
     if (!ENTER_BUFFERED(self))
         return NULL;
 
@@ -1439,29 +1423,27 @@
  * class BufferedReader
  */
 
-PyDoc_STRVAR(bufferedreader_doc,
-             "Create a new buffered reader using the given readable raw IO object.");
-
 static void _bufferedreader_reset_buf(buffered *self)
 {
     self->read_end = -1;
 }
 
+/*[clinic input]
+_io.BufferedReader.__init__
+    raw: object
+    buffer_size: Py_ssize_t(c_default="DEFAULT_BUFFER_SIZE") = DEFAULT_BUFFER_SIZE
+
+Create a new buffered reader using the given readable raw IO object.
+[clinic start generated code]*/
+
 static int
-bufferedreader_init(buffered *self, PyObject *args, PyObject *kwds)
+_io_BufferedReader___init___impl(buffered *self, PyObject *raw,
+                                 Py_ssize_t buffer_size)
+/*[clinic end generated code: output=cddcfefa0ed294c4 input=fb887e06f11b4e48]*/
 {
-    char *kwlist[] = {"raw", "buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    PyObject *raw;
-
     self->ok = 0;
     self->detached = 0;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
-                                     &raw, &buffer_size)) {
-        return -1;
-    }
-
     if (_PyIOBase_check_readable(raw, Py_True) == NULL)
         return -1;
 
@@ -1782,112 +1764,12 @@
     self->pos = 0;
     return PyBytes_FromStringAndSize(self->buffer, r);
 }
-
-static PyMethodDef bufferedreader_methods[] = {
-    /* BufferedIOMixin methods */
-    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
-    {"flush", (PyCFunction)buffered_simple_flush, METH_NOARGS},
-    {"close", (PyCFunction)buffered_close, METH_NOARGS},
-    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
-    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
-    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
-    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
-    {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
-    {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
-
-    {"read", (PyCFunction)buffered_read, METH_VARARGS},
-    {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
-    {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
-    {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS},
-    {"readinto1", (PyCFunction)buffered_readinto1, METH_VARARGS},
-    {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
-    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
-    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
-    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
-    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef bufferedreader_members[] = {
-    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
-    {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0},
-    {NULL}
-};
-
-static PyGetSetDef bufferedreader_getset[] = {
-    {"closed", (getter)buffered_closed_get, NULL, NULL},
-    {"name", (getter)buffered_name_get, NULL, NULL},
-    {"mode", (getter)buffered_mode_get, NULL, NULL},
-    {NULL}
-};
-
-
-PyTypeObject PyBufferedReader_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.BufferedReader",       /*tp_name*/
-    sizeof(buffered),           /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)buffered_dealloc,     /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    (reprfunc)buffered_repr,    /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
-    bufferedreader_doc,         /* tp_doc */
-    (traverseproc)buffered_traverse, /* tp_traverse */
-    (inquiry)buffered_clear,    /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    (iternextfunc)buffered_iternext, /* tp_iternext */
-    bufferedreader_methods,     /* tp_methods */
-    bufferedreader_members,     /* tp_members */
-    bufferedreader_getset,      /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(buffered, dict), /* tp_dictoffset */
-    (initproc)bufferedreader_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
 

 
 
 /*
  * class BufferedWriter
  */
-PyDoc_STRVAR(bufferedwriter_doc,
-    "A buffer for a writeable sequential RawIO object.\n"
-    "\n"
-    "The constructor creates a BufferedWriter for the given writeable raw\n"
-    "stream. If the buffer_size is not given, it defaults to\n"
-    "DEFAULT_BUFFER_SIZE.\n"
-    );
-
 static void
 _bufferedwriter_reset_buf(buffered *self)
 {
@@ -1895,21 +1777,26 @@
     self->write_end = -1;
 }
 
+/*[clinic input]
+_io.BufferedWriter.__init__
+    raw: object
+    buffer_size: Py_ssize_t(c_default="DEFAULT_BUFFER_SIZE") = DEFAULT_BUFFER_SIZE
+
+A buffer for a writeable sequential RawIO object.
+
+The constructor creates a BufferedWriter for the given writeable raw
+stream. If the buffer_size is not given, it defaults to
+DEFAULT_BUFFER_SIZE.
+[clinic start generated code]*/
+
 static int
-bufferedwriter_init(buffered *self, PyObject *args, PyObject *kwds)
+_io_BufferedWriter___init___impl(buffered *self, PyObject *raw,
+                                 Py_ssize_t buffer_size)
+/*[clinic end generated code: output=c8942a020c0dee64 input=914be9b95e16007b]*/
 {
-    char *kwlist[] = {"raw", "buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    PyObject *raw;
-
     self->ok = 0;
     self->detached = 0;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedWriter", kwlist,
-                                     &raw, &buffer_size)) {
-        return -1;
-    }
-
     if (_PyIOBase_check_writable(raw, Py_True) == NULL)
         return -1;
 
@@ -2030,29 +1917,28 @@
     return NULL;
 }
 
+/*[clinic input]
+_io.BufferedWriter.write
+    buffer: Py_buffer
+    /
+[clinic start generated code]*/
+
 static PyObject *
-bufferedwriter_write(buffered *self, PyObject *args)
+_io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer)
+/*[clinic end generated code: output=7f8d1365759bfc6b input=dd87dd85fc7f8850]*/
 {
     PyObject *res = NULL;
-    Py_buffer buf;
     Py_ssize_t written, avail, remaining;
     Py_off_t offset;
 
     CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
+    if (IS_CLOSED(self)) {
+        PyErr_SetString(PyExc_ValueError, "write to closed file");
         return NULL;
     }
 
-    if (IS_CLOSED(self)) {
-        PyErr_SetString(PyExc_ValueError, "write to closed file");
-        PyBuffer_Release(&buf);
+    if (!ENTER_BUFFERED(self))
         return NULL;
-    }
-
-    if (!ENTER_BUFFERED(self)) {
-        PyBuffer_Release(&buf);
-        return NULL;
-    }
 
     /* Fast path: the data to write can be fully buffered. */
     if (!VALID_READ_BUFFER(self) && !VALID_WRITE_BUFFER(self)) {
@@ -2060,15 +1946,15 @@
         self->raw_pos = 0;
     }
     avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t);
-    if (buf.len <= avail) {
-        memcpy(self->buffer + self->pos, buf.buf, buf.len);
+    if (buffer->len <= avail) {
+        memcpy(self->buffer + self->pos, buffer->buf, buffer->len);
         if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) {
             self->write_pos = self->pos;
         }
-        ADJUST_POSITION(self, self->pos + buf.len);
+        ADJUST_POSITION(self, self->pos + buffer->len);
         if (self->pos > self->write_end)
             self->write_end = self->pos;
-        written = buf.len;
+        written = buffer->len;
         goto end;
     }
 
@@ -2091,17 +1977,17 @@
         self->write_pos = 0;
         avail = Py_SAFE_DOWNCAST(self->buffer_size - self->write_end,
                                  Py_off_t, Py_ssize_t);
-        if (buf.len <= avail) {
+        if (buffer->len <= avail) {
             /* Everything can be buffered */
             PyErr_Clear();
-            memcpy(self->buffer + self->write_end, buf.buf, buf.len);
-            self->write_end += buf.len;
-            self->pos += buf.len;
-            written = buf.len;
+            memcpy(self->buffer + self->write_end, buffer->buf, buffer->len);
+            self->write_end += buffer->len;
+            self->pos += buffer->len;
+            written = buffer->len;
             goto end;
         }
         /* Buffer as much as possible. */
-        memcpy(self->buffer + self->write_end, buf.buf, avail);
+        memcpy(self->buffer + self->write_end, buffer->buf, avail);
         self->write_end += avail;
         self->pos += avail;
         /* XXX Modifying the existing exception e using the pointer w
@@ -2127,11 +2013,11 @@
     }
 
     /* Then write buf itself. At this point the buffer has been emptied. */
-    remaining = buf.len;
+    remaining = buffer->len;
     written = 0;
     while (remaining > self->buffer_size) {
         Py_ssize_t n = _bufferedwriter_raw_write(
-            self, (char *) buf.buf + written, buf.len - written);
+            self, (char *) buffer->buf + written, buffer->len - written);
         if (n == -1) {
             goto error;
         } else if (n == -2) {
@@ -2139,7 +2025,7 @@
             if (remaining > self->buffer_size) {
                 /* Can't buffer everything, still buffer as much as possible */
                 memcpy(self->buffer,
-                       (char *) buf.buf + written, self->buffer_size);
+                       (char *) buffer->buf + written, self->buffer_size);
                 self->raw_pos = 0;
                 ADJUST_POSITION(self, self->buffer_size);
                 self->write_end = self->buffer_size;
@@ -2162,7 +2048,7 @@
     if (self->readable)
         _bufferedreader_reset_buf(self);
     if (remaining > 0) {
-        memcpy(self->buffer, (char *) buf.buf + written, remaining);
+        memcpy(self->buffer, (char *) buffer->buf + written, remaining);
         written += remaining;
     }
     self->write_pos = 0;
@@ -2176,96 +2062,8 @@
 
 error:
     LEAVE_BUFFERED(self)
-    PyBuffer_Release(&buf);
     return res;
 }
-
-static PyMethodDef bufferedwriter_methods[] = {
-    /* BufferedIOMixin methods */
-    {"close", (PyCFunction)buffered_close, METH_NOARGS},
-    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
-    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
-    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
-    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
-    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
-    {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
-    {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
-
-    {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
-    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
-    {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
-    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
-    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
-    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef bufferedwriter_members[] = {
-    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
-    {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0},
-    {NULL}
-};
-
-static PyGetSetDef bufferedwriter_getset[] = {
-    {"closed", (getter)buffered_closed_get, NULL, NULL},
-    {"name", (getter)buffered_name_get, NULL, NULL},
-    {"mode", (getter)buffered_mode_get, NULL, NULL},
-    {NULL}
-};
-
-
-PyTypeObject PyBufferedWriter_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.BufferedWriter",       /*tp_name*/
-    sizeof(buffered),           /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)buffered_dealloc,     /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    (reprfunc)buffered_repr,    /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,   /*tp_flags*/
-    bufferedwriter_doc,         /* tp_doc */
-    (traverseproc)buffered_traverse, /* tp_traverse */
-    (inquiry)buffered_clear,    /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    bufferedwriter_methods,     /* tp_methods */
-    bufferedwriter_members,     /* tp_members */
-    bufferedwriter_getset,      /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(buffered, dict),   /* tp_dictoffset */
-    (initproc)bufferedwriter_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
 

 
 
@@ -2273,18 +2071,6 @@
  * BufferedRWPair
  */
 
-PyDoc_STRVAR(bufferedrwpair_doc,
-    "A buffered reader and writer object together.\n"
-    "\n"
-    "A buffered reader object and buffered writer object put together to\n"
-    "form a sequential IO object that can read and write. This is typically\n"
-    "used with a socket or two-way pipe.\n"
-    "\n"
-    "reader and writer are RawIOBase objects that are readable and\n"
-    "writeable respectively. If the buffer_size is omitted it defaults to\n"
-    "DEFAULT_BUFFER_SIZE.\n"
-    );
-
 /* XXX The usefulness of this (compared to having two separate IO objects) is
  * questionable.
  */
@@ -2297,17 +2083,29 @@
     PyObject *weakreflist;
 } rwpair;
 
+/*[clinic input]
+_io.BufferedRWPair.__init__
+    reader: object
+    writer: object
+    buffer_size: Py_ssize_t(c_default="DEFAULT_BUFFER_SIZE") = DEFAULT_BUFFER_SIZE
+    /
+
+A buffered reader and writer object together.
+
+A buffered reader object and buffered writer object put together to
+form a sequential IO object that can read and write. This is typically
+used with a socket or two-way pipe.
+
+reader and writer are RawIOBase objects that are readable and
+writeable respectively. If the buffer_size is omitted it defaults to
+DEFAULT_BUFFER_SIZE.
+[clinic start generated code]*/
+
 static int
-bufferedrwpair_init(rwpair *self, PyObject *args, PyObject *kwds)
+_io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader,
+                                 PyObject *writer, Py_ssize_t buffer_size)
+/*[clinic end generated code: output=327e73d1aee8f984 input=620d42d71f33a031]*/
 {
-    PyObject *reader, *writer;
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-
-    if (!PyArg_ParseTuple(args, "OO|n:BufferedRWPair", &reader, &writer,
-                          &buffer_size)) {
-        return -1;
-    }
-
     if (_PyIOBase_check_readable(reader, Py_True) == NULL)
         return -1;
     if (_PyIOBase_check_writable(writer, Py_True) == NULL)
@@ -2472,6 +2270,306 @@
     }
     return PyObject_GetAttr((PyObject *) self->writer, _PyIO_str_closed);
 }
+

+
+
+/*
+ * BufferedRandom
+ */
+
+/*[clinic input]
+_io.BufferedRandom.__init__
+    raw: object
+    buffer_size: Py_ssize_t(c_default="DEFAULT_BUFFER_SIZE") = DEFAULT_BUFFER_SIZE
+
+A buffered interface to random access streams.
+
+The constructor creates a reader and writer for a seekable stream,
+raw, given in the first argument. If the buffer_size is omitted it
+defaults to DEFAULT_BUFFER_SIZE.
+[clinic start generated code]*/
+
+static int
+_io_BufferedRandom___init___impl(buffered *self, PyObject *raw,
+                                 Py_ssize_t buffer_size)
+/*[clinic end generated code: output=d3d64eb0f64e64a3 input=a4e818fb86d0e50c]*/
+{
+    self->ok = 0;
+    self->detached = 0;
+
+    if (_PyIOBase_check_seekable(raw, Py_True) == NULL)
+        return -1;
+    if (_PyIOBase_check_readable(raw, Py_True) == NULL)
+        return -1;
+    if (_PyIOBase_check_writable(raw, Py_True) == NULL)
+        return -1;
+
+    Py_CLEAR(self->raw);
+    Py_INCREF(raw);
+    self->raw = raw;
+    self->buffer_size = buffer_size;
+    self->readable = 1;
+    self->writable = 1;
+
+    if (_buffered_init(self) < 0)
+        return -1;
+    _bufferedreader_reset_buf(self);
+    _bufferedwriter_reset_buf(self);
+    self->pos = 0;
+
+    self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedRandom_Type &&
+                                Py_TYPE(raw) == &PyFileIO_Type);
+
+    self->ok = 1;
+    return 0;
+}
+
+#include "clinic/bufferedio.c.h"
+
+
+static PyMethodDef bufferediobase_methods[] = {
+    _IO__BUFFEREDIOBASE_DETACH_METHODDEF
+    {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc},
+    {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc},
+    _IO__BUFFEREDIOBASE_READINTO_METHODDEF
+    _IO__BUFFEREDIOBASE_READINTO1_METHODDEF
+    {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc},
+    {NULL, NULL}
+};
+
+PyTypeObject PyBufferedIOBase_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_io._BufferedIOBase",      /*tp_name*/
+    0,                          /*tp_basicsize*/
+    0,                          /*tp_itemsize*/
+    0,                          /*tp_dealloc*/
+    0,                          /*tp_print*/
+    0,                          /*tp_getattr*/
+    0,                          /*tp_setattr*/
+    0,                          /*tp_compare */
+    0,                          /*tp_repr*/
+    0,                          /*tp_as_number*/
+    0,                          /*tp_as_sequence*/
+    0,                          /*tp_as_mapping*/
+    0,                          /*tp_hash */
+    0,                          /*tp_call*/
+    0,                          /*tp_str*/
+    0,                          /*tp_getattro*/
+    0,                          /*tp_setattro*/
+    0,                          /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+        | Py_TPFLAGS_HAVE_FINALIZE,  /*tp_flags*/
+    bufferediobase_doc,         /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    0,                          /* tp_weaklistoffset */
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    bufferediobase_methods,     /* tp_methods */
+    0,                          /* tp_members */
+    0,                          /* tp_getset */
+    &PyIOBase_Type,             /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    0,                          /* tp_dictoffset */
+    0,                          /* tp_init */
+    0,                          /* tp_alloc */
+    0,                          /* tp_new */
+    0,                          /* tp_free */
+    0,                          /* tp_is_gc */
+    0,                          /* tp_bases */
+    0,                          /* tp_mro */
+    0,                          /* tp_cache */
+    0,                          /* tp_subclasses */
+    0,                          /* tp_weaklist */
+    0,                          /* tp_del */
+    0,                          /* tp_version_tag */
+    0,                          /* tp_finalize */
+};
+
+
+static PyMethodDef bufferedreader_methods[] = {
+    /* BufferedIOMixin methods */
+    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
+    {"flush", (PyCFunction)buffered_simple_flush, METH_NOARGS},
+    {"close", (PyCFunction)buffered_close, METH_NOARGS},
+    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
+    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
+    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
+    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
+    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
+    {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
+    {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
+
+    _IO__BUFFERED_READ_METHODDEF
+    _IO__BUFFERED_PEEK_METHODDEF
+    _IO__BUFFERED_READ1_METHODDEF
+    _IO__BUFFERED_READINTO_METHODDEF
+    _IO__BUFFERED_READINTO1_METHODDEF
+    _IO__BUFFERED_READLINE_METHODDEF
+    _IO__BUFFERED_SEEK_METHODDEF
+    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
+    _IO__BUFFERED_TRUNCATE_METHODDEF
+    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
+    {NULL, NULL}
+};
+
+static PyMemberDef bufferedreader_members[] = {
+    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
+    {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0},
+    {NULL}
+};
+
+static PyGetSetDef bufferedreader_getset[] = {
+    {"closed", (getter)buffered_closed_get, NULL, NULL},
+    {"name", (getter)buffered_name_get, NULL, NULL},
+    {"mode", (getter)buffered_mode_get, NULL, NULL},
+    {NULL}
+};
+
+
+PyTypeObject PyBufferedReader_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_io.BufferedReader",       /*tp_name*/
+    sizeof(buffered),           /*tp_basicsize*/
+    0,                          /*tp_itemsize*/
+    (destructor)buffered_dealloc,     /*tp_dealloc*/
+    0,                          /*tp_print*/
+    0,                          /*tp_getattr*/
+    0,                          /*tp_setattr*/
+    0,                          /*tp_compare */
+    (reprfunc)buffered_repr,    /*tp_repr*/
+    0,                          /*tp_as_number*/
+    0,                          /*tp_as_sequence*/
+    0,                          /*tp_as_mapping*/
+    0,                          /*tp_hash */
+    0,                          /*tp_call*/
+    0,                          /*tp_str*/
+    0,                          /*tp_getattro*/
+    0,                          /*tp_setattro*/
+    0,                          /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
+    _io_BufferedReader___init____doc__, /* tp_doc */
+    (traverseproc)buffered_traverse, /* tp_traverse */
+    (inquiry)buffered_clear,    /* tp_clear */
+    0,                          /* tp_richcompare */
+    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
+    0,                          /* tp_iter */
+    (iternextfunc)buffered_iternext, /* tp_iternext */
+    bufferedreader_methods,     /* tp_methods */
+    bufferedreader_members,     /* tp_members */
+    bufferedreader_getset,      /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    offsetof(buffered, dict), /* tp_dictoffset */
+    _io_BufferedReader___init__, /* tp_init */
+    0,                          /* tp_alloc */
+    PyType_GenericNew,          /* tp_new */
+    0,                          /* tp_free */
+    0,                          /* tp_is_gc */
+    0,                          /* tp_bases */
+    0,                          /* tp_mro */
+    0,                          /* tp_cache */
+    0,                          /* tp_subclasses */
+    0,                          /* tp_weaklist */
+    0,                          /* tp_del */
+    0,                          /* tp_version_tag */
+    0,                          /* tp_finalize */
+};
+
+
+static PyMethodDef bufferedwriter_methods[] = {
+    /* BufferedIOMixin methods */
+    {"close", (PyCFunction)buffered_close, METH_NOARGS},
+    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
+    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
+    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
+    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
+    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
+    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
+    {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
+    {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
+
+    _IO_BUFFEREDWRITER_WRITE_METHODDEF
+    _IO__BUFFERED_TRUNCATE_METHODDEF
+    {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
+    _IO__BUFFERED_SEEK_METHODDEF
+    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
+    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
+    {NULL, NULL}
+};
+
+static PyMemberDef bufferedwriter_members[] = {
+    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
+    {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0},
+    {NULL}
+};
+
+static PyGetSetDef bufferedwriter_getset[] = {
+    {"closed", (getter)buffered_closed_get, NULL, NULL},
+    {"name", (getter)buffered_name_get, NULL, NULL},
+    {"mode", (getter)buffered_mode_get, NULL, NULL},
+    {NULL}
+};
+
+
+PyTypeObject PyBufferedWriter_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_io.BufferedWriter",       /*tp_name*/
+    sizeof(buffered),           /*tp_basicsize*/
+    0,                          /*tp_itemsize*/
+    (destructor)buffered_dealloc,     /*tp_dealloc*/
+    0,                          /*tp_print*/
+    0,                          /*tp_getattr*/
+    0,                          /*tp_setattr*/
+    0,                          /*tp_compare */
+    (reprfunc)buffered_repr,    /*tp_repr*/
+    0,                          /*tp_as_number*/
+    0,                          /*tp_as_sequence*/
+    0,                          /*tp_as_mapping*/
+    0,                          /*tp_hash */
+    0,                          /*tp_call*/
+    0,                          /*tp_str*/
+    0,                          /*tp_getattro*/
+    0,                          /*tp_setattro*/
+    0,                          /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,   /*tp_flags*/
+    _io_BufferedWriter___init____doc__, /* tp_doc */
+    (traverseproc)buffered_traverse, /* tp_traverse */
+    (inquiry)buffered_clear,    /* tp_clear */
+    0,                          /* tp_richcompare */
+    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    bufferedwriter_methods,     /* tp_methods */
+    bufferedwriter_members,     /* tp_members */
+    bufferedwriter_getset,      /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    offsetof(buffered, dict),   /* tp_dictoffset */
+    _io_BufferedWriter___init__, /* tp_init */
+    0,                          /* tp_alloc */
+    PyType_GenericNew,          /* tp_new */
+    0,                          /* tp_free */
+    0,                          /* tp_is_gc */
+    0,                          /* tp_bases */
+    0,                          /* tp_mro */
+    0,                          /* tp_cache */
+    0,                          /* tp_subclasses */
+    0,                          /* tp_weaklist */
+    0,                          /* tp_del */
+    0,                          /* tp_version_tag */
+    0,                          /* tp_finalize */
+};
+
 
 static PyMethodDef bufferedrwpair_methods[] = {
     {"read", (PyCFunction)bufferedrwpair_read, METH_VARARGS},
@@ -2521,7 +2619,7 @@
     0,                          /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
         | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,   /* tp_flags */
-    bufferedrwpair_doc,         /* tp_doc */
+    _io_BufferedRWPair___init____doc__, /* tp_doc */
     (traverseproc)bufferedrwpair_traverse, /* tp_traverse */
     (inquiry)bufferedrwpair_clear, /* tp_clear */
     0,                          /* tp_richcompare */
@@ -2536,7 +2634,7 @@
     0,                          /* tp_descr_get */
     0,                          /* tp_descr_set */
     offsetof(rwpair, dict),     /* tp_dictoffset */
-    (initproc)bufferedrwpair_init, /* tp_init */
+    _io_BufferedRWPair___init__, /* tp_init */
     0,                          /* tp_alloc */
     PyType_GenericNew,          /* tp_new */
     0,                          /* tp_free */
@@ -2550,63 +2648,8 @@
     0,                          /* tp_version_tag */
     0,                          /* tp_finalize */
 };
-

 
 
-/*
- * BufferedRandom
- */
-
-PyDoc_STRVAR(bufferedrandom_doc,
-    "A buffered interface to random access streams.\n"
-    "\n"
-    "The constructor creates a reader and writer for a seekable stream,\n"
-    "raw, given in the first argument. If the buffer_size is omitted it\n"
-    "defaults to DEFAULT_BUFFER_SIZE.\n"
-    );
-
-static int
-bufferedrandom_init(buffered *self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"raw", "buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    PyObject *raw;
-
-    self->ok = 0;
-    self->detached = 0;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedRandom", kwlist,
-                                     &raw, &buffer_size)) {
-        return -1;
-    }
-
-    if (_PyIOBase_check_seekable(raw, Py_True) == NULL)
-        return -1;
-    if (_PyIOBase_check_readable(raw, Py_True) == NULL)
-        return -1;
-    if (_PyIOBase_check_writable(raw, Py_True) == NULL)
-        return -1;
-
-    Py_CLEAR(self->raw);
-    Py_INCREF(raw);
-    self->raw = raw;
-    self->buffer_size = buffer_size;
-    self->readable = 1;
-    self->writable = 1;
-
-    if (_buffered_init(self) < 0)
-        return -1;
-    _bufferedreader_reset_buf(self);
-    _bufferedwriter_reset_buf(self);
-    self->pos = 0;
-
-    self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedRandom_Type &&
-                                Py_TYPE(raw) == &PyFileIO_Type);
-
-    self->ok = 1;
-    return 0;
-}
-
 static PyMethodDef bufferedrandom_methods[] = {
     /* BufferedIOMixin methods */
     {"close", (PyCFunction)buffered_close, METH_NOARGS},
@@ -2621,16 +2664,16 @@
 
     {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
 
-    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
+    _IO__BUFFERED_SEEK_METHODDEF
     {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
-    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
-    {"read", (PyCFunction)buffered_read, METH_VARARGS},
-    {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
-    {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS},
-    {"readinto1", (PyCFunction)buffered_readinto1, METH_VARARGS},
-    {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
-    {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
-    {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
+    _IO__BUFFERED_TRUNCATE_METHODDEF
+    _IO__BUFFERED_READ_METHODDEF
+    _IO__BUFFERED_READ1_METHODDEF
+    _IO__BUFFERED_READINTO_METHODDEF
+    _IO__BUFFERED_READINTO1_METHODDEF
+    _IO__BUFFERED_READLINE_METHODDEF
+    _IO__BUFFERED_PEEK_METHODDEF
+    _IO_BUFFEREDWRITER_WRITE_METHODDEF
     {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
     {NULL, NULL}
 };
@@ -2671,7 +2714,7 @@
     0,                          /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
         | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,   /*tp_flags*/
-    bufferedrandom_doc,         /* tp_doc */
+    _io_BufferedRandom___init____doc__, /* tp_doc */
     (traverseproc)buffered_traverse, /* tp_traverse */
     (inquiry)buffered_clear,    /* tp_clear */
     0,                          /* tp_richcompare */
@@ -2686,7 +2729,7 @@
     0,                          /* tp_descr_get */
     0,                          /* tp_descr_set */
     offsetof(buffered, dict), /*tp_dictoffset*/
-    (initproc)bufferedrandom_init, /* tp_init */
+    _io_BufferedRandom___init__, /* tp_init */
     0,                          /* tp_alloc */
     PyType_GenericNew,          /* tp_new */
     0,                          /* tp_free */
diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c
--- a/Modules/_io/bytesio.c
+++ b/Modules/_io/bytesio.c
@@ -2,6 +2,12 @@
 #include "structmember.h"       /* for offsetof() */
 #include "_iomodule.h"
 
+/*[clinic input]
+module _io
+class _io.BytesIO "bytesio *" "&PyBytesIO_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7f50ec034f5c0b26]*/
+
 typedef struct {
     PyObject_HEAD
     PyObject *buf;
@@ -203,40 +209,71 @@
     }
 }
 
-PyDoc_STRVAR(readable_doc,
-"readable() -> bool. Returns True if the IO object can be read.");
+/*[clinic input]
+_io.BytesIO.readable
 
-PyDoc_STRVAR(writable_doc,
-"writable() -> bool. Returns True if the IO object can be written.");
+Returns True if the IO object can be read.
+[clinic start generated code]*/
 
-PyDoc_STRVAR(seekable_doc,
-"seekable() -> bool. Returns True if the IO object can be seeked.");
-
-/* Generic getter for the writable, readable and seekable properties */
 static PyObject *
-return_not_closed(bytesio *self)
+_io_BytesIO_readable_impl(bytesio *self)
+/*[clinic end generated code: output=4e93822ad5b62263 input=96c5d0cccfb29f5c]*/
 {
     CHECK_CLOSED(self);
     Py_RETURN_TRUE;
 }
 
-PyDoc_STRVAR(flush_doc,
-"flush() -> None.  Does nothing.");
+/*[clinic input]
+_io.BytesIO.writable
+
+Returns True if the IO object can be written.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_flush(bytesio *self)
+_io_BytesIO_writable_impl(bytesio *self)
+/*[clinic end generated code: output=64ff6a254b1150b8 input=700eed808277560a]*/
+{
+    CHECK_CLOSED(self);
+    Py_RETURN_TRUE;
+}
+
+/*[clinic input]
+_io.BytesIO.seekable
+
+Returns True if the IO object can be seeked.
+[clinic start generated code]*/
+
+static PyObject *
+_io_BytesIO_seekable_impl(bytesio *self)
+/*[clinic end generated code: output=6b417f46dcc09b56 input=9421f65627a344dd]*/
+{
+    CHECK_CLOSED(self);
+    Py_RETURN_TRUE;
+}
+
+/*[clinic input]
+_io.BytesIO.flush
+
+Does nothing.
+[clinic start generated code]*/
+
+static PyObject *
+_io_BytesIO_flush_impl(bytesio *self)
+/*[clinic end generated code: output=187e3d781ca134a0 input=561ea490be4581a7]*/
 {
     CHECK_CLOSED(self);
     Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(getbuffer_doc,
-"getbuffer() -> bytes.\n"
-"\n"
-"Get a read-write view over the contents of the BytesIO object.");
+/*[clinic input]
+_io.BytesIO.getbuffer
+
+Get a read-write view over the contents of the BytesIO object.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_getbuffer(bytesio *self)
+_io_BytesIO_getbuffer_impl(bytesio *self)
+/*[clinic end generated code: output=72cd7c6e13aa09ed input=8f738ef615865176]*/
 {
     PyTypeObject *type = &_PyBytesIOBuffer_Type;
     bytesiobuf *buf;
@@ -254,13 +291,15 @@
     return view;
 }
 
-PyDoc_STRVAR(getval_doc,
-"getvalue() -> bytes.\n"
-"\n"
-"Retrieve the entire contents of the BytesIO object.");
+/*[clinic input]
+_io.BytesIO.getvalue
+
+Retrieve the entire contents of the BytesIO object.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_getvalue(bytesio *self)
+_io_BytesIO_getvalue_impl(bytesio *self)
+/*[clinic end generated code: output=b3f6a3233c8fd628 input=4b403ac0af3973ed]*/
 {
     CHECK_CLOSED(self);
     if (self->string_size <= 1 || self->exports > 0)
@@ -281,24 +320,31 @@
     return self->buf;
 }
 
-PyDoc_STRVAR(isatty_doc,
-"isatty() -> False.\n"
-"\n"
-"Always returns False since BytesIO objects are not connected\n"
-"to a tty-like device.");
+/*[clinic input]
+_io.BytesIO.isatty
+
+Always returns False.
+
+BytesIO objects are not connected to a TTY-like device.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_isatty(bytesio *self)
+_io_BytesIO_isatty_impl(bytesio *self)
+/*[clinic end generated code: output=df67712e669f6c8f input=6f97f0985d13f827]*/
 {
     CHECK_CLOSED(self);
     Py_RETURN_FALSE;
 }
 
-PyDoc_STRVAR(tell_doc,
-"tell() -> current file position, an integer\n");
+/*[clinic input]
+_io.BytesIO.tell
+
+Current file position, an integer.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_tell(bytesio *self)
+_io_BytesIO_tell_impl(bytesio *self)
+/*[clinic end generated code: output=b54b0f93cd0e5e1d input=b106adf099cb3657]*/
 {
     CHECK_CLOSED(self);
     return PyLong_FromSsize_t(self->pos);
@@ -324,23 +370,25 @@
     return PyBytes_FromStringAndSize(output, size);
 }
 
-PyDoc_STRVAR(read_doc,
-"read([size]) -> read at most size bytes, returned as a bytes object.\n"
-"\n"
-"If the size argument is negative, read until EOF is reached.\n"
-"Return an empty bytes object at EOF.");
+/*[clinic input]
+_io.BytesIO.read
+    size as arg: object = None
+    /
+
+Read at most size bytes, returned as a bytes object.
+
+If the size argument is negative, read until EOF is reached.
+Return an empty bytes object at EOF.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_read(bytesio *self, PyObject *args)
+_io_BytesIO_read_impl(bytesio *self, PyObject *arg)
+/*[clinic end generated code: output=85dacb535c1e1781 input=cc7ba4a797bb1555]*/
 {
     Py_ssize_t size, n;
-    PyObject *arg = Py_None;
 
     CHECK_CLOSED(self);
 
-    if (!PyArg_ParseTuple(args, "|O:read", &arg))
-        return NULL;
-
     if (PyLong_Check(arg)) {
         size = PyLong_AsSsize_t(arg);
         if (size == -1 && PyErr_Occurred())
@@ -368,43 +416,44 @@
 }
 
 
-PyDoc_STRVAR(read1_doc,
-"read1(size) -> read at most size bytes, returned as a bytes object.\n"
-"\n"
-"If the size argument is negative or omitted, read until EOF is reached.\n"
-"Return an empty bytes object at EOF.");
+/*[clinic input]
+_io.BytesIO.read1
+    size: object
+    /
+
+Read at most size bytes, returned as a bytes object.
+
+If the size argument is negative or omitted, read until EOF is reached.
+Return an empty bytes object at EOF.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_read1(bytesio *self, PyObject *n)
+_io_BytesIO_read1(bytesio *self, PyObject *size)
+/*[clinic end generated code: output=16021f5d0ac3d4e2 input=d4f40bb8f2f99418]*/
 {
-    PyObject *arg, *res;
-
-    arg = PyTuple_Pack(1, n);
-    if (arg == NULL)
-        return NULL;
-    res  = bytesio_read(self, arg);
-    Py_DECREF(arg);
-    return res;
+    return _io_BytesIO_read_impl(self, size);
 }
 
-PyDoc_STRVAR(readline_doc,
-"readline([size]) -> next line from the file, as a bytes object.\n"
-"\n"
-"Retain newline.  A non-negative size argument limits the maximum\n"
-"number of bytes to return (an incomplete line may be returned then).\n"
-"Return an empty bytes object at EOF.\n");
+/*[clinic input]
+_io.BytesIO.readline
+    size as arg: object = None
+    /
+
+Next line from the file, as a bytes object.
+
+Retain newline.  A non-negative size argument limits the maximum
+number of bytes to return (an incomplete line may be returned then).
+Return an empty bytes object at EOF.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_readline(bytesio *self, PyObject *args)
+_io_BytesIO_readline_impl(bytesio *self, PyObject *arg)
+/*[clinic end generated code: output=1c2115534a4f9276 input=ca31f06de6eab257]*/
 {
     Py_ssize_t size, n;
-    PyObject *arg = Py_None;
 
     CHECK_CLOSED(self);
 
-    if (!PyArg_ParseTuple(args, "|O:readline", &arg))
-        return NULL;
-
     if (PyLong_Check(arg)) {
         size = PyLong_AsSsize_t(arg);
         if (size == -1 && PyErr_Occurred())
@@ -425,26 +474,28 @@
     return read_bytes(self, n);
 }
 
-PyDoc_STRVAR(readlines_doc,
-"readlines([size]) -> list of strings, each a line from the file.\n"
-"\n"
-"Call readline() repeatedly and return a list of the lines so read.\n"
-"The optional size argument, if given, is an approximate bound on the\n"
-"total number of bytes in the lines returned.\n");
+/*[clinic input]
+_io.BytesIO.readlines
+    size as arg: object = None
+    /
+
+List of bytes objects, each a line from the file.
+
+Call readline() repeatedly and return a list of the lines so read.
+The optional size argument, if given, is an approximate bound on the
+total number of bytes in the lines returned.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_readlines(bytesio *self, PyObject *args)
+_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg)
+/*[clinic end generated code: output=09b8e34c880808ff input=691aa1314f2c2a87]*/
 {
     Py_ssize_t maxsize, size, n;
     PyObject *result, *line;
     char *output;
-    PyObject *arg = Py_None;
 
     CHECK_CLOSED(self);
 
-    if (!PyArg_ParseTuple(args, "|O:readlines", &arg))
-        return NULL;
-
     if (PyLong_Check(arg)) {
         maxsize = PyLong_AsSsize_t(arg);
         if (maxsize == -1 && PyErr_Occurred())
@@ -488,25 +539,27 @@
     return NULL;
 }
 
-PyDoc_STRVAR(readinto_doc,
-"readinto(bytearray) -> int.  Read up to len(b) bytes into b.\n"
-"\n"
-"Returns number of bytes read (0 for EOF), or None if the object\n"
-"is set not to block as has no data to read.");
+/*[clinic input]
+_io.BytesIO.readinto
+    buffer: Py_buffer(types={'rwbuffer'})
+    /
+
+Read up to len(buffer) bytes into buffer.
+
+Returns number of bytes read (0 for EOF), or None if the object
+is set not to block as has no data to read.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_readinto(bytesio *self, PyObject *arg)
+_io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer)
+/*[clinic end generated code: output=a5d407217dcf0639 input=d289da851c7c4159]*/
 {
-    Py_buffer buffer;
     Py_ssize_t len, n;
 
     CHECK_CLOSED(self);
 
-    if (!PyArg_Parse(arg, "w*", &buffer))
-        return NULL;
-
     /* adjust invalid sizes */
-    len = buffer.len;
+    len = buffer->len;
     n = self->string_size - self->pos;
     if (len > n) {
         len = n;
@@ -514,33 +567,34 @@
             len = 0;
     }
 
-    memcpy(buffer.buf, PyBytes_AS_STRING(self->buf) + self->pos, len);
+    memcpy(buffer->buf, PyBytes_AS_STRING(self->buf) + self->pos, len);
     assert(self->pos + len < PY_SSIZE_T_MAX);
     assert(len >= 0);
     self->pos += len;
-    PyBuffer_Release(&buffer);
 
     return PyLong_FromSsize_t(len);
 }
 
-PyDoc_STRVAR(truncate_doc,
-"truncate([size]) -> int.  Truncate the file to at most size bytes.\n"
-"\n"
-"Size defaults to the current file position, as returned by tell().\n"
-"The current file position is unchanged.  Returns the new size.\n");
+/*[clinic input]
+_io.BytesIO.truncate
+    size as arg: object = None
+    /
+
+Truncate the file to at most size bytes.
+
+Size defaults to the current file position, as returned by tell().
+The current file position is unchanged.  Returns the new size.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_truncate(bytesio *self, PyObject *args)
+_io_BytesIO_truncate_impl(bytesio *self, PyObject *arg)
+/*[clinic end generated code: output=81e6be60e67ddd66 input=11ed1966835462ba]*/
 {
     Py_ssize_t size;
-    PyObject *arg = Py_None;
 
     CHECK_CLOSED(self);
     CHECK_EXPORTS(self);
 
-    if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
-        return NULL;
-
     if (PyLong_Check(arg)) {
         size = PyLong_AsSsize_t(arg);
         if (size == -1 && PyErr_Occurred())
@@ -586,36 +640,37 @@
     return read_bytes(self, n);
 }
 
-PyDoc_STRVAR(seek_doc,
-"seek(pos, whence=0) -> int.  Change stream position.\n"
-"\n"
-"Seek to byte offset pos relative to position indicated by whence:\n"
-"     0  Start of stream (the default).  pos should be >= 0;\n"
-"     1  Current position - pos may be negative;\n"
-"     2  End of stream - pos usually negative.\n"
-"Returns the new absolute position.");
+/*[clinic input]
+_io.BytesIO.seek
+    pos: Py_ssize_t
+    whence: int = 0
+    /
+
+Change stream position.
+
+Seek to byte offset pos relative to position indicated by whence:
+     0  Start of stream (the default).  pos should be >= 0;
+     1  Current position - pos may be negative;
+     2  End of stream - pos usually negative.
+Returns the new absolute position.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_seek(bytesio *self, PyObject *args)
+_io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence)
+/*[clinic end generated code: output=c26204a68e9190e4 input=1e875e6ebc652948]*/
 {
-    Py_ssize_t pos;
-    int mode = 0;
-
     CHECK_CLOSED(self);
 
-    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode))
-        return NULL;
-
-    if (pos < 0 && mode == 0) {
+    if (pos < 0 && whence == 0) {
         PyErr_Format(PyExc_ValueError,
                      "negative seek value %zd", pos);
         return NULL;
     }
 
-    /* mode 0: offset relative to beginning of the string.
-       mode 1: offset relative to current position.
-       mode 2: offset relative the end of the string. */
-    if (mode == 1) {
+    /* whence = 0: offset relative to beginning of the string.
+       whence = 1: offset relative to current position.
+       whence = 2: offset relative the end of the string. */
+    if (whence == 1) {
         if (pos > PY_SSIZE_T_MAX - self->pos) {
             PyErr_SetString(PyExc_OverflowError,
                             "new position too large");
@@ -623,7 +678,7 @@
         }
         pos += self->pos;
     }
-    else if (mode == 2) {
+    else if (whence == 2) {
         if (pos > PY_SSIZE_T_MAX - self->string_size) {
             PyErr_SetString(PyExc_OverflowError,
                             "new position too large");
@@ -631,9 +686,9 @@
         }
         pos += self->string_size;
     }
-    else if (mode != 0) {
+    else if (whence != 0) {
         PyErr_Format(PyExc_ValueError,
-                     "invalid whence (%i, should be 0, 1 or 2)", mode);
+                     "invalid whence (%i, should be 0, 1 or 2)", whence);
         return NULL;
     }
 
@@ -644,54 +699,63 @@
     return PyLong_FromSsize_t(self->pos);
 }
 
-PyDoc_STRVAR(write_doc,
-"write(bytes) -> int.  Write bytes to file.\n"
-"\n"
-"Return the number of bytes written.");
+/*[clinic input]
+_io.BytesIO.write
+    b: object
+    /
+
+Write bytes to file.
+
+Return the number of bytes written.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_write(bytesio *self, PyObject *obj)
+_io_BytesIO_write(bytesio *self, PyObject *b)
+/*[clinic end generated code: output=53316d99800a0b95 input=f5ec7c8c64ed720a]*/
 {
     Py_ssize_t n = 0;
     Py_buffer buf;
-    PyObject *result = NULL;
 
     CHECK_CLOSED(self);
     CHECK_EXPORTS(self);
 
-    if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0)
+    if (PyObject_GetBuffer(b, &buf, PyBUF_CONTIG_RO) < 0)
         return NULL;
 
     if (buf.len != 0)
         n = write_bytes(self, buf.buf, buf.len);
-    if (n >= 0)
-        result = PyLong_FromSsize_t(n);
 
     PyBuffer_Release(&buf);
-    return result;
+    return n >= 0 ? PyLong_FromSsize_t(n) : NULL;
 }
 
-PyDoc_STRVAR(writelines_doc,
-"writelines(lines) -> None.  Write bytes objects to the file.\n"
-"\n"
-"Note that newlines are not added.  The argument can be any iterable\n"
-"object producing bytes objects. This is equivalent to calling write() for\n"
-"each bytes object.");
+/*[clinic input]
+_io.BytesIO.writelines
+    lines: object
+    /
+
+Write lines to the file.
+
+Note that newlines are not added.  lines can be any iterable object
+producing bytes-like objects. This is equivalent to calling write() for
+each element.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_writelines(bytesio *self, PyObject *v)
+_io_BytesIO_writelines(bytesio *self, PyObject *lines)
+/*[clinic end generated code: output=7f33aa3271c91752 input=e972539176fc8fc1]*/
 {
     PyObject *it, *item;
     PyObject *ret;
 
     CHECK_CLOSED(self);
 
-    it = PyObject_GetIter(v);
+    it = PyObject_GetIter(lines);
     if (it == NULL)
         return NULL;
 
     while ((item = PyIter_Next(it)) != NULL) {
-        ret = bytesio_write(self, item);
+        ret = _io_BytesIO_write(self, item);
         Py_DECREF(item);
         if (ret == NULL) {
             Py_DECREF(it);
@@ -708,11 +772,15 @@
     Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(close_doc,
-"close() -> None.  Disable all I/O operations.");
+/*[clinic input]
+_io.BytesIO.close
+
+Disable all I/O operations.
+[clinic start generated code]*/
 
 static PyObject *
-bytesio_close(bytesio *self)
+_io_BytesIO_close_impl(bytesio *self)
+/*[clinic end generated code: output=1471bb9411af84a0 input=37e1f55556e61f60]*/
 {
     CHECK_EXPORTS(self);
     Py_CLEAR(self->buf);
@@ -737,7 +805,7 @@
 static PyObject *
 bytesio_getstate(bytesio *self)
 {
-    PyObject *initvalue = bytesio_getvalue(self);
+    PyObject *initvalue = _io_BytesIO_getvalue_impl(self);
     PyObject *dict;
     PyObject *state;
 
@@ -787,7 +855,7 @@
 
     /* Set the value of the internal buffer. If state[0] does not support the
        buffer protocol, bytesio_write will raise the appropriate TypeError. */
-    result = bytesio_write(self, PyTuple_GET_ITEM(state, 0));
+    result = _io_BytesIO_write(self, PyTuple_GET_ITEM(state, 0));
     if (result == NULL)
         return NULL;
     Py_DECREF(result);
@@ -874,16 +942,17 @@
     return (PyObject *)self;
 }
 
+/*[clinic input]
+_io.BytesIO.__init__
+    initial_bytes as initvalue: object(c_default="NULL") = b''
+
+Buffered I/O implementation using an in-memory bytes buffer.
+[clinic start generated code]*/
+
 static int
-bytesio_init(bytesio *self, PyObject *args, PyObject *kwds)
+_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue)
+/*[clinic end generated code: output=65c0c51e24c5b621 input=aac7f31b67bf0fb6]*/
 {
-    char *kwlist[] = {"initial_bytes", NULL};
-    PyObject *initvalue = NULL;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:BytesIO", kwlist,
-                                     &initvalue))
-        return -1;
-
     /* In case, __init__ is called multiple times. */
     self->string_size = 0;
     self->pos = 0;
@@ -902,7 +971,7 @@
         }
         else {
             PyObject *res;
-            res = bytesio_write(self, initvalue);
+            res = _io_BytesIO_write(self, initvalue);
             if (res == NULL)
                 return -1;
             Py_DECREF(res);
@@ -939,6 +1008,8 @@
 }
 
 
+#include "clinic/bytesio.c.h"
+
 static PyGetSetDef bytesio_getsetlist[] = {
     {"closed",  (getter)bytesio_get_closed, NULL,
      "True if the file is closed."},
@@ -946,36 +1017,30 @@
 };
 
 static struct PyMethodDef bytesio_methods[] = {
-    {"readable",   (PyCFunction)return_not_closed,  METH_NOARGS, readable_doc},
-    {"seekable",   (PyCFunction)return_not_closed,  METH_NOARGS, seekable_doc},
-    {"writable",   (PyCFunction)return_not_closed,  METH_NOARGS, writable_doc},
-    {"close",      (PyCFunction)bytesio_close,      METH_NOARGS, close_doc},
-    {"flush",      (PyCFunction)bytesio_flush,      METH_NOARGS, flush_doc},
-    {"isatty",     (PyCFunction)bytesio_isatty,     METH_NOARGS, isatty_doc},
-    {"tell",       (PyCFunction)bytesio_tell,       METH_NOARGS, tell_doc},
-    {"write",      (PyCFunction)bytesio_write,      METH_O, write_doc},
-    {"writelines", (PyCFunction)bytesio_writelines, METH_O, writelines_doc},
-    {"read1",      (PyCFunction)bytesio_read1,      METH_O, read1_doc},
-    {"readinto",   (PyCFunction)bytesio_readinto,   METH_O, readinto_doc},
-    {"readline",   (PyCFunction)bytesio_readline,   METH_VARARGS, readline_doc},
-    {"readlines",  (PyCFunction)bytesio_readlines,  METH_VARARGS, readlines_doc},
-    {"read",       (PyCFunction)bytesio_read,       METH_VARARGS, read_doc},
-    {"getbuffer",  (PyCFunction)bytesio_getbuffer,  METH_NOARGS,  getbuffer_doc},
-    {"getvalue",   (PyCFunction)bytesio_getvalue,   METH_NOARGS,  getval_doc},
-    {"seek",       (PyCFunction)bytesio_seek,       METH_VARARGS, seek_doc},
-    {"truncate",   (PyCFunction)bytesio_truncate,   METH_VARARGS, truncate_doc},
+    _IO_BYTESIO_READABLE_METHODDEF
+    _IO_BYTESIO_SEEKABLE_METHODDEF
+    _IO_BYTESIO_WRITABLE_METHODDEF
+    _IO_BYTESIO_CLOSE_METHODDEF
+    _IO_BYTESIO_FLUSH_METHODDEF
+    _IO_BYTESIO_ISATTY_METHODDEF
+    _IO_BYTESIO_TELL_METHODDEF
+    _IO_BYTESIO_WRITE_METHODDEF
+    _IO_BYTESIO_WRITELINES_METHODDEF
+    _IO_BYTESIO_READ1_METHODDEF
+    _IO_BYTESIO_READINTO_METHODDEF
+    _IO_BYTESIO_READLINE_METHODDEF
+    _IO_BYTESIO_READLINES_METHODDEF
+    _IO_BYTESIO_READ_METHODDEF
+    _IO_BYTESIO_GETBUFFER_METHODDEF
+    _IO_BYTESIO_GETVALUE_METHODDEF
+    _IO_BYTESIO_SEEK_METHODDEF
+    _IO_BYTESIO_TRUNCATE_METHODDEF
     {"__getstate__",  (PyCFunction)bytesio_getstate,  METH_NOARGS, NULL},
     {"__setstate__",  (PyCFunction)bytesio_setstate,  METH_O, NULL},
     {"__sizeof__", (PyCFunction)bytesio_sizeof,     METH_NOARGS, NULL},
     {NULL, NULL}        /* sentinel */
 };
 
-PyDoc_STRVAR(bytesio_doc,
-"BytesIO([buffer]) -> object\n"
-"\n"
-"Create a buffered I/O implementation using an in-memory bytes\n"
-"buffer, ready for reading and writing.");
-
 PyTypeObject PyBytesIO_Type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "_io.BytesIO",                             /*tp_name*/
@@ -998,7 +1063,7 @@
     0,                                         /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
     Py_TPFLAGS_HAVE_GC,                        /*tp_flags*/
-    bytesio_doc,                               /*tp_doc*/
+    _io_BytesIO___init____doc__,               /*tp_doc*/
     (traverseproc)bytesio_traverse,            /*tp_traverse*/
     (inquiry)bytesio_clear,                    /*tp_clear*/
     0,                                         /*tp_richcompare*/
@@ -1013,7 +1078,7 @@
     0,                                         /*tp_descr_get*/
     0,                                         /*tp_descr_set*/
     offsetof(bytesio, dict),             /*tp_dictoffset*/
-    (initproc)bytesio_init,                    /*tp_init*/
+    _io_BytesIO___init__,                      /*tp_init*/
     0,                                         /*tp_alloc*/
     bytesio_new,                               /*tp_new*/
 };
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/clinic/_iomodule.c.h
copy from Modules/_io/_iomodule.c
copy to Modules/_io/clinic/_iomodule.c.h
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/clinic/_iomodule.c.h
@@ -1,115 +1,25 @@
-/*
-    An implementation of the new I/O lib as defined by PEP 3116 - "New I/O"
+/*[clinic input]
+preserve
+[clinic start generated code]*/
 
-    Classes defined here: UnsupportedOperation, BlockingIOError.
-    Functions defined here: open().
-
-    Mostly written by Amaury Forgeot d'Arc
-*/
-
-#define PY_SSIZE_T_CLEAN
-#include "Python.h"
-#include "structmember.h"
-#include "_iomodule.h"
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif /* HAVE_SYS_TYPES_H */
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif /* HAVE_SYS_STAT_H */
-
-
-/* Various interned strings */
-
-PyObject *_PyIO_str_close;
-PyObject *_PyIO_str_closed;
-PyObject *_PyIO_str_decode;
-PyObject *_PyIO_str_encode;
-PyObject *_PyIO_str_fileno;
-PyObject *_PyIO_str_flush;
-PyObject *_PyIO_str_getstate;
-PyObject *_PyIO_str_isatty;
-PyObject *_PyIO_str_newlines;
-PyObject *_PyIO_str_nl;
-PyObject *_PyIO_str_read;
-PyObject *_PyIO_str_read1;
-PyObject *_PyIO_str_readable;
-PyObject *_PyIO_str_readall;
-PyObject *_PyIO_str_readinto;
-PyObject *_PyIO_str_readline;
-PyObject *_PyIO_str_reset;
-PyObject *_PyIO_str_seek;
-PyObject *_PyIO_str_seekable;
-PyObject *_PyIO_str_setstate;
-PyObject *_PyIO_str_tell;
-PyObject *_PyIO_str_truncate;
-PyObject *_PyIO_str_writable;
-PyObject *_PyIO_str_write;
-
-PyObject *_PyIO_empty_str;
-PyObject *_PyIO_empty_bytes;
-PyObject *_PyIO_zero;
-
-

-PyDoc_STRVAR(module_doc,
-"The io module provides the Python interfaces to stream handling. The\n"
-"builtin open function is defined in this module.\n"
-"\n"
-"At the top of the I/O hierarchy is the abstract base class IOBase. It\n"
-"defines the basic interface to a stream. Note, however, that there is no\n"
-"separation between reading and writing to streams; implementations are\n"
-"allowed to raise an IOError if they do not support a given operation.\n"
-"\n"
-"Extending IOBase is RawIOBase which deals simply with the reading and\n"
-"writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide\n"
-"an interface to OS files.\n"
-"\n"
-"BufferedIOBase deals with buffering on a raw byte stream (RawIOBase). Its\n"
-"subclasses, BufferedWriter, BufferedReader, and BufferedRWPair buffer\n"
-"streams that are readable, writable, and both respectively.\n"
-"BufferedRandom provides a buffered interface to random access\n"
-"streams. BytesIO is a simple stream of in-memory bytes.\n"
-"\n"
-"Another IOBase subclass, TextIOBase, deals with the encoding and decoding\n"
-"of streams into text. TextIOWrapper, which extends it, is a buffered text\n"
-"interface to a buffered raw stream (`BufferedIOBase`). Finally, StringIO\n"
-"is a in-memory stream for text.\n"
-"\n"
-"Argument names are not part of the specification, and only the arguments\n"
-"of open() are intended to be used as keyword arguments.\n"
-"\n"
-"data:\n"
-"\n"
-"DEFAULT_BUFFER_SIZE\n"
-"\n"
-"   An int containing the default buffer size used by the module's buffered\n"
-"   I/O classes. open() uses the file's blksize (as obtained by os.stat) if\n"
-"   possible.\n"
-    );
-

-
-/*
- * The main open() function
- */
-PyDoc_STRVAR(open_doc,
-"open(file, mode='r', buffering=-1, encoding=None,\n"
-"     errors=None, newline=None, closefd=True, opener=None) -> file object\n"
+PyDoc_STRVAR(_io_open__doc__,
+"open($module, /, file, mode=\'r\', buffering=-1, encoding=None,\n"
+"     errors=None, newline=None, closefd=True, opener=None)\n"
+"--\n"
 "\n"
 "Open file and return a stream.  Raise IOError upon failure.\n"
 "\n"
 "file is either a text or byte string giving the name (and the path\n"
-"if the file isn't in the current working directory) of the file to\n"
+"if the file isn\'t in the current working directory) of the file to\n"
 "be opened or an integer file descriptor of the file to be\n"
 "wrapped. (If a file descriptor is given, it is closed when the\n"
 "returned I/O object is closed, unless closefd is set to False.)\n"
 "\n"
 "mode is an optional string that specifies the mode in which the file\n"
-"is opened. It defaults to 'r' which means open for reading in text\n"
-"mode.  Other common values are 'w' for writing (truncating the file if\n"
-"it already exists), 'x' for creating and writing to a new file, and\n"
-"'a' for appending (which on some Unix systems, means that all writes\n"
+"is opened. It defaults to \'r\' which means open for reading in text\n"
+"mode.  Other common values are \'w\' for writing (truncating the file if\n"
+"it already exists), \'x\' for creating and writing to a new file, and\n"
+"\'a\' for appending (which on some Unix systems, means that all writes\n"
 "append to the end of the file regardless of the current seek position).\n"
 "In text mode, if encoding is not specified the encoding used is platform\n"
 "dependent: locale.getpreferredencoding(False) is called to get the\n"
@@ -119,30 +29,30 @@
 "========= ===============================================================\n"
 "Character Meaning\n"
 "--------- ---------------------------------------------------------------\n"
-"'r'       open for reading (default)\n"
-"'w'       open for writing, truncating the file first\n"
-"'x'       create a new file and open it for writing\n"
-"'a'       open for writing, appending to the end of the file if it exists\n"
-"'b'       binary mode\n"
-"'t'       text mode (default)\n"
-"'+'       open a disk file for updating (reading and writing)\n"
-"'U'       universal newline mode (deprecated)\n"
+"\'r\'       open for reading (default)\n"
+"\'w\'       open for writing, truncating the file first\n"
+"\'x\'       create a new file and open it for writing\n"
+"\'a\'       open for writing, appending to the end of the file if it exists\n"
+"\'b\'       binary mode\n"
+"\'t\'       text mode (default)\n"
+"\'+\'       open a disk file for updating (reading and writing)\n"
+"\'U\'       universal newline mode (deprecated)\n"
 "========= ===============================================================\n"
 "\n"
-"The default mode is 'rt' (open for reading text). For binary random\n"
-"access, the mode 'w+b' opens and truncates the file to 0 bytes, while\n"
-"'r+b' opens the file without truncation. The 'x' mode implies 'w' and\n"
+"The default mode is \'rt\' (open for reading text). For binary random\n"
+"access, the mode \'w+b\' opens and truncates the file to 0 bytes, while\n"
+"\'r+b\' opens the file without truncation. The \'x\' mode implies \'w\' and\n"
 "raises an `FileExistsError` if the file already exists.\n"
 "\n"
 "Python distinguishes between files opened in binary and text modes,\n"
-"even when the underlying operating system doesn't. Files opened in\n"
-"binary mode (appending 'b' to the mode argument) return contents as\n"
+"even when the underlying operating system doesn\'t. Files opened in\n"
+"binary mode (appending \'b\' to the mode argument) return contents as\n"
 "bytes objects without any decoding. In text mode (the default, or when\n"
-"'t' is appended to the mode argument), the contents of the file are\n"
+"\'t\' is appended to the mode argument), the contents of the file are\n"
 "returned as strings, the bytes having been first decoded using a\n"
 "platform-dependent encoding or using the specified encoding if given.\n"
 "\n"
-"'U' mode is deprecated and will raise an exception in future versions\n"
+"\'U\' mode is deprecated and will raise an exception in future versions\n"
 "of Python.  It has no effect in Python 3.  Use newline to control\n"
 "universal newlines mode.\n"
 "\n"
@@ -153,7 +63,7 @@
 "given, the default buffering policy works as follows:\n"
 "\n"
 "* Binary files are buffered in fixed-size chunks; the size of the buffer\n"
-"  is chosen using a heuristic trying to determine the underlying device's\n"
+"  is chosen using a heuristic trying to determine the underlying device\'s\n"
 "  \"block size\" and falling back on `io.DEFAULT_BUFFER_SIZE`.\n"
 "  On many systems, the buffer will typically be 4096 or 8192 bytes long.\n"
 "\n"
@@ -168,28 +78,28 @@
 "\n"
 "errors is an optional string that specifies how encoding errors are to\n"
 "be handled---this argument should not be used in binary mode. Pass\n"
-"'strict' to raise a ValueError exception if there is an encoding error\n"
-"(the default of None has the same effect), or pass 'ignore' to ignore\n"
+"\'strict\' to raise a ValueError exception if there is an encoding error\n"
+"(the default of None has the same effect), or pass \'ignore\' to ignore\n"
 "errors. (Note that ignoring encoding errors can lead to data loss.)\n"
-"See the documentation for codecs.register or run 'help(codecs.Codec)'\n"
+"See the documentation for codecs.register or run \'help(codecs.Codec)\'\n"
 "for a list of the permitted encoding error strings.\n"
 "\n"
 "newline controls how universal newlines works (it only applies to text\n"
-"mode). It can be None, '', '\\n', '\\r', and '\\r\\n'.  It works as\n"
+"mode). It can be None, \'\', \'\\n\', \'\\r\', and \'\\r\\n\'.  It works as\n"
 "follows:\n"
 "\n"
 "* On input, if newline is None, universal newlines mode is\n"
-"  enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n"
-"  these are translated into '\\n' before being returned to the\n"
-"  caller. If it is '', universal newline mode is enabled, but line\n"
+"  enabled. Lines in the input can end in \'\\n\', \'\\r\', or \'\\r\\n\', and\n"
+"  these are translated into \'\\n\' before being returned to the\n"
+"  caller. If it is \'\', universal newline mode is enabled, but line\n"
 "  endings are returned to the caller untranslated. If it has any of\n"
 "  the other legal values, input lines are only terminated by the given\n"
 "  string, and the line ending is returned to the caller untranslated.\n"
 "\n"
-"* On output, if newline is None, any '\\n' characters written are\n"
+"* On output, if newline is None, any \'\\n\' characters written are\n"
 "  translated to the system default line separator, os.linesep. If\n"
-"  newline is '' or '\\n', no translation takes place. If newline is any\n"
-"  of the other legal values, any '\\n' characters written are translated\n"
+"  newline is \'\' or \'\\n\', no translation takes place. If newline is any\n"
+"  of the other legal values, any \'\\n\' characters written are translated\n"
 "  to the given string.\n"
 "\n"
 "If closefd is False, the underlying file descriptor will be kept open\n"
@@ -204,8 +114,8 @@
 "\n"
 "open() returns a file object whose type depends on the mode, and\n"
 "through which the standard file operations such as reading and writing\n"
-"are performed. When open() is used to open a file in a text mode ('w',\n"
-"'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open\n"
+"are performed. When open() is used to open a file in a text mode (\'w\',\n"
+"\'r\', \'wt\', \'rt\', etc.), it returns a TextIOWrapper. When used to open\n"
 "a file in a binary mode, the returned class varies: in read binary\n"
 "mode, it returns a BufferedReader; in write binary and append binary\n"
 "modes, it returns a BufferedWriter, and in read/write mode, it returns\n"
@@ -214,556 +124,37 @@
 "It is also possible to use a string or bytearray as a file for both\n"
 "reading and writing. For strings StringIO can be used like a file\n"
 "opened in a text mode, and for bytes a BytesIO can be used like a file\n"
-"opened in a binary mode.\n"
-    );
+"opened in a binary mode.");
+
+#define _IO_OPEN_METHODDEF    \
+    {"open", (PyCFunction)_io_open, METH_VARARGS|METH_KEYWORDS, _io_open__doc__},
 
 static PyObject *
-io_open(PyObject *self, PyObject *args, PyObject *kwds)
+_io_open_impl(PyModuleDef *module, PyObject *file, const char *mode,
+              int buffering, const char *encoding, const char *errors,
+              const char *newline, int closefd, PyObject *opener);
+
+static PyObject *
+_io_open(PyModuleDef *module, PyObject *args, PyObject *kwargs)
 {
-    char *kwlist[] = {"file", "mode", "buffering",
-                      "encoding", "errors", "newline",
-                      "closefd", "opener", NULL};
-    PyObject *file, *opener = Py_None;
-    char *mode = "r";
-    int buffering = -1, closefd = 1;
-    char *encoding = NULL, *errors = NULL, *newline = NULL;
-    unsigned i;
+    PyObject *return_value = NULL;
+    static char *_keywords[] = {"file", "mode", "buffering", "encoding", "errors", "newline", "closefd", "opener", NULL};
+    PyObject *file;
+    const char *mode = "r";
+    int buffering = -1;
+    const char *encoding = NULL;
+    const char *errors = NULL;
+    const char *newline = NULL;
+    int closefd = 1;
+    PyObject *opener = Py_None;
 
-    int creating = 0, reading = 0, writing = 0, appending = 0, updating = 0;
-    int text = 0, binary = 0, universal = 0;
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "O|sizzziO:open", _keywords,
+        &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener))
+        goto exit;
+    return_value = _io_open_impl(module, file, mode, buffering, encoding, errors, newline, closefd, opener);
 
-    char rawmode[6], *m;
-    int line_buffering, isatty;
-
-    PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL;
-
-    _Py_IDENTIFIER(_blksize);
-    _Py_IDENTIFIER(isatty);
-    _Py_IDENTIFIER(mode);
-    _Py_IDENTIFIER(close);
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzziO:open", kwlist,
-                                     &file, &mode, &buffering,
-                                     &encoding, &errors, &newline,
-                                     &closefd, &opener)) {
-        return NULL;
-    }
-
-    if (!PyUnicode_Check(file) &&
-	!PyBytes_Check(file) &&
-	!PyNumber_Check(file)) {
-        PyErr_Format(PyExc_TypeError, "invalid file: %R", file);
-        return NULL;
-    }
-
-    /* Decode mode */
-    for (i = 0; i < strlen(mode); i++) {
-        char c = mode[i];
-
-        switch (c) {
-        case 'x':
-            creating = 1;
-            break;
-        case 'r':
-            reading = 1;
-            break;
-        case 'w':
-            writing = 1;
-            break;
-        case 'a':
-            appending = 1;
-            break;
-        case '+':
-            updating = 1;
-            break;
-        case 't':
-            text = 1;
-            break;
-        case 'b':
-            binary = 1;
-            break;
-        case 'U':
-            universal = 1;
-            reading = 1;
-            break;
-        default:
-            goto invalid_mode;
-        }
-
-        /* c must not be duplicated */
-        if (strchr(mode+i+1, c)) {
-          invalid_mode:
-            PyErr_Format(PyExc_ValueError, "invalid mode: '%s'", mode);
-            return NULL;
-        }
-
-    }
-
-    m = rawmode;
-    if (creating)  *(m++) = 'x';
-    if (reading)   *(m++) = 'r';
-    if (writing)   *(m++) = 'w';
-    if (appending) *(m++) = 'a';
-    if (updating)  *(m++) = '+';
-    *m = '\0';
-
-    /* Parameters validation */
-    if (universal) {
-        if (writing || appending) {
-            PyErr_SetString(PyExc_ValueError,
-                            "can't use U and writing mode at once");
-            return NULL;
-        }
-        if (PyErr_WarnEx(PyExc_DeprecationWarning,
-                         "'U' mode is deprecated", 1) < 0)
-            return NULL;
-        reading = 1;
-    }
-
-    if (text && binary) {
-        PyErr_SetString(PyExc_ValueError,
-                        "can't have text and binary mode at once");
-        return NULL;
-    }
-
-    if (creating + reading + writing + appending > 1) {
-        PyErr_SetString(PyExc_ValueError,
-                        "must have exactly one of create/read/write/append mode");
-        return NULL;
-    }
-
-    if (binary && encoding != NULL) {
-        PyErr_SetString(PyExc_ValueError,
-                        "binary mode doesn't take an encoding argument");
-        return NULL;
-    }
-
-    if (binary && errors != NULL) {
-        PyErr_SetString(PyExc_ValueError,
-                        "binary mode doesn't take an errors argument");
-        return NULL;
-    }
-
-    if (binary && newline != NULL) {
-        PyErr_SetString(PyExc_ValueError,
-                        "binary mode doesn't take a newline argument");
-        return NULL;
-    }
-
-    /* Create the Raw file stream */
-    raw = PyObject_CallFunction((PyObject *)&PyFileIO_Type,
-                                "OsiO", file, rawmode, closefd, opener);
-    if (raw == NULL)
-        return NULL;
-    result = raw;
-
-    modeobj = PyUnicode_FromString(mode);
-    if (modeobj == NULL)
-        goto error;
-
-    /* buffering */
-    {
-        PyObject *res = _PyObject_CallMethodId(raw, &PyId_isatty, NULL);
-        if (res == NULL)
-            goto error;
-        isatty = PyLong_AsLong(res);
-        Py_DECREF(res);
-        if (isatty == -1 && PyErr_Occurred())
-            goto error;
-    }
-
-    if (buffering == 1 || (buffering < 0 && isatty)) {
-        buffering = -1;
-        line_buffering = 1;
-    }
-    else
-        line_buffering = 0;
-
-    if (buffering < 0) {
-        PyObject *blksize_obj;
-        blksize_obj = _PyObject_GetAttrId(raw, &PyId__blksize);
-        if (blksize_obj == NULL)
-            goto error;
-        buffering = PyLong_AsLong(blksize_obj);
-        Py_DECREF(blksize_obj);
-        if (buffering == -1 && PyErr_Occurred())
-            goto error;
-    }
-    if (buffering < 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "invalid buffering size");
-        goto error;
-    }
-
-    /* if not buffering, returns the raw file object */
-    if (buffering == 0) {
-        if (!binary) {
-            PyErr_SetString(PyExc_ValueError,
-                            "can't have unbuffered text I/O");
-            goto error;
-        }
-
-        Py_DECREF(modeobj);
-        return result;
-    }
-
-    /* wraps into a buffered file */
-    {
-        PyObject *Buffered_class;
-
-        if (updating)
-            Buffered_class = (PyObject *)&PyBufferedRandom_Type;
-        else if (creating || writing || appending)
-            Buffered_class = (PyObject *)&PyBufferedWriter_Type;
-        else if (reading)
-            Buffered_class = (PyObject *)&PyBufferedReader_Type;
-        else {
-            PyErr_Format(PyExc_ValueError,
-                         "unknown mode: '%s'", mode);
-            goto error;
-        }
-
-        buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
-    }
-    if (buffer == NULL)
-        goto error;
-    result = buffer;
-    Py_DECREF(raw);
-
-
-    /* if binary, returns the buffered file */
-    if (binary) {
-        Py_DECREF(modeobj);
-        return result;
-    }
-
-    /* wraps into a TextIOWrapper */
-    wrapper = PyObject_CallFunction((PyObject *)&PyTextIOWrapper_Type,
-				    "Osssi",
-				    buffer,
-				    encoding, errors, newline,
-				    line_buffering);
-    if (wrapper == NULL)
-        goto error;
-    result = wrapper;
-    Py_DECREF(buffer);
-
-    if (_PyObject_SetAttrId(wrapper, &PyId_mode, modeobj) < 0)
-        goto error;
-    Py_DECREF(modeobj);
-    return result;
-
-  error:
-    if (result != NULL) {
-        PyObject *exc, *val, *tb, *close_result;
-        PyErr_Fetch(&exc, &val, &tb);
-        close_result = _PyObject_CallMethodId(result, &PyId_close, NULL);
-        _PyErr_ChainExceptions(exc, val, tb);
-        Py_XDECREF(close_result);
-        Py_DECREF(result);
-    }
-    Py_XDECREF(modeobj);
-    return NULL;
+exit:
+    return return_value;
 }
-

-/*
- * Private helpers for the io module.
- */
-
-Py_off_t
-PyNumber_AsOff_t(PyObject *item, PyObject *err)
-{
-    Py_off_t result;
-    PyObject *runerr;
-    PyObject *value = PyNumber_Index(item);
-    if (value == NULL)
-        return -1;
-
-    /* We're done if PyLong_AsSsize_t() returns without error. */
-    result = PyLong_AsOff_t(value);
-    if (result != -1 || !(runerr = PyErr_Occurred()))
-        goto finish;
-
-    /* Error handling code -- only manage OverflowError differently */
-    if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError))
-        goto finish;
-
-    PyErr_Clear();
-    /* If no error-handling desired then the default clipping
-       is sufficient.
-     */
-    if (!err) {
-        assert(PyLong_Check(value));
-        /* Whether or not it is less than or equal to
-           zero is determined by the sign of ob_size
-        */
-        if (_PyLong_Sign(value) < 0)
-            result = PY_OFF_T_MIN;
-        else
-            result = PY_OFF_T_MAX;
-    }
-    else {
-        /* Otherwise replace the error with caller's error object. */
-        PyErr_Format(err,
-                     "cannot fit '%.200s' into an offset-sized integer",
-                     item->ob_type->tp_name);
-    }
-
- finish:
-    Py_DECREF(value);
-    return result;
-}
-
-
-/* Basically the "n" format code with the ability to turn None into -1. */
-int
-_PyIO_ConvertSsize_t(PyObject *obj, void *result) {
-    Py_ssize_t limit;
-    if (obj == Py_None) {
-        limit = -1;
-    }
-    else if (PyNumber_Check(obj)) {
-        limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError);
-        if (limit == -1 && PyErr_Occurred())
-            return 0;
-    }
-    else {
-        PyErr_Format(PyExc_TypeError,
-                     "integer argument expected, got '%.200s'",
-                     Py_TYPE(obj)->tp_name);
-        return 0;
-    }
-    *((Py_ssize_t *)result) = limit;
-    return 1;
-}
-
-
-_PyIO_State *
-_PyIO_get_module_state(void)
-{
-    PyObject *mod = PyState_FindModule(&_PyIO_Module);
-    _PyIO_State *state;
-    if (mod == NULL || (state = IO_MOD_STATE(mod)) == NULL) {
-        PyErr_SetString(PyExc_RuntimeError,
-                        "could not find io module state "
-                        "(interpreter shutdown?)");
-        return NULL;
-    }
-    return state;
-}
-
-PyObject *
-_PyIO_get_locale_module(_PyIO_State *state)
-{
-    PyObject *mod;
-    if (state->locale_module != NULL) {
-        assert(PyWeakref_CheckRef(state->locale_module));
-        mod = PyWeakref_GET_OBJECT(state->locale_module);
-        if (mod != Py_None) {
-            Py_INCREF(mod);
-            return mod;
-        }
-        Py_CLEAR(state->locale_module);
-    }
-    mod = PyImport_ImportModule("_bootlocale");
-    if (mod == NULL)
-        return NULL;
-    state->locale_module = PyWeakref_NewRef(mod, NULL);
-    if (state->locale_module == NULL) {
-        Py_DECREF(mod);
-        return NULL;
-    }
-    return mod;
-}
-
-
-static int
-iomodule_traverse(PyObject *mod, visitproc visit, void *arg) {
-    _PyIO_State *state = IO_MOD_STATE(mod);
-    if (!state->initialized)
-        return 0;
-    if (state->locale_module != NULL) {
-        Py_VISIT(state->locale_module);
-    }
-    Py_VISIT(state->unsupported_operation);
-    return 0;
-}
-
-
-static int
-iomodule_clear(PyObject *mod) {
-    _PyIO_State *state = IO_MOD_STATE(mod);
-    if (!state->initialized)
-        return 0;
-    if (state->locale_module != NULL)
-        Py_CLEAR(state->locale_module);
-    Py_CLEAR(state->unsupported_operation);
-    return 0;
-}
-
-static void
-iomodule_free(PyObject *mod) {
-    iomodule_clear(mod);
-}
-
-
-/*
- * Module definition
- */
-
-static PyMethodDef module_methods[] = {
-    {"open", (PyCFunction)io_open, METH_VARARGS|METH_KEYWORDS, open_doc},
-    {NULL, NULL}
-};
-
-struct PyModuleDef _PyIO_Module = {
-    PyModuleDef_HEAD_INIT,
-    "io",
-    module_doc,
-    sizeof(_PyIO_State),
-    module_methods,
-    NULL,
-    iomodule_traverse,
-    iomodule_clear,
-    (freefunc)iomodule_free,
-};
-
-PyMODINIT_FUNC
-PyInit__io(void)
-{
-    PyObject *m = PyModule_Create(&_PyIO_Module);
-    _PyIO_State *state = NULL;
-    if (m == NULL)
-        return NULL;
-    state = IO_MOD_STATE(m);
-    state->initialized = 0;
-
-#define ADD_TYPE(type, name) \
-    if (PyType_Ready(type) < 0) \
-        goto fail; \
-    Py_INCREF(type); \
-    if (PyModule_AddObject(m, name, (PyObject *)type) < 0) {  \
-        Py_DECREF(type); \
-        goto fail; \
-    }
-
-    /* DEFAULT_BUFFER_SIZE */
-    if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
-        goto fail;
-
-    /* UnsupportedOperation inherits from ValueError and IOError */
-    state->unsupported_operation = PyObject_CallFunction(
-        (PyObject *)&PyType_Type, "s(OO){}",
-        "UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
-    if (state->unsupported_operation == NULL)
-        goto fail;
-    Py_INCREF(state->unsupported_operation);
-    if (PyModule_AddObject(m, "UnsupportedOperation",
-                           state->unsupported_operation) < 0)
-        goto fail;
-
-    /* BlockingIOError, for compatibility */
-    Py_INCREF(PyExc_BlockingIOError);
-    if (PyModule_AddObject(m, "BlockingIOError",
-                           (PyObject *) PyExc_BlockingIOError) < 0)
-        goto fail;
-
-    /* Concrete base types of the IO ABCs.
-       (the ABCs themselves are declared through inheritance in io.py)
-    */
-    ADD_TYPE(&PyIOBase_Type, "_IOBase");
-    ADD_TYPE(&PyRawIOBase_Type, "_RawIOBase");
-    ADD_TYPE(&PyBufferedIOBase_Type, "_BufferedIOBase");
-    ADD_TYPE(&PyTextIOBase_Type, "_TextIOBase");
-
-    /* Implementation of concrete IO objects. */
-    /* FileIO */
-    PyFileIO_Type.tp_base = &PyRawIOBase_Type;
-    ADD_TYPE(&PyFileIO_Type, "FileIO");
-
-    /* BytesIO */
-    PyBytesIO_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBytesIO_Type, "BytesIO");
-    if (PyType_Ready(&_PyBytesIOBuffer_Type) < 0)
-        goto fail;
-
-    /* StringIO */
-    PyStringIO_Type.tp_base = &PyTextIOBase_Type;
-    ADD_TYPE(&PyStringIO_Type, "StringIO");
-
-    /* BufferedReader */
-    PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBufferedReader_Type, "BufferedReader");
-
-    /* BufferedWriter */
-    PyBufferedWriter_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBufferedWriter_Type, "BufferedWriter");
-
-    /* BufferedRWPair */
-    PyBufferedRWPair_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBufferedRWPair_Type, "BufferedRWPair");
-
-    /* BufferedRandom */
-    PyBufferedRandom_Type.tp_base = &PyBufferedIOBase_Type;
-    ADD_TYPE(&PyBufferedRandom_Type, "BufferedRandom");
-
-    /* TextIOWrapper */
-    PyTextIOWrapper_Type.tp_base = &PyTextIOBase_Type;
-    ADD_TYPE(&PyTextIOWrapper_Type, "TextIOWrapper");
-
-    /* IncrementalNewlineDecoder */
-    ADD_TYPE(&PyIncrementalNewlineDecoder_Type, "IncrementalNewlineDecoder");
-
-    /* Interned strings */
-#define ADD_INTERNED(name) \
-    if (!_PyIO_str_ ## name && \
-        !(_PyIO_str_ ## name = PyUnicode_InternFromString(# name))) \
-        goto fail;
-
-    ADD_INTERNED(close)
-    ADD_INTERNED(closed)
-    ADD_INTERNED(decode)
-    ADD_INTERNED(encode)
-    ADD_INTERNED(fileno)
-    ADD_INTERNED(flush)
-    ADD_INTERNED(getstate)
-    ADD_INTERNED(isatty)
-    ADD_INTERNED(newlines)
-    ADD_INTERNED(read)
-    ADD_INTERNED(read1)
-    ADD_INTERNED(readable)
-    ADD_INTERNED(readall)
-    ADD_INTERNED(readinto)
-    ADD_INTERNED(readline)
-    ADD_INTERNED(reset)
-    ADD_INTERNED(seek)
-    ADD_INTERNED(seekable)
-    ADD_INTERNED(setstate)
-    ADD_INTERNED(tell)
-    ADD_INTERNED(truncate)
-    ADD_INTERNED(write)
-    ADD_INTERNED(writable)
-
-    if (!_PyIO_str_nl &&
-        !(_PyIO_str_nl = PyUnicode_InternFromString("\n")))
-        goto fail;
-
-    if (!_PyIO_empty_str &&
-        !(_PyIO_empty_str = PyUnicode_FromStringAndSize(NULL, 0)))
-        goto fail;
-    if (!_PyIO_empty_bytes &&
-        !(_PyIO_empty_bytes = PyBytes_FromStringAndSize(NULL, 0)))
-        goto fail;
-    if (!_PyIO_zero &&
-        !(_PyIO_zero = PyLong_FromLong(0L)))
-        goto fail;
-
-    state->initialized = 1;
-
-    return m;
-
-  fail:
-    Py_XDECREF(state->unsupported_operation);
-    Py_DECREF(m);
-    return NULL;
-}
+/*[clinic end generated code: output=c51a5a443c11f02b input=a9049054013a1b77]*/
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/clinic/bufferedio.c.h
copy from Modules/_io/bufferedio.c
copy to Modules/_io/clinic/bufferedio.c.h
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/clinic/bufferedio.c.h
@@ -1,2702 +1,474 @@
-/*
-    An implementation of Buffered I/O as defined by PEP 3116 - "New I/O"
+/*[clinic input]
+preserve
+[clinic start generated code]*/
 
-    Classes defined here: BufferedIOBase, BufferedReader, BufferedWriter,
-    BufferedRandom.
+PyDoc_STRVAR(_io__BufferedIOBase_readinto__doc__,
+"readinto($self, buffer, /)\n"
+"--\n"
+"\n");
 
-    Written by Amaury Forgeot d'Arc and Antoine Pitrou
-*/
-
-#define PY_SSIZE_T_CLEAN
-#include "Python.h"
-#include "structmember.h"
-#include "pythread.h"
-#include "_iomodule.h"
-
-_Py_IDENTIFIER(close);
-_Py_IDENTIFIER(_dealloc_warn);
-_Py_IDENTIFIER(flush);
-_Py_IDENTIFIER(isatty);
-_Py_IDENTIFIER(mode);
-_Py_IDENTIFIER(name);
-_Py_IDENTIFIER(peek);
-_Py_IDENTIFIER(read);
-_Py_IDENTIFIER(read1);
-_Py_IDENTIFIER(readable);
-_Py_IDENTIFIER(readinto);
-_Py_IDENTIFIER(readinto1);
-_Py_IDENTIFIER(writable);
-_Py_IDENTIFIER(write);
-
-/*
- * BufferedIOBase class, inherits from IOBase.
- */
-PyDoc_STRVAR(bufferediobase_doc,
-    "Base class for buffered IO objects.\n"
-    "\n"
-    "The main difference with RawIOBase is that the read() method\n"
-    "supports omitting the size argument, and does not have a default\n"
-    "implementation that defers to readinto().\n"
-    "\n"
-    "In addition, read(), readinto() and write() may raise\n"
-    "BlockingIOError if the underlying raw stream is in non-blocking\n"
-    "mode and not ready; unlike their raw counterparts, they will never\n"
-    "return None.\n"
-    "\n"
-    "A typical implementation should not inherit from a RawIOBase\n"
-    "implementation, but wrap one.\n"
-    );
+#define _IO__BUFFEREDIOBASE_READINTO_METHODDEF    \
+    {"readinto", (PyCFunction)_io__BufferedIOBase_readinto, METH_O, _io__BufferedIOBase_readinto__doc__},
 
 static PyObject *
-_bufferediobase_readinto_generic(PyObject *self, PyObject *args, char readinto1)
+_io__BufferedIOBase_readinto_impl(PyObject *self, Py_buffer *buffer);
+
+static PyObject *
+_io__BufferedIOBase_readinto(PyObject *self, PyObject *arg)
 {
-    Py_buffer buf;
-    Py_ssize_t len;
-    PyObject *data;
+    PyObject *return_value = NULL;
+    Py_buffer buffer = {NULL, NULL};
+
+    if (!PyArg_Parse(arg,
+        "w*:readinto",
+        &buffer))
+        goto exit;
+    return_value = _io__BufferedIOBase_readinto_impl(self, &buffer);
+
+exit:
+    /* Cleanup for buffer */
+    if (buffer.obj)
+       PyBuffer_Release(&buffer);
+
+    return return_value;
+}
+
+PyDoc_STRVAR(_io__BufferedIOBase_readinto1__doc__,
+"readinto1($self, buffer, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFEREDIOBASE_READINTO1_METHODDEF    \
+    {"readinto1", (PyCFunction)_io__BufferedIOBase_readinto1, METH_O, _io__BufferedIOBase_readinto1__doc__},
+
+static PyObject *
+_io__BufferedIOBase_readinto1_impl(PyObject *self, Py_buffer *buffer);
+
+static PyObject *
+_io__BufferedIOBase_readinto1(PyObject *self, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    Py_buffer buffer = {NULL, NULL};
+
+    if (!PyArg_Parse(arg,
+        "w*:readinto1",
+        &buffer))
+        goto exit;
+    return_value = _io__BufferedIOBase_readinto1_impl(self, &buffer);
+
+exit:
+    /* Cleanup for buffer */
+    if (buffer.obj)
+       PyBuffer_Release(&buffer);
+
+    return return_value;
+}
+
+PyDoc_STRVAR(_io__BufferedIOBase_detach__doc__,
+"detach($self, /)\n"
+"--\n"
+"\n"
+"Disconnect this buffer from its underlying raw stream and return it.\n"
+"\n"
+"After the raw stream has been detached, the buffer is in an unusable\n"
+"state.");
+
+#define _IO__BUFFEREDIOBASE_DETACH_METHODDEF    \
+    {"detach", (PyCFunction)_io__BufferedIOBase_detach, METH_NOARGS, _io__BufferedIOBase_detach__doc__},
+
+static PyObject *
+_io__BufferedIOBase_detach_impl(PyObject *self);
+
+static PyObject *
+_io__BufferedIOBase_detach(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    return _io__BufferedIOBase_detach_impl(self);
+}
+
+PyDoc_STRVAR(_io__Buffered_peek__doc__,
+"peek($self, size=0, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFERED_PEEK_METHODDEF    \
+    {"peek", (PyCFunction)_io__Buffered_peek, METH_VARARGS, _io__Buffered_peek__doc__},
+
+static PyObject *
+_io__Buffered_peek_impl(buffered *self, Py_ssize_t size);
+
+static PyObject *
+_io__Buffered_peek(buffered *self, PyObject *args)
+{
+    PyObject *return_value = NULL;
+    Py_ssize_t size = 0;
 
     if (!PyArg_ParseTuple(args,
-                          readinto1 ? "w*:readinto1" : "w*:readinto",
-                          &buf)) {
-        return NULL;
-    }
+        "|n:peek",
+        &size))
+        goto exit;
+    return_value = _io__Buffered_peek_impl(self, size);
 
-    data = _PyObject_CallMethodId(self,
-                                  readinto1 ? &PyId_read1 : &PyId_read,
-                                  "n", buf.len);
-    if (data == NULL)
-        goto error;
-
-    if (!PyBytes_Check(data)) {
-        Py_DECREF(data);
-        PyErr_SetString(PyExc_TypeError, "read() should return bytes");
-        goto error;
-    }
-
-    len = Py_SIZE(data);
-    if (len > buf.len) {
-        PyErr_Format(PyExc_ValueError,
-                     "read() returned too much data: "
-                     "%zd bytes requested, %zd returned",
-                     buf.len, len);
-        Py_DECREF(data);
-        goto error;
-    }
-    memcpy(buf.buf, PyBytes_AS_STRING(data), len);
-
-    PyBuffer_Release(&buf);
-    Py_DECREF(data);
-
-    return PyLong_FromSsize_t(len);
-
-  error:
-    PyBuffer_Release(&buf);
-    return NULL;
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io__Buffered_read__doc__,
+"read($self, size=-1, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFERED_READ_METHODDEF    \
+    {"read", (PyCFunction)_io__Buffered_read, METH_VARARGS, _io__Buffered_read__doc__},
+
 static PyObject *
-bufferediobase_readinto(PyObject *self, PyObject *args)
+_io__Buffered_read_impl(buffered *self, Py_ssize_t n);
+
+static PyObject *
+_io__Buffered_read(buffered *self, PyObject *args)
 {
-    return _bufferediobase_readinto_generic(self, args, 0);
+    PyObject *return_value = NULL;
+    Py_ssize_t n = -1;
+
+    if (!PyArg_ParseTuple(args,
+        "|O&:read",
+        _PyIO_ConvertSsize_t, &n))
+        goto exit;
+    return_value = _io__Buffered_read_impl(self, n);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io__Buffered_read1__doc__,
+"read1($self, size, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFERED_READ1_METHODDEF    \
+    {"read1", (PyCFunction)_io__Buffered_read1, METH_O, _io__Buffered_read1__doc__},
+
 static PyObject *
-bufferediobase_readinto1(PyObject *self, PyObject *args)
+_io__Buffered_read1_impl(buffered *self, Py_ssize_t n);
+
+static PyObject *
+_io__Buffered_read1(buffered *self, PyObject *arg)
 {
-    return _bufferediobase_readinto_generic(self, args, 1);
+    PyObject *return_value = NULL;
+    Py_ssize_t n;
+
+    if (!PyArg_Parse(arg,
+        "n:read1",
+        &n))
+        goto exit;
+    return_value = _io__Buffered_read1_impl(self, n);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io__Buffered_readinto__doc__,
+"readinto($self, buffer, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFERED_READINTO_METHODDEF    \
+    {"readinto", (PyCFunction)_io__Buffered_readinto, METH_O, _io__Buffered_readinto__doc__},
+
 static PyObject *
-bufferediobase_unsupported(const char *message)
+_io__Buffered_readinto_impl(buffered *self, Py_buffer *buffer);
+
+static PyObject *
+_io__Buffered_readinto(buffered *self, PyObject *arg)
 {
-    _PyIO_State *state = IO_STATE();
-    if (state != NULL)
-        PyErr_SetString(state->unsupported_operation, message);
-    return NULL;
+    PyObject *return_value = NULL;
+    Py_buffer buffer = {NULL, NULL};
+
+    if (!PyArg_Parse(arg,
+        "w*:readinto",
+        &buffer))
+        goto exit;
+    return_value = _io__Buffered_readinto_impl(self, &buffer);
+
+exit:
+    /* Cleanup for buffer */
+    if (buffer.obj)
+       PyBuffer_Release(&buffer);
+
+    return return_value;
 }
 
-PyDoc_STRVAR(bufferediobase_detach_doc,
-    "Disconnect this buffer from its underlying raw stream and return it.\n"
-    "\n"
-    "After the raw stream has been detached, the buffer is in an unusable\n"
-    "state.\n");
+PyDoc_STRVAR(_io__Buffered_readinto1__doc__,
+"readinto1($self, buffer, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFERED_READINTO1_METHODDEF    \
+    {"readinto1", (PyCFunction)_io__Buffered_readinto1, METH_O, _io__Buffered_readinto1__doc__},
 
 static PyObject *
-bufferediobase_detach(PyObject *self)
+_io__Buffered_readinto1_impl(buffered *self, Py_buffer *buffer);
+
+static PyObject *
+_io__Buffered_readinto1(buffered *self, PyObject *arg)
 {
-    return bufferediobase_unsupported("detach");
+    PyObject *return_value = NULL;
+    Py_buffer buffer = {NULL, NULL};
+
+    if (!PyArg_Parse(arg,
+        "w*:readinto1",
+        &buffer))
+        goto exit;
+    return_value = _io__Buffered_readinto1_impl(self, &buffer);
+
+exit:
+    /* Cleanup for buffer */
+    if (buffer.obj)
+       PyBuffer_Release(&buffer);
+
+    return return_value;
 }
 
-PyDoc_STRVAR(bufferediobase_read_doc,
-    "Read and return up to n bytes.\n"
-    "\n"
-    "If the argument is omitted, None, or negative, reads and\n"
-    "returns all data until EOF.\n"
-    "\n"
-    "If the argument is positive, and the underlying raw stream is\n"
-    "not 'interactive', multiple raw reads may be issued to satisfy\n"
-    "the byte count (unless EOF is reached first).  But for\n"
-    "interactive raw streams (as well as sockets and pipes), at most\n"
-    "one raw read will be issued, and a short result does not imply\n"
-    "that EOF is imminent.\n"
-    "\n"
-    "Returns an empty bytes object on EOF.\n"
-    "\n"
-    "Returns None if the underlying raw stream was open in non-blocking\n"
-    "mode and no data is available at the moment.\n");
+PyDoc_STRVAR(_io__Buffered_readline__doc__,
+"readline($self, size=-1, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFERED_READLINE_METHODDEF    \
+    {"readline", (PyCFunction)_io__Buffered_readline, METH_VARARGS, _io__Buffered_readline__doc__},
 
 static PyObject *
-bufferediobase_read(PyObject *self, PyObject *args)
+_io__Buffered_readline_impl(buffered *self, Py_ssize_t size);
+
+static PyObject *
+_io__Buffered_readline(buffered *self, PyObject *args)
 {
-    return bufferediobase_unsupported("read");
+    PyObject *return_value = NULL;
+    Py_ssize_t size = -1;
+
+    if (!PyArg_ParseTuple(args,
+        "|O&:readline",
+        _PyIO_ConvertSsize_t, &size))
+        goto exit;
+    return_value = _io__Buffered_readline_impl(self, size);
+
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(bufferediobase_read1_doc,
-    "Read and return up to n bytes, with at most one read() call\n"
-    "to the underlying raw stream. A short result does not imply\n"
-    "that EOF is imminent.\n"
-    "\n"
-    "Returns an empty bytes object on EOF.\n");
+PyDoc_STRVAR(_io__Buffered_seek__doc__,
+"seek($self, target, whence=0, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFERED_SEEK_METHODDEF    \
+    {"seek", (PyCFunction)_io__Buffered_seek, METH_VARARGS, _io__Buffered_seek__doc__},
 
 static PyObject *
-bufferediobase_read1(PyObject *self, PyObject *args)
+_io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence);
+
+static PyObject *
+_io__Buffered_seek(buffered *self, PyObject *args)
 {
-    return bufferediobase_unsupported("read1");
+    PyObject *return_value = NULL;
+    PyObject *targetobj;
+    int whence = 0;
+
+    if (!PyArg_ParseTuple(args,
+        "O|i:seek",
+        &targetobj, &whence))
+        goto exit;
+    return_value = _io__Buffered_seek_impl(self, targetobj, whence);
+
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(bufferediobase_write_doc,
-    "Write the given buffer to the IO stream.\n"
-    "\n"
-    "Returns the number of bytes written, which is never less than\n"
-    "len(b).\n"
-    "\n"
-    "Raises BlockingIOError if the buffer is full and the\n"
-    "underlying raw stream cannot accept more data at the moment.\n");
+PyDoc_STRVAR(_io__Buffered_truncate__doc__,
+"truncate($self, pos=None, /)\n"
+"--\n"
+"\n");
+
+#define _IO__BUFFERED_TRUNCATE_METHODDEF    \
+    {"truncate", (PyCFunction)_io__Buffered_truncate, METH_VARARGS, _io__Buffered_truncate__doc__},
 
 static PyObject *
-bufferediobase_write(PyObject *self, PyObject *args)
+_io__Buffered_truncate_impl(buffered *self, PyObject *pos);
+
+static PyObject *
+_io__Buffered_truncate(buffered *self, PyObject *args)
 {
-    return bufferediobase_unsupported("write");
+    PyObject *return_value = NULL;
+    PyObject *pos = Py_None;
+
+    if (!PyArg_UnpackTuple(args, "truncate",
+        0, 1,
+        &pos))
+        goto exit;
+    return_value = _io__Buffered_truncate_impl(self, pos);
+
+exit:
+    return return_value;
 }
 
-
-static PyMethodDef bufferediobase_methods[] = {
-    {"detach", (PyCFunction)bufferediobase_detach, METH_NOARGS, bufferediobase_detach_doc},
-    {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc},
-    {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc},
-    {"readinto", bufferediobase_readinto, METH_VARARGS, NULL},
-    {"readinto1", bufferediobase_readinto1, METH_VARARGS, NULL},
-    {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc},
-    {NULL, NULL}
-};
-
-PyTypeObject PyBufferedIOBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io._BufferedIOBase",      /*tp_name*/
-    0,                          /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    0,                          /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_FINALIZE,  /*tp_flags*/
-    bufferediobase_doc,         /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    bufferediobase_methods,     /* tp_methods */
-    0,                          /* tp_members */
-    0,                          /* tp_getset */
-    &PyIOBase_Type,             /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    0,                          /* tp_dictoffset */
-    0,                          /* tp_init */
-    0,                          /* tp_alloc */
-    0,                          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
-
-
-typedef struct {
-    PyObject_HEAD
-
-    PyObject *raw;
-    int ok;    /* Initialized? */
-    int detached;
-    int readable;
-    int writable;
-    char finalizing;
-
-    /* True if this is a vanilla Buffered object (rather than a user derived
-       class) *and* the raw stream is a vanilla FileIO object. */
-    int fast_closed_checks;
-
-    /* Absolute position inside the raw stream (-1 if unknown). */
-    Py_off_t abs_pos;
-
-    /* A static buffer of size `buffer_size` */
-    char *buffer;
-    /* Current logical position in the buffer. */
-    Py_off_t pos;
-    /* Position of the raw stream in the buffer. */
-    Py_off_t raw_pos;
-
-    /* Just after the last buffered byte in the buffer, or -1 if the buffer
-       isn't ready for reading. */
-    Py_off_t read_end;
-
-    /* Just after the last byte actually written */
-    Py_off_t write_pos;
-    /* Just after the last byte waiting to be written, or -1 if the buffer
-       isn't ready for writing. */
-    Py_off_t write_end;
-
-#ifdef WITH_THREAD
-    PyThread_type_lock lock;
-    volatile long owner;
-#endif
-
-    Py_ssize_t buffer_size;
-    Py_ssize_t buffer_mask;
-
-    PyObject *dict;
-    PyObject *weakreflist;
-} buffered;
-
-/*
-    Implementation notes:
-
-    * BufferedReader, BufferedWriter and BufferedRandom try to share most
-      methods (this is helped by the members `readable` and `writable`, which
-      are initialized in the respective constructors)
-    * They also share a single buffer for reading and writing. This enables
-      interleaved reads and writes without flushing. It also makes the logic
-      a bit trickier to get right.
-    * The absolute position of the raw stream is cached, if possible, in the
-      `abs_pos` member. It must be updated every time an operation is done
-      on the raw stream. If not sure, it can be reinitialized by calling
-      _buffered_raw_tell(), which queries the raw stream (_buffered_raw_seek()
-      also does it). To read it, use RAW_TELL().
-    * Three helpers, _bufferedreader_raw_read, _bufferedwriter_raw_write and
-      _bufferedwriter_flush_unlocked do a lot of useful housekeeping.
-
-    NOTE: we should try to maintain block alignment of reads and writes to the
-    raw stream (according to the buffer size), but for now it is only done
-    in read() and friends.
-
-*/
-
-/* These macros protect the buffered object against concurrent operations. */
-
-#ifdef WITH_THREAD
+PyDoc_STRVAR(_io_BufferedReader___init____doc__,
+"BufferedReader(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n"
+"--\n"
+"\n"
+"Create a new buffered reader using the given readable raw IO object.");
 
 static int
-_enter_buffered_busy(buffered *self)
+_io_BufferedReader___init___impl(buffered *self, PyObject *raw,
+                                 Py_ssize_t buffer_size);
+
+static int
+_io_BufferedReader___init__(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-    int relax_locking;
-    PyLockStatus st;
-    if (self->owner == PyThread_get_thread_ident()) {
-        PyErr_Format(PyExc_RuntimeError,
-                     "reentrant call inside %R", self);
-        return 0;
-    }
-    relax_locking = (_Py_Finalizing != NULL);
-    Py_BEGIN_ALLOW_THREADS
-    if (!relax_locking)
-        st = PyThread_acquire_lock(self->lock, 1);
-    else {
-        /* When finalizing, we don't want a deadlock to happen with daemon
-         * threads abruptly shut down while they owned the lock.
-         * Therefore, only wait for a grace period (1 s.).
-         * Note that non-daemon threads have already exited here, so this
-         * shouldn't affect carefully written threaded I/O code.
-         */
-        st = PyThread_acquire_lock_timed(self->lock, 1e6, 0);
-    }
-    Py_END_ALLOW_THREADS
-    if (relax_locking && st != PY_LOCK_ACQUIRED) {
-        PyObject *msgobj = PyUnicode_FromFormat(
-            "could not acquire lock for %A at interpreter "
-            "shutdown, possibly due to daemon threads",
-            (PyObject *) self);
-        char *msg = PyUnicode_AsUTF8(msgobj);
-        Py_FatalError(msg);
-    }
-    return 1;
+    int return_value = -1;
+    static char *_keywords[] = {"raw", "buffer_size", NULL};
+    PyObject *raw;
+    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "O|n:BufferedReader", _keywords,
+        &raw, &buffer_size))
+        goto exit;
+    return_value = _io_BufferedReader___init___impl((buffered *)self, raw, buffer_size);
+
+exit:
+    return return_value;
 }
 
-#define ENTER_BUFFERED(self) \
-    ( (PyThread_acquire_lock(self->lock, 0) ? \
-       1 : _enter_buffered_busy(self)) \
-     && (self->owner = PyThread_get_thread_ident(), 1) )
+PyDoc_STRVAR(_io_BufferedWriter___init____doc__,
+"BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n"
+"--\n"
+"\n"
+"A buffer for a writeable sequential RawIO object.\n"
+"\n"
+"The constructor creates a BufferedWriter for the given writeable raw\n"
+"stream. If the buffer_size is not given, it defaults to\n"
+"DEFAULT_BUFFER_SIZE.");
 
-#define LEAVE_BUFFERED(self) \
-    do { \
-        self->owner = 0; \
-        PyThread_release_lock(self->lock); \
-    } while(0);
+static int
+_io_BufferedWriter___init___impl(buffered *self, PyObject *raw,
+                                 Py_ssize_t buffer_size);
 
-#else
-#define ENTER_BUFFERED(self) 1
-#define LEAVE_BUFFERED(self)
-#endif
+static int
+_io_BufferedWriter___init__(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    int return_value = -1;
+    static char *_keywords[] = {"raw", "buffer_size", NULL};
+    PyObject *raw;
+    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
 
-#define CHECK_INITIALIZED(self) \
-    if (self->ok <= 0) { \
-        if (self->detached) { \
-            PyErr_SetString(PyExc_ValueError, \
-                 "raw stream has been detached"); \
-        } else { \
-            PyErr_SetString(PyExc_ValueError, \
-                "I/O operation on uninitialized object"); \
-        } \
-        return NULL; \
-    }
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "O|n:BufferedWriter", _keywords,
+        &raw, &buffer_size))
+        goto exit;
+    return_value = _io_BufferedWriter___init___impl((buffered *)self, raw, buffer_size);
 
-#define CHECK_INITIALIZED_INT(self) \
-    if (self->ok <= 0) { \
-        if (self->detached) { \
-            PyErr_SetString(PyExc_ValueError, \
-                 "raw stream has been detached"); \
-        } else { \
-            PyErr_SetString(PyExc_ValueError, \
-                "I/O operation on uninitialized object"); \
-        } \
-        return -1; \
-    }
-
-#define IS_CLOSED(self) \
-    (self->fast_closed_checks \
-     ? _PyFileIO_closed(self->raw) \
-     : buffered_closed(self))
-
-#define CHECK_CLOSED(self, error_msg) \
-    if (IS_CLOSED(self)) { \
-        PyErr_SetString(PyExc_ValueError, error_msg); \
-        return NULL; \
-    }
-
-
-#define VALID_READ_BUFFER(self) \
-    (self->readable && self->read_end != -1)
-
-#define VALID_WRITE_BUFFER(self) \
-    (self->writable && self->write_end != -1)
-
-#define ADJUST_POSITION(self, _new_pos) \
-    do { \
-        self->pos = _new_pos; \
-        if (VALID_READ_BUFFER(self) && self->read_end < self->pos) \
-            self->read_end = self->pos; \
-    } while(0)
-
-#define READAHEAD(self) \
-    ((self->readable && VALID_READ_BUFFER(self)) \
-        ? (self->read_end - self->pos) : 0)
-
-#define RAW_OFFSET(self) \
-    (((VALID_READ_BUFFER(self) || VALID_WRITE_BUFFER(self)) \
-        && self->raw_pos >= 0) ? self->raw_pos - self->pos : 0)
-
-#define RAW_TELL(self) \
-    (self->abs_pos != -1 ? self->abs_pos : _buffered_raw_tell(self))
-
-#define MINUS_LAST_BLOCK(self, size) \
-    (self->buffer_mask ? \
-        (size & ~self->buffer_mask) : \
-        (self->buffer_size * (size / self->buffer_size)))
-
-
-static void
-buffered_dealloc(buffered *self)
-{
-    self->finalizing = 1;
-    if (_PyIOBase_finalize((PyObject *) self) < 0)
-        return;
-    _PyObject_GC_UNTRACK(self);
-    self->ok = 0;
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *)self);
-    Py_CLEAR(self->raw);
-    if (self->buffer) {
-        PyMem_Free(self->buffer);
-        self->buffer = NULL;
-    }
-#ifdef WITH_THREAD
-    if (self->lock) {
-        PyThread_free_lock(self->lock);
-        self->lock = NULL;
-    }
-#endif
-    Py_CLEAR(self->dict);
-    Py_TYPE(self)->tp_free((PyObject *)self);
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_BufferedWriter_write__doc__,
+"write($self, buffer, /)\n"
+"--\n"
+"\n");
+
+#define _IO_BUFFEREDWRITER_WRITE_METHODDEF    \
+    {"write", (PyCFunction)_io_BufferedWriter_write, METH_O, _io_BufferedWriter_write__doc__},
+
 static PyObject *
-buffered_sizeof(buffered *self, void *unused)
+_io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer);
+
+static PyObject *
+_io_BufferedWriter_write(buffered *self, PyObject *arg)
 {
-    Py_ssize_t res;
+    PyObject *return_value = NULL;
+    Py_buffer buffer = {NULL, NULL};
 
-    res = sizeof(buffered);
-    if (self->buffer)
-        res += self->buffer_size;
-    return PyLong_FromSsize_t(res);
+    if (!PyArg_Parse(arg,
+        "y*:write",
+        &buffer))
+        goto exit;
+    return_value = _io_BufferedWriter_write_impl(self, &buffer);
+
+exit:
+    /* Cleanup for buffer */
+    if (buffer.obj)
+       PyBuffer_Release(&buffer);
+
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_BufferedRWPair___init____doc__,
+"BufferedRWPair(reader, writer, buffer_size=DEFAULT_BUFFER_SIZE, /)\n"
+"--\n"
+"\n"
+"A buffered reader and writer object together.\n"
+"\n"
+"A buffered reader object and buffered writer object put together to\n"
+"form a sequential IO object that can read and write. This is typically\n"
+"used with a socket or two-way pipe.\n"
+"\n"
+"reader and writer are RawIOBase objects that are readable and\n"
+"writeable respectively. If the buffer_size is omitted it defaults to\n"
+"DEFAULT_BUFFER_SIZE.");
+
 static int
-buffered_traverse(buffered *self, visitproc visit, void *arg)
+_io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader,
+                                 PyObject *writer, Py_ssize_t buffer_size);
+
+static int
+_io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-    Py_VISIT(self->raw);
-    Py_VISIT(self->dict);
-    return 0;
+    int return_value = -1;
+    PyObject *reader;
+    PyObject *writer;
+    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+
+    if ((Py_TYPE(self) == &PyBufferedRWPair_Type) &&
+        !_PyArg_NoKeywords("BufferedRWPair", kwargs))
+        goto exit;
+    if (!PyArg_ParseTuple(args,
+        "OO|n:BufferedRWPair",
+        &reader, &writer, &buffer_size))
+        goto exit;
+    return_value = _io_BufferedRWPair___init___impl((rwpair *)self, reader, writer, buffer_size);
+
+exit:
+    return return_value;
 }
 
-static int
-buffered_clear(buffered *self)
-{
-    self->ok = 0;
-    Py_CLEAR(self->raw);
-    Py_CLEAR(self->dict);
-    return 0;
-}
-
-/* Because this can call arbitrary code, it shouldn't be called when
-   the refcount is 0 (that is, not directly from tp_dealloc unless
-   the refcount has been temporarily re-incremented). */
-static PyObject *
-buffered_dealloc_warn(buffered *self, PyObject *source)
-{
-    if (self->ok && self->raw) {
-        PyObject *r;
-        r = _PyObject_CallMethodId(self->raw, &PyId__dealloc_warn, "O", source);
-        if (r)
-            Py_DECREF(r);
-        else
-            PyErr_Clear();
-    }
-    Py_RETURN_NONE;
-}
-
-/*
- * _BufferedIOMixin methods
- * This is not a class, just a collection of methods that will be reused
- * by BufferedReader and BufferedWriter
- */
-
-/* Flush and close */
-
-static PyObject *
-buffered_simple_flush(buffered *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self)
-    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_flush, NULL);
-}
+PyDoc_STRVAR(_io_BufferedRandom___init____doc__,
+"BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n"
+"--\n"
+"\n"
+"A buffered interface to random access streams.\n"
+"\n"
+"The constructor creates a reader and writer for a seekable stream,\n"
+"raw, given in the first argument. If the buffer_size is omitted it\n"
+"defaults to DEFAULT_BUFFER_SIZE.");
 
 static int
-buffered_closed(buffered *self)
-{
-    int closed;
-    PyObject *res;
-    CHECK_INITIALIZED_INT(self)
-    res = PyObject_GetAttr(self->raw, _PyIO_str_closed);
-    if (res == NULL)
-        return -1;
-    closed = PyObject_IsTrue(res);
-    Py_DECREF(res);
-    return closed;
-}
-
-static PyObject *
-buffered_closed_get(buffered *self, void *context)
-{
-    CHECK_INITIALIZED(self)
-    return PyObject_GetAttr(self->raw, _PyIO_str_closed);
-}
-
-static PyObject *
-buffered_close(buffered *self, PyObject *args)
-{
-    PyObject *res = NULL, *exc = NULL, *val, *tb;
-    int r;
-
-    CHECK_INITIALIZED(self)
-    if (!ENTER_BUFFERED(self))
-        return NULL;
-
-    r = buffered_closed(self);
-    if (r < 0)
-        goto end;
-    if (r > 0) {
-        res = Py_None;
-        Py_INCREF(res);
-        goto end;
-    }
-
-    if (self->finalizing) {
-        PyObject *r = buffered_dealloc_warn(self, (PyObject *) self);
-        if (r)
-            Py_DECREF(r);
-        else
-            PyErr_Clear();
-    }
-    /* flush() will most probably re-take the lock, so drop it first */
-    LEAVE_BUFFERED(self)
-    res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
-    if (!ENTER_BUFFERED(self))
-        return NULL;
-    if (res == NULL)
-        PyErr_Fetch(&exc, &val, &tb);
-    else
-        Py_DECREF(res);
-
-    res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL);
-
-    if (self->buffer) {
-        PyMem_Free(self->buffer);
-        self->buffer = NULL;
-    }
-
-    if (exc != NULL) {
-        _PyErr_ChainExceptions(exc, val, tb);
-        Py_CLEAR(res);
-    }
-
-end:
-    LEAVE_BUFFERED(self)
-    return res;
-}
-
-/* detach */
-
-static PyObject *
-buffered_detach(buffered *self, PyObject *args)
-{
-    PyObject *raw, *res;
-    CHECK_INITIALIZED(self)
-    res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-    raw = self->raw;
-    self->raw = NULL;
-    self->detached = 1;
-    self->ok = 0;
-    return raw;
-}
-
-/* Inquiries */
-
-static PyObject *
-buffered_seekable(buffered *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self)
-    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_seekable, NULL);
-}
-
-static PyObject *
-buffered_readable(buffered *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self)
-    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readable, NULL);
-}
-
-static PyObject *
-buffered_writable(buffered *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self)
-    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_writable, NULL);
-}
-
-static PyObject *
-buffered_name_get(buffered *self, void *context)
-{
-    CHECK_INITIALIZED(self)
-    return _PyObject_GetAttrId(self->raw, &PyId_name);
-}
-
-static PyObject *
-buffered_mode_get(buffered *self, void *context)
-{
-    CHECK_INITIALIZED(self)
-    return _PyObject_GetAttrId(self->raw, &PyId_mode);
-}
-
-/* Lower-level APIs */
-
-static PyObject *
-buffered_fileno(buffered *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self)
-    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_fileno, NULL);
-}
-
-static PyObject *
-buffered_isatty(buffered *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self)
-    return PyObject_CallMethodObjArgs(self->raw, _PyIO_str_isatty, NULL);
-}
-
-/* Serialization */
-
-static PyObject *
-buffered_getstate(buffered *self, PyObject *args)
-{
-    PyErr_Format(PyExc_TypeError,
-                 "cannot serialize '%s' object", Py_TYPE(self)->tp_name);
-    return NULL;
-}
-
-/* Forward decls */
-static PyObject *
-_bufferedwriter_flush_unlocked(buffered *);
-static Py_ssize_t
-_bufferedreader_fill_buffer(buffered *self);
-static void
-_bufferedreader_reset_buf(buffered *self);
-static void
-_bufferedwriter_reset_buf(buffered *self);
-static PyObject *
-_bufferedreader_peek_unlocked(buffered *self);
-static PyObject *
-_bufferedreader_read_all(buffered *self);
-static PyObject *
-_bufferedreader_read_fast(buffered *self, Py_ssize_t);
-static PyObject *
-_bufferedreader_read_generic(buffered *self, Py_ssize_t);
-static Py_ssize_t
-_bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len);
-
-/*
- * Helpers
- */
-
-/* Sets the current error to BlockingIOError */
-static void
-_set_BlockingIOError(char *msg, Py_ssize_t written)
-{
-    PyObject *err;
-    PyErr_Clear();
-    err = PyObject_CallFunction(PyExc_BlockingIOError, "isn",
-                                errno, msg, written);
-    if (err)
-        PyErr_SetObject(PyExc_BlockingIOError, err);
-    Py_XDECREF(err);
-}
-
-/* Returns the address of the `written` member if a BlockingIOError was
-   raised, NULL otherwise. The error is always re-raised. */
-static Py_ssize_t *
-_buffered_check_blocking_error(void)
-{
-    PyObject *t, *v, *tb;
-    PyOSErrorObject *err;
-
-    PyErr_Fetch(&t, &v, &tb);
-    if (v == NULL || !PyErr_GivenExceptionMatches(v, PyExc_BlockingIOError)) {
-        PyErr_Restore(t, v, tb);
-        return NULL;
-    }
-    err = (PyOSErrorObject *) v;
-    /* TODO: sanity check (err->written >= 0) */
-    PyErr_Restore(t, v, tb);
-    return &err->written;
-}
-
-static Py_off_t
-_buffered_raw_tell(buffered *self)
-{
-    Py_off_t n;
-    PyObject *res;
-    res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_tell, NULL);
-    if (res == NULL)
-        return -1;
-    n = PyNumber_AsOff_t(res, PyExc_ValueError);
-    Py_DECREF(res);
-    if (n < 0) {
-        if (!PyErr_Occurred())
-            PyErr_Format(PyExc_IOError,
-                         "Raw stream returned invalid position %" PY_PRIdOFF,
-                         (PY_OFF_T_COMPAT)n);
-        return -1;
-    }
-    self->abs_pos = n;
-    return n;
-}
-
-static Py_off_t
-_buffered_raw_seek(buffered *self, Py_off_t target, int whence)
-{
-    PyObject *res, *posobj, *whenceobj;
-    Py_off_t n;
-
-    posobj = PyLong_FromOff_t(target);
-    if (posobj == NULL)
-        return -1;
-    whenceobj = PyLong_FromLong(whence);
-    if (whenceobj == NULL) {
-        Py_DECREF(posobj);
-        return -1;
-    }
-    res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_seek,
-                                     posobj, whenceobj, NULL);
-    Py_DECREF(posobj);
-    Py_DECREF(whenceobj);
-    if (res == NULL)
-        return -1;
-    n = PyNumber_AsOff_t(res, PyExc_ValueError);
-    Py_DECREF(res);
-    if (n < 0) {
-        if (!PyErr_Occurred())
-            PyErr_Format(PyExc_IOError,
-                         "Raw stream returned invalid position %" PY_PRIdOFF,
-                         (PY_OFF_T_COMPAT)n);
-        return -1;
-    }
-    self->abs_pos = n;
-    return n;
-}
+_io_BufferedRandom___init___impl(buffered *self, PyObject *raw,
+                                 Py_ssize_t buffer_size);
 
 static int
-_buffered_init(buffered *self)
+_io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-    Py_ssize_t n;
-    if (self->buffer_size <= 0) {
-        PyErr_SetString(PyExc_ValueError,
-            "buffer size must be strictly positive");
-        return -1;
-    }
-    if (self->buffer)
-        PyMem_Free(self->buffer);
-    self->buffer = PyMem_Malloc(self->buffer_size);
-    if (self->buffer == NULL) {
-        PyErr_NoMemory();
-        return -1;
-    }
-#ifdef WITH_THREAD
-    if (self->lock)
-        PyThread_free_lock(self->lock);
-    self->lock = PyThread_allocate_lock();
-    if (self->lock == NULL) {
-        PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
-        return -1;
-    }
-    self->owner = 0;
-#endif
-    /* Find out whether buffer_size is a power of 2 */
-    /* XXX is this optimization useful? */
-    for (n = self->buffer_size - 1; n & 1; n >>= 1)
-        ;
-    if (n == 0)
-        self->buffer_mask = self->buffer_size - 1;
-    else
-        self->buffer_mask = 0;
-    if (_buffered_raw_tell(self) == -1)
-        PyErr_Clear();
-    return 0;
-}
-
-/* Return 1 if an EnvironmentError with errno == EINTR is set (and then
-   clears the error indicator), 0 otherwise.
-   Should only be called when PyErr_Occurred() is true.
-*/
-int
-_PyIO_trap_eintr(void)
-{
-    static PyObject *eintr_int = NULL;
-    PyObject *typ, *val, *tb;
-    PyEnvironmentErrorObject *env_err;
-
-    if (eintr_int == NULL) {
-        eintr_int = PyLong_FromLong(EINTR);
-        assert(eintr_int != NULL);
-    }
-    if (!PyErr_ExceptionMatches(PyExc_EnvironmentError))
-        return 0;
-    PyErr_Fetch(&typ, &val, &tb);
-    PyErr_NormalizeException(&typ, &val, &tb);
-    env_err = (PyEnvironmentErrorObject *) val;
-    assert(env_err != NULL);
-    if (env_err->myerrno != NULL &&
-        PyObject_RichCompareBool(env_err->myerrno, eintr_int, Py_EQ) > 0) {
-        Py_DECREF(typ);
-        Py_DECREF(val);
-        Py_XDECREF(tb);
-        return 1;
-    }
-    /* This silences any error set by PyObject_RichCompareBool() */
-    PyErr_Restore(typ, val, tb);
-    return 0;
-}
-
-/*
- * Shared methods and wrappers
- */
-
-static PyObject *
-buffered_flush_and_rewind_unlocked(buffered *self)
-{
-    PyObject *res;
-
-    res = _bufferedwriter_flush_unlocked(self);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-
-    if (self->readable) {
-        /* Rewind the raw stream so that its position corresponds to
-           the current logical position. */
-        Py_off_t n;
-        n = _buffered_raw_seek(self, -RAW_OFFSET(self), 1);
-        _bufferedreader_reset_buf(self);
-        if (n == -1)
-            return NULL;
-    }
-    Py_RETURN_NONE;
-}
-
-static PyObject *
-buffered_flush(buffered *self, PyObject *args)
-{
-    PyObject *res;
-
-    CHECK_INITIALIZED(self)
-    CHECK_CLOSED(self, "flush of closed file")
-
-    if (!ENTER_BUFFERED(self))
-        return NULL;
-    res = buffered_flush_and_rewind_unlocked(self);
-    LEAVE_BUFFERED(self)
-
-    return res;
-}
-
-static PyObject *
-buffered_peek(buffered *self, PyObject *args)
-{
-    Py_ssize_t n = 0;
-    PyObject *res = NULL;
-
-    CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
-        return NULL;
-    }
-
-    if (!ENTER_BUFFERED(self))
-        return NULL;
-
-    if (self->writable) {
-        res = buffered_flush_and_rewind_unlocked(self);
-        if (res == NULL)
-            goto end;
-        Py_CLEAR(res);
-    }
-    res = _bufferedreader_peek_unlocked(self);
-
-end:
-    LEAVE_BUFFERED(self)
-    return res;
-}
-
-static PyObject *
-buffered_read(buffered *self, PyObject *args)
-{
-    Py_ssize_t n = -1;
-    PyObject *res;
-
-    CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) {
-        return NULL;
-    }
-    if (n < -1) {
-        PyErr_SetString(PyExc_ValueError,
-                        "read length must be positive or -1");
-        return NULL;
-    }
-
-    CHECK_CLOSED(self, "read of closed file")
-
-    if (n == -1) {
-        /* The number of bytes is unspecified, read until the end of stream */
-        if (!ENTER_BUFFERED(self))
-            return NULL;
-        res = _bufferedreader_read_all(self);
-    }
-    else {
-        res = _bufferedreader_read_fast(self, n);
-        if (res != Py_None)
-            return res;
-        Py_DECREF(res);
-        if (!ENTER_BUFFERED(self))
-            return NULL;
-        res = _bufferedreader_read_generic(self, n);
-    }
-
-    LEAVE_BUFFERED(self)
-    return res;
-}
-
-static PyObject *
-buffered_read1(buffered *self, PyObject *args)
-{
-    Py_ssize_t n, have, r;
-    PyObject *res = NULL;
-
-    CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "n:read1", &n)) {
-        return NULL;
-    }
-
-    if (n < 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "read length must be positive");
-        return NULL;
-    }
-    if (n == 0)
-        return PyBytes_FromStringAndSize(NULL, 0);
-
-    /* Return up to n bytes.  If at least one byte is buffered, we
-       only return buffered bytes.  Otherwise, we do one raw read. */
-
-    have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
-    if (have > 0) {
-        n = Py_MIN(have, n);
-        res = _bufferedreader_read_fast(self, n);
-        assert(res != Py_None);
-        return res;
-    }
-    res = PyBytes_FromStringAndSize(NULL, n);
-    if (res == NULL)
-        return NULL;
-    if (!ENTER_BUFFERED(self)) {
-        Py_DECREF(res);
-        return NULL;
-    }
-    _bufferedreader_reset_buf(self);
-    r = _bufferedreader_raw_read(self, PyBytes_AS_STRING(res), n);
-    LEAVE_BUFFERED(self)
-    if (r == -1) {
-        Py_DECREF(res);
-        return NULL;
-    }
-    if (r == -2)
-        r = 0;
-    if (n > r)
-        _PyBytes_Resize(&res, r);
-    return res;
-}
-
-static PyObject *
-_buffered_readinto_generic(buffered *self, PyObject *args, char readinto1)
-{
-    Py_buffer buf;
-    Py_ssize_t n, written = 0, remaining;
-    PyObject *res = NULL;
-
-    CHECK_INITIALIZED(self)
-
-    if (!PyArg_ParseTuple(args,
-                          readinto1 ? "w*:readinto1" : "w*:readinto",
-                          &buf))
-        return NULL;
-
-    n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
-    if (n > 0) {
-        if (n >= buf.len) {
-            memcpy(buf.buf, self->buffer + self->pos, buf.len);
-            self->pos += buf.len;
-            res = PyLong_FromSsize_t(buf.len);
-            goto end_unlocked;
-        }
-        memcpy(buf.buf, self->buffer + self->pos, n);
-        self->pos += n;
-        written = n;
-    }
-
-    if (!ENTER_BUFFERED(self))
-        goto end_unlocked;
-
-    if (self->writable) {
-        res = buffered_flush_and_rewind_unlocked(self);
-        if (res == NULL)
-            goto end;
-        Py_CLEAR(res);
-    }
-
-    _bufferedreader_reset_buf(self);
-    self->pos = 0;
-
-    for (remaining = buf.len - written;
-         remaining > 0;
-         written += n, remaining -= n) {
-        /* If remaining bytes is larger than internal buffer size, copy
-         * directly into caller's buffer. */
-        if (remaining > self->buffer_size) {
-            n = _bufferedreader_raw_read(self, (char *) buf.buf + written,
-                                         remaining);
-        }
-
-        /* In readinto1 mode, we do not want to fill the internal
-           buffer if we already have some data to return */
-        else if (!(readinto1 && written)) {
-            n = _bufferedreader_fill_buffer(self);
-            if (n > 0) {
-                if (n > remaining)
-                    n = remaining;
-                memcpy((char *) buf.buf + written,
-                       self->buffer + self->pos, n);
-                self->pos += n;
-                continue; /* short circuit */
-            }
-        }
-        else
-            n = 0;
-
-        if (n == 0 || (n == -2 && written > 0))
-            break;
-        if (n < 0) {
-            if (n == -2) {
-                Py_INCREF(Py_None);
-                res = Py_None;
-            }
-            goto end;
-        }
-
-        /* At most one read in readinto1 mode */
-        if (readinto1) {
-            written += n;
-            break;
-        }
-    }
-    res = PyLong_FromSsize_t(written);
-
-end:
-    LEAVE_BUFFERED(self);
-end_unlocked:
-    PyBuffer_Release(&buf);
-    return res;
-}
-
-static PyObject *
-buffered_readinto(buffered *self, PyObject *args)
-{
-    return _buffered_readinto_generic(self, args, 0);
-}
-
-static PyObject *
-buffered_readinto1(buffered *self, PyObject *args)
-{
-    return _buffered_readinto_generic(self, args, 1);
-}
-
-
-static PyObject *
-_buffered_readline(buffered *self, Py_ssize_t limit)
-{
-    PyObject *res = NULL;
-    PyObject *chunks = NULL;
-    Py_ssize_t n, written = 0;
-    const char *start, *s, *end;
-
-    CHECK_CLOSED(self, "readline of closed file")
-
-    /* First, try to find a line in the buffer. This can run unlocked because
-       the calls to the C API are simple enough that they can't trigger
-       any thread switch. */
-    n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
-    if (limit >= 0 && n > limit)
-        n = limit;
-    start = self->buffer + self->pos;
-    s = memchr(start, '\n', n);
-    if (s != NULL) {
-        res = PyBytes_FromStringAndSize(start, s - start + 1);
-        if (res != NULL)
-            self->pos += s - start + 1;
-        goto end_unlocked;
-    }
-    if (n == limit) {
-        res = PyBytes_FromStringAndSize(start, n);
-        if (res != NULL)
-            self->pos += n;
-        goto end_unlocked;
-    }
-
-    if (!ENTER_BUFFERED(self))
-        goto end_unlocked;
-
-    /* Now we try to get some more from the raw stream */
-    chunks = PyList_New(0);
-    if (chunks == NULL)
-        goto end;
-    if (n > 0) {
-        res = PyBytes_FromStringAndSize(start, n);
-        if (res == NULL)
-            goto end;
-        if (PyList_Append(chunks, res) < 0) {
-            Py_CLEAR(res);
-            goto end;
-        }
-        Py_CLEAR(res);
-        written += n;
-        self->pos += n;
-        if (limit >= 0)
-            limit -= n;
-    }
-    if (self->writable) {
-        PyObject *r = buffered_flush_and_rewind_unlocked(self);
-        if (r == NULL)
-            goto end;
-        Py_DECREF(r);
-    }
-
-    for (;;) {
-        _bufferedreader_reset_buf(self);
-        n = _bufferedreader_fill_buffer(self);
-        if (n == -1)
-            goto end;
-        if (n <= 0)
-            break;
-        if (limit >= 0 && n > limit)
-            n = limit;
-        start = self->buffer;
-        end = start + n;
-        s = start;
-        while (s < end) {
-            if (*s++ == '\n') {
-                res = PyBytes_FromStringAndSize(start, s - start);
-                if (res == NULL)
-                    goto end;
-                self->pos = s - start;
-                goto found;
-            }
-        }
-        res = PyBytes_FromStringAndSize(start, n);
-        if (res == NULL)
-            goto end;
-        if (n == limit) {
-            self->pos = n;
-            break;
-        }
-        if (PyList_Append(chunks, res) < 0) {
-            Py_CLEAR(res);
-            goto end;
-        }
-        Py_CLEAR(res);
-        written += n;
-        if (limit >= 0)
-            limit -= n;
-    }
-found:
-    if (res != NULL && PyList_Append(chunks, res) < 0) {
-        Py_CLEAR(res);
-        goto end;
-    }
-    Py_CLEAR(res);
-    res = _PyBytes_Join(_PyIO_empty_bytes, chunks);
-
-end:
-    LEAVE_BUFFERED(self)
-end_unlocked:
-    Py_XDECREF(chunks);
-    return res;
-}
-
-static PyObject *
-buffered_readline(buffered *self, PyObject *args)
-{
-    Py_ssize_t limit = -1;
-
-    CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit))
-        return NULL;
-    return _buffered_readline(self, limit);
-}
-
-
-static PyObject *
-buffered_tell(buffered *self, PyObject *args)
-{
-    Py_off_t pos;
-
-    CHECK_INITIALIZED(self)
-    pos = _buffered_raw_tell(self);
-    if (pos == -1)
-        return NULL;
-    pos -= RAW_OFFSET(self);
-    /* TODO: sanity check (pos >= 0) */
-    return PyLong_FromOff_t(pos);
-}
-
-static PyObject *
-buffered_seek(buffered *self, PyObject *args)
-{
-    Py_off_t target, n;
-    int whence = 0;
-    PyObject *targetobj, *res = NULL;
-
-    CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "O|i:seek", &targetobj, &whence)) {
-        return NULL;
-    }
-
-    /* Do some error checking instead of trusting OS 'seek()'
-    ** error detection, just in case.
-    */
-    if ((whence < 0 || whence >2)
-#ifdef SEEK_HOLE
-        && (whence != SEEK_HOLE)
-#endif
-#ifdef SEEK_DATA
-        && (whence != SEEK_DATA)
-#endif
-        ) {
-        PyErr_Format(PyExc_ValueError,
-                     "whence value %d unsupported", whence);
-        return NULL;
-    }
-
-    CHECK_CLOSED(self, "seek of closed file")
-
-    if (_PyIOBase_check_seekable(self->raw, Py_True) == NULL)
-        return NULL;
-
-    target = PyNumber_AsOff_t(targetobj, PyExc_ValueError);
-    if (target == -1 && PyErr_Occurred())
-        return NULL;
-
-    /* SEEK_SET and SEEK_CUR are special because we could seek inside the
-       buffer. Other whence values must be managed without this optimization.
-       Some Operating Systems can provide additional values, like
-       SEEK_HOLE/SEEK_DATA. */
-    if (((whence == 0) || (whence == 1)) && self->readable) {
-        Py_off_t current, avail;
-        /* Check if seeking leaves us inside the current buffer,
-           so as to return quickly if possible. Also, we needn't take the
-           lock in this fast path.
-           Don't know how to do that when whence == 2, though. */
-        /* NOTE: RAW_TELL() can release the GIL but the object is in a stable
-           state at this point. */
-        current = RAW_TELL(self);
-        avail = READAHEAD(self);
-        if (avail > 0) {
-            Py_off_t offset;
-            if (whence == 0)
-                offset = target - (current - RAW_OFFSET(self));
-            else
-                offset = target;
-            if (offset >= -self->pos && offset <= avail) {
-                self->pos += offset;
-                return PyLong_FromOff_t(current - avail + offset);
-            }
-        }
-    }
-
-    if (!ENTER_BUFFERED(self))
-        return NULL;
-
-    /* Fallback: invoke raw seek() method and clear buffer */
-    if (self->writable) {
-        res = _bufferedwriter_flush_unlocked(self);
-        if (res == NULL)
-            goto end;
-        Py_CLEAR(res);
-        _bufferedwriter_reset_buf(self);
-    }
-
-    /* TODO: align on block boundary and read buffer if needed? */
-    if (whence == 1)
-        target -= RAW_OFFSET(self);
-    n = _buffered_raw_seek(self, target, whence);
-    if (n == -1)
-        goto end;
-    self->raw_pos = -1;
-    res = PyLong_FromOff_t(n);
-    if (res != NULL && self->readable)
-        _bufferedreader_reset_buf(self);
-
-end:
-    LEAVE_BUFFERED(self)
-    return res;
-}
-
-static PyObject *
-buffered_truncate(buffered *self, PyObject *args)
-{
-    PyObject *pos = Py_None;
-    PyObject *res = NULL;
-
-    CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
-        return NULL;
-    }
-
-    if (!ENTER_BUFFERED(self))
-        return NULL;
-
-    if (self->writable) {
-        res = buffered_flush_and_rewind_unlocked(self);
-        if (res == NULL)
-            goto end;
-        Py_CLEAR(res);
-    }
-    res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_truncate, pos, NULL);
-    if (res == NULL)
-        goto end;
-    /* Reset cached position */
-    if (_buffered_raw_tell(self) == -1)
-        PyErr_Clear();
-
-end:
-    LEAVE_BUFFERED(self)
-    return res;
-}
-
-static PyObject *
-buffered_iternext(buffered *self)
-{
-    PyObject *line;
-    PyTypeObject *tp;
-
-    CHECK_INITIALIZED(self);
-
-    tp = Py_TYPE(self);
-    if (tp == &PyBufferedReader_Type ||
-        tp == &PyBufferedRandom_Type) {
-        /* Skip method call overhead for speed */
-        line = _buffered_readline(self, -1);
-    }
-    else {
-        line = PyObject_CallMethodObjArgs((PyObject *)self,
-                                           _PyIO_str_readline, NULL);
-        if (line && !PyBytes_Check(line)) {
-            PyErr_Format(PyExc_IOError,
-                         "readline() should have returned a bytes object, "
-                         "not '%.200s'", Py_TYPE(line)->tp_name);
-            Py_DECREF(line);
-            return NULL;
-        }
-    }
-
-    if (line == NULL)
-        return NULL;
-
-    if (PyBytes_GET_SIZE(line) == 0) {
-        /* Reached EOF or would have blocked */
-        Py_DECREF(line);
-        return NULL;
-    }
-
-    return line;
-}
-
-static PyObject *
-buffered_repr(buffered *self)
-{
-    PyObject *nameobj, *res;
-
-    nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
-    if (nameobj == NULL) {
-        if (PyErr_ExceptionMatches(PyExc_Exception))
-            PyErr_Clear();
-        else
-            return NULL;
-        res = PyUnicode_FromFormat("<%s>", Py_TYPE(self)->tp_name);
-    }
-    else {
-        res = PyUnicode_FromFormat("<%s name=%R>",
-                                   Py_TYPE(self)->tp_name, nameobj);
-        Py_DECREF(nameobj);
-    }
-    return res;
-}
-
-/*
- * class BufferedReader
- */
-
-PyDoc_STRVAR(bufferedreader_doc,
-             "Create a new buffered reader using the given readable raw IO object.");
-
-static void _bufferedreader_reset_buf(buffered *self)
-{
-    self->read_end = -1;
-}
-
-static int
-bufferedreader_init(buffered *self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"raw", "buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+    int return_value = -1;
+    static char *_keywords[] = {"raw", "buffer_size", NULL};
     PyObject *raw;
-
-    self->ok = 0;
-    self->detached = 0;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
-                                     &raw, &buffer_size)) {
-        return -1;
-    }
-
-    if (_PyIOBase_check_readable(raw, Py_True) == NULL)
-        return -1;
-
-    Py_CLEAR(self->raw);
-    Py_INCREF(raw);
-    self->raw = raw;
-    self->buffer_size = buffer_size;
-    self->readable = 1;
-    self->writable = 0;
-
-    if (_buffered_init(self) < 0)
-        return -1;
-    _bufferedreader_reset_buf(self);
-
-    self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedReader_Type &&
-                                Py_TYPE(raw) == &PyFileIO_Type);
-
-    self->ok = 1;
-    return 0;
-}
-
-static Py_ssize_t
-_bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len)
-{
-    Py_buffer buf;
-    PyObject *memobj, *res;
-    Py_ssize_t n;
-    /* NOTE: the buffer needn't be released as its object is NULL. */
-    if (PyBuffer_FillInfo(&buf, NULL, start, len, 0, PyBUF_CONTIG) == -1)
-        return -1;
-    memobj = PyMemoryView_FromBuffer(&buf);
-    if (memobj == NULL)
-        return -1;
-    /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() when EINTR
-       occurs so we needn't do it ourselves.
-       We then retry reading, ignoring the signal if no handler has
-       raised (see issue #10956).
-    */
-    do {
-        res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readinto, memobj, NULL);
-    } while (res == NULL && _PyIO_trap_eintr());
-    Py_DECREF(memobj);
-    if (res == NULL)
-        return -1;
-    if (res == Py_None) {
-        /* Non-blocking stream would have blocked. Special return code! */
-        Py_DECREF(res);
-        return -2;
-    }
-    n = PyNumber_AsSsize_t(res, PyExc_ValueError);
-    Py_DECREF(res);
-    if (n < 0 || n > len) {
-        PyErr_Format(PyExc_IOError,
-                     "raw readinto() returned invalid length %zd "
-                     "(should have been between 0 and %zd)", n, len);
-        return -1;
-    }
-    if (n > 0 && self->abs_pos != -1)
-        self->abs_pos += n;
-    return n;
-}
-
-static Py_ssize_t
-_bufferedreader_fill_buffer(buffered *self)
-{
-    Py_ssize_t start, len, n;
-    if (VALID_READ_BUFFER(self))
-        start = Py_SAFE_DOWNCAST(self->read_end, Py_off_t, Py_ssize_t);
-    else
-        start = 0;
-    len = self->buffer_size - start;
-    n = _bufferedreader_raw_read(self, self->buffer + start, len);
-    if (n <= 0)
-        return n;
-    self->read_end = start + n;
-    self->raw_pos = start + n;
-    return n;
-}
-
-static PyObject *
-_bufferedreader_read_all(buffered *self)
-{
-    Py_ssize_t current_size;
-    PyObject *res = NULL, *data = NULL, *tmp = NULL, *chunks = NULL;
-
-    /* First copy what we have in the current buffer. */
-    current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
-    if (current_size) {
-        data = PyBytes_FromStringAndSize(
-            self->buffer + self->pos, current_size);
-        if (data == NULL)
-            return NULL;
-        self->pos += current_size;
-    }
-    /* We're going past the buffer's bounds, flush it */
-    if (self->writable) {
-        tmp = buffered_flush_and_rewind_unlocked(self);
-        if (tmp == NULL)
-            goto cleanup;
-        Py_CLEAR(tmp);
-    }
-    _bufferedreader_reset_buf(self);
-
-    if (PyObject_HasAttr(self->raw, _PyIO_str_readall)) {
-        tmp = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL);
-        if (tmp == NULL)
-            goto cleanup;
-        if (tmp != Py_None && !PyBytes_Check(tmp)) {
-            PyErr_SetString(PyExc_TypeError, "readall() should return bytes");
-            goto cleanup;
-        }
-        if (tmp == Py_None) {
-            if (current_size == 0) {
-                res = Py_None;
-                goto cleanup;
-            } else {
-                res = data;
-                goto cleanup;
-            }
-        }
-        else if (current_size) {
-            PyBytes_Concat(&data, tmp);
-            res = data;
-            goto cleanup;
-        }
-        else {
-            res = tmp;
-            goto cleanup;
-        }
-    }
-
-    chunks = PyList_New(0);
-    if (chunks == NULL)
-        goto cleanup;
-
-    while (1) {
-        if (data) {
-            if (PyList_Append(chunks, data) < 0)
-                goto cleanup;
-            Py_CLEAR(data);
-        }
-
-        /* Read until EOF or until read() would block. */
-        data = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_read, NULL);
-        if (data == NULL)
-            goto cleanup;
-        if (data != Py_None && !PyBytes_Check(data)) {
-            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
-            goto cleanup;
-        }
-        if (data == Py_None || PyBytes_GET_SIZE(data) == 0) {
-            if (current_size == 0) {
-                res = data;
-                goto cleanup;
-            }
-            else {
-                tmp = _PyBytes_Join(_PyIO_empty_bytes, chunks);
-                res = tmp;
-                goto cleanup;
-            }
-        }
-        current_size += PyBytes_GET_SIZE(data);
-        if (self->abs_pos != -1)
-            self->abs_pos += PyBytes_GET_SIZE(data);
-    }
-cleanup:
-    /* res is either NULL or a borrowed ref */
-    Py_XINCREF(res);
-    Py_XDECREF(data);
-    Py_XDECREF(tmp);
-    Py_XDECREF(chunks);
-    return res;
-}
-
-/* Read n bytes from the buffer if it can, otherwise return None.
-   This function is simple enough that it can run unlocked. */
-static PyObject *
-_bufferedreader_read_fast(buffered *self, Py_ssize_t n)
-{
-    Py_ssize_t current_size;
-
-    current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
-    if (n <= current_size) {
-        /* Fast path: the data to read is fully buffered. */
-        PyObject *res = PyBytes_FromStringAndSize(self->buffer + self->pos, n);
-        if (res != NULL)
-            self->pos += n;
-        return res;
-    }
-    Py_RETURN_NONE;
-}
-
-/* Generic read function: read from the stream until enough bytes are read,
- * or until an EOF occurs or until read() would block.
- */
-static PyObject *
-_bufferedreader_read_generic(buffered *self, Py_ssize_t n)
-{
-    PyObject *res = NULL;
-    Py_ssize_t current_size, remaining, written;
-    char *out;
-
-    current_size = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
-    if (n <= current_size)
-        return _bufferedreader_read_fast(self, n);
-
-    res = PyBytes_FromStringAndSize(NULL, n);
-    if (res == NULL)
-        goto error;
-    out = PyBytes_AS_STRING(res);
-    remaining = n;
-    written = 0;
-    if (current_size > 0) {
-        memcpy(out, self->buffer + self->pos, current_size);
-        remaining -= current_size;
-        written += current_size;
-        self->pos += current_size;
-    }
-    /* Flush the write buffer if necessary */
-    if (self->writable) {
-        PyObject *r = buffered_flush_and_rewind_unlocked(self);
-        if (r == NULL)
-            goto error;
-        Py_DECREF(r);
-    }
-    _bufferedreader_reset_buf(self);
-    while (remaining > 0) {
-        /* We want to read a whole block at the end into buffer.
-           If we had readv() we could do this in one pass. */
-        Py_ssize_t r = MINUS_LAST_BLOCK(self, remaining);
-        if (r == 0)
-            break;
-        r = _bufferedreader_raw_read(self, out + written, r);
-        if (r == -1)
-            goto error;
-        if (r == 0 || r == -2) {
-            /* EOF occurred or read() would block. */
-            if (r == 0 || written > 0) {
-                if (_PyBytes_Resize(&res, written))
-                    goto error;
-                return res;
-            }
-            Py_DECREF(res);
-            Py_INCREF(Py_None);
-            return Py_None;
-        }
-        remaining -= r;
-        written += r;
-    }
-    assert(remaining <= self->buffer_size);
-    self->pos = 0;
-    self->raw_pos = 0;
-    self->read_end = 0;
-    /* NOTE: when the read is satisfied, we avoid issuing any additional
-       reads, which could block indefinitely (e.g. on a socket).
-       See issue #9550. */
-    while (remaining > 0 && self->read_end < self->buffer_size) {
-        Py_ssize_t r = _bufferedreader_fill_buffer(self);
-        if (r == -1)
-            goto error;
-        if (r == 0 || r == -2) {
-            /* EOF occurred or read() would block. */
-            if (r == 0 || written > 0) {
-                if (_PyBytes_Resize(&res, written))
-                    goto error;
-                return res;
-            }
-            Py_DECREF(res);
-            Py_INCREF(Py_None);
-            return Py_None;
-        }
-        if (remaining > r) {
-            memcpy(out + written, self->buffer + self->pos, r);
-            written += r;
-            self->pos += r;
-            remaining -= r;
-        }
-        else if (remaining > 0) {
-            memcpy(out + written, self->buffer + self->pos, remaining);
-            written += remaining;
-            self->pos += remaining;
-            remaining = 0;
-        }
-        if (remaining == 0)
-            break;
-    }
-
-    return res;
-
-error:
-    Py_XDECREF(res);
-    return NULL;
-}
-
-static PyObject *
-_bufferedreader_peek_unlocked(buffered *self)
-{
-    Py_ssize_t have, r;
-
-    have = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t);
-    /* Constraints:
-       1. we don't want to advance the file position.
-       2. we don't want to lose block alignment, so we can't shift the buffer
-          to make some place.
-       Therefore, we either return `have` bytes (if > 0), or a full buffer.
-    */
-    if (have > 0) {
-        return PyBytes_FromStringAndSize(self->buffer + self->pos, have);
-    }
-
-    /* Fill the buffer from the raw stream, and copy it to the result. */
-    _bufferedreader_reset_buf(self);
-    r = _bufferedreader_fill_buffer(self);
-    if (r == -1)
-        return NULL;
-    if (r == -2)
-        r = 0;
-    self->pos = 0;
-    return PyBytes_FromStringAndSize(self->buffer, r);
-}
-
-static PyMethodDef bufferedreader_methods[] = {
-    /* BufferedIOMixin methods */
-    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
-    {"flush", (PyCFunction)buffered_simple_flush, METH_NOARGS},
-    {"close", (PyCFunction)buffered_close, METH_NOARGS},
-    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
-    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
-    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
-    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
-    {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
-    {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
-
-    {"read", (PyCFunction)buffered_read, METH_VARARGS},
-    {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
-    {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
-    {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS},
-    {"readinto1", (PyCFunction)buffered_readinto1, METH_VARARGS},
-    {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
-    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
-    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
-    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
-    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef bufferedreader_members[] = {
-    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
-    {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0},
-    {NULL}
-};
-
-static PyGetSetDef bufferedreader_getset[] = {
-    {"closed", (getter)buffered_closed_get, NULL, NULL},
-    {"name", (getter)buffered_name_get, NULL, NULL},
-    {"mode", (getter)buffered_mode_get, NULL, NULL},
-    {NULL}
-};
-
-
-PyTypeObject PyBufferedReader_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.BufferedReader",       /*tp_name*/
-    sizeof(buffered),           /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)buffered_dealloc,     /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    (reprfunc)buffered_repr,    /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
-    bufferedreader_doc,         /* tp_doc */
-    (traverseproc)buffered_traverse, /* tp_traverse */
-    (inquiry)buffered_clear,    /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    (iternextfunc)buffered_iternext, /* tp_iternext */
-    bufferedreader_methods,     /* tp_methods */
-    bufferedreader_members,     /* tp_members */
-    bufferedreader_getset,      /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(buffered, dict), /* tp_dictoffset */
-    (initproc)bufferedreader_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
-

-
-
-/*
- * class BufferedWriter
- */
-PyDoc_STRVAR(bufferedwriter_doc,
-    "A buffer for a writeable sequential RawIO object.\n"
-    "\n"
-    "The constructor creates a BufferedWriter for the given writeable raw\n"
-    "stream. If the buffer_size is not given, it defaults to\n"
-    "DEFAULT_BUFFER_SIZE.\n"
-    );
-
-static void
-_bufferedwriter_reset_buf(buffered *self)
-{
-    self->write_pos = 0;
-    self->write_end = -1;
-}
-
-static int
-bufferedwriter_init(buffered *self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"raw", "buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    PyObject *raw;
-
-    self->ok = 0;
-    self->detached = 0;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedWriter", kwlist,
-                                     &raw, &buffer_size)) {
-        return -1;
-    }
-
-    if (_PyIOBase_check_writable(raw, Py_True) == NULL)
-        return -1;
-
-    Py_CLEAR(self->raw);
-    Py_INCREF(raw);
-    self->raw = raw;
-    self->readable = 0;
-    self->writable = 1;
-
-    self->buffer_size = buffer_size;
-    if (_buffered_init(self) < 0)
-        return -1;
-    _bufferedwriter_reset_buf(self);
-    self->pos = 0;
-
-    self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedWriter_Type &&
-                                Py_TYPE(raw) == &PyFileIO_Type);
-
-    self->ok = 1;
-    return 0;
-}
-
-static Py_ssize_t
-_bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
-{
-    Py_buffer buf;
-    PyObject *memobj, *res;
-    Py_ssize_t n;
-    int errnum;
-    /* NOTE: the buffer needn't be released as its object is NULL. */
-    if (PyBuffer_FillInfo(&buf, NULL, start, len, 1, PyBUF_CONTIG_RO) == -1)
-        return -1;
-    memobj = PyMemoryView_FromBuffer(&buf);
-    if (memobj == NULL)
-        return -1;
-    /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() when EINTR
-       occurs so we needn't do it ourselves.
-       We then retry writing, ignoring the signal if no handler has
-       raised (see issue #10956).
-    */
-    do {
-        errno = 0;
-        res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_write, memobj, NULL);
-        errnum = errno;
-    } while (res == NULL && _PyIO_trap_eintr());
-    Py_DECREF(memobj);
-    if (res == NULL)
-        return -1;
-    if (res == Py_None) {
-        /* Non-blocking stream would have blocked. Special return code!
-           Being paranoid we reset errno in case it is changed by code
-           triggered by a decref.  errno is used by _set_BlockingIOError(). */
-        Py_DECREF(res);
-        errno = errnum;
-        return -2;
-    }
-    n = PyNumber_AsSsize_t(res, PyExc_ValueError);
-    Py_DECREF(res);
-    if (n < 0 || n > len) {
-        PyErr_Format(PyExc_IOError,
-                     "raw write() returned invalid length %zd "
-                     "(should have been between 0 and %zd)", n, len);
-        return -1;
-    }
-    if (n > 0 && self->abs_pos != -1)
-        self->abs_pos += n;
-    return n;
-}
-
-/* `restore_pos` is 1 if we need to restore the raw stream position at
-   the end, 0 otherwise. */
-static PyObject *
-_bufferedwriter_flush_unlocked(buffered *self)
-{
-    Py_ssize_t written = 0;
-    Py_off_t n, rewind;
-
-    if (!VALID_WRITE_BUFFER(self) || self->write_pos == self->write_end)
-        goto end;
-    /* First, rewind */
-    rewind = RAW_OFFSET(self) + (self->pos - self->write_pos);
-    if (rewind != 0) {
-        n = _buffered_raw_seek(self, -rewind, 1);
-        if (n < 0) {
-            goto error;
-        }
-        self->raw_pos -= rewind;
-    }
-    while (self->write_pos < self->write_end) {
-        n = _bufferedwriter_raw_write(self,
-            self->buffer + self->write_pos,
-            Py_SAFE_DOWNCAST(self->write_end - self->write_pos,
-                             Py_off_t, Py_ssize_t));
-        if (n == -1) {
-            goto error;
-        }
-        else if (n == -2) {
-            _set_BlockingIOError("write could not complete without blocking",
-                                 0);
-            goto error;
-        }
-        self->write_pos += n;
-        self->raw_pos = self->write_pos;
-        written += Py_SAFE_DOWNCAST(n, Py_off_t, Py_ssize_t);
-        /* Partial writes can return successfully when interrupted by a
-           signal (see write(2)).  We must run signal handlers before
-           blocking another time, possibly indefinitely. */
-        if (PyErr_CheckSignals() < 0)
-            goto error;
-    }
-
-    _bufferedwriter_reset_buf(self);
-
-end:
-    Py_RETURN_NONE;
-
-error:
-    return NULL;
-}
-
-static PyObject *
-bufferedwriter_write(buffered *self, PyObject *args)
-{
-    PyObject *res = NULL;
-    Py_buffer buf;
-    Py_ssize_t written, avail, remaining;
-    Py_off_t offset;
-
-    CHECK_INITIALIZED(self)
-    if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
-        return NULL;
-    }
-
-    if (IS_CLOSED(self)) {
-        PyErr_SetString(PyExc_ValueError, "write to closed file");
-        PyBuffer_Release(&buf);
-        return NULL;
-    }
-
-    if (!ENTER_BUFFERED(self)) {
-        PyBuffer_Release(&buf);
-        return NULL;
-    }
-
-    /* Fast path: the data to write can be fully buffered. */
-    if (!VALID_READ_BUFFER(self) && !VALID_WRITE_BUFFER(self)) {
-        self->pos = 0;
-        self->raw_pos = 0;
-    }
-    avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t);
-    if (buf.len <= avail) {
-        memcpy(self->buffer + self->pos, buf.buf, buf.len);
-        if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) {
-            self->write_pos = self->pos;
-        }
-        ADJUST_POSITION(self, self->pos + buf.len);
-        if (self->pos > self->write_end)
-            self->write_end = self->pos;
-        written = buf.len;
-        goto end;
-    }
-
-    /* First write the current buffer */
-    res = _bufferedwriter_flush_unlocked(self);
-    if (res == NULL) {
-        Py_ssize_t *w = _buffered_check_blocking_error();
-        if (w == NULL)
-            goto error;
-        if (self->readable)
-            _bufferedreader_reset_buf(self);
-        /* Make some place by shifting the buffer. */
-        assert(VALID_WRITE_BUFFER(self));
-        memmove(self->buffer, self->buffer + self->write_pos,
-                Py_SAFE_DOWNCAST(self->write_end - self->write_pos,
-                                 Py_off_t, Py_ssize_t));
-        self->write_end -= self->write_pos;
-        self->raw_pos -= self->write_pos;
-        self->pos -= self->write_pos;
-        self->write_pos = 0;
-        avail = Py_SAFE_DOWNCAST(self->buffer_size - self->write_end,
-                                 Py_off_t, Py_ssize_t);
-        if (buf.len <= avail) {
-            /* Everything can be buffered */
-            PyErr_Clear();
-            memcpy(self->buffer + self->write_end, buf.buf, buf.len);
-            self->write_end += buf.len;
-            self->pos += buf.len;
-            written = buf.len;
-            goto end;
-        }
-        /* Buffer as much as possible. */
-        memcpy(self->buffer + self->write_end, buf.buf, avail);
-        self->write_end += avail;
-        self->pos += avail;
-        /* XXX Modifying the existing exception e using the pointer w
-           will change e.characters_written but not e.args[2].
-           Therefore we just replace with a new error. */
-        _set_BlockingIOError("write could not complete without blocking",
-                             avail);
-        goto error;
-    }
-    Py_CLEAR(res);
-
-    /* Adjust the raw stream position if it is away from the logical stream
-       position. This happens if the read buffer has been filled but not
-       modified (and therefore _bufferedwriter_flush_unlocked() didn't rewind
-       the raw stream by itself).
-       Fixes issue #6629.
-    */
-    offset = RAW_OFFSET(self);
-    if (offset != 0) {
-        if (_buffered_raw_seek(self, -offset, 1) < 0)
-            goto error;
-        self->raw_pos -= offset;
-    }
-
-    /* Then write buf itself. At this point the buffer has been emptied. */
-    remaining = buf.len;
-    written = 0;
-    while (remaining > self->buffer_size) {
-        Py_ssize_t n = _bufferedwriter_raw_write(
-            self, (char *) buf.buf + written, buf.len - written);
-        if (n == -1) {
-            goto error;
-        } else if (n == -2) {
-            /* Write failed because raw file is non-blocking */
-            if (remaining > self->buffer_size) {
-                /* Can't buffer everything, still buffer as much as possible */
-                memcpy(self->buffer,
-                       (char *) buf.buf + written, self->buffer_size);
-                self->raw_pos = 0;
-                ADJUST_POSITION(self, self->buffer_size);
-                self->write_end = self->buffer_size;
-                written += self->buffer_size;
-                _set_BlockingIOError("write could not complete without "
-                                     "blocking", written);
-                goto error;
-            }
-            PyErr_Clear();
-            break;
-        }
-        written += n;
-        remaining -= n;
-        /* Partial writes can return successfully when interrupted by a
-           signal (see write(2)).  We must run signal handlers before
-           blocking another time, possibly indefinitely. */
-        if (PyErr_CheckSignals() < 0)
-            goto error;
-    }
-    if (self->readable)
-        _bufferedreader_reset_buf(self);
-    if (remaining > 0) {
-        memcpy(self->buffer, (char *) buf.buf + written, remaining);
-        written += remaining;
-    }
-    self->write_pos = 0;
-    /* TODO: sanity check (remaining >= 0) */
-    self->write_end = remaining;
-    ADJUST_POSITION(self, remaining);
-    self->raw_pos = 0;
-
-end:
-    res = PyLong_FromSsize_t(written);
-
-error:
-    LEAVE_BUFFERED(self)
-    PyBuffer_Release(&buf);
-    return res;
-}
-
-static PyMethodDef bufferedwriter_methods[] = {
-    /* BufferedIOMixin methods */
-    {"close", (PyCFunction)buffered_close, METH_NOARGS},
-    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
-    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
-    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
-    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
-    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
-    {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
-    {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
-
-    {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
-    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
-    {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
-    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
-    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
-    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef bufferedwriter_members[] = {
-    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
-    {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0},
-    {NULL}
-};
-
-static PyGetSetDef bufferedwriter_getset[] = {
-    {"closed", (getter)buffered_closed_get, NULL, NULL},
-    {"name", (getter)buffered_name_get, NULL, NULL},
-    {"mode", (getter)buffered_mode_get, NULL, NULL},
-    {NULL}
-};
-
-
-PyTypeObject PyBufferedWriter_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.BufferedWriter",       /*tp_name*/
-    sizeof(buffered),           /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)buffered_dealloc,     /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    (reprfunc)buffered_repr,    /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,   /*tp_flags*/
-    bufferedwriter_doc,         /* tp_doc */
-    (traverseproc)buffered_traverse, /* tp_traverse */
-    (inquiry)buffered_clear,    /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    bufferedwriter_methods,     /* tp_methods */
-    bufferedwriter_members,     /* tp_members */
-    bufferedwriter_getset,      /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(buffered, dict),   /* tp_dictoffset */
-    (initproc)bufferedwriter_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
-

-
-
-/*
- * BufferedRWPair
- */
-
-PyDoc_STRVAR(bufferedrwpair_doc,
-    "A buffered reader and writer object together.\n"
-    "\n"
-    "A buffered reader object and buffered writer object put together to\n"
-    "form a sequential IO object that can read and write. This is typically\n"
-    "used with a socket or two-way pipe.\n"
-    "\n"
-    "reader and writer are RawIOBase objects that are readable and\n"
-    "writeable respectively. If the buffer_size is omitted it defaults to\n"
-    "DEFAULT_BUFFER_SIZE.\n"
-    );
-
-/* XXX The usefulness of this (compared to having two separate IO objects) is
- * questionable.
- */
-
-typedef struct {
-    PyObject_HEAD
-    buffered *reader;
-    buffered *writer;
-    PyObject *dict;
-    PyObject *weakreflist;
-} rwpair;
-
-static int
-bufferedrwpair_init(rwpair *self, PyObject *args, PyObject *kwds)
-{
-    PyObject *reader, *writer;
     Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
 
-    if (!PyArg_ParseTuple(args, "OO|n:BufferedRWPair", &reader, &writer,
-                          &buffer_size)) {
-        return -1;
-    }
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "O|n:BufferedRandom", _keywords,
+        &raw, &buffer_size))
+        goto exit;
+    return_value = _io_BufferedRandom___init___impl((buffered *)self, raw, buffer_size);
 
-    if (_PyIOBase_check_readable(reader, Py_True) == NULL)
-        return -1;
-    if (_PyIOBase_check_writable(writer, Py_True) == NULL)
-        return -1;
-
-    self->reader = (buffered *) PyObject_CallFunction(
-            (PyObject *) &PyBufferedReader_Type, "On", reader, buffer_size);
-    if (self->reader == NULL)
-        return -1;
-
-    self->writer = (buffered *) PyObject_CallFunction(
-            (PyObject *) &PyBufferedWriter_Type, "On", writer, buffer_size);
-    if (self->writer == NULL) {
-        Py_CLEAR(self->reader);
-        return -1;
-    }
-
-    return 0;
+exit:
+    return return_value;
 }
-
-static int
-bufferedrwpair_traverse(rwpair *self, visitproc visit, void *arg)
-{
-    Py_VISIT(self->dict);
-    return 0;
-}
-
-static int
-bufferedrwpair_clear(rwpair *self)
-{
-    Py_CLEAR(self->reader);
-    Py_CLEAR(self->writer);
-    Py_CLEAR(self->dict);
-    return 0;
-}
-
-static void
-bufferedrwpair_dealloc(rwpair *self)
-{
-    _PyObject_GC_UNTRACK(self);
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *)self);
-    Py_CLEAR(self->reader);
-    Py_CLEAR(self->writer);
-    Py_CLEAR(self->dict);
-    Py_TYPE(self)->tp_free((PyObject *) self);
-}
-
-static PyObject *
-_forward_call(buffered *self, _Py_Identifier *name, PyObject *args)
-{
-    PyObject *func, *ret;
-    if (self == NULL) {
-        PyErr_SetString(PyExc_ValueError,
-                        "I/O operation on uninitialized object");
-        return NULL;
-    }
-
-    func = _PyObject_GetAttrId((PyObject *)self, name);
-    if (func == NULL) {
-        PyErr_SetString(PyExc_AttributeError, name->string);
-        return NULL;
-    }
-
-    ret = PyObject_CallObject(func, args);
-    Py_DECREF(func);
-    return ret;
-}
-
-static PyObject *
-bufferedrwpair_read(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->reader, &PyId_read, args);
-}
-
-static PyObject *
-bufferedrwpair_peek(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->reader, &PyId_peek, args);
-}
-
-static PyObject *
-bufferedrwpair_read1(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->reader, &PyId_read1, args);
-}
-
-static PyObject *
-bufferedrwpair_readinto(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->reader, &PyId_readinto, args);
-}
-
-static PyObject *
-bufferedrwpair_readinto1(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->reader, &PyId_readinto1, args);
-}
-
-static PyObject *
-bufferedrwpair_write(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->writer, &PyId_write, args);
-}
-
-static PyObject *
-bufferedrwpair_flush(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->writer, &PyId_flush, args);
-}
-
-static PyObject *
-bufferedrwpair_readable(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->reader, &PyId_readable, args);
-}
-
-static PyObject *
-bufferedrwpair_writable(rwpair *self, PyObject *args)
-{
-    return _forward_call(self->writer, &PyId_writable, args);
-}
-
-static PyObject *
-bufferedrwpair_close(rwpair *self, PyObject *args)
-{
-    PyObject *exc = NULL, *val, *tb;
-    PyObject *ret = _forward_call(self->writer, &PyId_close, args);
-    if (ret == NULL)
-        PyErr_Fetch(&exc, &val, &tb);
-    else
-        Py_DECREF(ret);
-    ret = _forward_call(self->reader, &PyId_close, args);
-    if (exc != NULL) {
-        _PyErr_ChainExceptions(exc, val, tb);
-        Py_CLEAR(ret);
-    }
-    return ret;
-}
-
-static PyObject *
-bufferedrwpair_isatty(rwpair *self, PyObject *args)
-{
-    PyObject *ret = _forward_call(self->writer, &PyId_isatty, args);
-
-    if (ret != Py_False) {
-        /* either True or exception */
-        return ret;
-    }
-    Py_DECREF(ret);
-
-    return _forward_call(self->reader, &PyId_isatty, args);
-}
-
-static PyObject *
-bufferedrwpair_closed_get(rwpair *self, void *context)
-{
-    if (self->writer == NULL) {
-        PyErr_SetString(PyExc_RuntimeError,
-                "the BufferedRWPair object is being garbage-collected");
-        return NULL;
-    }
-    return PyObject_GetAttr((PyObject *) self->writer, _PyIO_str_closed);
-}
-
-static PyMethodDef bufferedrwpair_methods[] = {
-    {"read", (PyCFunction)bufferedrwpair_read, METH_VARARGS},
-    {"peek", (PyCFunction)bufferedrwpair_peek, METH_VARARGS},
-    {"read1", (PyCFunction)bufferedrwpair_read1, METH_VARARGS},
-    {"readinto", (PyCFunction)bufferedrwpair_readinto, METH_VARARGS},
-    {"readinto1", (PyCFunction)bufferedrwpair_readinto1, METH_VARARGS},
-
-    {"write", (PyCFunction)bufferedrwpair_write, METH_VARARGS},
-    {"flush", (PyCFunction)bufferedrwpair_flush, METH_NOARGS},
-
-    {"readable", (PyCFunction)bufferedrwpair_readable, METH_NOARGS},
-    {"writable", (PyCFunction)bufferedrwpair_writable, METH_NOARGS},
-
-    {"close", (PyCFunction)bufferedrwpair_close, METH_NOARGS},
-    {"isatty", (PyCFunction)bufferedrwpair_isatty, METH_NOARGS},
-
-    {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
-
-    {NULL, NULL}
-};
-
-static PyGetSetDef bufferedrwpair_getset[] = {
-    {"closed", (getter)bufferedrwpair_closed_get, NULL, NULL},
-    {NULL}
-};
-
-PyTypeObject PyBufferedRWPair_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.BufferedRWPair",       /*tp_name*/
-    sizeof(rwpair),            /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)bufferedrwpair_dealloc,     /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,   /* tp_flags */
-    bufferedrwpair_doc,         /* tp_doc */
-    (traverseproc)bufferedrwpair_traverse, /* tp_traverse */
-    (inquiry)bufferedrwpair_clear, /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(rwpair, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    bufferedrwpair_methods,     /* tp_methods */
-    0,                          /* tp_members */
-    bufferedrwpair_getset,      /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(rwpair, dict),     /* tp_dictoffset */
-    (initproc)bufferedrwpair_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
-

-
-
-/*
- * BufferedRandom
- */
-
-PyDoc_STRVAR(bufferedrandom_doc,
-    "A buffered interface to random access streams.\n"
-    "\n"
-    "The constructor creates a reader and writer for a seekable stream,\n"
-    "raw, given in the first argument. If the buffer_size is omitted it\n"
-    "defaults to DEFAULT_BUFFER_SIZE.\n"
-    );
-
-static int
-bufferedrandom_init(buffered *self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"raw", "buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    PyObject *raw;
-
-    self->ok = 0;
-    self->detached = 0;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedRandom", kwlist,
-                                     &raw, &buffer_size)) {
-        return -1;
-    }
-
-    if (_PyIOBase_check_seekable(raw, Py_True) == NULL)
-        return -1;
-    if (_PyIOBase_check_readable(raw, Py_True) == NULL)
-        return -1;
-    if (_PyIOBase_check_writable(raw, Py_True) == NULL)
-        return -1;
-
-    Py_CLEAR(self->raw);
-    Py_INCREF(raw);
-    self->raw = raw;
-    self->buffer_size = buffer_size;
-    self->readable = 1;
-    self->writable = 1;
-
-    if (_buffered_init(self) < 0)
-        return -1;
-    _bufferedreader_reset_buf(self);
-    _bufferedwriter_reset_buf(self);
-    self->pos = 0;
-
-    self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedRandom_Type &&
-                                Py_TYPE(raw) == &PyFileIO_Type);
-
-    self->ok = 1;
-    return 0;
-}
-
-static PyMethodDef bufferedrandom_methods[] = {
-    /* BufferedIOMixin methods */
-    {"close", (PyCFunction)buffered_close, METH_NOARGS},
-    {"detach", (PyCFunction)buffered_detach, METH_NOARGS},
-    {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)buffered_readable, METH_NOARGS},
-    {"writable", (PyCFunction)buffered_writable, METH_NOARGS},
-    {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS},
-    {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS},
-    {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O},
-    {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS},
-
-    {"flush", (PyCFunction)buffered_flush, METH_NOARGS},
-
-    {"seek", (PyCFunction)buffered_seek, METH_VARARGS},
-    {"tell", (PyCFunction)buffered_tell, METH_NOARGS},
-    {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS},
-    {"read", (PyCFunction)buffered_read, METH_VARARGS},
-    {"read1", (PyCFunction)buffered_read1, METH_VARARGS},
-    {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS},
-    {"readinto1", (PyCFunction)buffered_readinto1, METH_VARARGS},
-    {"readline", (PyCFunction)buffered_readline, METH_VARARGS},
-    {"peek", (PyCFunction)buffered_peek, METH_VARARGS},
-    {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS},
-    {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef bufferedrandom_members[] = {
-    {"raw", T_OBJECT, offsetof(buffered, raw), READONLY},
-    {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0},
-    {NULL}
-};
-
-static PyGetSetDef bufferedrandom_getset[] = {
-    {"closed", (getter)buffered_closed_get, NULL, NULL},
-    {"name", (getter)buffered_name_get, NULL, NULL},
-    {"mode", (getter)buffered_mode_get, NULL, NULL},
-    {NULL}
-};
-
-
-PyTypeObject PyBufferedRandom_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.BufferedRandom",       /*tp_name*/
-    sizeof(buffered),           /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)buffered_dealloc,     /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    (reprfunc)buffered_repr,    /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,   /*tp_flags*/
-    bufferedrandom_doc,         /* tp_doc */
-    (traverseproc)buffered_traverse, /* tp_traverse */
-    (inquiry)buffered_clear,    /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(buffered, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    (iternextfunc)buffered_iternext, /* tp_iternext */
-    bufferedrandom_methods,     /* tp_methods */
-    bufferedrandom_members,     /* tp_members */
-    bufferedrandom_getset,      /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /*tp_dict*/
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(buffered, dict), /*tp_dictoffset*/
-    (initproc)bufferedrandom_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
+/*[clinic end generated code: output=78808e39f36e3fa9 input=a9049054013a1b77]*/
diff --git a/Modules/_io/bytesio.c b/Modules/_io/clinic/bytesio.c.h
copy from Modules/_io/bytesio.c
copy to Modules/_io/clinic/bytesio.c.h
--- a/Modules/_io/bytesio.c
+++ b/Modules/_io/clinic/bytesio.c.h
@@ -1,593 +1,331 @@
-#include "Python.h"
-#include "structmember.h"       /* for offsetof() */
-#include "_iomodule.h"
+/*[clinic input]
+preserve
+[clinic start generated code]*/
 
-typedef struct {
-    PyObject_HEAD
-    PyObject *buf;
-    Py_ssize_t pos;
-    Py_ssize_t string_size;
-    PyObject *dict;
-    PyObject *weakreflist;
-    Py_ssize_t exports;
-} bytesio;
+PyDoc_STRVAR(_io_BytesIO_readable__doc__,
+"readable($self, /)\n"
+"--\n"
+"\n"
+"Returns True if the IO object can be read.");
 
-typedef struct {
-    PyObject_HEAD
-    bytesio *source;
-} bytesiobuf;
+#define _IO_BYTESIO_READABLE_METHODDEF    \
+    {"readable", (PyCFunction)_io_BytesIO_readable, METH_NOARGS, _io_BytesIO_readable__doc__},
 
-/* The bytesio object can be in three states:
-  * Py_REFCNT(buf) == 1, exports == 0.
-  * Py_REFCNT(buf) > 1.  exports == 0,
-    first modification or export causes the internal buffer copying.
-  * exports > 0.  Py_REFCNT(buf) == 1, any modifications are forbidden.
-*/
+static PyObject *
+_io_BytesIO_readable_impl(bytesio *self);
 
-#define CHECK_CLOSED(self)                                  \
-    if ((self)->buf == NULL) {                              \
-        PyErr_SetString(PyExc_ValueError,                   \
-                        "I/O operation on closed file.");   \
-        return NULL;                                        \
-    }
-
-#define CHECK_EXPORTS(self) \
-    if ((self)->exports > 0) { \
-        PyErr_SetString(PyExc_BufferError, \
-                        "Existing exports of data: object cannot be re-sized"); \
-        return NULL; \
-    }
-
-#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1)
-
-
-/* Internal routine to get a line from the buffer of a BytesIO
-   object. Returns the length between the current position to the
-   next newline character. */
-static Py_ssize_t
-scan_eol(bytesio *self, Py_ssize_t len)
+static PyObject *
+_io_BytesIO_readable(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    const char *start, *n;
-    Py_ssize_t maxlen;
-
-    assert(self->buf != NULL);
-
-    /* Move to the end of the line, up to the end of the string, s. */
-    start = PyBytes_AS_STRING(self->buf) + self->pos;
-    maxlen = self->string_size - self->pos;
-    if (len < 0 || len > maxlen)
-        len = maxlen;
-
-    if (len) {
-        n = memchr(start, '\n', len);
-        if (n)
-            /* Get the length from the current position to the end of
-               the line. */
-            len = n - start + 1;
-    }
-    assert(len >= 0);
-    assert(self->pos < PY_SSIZE_T_MAX - len);
-
-    return len;
+    return _io_BytesIO_readable_impl(self);
 }
 
-/* Internal routine for detaching the shared buffer of BytesIO objects.
-   The caller should ensure that the 'size' argument is non-negative and
-   not lesser than self->string_size.  Returns 0 on success, -1 otherwise. */
-static int
-unshare_buffer(bytesio *self, size_t size)
+PyDoc_STRVAR(_io_BytesIO_writable__doc__,
+"writable($self, /)\n"
+"--\n"
+"\n"
+"Returns True if the IO object can be written.");
+
+#define _IO_BYTESIO_WRITABLE_METHODDEF    \
+    {"writable", (PyCFunction)_io_BytesIO_writable, METH_NOARGS, _io_BytesIO_writable__doc__},
+
+static PyObject *
+_io_BytesIO_writable_impl(bytesio *self);
+
+static PyObject *
+_io_BytesIO_writable(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *new_buf, *old_buf;
-    assert(SHARED_BUF(self));
-    assert(self->exports == 0);
-    assert(size >= (size_t)self->string_size);
-    new_buf = PyBytes_FromStringAndSize(NULL, size);
-    if (new_buf == NULL)
-        return -1;
-    memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf),
-           self->string_size);
-    old_buf = self->buf;
-    self->buf = new_buf;
-    Py_DECREF(old_buf);
-    return 0;
+    return _io_BytesIO_writable_impl(self);
 }
 
-/* Internal routine for changing the size of the buffer of BytesIO objects.
-   The caller should ensure that the 'size' argument is non-negative.  Returns
-   0 on success, -1 otherwise. */
-static int
-resize_buffer(bytesio *self, size_t size)
+PyDoc_STRVAR(_io_BytesIO_seekable__doc__,
+"seekable($self, /)\n"
+"--\n"
+"\n"
+"Returns True if the IO object can be seeked.");
+
+#define _IO_BYTESIO_SEEKABLE_METHODDEF    \
+    {"seekable", (PyCFunction)_io_BytesIO_seekable, METH_NOARGS, _io_BytesIO_seekable__doc__},
+
+static PyObject *
+_io_BytesIO_seekable_impl(bytesio *self);
+
+static PyObject *
+_io_BytesIO_seekable(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    /* Here, unsigned types are used to avoid dealing with signed integer
-       overflow, which is undefined in C. */
-    size_t alloc = PyBytes_GET_SIZE(self->buf);
-
-    assert(self->buf != NULL);
-
-    /* For simplicity, stay in the range of the signed type. Anyway, Python
-       doesn't allow strings to be longer than this. */
-    if (size > PY_SSIZE_T_MAX)
-        goto overflow;
-
-    if (size < alloc / 2) {
-        /* Major downsize; resize down to exact size. */
-        alloc = size + 1;
-    }
-    else if (size < alloc) {
-        /* Within allocated size; quick exit */
-        return 0;
-    }
-    else if (size <= alloc * 1.125) {
-        /* Moderate upsize; overallocate similar to list_resize() */
-        alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
-    }
-    else {
-        /* Major upsize; resize up to exact size */
-        alloc = size + 1;
-    }
-
-    if (alloc > ((size_t)-1) / sizeof(char))
-        goto overflow;
-
-    if (SHARED_BUF(self)) {
-        if (unshare_buffer(self, alloc) < 0)
-            return -1;
-    }
-    else {
-        if (_PyBytes_Resize(&self->buf, alloc) < 0)
-            return -1;
-    }
-
-    return 0;
-
-  overflow:
-    PyErr_SetString(PyExc_OverflowError,
-                    "new buffer size too large");
-    return -1;
+    return _io_BytesIO_seekable_impl(self);
 }
 
-/* Internal routine for writing a string of bytes to the buffer of a BytesIO
-   object. Returns the number of bytes written, or -1 on error. */
-static Py_ssize_t
-write_bytes(bytesio *self, const char *bytes, Py_ssize_t len)
+PyDoc_STRVAR(_io_BytesIO_flush__doc__,
+"flush($self, /)\n"
+"--\n"
+"\n"
+"Does nothing.");
+
+#define _IO_BYTESIO_FLUSH_METHODDEF    \
+    {"flush", (PyCFunction)_io_BytesIO_flush, METH_NOARGS, _io_BytesIO_flush__doc__},
+
+static PyObject *
+_io_BytesIO_flush_impl(bytesio *self);
+
+static PyObject *
+_io_BytesIO_flush(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    size_t endpos;
-    assert(self->buf != NULL);
-    assert(self->pos >= 0);
-    assert(len >= 0);
-
-    endpos = (size_t)self->pos + len;
-    if (endpos > (size_t)PyBytes_GET_SIZE(self->buf)) {
-        if (resize_buffer(self, endpos) < 0)
-            return -1;
-    }
-    else if (SHARED_BUF(self)) {
-        if (unshare_buffer(self, Py_MAX(endpos, (size_t)self->string_size)) < 0)
-            return -1;
-    }
-
-    if (self->pos > self->string_size) {
-        /* In case of overseek, pad with null bytes the buffer region between
-           the end of stream and the current position.
-
-          0   lo      string_size                           hi
-          |   |<---used--->|<----------available----------->|
-          |   |            <--to pad-->|<---to write--->    |
-          0   buf                   position
-        */
-        memset(PyBytes_AS_STRING(self->buf) + self->string_size, '\0',
-               (self->pos - self->string_size) * sizeof(char));
-    }
-
-    /* Copy the data to the internal buffer, overwriting some of the existing
-       data if self->pos < self->string_size. */
-    memcpy(PyBytes_AS_STRING(self->buf) + self->pos, bytes, len);
-    self->pos = endpos;
-
-    /* Set the new length of the internal string if it has changed. */
-    if ((size_t)self->string_size < endpos) {
-        self->string_size = endpos;
-    }
-
-    return len;
+    return _io_BytesIO_flush_impl(self);
 }
 
-static PyObject *
-bytesio_get_closed(bytesio *self)
-{
-    if (self->buf == NULL) {
-        Py_RETURN_TRUE;
-    }
-    else {
-        Py_RETURN_FALSE;
-    }
-}
-
-PyDoc_STRVAR(readable_doc,
-"readable() -> bool. Returns True if the IO object can be read.");
-
-PyDoc_STRVAR(writable_doc,
-"writable() -> bool. Returns True if the IO object can be written.");
-
-PyDoc_STRVAR(seekable_doc,
-"seekable() -> bool. Returns True if the IO object can be seeked.");
-
-/* Generic getter for the writable, readable and seekable properties */
-static PyObject *
-return_not_closed(bytesio *self)
-{
-    CHECK_CLOSED(self);
-    Py_RETURN_TRUE;
-}
-
-PyDoc_STRVAR(flush_doc,
-"flush() -> None.  Does nothing.");
-
-static PyObject *
-bytesio_flush(bytesio *self)
-{
-    CHECK_CLOSED(self);
-    Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(getbuffer_doc,
-"getbuffer() -> bytes.\n"
+PyDoc_STRVAR(_io_BytesIO_getbuffer__doc__,
+"getbuffer($self, /)\n"
+"--\n"
 "\n"
 "Get a read-write view over the contents of the BytesIO object.");
 
+#define _IO_BYTESIO_GETBUFFER_METHODDEF    \
+    {"getbuffer", (PyCFunction)_io_BytesIO_getbuffer, METH_NOARGS, _io_BytesIO_getbuffer__doc__},
+
 static PyObject *
-bytesio_getbuffer(bytesio *self)
+_io_BytesIO_getbuffer_impl(bytesio *self);
+
+static PyObject *
+_io_BytesIO_getbuffer(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    PyTypeObject *type = &_PyBytesIOBuffer_Type;
-    bytesiobuf *buf;
-    PyObject *view;
-
-    CHECK_CLOSED(self);
-
-    buf = (bytesiobuf *) type->tp_alloc(type, 0);
-    if (buf == NULL)
-        return NULL;
-    Py_INCREF(self);
-    buf->source = self;
-    view = PyMemoryView_FromObject((PyObject *) buf);
-    Py_DECREF(buf);
-    return view;
+    return _io_BytesIO_getbuffer_impl(self);
 }
 
-PyDoc_STRVAR(getval_doc,
-"getvalue() -> bytes.\n"
+PyDoc_STRVAR(_io_BytesIO_getvalue__doc__,
+"getvalue($self, /)\n"
+"--\n"
 "\n"
 "Retrieve the entire contents of the BytesIO object.");
 
+#define _IO_BYTESIO_GETVALUE_METHODDEF    \
+    {"getvalue", (PyCFunction)_io_BytesIO_getvalue, METH_NOARGS, _io_BytesIO_getvalue__doc__},
+
 static PyObject *
-bytesio_getvalue(bytesio *self)
+_io_BytesIO_getvalue_impl(bytesio *self);
+
+static PyObject *
+_io_BytesIO_getvalue(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    CHECK_CLOSED(self);
-    if (self->string_size <= 1 || self->exports > 0)
-        return PyBytes_FromStringAndSize(PyBytes_AS_STRING(self->buf),
-                                         self->string_size);
-
-    if (self->string_size != PyBytes_GET_SIZE(self->buf)) {
-        if (SHARED_BUF(self)) {
-            if (unshare_buffer(self, self->string_size) < 0)
-                return NULL;
-        }
-        else {
-            if (_PyBytes_Resize(&self->buf, self->string_size) < 0)
-                return NULL;
-        }
-    }
-    Py_INCREF(self->buf);
-    return self->buf;
+    return _io_BytesIO_getvalue_impl(self);
 }
 
-PyDoc_STRVAR(isatty_doc,
-"isatty() -> False.\n"
+PyDoc_STRVAR(_io_BytesIO_isatty__doc__,
+"isatty($self, /)\n"
+"--\n"
 "\n"
-"Always returns False since BytesIO objects are not connected\n"
-"to a tty-like device.");
+"Always returns False.\n"
+"\n"
+"BytesIO objects are not connected to a TTY-like device.");
+
+#define _IO_BYTESIO_ISATTY_METHODDEF    \
+    {"isatty", (PyCFunction)_io_BytesIO_isatty, METH_NOARGS, _io_BytesIO_isatty__doc__},
 
 static PyObject *
-bytesio_isatty(bytesio *self)
+_io_BytesIO_isatty_impl(bytesio *self);
+
+static PyObject *
+_io_BytesIO_isatty(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    CHECK_CLOSED(self);
-    Py_RETURN_FALSE;
+    return _io_BytesIO_isatty_impl(self);
 }
 
-PyDoc_STRVAR(tell_doc,
-"tell() -> current file position, an integer\n");
+PyDoc_STRVAR(_io_BytesIO_tell__doc__,
+"tell($self, /)\n"
+"--\n"
+"\n"
+"Current file position, an integer.");
+
+#define _IO_BYTESIO_TELL_METHODDEF    \
+    {"tell", (PyCFunction)_io_BytesIO_tell, METH_NOARGS, _io_BytesIO_tell__doc__},
 
 static PyObject *
-bytesio_tell(bytesio *self)
+_io_BytesIO_tell_impl(bytesio *self);
+
+static PyObject *
+_io_BytesIO_tell(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    CHECK_CLOSED(self);
-    return PyLong_FromSsize_t(self->pos);
+    return _io_BytesIO_tell_impl(self);
 }
 
-static PyObject *
-read_bytes(bytesio *self, Py_ssize_t size)
-{
-    char *output;
-
-    assert(self->buf != NULL);
-    assert(size <= self->string_size);
-    if (size > 1 &&
-        self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) &&
-        self->exports == 0) {
-        self->pos += size;
-        Py_INCREF(self->buf);
-        return self->buf;
-    }
-
-    output = PyBytes_AS_STRING(self->buf) + self->pos;
-    self->pos += size;
-    return PyBytes_FromStringAndSize(output, size);
-}
-
-PyDoc_STRVAR(read_doc,
-"read([size]) -> read at most size bytes, returned as a bytes object.\n"
+PyDoc_STRVAR(_io_BytesIO_read__doc__,
+"read($self, size=None, /)\n"
+"--\n"
+"\n"
+"Read at most size bytes, returned as a bytes object.\n"
 "\n"
 "If the size argument is negative, read until EOF is reached.\n"
 "Return an empty bytes object at EOF.");
 
+#define _IO_BYTESIO_READ_METHODDEF    \
+    {"read", (PyCFunction)_io_BytesIO_read, METH_VARARGS, _io_BytesIO_read__doc__},
+
 static PyObject *
-bytesio_read(bytesio *self, PyObject *args)
+_io_BytesIO_read_impl(bytesio *self, PyObject *arg);
+
+static PyObject *
+_io_BytesIO_read(bytesio *self, PyObject *args)
 {
-    Py_ssize_t size, n;
+    PyObject *return_value = NULL;
     PyObject *arg = Py_None;
 
-    CHECK_CLOSED(self);
+    if (!PyArg_UnpackTuple(args, "read",
+        0, 1,
+        &arg))
+        goto exit;
+    return_value = _io_BytesIO_read_impl(self, arg);
 
-    if (!PyArg_ParseTuple(args, "|O:read", &arg))
-        return NULL;
-
-    if (PyLong_Check(arg)) {
-        size = PyLong_AsSsize_t(arg);
-        if (size == -1 && PyErr_Occurred())
-            return NULL;
-    }
-    else if (arg == Py_None) {
-        /* Read until EOF is reached, by default. */
-        size = -1;
-    }
-    else {
-        PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
-                     Py_TYPE(arg)->tp_name);
-        return NULL;
-    }
-
-    /* adjust invalid sizes */
-    n = self->string_size - self->pos;
-    if (size < 0 || size > n) {
-        size = n;
-        if (size < 0)
-            size = 0;
-    }
-
-    return read_bytes(self, size);
+exit:
+    return return_value;
 }
 
-
-PyDoc_STRVAR(read1_doc,
-"read1(size) -> read at most size bytes, returned as a bytes object.\n"
+PyDoc_STRVAR(_io_BytesIO_read1__doc__,
+"read1($self, size, /)\n"
+"--\n"
+"\n"
+"Read at most size bytes, returned as a bytes object.\n"
 "\n"
 "If the size argument is negative or omitted, read until EOF is reached.\n"
 "Return an empty bytes object at EOF.");
 
-static PyObject *
-bytesio_read1(bytesio *self, PyObject *n)
-{
-    PyObject *arg, *res;
+#define _IO_BYTESIO_READ1_METHODDEF    \
+    {"read1", (PyCFunction)_io_BytesIO_read1, METH_O, _io_BytesIO_read1__doc__},
 
-    arg = PyTuple_Pack(1, n);
-    if (arg == NULL)
-        return NULL;
-    res  = bytesio_read(self, arg);
-    Py_DECREF(arg);
-    return res;
-}
-
-PyDoc_STRVAR(readline_doc,
-"readline([size]) -> next line from the file, as a bytes object.\n"
+PyDoc_STRVAR(_io_BytesIO_readline__doc__,
+"readline($self, size=None, /)\n"
+"--\n"
+"\n"
+"Next line from the file, as a bytes object.\n"
 "\n"
 "Retain newline.  A non-negative size argument limits the maximum\n"
 "number of bytes to return (an incomplete line may be returned then).\n"
-"Return an empty bytes object at EOF.\n");
+"Return an empty bytes object at EOF.");
+
+#define _IO_BYTESIO_READLINE_METHODDEF    \
+    {"readline", (PyCFunction)_io_BytesIO_readline, METH_VARARGS, _io_BytesIO_readline__doc__},
 
 static PyObject *
-bytesio_readline(bytesio *self, PyObject *args)
+_io_BytesIO_readline_impl(bytesio *self, PyObject *arg);
+
+static PyObject *
+_io_BytesIO_readline(bytesio *self, PyObject *args)
 {
-    Py_ssize_t size, n;
+    PyObject *return_value = NULL;
     PyObject *arg = Py_None;
 
-    CHECK_CLOSED(self);
+    if (!PyArg_UnpackTuple(args, "readline",
+        0, 1,
+        &arg))
+        goto exit;
+    return_value = _io_BytesIO_readline_impl(self, arg);
 
-    if (!PyArg_ParseTuple(args, "|O:readline", &arg))
-        return NULL;
-
-    if (PyLong_Check(arg)) {
-        size = PyLong_AsSsize_t(arg);
-        if (size == -1 && PyErr_Occurred())
-            return NULL;
-    }
-    else if (arg == Py_None) {
-        /* No size limit, by default. */
-        size = -1;
-    }
-    else {
-        PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
-                     Py_TYPE(arg)->tp_name);
-        return NULL;
-    }
-
-    n = scan_eol(self, size);
-
-    return read_bytes(self, n);
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(readlines_doc,
-"readlines([size]) -> list of strings, each a line from the file.\n"
+PyDoc_STRVAR(_io_BytesIO_readlines__doc__,
+"readlines($self, size=None, /)\n"
+"--\n"
+"\n"
+"List of bytes objects, each a line from the file.\n"
 "\n"
 "Call readline() repeatedly and return a list of the lines so read.\n"
 "The optional size argument, if given, is an approximate bound on the\n"
-"total number of bytes in the lines returned.\n");
+"total number of bytes in the lines returned.");
+
+#define _IO_BYTESIO_READLINES_METHODDEF    \
+    {"readlines", (PyCFunction)_io_BytesIO_readlines, METH_VARARGS, _io_BytesIO_readlines__doc__},
 
 static PyObject *
-bytesio_readlines(bytesio *self, PyObject *args)
+_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg);
+
+static PyObject *
+_io_BytesIO_readlines(bytesio *self, PyObject *args)
 {
-    Py_ssize_t maxsize, size, n;
-    PyObject *result, *line;
-    char *output;
+    PyObject *return_value = NULL;
     PyObject *arg = Py_None;
 
-    CHECK_CLOSED(self);
+    if (!PyArg_UnpackTuple(args, "readlines",
+        0, 1,
+        &arg))
+        goto exit;
+    return_value = _io_BytesIO_readlines_impl(self, arg);
 
-    if (!PyArg_ParseTuple(args, "|O:readlines", &arg))
-        return NULL;
-
-    if (PyLong_Check(arg)) {
-        maxsize = PyLong_AsSsize_t(arg);
-        if (maxsize == -1 && PyErr_Occurred())
-            return NULL;
-    }
-    else if (arg == Py_None) {
-        /* No size limit, by default. */
-        maxsize = -1;
-    }
-    else {
-        PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
-                     Py_TYPE(arg)->tp_name);
-        return NULL;
-    }
-
-    size = 0;
-    result = PyList_New(0);
-    if (!result)
-        return NULL;
-
-    output = PyBytes_AS_STRING(self->buf) + self->pos;
-    while ((n = scan_eol(self, -1)) != 0) {
-        self->pos += n;
-        line = PyBytes_FromStringAndSize(output, n);
-        if (!line)
-            goto on_error;
-        if (PyList_Append(result, line) == -1) {
-            Py_DECREF(line);
-            goto on_error;
-        }
-        Py_DECREF(line);
-        size += n;
-        if (maxsize > 0 && size >= maxsize)
-            break;
-        output += n;
-    }
-    return result;
-
-  on_error:
-    Py_DECREF(result);
-    return NULL;
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(readinto_doc,
-"readinto(bytearray) -> int.  Read up to len(b) bytes into b.\n"
+PyDoc_STRVAR(_io_BytesIO_readinto__doc__,
+"readinto($self, buffer, /)\n"
+"--\n"
+"\n"
+"Read up to len(buffer) bytes into buffer.\n"
 "\n"
 "Returns number of bytes read (0 for EOF), or None if the object\n"
 "is set not to block as has no data to read.");
 
+#define _IO_BYTESIO_READINTO_METHODDEF    \
+    {"readinto", (PyCFunction)_io_BytesIO_readinto, METH_O, _io_BytesIO_readinto__doc__},
+
 static PyObject *
-bytesio_readinto(bytesio *self, PyObject *arg)
+_io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer);
+
+static PyObject *
+_io_BytesIO_readinto(bytesio *self, PyObject *arg)
 {
-    Py_buffer buffer;
-    Py_ssize_t len, n;
+    PyObject *return_value = NULL;
+    Py_buffer buffer = {NULL, NULL};
 
-    CHECK_CLOSED(self);
+    if (!PyArg_Parse(arg,
+        "w*:readinto",
+        &buffer))
+        goto exit;
+    return_value = _io_BytesIO_readinto_impl(self, &buffer);
 
-    if (!PyArg_Parse(arg, "w*", &buffer))
-        return NULL;
+exit:
+    /* Cleanup for buffer */
+    if (buffer.obj)
+       PyBuffer_Release(&buffer);
 
-    /* adjust invalid sizes */
-    len = buffer.len;
-    n = self->string_size - self->pos;
-    if (len > n) {
-        len = n;
-        if (len < 0)
-            len = 0;
-    }
-
-    memcpy(buffer.buf, PyBytes_AS_STRING(self->buf) + self->pos, len);
-    assert(self->pos + len < PY_SSIZE_T_MAX);
-    assert(len >= 0);
-    self->pos += len;
-    PyBuffer_Release(&buffer);
-
-    return PyLong_FromSsize_t(len);
+    return return_value;
 }
 
-PyDoc_STRVAR(truncate_doc,
-"truncate([size]) -> int.  Truncate the file to at most size bytes.\n"
+PyDoc_STRVAR(_io_BytesIO_truncate__doc__,
+"truncate($self, size=None, /)\n"
+"--\n"
+"\n"
+"Truncate the file to at most size bytes.\n"
 "\n"
 "Size defaults to the current file position, as returned by tell().\n"
-"The current file position is unchanged.  Returns the new size.\n");
+"The current file position is unchanged.  Returns the new size.");
+
+#define _IO_BYTESIO_TRUNCATE_METHODDEF    \
+    {"truncate", (PyCFunction)_io_BytesIO_truncate, METH_VARARGS, _io_BytesIO_truncate__doc__},
 
 static PyObject *
-bytesio_truncate(bytesio *self, PyObject *args)
+_io_BytesIO_truncate_impl(bytesio *self, PyObject *arg);
+
+static PyObject *
+_io_BytesIO_truncate(bytesio *self, PyObject *args)
 {
-    Py_ssize_t size;
+    PyObject *return_value = NULL;
     PyObject *arg = Py_None;
 
-    CHECK_CLOSED(self);
-    CHECK_EXPORTS(self);
+    if (!PyArg_UnpackTuple(args, "truncate",
+        0, 1,
+        &arg))
+        goto exit;
+    return_value = _io_BytesIO_truncate_impl(self, arg);
 
-    if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
-        return NULL;
-
-    if (PyLong_Check(arg)) {
-        size = PyLong_AsSsize_t(arg);
-        if (size == -1 && PyErr_Occurred())
-            return NULL;
-    }
-    else if (arg == Py_None) {
-        /* Truncate to current position if no argument is passed. */
-        size = self->pos;
-    }
-    else {
-        PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
-                     Py_TYPE(arg)->tp_name);
-        return NULL;
-    }
-
-    if (size < 0) {
-        PyErr_Format(PyExc_ValueError,
-                     "negative size value %zd", size);
-        return NULL;
-    }
-
-    if (size < self->string_size) {
-        self->string_size = size;
-        if (resize_buffer(self, size) < 0)
-            return NULL;
-    }
-
-    return PyLong_FromSsize_t(size);
+exit:
+    return return_value;
 }
 
-static PyObject *
-bytesio_iternext(bytesio *self)
-{
-    Py_ssize_t n;
-
-    CHECK_CLOSED(self);
-
-    n = scan_eol(self, -1);
-
-    if (n == 0)
-        return NULL;
-
-    return read_bytes(self, n);
-}
-
-PyDoc_STRVAR(seek_doc,
-"seek(pos, whence=0) -> int.  Change stream position.\n"
+PyDoc_STRVAR(_io_BytesIO_seek__doc__,
+"seek($self, pos, whence=0, /)\n"
+"--\n"
+"\n"
+"Change stream position.\n"
 "\n"
 "Seek to byte offset pos relative to position indicated by whence:\n"
 "     0  Start of stream (the default).  pos should be >= 0;\n"
@@ -595,522 +333,94 @@
 "     2  End of stream - pos usually negative.\n"
 "Returns the new absolute position.");
 
+#define _IO_BYTESIO_SEEK_METHODDEF    \
+    {"seek", (PyCFunction)_io_BytesIO_seek, METH_VARARGS, _io_BytesIO_seek__doc__},
+
 static PyObject *
-bytesio_seek(bytesio *self, PyObject *args)
+_io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence);
+
+static PyObject *
+_io_BytesIO_seek(bytesio *self, PyObject *args)
 {
+    PyObject *return_value = NULL;
     Py_ssize_t pos;
-    int mode = 0;
+    int whence = 0;
 
-    CHECK_CLOSED(self);
+    if (!PyArg_ParseTuple(args,
+        "n|i:seek",
+        &pos, &whence))
+        goto exit;
+    return_value = _io_BytesIO_seek_impl(self, pos, whence);
 
-    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode))
-        return NULL;
-
-    if (pos < 0 && mode == 0) {
-        PyErr_Format(PyExc_ValueError,
-                     "negative seek value %zd", pos);
-        return NULL;
-    }
-
-    /* mode 0: offset relative to beginning of the string.
-       mode 1: offset relative to current position.
-       mode 2: offset relative the end of the string. */
-    if (mode == 1) {
-        if (pos > PY_SSIZE_T_MAX - self->pos) {
-            PyErr_SetString(PyExc_OverflowError,
-                            "new position too large");
-            return NULL;
-        }
-        pos += self->pos;
-    }
-    else if (mode == 2) {
-        if (pos > PY_SSIZE_T_MAX - self->string_size) {
-            PyErr_SetString(PyExc_OverflowError,
-                            "new position too large");
-            return NULL;
-        }
-        pos += self->string_size;
-    }
-    else if (mode != 0) {
-        PyErr_Format(PyExc_ValueError,
-                     "invalid whence (%i, should be 0, 1 or 2)", mode);
-        return NULL;
-    }
-
-    if (pos < 0)
-        pos = 0;
-    self->pos = pos;
-
-    return PyLong_FromSsize_t(self->pos);
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(write_doc,
-"write(bytes) -> int.  Write bytes to file.\n"
+PyDoc_STRVAR(_io_BytesIO_write__doc__,
+"write($self, b, /)\n"
+"--\n"
+"\n"
+"Write bytes to file.\n"
 "\n"
 "Return the number of bytes written.");
 
+#define _IO_BYTESIO_WRITE_METHODDEF    \
+    {"write", (PyCFunction)_io_BytesIO_write, METH_O, _io_BytesIO_write__doc__},
+
+PyDoc_STRVAR(_io_BytesIO_writelines__doc__,
+"writelines($self, lines, /)\n"
+"--\n"
+"\n"
+"Write lines to the file.\n"
+"\n"
+"Note that newlines are not added.  lines can be any iterable object\n"
+"producing bytes-like objects. This is equivalent to calling write() for\n"
+"each element.");
+
+#define _IO_BYTESIO_WRITELINES_METHODDEF    \
+    {"writelines", (PyCFunction)_io_BytesIO_writelines, METH_O, _io_BytesIO_writelines__doc__},
+
+PyDoc_STRVAR(_io_BytesIO_close__doc__,
+"close($self, /)\n"
+"--\n"
+"\n"
+"Disable all I/O operations.");
+
+#define _IO_BYTESIO_CLOSE_METHODDEF    \
+    {"close", (PyCFunction)_io_BytesIO_close, METH_NOARGS, _io_BytesIO_close__doc__},
+
 static PyObject *
-bytesio_write(bytesio *self, PyObject *obj)
+_io_BytesIO_close_impl(bytesio *self);
+
+static PyObject *
+_io_BytesIO_close(bytesio *self, PyObject *Py_UNUSED(ignored))
 {
-    Py_ssize_t n = 0;
-    Py_buffer buf;
-    PyObject *result = NULL;
-
-    CHECK_CLOSED(self);
-    CHECK_EXPORTS(self);
-
-    if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0)
-        return NULL;
-
-    if (buf.len != 0)
-        n = write_bytes(self, buf.buf, buf.len);
-    if (n >= 0)
-        result = PyLong_FromSsize_t(n);
-
-    PyBuffer_Release(&buf);
-    return result;
+    return _io_BytesIO_close_impl(self);
 }
 
-PyDoc_STRVAR(writelines_doc,
-"writelines(lines) -> None.  Write bytes objects to the file.\n"
+PyDoc_STRVAR(_io_BytesIO___init____doc__,
+"BytesIO(initial_bytes=b\'\')\n"
+"--\n"
 "\n"
-"Note that newlines are not added.  The argument can be any iterable\n"
-"object producing bytes objects. This is equivalent to calling write() for\n"
-"each bytes object.");
-
-static PyObject *
-bytesio_writelines(bytesio *self, PyObject *v)
-{
-    PyObject *it, *item;
-    PyObject *ret;
-
-    CHECK_CLOSED(self);
-
-    it = PyObject_GetIter(v);
-    if (it == NULL)
-        return NULL;
-
-    while ((item = PyIter_Next(it)) != NULL) {
-        ret = bytesio_write(self, item);
-        Py_DECREF(item);
-        if (ret == NULL) {
-            Py_DECREF(it);
-            return NULL;
-        }
-        Py_DECREF(ret);
-    }
-    Py_DECREF(it);
-
-    /* See if PyIter_Next failed */
-    if (PyErr_Occurred())
-        return NULL;
-
-    Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(close_doc,
-"close() -> None.  Disable all I/O operations.");
-
-static PyObject *
-bytesio_close(bytesio *self)
-{
-    CHECK_EXPORTS(self);
-    Py_CLEAR(self->buf);
-    Py_RETURN_NONE;
-}
-
-/* Pickling support.
-
-   Note that only pickle protocol 2 and onward are supported since we use
-   extended __reduce__ API of PEP 307 to make BytesIO instances picklable.
-
-   Providing support for protocol < 2 would require the __reduce_ex__ method
-   which is notably long-winded when defined properly.
-
-   For BytesIO, the implementation would similar to one coded for
-   object.__reduce_ex__, but slightly less general. To be more specific, we
-   could call bytesio_getstate directly and avoid checking for the presence of
-   a fallback __reduce__ method. However, we would still need a __newobj__
-   function to use the efficient instance representation of PEP 307.
- */
-
-static PyObject *
-bytesio_getstate(bytesio *self)
-{
-    PyObject *initvalue = bytesio_getvalue(self);
-    PyObject *dict;
-    PyObject *state;
-
-    if (initvalue == NULL)
-        return NULL;
-    if (self->dict == NULL) {
-        Py_INCREF(Py_None);
-        dict = Py_None;
-    }
-    else {
-        dict = PyDict_Copy(self->dict);
-        if (dict == NULL) {
-            Py_DECREF(initvalue);
-            return NULL;
-        }
-    }
-
-    state = Py_BuildValue("(OnN)", initvalue, self->pos, dict);
-    Py_DECREF(initvalue);
-    return state;
-}
-
-static PyObject *
-bytesio_setstate(bytesio *self, PyObject *state)
-{
-    PyObject *result;
-    PyObject *position_obj;
-    PyObject *dict;
-    Py_ssize_t pos;
-
-    assert(state != NULL);
-
-    /* We allow the state tuple to be longer than 3, because we may need
-       someday to extend the object's state without breaking
-       backward-compatibility. */
-    if (!PyTuple_Check(state) || Py_SIZE(state) < 3) {
-        PyErr_Format(PyExc_TypeError,
-                     "%.200s.__setstate__ argument should be 3-tuple, got %.200s",
-                     Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
-        return NULL;
-    }
-    CHECK_EXPORTS(self);
-    /* Reset the object to its default state. This is only needed to handle
-       the case of repeated calls to __setstate__. */
-    self->string_size = 0;
-    self->pos = 0;
-
-    /* Set the value of the internal buffer. If state[0] does not support the
-       buffer protocol, bytesio_write will raise the appropriate TypeError. */
-    result = bytesio_write(self, PyTuple_GET_ITEM(state, 0));
-    if (result == NULL)
-        return NULL;
-    Py_DECREF(result);
-
-    /* Set carefully the position value. Alternatively, we could use the seek
-       method instead of modifying self->pos directly to better protect the
-       object internal state against errneous (or malicious) inputs. */
-    position_obj = PyTuple_GET_ITEM(state, 1);
-    if (!PyLong_Check(position_obj)) {
-        PyErr_Format(PyExc_TypeError,
-                     "second item of state must be an integer, not %.200s",
-                     Py_TYPE(position_obj)->tp_name);
-        return NULL;
-    }
-    pos = PyLong_AsSsize_t(position_obj);
-    if (pos == -1 && PyErr_Occurred())
-        return NULL;
-    if (pos < 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "position value cannot be negative");
-        return NULL;
-    }
-    self->pos = pos;
-
-    /* Set the dictionary of the instance variables. */
-    dict = PyTuple_GET_ITEM(state, 2);
-    if (dict != Py_None) {
-        if (!PyDict_Check(dict)) {
-            PyErr_Format(PyExc_TypeError,
-                         "third item of state should be a dict, got a %.200s",
-                         Py_TYPE(dict)->tp_name);
-            return NULL;
-        }
-        if (self->dict) {
-            /* Alternatively, we could replace the internal dictionary
-               completely. However, it seems more practical to just update it. */
-            if (PyDict_Update(self->dict, dict) < 0)
-                return NULL;
-        }
-        else {
-            Py_INCREF(dict);
-            self->dict = dict;
-        }
-    }
-
-    Py_RETURN_NONE;
-}
-
-static void
-bytesio_dealloc(bytesio *self)
-{
-    _PyObject_GC_UNTRACK(self);
-    if (self->exports > 0) {
-        PyErr_SetString(PyExc_SystemError,
-                        "deallocated BytesIO object has exported buffers");
-        PyErr_Print();
-    }
-    Py_CLEAR(self->buf);
-    Py_CLEAR(self->dict);
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *) self);
-    Py_TYPE(self)->tp_free(self);
-}
-
-static PyObject *
-bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    bytesio *self;
-
-    assert(type != NULL && type->tp_alloc != NULL);
-    self = (bytesio *)type->tp_alloc(type, 0);
-    if (self == NULL)
-        return NULL;
-
-    /* tp_alloc initializes all the fields to zero. So we don't have to
-       initialize them here. */
-
-    self->buf = PyBytes_FromStringAndSize(NULL, 0);
-    if (self->buf == NULL) {
-        Py_DECREF(self);
-        return PyErr_NoMemory();
-    }
-
-    return (PyObject *)self;
-}
+"Buffered I/O implementation using an in-memory bytes buffer.");
 
 static int
-bytesio_init(bytesio *self, PyObject *args, PyObject *kwds)
+_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue);
+
+static int
+_io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-    char *kwlist[] = {"initial_bytes", NULL};
+    int return_value = -1;
+    static char *_keywords[] = {"initial_bytes", NULL};
     PyObject *initvalue = NULL;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:BytesIO", kwlist,
-                                     &initvalue))
-        return -1;
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "|O:BytesIO", _keywords,
+        &initvalue))
+        goto exit;
+    return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue);
 
-    /* In case, __init__ is called multiple times. */
-    self->string_size = 0;
-    self->pos = 0;
-
-    if (self->exports > 0) {
-        PyErr_SetString(PyExc_BufferError,
-                        "Existing exports of data: object cannot be re-sized");
-        return -1;
-    }
-    if (initvalue && initvalue != Py_None) {
-        if (PyBytes_CheckExact(initvalue)) {
-            Py_INCREF(initvalue);
-            Py_XDECREF(self->buf);
-            self->buf = initvalue;
-            self->string_size = PyBytes_GET_SIZE(initvalue);
-        }
-        else {
-            PyObject *res;
-            res = bytesio_write(self, initvalue);
-            if (res == NULL)
-                return -1;
-            Py_DECREF(res);
-            self->pos = 0;
-        }
-    }
-
-    return 0;
+exit:
+    return return_value;
 }
-
-static PyObject *
-bytesio_sizeof(bytesio *self, void *unused)
-{
-    Py_ssize_t res;
-
-    res = sizeof(bytesio);
-    if (self->buf && !SHARED_BUF(self))
-        res += _PySys_GetSizeOf(self->buf);
-    return PyLong_FromSsize_t(res);
-}
-
-static int
-bytesio_traverse(bytesio *self, visitproc visit, void *arg)
-{
-    Py_VISIT(self->dict);
-    return 0;
-}
-
-static int
-bytesio_clear(bytesio *self)
-{
-    Py_CLEAR(self->dict);
-    return 0;
-}
-
-
-static PyGetSetDef bytesio_getsetlist[] = {
-    {"closed",  (getter)bytesio_get_closed, NULL,
-     "True if the file is closed."},
-    {NULL},            /* sentinel */
-};
-
-static struct PyMethodDef bytesio_methods[] = {
-    {"readable",   (PyCFunction)return_not_closed,  METH_NOARGS, readable_doc},
-    {"seekable",   (PyCFunction)return_not_closed,  METH_NOARGS, seekable_doc},
-    {"writable",   (PyCFunction)return_not_closed,  METH_NOARGS, writable_doc},
-    {"close",      (PyCFunction)bytesio_close,      METH_NOARGS, close_doc},
-    {"flush",      (PyCFunction)bytesio_flush,      METH_NOARGS, flush_doc},
-    {"isatty",     (PyCFunction)bytesio_isatty,     METH_NOARGS, isatty_doc},
-    {"tell",       (PyCFunction)bytesio_tell,       METH_NOARGS, tell_doc},
-    {"write",      (PyCFunction)bytesio_write,      METH_O, write_doc},
-    {"writelines", (PyCFunction)bytesio_writelines, METH_O, writelines_doc},
-    {"read1",      (PyCFunction)bytesio_read1,      METH_O, read1_doc},
-    {"readinto",   (PyCFunction)bytesio_readinto,   METH_O, readinto_doc},
-    {"readline",   (PyCFunction)bytesio_readline,   METH_VARARGS, readline_doc},
-    {"readlines",  (PyCFunction)bytesio_readlines,  METH_VARARGS, readlines_doc},
-    {"read",       (PyCFunction)bytesio_read,       METH_VARARGS, read_doc},
-    {"getbuffer",  (PyCFunction)bytesio_getbuffer,  METH_NOARGS,  getbuffer_doc},
-    {"getvalue",   (PyCFunction)bytesio_getvalue,   METH_NOARGS,  getval_doc},
-    {"seek",       (PyCFunction)bytesio_seek,       METH_VARARGS, seek_doc},
-    {"truncate",   (PyCFunction)bytesio_truncate,   METH_VARARGS, truncate_doc},
-    {"__getstate__",  (PyCFunction)bytesio_getstate,  METH_NOARGS, NULL},
-    {"__setstate__",  (PyCFunction)bytesio_setstate,  METH_O, NULL},
-    {"__sizeof__", (PyCFunction)bytesio_sizeof,     METH_NOARGS, NULL},
-    {NULL, NULL}        /* sentinel */
-};
-
-PyDoc_STRVAR(bytesio_doc,
-"BytesIO([buffer]) -> object\n"
-"\n"
-"Create a buffered I/O implementation using an in-memory bytes\n"
-"buffer, ready for reading and writing.");
-
-PyTypeObject PyBytesIO_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.BytesIO",                             /*tp_name*/
-    sizeof(bytesio),                     /*tp_basicsize*/
-    0,                                         /*tp_itemsize*/
-    (destructor)bytesio_dealloc,               /*tp_dealloc*/
-    0,                                         /*tp_print*/
-    0,                                         /*tp_getattr*/
-    0,                                         /*tp_setattr*/
-    0,                                         /*tp_reserved*/
-    0,                                         /*tp_repr*/
-    0,                                         /*tp_as_number*/
-    0,                                         /*tp_as_sequence*/
-    0,                                         /*tp_as_mapping*/
-    0,                                         /*tp_hash*/
-    0,                                         /*tp_call*/
-    0,                                         /*tp_str*/
-    0,                                         /*tp_getattro*/
-    0,                                         /*tp_setattro*/
-    0,                                         /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
-    Py_TPFLAGS_HAVE_GC,                        /*tp_flags*/
-    bytesio_doc,                               /*tp_doc*/
-    (traverseproc)bytesio_traverse,            /*tp_traverse*/
-    (inquiry)bytesio_clear,                    /*tp_clear*/
-    0,                                         /*tp_richcompare*/
-    offsetof(bytesio, weakreflist),      /*tp_weaklistoffset*/
-    PyObject_SelfIter,                         /*tp_iter*/
-    (iternextfunc)bytesio_iternext,            /*tp_iternext*/
-    bytesio_methods,                           /*tp_methods*/
-    0,                                         /*tp_members*/
-    bytesio_getsetlist,                        /*tp_getset*/
-    0,                                         /*tp_base*/
-    0,                                         /*tp_dict*/
-    0,                                         /*tp_descr_get*/
-    0,                                         /*tp_descr_set*/
-    offsetof(bytesio, dict),             /*tp_dictoffset*/
-    (initproc)bytesio_init,                    /*tp_init*/
-    0,                                         /*tp_alloc*/
-    bytesio_new,                               /*tp_new*/
-};
-
-
-/*
- * Implementation of the small intermediate object used by getbuffer().
- * getbuffer() returns a memoryview over this object, which should make it
- * invisible from Python code.
- */
-
-static int
-bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags)
-{
-    bytesio *b = (bytesio *) obj->source;
-
-    if (view == NULL) {
-        PyErr_SetString(PyExc_BufferError,
-            "bytesiobuf_getbuffer: view==NULL argument is obsolete");
-        return -1;
-    }
-    if (SHARED_BUF(b)) {
-        if (unshare_buffer(b, b->string_size) < 0)
-            return -1;
-    }
-
-    /* cannot fail if view != NULL and readonly == 0 */
-    (void)PyBuffer_FillInfo(view, (PyObject*)obj,
-                            PyBytes_AS_STRING(b->buf), b->string_size,
-                            0, flags);
-    b->exports++;
-    return 0;
-}
-
-static void
-bytesiobuf_releasebuffer(bytesiobuf *obj, Py_buffer *view)
-{
-    bytesio *b = (bytesio *) obj->source;
-    b->exports--;
-}
-
-static int
-bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg)
-{
-    Py_VISIT(self->source);
-    return 0;
-}
-
-static void
-bytesiobuf_dealloc(bytesiobuf *self)
-{
-    Py_CLEAR(self->source);
-    Py_TYPE(self)->tp_free(self);
-}
-
-static PyBufferProcs bytesiobuf_as_buffer = {
-    (getbufferproc) bytesiobuf_getbuffer,
-    (releasebufferproc) bytesiobuf_releasebuffer,
-};
-
-PyTypeObject _PyBytesIOBuffer_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io._BytesIOBuffer",                      /*tp_name*/
-    sizeof(bytesiobuf),                        /*tp_basicsize*/
-    0,                                         /*tp_itemsize*/
-    (destructor)bytesiobuf_dealloc,            /*tp_dealloc*/
-    0,                                         /*tp_print*/
-    0,                                         /*tp_getattr*/
-    0,                                         /*tp_setattr*/
-    0,                                         /*tp_reserved*/
-    0,                                         /*tp_repr*/
-    0,                                         /*tp_as_number*/
-    0,                                         /*tp_as_sequence*/
-    0,                                         /*tp_as_mapping*/
-    0,                                         /*tp_hash*/
-    0,                                         /*tp_call*/
-    0,                                         /*tp_str*/
-    0,                                         /*tp_getattro*/
-    0,                                         /*tp_setattro*/
-    &bytesiobuf_as_buffer,                     /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/
-    0,                                         /*tp_doc*/
-    (traverseproc)bytesiobuf_traverse,         /*tp_traverse*/
-    0,                                         /*tp_clear*/
-    0,                                         /*tp_richcompare*/
-    0,                                         /*tp_weaklistoffset*/
-    0,                                         /*tp_iter*/
-    0,                                         /*tp_iternext*/
-    0,                                         /*tp_methods*/
-    0,                                         /*tp_members*/
-    0,                                         /*tp_getset*/
-    0,                                         /*tp_base*/
-    0,                                         /*tp_dict*/
-    0,                                         /*tp_descr_get*/
-    0,                                         /*tp_descr_set*/
-    0,                                         /*tp_dictoffset*/
-    0,                                         /*tp_init*/
-    0,                                         /*tp_alloc*/
-    0,                                         /*tp_new*/
-};
+/*[clinic end generated code: output=e22697ada514f4eb input=a9049054013a1b77]*/
diff --git a/Modules/_io/fileio.c b/Modules/_io/clinic/fileio.c.h
copy from Modules/_io/fileio.c
copy to Modules/_io/clinic/fileio.c.h
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/clinic/fileio.c.h
@@ -1,1026 +1,268 @@
-/* Author: Daniel Stutzbach */
+/*[clinic input]
+preserve
+[clinic start generated code]*/
 
-#define PY_SSIZE_T_CLEAN
-#include "Python.h"
-#include "structmember.h"
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#include <stddef.h> /* For offsetof */
-#include "_iomodule.h"
+PyDoc_STRVAR(_io_FileIO_close__doc__,
+"close($self, /)\n"
+"--\n"
+"\n"
+"Close the file.\n"
+"\n"
+"A closed file cannot be used for further I/O operations.  close() may be\n"
+"called more than once without error.");
 
-/*
- * Known likely problems:
- *
- * - Files larger then 2**32-1
- * - Files with unicode filenames
- * - Passing numbers greater than 2**32-1 when an integer is expected
- * - Making it work on Windows and other oddball platforms
- *
- * To Do:
- *
- * - autoconfify header file inclusion
- */
+#define _IO_FILEIO_CLOSE_METHODDEF    \
+    {"close", (PyCFunction)_io_FileIO_close, METH_NOARGS, _io_FileIO_close__doc__},
 
-#ifdef MS_WINDOWS
-/* can simulate truncate with Win32 API functions; see file_truncate */
-#define HAVE_FTRUNCATE
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#endif
+static PyObject *
+_io_FileIO_close_impl(fileio *self);
 
-#if BUFSIZ < (8*1024)
-#define SMALLCHUNK (8*1024)
-#elif (BUFSIZ >= (2 << 25))
-#error "unreasonable BUFSIZ > 64MB defined"
-#else
-#define SMALLCHUNK BUFSIZ
-#endif
-
-typedef struct {
-    PyObject_HEAD
-    int fd;
-    unsigned int created : 1;
-    unsigned int readable : 1;
-    unsigned int writable : 1;
-    unsigned int appending : 1;
-    signed int seekable : 2; /* -1 means unknown */
-    unsigned int closefd : 1;
-    char finalizing;
-    unsigned int blksize;
-    PyObject *weakreflist;
-    PyObject *dict;
-} fileio;
-
-PyTypeObject PyFileIO_Type;
-
-_Py_IDENTIFIER(name);
-
-#define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type))
-
-int
-_PyFileIO_closed(PyObject *self)
+static PyObject *
+_io_FileIO_close(fileio *self, PyObject *Py_UNUSED(ignored))
 {
-    return ((fileio *)self)->fd < 0;
+    return _io_FileIO_close_impl(self);
 }
 
-/* Because this can call arbitrary code, it shouldn't be called when
-   the refcount is 0 (that is, not directly from tp_dealloc unless
-   the refcount has been temporarily re-incremented). */
-static PyObject *
-fileio_dealloc_warn(fileio *self, PyObject *source)
-{
-    if (self->fd >= 0 && self->closefd) {
-        PyObject *exc, *val, *tb;
-        PyErr_Fetch(&exc, &val, &tb);
-        if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
-                             "unclosed file %R", source)) {
-            /* Spurious errors can appear at shutdown */
-            if (PyErr_ExceptionMatches(PyExc_Warning))
-                PyErr_WriteUnraisable((PyObject *) self);
-        }
-        PyErr_Restore(exc, val, tb);
-    }
-    Py_RETURN_NONE;
-}
-
-static PyObject *
-portable_lseek(int fd, PyObject *posobj, int whence);
-
-static PyObject *portable_lseek(int fd, PyObject *posobj, int whence);
-
-/* Returns 0 on success, -1 with exception set on failure. */
-static int
-internal_close(fileio *self)
-{
-    int err = 0;
-    int save_errno = 0;
-    if (self->fd >= 0) {
-        int fd = self->fd;
-        self->fd = -1;
-        /* fd is accessible and someone else may have closed it */
-        if (_PyVerify_fd(fd)) {
-            Py_BEGIN_ALLOW_THREADS
-            _Py_BEGIN_SUPPRESS_IPH
-            err = close(fd);
-            if (err < 0)
-                save_errno = errno;
-            _Py_END_SUPPRESS_IPH
-            Py_END_ALLOW_THREADS
-        } else {
-            save_errno = errno;
-            err = -1;
-        }
-    }
-    if (err < 0) {
-        errno = save_errno;
-        PyErr_SetFromErrno(PyExc_IOError);
-        return -1;
-    }
-    return 0;
-}
-
-static PyObject *
-fileio_close(fileio *self)
-{
-    PyObject *res;
-    PyObject *exc, *val, *tb;
-    int rc;
-    _Py_IDENTIFIER(close);
-    res = _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type,
-                                 &PyId_close, "O", self);
-    if (!self->closefd) {
-        self->fd = -1;
-        return res;
-    }
-    if (res == NULL)
-        PyErr_Fetch(&exc, &val, &tb);
-    if (self->finalizing) {
-        PyObject *r = fileio_dealloc_warn(self, (PyObject *) self);
-        if (r)
-            Py_DECREF(r);
-        else
-            PyErr_Clear();
-    }
-    rc = internal_close(self);
-    if (res == NULL)
-        _PyErr_ChainExceptions(exc, val, tb);
-    if (rc < 0)
-        Py_CLEAR(res);
-    return res;
-}
-
-static PyObject *
-fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    fileio *self;
-
-    assert(type != NULL && type->tp_alloc != NULL);
-
-    self = (fileio *) type->tp_alloc(type, 0);
-    if (self != NULL) {
-        self->fd = -1;
-        self->created = 0;
-        self->readable = 0;
-        self->writable = 0;
-        self->appending = 0;
-        self->seekable = -1;
-        self->blksize = 0;
-        self->closefd = 1;
-        self->weakreflist = NULL;
-    }
-
-    return (PyObject *) self;
-}
-
-#ifdef O_CLOEXEC
-extern int _Py_open_cloexec_works;
-#endif
-
-static int
-fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
-{
-    fileio *self = (fileio *) oself;
-    static char *kwlist[] = {"file", "mode", "closefd", "opener", NULL};
-    const char *name = NULL;
-    PyObject *nameobj, *stringobj = NULL, *opener = Py_None;
-    char *mode = "r";
-    char *s;
-#ifdef MS_WINDOWS
-    Py_UNICODE *widename = NULL;
-#endif
-    int ret = 0;
-    int rwa = 0, plus = 0;
-    int flags = 0;
-    int fd = -1;
-    int closefd = 1;
-    int fd_is_own = 0;
-#ifdef O_CLOEXEC
-    int *atomic_flag_works = &_Py_open_cloexec_works;
-#elif !defined(MS_WINDOWS)
-    int *atomic_flag_works = NULL;
-#endif
-    struct _Py_stat_struct fdfstat;
-    int async_err = 0;
-
-    assert(PyFileIO_Check(oself));
-    if (self->fd >= 0) {
-        if (self->closefd) {
-            /* Have to close the existing file first. */
-            if (internal_close(self) < 0)
-                return -1;
-        }
-        else
-            self->fd = -1;
-    }
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|siO:fileio",
-                                     kwlist, &nameobj, &mode, &closefd,
-                                     &opener))
-        return -1;
-
-    if (PyFloat_Check(nameobj)) {
-        PyErr_SetString(PyExc_TypeError,
-                        "integer argument expected, got float");
-        return -1;
-    }
-
-    fd = _PyLong_AsInt(nameobj);
-    if (fd < 0) {
-        if (!PyErr_Occurred()) {
-            PyErr_SetString(PyExc_ValueError,
-                            "negative file descriptor");
-            return -1;
-        }
-        PyErr_Clear();
-    }
-
-#ifdef MS_WINDOWS
-    if (PyUnicode_Check(nameobj)) {
-        int rv = _PyUnicode_HasNULChars(nameobj);
-        if (rv) {
-            if (rv != -1)
-                PyErr_SetString(PyExc_ValueError, "embedded null character");
-            return -1;
-        }
-        widename = PyUnicode_AsUnicode(nameobj);
-        if (widename == NULL)
-            return -1;
-    } else
-#endif
-    if (fd < 0)
-    {
-        if (!PyUnicode_FSConverter(nameobj, &stringobj)) {
-            return -1;
-        }
-        name = PyBytes_AS_STRING(stringobj);
-    }
-
-    s = mode;
-    while (*s) {
-        switch (*s++) {
-        case 'x':
-            if (rwa) {
-            bad_mode:
-                PyErr_SetString(PyExc_ValueError,
-                                "Must have exactly one of create/read/write/append "
-                                "mode and at most one plus");
-                goto error;
-            }
-            rwa = 1;
-            self->created = 1;
-            self->writable = 1;
-            flags |= O_EXCL | O_CREAT;
-            break;
-        case 'r':
-            if (rwa)
-                goto bad_mode;
-            rwa = 1;
-            self->readable = 1;
-            break;
-        case 'w':
-            if (rwa)
-                goto bad_mode;
-            rwa = 1;
-            self->writable = 1;
-            flags |= O_CREAT | O_TRUNC;
-            break;
-        case 'a':
-            if (rwa)
-                goto bad_mode;
-            rwa = 1;
-            self->writable = 1;
-            self->appending = 1;
-            flags |= O_APPEND | O_CREAT;
-            break;
-        case 'b':
-            break;
-        case '+':
-            if (plus)
-                goto bad_mode;
-            self->readable = self->writable = 1;
-            plus = 1;
-            break;
-        default:
-            PyErr_Format(PyExc_ValueError,
-                         "invalid mode: %.200s", mode);
-            goto error;
-        }
-    }
-
-    if (!rwa)
-        goto bad_mode;
-
-    if (self->readable && self->writable)
-        flags |= O_RDWR;
-    else if (self->readable)
-        flags |= O_RDONLY;
-    else
-        flags |= O_WRONLY;
-
-#ifdef O_BINARY
-    flags |= O_BINARY;
-#endif
-
-#ifdef MS_WINDOWS
-    flags |= O_NOINHERIT;
-#elif defined(O_CLOEXEC)
-    flags |= O_CLOEXEC;
-#endif
-
-    if (fd >= 0) {
-        self->fd = fd;
-        self->closefd = closefd;
-    }
-    else {
-        self->closefd = 1;
-        if (!closefd) {
-            PyErr_SetString(PyExc_ValueError,
-                "Cannot use closefd=False with file name");
-            goto error;
-        }
-
-        errno = 0;
-        if (opener == Py_None) {
-            do {
-                Py_BEGIN_ALLOW_THREADS
-#ifdef MS_WINDOWS
-                if (widename != NULL)
-                    self->fd = _wopen(widename, flags, 0666);
-                else
-#endif
-                    self->fd = open(name, flags, 0666);
-                Py_END_ALLOW_THREADS
-            } while (self->fd < 0 && errno == EINTR &&
-                     !(async_err = PyErr_CheckSignals()));
-
-            if (async_err)
-                goto error;
-        }
-        else {
-            PyObject *fdobj;
-
-#ifndef MS_WINDOWS
-            /* the opener may clear the atomic flag */
-            atomic_flag_works = NULL;
-#endif
-
-            fdobj = PyObject_CallFunction(opener, "Oi", nameobj, flags);
-            if (fdobj == NULL)
-                goto error;
-            if (!PyLong_Check(fdobj)) {
-                Py_DECREF(fdobj);
-                PyErr_SetString(PyExc_TypeError,
-                        "expected integer from opener");
-                goto error;
-            }
-
-            self->fd = _PyLong_AsInt(fdobj);
-            Py_DECREF(fdobj);
-            if (self->fd == -1) {
-                goto error;
-            }
-        }
-
-        fd_is_own = 1;
-        if (self->fd < 0) {
-            PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
-            goto error;
-        }
-
-#ifndef MS_WINDOWS
-        if (_Py_set_inheritable(self->fd, 0, atomic_flag_works) < 0)
-            goto error;
-#endif
-    }
-
-    self->blksize = DEFAULT_BUFFER_SIZE;
-    if (_Py_fstat(self->fd, &fdfstat) < 0)
-        goto error;
-#if defined(S_ISDIR) && defined(EISDIR)
-    /* On Unix, open will succeed for directories.
-       In Python, there should be no file objects referring to
-       directories, so we need a check.  */
-    if (S_ISDIR(fdfstat.st_mode)) {
-        errno = EISDIR;
-        PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj);
-        goto error;
-    }
-#endif /* defined(S_ISDIR) */
-#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
-    if (fdfstat.st_blksize > 1)
-        self->blksize = fdfstat.st_blksize;
-#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */
-
-#if defined(MS_WINDOWS) || defined(__CYGWIN__)
-    /* don't translate newlines (\r\n <=> \n) */
-    _setmode(self->fd, O_BINARY);
-#endif
-
-    if (_PyObject_SetAttrId((PyObject *)self, &PyId_name, nameobj) < 0)
-        goto error;
-
-    if (self->appending) {
-        /* For consistent behaviour, we explicitly seek to the
-           end of file (otherwise, it might be done only on the
-           first write()). */
-        PyObject *pos = portable_lseek(self->fd, NULL, 2);
-        if (pos == NULL)
-            goto error;
-        Py_DECREF(pos);
-    }
-
-    goto done;
-
- error:
-    ret = -1;
-    if (!fd_is_own)
-        self->fd = -1;
-    if (self->fd >= 0)
-        internal_close(self);
-
- done:
-    Py_CLEAR(stringobj);
-    return ret;
-}
-
-static int
-fileio_traverse(fileio *self, visitproc visit, void *arg)
-{
-    Py_VISIT(self->dict);
-    return 0;
-}
-
-static int
-fileio_clear(fileio *self)
-{
-    Py_CLEAR(self->dict);
-    return 0;
-}
-
-static void
-fileio_dealloc(fileio *self)
-{
-    self->finalizing = 1;
-    if (_PyIOBase_finalize((PyObject *) self) < 0)
-        return;
-    _PyObject_GC_UNTRACK(self);
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *) self);
-    Py_CLEAR(self->dict);
-    Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-static PyObject *
-err_closed(void)
-{
-    PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
-    return NULL;
-}
-
-static PyObject *
-err_mode(char *action)
-{
-    _PyIO_State *state = IO_STATE();
-    if (state != NULL)
-        PyErr_Format(state->unsupported_operation,
-                     "File not open for %s", action);
-    return NULL;
-}
-
-static PyObject *
-fileio_fileno(fileio *self)
-{
-    if (self->fd < 0)
-        return err_closed();
-    return PyLong_FromLong((long) self->fd);
-}
-
-static PyObject *
-fileio_readable(fileio *self)
-{
-    if (self->fd < 0)
-        return err_closed();
-    return PyBool_FromLong((long) self->readable);
-}
-
-static PyObject *
-fileio_writable(fileio *self)
-{
-    if (self->fd < 0)
-        return err_closed();
-    return PyBool_FromLong((long) self->writable);
-}
-
-static PyObject *
-fileio_seekable(fileio *self)
-{
-    if (self->fd < 0)
-        return err_closed();
-    if (self->seekable < 0) {
-        PyObject *pos = portable_lseek(self->fd, NULL, SEEK_CUR);
-        if (pos == NULL) {
-            PyErr_Clear();
-            self->seekable = 0;
-        } else {
-            Py_DECREF(pos);
-            self->seekable = 1;
-        }
-    }
-    return PyBool_FromLong((long) self->seekable);
-}
-
-static PyObject *
-fileio_readinto(fileio *self, PyObject *args)
-{
-    Py_buffer pbuf;
-    Py_ssize_t n;
-    int err;
-
-    if (self->fd < 0)
-        return err_closed();
-    if (!self->readable)
-        return err_mode("reading");
-
-    if (!PyArg_ParseTuple(args, "w*", &pbuf))
-        return NULL;
-
-    n = _Py_read(self->fd, pbuf.buf, pbuf.len);
-    /* copy errno because PyBuffer_Release() can indirectly modify it */
-    err = errno;
-    PyBuffer_Release(&pbuf);
-
-    if (n == -1) {
-        if (err == EAGAIN) {
-            PyErr_Clear();
-            Py_RETURN_NONE;
-        }
-        return NULL;
-    }
-
-    return PyLong_FromSsize_t(n);
-}
-
-static size_t
-new_buffersize(fileio *self, size_t currentsize)
-{
-    size_t addend;
-
-    /* Expand the buffer by an amount proportional to the current size,
-       giving us amortized linear-time behavior.  For bigger sizes, use a
-       less-than-double growth factor to avoid excessive allocation. */
-    assert(currentsize <= PY_SSIZE_T_MAX);
-    if (currentsize > 65536)
-        addend = currentsize >> 3;
-    else
-        addend = 256 + currentsize;
-    if (addend < SMALLCHUNK)
-        /* Avoid tiny read() calls. */
-        addend = SMALLCHUNK;
-    return addend + currentsize;
-}
-
-static PyObject *
-fileio_readall(fileio *self)
-{
-    struct _Py_stat_struct status;
-    Py_off_t pos, end;
-    PyObject *result;
-    Py_ssize_t bytes_read = 0;
-    Py_ssize_t n;
-    size_t bufsize;
-
-    if (self->fd < 0)
-        return err_closed();
-    if (!_PyVerify_fd(self->fd))
-        return PyErr_SetFromErrno(PyExc_IOError);
-
-    _Py_BEGIN_SUPPRESS_IPH
-#ifdef MS_WINDOWS
-    pos = _lseeki64(self->fd, 0L, SEEK_CUR);
-#else
-    pos = lseek(self->fd, 0L, SEEK_CUR);
-#endif
-    _Py_END_SUPPRESS_IPH
-
-    if (_Py_fstat_noraise(self->fd, &status) == 0)
-        end = status.st_size;
-    else
-        end = (Py_off_t)-1;
-
-    if (end > 0 && end >= pos && pos >= 0 && end - pos < PY_SSIZE_T_MAX) {
-        /* This is probably a real file, so we try to allocate a
-           buffer one byte larger than the rest of the file.  If the
-           calculation is right then we should get EOF without having
-           to enlarge the buffer. */
-        bufsize = (size_t)(end - pos + 1);
-    } else {
-        bufsize = SMALLCHUNK;
-    }
-
-    result = PyBytes_FromStringAndSize(NULL, bufsize);
-    if (result == NULL)
-        return NULL;
-
-    while (1) {
-        if (bytes_read >= (Py_ssize_t)bufsize) {
-            bufsize = new_buffersize(self, bytes_read);
-            if (bufsize > PY_SSIZE_T_MAX || bufsize <= 0) {
-                PyErr_SetString(PyExc_OverflowError,
-                                "unbounded read returned more bytes "
-                                "than a Python bytes object can hold");
-                Py_DECREF(result);
-                return NULL;
-            }
-
-            if (PyBytes_GET_SIZE(result) < (Py_ssize_t)bufsize) {
-                if (_PyBytes_Resize(&result, bufsize) < 0)
-                    return NULL;
-            }
-        }
-
-        n = _Py_read(self->fd,
-                     PyBytes_AS_STRING(result) + bytes_read,
-                     bufsize - bytes_read);
-
-        if (n == 0)
-            break;
-        if (n == -1) {
-            if (errno == EAGAIN) {
-                PyErr_Clear();
-                if (bytes_read > 0)
-                    break;
-                Py_DECREF(result);
-                Py_RETURN_NONE;
-            }
-            Py_DECREF(result);
-            return NULL;
-        }
-        bytes_read += n;
-        pos += n;
-    }
-
-    if (PyBytes_GET_SIZE(result) > bytes_read) {
-        if (_PyBytes_Resize(&result, bytes_read) < 0)
-            return NULL;
-    }
-    return result;
-}
-
-static PyObject *
-fileio_read(fileio *self, PyObject *args)
-{
-    char *ptr;
-    Py_ssize_t n;
-    Py_ssize_t size = -1;
-    PyObject *bytes;
-
-    if (self->fd < 0)
-        return err_closed();
-    if (!self->readable)
-        return err_mode("reading");
-
-    if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
-        return NULL;
-
-    if (size < 0)
-        return fileio_readall(self);
-
-#ifdef MS_WINDOWS
-    /* On Windows, the count parameter of read() is an int */
-    if (size > INT_MAX)
-        size = INT_MAX;
-#endif
-
-    bytes = PyBytes_FromStringAndSize(NULL, size);
-    if (bytes == NULL)
-        return NULL;
-    ptr = PyBytes_AS_STRING(bytes);
-
-    n = _Py_read(self->fd, ptr, size);
-    if (n == -1) {
-        /* copy errno because Py_DECREF() can indirectly modify it */
-        int err = errno;
-        Py_DECREF(bytes);
-        if (err == EAGAIN) {
-            PyErr_Clear();
-            Py_RETURN_NONE;
-        }
-        return NULL;
-    }
-
-    if (n != size) {
-        if (_PyBytes_Resize(&bytes, n) < 0) {
-            Py_CLEAR(bytes);
-            return NULL;
-        }
-    }
-
-    return (PyObject *) bytes;
-}
-
-static PyObject *
-fileio_write(fileio *self, PyObject *args)
-{
-    Py_buffer pbuf;
-    Py_ssize_t n;
-    int err;
-
-    if (self->fd < 0)
-        return err_closed();
-    if (!self->writable)
-        return err_mode("writing");
-
-    if (!PyArg_ParseTuple(args, "y*", &pbuf))
-        return NULL;
-
-    n = _Py_write(self->fd, pbuf.buf, pbuf.len);
-    /* copy errno because PyBuffer_Release() can indirectly modify it */
-    err = errno;
-    PyBuffer_Release(&pbuf);
-
-    if (n < 0) {
-        if (err == EAGAIN) {
-            PyErr_Clear();
-            Py_RETURN_NONE;
-        }
-        return NULL;
-    }
-
-    return PyLong_FromSsize_t(n);
-}
-
-/* XXX Windows support below is likely incomplete */
-
-/* Cribbed from posix_lseek() */
-static PyObject *
-portable_lseek(int fd, PyObject *posobj, int whence)
-{
-    Py_off_t pos, res;
-
-#ifdef SEEK_SET
-    /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
-    switch (whence) {
-#if SEEK_SET != 0
-    case 0: whence = SEEK_SET; break;
-#endif
-#if SEEK_CUR != 1
-    case 1: whence = SEEK_CUR; break;
-#endif
-#if SEEK_END != 2
-    case 2: whence = SEEK_END; break;
-#endif
-    }
-#endif /* SEEK_SET */
-
-    if (posobj == NULL)
-        pos = 0;
-    else {
-        if(PyFloat_Check(posobj)) {
-            PyErr_SetString(PyExc_TypeError, "an integer is required");
-            return NULL;
-        }
-#if defined(HAVE_LARGEFILE_SUPPORT)
-        pos = PyLong_AsLongLong(posobj);
-#else
-        pos = PyLong_AsLong(posobj);
-#endif
-        if (PyErr_Occurred())
-            return NULL;
-    }
-
-    if (_PyVerify_fd(fd)) {
-        Py_BEGIN_ALLOW_THREADS
-        _Py_BEGIN_SUPPRESS_IPH
-#ifdef MS_WINDOWS
-        res = _lseeki64(fd, pos, whence);
-#else
-        res = lseek(fd, pos, whence);
-#endif
-        _Py_END_SUPPRESS_IPH
-        Py_END_ALLOW_THREADS
-    } else
-        res = -1;
-    if (res < 0)
-        return PyErr_SetFromErrno(PyExc_IOError);
-
-#if defined(HAVE_LARGEFILE_SUPPORT)
-    return PyLong_FromLongLong(res);
-#else
-    return PyLong_FromLong(res);
-#endif
-}
-
-static PyObject *
-fileio_seek(fileio *self, PyObject *args)
-{
-    PyObject *posobj;
-    int whence = 0;
-
-    if (self->fd < 0)
-        return err_closed();
-
-    if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
-        return NULL;
-
-    return portable_lseek(self->fd, posobj, whence);
-}
-
-static PyObject *
-fileio_tell(fileio *self, PyObject *args)
-{
-    if (self->fd < 0)
-        return err_closed();
-
-    return portable_lseek(self->fd, NULL, 1);
-}
-
-#ifdef HAVE_FTRUNCATE
-static PyObject *
-fileio_truncate(fileio *self, PyObject *args)
-{
-    PyObject *posobj = NULL; /* the new size wanted by the user */
-    Py_off_t pos;
-    int ret;
-    int fd;
-
-    fd = self->fd;
-    if (fd < 0)
-        return err_closed();
-    if (!self->writable)
-        return err_mode("writing");
-
-    if (!PyArg_ParseTuple(args, "|O", &posobj))
-        return NULL;
-
-    if (posobj == Py_None || posobj == NULL) {
-        /* Get the current position. */
-        posobj = portable_lseek(fd, NULL, 1);
-        if (posobj == NULL)
-            return NULL;
-    }
-    else {
-        Py_INCREF(posobj);
-    }
-
-#if defined(HAVE_LARGEFILE_SUPPORT)
-    pos = PyLong_AsLongLong(posobj);
-#else
-    pos = PyLong_AsLong(posobj);
-#endif
-    if (PyErr_Occurred()){
-        Py_DECREF(posobj);
-        return NULL;
-    }
-
-    Py_BEGIN_ALLOW_THREADS
-    _Py_BEGIN_SUPPRESS_IPH
-    errno = 0;
-#ifdef MS_WINDOWS
-    ret = _chsize_s(fd, pos);
-#else
-    ret = ftruncate(fd, pos);
-#endif
-    _Py_END_SUPPRESS_IPH
-    Py_END_ALLOW_THREADS
-
-    if (ret != 0) {
-        Py_DECREF(posobj);
-        PyErr_SetFromErrno(PyExc_IOError);
-        return NULL;
-    }
-
-    return posobj;
-}
-#endif /* HAVE_FTRUNCATE */
-
-static char *
-mode_string(fileio *self)
-{
-    if (self->created) {
-        if (self->readable)
-            return "xb+";
-        else
-            return "xb";
-    }
-    if (self->appending) {
-        if (self->readable)
-            return "ab+";
-        else
-            return "ab";
-    }
-    else if (self->readable) {
-        if (self->writable)
-            return "rb+";
-        else
-            return "rb";
-    }
-    else
-        return "wb";
-}
-
-static PyObject *
-fileio_repr(fileio *self)
-{
-    PyObject *nameobj, *res;
-
-    if (self->fd < 0)
-        return PyUnicode_FromFormat("<_io.FileIO [closed]>");
-
-    nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
-    if (nameobj == NULL) {
-        if (PyErr_ExceptionMatches(PyExc_AttributeError))
-            PyErr_Clear();
-        else
-            return NULL;
-        res = PyUnicode_FromFormat(
-            "<_io.FileIO fd=%d mode='%s' closefd=%s>",
-            self->fd, mode_string(self), self->closefd ? "True" : "False");
-    }
-    else {
-        res = PyUnicode_FromFormat(
-            "<_io.FileIO name=%R mode='%s' closefd=%s>",
-            nameobj, mode_string(self), self->closefd ? "True" : "False");
-        Py_DECREF(nameobj);
-    }
-    return res;
-}
-
-static PyObject *
-fileio_isatty(fileio *self)
-{
-    long res;
-
-    if (self->fd < 0)
-        return err_closed();
-    Py_BEGIN_ALLOW_THREADS
-    _Py_BEGIN_SUPPRESS_IPH
-    if (_PyVerify_fd(self->fd))
-        res = isatty(self->fd);
-    else
-        res = 0;
-    _Py_END_SUPPRESS_IPH
-    Py_END_ALLOW_THREADS
-    return PyBool_FromLong(res);
-}
-
-static PyObject *
-fileio_getstate(fileio *self)
-{
-    PyErr_Format(PyExc_TypeError,
-                 "cannot serialize '%s' object", Py_TYPE(self)->tp_name);
-    return NULL;
-}
-
-
-PyDoc_STRVAR(fileio_doc,
-"file(name: str[, mode: str][, opener: None]) -> file IO object\n"
+PyDoc_STRVAR(_io_FileIO___init____doc__,
+"FileIO(file, mode=\'r\', closefd=True, opener=None)\n"
+"--\n"
 "\n"
-"Open a file.  The mode can be 'r' (default), 'w', 'x' or 'a' for reading,\n"
+"Open a file.\n"
+"\n"
+"The mode can be \'r\' (default), \'w\', \'x\' or \'a\' for reading,\n"
 "writing, exclusive creation or appending.  The file will be created if it\n"
-"doesn't exist when opened for writing or appending; it will be truncated\n"
+"doesn\'t exist when opened for writing or appending; it will be truncated\n"
 "when opened for writing.  A FileExistsError will be raised if it already\n"
 "exists when opened for creating. Opening a file for creating implies\n"
-"writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode\n"
+"writing so this mode behaves in a similar way to \'w\'.Add a \'+\' to the mode\n"
 "to allow simultaneous reading and writing. A custom opener can be used by\n"
 "passing a callable as *opener*. The underlying file descriptor for the file\n"
 "object is then obtained by calling opener with (*name*, *flags*).\n"
 "*opener* must return an open file descriptor (passing os.open as *opener*\n"
 "results in functionality similar to passing None).");
 
-PyDoc_STRVAR(read_doc,
-"read(size: int) -> bytes.  read at most size bytes, returned as bytes.\n"
+static int
+_io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
+                         int closefd, PyObject *opener);
+
+static int
+_io_FileIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    int return_value = -1;
+    static char *_keywords[] = {"file", "mode", "closefd", "opener", NULL};
+    PyObject *nameobj;
+    const char *mode = "r";
+    int closefd = 1;
+    PyObject *opener = Py_None;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "O|siO:FileIO", _keywords,
+        &nameobj, &mode, &closefd, &opener))
+        goto exit;
+    return_value = _io_FileIO___init___impl((fileio *)self, nameobj, mode, closefd, opener);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_io_FileIO_fileno__doc__,
+"fileno($self, /)\n"
+"--\n"
 "\n"
-"Only makes one system call, so less data may be returned than requested\n"
-"In non-blocking mode, returns None if no data is available.\n"
-"Return an empty bytes object at EOF.");
+"Return the underlying file descriptor (an integer).");
 
-PyDoc_STRVAR(readall_doc,
-"readall() -> bytes.  read all data from the file, returned as bytes.\n"
+#define _IO_FILEIO_FILENO_METHODDEF    \
+    {"fileno", (PyCFunction)_io_FileIO_fileno, METH_NOARGS, _io_FileIO_fileno__doc__},
+
+static PyObject *
+_io_FileIO_fileno_impl(fileio *self);
+
+static PyObject *
+_io_FileIO_fileno(fileio *self, PyObject *Py_UNUSED(ignored))
+{
+    return _io_FileIO_fileno_impl(self);
+}
+
+PyDoc_STRVAR(_io_FileIO_readable__doc__,
+"readable($self, /)\n"
+"--\n"
+"\n"
+"True if file was opened in a read mode.");
+
+#define _IO_FILEIO_READABLE_METHODDEF    \
+    {"readable", (PyCFunction)_io_FileIO_readable, METH_NOARGS, _io_FileIO_readable__doc__},
+
+static PyObject *
+_io_FileIO_readable_impl(fileio *self);
+
+static PyObject *
+_io_FileIO_readable(fileio *self, PyObject *Py_UNUSED(ignored))
+{
+    return _io_FileIO_readable_impl(self);
+}
+
+PyDoc_STRVAR(_io_FileIO_writable__doc__,
+"writable($self, /)\n"
+"--\n"
+"\n"
+"True if file was opened in a write mode.");
+
+#define _IO_FILEIO_WRITABLE_METHODDEF    \
+    {"writable", (PyCFunction)_io_FileIO_writable, METH_NOARGS, _io_FileIO_writable__doc__},
+
+static PyObject *
+_io_FileIO_writable_impl(fileio *self);
+
+static PyObject *
+_io_FileIO_writable(fileio *self, PyObject *Py_UNUSED(ignored))
+{
+    return _io_FileIO_writable_impl(self);
+}
+
+PyDoc_STRVAR(_io_FileIO_seekable__doc__,
+"seekable($self, /)\n"
+"--\n"
+"\n"
+"True if file supports random-access.");
+
+#define _IO_FILEIO_SEEKABLE_METHODDEF    \
+    {"seekable", (PyCFunction)_io_FileIO_seekable, METH_NOARGS, _io_FileIO_seekable__doc__},
+
+static PyObject *
+_io_FileIO_seekable_impl(fileio *self);
+
+static PyObject *
+_io_FileIO_seekable(fileio *self, PyObject *Py_UNUSED(ignored))
+{
+    return _io_FileIO_seekable_impl(self);
+}
+
+PyDoc_STRVAR(_io_FileIO_readinto__doc__,
+"readinto($self, buffer, /)\n"
+"--\n"
+"\n"
+"Same as RawIOBase.readinto().");
+
+#define _IO_FILEIO_READINTO_METHODDEF    \
+    {"readinto", (PyCFunction)_io_FileIO_readinto, METH_O, _io_FileIO_readinto__doc__},
+
+static PyObject *
+_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer);
+
+static PyObject *
+_io_FileIO_readinto(fileio *self, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    Py_buffer buffer = {NULL, NULL};
+
+    if (!PyArg_Parse(arg,
+        "w*:readinto",
+        &buffer))
+        goto exit;
+    return_value = _io_FileIO_readinto_impl(self, &buffer);
+
+exit:
+    /* Cleanup for buffer */
+    if (buffer.obj)
+       PyBuffer_Release(&buffer);
+
+    return return_value;
+}
+
+PyDoc_STRVAR(_io_FileIO_readall__doc__,
+"readall($self, /)\n"
+"--\n"
+"\n"
+"Read all data from the file, returned as bytes.\n"
 "\n"
 "In non-blocking mode, returns as much as is immediately available,\n"
 "or None if no data is available.  Return an empty bytes object at EOF.");
 
-PyDoc_STRVAR(write_doc,
-"write(b: bytes) -> int.  Write bytes b to file, return number written.\n"
+#define _IO_FILEIO_READALL_METHODDEF    \
+    {"readall", (PyCFunction)_io_FileIO_readall, METH_NOARGS, _io_FileIO_readall__doc__},
+
+static PyObject *
+_io_FileIO_readall_impl(fileio *self);
+
+static PyObject *
+_io_FileIO_readall(fileio *self, PyObject *Py_UNUSED(ignored))
+{
+    return _io_FileIO_readall_impl(self);
+}
+
+PyDoc_STRVAR(_io_FileIO_read__doc__,
+"read($self, size=-1, /)\n"
+"--\n"
+"\n"
+"Read at most size bytes, returned as bytes.\n"
+"\n"
+"Only makes one system call, so less data may be returned than requested.\n"
+"In non-blocking mode, returns None if no data is available.\n"
+"Return an empty bytes object at EOF.");
+
+#define _IO_FILEIO_READ_METHODDEF    \
+    {"read", (PyCFunction)_io_FileIO_read, METH_VARARGS, _io_FileIO_read__doc__},
+
+static PyObject *
+_io_FileIO_read_impl(fileio *self, Py_ssize_t size);
+
+static PyObject *
+_io_FileIO_read(fileio *self, PyObject *args)
+{
+    PyObject *return_value = NULL;
+    Py_ssize_t size = -1;
+
+    if (!PyArg_ParseTuple(args,
+        "|O&:read",
+        _PyIO_ConvertSsize_t, &size))
+        goto exit;
+    return_value = _io_FileIO_read_impl(self, size);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_io_FileIO_write__doc__,
+"write($self, b, /)\n"
+"--\n"
+"\n"
+"Write bytes b to file, return number written.\n"
 "\n"
 "Only makes one system call, so not all of the data may be written.\n"
 "The number of bytes actually written is returned.  In non-blocking mode,\n"
-"returns None if the write would block."
-);
+"returns None if the write would block.");
 
-PyDoc_STRVAR(fileno_doc,
-"fileno() -> int.  Return the underlying file descriptor (an integer).");
+#define _IO_FILEIO_WRITE_METHODDEF    \
+    {"write", (PyCFunction)_io_FileIO_write, METH_O, _io_FileIO_write__doc__},
 
-PyDoc_STRVAR(seek_doc,
-"seek(offset: int[, whence: int]) -> int.  Move to new file position and\n"
-"return the file position.\n"
+static PyObject *
+_io_FileIO_write_impl(fileio *self, Py_buffer *b);
+
+static PyObject *
+_io_FileIO_write(fileio *self, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    Py_buffer b = {NULL, NULL};
+
+    if (!PyArg_Parse(arg,
+        "y*:write",
+        &b))
+        goto exit;
+    return_value = _io_FileIO_write_impl(self, &b);
+
+exit:
+    /* Cleanup for b */
+    if (b.obj)
+       PyBuffer_Release(&b);
+
+    return return_value;
+}
+
+PyDoc_STRVAR(_io_FileIO_seek__doc__,
+"seek($self, pos, whence=0, /)\n"
+"--\n"
+"\n"
+"Move to new file position and return the file position.\n"
 "\n"
 "Argument offset is a byte count.  Optional argument whence defaults to\n"
 "SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n"
@@ -1030,145 +272,103 @@
 "\n"
 "Note that not all file objects are seekable.");
 
-#ifdef HAVE_FTRUNCATE
-PyDoc_STRVAR(truncate_doc,
-"truncate([size: int]) -> int.  Truncate the file to at most size bytes\n"
-"and return the truncated size.\n"
+#define _IO_FILEIO_SEEK_METHODDEF    \
+    {"seek", (PyCFunction)_io_FileIO_seek, METH_VARARGS, _io_FileIO_seek__doc__},
+
+static PyObject *
+_io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence);
+
+static PyObject *
+_io_FileIO_seek(fileio *self, PyObject *args)
+{
+    PyObject *return_value = NULL;
+    PyObject *pos;
+    int whence = 0;
+
+    if (!PyArg_ParseTuple(args,
+        "O|i:seek",
+        &pos, &whence))
+        goto exit;
+    return_value = _io_FileIO_seek_impl(self, pos, whence);
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_io_FileIO_tell__doc__,
+"tell($self, /)\n"
+"--\n"
+"\n"
+"Current file position.\n"
+"\n"
+"Can raise OSError for non seekable files.");
+
+#define _IO_FILEIO_TELL_METHODDEF    \
+    {"tell", (PyCFunction)_io_FileIO_tell, METH_NOARGS, _io_FileIO_tell__doc__},
+
+static PyObject *
+_io_FileIO_tell_impl(fileio *self);
+
+static PyObject *
+_io_FileIO_tell(fileio *self, PyObject *Py_UNUSED(ignored))
+{
+    return _io_FileIO_tell_impl(self);
+}
+
+#if defined(HAVE_FTRUNCATE)
+
+PyDoc_STRVAR(_io_FileIO_truncate__doc__,
+"truncate($self, size=None, /)\n"
+"--\n"
+"\n"
+"Truncate the file to at most size bytes and return the truncated size.\n"
 "\n"
 "Size defaults to the current file position, as returned by tell().\n"
 "The current file position is changed to the value of size.");
-#endif
 
-PyDoc_STRVAR(tell_doc,
-"tell() -> int.  Current file position.\n"
-"\n"
-"Can raise OSError for non seekable files."
-);
-
-PyDoc_STRVAR(readinto_doc,
-"readinto() -> Same as RawIOBase.readinto().");
-
-PyDoc_STRVAR(close_doc,
-"close() -> None.  Close the file.\n"
-"\n"
-"A closed file cannot be used for further I/O operations.  close() may be\n"
-"called more than once without error.");
-
-PyDoc_STRVAR(isatty_doc,
-"isatty() -> bool.  True if the file is connected to a TTY device.");
-
-PyDoc_STRVAR(seekable_doc,
-"seekable() -> bool.  True if file supports random-access.");
-
-PyDoc_STRVAR(readable_doc,
-"readable() -> bool.  True if file was opened in a read mode.");
-
-PyDoc_STRVAR(writable_doc,
-"writable() -> bool.  True if file was opened in a write mode.");
-
-static PyMethodDef fileio_methods[] = {
-    {"read",     (PyCFunction)fileio_read,         METH_VARARGS, read_doc},
-    {"readall",  (PyCFunction)fileio_readall,  METH_NOARGS,  readall_doc},
-    {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
-    {"write",    (PyCFunction)fileio_write,        METH_VARARGS, write_doc},
-    {"seek",     (PyCFunction)fileio_seek,         METH_VARARGS, seek_doc},
-    {"tell",     (PyCFunction)fileio_tell,         METH_VARARGS, tell_doc},
-#ifdef HAVE_FTRUNCATE
-    {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
-#endif
-    {"close",    (PyCFunction)fileio_close,        METH_NOARGS,  close_doc},
-    {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS,      seekable_doc},
-    {"readable", (PyCFunction)fileio_readable, METH_NOARGS,      readable_doc},
-    {"writable", (PyCFunction)fileio_writable, METH_NOARGS,      writable_doc},
-    {"fileno",   (PyCFunction)fileio_fileno,   METH_NOARGS,      fileno_doc},
-    {"isatty",   (PyCFunction)fileio_isatty,   METH_NOARGS,      isatty_doc},
-    {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
-    {"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL},
-    {NULL,           NULL}             /* sentinel */
-};
-
-/* 'closed' and 'mode' are attributes for backwards compatibility reasons. */
+#define _IO_FILEIO_TRUNCATE_METHODDEF    \
+    {"truncate", (PyCFunction)_io_FileIO_truncate, METH_VARARGS, _io_FileIO_truncate__doc__},
 
 static PyObject *
-get_closed(fileio *self, void *closure)
+_io_FileIO_truncate_impl(fileio *self, PyObject *posobj);
+
+static PyObject *
+_io_FileIO_truncate(fileio *self, PyObject *args)
 {
-    return PyBool_FromLong((long)(self->fd < 0));
+    PyObject *return_value = NULL;
+    PyObject *posobj = NULL;
+
+    if (!PyArg_UnpackTuple(args, "truncate",
+        0, 1,
+        &posobj))
+        goto exit;
+    return_value = _io_FileIO_truncate_impl(self, posobj);
+
+exit:
+    return return_value;
 }
 
+#endif /* defined(HAVE_FTRUNCATE) */
+
+PyDoc_STRVAR(_io_FileIO_isatty__doc__,
+"isatty($self, /)\n"
+"--\n"
+"\n"
+"True if the file is connected to a TTY device.");
+
+#define _IO_FILEIO_ISATTY_METHODDEF    \
+    {"isatty", (PyCFunction)_io_FileIO_isatty, METH_NOARGS, _io_FileIO_isatty__doc__},
+
 static PyObject *
-get_closefd(fileio *self, void *closure)
+_io_FileIO_isatty_impl(fileio *self);
+
+static PyObject *
+_io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored))
 {
-    return PyBool_FromLong((long)(self->closefd));
+    return _io_FileIO_isatty_impl(self);
 }
 
-static PyObject *
-get_mode(fileio *self, void *closure)
-{
-    return PyUnicode_FromString(mode_string(self));
-}
-
-static PyGetSetDef fileio_getsetlist[] = {
-    {"closed", (getter)get_closed, NULL, "True if the file is closed"},
-    {"closefd", (getter)get_closefd, NULL,
-        "True if the file descriptor will be closed by close()."},
-    {"mode", (getter)get_mode, NULL, "String giving the file mode"},
-    {NULL},
-};
-
-static PyMemberDef fileio_members[] = {
-    {"_blksize", T_UINT, offsetof(fileio, blksize), 0},
-    {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0},
-    {NULL}
-};
-
-PyTypeObject PyFileIO_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.FileIO",
-    sizeof(fileio),
-    0,
-    (destructor)fileio_dealloc,                 /* tp_dealloc */
-    0,                                          /* tp_print */
-    0,                                          /* tp_getattr */
-    0,                                          /* tp_setattr */
-    0,                                          /* tp_reserved */
-    (reprfunc)fileio_repr,                      /* tp_repr */
-    0,                                          /* tp_as_number */
-    0,                                          /* tp_as_sequence */
-    0,                                          /* tp_as_mapping */
-    0,                                          /* tp_hash */
-    0,                                          /* tp_call */
-    0,                                          /* tp_str */
-    PyObject_GenericGetAttr,                    /* tp_getattro */
-    0,                                          /* tp_setattro */
-    0,                                          /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,       /* tp_flags */
-    fileio_doc,                                 /* tp_doc */
-    (traverseproc)fileio_traverse,              /* tp_traverse */
-    (inquiry)fileio_clear,                      /* tp_clear */
-    0,                                          /* tp_richcompare */
-    offsetof(fileio, weakreflist),      /* tp_weaklistoffset */
-    0,                                          /* tp_iter */
-    0,                                          /* tp_iternext */
-    fileio_methods,                             /* tp_methods */
-    fileio_members,                             /* tp_members */
-    fileio_getsetlist,                          /* tp_getset */
-    0,                                          /* tp_base */
-    0,                                          /* tp_dict */
-    0,                                          /* tp_descr_get */
-    0,                                          /* tp_descr_set */
-    offsetof(fileio, dict),         /* tp_dictoffset */
-    fileio_init,                                /* tp_init */
-    PyType_GenericAlloc,                        /* tp_alloc */
-    fileio_new,                                 /* tp_new */
-    PyObject_GC_Del,                            /* tp_free */
-    0,                                          /* tp_is_gc */
-    0,                                          /* tp_bases */
-    0,                                          /* tp_mro */
-    0,                                          /* tp_cache */
-    0,                                          /* tp_subclasses */
-    0,                                          /* tp_weaklist */
-    0,                                          /* tp_del */
-    0,                                          /* tp_version_tag */
-    0,                                          /* tp_finalize */
-};
+#ifndef _IO_FILEIO_TRUNCATE_METHODDEF
+    #define _IO_FILEIO_TRUNCATE_METHODDEF
+#endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */
+/*[clinic end generated code: output=c6708e1980f6e02d input=a9049054013a1b77]*/
diff --git a/Modules/_io/iobase.c b/Modules/_io/clinic/iobase.c.h
copy from Modules/_io/iobase.c
copy to Modules/_io/clinic/iobase.c.h
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/clinic/iobase.c.h
@@ -1,950 +1,282 @@
-/*
-    An implementation of the I/O abstract base classes hierarchy
-    as defined by PEP 3116 - "New I/O"
+/*[clinic input]
+preserve
+[clinic start generated code]*/
 
-    Classes defined here: IOBase, RawIOBase.
+PyDoc_STRVAR(_io__IOBase_tell__doc__,
+"tell($self, /)\n"
+"--\n"
+"\n"
+"Return current stream position.");
 
-    Written by Amaury Forgeot d'Arc and Antoine Pitrou
-*/
+#define _IO__IOBASE_TELL_METHODDEF    \
+    {"tell", (PyCFunction)_io__IOBase_tell, METH_NOARGS, _io__IOBase_tell__doc__},
 
+static PyObject *
+_io__IOBase_tell_impl(PyObject *self);
 
-#define PY_SSIZE_T_CLEAN
-#include "Python.h"
-#include "structmember.h"
-#include "_iomodule.h"
-
-/*
- * IOBase class, an abstract class
- */
-
-typedef struct {
-    PyObject_HEAD
-
-    PyObject *dict;
-    PyObject *weakreflist;
-} iobase;
-
-PyDoc_STRVAR(iobase_doc,
-    "The abstract base class for all I/O classes, acting on streams of\n"
-    "bytes. There is no public constructor.\n"
-    "\n"
-    "This class provides dummy implementations for many methods that\n"
-    "derived classes can override selectively; the default implementations\n"
-    "represent a file that cannot be read, written or seeked.\n"
-    "\n"
-    "Even though IOBase does not declare read, readinto, or write because\n"
-    "their signatures will vary, implementations and clients should\n"
-    "consider those methods part of the interface. Also, implementations\n"
-    "may raise UnsupportedOperation when operations they do not support are\n"
-    "called.\n"
-    "\n"
-    "The basic type used for binary data read from or written to a file is\n"
-    "bytes. bytearrays are accepted too, and in some cases (such as\n"
-    "readinto) needed. Text I/O classes work with str data.\n"
-    "\n"
-    "Note that calling any method (except additional calls to close(),\n"
-    "which are ignored) on a closed stream should raise a ValueError.\n"
-    "\n"
-    "IOBase (and its subclasses) support the iterator protocol, meaning\n"
-    "that an IOBase object can be iterated over yielding the lines in a\n"
-    "stream.\n"
-    "\n"
-    "IOBase also supports the :keyword:`with` statement. In this example,\n"
-    "fp is closed after the suite of the with statement is complete:\n"
-    "\n"
-    "with open('spam.txt', 'r') as fp:\n"
-    "    fp.write('Spam and eggs!')\n");
-
-/* Use this macro whenever you want to check the internal `closed` status
-   of the IOBase object rather than the virtual `closed` attribute as returned
-   by whatever subclass. */
-
-_Py_IDENTIFIER(__IOBase_closed);
-#define IS_CLOSED(self) \
-    _PyObject_HasAttrId(self, &PyId___IOBase_closed)
-
-_Py_IDENTIFIER(read);
-
-/* Internal methods */
 static PyObject *
-iobase_unsupported(const char *message)
+_io__IOBase_tell(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    _PyIO_State *state = IO_STATE();
-    if (state != NULL)
-        PyErr_SetString(state->unsupported_operation, message);
-    return NULL;
+    return _io__IOBase_tell_impl(self);
 }
 
-/* Positionning */
+PyDoc_STRVAR(_io__IOBase_flush__doc__,
+"flush($self, /)\n"
+"--\n"
+"\n"
+"Flush write buffers, if applicable.\n"
+"\n"
+"This is not implemented for read-only and non-blocking streams.");
 
-PyDoc_STRVAR(iobase_seek_doc,
-    "Change stream position.\n"
-    "\n"
-    "Change the stream position to the given byte offset. The offset is\n"
-    "interpreted relative to the position indicated by whence.  Values\n"
-    "for whence are:\n"
-    "\n"
-    "* 0 -- start of stream (the default); offset should be zero or positive\n"
-    "* 1 -- current stream position; offset may be negative\n"
-    "* 2 -- end of stream; offset is usually negative\n"
-    "\n"
-    "Return the new absolute position.");
+#define _IO__IOBASE_FLUSH_METHODDEF    \
+    {"flush", (PyCFunction)_io__IOBase_flush, METH_NOARGS, _io__IOBase_flush__doc__},
 
 static PyObject *
-iobase_seek(PyObject *self, PyObject *args)
+_io__IOBase_flush_impl(PyObject *self);
+
+static PyObject *
+_io__IOBase_flush(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return iobase_unsupported("seek");
+    return _io__IOBase_flush_impl(self);
 }
 
-PyDoc_STRVAR(iobase_tell_doc,
-             "Return current stream position.");
+PyDoc_STRVAR(_io__IOBase_close__doc__,
+"close($self, /)\n"
+"--\n"
+"\n"
+"Flush and close the IO object.\n"
+"\n"
+"This method has no effect if the file is already closed.");
+
+#define _IO__IOBASE_CLOSE_METHODDEF    \
+    {"close", (PyCFunction)_io__IOBase_close, METH_NOARGS, _io__IOBase_close__doc__},
 
 static PyObject *
-iobase_tell(PyObject *self, PyObject *args)
+_io__IOBase_close_impl(PyObject *self);
+
+static PyObject *
+_io__IOBase_close(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    _Py_IDENTIFIER(seek);
-
-    return _PyObject_CallMethodId(self, &PyId_seek, "ii", 0, 1);
+    return _io__IOBase_close_impl(self);
 }
 
-PyDoc_STRVAR(iobase_truncate_doc,
-    "Truncate file to size bytes.\n"
-    "\n"
-    "File pointer is left unchanged.  Size defaults to the current IO\n"
-    "position as reported by tell().  Returns the new size.");
+PyDoc_STRVAR(_io__IOBase_seekable__doc__,
+"seekable($self, /)\n"
+"--\n"
+"\n"
+"Return whether object supports random access.\n"
+"\n"
+"If False, seek(), tell() and truncate() will raise UnsupportedOperation.\n"
+"This method may need to do a test seek().");
+
+#define _IO__IOBASE_SEEKABLE_METHODDEF    \
+    {"seekable", (PyCFunction)_io__IOBase_seekable, METH_NOARGS, _io__IOBase_seekable__doc__},
 
 static PyObject *
-iobase_truncate(PyObject *self, PyObject *args)
+_io__IOBase_seekable_impl(PyObject *self);
+
+static PyObject *
+_io__IOBase_seekable(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return iobase_unsupported("truncate");
+    return _io__IOBase_seekable_impl(self);
 }
 
-/* Flush and close methods */
+PyDoc_STRVAR(_io__IOBase_readable__doc__,
+"readable($self, /)\n"
+"--\n"
+"\n"
+"Return whether object was opened for reading.\n"
+"\n"
+"If False, read() will raise UnsupportedOperation.");
 
-PyDoc_STRVAR(iobase_flush_doc,
-    "Flush write buffers, if applicable.\n"
-    "\n"
-    "This is not implemented for read-only and non-blocking streams.\n");
+#define _IO__IOBASE_READABLE_METHODDEF    \
+    {"readable", (PyCFunction)_io__IOBase_readable, METH_NOARGS, _io__IOBase_readable__doc__},
 
 static PyObject *
-iobase_flush(PyObject *self, PyObject *args)
+_io__IOBase_readable_impl(PyObject *self);
+
+static PyObject *
+_io__IOBase_readable(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    /* XXX Should this return the number of bytes written??? */
-    if (IS_CLOSED(self)) {
-        PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
-        return NULL;
-    }
-    Py_RETURN_NONE;
+    return _io__IOBase_readable_impl(self);
 }
 
-PyDoc_STRVAR(iobase_close_doc,
-    "Flush and close the IO object.\n"
-    "\n"
-    "This method has no effect if the file is already closed.\n");
+PyDoc_STRVAR(_io__IOBase_writable__doc__,
+"writable($self, /)\n"
+"--\n"
+"\n"
+"Return whether object was opened for writing.\n"
+"\n"
+"If False, write() will raise UnsupportedOperation.");
 
-static int
-iobase_closed(PyObject *self)
+#define _IO__IOBASE_WRITABLE_METHODDEF    \
+    {"writable", (PyCFunction)_io__IOBase_writable, METH_NOARGS, _io__IOBase_writable__doc__},
+
+static PyObject *
+_io__IOBase_writable_impl(PyObject *self);
+
+static PyObject *
+_io__IOBase_writable(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *res;
-    int closed;
-    /* This gets the derived attribute, which is *not* __IOBase_closed
-       in most cases! */
-    res = PyObject_GetAttr(self, _PyIO_str_closed);
-    if (res == NULL)
-        return 0;
-    closed = PyObject_IsTrue(res);
-    Py_DECREF(res);
-    return closed;
+    return _io__IOBase_writable_impl(self);
 }
 
+PyDoc_STRVAR(_io__IOBase_fileno__doc__,
+"fileno($self, /)\n"
+"--\n"
+"\n"
+"Returns underlying file descriptor if one exists.\n"
+"\n"
+"An IOError is raised if the IO object does not use a file descriptor.");
+
+#define _IO__IOBASE_FILENO_METHODDEF    \
+    {"fileno", (PyCFunction)_io__IOBase_fileno, METH_NOARGS, _io__IOBase_fileno__doc__},
+
 static PyObject *
-iobase_closed_get(PyObject *self, void *context)
+_io__IOBase_fileno_impl(PyObject *self);
+
+static PyObject *
+_io__IOBase_fileno(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    return PyBool_FromLong(IS_CLOSED(self));
+    return _io__IOBase_fileno_impl(self);
 }
 
-PyObject *
-_PyIOBase_check_closed(PyObject *self, PyObject *args)
+PyDoc_STRVAR(_io__IOBase_isatty__doc__,
+"isatty($self, /)\n"
+"--\n"
+"\n"
+"Return whether this is an \'interactive\' stream.\n"
+"\n"
+"Return False if it can\'t be determined.");
+
+#define _IO__IOBASE_ISATTY_METHODDEF    \
+    {"isatty", (PyCFunction)_io__IOBase_isatty, METH_NOARGS, _io__IOBase_isatty__doc__},
+
+static PyObject *
+_io__IOBase_isatty_impl(PyObject *self);
+
+static PyObject *
+_io__IOBase_isatty(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    if (iobase_closed(self)) {
-        PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
-        return NULL;
-    }
-    if (args == Py_True)
-        return Py_None;
-    else
-        Py_RETURN_NONE;
+    return _io__IOBase_isatty_impl(self);
 }
 
-/* XXX: IOBase thinks it has to maintain its own internal state in
-   `__IOBase_closed` and call flush() by itself, but it is redundant with
-   whatever behaviour a non-trivial derived class will implement. */
+PyDoc_STRVAR(_io__IOBase_readline__doc__,
+"readline($self, size=-1, /)\n"
+"--\n"
+"\n"
+"Read and return a line from the stream.\n"
+"\n"
+"If size is specified, at most size bytes will be read.\n"
+"\n"
+"The line terminator is always b\'\\n\' for binary files; for text\n"
+"files, the newlines argument to open can be used to select the line\n"
+"terminator(s) recognized.");
+
+#define _IO__IOBASE_READLINE_METHODDEF    \
+    {"readline", (PyCFunction)_io__IOBase_readline, METH_VARARGS, _io__IOBase_readline__doc__},
 
 static PyObject *
-iobase_close(PyObject *self, PyObject *args)
+_io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit);
+
+static PyObject *
+_io__IOBase_readline(PyObject *self, PyObject *args)
 {
-    PyObject *res;
+    PyObject *return_value = NULL;
+    Py_ssize_t limit = -1;
 
-    if (IS_CLOSED(self))
-        Py_RETURN_NONE;
+    if (!PyArg_ParseTuple(args,
+        "|O&:readline",
+        _PyIO_ConvertSsize_t, &limit))
+        goto exit;
+    return_value = _io__IOBase_readline_impl(self, limit);
 
-    res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
-
-    if (_PyObject_SetAttrId(self, &PyId___IOBase_closed, Py_True) < 0) {
-        Py_XDECREF(res);
-        return NULL;
-    }
-
-    if (res == NULL)
-        return NULL;
-
-    Py_DECREF(res);
-    Py_RETURN_NONE;
+exit:
+    return return_value;
 }
 
-/* Finalization and garbage collection support */
+PyDoc_STRVAR(_io__IOBase_readlines__doc__,
+"readlines($self, hint=-1, /)\n"
+"--\n"
+"\n"
+"Return a list of lines from the stream.\n"
+"\n"
+"hint can be specified to control the number of lines read: no more\n"
+"lines will be read if the total size (in bytes/characters) of all\n"
+"lines so far exceeds hint.");
 
-static void
-iobase_finalize(PyObject *self)
+#define _IO__IOBASE_READLINES_METHODDEF    \
+    {"readlines", (PyCFunction)_io__IOBase_readlines, METH_VARARGS, _io__IOBase_readlines__doc__},
+
+static PyObject *
+_io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint);
+
+static PyObject *
+_io__IOBase_readlines(PyObject *self, PyObject *args)
 {
-    PyObject *res;
-    PyObject *error_type, *error_value, *error_traceback;
-    int closed;
-    _Py_IDENTIFIER(_finalizing);
+    PyObject *return_value = NULL;
+    Py_ssize_t hint = -1;
 
-    /* Save the current exception, if any. */
-    PyErr_Fetch(&error_type, &error_value, &error_traceback);
+    if (!PyArg_ParseTuple(args,
+        "|O&:readlines",
+        _PyIO_ConvertSsize_t, &hint))
+        goto exit;
+    return_value = _io__IOBase_readlines_impl(self, hint);
 
-    /* If `closed` doesn't exist or can't be evaluated as bool, then the
-       object is probably in an unusable state, so ignore. */
-    res = PyObject_GetAttr(self, _PyIO_str_closed);
-    if (res == NULL) {
-        PyErr_Clear();
-        closed = -1;
-    }
-    else {
-        closed = PyObject_IsTrue(res);
-        Py_DECREF(res);
-        if (closed == -1)
-            PyErr_Clear();
-    }
-    if (closed == 0) {
-        /* Signal close() that it was called as part of the object
-           finalization process. */
-        if (_PyObject_SetAttrId(self, &PyId__finalizing, Py_True))
-            PyErr_Clear();
-        res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_close,
-                                          NULL);
-        /* Silencing I/O errors is bad, but printing spurious tracebacks is
-           equally as bad, and potentially more frequent (because of
-           shutdown issues). */
-        if (res == NULL)
-            PyErr_Clear();
-        else
-            Py_DECREF(res);
-    }
-
-    /* Restore the saved exception. */
-    PyErr_Restore(error_type, error_value, error_traceback);
+exit:
+    return return_value;
 }
 
-int
-_PyIOBase_finalize(PyObject *self)
+PyDoc_STRVAR(_io__IOBase_writelines__doc__,
+"writelines($self, lines, /)\n"
+"--\n"
+"\n");
+
+#define _IO__IOBASE_WRITELINES_METHODDEF    \
+    {"writelines", (PyCFunction)_io__IOBase_writelines, METH_O, _io__IOBase_writelines__doc__},
+
+PyDoc_STRVAR(_io__RawIOBase_read__doc__,
+"read($self, size=-1, /)\n"
+"--\n"
+"\n");
+
+#define _IO__RAWIOBASE_READ_METHODDEF    \
+    {"read", (PyCFunction)_io__RawIOBase_read, METH_VARARGS, _io__RawIOBase_read__doc__},
+
+static PyObject *
+_io__RawIOBase_read_impl(PyObject *self, Py_ssize_t n);
+
+static PyObject *
+_io__RawIOBase_read(PyObject *self, PyObject *args)
 {
-    int is_zombie;
+    PyObject *return_value = NULL;
+    Py_ssize_t n = -1;
 
-    /* If _PyIOBase_finalize() is called from a destructor, we need to
-       resurrect the object as calling close() can invoke arbitrary code. */
-    is_zombie = (Py_REFCNT(self) == 0);
-    if (is_zombie)
-        return PyObject_CallFinalizerFromDealloc(self);
-    else {
-        PyObject_CallFinalizer(self);
-        return 0;
-    }
+    if (!PyArg_ParseTuple(args,
+        "|n:read",
+        &n))
+        goto exit;
+    return_value = _io__RawIOBase_read_impl(self, n);
+
+exit:
+    return return_value;
 }
 
-static int
-iobase_traverse(iobase *self, visitproc visit, void *arg)
-{
-    Py_VISIT(self->dict);
-    return 0;
-}
+PyDoc_STRVAR(_io__RawIOBase_readall__doc__,
+"readall($self, /)\n"
+"--\n"
+"\n"
+"Read until EOF, using multiple read() call.");
 
-static int
-iobase_clear(iobase *self)
-{
-    Py_CLEAR(self->dict);
-    return 0;
-}
-
-/* Destructor */
-
-static void
-iobase_dealloc(iobase *self)
-{
-    /* NOTE: since IOBaseObject has its own dict, Python-defined attributes
-       are still available here for close() to use.
-       However, if the derived class declares a __slots__, those slots are
-       already gone.
-    */
-    if (_PyIOBase_finalize((PyObject *) self) < 0) {
-        /* When called from a heap type's dealloc, the type will be
-           decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */
-        if (PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE))
-            Py_INCREF(Py_TYPE(self));
-        return;
-    }
-    _PyObject_GC_UNTRACK(self);
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *) self);
-    Py_CLEAR(self->dict);
-    Py_TYPE(self)->tp_free((PyObject *) self);
-}
-
-/* Inquiry methods */
-
-PyDoc_STRVAR(iobase_seekable_doc,
-    "Return whether object supports random access.\n"
-    "\n"
-    "If False, seek(), tell() and truncate() will raise UnsupportedOperation.\n"
-    "This method may need to do a test seek().");
+#define _IO__RAWIOBASE_READALL_METHODDEF    \
+    {"readall", (PyCFunction)_io__RawIOBase_readall, METH_NOARGS, _io__RawIOBase_readall__doc__},
 
 static PyObject *
-iobase_seekable(PyObject *self, PyObject *args)
-{
-    Py_RETURN_FALSE;
-}
-
-PyObject *
-_PyIOBase_check_seekable(PyObject *self, PyObject *args)
-{
-    PyObject *res  = PyObject_CallMethodObjArgs(self, _PyIO_str_seekable, NULL);
-    if (res == NULL)
-        return NULL;
-    if (res != Py_True) {
-        Py_CLEAR(res);
-        iobase_unsupported("File or stream is not seekable.");
-        return NULL;
-    }
-    if (args == Py_True) {
-        Py_DECREF(res);
-    }
-    return res;
-}
-
-PyDoc_STRVAR(iobase_readable_doc,
-    "Return whether object was opened for reading.\n"
-    "\n"
-    "If False, read() will raise UnsupportedOperation.");
+_io__RawIOBase_readall_impl(PyObject *self);
 
 static PyObject *
-iobase_readable(PyObject *self, PyObject *args)
+_io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored))
 {
-    Py_RETURN_FALSE;
+    return _io__RawIOBase_readall_impl(self);
 }
-
-/* May be called with any object */
-PyObject *
-_PyIOBase_check_readable(PyObject *self, PyObject *args)
-{
-    PyObject *res  = PyObject_CallMethodObjArgs(self, _PyIO_str_readable, NULL);
-    if (res == NULL)
-        return NULL;
-    if (res != Py_True) {
-        Py_CLEAR(res);
-        iobase_unsupported("File or stream is not readable.");
-        return NULL;
-    }
-    if (args == Py_True) {
-        Py_DECREF(res);
-    }
-    return res;
-}
-
-PyDoc_STRVAR(iobase_writable_doc,
-    "Return whether object was opened for writing.\n"
-    "\n"
-    "If False, write() will raise UnsupportedOperation.");
-
-static PyObject *
-iobase_writable(PyObject *self, PyObject *args)
-{
-    Py_RETURN_FALSE;
-}
-
-/* May be called with any object */
-PyObject *
-_PyIOBase_check_writable(PyObject *self, PyObject *args)
-{
-    PyObject *res  = PyObject_CallMethodObjArgs(self, _PyIO_str_writable, NULL);
-    if (res == NULL)
-        return NULL;
-    if (res != Py_True) {
-        Py_CLEAR(res);
-        iobase_unsupported("File or stream is not writable.");
-        return NULL;
-    }
-    if (args == Py_True) {
-        Py_DECREF(res);
-    }
-    return res;
-}
-
-/* Context manager */
-
-static PyObject *
-iobase_enter(PyObject *self, PyObject *args)
-{
-    if (_PyIOBase_check_closed(self, Py_True) == NULL)
-        return NULL;
-
-    Py_INCREF(self);
-    return self;
-}
-
-static PyObject *
-iobase_exit(PyObject *self, PyObject *args)
-{
-    return PyObject_CallMethodObjArgs(self, _PyIO_str_close, NULL);
-}
-
-/* Lower-level APIs */
-
-/* XXX Should these be present even if unimplemented? */
-
-PyDoc_STRVAR(iobase_fileno_doc,
-    "Returns underlying file descriptor if one exists.\n"
-    "\n"
-    "An IOError is raised if the IO object does not use a file descriptor.\n");
-
-static PyObject *
-iobase_fileno(PyObject *self, PyObject *args)
-{
-    return iobase_unsupported("fileno");
-}
-
-PyDoc_STRVAR(iobase_isatty_doc,
-    "Return whether this is an 'interactive' stream.\n"
-    "\n"
-    "Return False if it can't be determined.\n");
-
-static PyObject *
-iobase_isatty(PyObject *self, PyObject *args)
-{
-    if (_PyIOBase_check_closed(self, Py_True) == NULL)
-        return NULL;
-    Py_RETURN_FALSE;
-}
-
-/* Readline(s) and writelines */
-
-PyDoc_STRVAR(iobase_readline_doc,
-    "Read and return a line from the stream.\n"
-    "\n"
-    "If limit is specified, at most limit bytes will be read.\n"
-    "\n"
-    "The line terminator is always b'\\n' for binary files; for text\n"
-    "files, the newlines argument to open can be used to select the line\n"
-    "terminator(s) recognized.\n");
-
-static PyObject *
-iobase_readline(PyObject *self, PyObject *args)
-{
-    /* For backwards compatibility, a (slowish) readline(). */
-
-    Py_ssize_t limit = -1;
-    int has_peek = 0;
-    PyObject *buffer, *result;
-    Py_ssize_t old_size = -1;
-    _Py_IDENTIFIER(peek);
-
-    if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit)) {
-        return NULL;
-    }
-
-    if (_PyObject_HasAttrId(self, &PyId_peek))
-        has_peek = 1;
-
-    buffer = PyByteArray_FromStringAndSize(NULL, 0);
-    if (buffer == NULL)
-        return NULL;
-
-    while (limit < 0 || Py_SIZE(buffer) < limit) {
-        Py_ssize_t nreadahead = 1;
-        PyObject *b;
-
-        if (has_peek) {
-            PyObject *readahead = _PyObject_CallMethodId(self, &PyId_peek, "i", 1);
-            if (readahead == NULL) {
-                /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
-                   when EINTR occurs so we needn't do it ourselves. */
-                if (_PyIO_trap_eintr()) {
-                    continue;
-                }
-                goto fail;
-            }
-            if (!PyBytes_Check(readahead)) {
-                PyErr_Format(PyExc_IOError,
-                             "peek() should have returned a bytes object, "
-                             "not '%.200s'", Py_TYPE(readahead)->tp_name);
-                Py_DECREF(readahead);
-                goto fail;
-            }
-            if (PyBytes_GET_SIZE(readahead) > 0) {
-                Py_ssize_t n = 0;
-                const char *buf = PyBytes_AS_STRING(readahead);
-                if (limit >= 0) {
-                    do {
-                        if (n >= PyBytes_GET_SIZE(readahead) || n >= limit)
-                            break;
-                        if (buf[n++] == '\n')
-                            break;
-                    } while (1);
-                }
-                else {
-                    do {
-                        if (n >= PyBytes_GET_SIZE(readahead))
-                            break;
-                        if (buf[n++] == '\n')
-                            break;
-                    } while (1);
-                }
-                nreadahead = n;
-            }
-            Py_DECREF(readahead);
-        }
-
-        b = _PyObject_CallMethodId(self, &PyId_read, "n", nreadahead);
-        if (b == NULL) {
-            /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
-               when EINTR occurs so we needn't do it ourselves. */
-            if (_PyIO_trap_eintr()) {
-                continue;
-            }
-            goto fail;
-        }
-        if (!PyBytes_Check(b)) {
-            PyErr_Format(PyExc_IOError,
-                         "read() should have returned a bytes object, "
-                         "not '%.200s'", Py_TYPE(b)->tp_name);
-            Py_DECREF(b);
-            goto fail;
-        }
-        if (PyBytes_GET_SIZE(b) == 0) {
-            Py_DECREF(b);
-            break;
-        }
-
-        old_size = PyByteArray_GET_SIZE(buffer);
-        if (PyByteArray_Resize(buffer, old_size + PyBytes_GET_SIZE(b)) < 0) {
-            Py_DECREF(b);
-            goto fail;
-        }
-        memcpy(PyByteArray_AS_STRING(buffer) + old_size,
-               PyBytes_AS_STRING(b), PyBytes_GET_SIZE(b));
-
-        Py_DECREF(b);
-
-        if (PyByteArray_AS_STRING(buffer)[PyByteArray_GET_SIZE(buffer) - 1] == '\n')
-            break;
-    }
-
-    result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(buffer),
-                                       PyByteArray_GET_SIZE(buffer));
-    Py_DECREF(buffer);
-    return result;
-  fail:
-    Py_DECREF(buffer);
-    return NULL;
-}
-
-static PyObject *
-iobase_iter(PyObject *self)
-{
-    if (_PyIOBase_check_closed(self, Py_True) == NULL)
-        return NULL;
-
-    Py_INCREF(self);
-    return self;
-}
-
-static PyObject *
-iobase_iternext(PyObject *self)
-{
-    PyObject *line = PyObject_CallMethodObjArgs(self, _PyIO_str_readline, NULL);
-
-    if (line == NULL)
-        return NULL;
-
-    if (PyObject_Size(line) == 0) {
-        Py_DECREF(line);
-        return NULL;
-    }
-
-    return line;
-}
-
-PyDoc_STRVAR(iobase_readlines_doc,
-    "Return a list of lines from the stream.\n"
-    "\n"
-    "hint can be specified to control the number of lines read: no more\n"
-    "lines will be read if the total size (in bytes/characters) of all\n"
-    "lines so far exceeds hint.");
-
-static PyObject *
-iobase_readlines(PyObject *self, PyObject *args)
-{
-    Py_ssize_t hint = -1, length = 0;
-    PyObject *result;
-
-    if (!PyArg_ParseTuple(args, "|O&:readlines", &_PyIO_ConvertSsize_t, &hint)) {
-        return NULL;
-    }
-
-    result = PyList_New(0);
-    if (result == NULL)
-        return NULL;
-
-    if (hint <= 0) {
-        /* XXX special-casing this made sense in the Python version in order
-           to remove the bytecode interpretation overhead, but it could
-           probably be removed here. */
-        _Py_IDENTIFIER(extend);
-        PyObject *ret = _PyObject_CallMethodId(result, &PyId_extend, "O", self);
-
-        if (ret == NULL) {
-            Py_DECREF(result);
-            return NULL;
-        }
-        Py_DECREF(ret);
-        return result;
-    }
-
-    while (1) {
-        PyObject *line = PyIter_Next(self);
-        if (line == NULL) {
-            if (PyErr_Occurred()) {
-                Py_DECREF(result);
-                return NULL;
-            }
-            else
-                break; /* StopIteration raised */
-        }
-
-        if (PyList_Append(result, line) < 0) {
-            Py_DECREF(line);
-            Py_DECREF(result);
-            return NULL;
-        }
-        length += PyObject_Size(line);
-        Py_DECREF(line);
-
-        if (length > hint)
-            break;
-    }
-    return result;
-}
-
-static PyObject *
-iobase_writelines(PyObject *self, PyObject *args)
-{
-    PyObject *lines, *iter, *res;
-
-    if (!PyArg_ParseTuple(args, "O:writelines", &lines)) {
-        return NULL;
-    }
-
-    if (_PyIOBase_check_closed(self, Py_True) == NULL)
-        return NULL;
-
-    iter = PyObject_GetIter(lines);
-    if (iter == NULL)
-        return NULL;
-
-    while (1) {
-        PyObject *line = PyIter_Next(iter);
-        if (line == NULL) {
-            if (PyErr_Occurred()) {
-                Py_DECREF(iter);
-                return NULL;
-            }
-            else
-                break; /* Stop Iteration */
-        }
-
-        res = NULL;
-        do {
-            res = PyObject_CallMethodObjArgs(self, _PyIO_str_write, line, NULL);
-        } while (res == NULL && _PyIO_trap_eintr());
-        Py_DECREF(line);
-        if (res == NULL) {
-            Py_DECREF(iter);
-            return NULL;
-        }
-        Py_DECREF(res);
-    }
-    Py_DECREF(iter);
-    Py_RETURN_NONE;
-}
-
-static PyMethodDef iobase_methods[] = {
-    {"seek", iobase_seek, METH_VARARGS, iobase_seek_doc},
-    {"tell", iobase_tell, METH_NOARGS, iobase_tell_doc},
-    {"truncate", iobase_truncate, METH_VARARGS, iobase_truncate_doc},
-    {"flush", iobase_flush, METH_NOARGS, iobase_flush_doc},
-    {"close", iobase_close, METH_NOARGS, iobase_close_doc},
-
-    {"seekable", iobase_seekable, METH_NOARGS, iobase_seekable_doc},
-    {"readable", iobase_readable, METH_NOARGS, iobase_readable_doc},
-    {"writable", iobase_writable, METH_NOARGS, iobase_writable_doc},
-
-    {"_checkClosed",   _PyIOBase_check_closed, METH_NOARGS},
-    {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS},
-    {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS},
-    {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS},
-
-    {"fileno", iobase_fileno, METH_NOARGS, iobase_fileno_doc},
-    {"isatty", iobase_isatty, METH_NOARGS, iobase_isatty_doc},
-
-    {"__enter__", iobase_enter, METH_NOARGS},
-    {"__exit__", iobase_exit, METH_VARARGS},
-
-    {"readline", iobase_readline, METH_VARARGS, iobase_readline_doc},
-    {"readlines", iobase_readlines, METH_VARARGS, iobase_readlines_doc},
-    {"writelines", iobase_writelines, METH_VARARGS},
-
-    {NULL, NULL}
-};
-
-static PyGetSetDef iobase_getset[] = {
-    {"__dict__", PyObject_GenericGetDict, NULL, NULL},
-    {"closed", (getter)iobase_closed_get, NULL, NULL},
-    {NULL}
-};
-
-
-PyTypeObject PyIOBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io._IOBase",              /*tp_name*/
-    sizeof(iobase),             /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)iobase_dealloc, /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,   /*tp_flags*/
-    iobase_doc,                 /* tp_doc */
-    (traverseproc)iobase_traverse, /* tp_traverse */
-    (inquiry)iobase_clear,      /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(iobase, weakreflist), /* tp_weaklistoffset */
-    iobase_iter,                /* tp_iter */
-    iobase_iternext,            /* tp_iternext */
-    iobase_methods,             /* tp_methods */
-    0,                          /* tp_members */
-    iobase_getset,              /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(iobase, dict),     /* tp_dictoffset */
-    0,                          /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    (destructor)iobase_finalize, /* tp_finalize */
-};
-
-
-/*
- * RawIOBase class, Inherits from IOBase.
- */
-PyDoc_STRVAR(rawiobase_doc,
-             "Base class for raw binary I/O.");
-
-/*
- * The read() method is implemented by calling readinto(); derived classes
- * that want to support read() only need to implement readinto() as a
- * primitive operation.  In general, readinto() can be more efficient than
- * read().
- *
- * (It would be tempting to also provide an implementation of readinto() in
- * terms of read(), in case the latter is a more suitable primitive operation,
- * but that would lead to nasty recursion in case a subclass doesn't implement
- * either.)
-*/
-
-static PyObject *
-rawiobase_read(PyObject *self, PyObject *args)
-{
-    Py_ssize_t n = -1;
-    PyObject *b, *res;
-
-    if (!PyArg_ParseTuple(args, "|n:read", &n)) {
-        return NULL;
-    }
-
-    if (n < 0) {
-        _Py_IDENTIFIER(readall);
-
-        return _PyObject_CallMethodId(self, &PyId_readall, NULL);
-    }
-
-    /* TODO: allocate a bytes object directly instead and manually construct
-       a writable memoryview pointing to it. */
-    b = PyByteArray_FromStringAndSize(NULL, n);
-    if (b == NULL)
-        return NULL;
-
-    res = PyObject_CallMethodObjArgs(self, _PyIO_str_readinto, b, NULL);
-    if (res == NULL || res == Py_None) {
-        Py_DECREF(b);
-        return res;
-    }
-
-    n = PyNumber_AsSsize_t(res, PyExc_ValueError);
-    Py_DECREF(res);
-    if (n == -1 && PyErr_Occurred()) {
-        Py_DECREF(b);
-        return NULL;
-    }
-
-    res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n);
-    Py_DECREF(b);
-    return res;
-}
-
-
-PyDoc_STRVAR(rawiobase_readall_doc,
-             "Read until EOF, using multiple read() call.");
-
-static PyObject *
-rawiobase_readall(PyObject *self, PyObject *args)
-{
-    int r;
-    PyObject *chunks = PyList_New(0);
-    PyObject *result;
-
-    if (chunks == NULL)
-        return NULL;
-
-    while (1) {
-        PyObject *data = _PyObject_CallMethodId(self, &PyId_read,
-                                                "i", DEFAULT_BUFFER_SIZE);
-        if (!data) {
-            /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
-               when EINTR occurs so we needn't do it ourselves. */
-            if (_PyIO_trap_eintr()) {
-                continue;
-            }
-            Py_DECREF(chunks);
-            return NULL;
-        }
-        if (data == Py_None) {
-            if (PyList_GET_SIZE(chunks) == 0) {
-                Py_DECREF(chunks);
-                return data;
-            }
-            Py_DECREF(data);
-            break;
-        }
-        if (!PyBytes_Check(data)) {
-            Py_DECREF(chunks);
-            Py_DECREF(data);
-            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
-            return NULL;
-        }
-        if (PyBytes_GET_SIZE(data) == 0) {
-            /* EOF */
-            Py_DECREF(data);
-            break;
-        }
-        r = PyList_Append(chunks, data);
-        Py_DECREF(data);
-        if (r < 0) {
-            Py_DECREF(chunks);
-            return NULL;
-        }
-    }
-    result = _PyBytes_Join(_PyIO_empty_bytes, chunks);
-    Py_DECREF(chunks);
-    return result;
-}
-
-static PyMethodDef rawiobase_methods[] = {
-    {"read", rawiobase_read, METH_VARARGS},
-    {"readall", rawiobase_readall, METH_NOARGS, rawiobase_readall_doc},
-    {NULL, NULL}
-};
-
-PyTypeObject PyRawIOBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io._RawIOBase",                /*tp_name*/
-    0,                          /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    0,                          /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE,  /*tp_flags*/
-    rawiobase_doc,              /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    rawiobase_methods,          /* tp_methods */
-    0,                          /* tp_members */
-    0,                          /* tp_getset */
-    &PyIOBase_Type,             /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    0,                          /* tp_dictoffset */
-    0,                          /* tp_init */
-    0,                          /* tp_alloc */
-    0,                          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
+/*[clinic end generated code: output=84eef4b7541f54b7 input=a9049054013a1b77]*/
diff --git a/Modules/_io/stringio.c b/Modules/_io/clinic/stringio.c.h
copy from Modules/_io/stringio.c
copy to Modules/_io/clinic/stringio.c.h
--- a/Modules/_io/stringio.c
+++ b/Modules/_io/clinic/stringio.c.h
@@ -1,1034 +1,288 @@
-#define PY_SSIZE_T_CLEAN
-#include "Python.h"
-#include "structmember.h"
-#include "accu.h"
-#include "_iomodule.h"
+/*[clinic input]
+preserve
+[clinic start generated code]*/
 
-/* Implementation note: the buffer is always at least one character longer
-   than the enclosed string, for proper functioning of _PyIO_find_line_ending.
-*/
+PyDoc_STRVAR(_io_StringIO_getvalue__doc__,
+"getvalue($self, /)\n"
+"--\n"
+"\n"
+"Retrieve the entire contents of the object.");
 
-#define STATE_REALIZED 1
-#define STATE_ACCUMULATING 2
+#define _IO_STRINGIO_GETVALUE_METHODDEF    \
+    {"getvalue", (PyCFunction)_io_StringIO_getvalue, METH_NOARGS, _io_StringIO_getvalue__doc__},
 
-typedef struct {
-    PyObject_HEAD
-    Py_UCS4 *buf;
-    Py_ssize_t pos;
-    Py_ssize_t string_size;
-    size_t buf_size;
+static PyObject *
+_io_StringIO_getvalue_impl(stringio *self);
 
-    /* The stringio object can be in two states: accumulating or realized.
-       In accumulating state, the internal buffer contains nothing and
-       the contents are given by the embedded _PyAccu structure.
-       In realized state, the internal buffer is meaningful and the
-       _PyAccu is destroyed.
-    */
-    int state;
-    _PyAccu accu;
-
-    char ok; /* initialized? */
-    char closed;
-    char readuniversal;
-    char readtranslate;
-    PyObject *decoder;
-    PyObject *readnl;
-    PyObject *writenl;
-
-    PyObject *dict;
-    PyObject *weakreflist;
-} stringio;
-
-#define CHECK_INITIALIZED(self) \
-    if (self->ok <= 0) { \
-        PyErr_SetString(PyExc_ValueError, \
-            "I/O operation on uninitialized object"); \
-        return NULL; \
-    }
-
-#define CHECK_CLOSED(self) \
-    if (self->closed) { \
-        PyErr_SetString(PyExc_ValueError, \
-            "I/O operation on closed file"); \
-        return NULL; \
-    }
-
-#define ENSURE_REALIZED(self) \
-    if (realize(self) < 0) { \
-        return NULL; \
-    }
-
-PyDoc_STRVAR(stringio_doc,
-    "Text I/O implementation using an in-memory buffer.\n"
-    "\n"
-    "The initial_value argument sets the value of object.  The newline\n"
-    "argument is like the one of TextIOWrapper's constructor.");
-
-
-/* Internal routine for changing the size, in terms of characters, of the
-   buffer of StringIO objects.  The caller should ensure that the 'size'
-   argument is non-negative.  Returns 0 on success, -1 otherwise. */
-static int
-resize_buffer(stringio *self, size_t size)
+static PyObject *
+_io_StringIO_getvalue(stringio *self, PyObject *Py_UNUSED(ignored))
 {
-    /* Here, unsigned types are used to avoid dealing with signed integer
-       overflow, which is undefined in C. */
-    size_t alloc = self->buf_size;
-    Py_UCS4 *new_buf = NULL;
-
-    assert(self->buf != NULL);
-
-    /* Reserve one more char for line ending detection. */
-    size = size + 1;
-    /* For simplicity, stay in the range of the signed type. Anyway, Python
-       doesn't allow strings to be longer than this. */
-    if (size > PY_SSIZE_T_MAX)
-        goto overflow;
-
-    if (size < alloc / 2) {
-        /* Major downsize; resize down to exact size. */
-        alloc = size + 1;
-    }
-    else if (size < alloc) {
-        /* Within allocated size; quick exit */
-        return 0;
-    }
-    else if (size <= alloc * 1.125) {
-        /* Moderate upsize; overallocate similar to list_resize() */
-        alloc = size + (size >> 3) + (size < 9 ? 3 : 6);
-    }
-    else {
-        /* Major upsize; resize up to exact size */
-        alloc = size + 1;
-    }
-
-    if (alloc > PY_SIZE_MAX / sizeof(Py_UCS4))
-        goto overflow;
-    new_buf = (Py_UCS4 *)PyMem_Realloc(self->buf, alloc * sizeof(Py_UCS4));
-    if (new_buf == NULL) {
-        PyErr_NoMemory();
-        return -1;
-    }
-    self->buf_size = alloc;
-    self->buf = new_buf;
-
-    return 0;
-
-  overflow:
-    PyErr_SetString(PyExc_OverflowError,
-                    "new buffer size too large");
-    return -1;
+    return _io_StringIO_getvalue_impl(self);
 }
 
+PyDoc_STRVAR(_io_StringIO_tell__doc__,
+"tell($self, /)\n"
+"--\n"
+"\n"
+"Tell the current file position.");
+
+#define _IO_STRINGIO_TELL_METHODDEF    \
+    {"tell", (PyCFunction)_io_StringIO_tell, METH_NOARGS, _io_StringIO_tell__doc__},
+
 static PyObject *
-make_intermediate(stringio *self)
+_io_StringIO_tell_impl(stringio *self);
+
+static PyObject *
+_io_StringIO_tell(stringio *self, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *intermediate = _PyAccu_Finish(&self->accu);
-    self->state = STATE_REALIZED;
-    if (intermediate == NULL)
-        return NULL;
-    if (_PyAccu_Init(&self->accu) ||
-        _PyAccu_Accumulate(&self->accu, intermediate)) {
-        Py_DECREF(intermediate);
-        return NULL;
-    }
-    self->state = STATE_ACCUMULATING;
-    return intermediate;
+    return _io_StringIO_tell_impl(self);
 }
 
-static int
-realize(stringio *self)
+PyDoc_STRVAR(_io_StringIO_read__doc__,
+"read($self, size=None, /)\n"
+"--\n"
+"\n"
+"Read at most size characters, returned as a string.\n"
+"\n"
+"If the argument is negative or omitted, read until EOF\n"
+"is reached. Return an empty string at EOF.");
+
+#define _IO_STRINGIO_READ_METHODDEF    \
+    {"read", (PyCFunction)_io_StringIO_read, METH_VARARGS, _io_StringIO_read__doc__},
+
+static PyObject *
+_io_StringIO_read_impl(stringio *self, PyObject *arg);
+
+static PyObject *
+_io_StringIO_read(stringio *self, PyObject *args)
 {
-    Py_ssize_t len;
-    PyObject *intermediate;
+    PyObject *return_value = NULL;
+    PyObject *arg = Py_None;
 
-    if (self->state == STATE_REALIZED)
-        return 0;
-    assert(self->state == STATE_ACCUMULATING);
-    self->state = STATE_REALIZED;
+    if (!PyArg_UnpackTuple(args, "read",
+        0, 1,
+        &arg))
+        goto exit;
+    return_value = _io_StringIO_read_impl(self, arg);
 
-    intermediate = _PyAccu_Finish(&self->accu);
-    if (intermediate == NULL)
-        return -1;
-
-    /* Append the intermediate string to the internal buffer.
-       The length should be equal to the current cursor position.
-     */
-    len = PyUnicode_GET_LENGTH(intermediate);
-    if (resize_buffer(self, len) < 0) {
-        Py_DECREF(intermediate);
-        return -1;
-    }
-    if (!PyUnicode_AsUCS4(intermediate, self->buf, len, 0)) {
-        Py_DECREF(intermediate);
-        return -1;
-    }
-
-    Py_DECREF(intermediate);
-    return 0;
+exit:
+    return return_value;
 }
 
-/* Internal routine for writing a whole PyUnicode object to the buffer of a
-   StringIO object. Returns 0 on success, or -1 on error. */
-static Py_ssize_t
-write_str(stringio *self, PyObject *obj)
+PyDoc_STRVAR(_io_StringIO_readline__doc__,
+"readline($self, size=None, /)\n"
+"--\n"
+"\n"
+"Read until newline or EOF.\n"
+"\n"
+"Returns an empty string if EOF is hit immediately.");
+
+#define _IO_STRINGIO_READLINE_METHODDEF    \
+    {"readline", (PyCFunction)_io_StringIO_readline, METH_VARARGS, _io_StringIO_readline__doc__},
+
+static PyObject *
+_io_StringIO_readline_impl(stringio *self, PyObject *arg);
+
+static PyObject *
+_io_StringIO_readline(stringio *self, PyObject *args)
 {
-    Py_ssize_t len;
-    PyObject *decoded = NULL;
+    PyObject *return_value = NULL;
+    PyObject *arg = Py_None;
 
-    assert(self->buf != NULL);
-    assert(self->pos >= 0);
+    if (!PyArg_UnpackTuple(args, "readline",
+        0, 1,
+        &arg))
+        goto exit;
+    return_value = _io_StringIO_readline_impl(self, arg);
 
-    if (self->decoder != NULL) {
-        decoded = _PyIncrementalNewlineDecoder_decode(
-            self->decoder, obj, 1 /* always final */);
-    }
-    else {
-        decoded = obj;
-        Py_INCREF(decoded);
-    }
-    if (self->writenl) {
-        PyObject *translated = PyUnicode_Replace(
-            decoded, _PyIO_str_nl, self->writenl, -1);
-        Py_DECREF(decoded);
-        decoded = translated;
-    }
-    if (decoded == NULL)
-        return -1;
-
-    assert(PyUnicode_Check(decoded));
-    if (PyUnicode_READY(decoded)) {
-        Py_DECREF(decoded);
-        return -1;
-    }
-    len = PyUnicode_GET_LENGTH(decoded);
-    assert(len >= 0);
-
-    /* This overflow check is not strictly necessary. However, it avoids us to
-       deal with funky things like comparing an unsigned and a signed
-       integer. */
-    if (self->pos > PY_SSIZE_T_MAX - len) {
-        PyErr_SetString(PyExc_OverflowError,
-                        "new position too large");
-        goto fail;
-    }
-
-    if (self->state == STATE_ACCUMULATING) {
-        if (self->string_size == self->pos) {
-            if (_PyAccu_Accumulate(&self->accu, decoded))
-                goto fail;
-            goto success;
-        }
-        if (realize(self))
-            goto fail;
-    }
-
-    if (self->pos + len > self->string_size) {
-        if (resize_buffer(self, self->pos + len) < 0)
-            goto fail;
-    }
-
-    if (self->pos > self->string_size) {
-        /* In case of overseek, pad with null bytes the buffer region between
-           the end of stream and the current position.
-
-          0   lo      string_size                           hi
-          |   |<---used--->|<----------available----------->|
-          |   |            <--to pad-->|<---to write--->    |
-          0   buf                   position
-
-        */
-        memset(self->buf + self->string_size, '\0',
-               (self->pos - self->string_size) * sizeof(Py_UCS4));
-    }
-
-    /* Copy the data to the internal buffer, overwriting some of the
-       existing data if self->pos < self->string_size. */
-    if (!PyUnicode_AsUCS4(decoded,
-                          self->buf + self->pos,
-                          self->buf_size - self->pos,
-                          0))
-        goto fail;
-
-success:
-    /* Set the new length of the internal string if it has changed. */
-    self->pos += len;
-    if (self->string_size < self->pos)
-        self->string_size = self->pos;
-
-    Py_DECREF(decoded);
-    return 0;
-
-fail:
-    Py_XDECREF(decoded);
-    return -1;
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(stringio_getvalue_doc,
-    "Retrieve the entire contents of the object.");
+PyDoc_STRVAR(_io_StringIO_truncate__doc__,
+"truncate($self, pos=None, /)\n"
+"--\n"
+"\n"
+"Truncate size to pos.\n"
+"\n"
+"The pos argument defaults to the current file position, as\n"
+"returned by tell().  The current file position is unchanged.\n"
+"Returns the new absolute position.");
+
+#define _IO_STRINGIO_TRUNCATE_METHODDEF    \
+    {"truncate", (PyCFunction)_io_StringIO_truncate, METH_VARARGS, _io_StringIO_truncate__doc__},
 
 static PyObject *
-stringio_getvalue(stringio *self)
+_io_StringIO_truncate_impl(stringio *self, PyObject *arg);
+
+static PyObject *
+_io_StringIO_truncate(stringio *self, PyObject *args)
 {
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    if (self->state == STATE_ACCUMULATING)
-        return make_intermediate(self);
-    return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, self->buf,
-                                     self->string_size);
+    PyObject *return_value = NULL;
+    PyObject *arg = Py_None;
+
+    if (!PyArg_UnpackTuple(args, "truncate",
+        0, 1,
+        &arg))
+        goto exit;
+    return_value = _io_StringIO_truncate_impl(self, arg);
+
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(stringio_tell_doc,
-    "Tell the current file position.");
+PyDoc_STRVAR(_io_StringIO_seek__doc__,
+"seek($self, pos, whence=0, /)\n"
+"--\n"
+"\n"
+"Change stream position.\n"
+"\n"
+"Seek to character offset pos relative to position indicated by whence:\n"
+"    0  Start of stream (the default).  pos should be >= 0;\n"
+"    1  Current position - pos must be 0;\n"
+"    2  End of stream - pos must be 0.\n"
+"Returns the new absolute position.");
+
+#define _IO_STRINGIO_SEEK_METHODDEF    \
+    {"seek", (PyCFunction)_io_StringIO_seek, METH_VARARGS, _io_StringIO_seek__doc__},
 
 static PyObject *
-stringio_tell(stringio *self)
+_io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence);
+
+static PyObject *
+_io_StringIO_seek(stringio *self, PyObject *args)
 {
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    return PyLong_FromSsize_t(self->pos);
+    PyObject *return_value = NULL;
+    Py_ssize_t pos;
+    int whence = 0;
+
+    if (!PyArg_ParseTuple(args,
+        "n|i:seek",
+        &pos, &whence))
+        goto exit;
+    return_value = _io_StringIO_seek_impl(self, pos, whence);
+
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(stringio_read_doc,
-    "Read at most n characters, returned as a string.\n"
-    "\n"
-    "If the argument is negative or omitted, read until EOF\n"
-    "is reached. Return an empty string at EOF.\n");
+PyDoc_STRVAR(_io_StringIO_write__doc__,
+"write($self, s, /)\n"
+"--\n"
+"\n"
+"Write string to file.\n"
+"\n"
+"Returns the number of characters written, which is always equal to\n"
+"the length of the string.");
+
+#define _IO_STRINGIO_WRITE_METHODDEF    \
+    {"write", (PyCFunction)_io_StringIO_write, METH_O, _io_StringIO_write__doc__},
+
+PyDoc_STRVAR(_io_StringIO_close__doc__,
+"close($self, /)\n"
+"--\n"
+"\n"
+"Close the IO object.\n"
+"\n"
+"Attempting any further operation after the object is closed\n"
+"will raise a ValueError.\n"
+"\n"
+"This method has no effect if the file is already closed.");
+
+#define _IO_STRINGIO_CLOSE_METHODDEF    \
+    {"close", (PyCFunction)_io_StringIO_close, METH_NOARGS, _io_StringIO_close__doc__},
 
 static PyObject *
-stringio_read(stringio *self, PyObject *args)
+_io_StringIO_close_impl(stringio *self);
+
+static PyObject *
+_io_StringIO_close(stringio *self, PyObject *Py_UNUSED(ignored))
 {
-    Py_ssize_t size, n;
-    Py_UCS4 *output;
-    PyObject *arg = Py_None;
-
-    CHECK_INITIALIZED(self);
-    if (!PyArg_ParseTuple(args, "|O:read", &arg))
-        return NULL;
-    CHECK_CLOSED(self);
-
-    if (PyNumber_Check(arg)) {
-        size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
-        if (size == -1 && PyErr_Occurred())
-            return NULL;
-    }
-    else if (arg == Py_None) {
-        /* Read until EOF is reached, by default. */
-        size = -1;
-    }
-    else {
-        PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
-                     Py_TYPE(arg)->tp_name);
-        return NULL;
-    }
-
-    /* adjust invalid sizes */
-    n = self->string_size - self->pos;
-    if (size < 0 || size > n) {
-        size = n;
-        if (size < 0)
-            size = 0;
-    }
-
-    /* Optimization for seek(0); read() */
-    if (self->state == STATE_ACCUMULATING && self->pos == 0 && size == n) {
-        PyObject *result = make_intermediate(self);
-        self->pos = self->string_size;
-        return result;
-    }
-
-    ENSURE_REALIZED(self);
-    output = self->buf + self->pos;
-    self->pos += size;
-    return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, output, size);
+    return _io_StringIO_close_impl(self);
 }
 
-/* Internal helper, used by stringio_readline and stringio_iternext */
-static PyObject *
-_stringio_readline(stringio *self, Py_ssize_t limit)
+PyDoc_STRVAR(_io_StringIO___init____doc__,
+"StringIO(initial_value=\'\', newline=\'\\n\')\n"
+"--\n"
+"\n"
+"Text I/O implementation using an in-memory buffer.\n"
+"\n"
+"The initial_value argument sets the value of object.  The newline\n"
+"argument is like the one of TextIOWrapper\'s constructor.");
+
+static int
+_io_StringIO___init___impl(stringio *self, PyObject *value,
+                           PyObject *newline_obj);
+
+static int
+_io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-    Py_UCS4 *start, *end, old_char;
-    Py_ssize_t len, consumed;
+    int return_value = -1;
+    static char *_keywords[] = {"initial_value", "newline", NULL};
+    PyObject *value = NULL;
+    PyObject *newline_obj = NULL;
 
-    /* In case of overseek, return the empty string */
-    if (self->pos >= self->string_size)
-        return PyUnicode_New(0, 0);
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "|OO:StringIO", _keywords,
+        &value, &newline_obj))
+        goto exit;
+    return_value = _io_StringIO___init___impl((stringio *)self, value, newline_obj);
 
-    start = self->buf + self->pos;
-    if (limit < 0 || limit > self->string_size - self->pos)
-        limit = self->string_size - self->pos;
-
-    end = start + limit;
-    old_char = *end;
-    *end = '\0';
-    len = _PyIO_find_line_ending(
-        self->readtranslate, self->readuniversal, self->readnl,
-        PyUnicode_4BYTE_KIND, (char*)start, (char*)end, &consumed);
-    *end = old_char;
-    /* If we haven't found any line ending, we just return everything
-       (`consumed` is ignored). */
-    if (len < 0)
-        len = limit;
-    self->pos += len;
-    return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, start, len);
+exit:
+    return return_value;
 }
 
-PyDoc_STRVAR(stringio_readline_doc,
-    "Read until newline or EOF.\n"
-    "\n"
-    "Returns an empty string if EOF is hit immediately.\n");
+PyDoc_STRVAR(_io_StringIO_readable__doc__,
+"readable($self, /)\n"
+"--\n"
+"\n"
+"Returns True if the IO object can be read.");
+
+#define _IO_STRINGIO_READABLE_METHODDEF    \
+    {"readable", (PyCFunction)_io_StringIO_readable, METH_NOARGS, _io_StringIO_readable__doc__},
 
 static PyObject *
-stringio_readline(stringio *self, PyObject *args)
+_io_StringIO_readable_impl(stringio *self);
+
+static PyObject *
+_io_StringIO_readable(stringio *self, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *arg = Py_None;
-    Py_ssize_t limit = -1;
-
-    CHECK_INITIALIZED(self);
-    if (!PyArg_ParseTuple(args, "|O:readline", &arg))
-        return NULL;
-    CHECK_CLOSED(self);
-    ENSURE_REALIZED(self);
-
-    if (PyNumber_Check(arg)) {
-        limit = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
-        if (limit == -1 && PyErr_Occurred())
-            return NULL;
-    }
-    else if (arg != Py_None) {
-        PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
-                     Py_TYPE(arg)->tp_name);
-        return NULL;
-    }
-    return _stringio_readline(self, limit);
+    return _io_StringIO_readable_impl(self);
 }
 
+PyDoc_STRVAR(_io_StringIO_writable__doc__,
+"writable($self, /)\n"
+"--\n"
+"\n"
+"Returns True if the IO object can be written.");
+
+#define _IO_STRINGIO_WRITABLE_METHODDEF    \
+    {"writable", (PyCFunction)_io_StringIO_writable, METH_NOARGS, _io_StringIO_writable__doc__},
+
 static PyObject *
-stringio_iternext(stringio *self)
+_io_StringIO_writable_impl(stringio *self);
+
+static PyObject *
+_io_StringIO_writable(stringio *self, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *line;
-
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    ENSURE_REALIZED(self);
-
-    if (Py_TYPE(self) == &PyStringIO_Type) {
-        /* Skip method call overhead for speed */
-        line = _stringio_readline(self, -1);
-    }
-    else {
-        /* XXX is subclassing StringIO really supported? */
-        line = PyObject_CallMethodObjArgs((PyObject *)self,
-                                           _PyIO_str_readline, NULL);
-        if (line && !PyUnicode_Check(line)) {
-            PyErr_Format(PyExc_IOError,
-                         "readline() should have returned an str object, "
-                         "not '%.200s'", Py_TYPE(line)->tp_name);
-            Py_DECREF(line);
-            return NULL;
-        }
-    }
-
-    if (line == NULL)
-        return NULL;
-
-    if (PyUnicode_GET_LENGTH(line) == 0) {
-        /* Reached EOF */
-        Py_DECREF(line);
-        return NULL;
-    }
-
-    return line;
+    return _io_StringIO_writable_impl(self);
 }
 
-PyDoc_STRVAR(stringio_truncate_doc,
-    "Truncate size to pos.\n"
-    "\n"
-    "The pos argument defaults to the current file position, as\n"
-    "returned by tell().  The current file position is unchanged.\n"
-    "Returns the new absolute position.\n");
+PyDoc_STRVAR(_io_StringIO_seekable__doc__,
+"seekable($self, /)\n"
+"--\n"
+"\n"
+"Returns True if the IO object can be seeked.");
+
+#define _IO_STRINGIO_SEEKABLE_METHODDEF    \
+    {"seekable", (PyCFunction)_io_StringIO_seekable, METH_NOARGS, _io_StringIO_seekable__doc__},
 
 static PyObject *
-stringio_truncate(stringio *self, PyObject *args)
-{
-    Py_ssize_t size;
-    PyObject *arg = Py_None;
-
-    CHECK_INITIALIZED(self);
-    if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
-        return NULL;
-    CHECK_CLOSED(self);
-
-    if (PyNumber_Check(arg)) {
-        size = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
-        if (size == -1 && PyErr_Occurred())
-            return NULL;
-    }
-    else if (arg == Py_None) {
-        /* Truncate to current position if no argument is passed. */
-        size = self->pos;
-    }
-    else {
-        PyErr_Format(PyExc_TypeError, "integer argument expected, got '%s'",
-                     Py_TYPE(arg)->tp_name);
-        return NULL;
-    }
-
-    if (size < 0) {
-        PyErr_Format(PyExc_ValueError,
-                     "Negative size value %zd", size);
-        return NULL;
-    }
-
-    if (size < self->string_size) {
-        ENSURE_REALIZED(self);
-        if (resize_buffer(self, size) < 0)
-            return NULL;
-        self->string_size = size;
-    }
-
-    return PyLong_FromSsize_t(size);
-}
-
-PyDoc_STRVAR(stringio_seek_doc,
-    "Change stream position.\n"
-    "\n"
-    "Seek to character offset pos relative to position indicated by whence:\n"
-    "    0  Start of stream (the default).  pos should be >= 0;\n"
-    "    1  Current position - pos must be 0;\n"
-    "    2  End of stream - pos must be 0.\n"
-    "Returns the new absolute position.\n");
+_io_StringIO_seekable_impl(stringio *self);
 
 static PyObject *
-stringio_seek(stringio *self, PyObject *args)
+_io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored))
 {
-    Py_ssize_t pos;
-    int mode = 0;
-
-    CHECK_INITIALIZED(self);
-    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode))
-        return NULL;
-    CHECK_CLOSED(self);
-
-    if (mode != 0 && mode != 1 && mode != 2) {
-        PyErr_Format(PyExc_ValueError,
-                     "Invalid whence (%i, should be 0, 1 or 2)", mode);
-        return NULL;
-    }
-    else if (pos < 0 && mode == 0) {
-        PyErr_Format(PyExc_ValueError,
-                     "Negative seek position %zd", pos);
-        return NULL;
-    }
-    else if (mode != 0 && pos != 0) {
-        PyErr_SetString(PyExc_IOError,
-                        "Can't do nonzero cur-relative seeks");
-        return NULL;
-    }
-
-    /* mode 0: offset relative to beginning of the string.
-       mode 1: no change to current position.
-       mode 2: change position to end of file. */
-    if (mode == 1) {
-        pos = self->pos;
-    }
-    else if (mode == 2) {
-        pos = self->string_size;
-    }
-
-    self->pos = pos;
-
-    return PyLong_FromSsize_t(self->pos);
+    return _io_StringIO_seekable_impl(self);
 }
-
-PyDoc_STRVAR(stringio_write_doc,
-    "Write string to file.\n"
-    "\n"
-    "Returns the number of characters written, which is always equal to\n"
-    "the length of the string.\n");
-
-static PyObject *
-stringio_write(stringio *self, PyObject *obj)
-{
-    Py_ssize_t size;
-
-    CHECK_INITIALIZED(self);
-    if (!PyUnicode_Check(obj)) {
-        PyErr_Format(PyExc_TypeError, "string argument expected, got '%s'",
-                     Py_TYPE(obj)->tp_name);
-        return NULL;
-    }
-    if (PyUnicode_READY(obj))
-        return NULL;
-    CHECK_CLOSED(self);
-    size = PyUnicode_GET_LENGTH(obj);
-
-    if (size > 0 && write_str(self, obj) < 0)
-        return NULL;
-
-    return PyLong_FromSsize_t(size);
-}
-
-PyDoc_STRVAR(stringio_close_doc,
-    "Close the IO object. Attempting any further operation after the\n"
-    "object is closed will raise a ValueError.\n"
-    "\n"
-    "This method has no effect if the file is already closed.\n");
-
-static PyObject *
-stringio_close(stringio *self)
-{
-    self->closed = 1;
-    /* Free up some memory */
-    if (resize_buffer(self, 0) < 0)
-        return NULL;
-    _PyAccu_Destroy(&self->accu);
-    Py_CLEAR(self->readnl);
-    Py_CLEAR(self->writenl);
-    Py_CLEAR(self->decoder);
-    Py_RETURN_NONE;
-}
-
-static int
-stringio_traverse(stringio *self, visitproc visit, void *arg)
-{
-    Py_VISIT(self->dict);
-    return 0;
-}
-
-static int
-stringio_clear(stringio *self)
-{
-    Py_CLEAR(self->dict);
-    return 0;
-}
-
-static void
-stringio_dealloc(stringio *self)
-{
-    _PyObject_GC_UNTRACK(self);
-    self->ok = 0;
-    if (self->buf) {
-        PyMem_Free(self->buf);
-        self->buf = NULL;
-    }
-    _PyAccu_Destroy(&self->accu);
-    Py_CLEAR(self->readnl);
-    Py_CLEAR(self->writenl);
-    Py_CLEAR(self->decoder);
-    Py_CLEAR(self->dict);
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *) self);
-    Py_TYPE(self)->tp_free(self);
-}
-
-static PyObject *
-stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    stringio *self;
-
-    assert(type != NULL && type->tp_alloc != NULL);
-    self = (stringio *)type->tp_alloc(type, 0);
-    if (self == NULL)
-        return NULL;
-
-    /* tp_alloc initializes all the fields to zero. So we don't have to
-       initialize them here. */
-
-    self->buf = (Py_UCS4 *)PyMem_Malloc(0);
-    if (self->buf == NULL) {
-        Py_DECREF(self);
-        return PyErr_NoMemory();
-    }
-
-    return (PyObject *)self;
-}
-
-static int
-stringio_init(stringio *self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"initial_value", "newline", NULL};
-    PyObject *value = NULL;
-    PyObject *newline_obj = NULL;
-    char *newline = "\n";
-    Py_ssize_t value_len;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:__init__", kwlist,
-                                     &value, &newline_obj))
-        return -1;
-
-    /* Parse the newline argument. This used to be done with the 'z'
-       specifier, however this allowed any object with the buffer interface to
-       be converted. Thus we have to parse it manually since we only want to
-       allow unicode objects or None. */
-    if (newline_obj == Py_None) {
-        newline = NULL;
-    }
-    else if (newline_obj) {
-        if (!PyUnicode_Check(newline_obj)) {
-            PyErr_Format(PyExc_TypeError,
-                         "newline must be str or None, not %.200s",
-                         Py_TYPE(newline_obj)->tp_name);
-            return -1;
-        }
-        newline = _PyUnicode_AsString(newline_obj);
-        if (newline == NULL)
-            return -1;
-    }
-
-    if (newline && newline[0] != '\0'
-        && !(newline[0] == '\n' && newline[1] == '\0')
-        && !(newline[0] == '\r' && newline[1] == '\0')
-        && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
-        PyErr_Format(PyExc_ValueError,
-                     "illegal newline value: %R", newline_obj);
-        return -1;
-    }
-    if (value && value != Py_None && !PyUnicode_Check(value)) {
-        PyErr_Format(PyExc_TypeError,
-                     "initial_value must be str or None, not %.200s",
-                     Py_TYPE(value)->tp_name);
-        return -1;
-    }
-
-    self->ok = 0;
-
-    _PyAccu_Destroy(&self->accu);
-    Py_CLEAR(self->readnl);
-    Py_CLEAR(self->writenl);
-    Py_CLEAR(self->decoder);
-
-    assert((newline != NULL && newline_obj != Py_None) ||
-           (newline == NULL && newline_obj == Py_None));
-
-    if (newline) {
-        self->readnl = PyUnicode_FromString(newline);
-        if (self->readnl == NULL)
-            return -1;
-    }
-    self->readuniversal = (newline == NULL || newline[0] == '\0');
-    self->readtranslate = (newline == NULL);
-    /* If newline == "", we don't translate anything.
-       If newline == "\n" or newline == None, we translate to "\n", which is
-       a no-op.
-       (for newline == None, TextIOWrapper translates to os.sepline, but it
-       is pointless for StringIO)
-    */
-    if (newline != NULL && newline[0] == '\r') {
-        self->writenl = self->readnl;
-        Py_INCREF(self->writenl);
-    }
-
-    if (self->readuniversal) {
-        self->decoder = PyObject_CallFunction(
-            (PyObject *)&PyIncrementalNewlineDecoder_Type,
-            "Oi", Py_None, (int) self->readtranslate);
-        if (self->decoder == NULL)
-            return -1;
-    }
-
-    /* Now everything is set up, resize buffer to size of initial value,
-       and copy it */
-    self->string_size = 0;
-    if (value && value != Py_None)
-        value_len = PyUnicode_GetLength(value);
-    else
-        value_len = 0;
-    if (value_len > 0) {
-        /* This is a heuristic, for newline translation might change
-           the string length. */
-        if (resize_buffer(self, 0) < 0)
-            return -1;
-        self->state = STATE_REALIZED;
-        self->pos = 0;
-        if (write_str(self, value) < 0)
-            return -1;
-    }
-    else {
-        /* Empty stringio object, we can start by accumulating */
-        if (resize_buffer(self, 0) < 0)
-            return -1;
-        if (_PyAccu_Init(&self->accu))
-            return -1;
-        self->state = STATE_ACCUMULATING;
-    }
-    self->pos = 0;
-
-    self->closed = 0;
-    self->ok = 1;
-    return 0;
-}
-
-/* Properties and pseudo-properties */
-
-PyDoc_STRVAR(stringio_readable_doc,
-"readable() -> bool. Returns True if the IO object can be read.");
-
-PyDoc_STRVAR(stringio_writable_doc,
-"writable() -> bool. Returns True if the IO object can be written.");
-
-PyDoc_STRVAR(stringio_seekable_doc,
-"seekable() -> bool. Returns True if the IO object can be seeked.");
-
-static PyObject *
-stringio_seekable(stringio *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    Py_RETURN_TRUE;
-}
-
-static PyObject *
-stringio_readable(stringio *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    Py_RETURN_TRUE;
-}
-
-static PyObject *
-stringio_writable(stringio *self, PyObject *args)
-{
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    Py_RETURN_TRUE;
-}
-
-/* Pickling support.
-
-   The implementation of __getstate__ is similar to the one for BytesIO,
-   except that we also save the newline parameter. For __setstate__ and unlike
-   BytesIO, we call __init__ to restore the object's state. Doing so allows us
-   to avoid decoding the complex newline state while keeping the object
-   representation compact.
-
-   See comment in bytesio.c regarding why only pickle protocols and onward are
-   supported.
-*/
-
-static PyObject *
-stringio_getstate(stringio *self)
-{
-    PyObject *initvalue = stringio_getvalue(self);
-    PyObject *dict;
-    PyObject *state;
-
-    if (initvalue == NULL)
-        return NULL;
-    if (self->dict == NULL) {
-        Py_INCREF(Py_None);
-        dict = Py_None;
-    }
-    else {
-        dict = PyDict_Copy(self->dict);
-        if (dict == NULL)
-            return NULL;
-    }
-
-    state = Py_BuildValue("(OOnN)", initvalue,
-                          self->readnl ? self->readnl : Py_None,
-                          self->pos, dict);
-    Py_DECREF(initvalue);
-    return state;
-}
-
-static PyObject *
-stringio_setstate(stringio *self, PyObject *state)
-{
-    PyObject *initarg;
-    PyObject *position_obj;
-    PyObject *dict;
-    Py_ssize_t pos;
-
-    assert(state != NULL);
-    CHECK_CLOSED(self);
-
-    /* We allow the state tuple to be longer than 4, because we may need
-       someday to extend the object's state without breaking
-       backward-compatibility. */
-    if (!PyTuple_Check(state) || Py_SIZE(state) < 4) {
-        PyErr_Format(PyExc_TypeError,
-                     "%.200s.__setstate__ argument should be 4-tuple, got %.200s",
-                     Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name);
-        return NULL;
-    }
-
-    /* Initialize the object's state. */
-    initarg = PyTuple_GetSlice(state, 0, 2);
-    if (initarg == NULL)
-        return NULL;
-    if (stringio_init(self, initarg, NULL) < 0) {
-        Py_DECREF(initarg);
-        return NULL;
-    }
-    Py_DECREF(initarg);
-
-    /* Restore the buffer state. Even if __init__ did initialize the buffer,
-       we have to initialize it again since __init__ may translates the
-       newlines in the inital_value string. We clearly do not want that
-       because the string value in the state tuple has already been translated
-       once by __init__. So we do not take any chance and replace object's
-       buffer completely. */
-    {
-        PyObject *item;
-        Py_UCS4 *buf;
-        Py_ssize_t bufsize;
-
-        item = PyTuple_GET_ITEM(state, 0);
-        buf = PyUnicode_AsUCS4Copy(item);
-        if (buf == NULL)
-            return NULL;
-        bufsize = PyUnicode_GET_LENGTH(item);
-
-        if (resize_buffer(self, bufsize) < 0) {
-            PyMem_Free(buf);
-            return NULL;
-        }
-        memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4));
-        PyMem_Free(buf);
-        self->string_size = bufsize;
-    }
-
-    /* Set carefully the position value. Alternatively, we could use the seek
-       method instead of modifying self->pos directly to better protect the
-       object internal state against errneous (or malicious) inputs. */
-    position_obj = PyTuple_GET_ITEM(state, 2);
-    if (!PyLong_Check(position_obj)) {
-        PyErr_Format(PyExc_TypeError,
-                     "third item of state must be an integer, got %.200s",
-                     Py_TYPE(position_obj)->tp_name);
-        return NULL;
-    }
-    pos = PyLong_AsSsize_t(position_obj);
-    if (pos == -1 && PyErr_Occurred())
-        return NULL;
-    if (pos < 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "position value cannot be negative");
-        return NULL;
-    }
-    self->pos = pos;
-
-    /* Set the dictionary of the instance variables. */
-    dict = PyTuple_GET_ITEM(state, 3);
-    if (dict != Py_None) {
-        if (!PyDict_Check(dict)) {
-            PyErr_Format(PyExc_TypeError,
-                         "fourth item of state should be a dict, got a %.200s",
-                         Py_TYPE(dict)->tp_name);
-            return NULL;
-        }
-        if (self->dict) {
-            /* Alternatively, we could replace the internal dictionary
-               completely. However, it seems more practical to just update it. */
-            if (PyDict_Update(self->dict, dict) < 0)
-                return NULL;
-        }
-        else {
-            Py_INCREF(dict);
-            self->dict = dict;
-        }
-    }
-
-    Py_RETURN_NONE;
-}
-
-
-static PyObject *
-stringio_closed(stringio *self, void *context)
-{
-    CHECK_INITIALIZED(self);
-    return PyBool_FromLong(self->closed);
-}
-
-static PyObject *
-stringio_line_buffering(stringio *self, void *context)
-{
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    Py_RETURN_FALSE;
-}
-
-static PyObject *
-stringio_newlines(stringio *self, void *context)
-{
-    CHECK_INITIALIZED(self);
-    CHECK_CLOSED(self);
-    if (self->decoder == NULL)
-        Py_RETURN_NONE;
-    return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
-}
-
-static struct PyMethodDef stringio_methods[] = {
-    {"close",    (PyCFunction)stringio_close,    METH_NOARGS,  stringio_close_doc},
-    {"getvalue", (PyCFunction)stringio_getvalue, METH_NOARGS,  stringio_getvalue_doc},
-    {"read",     (PyCFunction)stringio_read,     METH_VARARGS, stringio_read_doc},
-    {"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
-    {"tell",     (PyCFunction)stringio_tell,     METH_NOARGS,  stringio_tell_doc},
-    {"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
-    {"seek",     (PyCFunction)stringio_seek,     METH_VARARGS, stringio_seek_doc},
-    {"write",    (PyCFunction)stringio_write,    METH_O,       stringio_write_doc},
-
-    {"seekable", (PyCFunction)stringio_seekable, METH_NOARGS, stringio_seekable_doc},
-    {"readable", (PyCFunction)stringio_readable, METH_NOARGS, stringio_readable_doc},
-    {"writable", (PyCFunction)stringio_writable, METH_NOARGS, stringio_writable_doc},
-
-    {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS},
-    {"__setstate__", (PyCFunction)stringio_setstate, METH_O},
-    {NULL, NULL}        /* sentinel */
-};
-
-static PyGetSetDef stringio_getset[] = {
-    {"closed",         (getter)stringio_closed,         NULL, NULL},
-    {"newlines",       (getter)stringio_newlines,       NULL, NULL},
-    /*  (following comments straight off of the original Python wrapper:)
-        XXX Cruft to support the TextIOWrapper API. This would only
-        be meaningful if StringIO supported the buffer attribute.
-        Hopefully, a better solution, than adding these pseudo-attributes,
-        will be found.
-    */
-    {"line_buffering", (getter)stringio_line_buffering, NULL, NULL},
-    {NULL}
-};
-
-PyTypeObject PyStringIO_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.StringIO",                            /*tp_name*/
-    sizeof(stringio),                    /*tp_basicsize*/
-    0,                                         /*tp_itemsize*/
-    (destructor)stringio_dealloc,              /*tp_dealloc*/
-    0,                                         /*tp_print*/
-    0,                                         /*tp_getattr*/
-    0,                                         /*tp_setattr*/
-    0,                                         /*tp_reserved*/
-    0,                                         /*tp_repr*/
-    0,                                         /*tp_as_number*/
-    0,                                         /*tp_as_sequence*/
-    0,                                         /*tp_as_mapping*/
-    0,                                         /*tp_hash*/
-    0,                                         /*tp_call*/
-    0,                                         /*tp_str*/
-    0,                                         /*tp_getattro*/
-    0,                                         /*tp_setattro*/
-    0,                                         /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-                       | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/
-    stringio_doc,                              /*tp_doc*/
-    (traverseproc)stringio_traverse,           /*tp_traverse*/
-    (inquiry)stringio_clear,                   /*tp_clear*/
-    0,                                         /*tp_richcompare*/
-    offsetof(stringio, weakreflist),            /*tp_weaklistoffset*/
-    0,                                         /*tp_iter*/
-    (iternextfunc)stringio_iternext,           /*tp_iternext*/
-    stringio_methods,                          /*tp_methods*/
-    0,                                         /*tp_members*/
-    stringio_getset,                           /*tp_getset*/
-    0,                                         /*tp_base*/
-    0,                                         /*tp_dict*/
-    0,                                         /*tp_descr_get*/
-    0,                                         /*tp_descr_set*/
-    offsetof(stringio, dict),                  /*tp_dictoffset*/
-    (initproc)stringio_init,                   /*tp_init*/
-    0,                                         /*tp_alloc*/
-    stringio_new,                              /*tp_new*/
-};
+/*[clinic end generated code: output=f3062096d357c652 input=a9049054013a1b77]*/
diff --git a/Modules/_io/textio.c b/Modules/_io/clinic/textio.c.h
copy from Modules/_io/textio.c
copy to Modules/_io/clinic/textio.c.h
--- a/Modules/_io/textio.c
+++ b/Modules/_io/clinic/textio.c.h
@@ -1,2833 +1,464 @@
-/*
-    An implementation of Text I/O as defined by PEP 3116 - "New I/O"
+/*[clinic input]
+preserve
+[clinic start generated code]*/
 
-    Classes defined here: TextIOBase, IncrementalNewlineDecoder, TextIOWrapper.
-
-    Written by Amaury Forgeot d'Arc and Antoine Pitrou
-*/
-
-#define PY_SSIZE_T_CLEAN
-#include "Python.h"
-#include "structmember.h"
-#include "_iomodule.h"
-
-_Py_IDENTIFIER(close);
-_Py_IDENTIFIER(_dealloc_warn);
-_Py_IDENTIFIER(decode);
-_Py_IDENTIFIER(fileno);
-_Py_IDENTIFIER(flush);
-_Py_IDENTIFIER(getpreferredencoding);
-_Py_IDENTIFIER(isatty);
-_Py_IDENTIFIER(mode);
-_Py_IDENTIFIER(name);
-_Py_IDENTIFIER(raw);
-_Py_IDENTIFIER(read);
-_Py_IDENTIFIER(read1);
-_Py_IDENTIFIER(readable);
-_Py_IDENTIFIER(replace);
-_Py_IDENTIFIER(reset);
-_Py_IDENTIFIER(seek);
-_Py_IDENTIFIER(seekable);
-_Py_IDENTIFIER(setstate);
-_Py_IDENTIFIER(tell);
-_Py_IDENTIFIER(writable);
-
-/* TextIOBase */
-
-PyDoc_STRVAR(textiobase_doc,
-    "Base class for text I/O.\n"
-    "\n"
-    "This class provides a character and line based interface to stream\n"
-    "I/O. There is no readinto method because Python's character strings\n"
-    "are immutable. There is no public constructor.\n"
-    );
-
-static PyObject *
-_unsupported(const char *message)
-{
-    _PyIO_State *state = IO_STATE();
-    if (state != NULL)
-        PyErr_SetString(state->unsupported_operation, message);
-    return NULL;
-}
-
-PyDoc_STRVAR(textiobase_detach_doc,
-    "Separate the underlying buffer from the TextIOBase and return it.\n"
-    "\n"
-    "After the underlying buffer has been detached, the TextIO is in an\n"
-    "unusable state.\n"
-    );
-
-static PyObject *
-textiobase_detach(PyObject *self)
-{
-    return _unsupported("detach");
-}
-
-PyDoc_STRVAR(textiobase_read_doc,
-    "Read at most n characters from stream.\n"
-    "\n"
-    "Read from underlying buffer until we have n characters or we hit EOF.\n"
-    "If n is negative or omitted, read until EOF.\n"
-    );
-
-static PyObject *
-textiobase_read(PyObject *self, PyObject *args)
-{
-    return _unsupported("read");
-}
-
-PyDoc_STRVAR(textiobase_readline_doc,
-    "Read until newline or EOF.\n"
-    "\n"
-    "Returns an empty string if EOF is hit immediately.\n"
-    );
-
-static PyObject *
-textiobase_readline(PyObject *self, PyObject *args)
-{
-    return _unsupported("readline");
-}
-
-PyDoc_STRVAR(textiobase_write_doc,
-    "Write string to stream.\n"
-    "Returns the number of characters written (which is always equal to\n"
-    "the length of the string).\n"
-    );
-
-static PyObject *
-textiobase_write(PyObject *self, PyObject *args)
-{
-    return _unsupported("write");
-}
-
-PyDoc_STRVAR(textiobase_encoding_doc,
-    "Encoding of the text stream.\n"
-    "\n"
-    "Subclasses should override.\n"
-    );
-
-static PyObject *
-textiobase_encoding_get(PyObject *self, void *context)
-{
-    Py_RETURN_NONE;
-}
-
-PyDoc_STRVAR(textiobase_newlines_doc,
-    "Line endings translated so far.\n"
-    "\n"
-    "Only line endings translated during reading are considered.\n"
-    "\n"
-    "Subclasses should override.\n"
-    );
-
-static PyObject *
-textiobase_newlines_get(PyObject *self, void *context)
-{
-    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},
-    {"read", textiobase_read, METH_VARARGS, textiobase_read_doc},
-    {"readline", textiobase_readline, METH_VARARGS, textiobase_readline_doc},
-    {"write", textiobase_write, METH_VARARGS, textiobase_write_doc},
-    {NULL, NULL}
-};
-
-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}
-};
-
-PyTypeObject PyTextIOBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io._TextIOBase",          /*tp_name*/
-    0,                          /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    0,                          /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_FINALIZE,  /*tp_flags*/
-    textiobase_doc,             /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    textiobase_methods,         /* tp_methods */
-    0,                          /* tp_members */
-    textiobase_getset,          /* tp_getset */
-    &PyIOBase_Type,             /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    0,                          /* tp_dictoffset */
-    0,                          /* tp_init */
-    0,                          /* tp_alloc */
-    0,                          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
-
-
-/* IncrementalNewlineDecoder */
-
-PyDoc_STRVAR(incrementalnewlinedecoder_doc,
-    "Codec used when reading a file in universal newlines mode.  It wraps\n"
-    "another incremental decoder, translating \\r\\n and \\r into \\n.  It also\n"
-    "records the types of newlines encountered.  When used with\n"
-    "translate=False, it ensures that the newline sequence is returned in\n"
-    "one piece. When used with decoder=None, it expects unicode strings as\n"
-    "decode input and translates newlines without first invoking an external\n"
-    "decoder.\n"
-    );
-
-typedef struct {
-    PyObject_HEAD
-    PyObject *decoder;
-    PyObject *errors;
-    unsigned int pendingcr: 1;
-    unsigned int translate: 1;
-    unsigned int seennl: 3;
-} nldecoder_object;
+PyDoc_STRVAR(_io_IncrementalNewlineDecoder___init____doc__,
+"IncrementalNewlineDecoder(decoder, translate, errors=\'strict\')\n"
+"--\n"
+"\n"
+"Codec used when reading a file in universal newlines mode.\n"
+"\n"
+"It wraps another incremental decoder, translating \\r\\n and \\r into \\n.\n"
+"It also records the types of newlines encountered.  When used with\n"
+"translate=False, it ensures that the newline sequence is returned in\n"
+"one piece. When used with decoder=None, it expects unicode strings as\n"
+"decode input and translates newlines without first invoking an external\n"
+"decoder.");
 
 static int
-incrementalnewlinedecoder_init(nldecoder_object *self,
-                               PyObject *args, PyObject *kwds)
+_io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self,
+                                            PyObject *decoder, int translate,
+                                            PyObject *errors);
+
+static int
+_io_IncrementalNewlineDecoder___init__(PyObject *self, PyObject *args, PyObject *kwargs)
 {
+    int return_value = -1;
+    static char *_keywords[] = {"decoder", "translate", "errors", NULL};
     PyObject *decoder;
     int translate;
     PyObject *errors = NULL;
-    char *kwlist[] = {"decoder", "translate", "errors", NULL};
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi|O:IncrementalNewlineDecoder",
-                                     kwlist, &decoder, &translate, &errors))
-        return -1;
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "Oi|O:IncrementalNewlineDecoder", _keywords,
+        &decoder, &translate, &errors))
+        goto exit;
+    return_value = _io_IncrementalNewlineDecoder___init___impl((nldecoder_object *)self, decoder, translate, errors);
 
-    self->decoder = decoder;
-    Py_INCREF(decoder);
-
-    if (errors == NULL) {
-        self->errors = PyUnicode_FromString("strict");
-        if (self->errors == NULL)
-            return -1;
-    }
-    else {
-        Py_INCREF(errors);
-        self->errors = errors;
-    }
-
-    self->translate = translate;
-    self->seennl = 0;
-    self->pendingcr = 0;
-
-    return 0;
+exit:
+    return return_value;
 }
 
-static void
-incrementalnewlinedecoder_dealloc(nldecoder_object *self)
-{
-    Py_CLEAR(self->decoder);
-    Py_CLEAR(self->errors);
-    Py_TYPE(self)->tp_free((PyObject *)self);
-}
+PyDoc_STRVAR(_io_IncrementalNewlineDecoder_decode__doc__,
+"decode($self, /, input, final=False)\n"
+"--\n"
+"\n");
 
-static int
-check_decoded(PyObject *decoded)
-{
-    if (decoded == NULL)
-        return -1;
-    if (!PyUnicode_Check(decoded)) {
-        PyErr_Format(PyExc_TypeError,
-                     "decoder should return a string result, not '%.200s'",
-                     Py_TYPE(decoded)->tp_name);
-        Py_DECREF(decoded);
-        return -1;
-    }
-    if (PyUnicode_READY(decoded) < 0) {
-        Py_DECREF(decoded);
-        return -1;
-    }
-    return 0;
-}
-
-#define SEEN_CR   1
-#define SEEN_LF   2
-#define SEEN_CRLF 4
-#define SEEN_ALL (SEEN_CR | SEEN_LF | SEEN_CRLF)
-
-PyObject *
-_PyIncrementalNewlineDecoder_decode(PyObject *myself,
-                                    PyObject *input, int final)
-{
-    PyObject *output;
-    Py_ssize_t output_len;
-    nldecoder_object *self = (nldecoder_object *) myself;
-
-    if (self->decoder == NULL) {
-        PyErr_SetString(PyExc_ValueError,
-                        "IncrementalNewlineDecoder.__init__ not called");
-        return NULL;
-    }
-
-    /* decode input (with the eventual \r from a previous pass) */
-    if (self->decoder != Py_None) {
-        output = PyObject_CallMethodObjArgs(self->decoder,
-            _PyIO_str_decode, input, final ? Py_True : Py_False, NULL);
-    }
-    else {
-        output = input;
-        Py_INCREF(output);
-    }
-
-    if (check_decoded(output) < 0)
-        return NULL;
-
-    output_len = PyUnicode_GET_LENGTH(output);
-    if (self->pendingcr && (final || output_len > 0)) {
-        /* Prefix output with CR */
-        int kind;
-        PyObject *modified;
-        char *out;
-
-        modified = PyUnicode_New(output_len + 1,
-                                 PyUnicode_MAX_CHAR_VALUE(output));
-        if (modified == NULL)
-            goto error;
-        kind = PyUnicode_KIND(modified);
-        out = PyUnicode_DATA(modified);
-        PyUnicode_WRITE(kind, PyUnicode_DATA(modified), 0, '\r');
-        memcpy(out + kind, PyUnicode_DATA(output), kind * output_len);
-        Py_DECREF(output);
-        output = modified; /* output remains ready */
-        self->pendingcr = 0;
-        output_len++;
-    }
-
-    /* retain last \r even when not translating data:
-     * then readline() is sure to get \r\n in one pass
-     */
-    if (!final) {
-        if (output_len > 0
-            && PyUnicode_READ_CHAR(output, output_len - 1) == '\r')
-        {
-            PyObject *modified = PyUnicode_Substring(output, 0, output_len -1);
-            if (modified == NULL)
-                goto error;
-            Py_DECREF(output);
-            output = modified;
-            self->pendingcr = 1;
-        }
-    }
-
-    /* Record which newlines are read and do newline translation if desired,
-       all in one pass. */
-    {
-        void *in_str;
-        Py_ssize_t len;
-        int seennl = self->seennl;
-        int only_lf = 0;
-        int kind;
-
-        in_str = PyUnicode_DATA(output);
-        len = PyUnicode_GET_LENGTH(output);
-        kind = PyUnicode_KIND(output);
-
-        if (len == 0)
-            return output;
-
-        /* If, up to now, newlines are consistently \n, do a quick check
-           for the \r *byte* with the libc's optimized memchr.
-           */
-        if (seennl == SEEN_LF || seennl == 0) {
-            only_lf = (memchr(in_str, '\r', kind * len) == NULL);
-        }
-
-        if (only_lf) {
-            /* If not already seen, quick scan for a possible "\n" character.
-               (there's nothing else to be done, even when in translation mode)
-            */
-            if (seennl == 0 &&
-                memchr(in_str, '\n', kind * len) != NULL) {
-                if (kind == PyUnicode_1BYTE_KIND)
-                    seennl |= SEEN_LF;
-                else {
-                    Py_ssize_t i = 0;
-                    for (;;) {
-                        Py_UCS4 c;
-                        /* Fast loop for non-control characters */
-                        while (PyUnicode_READ(kind, in_str, i) > '\n')
-                            i++;
-                        c = PyUnicode_READ(kind, in_str, i++);
-                        if (c == '\n') {
-                            seennl |= SEEN_LF;
-                            break;
-                        }
-                        if (i >= len)
-                            break;
-                    }
-                }
-            }
-            /* Finished: we have scanned for newlines, and none of them
-               need translating */
-        }
-        else if (!self->translate) {
-            Py_ssize_t i = 0;
-            /* We have already seen all newline types, no need to scan again */
-            if (seennl == SEEN_ALL)
-                goto endscan;
-            for (;;) {
-                Py_UCS4 c;
-                /* Fast loop for non-control characters */
-                while (PyUnicode_READ(kind, in_str, i) > '\r')
-                    i++;
-                c = PyUnicode_READ(kind, in_str, i++);
-                if (c == '\n')
-                    seennl |= SEEN_LF;
-                else if (c == '\r') {
-                    if (PyUnicode_READ(kind, in_str, i) == '\n') {
-                        seennl |= SEEN_CRLF;
-                        i++;
-                    }
-                    else
-                        seennl |= SEEN_CR;
-                }
-                if (i >= len)
-                    break;
-                if (seennl == SEEN_ALL)
-                    break;
-            }
-        endscan:
-            ;
-        }
-        else {
-            void *translated;
-            int kind = PyUnicode_KIND(output);
-            void *in_str = PyUnicode_DATA(output);
-            Py_ssize_t in, out;
-            /* XXX: Previous in-place translation here is disabled as
-               resizing is not possible anymore */
-            /* We could try to optimize this so that we only do a copy
-               when there is something to translate. On the other hand,
-               we already know there is a \r byte, so chances are high
-               that something needs to be done. */
-            translated = PyMem_Malloc(kind * len);
-            if (translated == NULL) {
-                PyErr_NoMemory();
-                goto error;
-            }
-            in = out = 0;
-            for (;;) {
-                Py_UCS4 c;
-                /* Fast loop for non-control characters */
-                while ((c = PyUnicode_READ(kind, in_str, in++)) > '\r')
-                    PyUnicode_WRITE(kind, translated, out++, c);
-                if (c == '\n') {
-                    PyUnicode_WRITE(kind, translated, out++, c);
-                    seennl |= SEEN_LF;
-                    continue;
-                }
-                if (c == '\r') {
-                    if (PyUnicode_READ(kind, in_str, in) == '\n') {
-                        in++;
-                        seennl |= SEEN_CRLF;
-                    }
-                    else
-                        seennl |= SEEN_CR;
-                    PyUnicode_WRITE(kind, translated, out++, '\n');
-                    continue;
-                }
-                if (in > len)
-                    break;
-                PyUnicode_WRITE(kind, translated, out++, c);
-            }
-            Py_DECREF(output);
-            output = PyUnicode_FromKindAndData(kind, translated, out);
-            PyMem_Free(translated);
-            if (!output)
-                return NULL;
-        }
-        self->seennl |= seennl;
-    }
-
-    return output;
-
-  error:
-    Py_DECREF(output);
-    return NULL;
-}
+#define _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF    \
+    {"decode", (PyCFunction)_io_IncrementalNewlineDecoder_decode, METH_VARARGS|METH_KEYWORDS, _io_IncrementalNewlineDecoder_decode__doc__},
 
 static PyObject *
-incrementalnewlinedecoder_decode(nldecoder_object *self,
-                                 PyObject *args, PyObject *kwds)
+_io_IncrementalNewlineDecoder_decode_impl(nldecoder_object *self,
+                                          PyObject *input, int final);
+
+static PyObject *
+_io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *args, PyObject *kwargs)
 {
-    char *kwlist[] = {"input", "final", NULL};
+    PyObject *return_value = NULL;
+    static char *_keywords[] = {"input", "final", NULL};
     PyObject *input;
     int final = 0;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:IncrementalNewlineDecoder",
-                                     kwlist, &input, &final))
-        return NULL;
-    return _PyIncrementalNewlineDecoder_decode((PyObject *) self, input, final);
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "O|i:decode", _keywords,
+        &input, &final))
+        goto exit;
+    return_value = _io_IncrementalNewlineDecoder_decode_impl(self, input, final);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_IncrementalNewlineDecoder_getstate__doc__,
+"getstate($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF    \
+    {"getstate", (PyCFunction)_io_IncrementalNewlineDecoder_getstate, METH_NOARGS, _io_IncrementalNewlineDecoder_getstate__doc__},
+
 static PyObject *
-incrementalnewlinedecoder_getstate(nldecoder_object *self, PyObject *args)
+_io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self);
+
+static PyObject *
+_io_IncrementalNewlineDecoder_getstate(nldecoder_object *self, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *buffer;
-    unsigned PY_LONG_LONG flag;
-
-    if (self->decoder != Py_None) {
-        PyObject *state = PyObject_CallMethodObjArgs(self->decoder,
-           _PyIO_str_getstate, NULL);
-        if (state == NULL)
-            return NULL;
-        if (!PyArg_Parse(state, "(OK)", &buffer, &flag)) {
-            Py_DECREF(state);
-            return NULL;
-        }
-        Py_INCREF(buffer);
-        Py_DECREF(state);
-    }
-    else {
-        buffer = PyBytes_FromString("");
-        flag = 0;
-    }
-    flag <<= 1;
-    if (self->pendingcr)
-        flag |= 1;
-    return Py_BuildValue("NK", buffer, flag);
+    return _io_IncrementalNewlineDecoder_getstate_impl(self);
 }
 
+PyDoc_STRVAR(_io_IncrementalNewlineDecoder_setstate__doc__,
+"setstate($self, state, /)\n"
+"--\n"
+"\n");
+
+#define _IO_INCREMENTALNEWLINEDECODER_SETSTATE_METHODDEF    \
+    {"setstate", (PyCFunction)_io_IncrementalNewlineDecoder_setstate, METH_O, _io_IncrementalNewlineDecoder_setstate__doc__},
+
+PyDoc_STRVAR(_io_IncrementalNewlineDecoder_reset__doc__,
+"reset($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_INCREMENTALNEWLINEDECODER_RESET_METHODDEF    \
+    {"reset", (PyCFunction)_io_IncrementalNewlineDecoder_reset, METH_NOARGS, _io_IncrementalNewlineDecoder_reset__doc__},
+
 static PyObject *
-incrementalnewlinedecoder_setstate(nldecoder_object *self, PyObject *state)
+_io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self);
+
+static PyObject *
+_io_IncrementalNewlineDecoder_reset(nldecoder_object *self, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *buffer;
-    unsigned PY_LONG_LONG flag;
-
-    if (!PyArg_Parse(state, "(OK)", &buffer, &flag))
-        return NULL;
-
-    self->pendingcr = (int) (flag & 1);
-    flag >>= 1;
-
-    if (self->decoder != Py_None)
-        return _PyObject_CallMethodId(self->decoder,
-                                      &PyId_setstate, "((OK))", buffer, flag);
-    else
-        Py_RETURN_NONE;
+    return _io_IncrementalNewlineDecoder_reset_impl(self);
 }
 
-static PyObject *
-incrementalnewlinedecoder_reset(nldecoder_object *self, PyObject *args)
+PyDoc_STRVAR(_io_TextIOWrapper___init____doc__,
+"TextIOWrapper(buffer, encoding=None, errors=None, newline=None,\n"
+"              line_buffering=False, write_through=False)\n"
+"--\n"
+"\n"
+"Character and line based layer over a BufferedIOBase object, buffer.\n"
+"\n"
+"encoding gives the name of the encoding that the stream will be\n"
+"decoded or encoded with. It defaults to locale.getpreferredencoding(False).\n"
+"\n"
+"errors determines the strictness of encoding and decoding (see\n"
+"help(codecs.Codec) or the documentation for codecs.register) and\n"
+"defaults to \"strict\".\n"
+"\n"
+"newline controls how line endings are handled. It can be None, \'\',\n"
+"\'\\n\', \'\\r\', and \'\\r\\n\'.  It works as follows:\n"
+"\n"
+"* On input, if newline is None, universal newlines mode is\n"
+"  enabled. Lines in the input can end in \'\\n\', \'\\r\', or \'\\r\\n\', and\n"
+"  these are translated into \'\\n\' before being returned to the\n"
+"  caller. If it is \'\', universal newline mode is enabled, but line\n"
+"  endings are returned to the caller untranslated. If it has any of\n"
+"  the other legal values, input lines are only terminated by the given\n"
+"  string, and the line ending is returned to the caller untranslated.\n"
+"\n"
+"* On output, if newline is None, any \'\\n\' characters written are\n"
+"  translated to the system default line separator, os.linesep. If\n"
+"  newline is \'\' or \'\\n\', no translation takes place. If newline is any\n"
+"  of the other legal values, any \'\\n\' characters written are translated\n"
+"  to the given string.\n"
+"\n"
+"If line_buffering is True, a call to flush is implied when a call to\n"
+"write contains a newline character.");
+
+static int
+_io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
+                                const char *encoding, const char *errors,
+                                const char *newline, int line_buffering,
+                                int write_through);
+
+static int
+_io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs)
 {
-    self->seennl = 0;
-    self->pendingcr = 0;
-    if (self->decoder != Py_None)
-        return PyObject_CallMethodObjArgs(self->decoder, _PyIO_str_reset, NULL);
-    else
-        Py_RETURN_NONE;
+    int return_value = -1;
+    static char *_keywords[] = {"buffer", "encoding", "errors", "newline", "line_buffering", "write_through", NULL};
+    PyObject *buffer;
+    const char *encoding = NULL;
+    const char *errors = NULL;
+    const char *newline = NULL;
+    int line_buffering = 0;
+    int write_through = 0;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+        "O|zzzii:TextIOWrapper", _keywords,
+        &buffer, &encoding, &errors, &newline, &line_buffering, &write_through))
+        goto exit;
+    return_value = _io_TextIOWrapper___init___impl((textio *)self, buffer, encoding, errors, newline, line_buffering, write_through);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_detach__doc__,
+"detach($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_DETACH_METHODDEF    \
+    {"detach", (PyCFunction)_io_TextIOWrapper_detach, METH_NOARGS, _io_TextIOWrapper_detach__doc__},
+
 static PyObject *
-incrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context)
+_io_TextIOWrapper_detach_impl(textio *self);
+
+static PyObject *
+_io_TextIOWrapper_detach(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    switch (self->seennl) {
-    case SEEN_CR:
-        return PyUnicode_FromString("\r");
-    case SEEN_LF:
-        return PyUnicode_FromString("\n");
-    case SEEN_CRLF:
-        return PyUnicode_FromString("\r\n");
-    case SEEN_CR | SEEN_LF:
-        return Py_BuildValue("ss", "\r", "\n");
-    case SEEN_CR | SEEN_CRLF:
-        return Py_BuildValue("ss", "\r", "\r\n");
-    case SEEN_LF | SEEN_CRLF:
-        return Py_BuildValue("ss", "\n", "\r\n");
-    case SEEN_CR | SEEN_LF | SEEN_CRLF:
-        return Py_BuildValue("sss", "\r", "\n", "\r\n");
-    default:
-        Py_RETURN_NONE;
-   }
-
+    return _io_TextIOWrapper_detach_impl(self);
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_write__doc__,
+"write($self, text, /)\n"
+"--\n"
+"\n");
 
-static PyMethodDef incrementalnewlinedecoder_methods[] = {
-    {"decode", (PyCFunction)incrementalnewlinedecoder_decode, METH_VARARGS|METH_KEYWORDS},
-    {"getstate", (PyCFunction)incrementalnewlinedecoder_getstate, METH_NOARGS},
-    {"setstate", (PyCFunction)incrementalnewlinedecoder_setstate, METH_O},
-    {"reset", (PyCFunction)incrementalnewlinedecoder_reset, METH_NOARGS},
-    {NULL}
-};
-
-static PyGetSetDef incrementalnewlinedecoder_getset[] = {
-    {"newlines", (getter)incrementalnewlinedecoder_newlines_get, NULL, NULL},
-    {NULL}
-};
-
-PyTypeObject PyIncrementalNewlineDecoder_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.IncrementalNewlineDecoder", /*tp_name*/
-    sizeof(nldecoder_object), /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)incrementalnewlinedecoder_dealloc, /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
-    incrementalnewlinedecoder_doc,          /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    incrementalnewlinedecoder_methods, /* tp_methods */
-    0,                          /* tp_members */
-    incrementalnewlinedecoder_getset, /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    0,                          /* tp_dictoffset */
-    (initproc)incrementalnewlinedecoder_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-};
-
-
-/* TextIOWrapper */
-
-PyDoc_STRVAR(textiowrapper_doc,
-    "Character and line based layer over a BufferedIOBase object, buffer.\n"
-    "\n"
-    "encoding gives the name of the encoding that the stream will be\n"
-    "decoded or encoded with. It defaults to locale.getpreferredencoding(False).\n"
-    "\n"
-    "errors determines the strictness of encoding and decoding (see\n"
-    "help(codecs.Codec) or the documentation for codecs.register) and\n"
-    "defaults to \"strict\".\n"
-    "\n"
-    "newline controls how line endings are handled. It can be None, '',\n"
-    "'\\n', '\\r', and '\\r\\n'.  It works as follows:\n"
-    "\n"
-    "* On input, if newline is None, universal newlines mode is\n"
-    "  enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n"
-    "  these are translated into '\\n' before being returned to the\n"
-    "  caller. If it is '', universal newline mode is enabled, but line\n"
-    "  endings are returned to the caller untranslated. If it has any of\n"
-    "  the other legal values, input lines are only terminated by the given\n"
-    "  string, and the line ending is returned to the caller untranslated.\n"
-    "\n"
-    "* On output, if newline is None, any '\\n' characters written are\n"
-    "  translated to the system default line separator, os.linesep. If\n"
-    "  newline is '' or '\\n', no translation takes place. If newline is any\n"
-    "  of the other legal values, any '\\n' characters written are translated\n"
-    "  to the given string.\n"
-    "\n"
-    "If line_buffering is True, a call to flush is implied when a call to\n"
-    "write contains a newline character."
-    );
-
-typedef PyObject *
-        (*encodefunc_t)(PyObject *, PyObject *);
-
-typedef struct
-{
-    PyObject_HEAD
-    int ok; /* initialized? */
-    int detached;
-    Py_ssize_t chunk_size;
-    PyObject *buffer;
-    PyObject *encoding;
-    PyObject *encoder;
-    PyObject *decoder;
-    PyObject *readnl;
-    PyObject *errors;
-    const char *writenl; /* utf-8 encoded, NULL stands for \n */
-    char line_buffering;
-    char write_through;
-    char readuniversal;
-    char readtranslate;
-    char writetranslate;
-    char seekable;
-    char has_read1;
-    char telling;
-    char finalizing;
-    /* Specialized encoding func (see below) */
-    encodefunc_t encodefunc;
-    /* Whether or not it's the start of the stream */
-    char encoding_start_of_stream;
-
-    /* Reads and writes are internally buffered in order to speed things up.
-       However, any read will first flush the write buffer if itsn't empty.
-
-       Please also note that text to be written is first encoded before being
-       buffered. This is necessary so that encoding errors are immediately
-       reported to the caller, but it unfortunately means that the
-       IncrementalEncoder (whose encode() method is always written in Python)
-       becomes a bottleneck for small writes.
-    */
-    PyObject *decoded_chars;       /* buffer for text returned from decoder */
-    Py_ssize_t decoded_chars_used; /* offset into _decoded_chars for read() */
-    PyObject *pending_bytes;       /* list of bytes objects waiting to be
-                                      written, or NULL */
-    Py_ssize_t pending_bytes_count;
-
-    /* snapshot is either None, or a tuple (dec_flags, next_input) where
-     * dec_flags is the second (integer) item of the decoder state and
-     * next_input is the chunk of input bytes that comes next after the
-     * snapshot point.  We use this to reconstruct decoder states in tell().
-     */
-    PyObject *snapshot;
-    /* Bytes-to-characters ratio for the current chunk. Serves as input for
-       the heuristic in tell(). */
-    double b2cratio;
-
-    /* Cache raw object if it's a FileIO object */
-    PyObject *raw;
-
-    PyObject *weakreflist;
-    PyObject *dict;
-} textio;
-
-
-/* A couple of specialized cases in order to bypass the slow incremental
-   encoding methods for the most popular encodings. */
+#define _IO_TEXTIOWRAPPER_WRITE_METHODDEF    \
+    {"write", (PyCFunction)_io_TextIOWrapper_write, METH_O, _io_TextIOWrapper_write__doc__},
 
 static PyObject *
-ascii_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_write_impl(textio *self, PyObject *text);
+
+static PyObject *
+_io_TextIOWrapper_write(textio *self, PyObject *arg)
 {
-    return _PyUnicode_AsASCIIString(text, PyBytes_AS_STRING(self->errors));
+    PyObject *return_value = NULL;
+    PyObject *text;
+
+    if (!PyArg_Parse(arg,
+        "U:write",
+        &text))
+        goto exit;
+    return_value = _io_TextIOWrapper_write_impl(self, text);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_read__doc__,
+"read($self, size=-1, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_READ_METHODDEF    \
+    {"read", (PyCFunction)_io_TextIOWrapper_read, METH_VARARGS, _io_TextIOWrapper_read__doc__},
+
 static PyObject *
-utf16be_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n);
+
+static PyObject *
+_io_TextIOWrapper_read(textio *self, PyObject *args)
 {
-    return _PyUnicode_EncodeUTF16(text,
-                                  PyBytes_AS_STRING(self->errors), 1);
+    PyObject *return_value = NULL;
+    Py_ssize_t n = -1;
+
+    if (!PyArg_ParseTuple(args,
+        "|O&:read",
+        _PyIO_ConvertSsize_t, &n))
+        goto exit;
+    return_value = _io_TextIOWrapper_read_impl(self, n);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_readline__doc__,
+"readline($self, size=-1, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_READLINE_METHODDEF    \
+    {"readline", (PyCFunction)_io_TextIOWrapper_readline, METH_VARARGS, _io_TextIOWrapper_readline__doc__},
+
 static PyObject *
-utf16le_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_readline_impl(textio *self, Py_ssize_t size);
+
+static PyObject *
+_io_TextIOWrapper_readline(textio *self, PyObject *args)
 {
-    return _PyUnicode_EncodeUTF16(text,
-                                  PyBytes_AS_STRING(self->errors), -1);
+    PyObject *return_value = NULL;
+    Py_ssize_t size = -1;
+
+    if (!PyArg_ParseTuple(args,
+        "|n:readline",
+        &size))
+        goto exit;
+    return_value = _io_TextIOWrapper_readline_impl(self, size);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_seek__doc__,
+"seek($self, cookie, whence=0, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_SEEK_METHODDEF    \
+    {"seek", (PyCFunction)_io_TextIOWrapper_seek, METH_VARARGS, _io_TextIOWrapper_seek__doc__},
+
 static PyObject *
-utf16_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence);
+
+static PyObject *
+_io_TextIOWrapper_seek(textio *self, PyObject *args)
 {
-    if (!self->encoding_start_of_stream) {
-        /* Skip the BOM and use native byte ordering */
-#if PY_BIG_ENDIAN
-        return utf16be_encode(self, text);
-#else
-        return utf16le_encode(self, text);
-#endif
-    }
-    return _PyUnicode_EncodeUTF16(text,
-                                  PyBytes_AS_STRING(self->errors), 0);
+    PyObject *return_value = NULL;
+    PyObject *cookieObj;
+    int whence = 0;
+
+    if (!PyArg_ParseTuple(args,
+        "O|i:seek",
+        &cookieObj, &whence))
+        goto exit;
+    return_value = _io_TextIOWrapper_seek_impl(self, cookieObj, whence);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_tell__doc__,
+"tell($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_TELL_METHODDEF    \
+    {"tell", (PyCFunction)_io_TextIOWrapper_tell, METH_NOARGS, _io_TextIOWrapper_tell__doc__},
+
 static PyObject *
-utf32be_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_tell_impl(textio *self);
+
+static PyObject *
+_io_TextIOWrapper_tell(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    return _PyUnicode_EncodeUTF32(text,
-                                  PyBytes_AS_STRING(self->errors), 1);
+    return _io_TextIOWrapper_tell_impl(self);
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_truncate__doc__,
+"truncate($self, pos=None, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF    \
+    {"truncate", (PyCFunction)_io_TextIOWrapper_truncate, METH_VARARGS, _io_TextIOWrapper_truncate__doc__},
+
 static PyObject *
-utf32le_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_truncate_impl(textio *self, PyObject *pos);
+
+static PyObject *
+_io_TextIOWrapper_truncate(textio *self, PyObject *args)
 {
-    return _PyUnicode_EncodeUTF32(text,
-                                  PyBytes_AS_STRING(self->errors), -1);
+    PyObject *return_value = NULL;
+    PyObject *pos = Py_None;
+
+    if (!PyArg_UnpackTuple(args, "truncate",
+        0, 1,
+        &pos))
+        goto exit;
+    return_value = _io_TextIOWrapper_truncate_impl(self, pos);
+
+exit:
+    return return_value;
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_fileno__doc__,
+"fileno($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_FILENO_METHODDEF    \
+    {"fileno", (PyCFunction)_io_TextIOWrapper_fileno, METH_NOARGS, _io_TextIOWrapper_fileno__doc__},
+
 static PyObject *
-utf32_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_fileno_impl(textio *self);
+
+static PyObject *
+_io_TextIOWrapper_fileno(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    if (!self->encoding_start_of_stream) {
-        /* Skip the BOM and use native byte ordering */
-#if PY_BIG_ENDIAN
-        return utf32be_encode(self, text);
-#else
-        return utf32le_encode(self, text);
-#endif
-    }
-    return _PyUnicode_EncodeUTF32(text,
-                                  PyBytes_AS_STRING(self->errors), 0);
+    return _io_TextIOWrapper_fileno_impl(self);
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_seekable__doc__,
+"seekable($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_SEEKABLE_METHODDEF    \
+    {"seekable", (PyCFunction)_io_TextIOWrapper_seekable, METH_NOARGS, _io_TextIOWrapper_seekable__doc__},
+
 static PyObject *
-utf8_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_seekable_impl(textio *self);
+
+static PyObject *
+_io_TextIOWrapper_seekable(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    return _PyUnicode_AsUTF8String(text, PyBytes_AS_STRING(self->errors));
+    return _io_TextIOWrapper_seekable_impl(self);
 }
 
+PyDoc_STRVAR(_io_TextIOWrapper_readable__doc__,
+"readable($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_READABLE_METHODDEF    \
+    {"readable", (PyCFunction)_io_TextIOWrapper_readable, METH_NOARGS, _io_TextIOWrapper_readable__doc__},
+
 static PyObject *
-latin1_encode(textio *self, PyObject *text)
+_io_TextIOWrapper_readable_impl(textio *self);
+
+static PyObject *
+_io_TextIOWrapper_readable(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    return _PyUnicode_AsLatin1String(text, PyBytes_AS_STRING(self->errors));
+    return _io_TextIOWrapper_readable_impl(self);
 }
 
-/* Map normalized encoding names onto the specialized encoding funcs */
+PyDoc_STRVAR(_io_TextIOWrapper_writable__doc__,
+"writable($self, /)\n"
+"--\n"
+"\n");
 
-typedef struct {
-    const char *name;
-    encodefunc_t encodefunc;
-} encodefuncentry;
+#define _IO_TEXTIOWRAPPER_WRITABLE_METHODDEF    \
+    {"writable", (PyCFunction)_io_TextIOWrapper_writable, METH_NOARGS, _io_TextIOWrapper_writable__doc__},
 
-static encodefuncentry encodefuncs[] = {
-    {"ascii",       (encodefunc_t) ascii_encode},
-    {"iso8859-1",   (encodefunc_t) latin1_encode},
-    {"utf-8",       (encodefunc_t) utf8_encode},
-    {"utf-16-be",   (encodefunc_t) utf16be_encode},
-    {"utf-16-le",   (encodefunc_t) utf16le_encode},
-    {"utf-16",      (encodefunc_t) utf16_encode},
-    {"utf-32-be",   (encodefunc_t) utf32be_encode},
-    {"utf-32-le",   (encodefunc_t) utf32le_encode},
-    {"utf-32",      (encodefunc_t) utf32_encode},
-    {NULL, NULL}
-};
+static PyObject *
+_io_TextIOWrapper_writable_impl(textio *self);
 
-
-static int
-textiowrapper_init(textio *self, PyObject *args, PyObject *kwds)
+static PyObject *
+_io_TextIOWrapper_writable(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    char *kwlist[] = {"buffer", "encoding", "errors",
-                      "newline", "line_buffering", "write_through",
-                      NULL};
-    PyObject *buffer, *raw, *codec_info = NULL;
-    char *encoding = NULL;
-    char *errors = NULL;
-    char *newline = NULL;
-    int line_buffering = 0, write_through = 0;
-    _PyIO_State *state = NULL;
-
-    PyObject *res;
-    int r;
-
-    self->ok = 0;
-    self->detached = 0;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|zzzii:fileio",
-                                     kwlist, &buffer, &encoding, &errors,
-                                     &newline, &line_buffering, &write_through))
-        return -1;
-
-    if (newline && newline[0] != '\0'
-        && !(newline[0] == '\n' && newline[1] == '\0')
-        && !(newline[0] == '\r' && newline[1] == '\0')
-        && !(newline[0] == '\r' && newline[1] == '\n' && newline[2] == '\0')) {
-        PyErr_Format(PyExc_ValueError,
-                     "illegal newline value: %s", newline);
-        return -1;
-    }
-
-    Py_CLEAR(self->buffer);
-    Py_CLEAR(self->encoding);
-    Py_CLEAR(self->encoder);
-    Py_CLEAR(self->decoder);
-    Py_CLEAR(self->readnl);
-    Py_CLEAR(self->decoded_chars);
-    Py_CLEAR(self->pending_bytes);
-    Py_CLEAR(self->snapshot);
-    Py_CLEAR(self->errors);
-    Py_CLEAR(self->raw);
-    self->decoded_chars_used = 0;
-    self->pending_bytes_count = 0;
-    self->encodefunc = NULL;
-    self->b2cratio = 0.0;
-
-    if (encoding == NULL) {
-        /* Try os.device_encoding(fileno) */
-        PyObject *fileno;
-        state = IO_STATE();
-        if (state == NULL)
-            goto error;
-        fileno = _PyObject_CallMethodId(buffer, &PyId_fileno, NULL);
-        /* Ignore only AttributeError and UnsupportedOperation */
-        if (fileno == NULL) {
-            if (PyErr_ExceptionMatches(PyExc_AttributeError) ||
-                PyErr_ExceptionMatches(state->unsupported_operation)) {
-                PyErr_Clear();
-            }
-            else {
-                goto error;
-            }
-        }
-        else {
-            int fd = _PyLong_AsInt(fileno);
-            Py_DECREF(fileno);
-            if (fd == -1 && PyErr_Occurred()) {
-                goto error;
-            }
-
-            self->encoding = _Py_device_encoding(fd);
-            if (self->encoding == NULL)
-                goto error;
-            else if (!PyUnicode_Check(self->encoding))
-                Py_CLEAR(self->encoding);
-        }
-    }
-    if (encoding == NULL && self->encoding == NULL) {
-        PyObject *locale_module = _PyIO_get_locale_module(state);
-        if (locale_module == NULL)
-            goto catch_ImportError;
-        self->encoding = _PyObject_CallMethodId(
-            locale_module, &PyId_getpreferredencoding, "O", Py_False);
-        Py_DECREF(locale_module);
-        if (self->encoding == NULL) {
-          catch_ImportError:
-            /*
-             Importing locale can raise a ImportError because of
-             _functools, and locale.getpreferredencoding can raise a
-             ImportError if _locale is not available.  These will happen
-             during module building.
-            */
-            if (PyErr_ExceptionMatches(PyExc_ImportError)) {
-                PyErr_Clear();
-                self->encoding = PyUnicode_FromString("ascii");
-            }
-            else
-                goto error;
-        }
-        else if (!PyUnicode_Check(self->encoding))
-            Py_CLEAR(self->encoding);
-    }
-    if (self->encoding != NULL) {
-        encoding = _PyUnicode_AsString(self->encoding);
-        if (encoding == NULL)
-            goto error;
-    }
-    else if (encoding != NULL) {
-        self->encoding = PyUnicode_FromString(encoding);
-        if (self->encoding == NULL)
-            goto error;
-    }
-    else {
-        PyErr_SetString(PyExc_IOError,
-                        "could not determine default encoding");
-    }
-
-    /* Check we have been asked for a real text encoding */
-    codec_info = _PyCodec_LookupTextEncoding(encoding, "codecs.open()");
-    if (codec_info == NULL) {
-        Py_CLEAR(self->encoding);
-        goto error;
-    }
-
-    /* XXX: Failures beyond this point have the potential to leak elements
-     * of the partially constructed object (like self->encoding)
-     */
-
-    if (errors == NULL)
-        errors = "strict";
-    self->errors = PyBytes_FromString(errors);
-    if (self->errors == NULL)
-        goto error;
-
-    self->chunk_size = 8192;
-    self->readuniversal = (newline == NULL || newline[0] == '\0');
-    self->line_buffering = line_buffering;
-    self->write_through = write_through;
-    self->readtranslate = (newline == NULL);
-    if (newline) {
-        self->readnl = PyUnicode_FromString(newline);
-        if (self->readnl == NULL)
-            goto error;
-    }
-    self->writetranslate = (newline == NULL || newline[0] != '\0');
-    if (!self->readuniversal && self->readnl) {
-        self->writenl = _PyUnicode_AsString(self->readnl);
-        if (self->writenl == NULL)
-            goto error;
-        if (!strcmp(self->writenl, "\n"))
-            self->writenl = NULL;
-    }
-#ifdef MS_WINDOWS
-    else
-        self->writenl = "\r\n";
-#endif
-
-    /* Build the decoder object */
-    res = _PyObject_CallMethodId(buffer, &PyId_readable, NULL);
-    if (res == NULL)
-        goto error;
-    r = PyObject_IsTrue(res);
-    Py_DECREF(res);
-    if (r == -1)
-        goto error;
-    if (r == 1) {
-        self->decoder = _PyCodecInfo_GetIncrementalDecoder(codec_info,
-                                                           errors);
-        if (self->decoder == NULL)
-            goto error;
-
-        if (self->readuniversal) {
-            PyObject *incrementalDecoder = PyObject_CallFunction(
-                (PyObject *)&PyIncrementalNewlineDecoder_Type,
-                "Oi", self->decoder, (int)self->readtranslate);
-            if (incrementalDecoder == NULL)
-                goto error;
-            Py_CLEAR(self->decoder);
-            self->decoder = incrementalDecoder;
-        }
-    }
-
-    /* Build the encoder object */
-    res = _PyObject_CallMethodId(buffer, &PyId_writable, NULL);
-    if (res == NULL)
-        goto error;
-    r = PyObject_IsTrue(res);
-    Py_DECREF(res);
-    if (r == -1)
-        goto error;
-    if (r == 1) {
-        self->encoder = _PyCodecInfo_GetIncrementalEncoder(codec_info,
-                                                           errors);
-        if (self->encoder == NULL)
-            goto error;
-        /* Get the normalized named of the codec */
-        res = _PyObject_GetAttrId(codec_info, &PyId_name);
-        if (res == NULL) {
-            if (PyErr_ExceptionMatches(PyExc_AttributeError))
-                PyErr_Clear();
-            else
-                goto error;
-        }
-        else if (PyUnicode_Check(res)) {
-            encodefuncentry *e = encodefuncs;
-            while (e->name != NULL) {
-                if (!PyUnicode_CompareWithASCIIString(res, e->name)) {
-                    self->encodefunc = e->encodefunc;
-                    break;
-                }
-                e++;
-            }
-        }
-        Py_XDECREF(res);
-    }
-
-    /* Finished sorting out the codec details */
-    Py_CLEAR(codec_info);
-
-    self->buffer = buffer;
-    Py_INCREF(buffer);
-
-    if (Py_TYPE(buffer) == &PyBufferedReader_Type ||
-        Py_TYPE(buffer) == &PyBufferedWriter_Type ||
-        Py_TYPE(buffer) == &PyBufferedRandom_Type) {
-        raw = _PyObject_GetAttrId(buffer, &PyId_raw);
-        /* Cache the raw FileIO object to speed up 'closed' checks */
-        if (raw == NULL) {
-            if (PyErr_ExceptionMatches(PyExc_AttributeError))
-                PyErr_Clear();
-            else
-                goto error;
-        }
-        else if (Py_TYPE(raw) == &PyFileIO_Type)
-            self->raw = raw;
-        else
-            Py_DECREF(raw);
-    }
-
-    res = _PyObject_CallMethodId(buffer, &PyId_seekable, NULL);
-    if (res == NULL)
-        goto error;
-    r = PyObject_IsTrue(res);
-    Py_DECREF(res);
-    if (r < 0)
-        goto error;
-    self->seekable = self->telling = r;
-
-    self->has_read1 = _PyObject_HasAttrId(buffer, &PyId_read1);
-
-    self->encoding_start_of_stream = 0;
-    if (self->seekable && self->encoder) {
-        PyObject *cookieObj;
-        int cmp;
-
-        self->encoding_start_of_stream = 1;
-
-        cookieObj = PyObject_CallMethodObjArgs(buffer, _PyIO_str_tell, NULL);
-        if (cookieObj == NULL)
-            goto error;
-
-        cmp = PyObject_RichCompareBool(cookieObj, _PyIO_zero, Py_EQ);
-        Py_DECREF(cookieObj);
-        if (cmp < 0) {
-            goto error;
-        }
-
-        if (cmp == 0) {
-            self->encoding_start_of_stream = 0;
-            res = PyObject_CallMethodObjArgs(self->encoder, _PyIO_str_setstate,
-                                             _PyIO_zero, NULL);
-            if (res == NULL)
-                goto error;
-            Py_DECREF(res);
-        }
-    }
-
-    self->ok = 1;
-    return 0;
-
-  error:
-    Py_XDECREF(codec_info);
-    return -1;
+    return _io_TextIOWrapper_writable_impl(self);
 }
 
-static int
-_textiowrapper_clear(textio *self)
+PyDoc_STRVAR(_io_TextIOWrapper_isatty__doc__,
+"isatty($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_ISATTY_METHODDEF    \
+    {"isatty", (PyCFunction)_io_TextIOWrapper_isatty, METH_NOARGS, _io_TextIOWrapper_isatty__doc__},
+
+static PyObject *
+_io_TextIOWrapper_isatty_impl(textio *self);
+
+static PyObject *
+_io_TextIOWrapper_isatty(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    self->ok = 0;
-    Py_CLEAR(self->buffer);
-    Py_CLEAR(self->encoding);
-    Py_CLEAR(self->encoder);
-    Py_CLEAR(self->decoder);
-    Py_CLEAR(self->readnl);
-    Py_CLEAR(self->decoded_chars);
-    Py_CLEAR(self->pending_bytes);
-    Py_CLEAR(self->snapshot);
-    Py_CLEAR(self->errors);
-    Py_CLEAR(self->raw);
-    return 0;
+    return _io_TextIOWrapper_isatty_impl(self);
 }
 
-static void
-textiowrapper_dealloc(textio *self)
+PyDoc_STRVAR(_io_TextIOWrapper_flush__doc__,
+"flush($self, /)\n"
+"--\n"
+"\n");
+
+#define _IO_TEXTIOWRAPPER_FLUSH_METHODDEF    \
+    {"flush", (PyCFunction)_io_TextIOWrapper_flush, METH_NOARGS, _io_TextIOWrapper_flush__doc__},
+
+static PyObject *
+_io_TextIOWrapper_flush_impl(textio *self);
+
+static PyObject *
+_io_TextIOWrapper_flush(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    self->finalizing = 1;
-    if (_PyIOBase_finalize((PyObject *) self) < 0)
-        return;
-    _textiowrapper_clear(self);
-    _PyObject_GC_UNTRACK(self);
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *)self);
-    Py_CLEAR(self->dict);
-    Py_TYPE(self)->tp_free((PyObject *)self);
+    return _io_TextIOWrapper_flush_impl(self);
 }
 
-static int
-textiowrapper_traverse(textio *self, visitproc visit, void *arg)
-{
-    Py_VISIT(self->buffer);
-    Py_VISIT(self->encoding);
-    Py_VISIT(self->encoder);
-    Py_VISIT(self->decoder);
-    Py_VISIT(self->readnl);
-    Py_VISIT(self->decoded_chars);
-    Py_VISIT(self->pending_bytes);
-    Py_VISIT(self->snapshot);
-    Py_VISIT(self->errors);
-    Py_VISIT(self->raw);
+PyDoc_STRVAR(_io_TextIOWrapper_close__doc__,
+"close($self, /)\n"
+"--\n"
+"\n");
 
-    Py_VISIT(self->dict);
-    return 0;
-}
-
-static int
-textiowrapper_clear(textio *self)
-{
-    if (_textiowrapper_clear(self) < 0)
-        return -1;
-    Py_CLEAR(self->dict);
-    return 0;
-}
+#define _IO_TEXTIOWRAPPER_CLOSE_METHODDEF    \
+    {"close", (PyCFunction)_io_TextIOWrapper_close, METH_NOARGS, _io_TextIOWrapper_close__doc__},
 
 static PyObject *
-textiowrapper_closed_get(textio *self, void *context);
-
-/* This macro takes some shortcuts to make the common case faster. */
-#define CHECK_CLOSED(self) \
-    do { \
-        int r; \
-        PyObject *_res; \
-        if (Py_TYPE(self) == &PyTextIOWrapper_Type) { \
-            if (self->raw != NULL) \
-                r = _PyFileIO_closed(self->raw); \
-            else { \
-                _res = textiowrapper_closed_get(self, NULL); \
-                if (_res == NULL) \
-                    return NULL; \
-                r = PyObject_IsTrue(_res); \
-                Py_DECREF(_res); \
-                if (r < 0) \
-                    return NULL; \
-            } \
-            if (r > 0) { \
-                PyErr_SetString(PyExc_ValueError, \
-                                "I/O operation on closed file."); \
-                return NULL; \
-            } \
-        } \
-        else if (_PyIOBase_check_closed((PyObject *)self, Py_True) == NULL) \
-            return NULL; \
-    } while (0)
-
-#define CHECK_INITIALIZED(self) \
-    if (self->ok <= 0) { \
-        PyErr_SetString(PyExc_ValueError, \
-            "I/O operation on uninitialized object"); \
-        return NULL; \
-    }
-
-#define CHECK_ATTACHED(self) \
-    CHECK_INITIALIZED(self); \
-    if (self->detached) { \
-        PyErr_SetString(PyExc_ValueError, \
-             "underlying buffer has been detached"); \
-        return NULL; \
-    }
-
-#define CHECK_ATTACHED_INT(self) \
-    if (self->ok <= 0) { \
-        PyErr_SetString(PyExc_ValueError, \
-            "I/O operation on uninitialized object"); \
-        return -1; \
-    } else if (self->detached) { \
-        PyErr_SetString(PyExc_ValueError, \
-             "underlying buffer has been detached"); \
-        return -1; \
-    }
-
+_io_TextIOWrapper_close_impl(textio *self);
 
 static PyObject *
-textiowrapper_detach(textio *self)
+_io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored))
 {
-    PyObject *buffer, *res;
-    CHECK_ATTACHED(self);
-    res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-    buffer = self->buffer;
-    self->buffer = NULL;
-    self->detached = 1;
-    return buffer;
+    return _io_TextIOWrapper_close_impl(self);
 }
-
-/* Flush the internal write buffer. This doesn't explicitly flush the
-   underlying buffered object, though. */
-static int
-_textiowrapper_writeflush(textio *self)
-{
-    PyObject *pending, *b, *ret;
-
-    if (self->pending_bytes == NULL)
-        return 0;
-
-    pending = self->pending_bytes;
-    Py_INCREF(pending);
-    self->pending_bytes_count = 0;
-    Py_CLEAR(self->pending_bytes);
-
-    b = _PyBytes_Join(_PyIO_empty_bytes, pending);
-    Py_DECREF(pending);
-    if (b == NULL)
-        return -1;
-    ret = NULL;
-    do {
-        ret = PyObject_CallMethodObjArgs(self->buffer,
-                                         _PyIO_str_write, b, NULL);
-    } while (ret == NULL && _PyIO_trap_eintr());
-    Py_DECREF(b);
-    if (ret == NULL)
-        return -1;
-    Py_DECREF(ret);
-    return 0;
-}
-
-static PyObject *
-textiowrapper_write(textio *self, PyObject *args)
-{
-    PyObject *ret;
-    PyObject *text; /* owned reference */
-    PyObject *b;
-    Py_ssize_t textlen;
-    int haslf = 0;
-    int needflush = 0, text_needflush = 0;
-
-    CHECK_ATTACHED(self);
-
-    if (!PyArg_ParseTuple(args, "U:write", &text)) {
-        return NULL;
-    }
-
-    if (PyUnicode_READY(text) == -1)
-        return NULL;
-
-    CHECK_CLOSED(self);
-
-    if (self->encoder == NULL)
-        return _unsupported("not writable");
-
-    Py_INCREF(text);
-
-    textlen = PyUnicode_GET_LENGTH(text);
-
-    if ((self->writetranslate && self->writenl != NULL) || self->line_buffering)
-        if (PyUnicode_FindChar(text, '\n', 0, PyUnicode_GET_LENGTH(text), 1) != -1)
-            haslf = 1;
-
-    if (haslf && self->writetranslate && self->writenl != NULL) {
-        PyObject *newtext = _PyObject_CallMethodId(
-            text, &PyId_replace, "ss", "\n", self->writenl);
-        Py_DECREF(text);
-        if (newtext == NULL)
-            return NULL;
-        text = newtext;
-    }
-
-    if (self->write_through)
-        text_needflush = 1;
-    if (self->line_buffering &&
-        (haslf ||
-         PyUnicode_FindChar(text, '\r', 0, PyUnicode_GET_LENGTH(text), 1) != -1))
-        needflush = 1;
-
-    /* XXX What if we were just reading? */
-    if (self->encodefunc != NULL) {
-        b = (*self->encodefunc)((PyObject *) self, text);
-        self->encoding_start_of_stream = 0;
-    }
-    else
-        b = PyObject_CallMethodObjArgs(self->encoder,
-                                       _PyIO_str_encode, text, NULL);
-    Py_DECREF(text);
-    if (b == NULL)
-        return NULL;
-
-    if (self->pending_bytes == NULL) {
-        self->pending_bytes = PyList_New(0);
-        if (self->pending_bytes == NULL) {
-            Py_DECREF(b);
-            return NULL;
-        }
-        self->pending_bytes_count = 0;
-    }
-    if (PyList_Append(self->pending_bytes, b) < 0) {
-        Py_DECREF(b);
-        return NULL;
-    }
-    self->pending_bytes_count += PyBytes_GET_SIZE(b);
-    Py_DECREF(b);
-    if (self->pending_bytes_count > self->chunk_size || needflush ||
-        text_needflush) {
-        if (_textiowrapper_writeflush(self) < 0)
-            return NULL;
-    }
-
-    if (needflush) {
-        ret = PyObject_CallMethodObjArgs(self->buffer, _PyIO_str_flush, NULL);
-        if (ret == NULL)
-            return NULL;
-        Py_DECREF(ret);
-    }
-
-    Py_CLEAR(self->snapshot);
-
-    if (self->decoder) {
-        ret = _PyObject_CallMethodId(self->decoder, &PyId_reset, NULL);
-        if (ret == NULL)
-            return NULL;
-        Py_DECREF(ret);
-    }
-
-    return PyLong_FromSsize_t(textlen);
-}
-
-/* Steal a reference to chars and store it in the decoded_char buffer;
- */
-static void
-textiowrapper_set_decoded_chars(textio *self, PyObject *chars)
-{
-    Py_CLEAR(self->decoded_chars);
-    self->decoded_chars = chars;
-    self->decoded_chars_used = 0;
-}
-
-static PyObject *
-textiowrapper_get_decoded_chars(textio *self, Py_ssize_t n)
-{
-    PyObject *chars;
-    Py_ssize_t avail;
-
-    if (self->decoded_chars == NULL)
-        return PyUnicode_FromStringAndSize(NULL, 0);
-
-    /* decoded_chars is guaranteed to be "ready". */
-    avail = (PyUnicode_GET_LENGTH(self->decoded_chars)
-             - self->decoded_chars_used);
-
-    assert(avail >= 0);
-
-    if (n < 0 || n > avail)
-        n = avail;
-
-    if (self->decoded_chars_used > 0 || n < avail) {
-        chars = PyUnicode_Substring(self->decoded_chars,
-                                    self->decoded_chars_used,
-                                    self->decoded_chars_used + n);
-        if (chars == NULL)
-            return NULL;
-    }
-    else {
-        chars = self->decoded_chars;
-        Py_INCREF(chars);
-    }
-
-    self->decoded_chars_used += n;
-    return chars;
-}
-
-/* Read and decode the next chunk of data from the BufferedReader.
- */
-static int
-textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint)
-{
-    PyObject *dec_buffer = NULL;
-    PyObject *dec_flags = NULL;
-    PyObject *input_chunk = NULL;
-    Py_buffer input_chunk_buf;
-    PyObject *decoded_chars, *chunk_size;
-    Py_ssize_t nbytes, nchars;
-    int eof;
-
-    /* The return value is True unless EOF was reached.  The decoded string is
-     * placed in self._decoded_chars (replacing its previous value).  The
-     * entire input chunk is sent to the decoder, though some of it may remain
-     * buffered in the decoder, yet to be converted.
-     */
-
-    if (self->decoder == NULL) {
-        _unsupported("not readable");
-        return -1;
-    }
-
-    if (self->telling) {
-        /* To prepare for tell(), we need to snapshot a point in the file
-         * where the decoder's input buffer is empty.
-         */
-
-        PyObject *state = PyObject_CallMethodObjArgs(self->decoder,
-                                                     _PyIO_str_getstate, NULL);
-        if (state == NULL)
-            return -1;
-        /* Given this, we know there was a valid snapshot point
-         * len(dec_buffer) bytes ago with decoder state (b'', dec_flags).
-         */
-        if (PyArg_Parse(state, "(OO)", &dec_buffer, &dec_flags) < 0) {
-            Py_DECREF(state);
-            return -1;
-        }
-
-        if (!PyBytes_Check(dec_buffer)) {
-            PyErr_Format(PyExc_TypeError,
-                         "decoder getstate() should have returned a bytes "
-                         "object, not '%.200s'",
-                         Py_TYPE(dec_buffer)->tp_name);
-            Py_DECREF(state);
-            return -1;
-        }
-        Py_INCREF(dec_buffer);
-        Py_INCREF(dec_flags);
-        Py_DECREF(state);
-    }
-
-    /* Read a chunk, decode it, and put the result in self._decoded_chars. */
-    if (size_hint > 0) {
-        size_hint = (Py_ssize_t)(Py_MAX(self->b2cratio, 1.0) * size_hint);
-    }
-    chunk_size = PyLong_FromSsize_t(Py_MAX(self->chunk_size, size_hint));
-    if (chunk_size == NULL)
-        goto fail;
-
-    input_chunk = PyObject_CallMethodObjArgs(self->buffer,
-        (self->has_read1 ? _PyIO_str_read1: _PyIO_str_read),
-        chunk_size, NULL);
-    Py_DECREF(chunk_size);
-    if (input_chunk == NULL)
-        goto fail;
-
-    if (PyObject_GetBuffer(input_chunk, &input_chunk_buf, 0) != 0) {
-        PyErr_Format(PyExc_TypeError,
-                     "underlying %s() should have returned a bytes-like object, "
-                     "not '%.200s'", (self->has_read1 ? "read1": "read"),
-                     Py_TYPE(input_chunk)->tp_name);
-        goto fail;
-    }
-
-    nbytes = input_chunk_buf.len;
-    eof = (nbytes == 0);
-    if (Py_TYPE(self->decoder) == &PyIncrementalNewlineDecoder_Type) {
-        decoded_chars = _PyIncrementalNewlineDecoder_decode(
-            self->decoder, input_chunk, eof);
-    }
-    else {
-        decoded_chars = PyObject_CallMethodObjArgs(self->decoder,
-            _PyIO_str_decode, input_chunk, eof ? Py_True : Py_False, NULL);
-    }
-    PyBuffer_Release(&input_chunk_buf);
-
-    if (check_decoded(decoded_chars) < 0)
-        goto fail;
-    textiowrapper_set_decoded_chars(self, decoded_chars);
-    nchars = PyUnicode_GET_LENGTH(decoded_chars);
-    if (nchars > 0)
-        self->b2cratio = (double) nbytes / nchars;
-    else
-        self->b2cratio = 0.0;
-    if (nchars > 0)
-        eof = 0;
-
-    if (self->telling) {
-        /* At the snapshot point, len(dec_buffer) bytes before the read, the
-         * next input to be decoded is dec_buffer + input_chunk.
-         */
-        PyObject *next_input = dec_buffer;
-        PyBytes_Concat(&next_input, input_chunk);
-        if (next_input == NULL) {
-            dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
-            goto fail;
-        }
-        Py_CLEAR(self->snapshot);
-        self->snapshot = Py_BuildValue("NN", dec_flags, next_input);
-    }
-    Py_DECREF(input_chunk);
-
-    return (eof == 0);
-
-  fail:
-    Py_XDECREF(dec_buffer);
-    Py_XDECREF(dec_flags);
-    Py_XDECREF(input_chunk);
-    return -1;
-}
-
-static PyObject *
-textiowrapper_read(textio *self, PyObject *args)
-{
-    Py_ssize_t n = -1;
-    PyObject *result = NULL, *chunks = NULL;
-
-    CHECK_ATTACHED(self);
-
-    if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n))
-        return NULL;
-
-    CHECK_CLOSED(self);
-
-    if (self->decoder == NULL)
-        return _unsupported("not readable");
-
-    if (_textiowrapper_writeflush(self) < 0)
-        return NULL;
-
-    if (n < 0) {
-        /* Read everything */
-        PyObject *bytes = _PyObject_CallMethodId(self->buffer, &PyId_read, NULL);
-        PyObject *decoded;
-        if (bytes == NULL)
-            goto fail;
-
-        if (Py_TYPE(self->decoder) == &PyIncrementalNewlineDecoder_Type)
-            decoded = _PyIncrementalNewlineDecoder_decode(self->decoder,
-                                                          bytes, 1);
-        else
-            decoded = PyObject_CallMethodObjArgs(
-                self->decoder, _PyIO_str_decode, bytes, Py_True, NULL);
-        Py_DECREF(bytes);
-        if (check_decoded(decoded) < 0)
-            goto fail;
-
-        result = textiowrapper_get_decoded_chars(self, -1);
-
-        if (result == NULL) {
-            Py_DECREF(decoded);
-            return NULL;
-        }
-
-        PyUnicode_AppendAndDel(&result, decoded);
-        if (result == NULL)
-            goto fail;
-
-        Py_CLEAR(self->snapshot);
-        return result;
-    }
-    else {
-        int res = 1;
-        Py_ssize_t remaining = n;
-
-        result = textiowrapper_get_decoded_chars(self, n);
-        if (result == NULL)
-            goto fail;
-        if (PyUnicode_READY(result) == -1)
-            goto fail;
-        remaining -= PyUnicode_GET_LENGTH(result);
-
-        /* Keep reading chunks until we have n characters to return */
-        while (remaining > 0) {
-            res = textiowrapper_read_chunk(self, remaining);
-            if (res < 0) {
-                /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
-                   when EINTR occurs so we needn't do it ourselves. */
-                if (_PyIO_trap_eintr()) {
-                    continue;
-                }
-                goto fail;
-            }
-            if (res == 0)  /* EOF */
-                break;
-            if (chunks == NULL) {
-                chunks = PyList_New(0);
-                if (chunks == NULL)
-                    goto fail;
-            }
-            if (PyUnicode_GET_LENGTH(result) > 0 &&
-                PyList_Append(chunks, result) < 0)
-                goto fail;
-            Py_DECREF(result);
-            result = textiowrapper_get_decoded_chars(self, remaining);
-            if (result == NULL)
-                goto fail;
-            remaining -= PyUnicode_GET_LENGTH(result);
-        }
-        if (chunks != NULL) {
-            if (result != NULL && PyList_Append(chunks, result) < 0)
-                goto fail;
-            Py_CLEAR(result);
-            result = PyUnicode_Join(_PyIO_empty_str, chunks);
-            if (result == NULL)
-                goto fail;
-            Py_CLEAR(chunks);
-        }
-        return result;
-    }
-  fail:
-    Py_XDECREF(result);
-    Py_XDECREF(chunks);
-    return NULL;
-}
-
-
-/* NOTE: `end` must point to the real end of the Py_UCS4 storage,
-   that is to the NUL character. Otherwise the function will produce
-   incorrect results. */
-static char *
-find_control_char(int kind, char *s, char *end, Py_UCS4 ch)
-{
-    if (kind == PyUnicode_1BYTE_KIND) {
-        assert(ch < 256);
-        return (char *) memchr((void *) s, (char) ch, end - s);
-    }
-    for (;;) {
-        while (PyUnicode_READ(kind, s, 0) > ch)
-            s += kind;
-        if (PyUnicode_READ(kind, s, 0) == ch)
-            return s;
-        if (s == end)
-            return NULL;
-        s += kind;
-    }
-}
-
-Py_ssize_t
-_PyIO_find_line_ending(
-    int translated, int universal, PyObject *readnl,
-    int kind, char *start, char *end, Py_ssize_t *consumed)
-{
-    Py_ssize_t len = ((char*)end - (char*)start)/kind;
-
-    if (translated) {
-        /* Newlines are already translated, only search for \n */
-        char *pos = find_control_char(kind, start, end, '\n');
-        if (pos != NULL)
-            return (pos - start)/kind + 1;
-        else {
-            *consumed = len;
-            return -1;
-        }
-    }
-    else if (universal) {
-        /* Universal newline search. Find any of \r, \r\n, \n
-         * The decoder ensures that \r\n are not split in two pieces
-         */
-        char *s = start;
-        for (;;) {
-            Py_UCS4 ch;
-            /* Fast path for non-control chars. The loop always ends
-               since the Unicode string is NUL-terminated. */
-            while (PyUnicode_READ(kind, s, 0) > '\r')
-                s += kind;
-            if (s >= end) {
-                *consumed = len;
-                return -1;
-            }
-            ch = PyUnicode_READ(kind, s, 0);
-            s += kind;
-            if (ch == '\n')
-                return (s - start)/kind;
-            if (ch == '\r') {
-                if (PyUnicode_READ(kind, s, 0) == '\n')
-                    return (s - start)/kind + 1;
-                else
-                    return (s - start)/kind;
-            }
-        }
-    }
-    else {
-        /* Non-universal mode. */
-        Py_ssize_t readnl_len = PyUnicode_GET_LENGTH(readnl);
-        Py_UCS1 *nl = PyUnicode_1BYTE_DATA(readnl);
-        /* Assume that readnl is an ASCII character. */
-        assert(PyUnicode_KIND(readnl) == PyUnicode_1BYTE_KIND);
-        if (readnl_len == 1) {
-            char *pos = find_control_char(kind, start, end, nl[0]);
-            if (pos != NULL)
-                return (pos - start)/kind + 1;
-            *consumed = len;
-            return -1;
-        }
-        else {
-            char *s = start;
-            char *e = end - (readnl_len - 1)*kind;
-            char *pos;
-            if (e < s)
-                e = s;
-            while (s < e) {
-                Py_ssize_t i;
-                char *pos = find_control_char(kind, s, end, nl[0]);
-                if (pos == NULL || pos >= e)
-                    break;
-                for (i = 1; i < readnl_len; i++) {
-                    if (PyUnicode_READ(kind, pos, i) != nl[i])
-                        break;
-                }
-                if (i == readnl_len)
-                    return (pos - start)/kind + readnl_len;
-                s = pos + kind;
-            }
-            pos = find_control_char(kind, e, end, nl[0]);
-            if (pos == NULL)
-                *consumed = len;
-            else
-                *consumed = (pos - start)/kind;
-            return -1;
-        }
-    }
-}
-
-static PyObject *
-_textiowrapper_readline(textio *self, Py_ssize_t limit)
-{
-    PyObject *line = NULL, *chunks = NULL, *remaining = NULL;
-    Py_ssize_t start, endpos, chunked, offset_to_buffer;
-    int res;
-
-    CHECK_CLOSED(self);
-
-    if (_textiowrapper_writeflush(self) < 0)
-        return NULL;
-
-    chunked = 0;
-
-    while (1) {
-        char *ptr;
-        Py_ssize_t line_len;
-        int kind;
-        Py_ssize_t consumed = 0;
-
-        /* First, get some data if necessary */
-        res = 1;
-        while (!self->decoded_chars ||
-               !PyUnicode_GET_LENGTH(self->decoded_chars)) {
-            res = textiowrapper_read_chunk(self, 0);
-            if (res < 0) {
-                /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
-                   when EINTR occurs so we needn't do it ourselves. */
-                if (_PyIO_trap_eintr()) {
-                    continue;
-                }
-                goto error;
-            }
-            if (res == 0)
-                break;
-        }
-        if (res == 0) {
-            /* end of file */
-            textiowrapper_set_decoded_chars(self, NULL);
-            Py_CLEAR(self->snapshot);
-            start = endpos = offset_to_buffer = 0;
-            break;
-        }
-
-        if (remaining == NULL) {
-            line = self->decoded_chars;
-            start = self->decoded_chars_used;
-            offset_to_buffer = 0;
-            Py_INCREF(line);
-        }
-        else {
-            assert(self->decoded_chars_used == 0);
-            line = PyUnicode_Concat(remaining, self->decoded_chars);
-            start = 0;
-            offset_to_buffer = PyUnicode_GET_LENGTH(remaining);
-            Py_CLEAR(remaining);
-            if (line == NULL)
-                goto error;
-            if (PyUnicode_READY(line) == -1)
-                goto error;
-        }
-
-        ptr = PyUnicode_DATA(line);
-        line_len = PyUnicode_GET_LENGTH(line);
-        kind = PyUnicode_KIND(line);
-
-        endpos = _PyIO_find_line_ending(
-            self->readtranslate, self->readuniversal, self->readnl,
-            kind,
-            ptr + kind * start,
-            ptr + kind * line_len,
-            &consumed);
-        if (endpos >= 0) {
-            endpos += start;
-            if (limit >= 0 && (endpos - start) + chunked >= limit)
-                endpos = start + limit - chunked;
-            break;
-        }
-
-        /* We can put aside up to `endpos` */
-        endpos = consumed + start;
-        if (limit >= 0 && (endpos - start) + chunked >= limit) {
-            /* Didn't find line ending, but reached length limit */
-            endpos = start + limit - chunked;
-            break;
-        }
-
-        if (endpos > start) {
-            /* No line ending seen yet - put aside current data */
-            PyObject *s;
-            if (chunks == NULL) {
-                chunks = PyList_New(0);
-                if (chunks == NULL)
-                    goto error;
-            }
-            s = PyUnicode_Substring(line, start, endpos);
-            if (s == NULL)
-                goto error;
-            if (PyList_Append(chunks, s) < 0) {
-                Py_DECREF(s);
-                goto error;
-            }
-            chunked += PyUnicode_GET_LENGTH(s);
-            Py_DECREF(s);
-        }
-        /* There may be some remaining bytes we'll have to prepend to the
-           next chunk of data */
-        if (endpos < line_len) {
-            remaining = PyUnicode_Substring(line, endpos, line_len);
-            if (remaining == NULL)
-                goto error;
-        }
-        Py_CLEAR(line);
-        /* We have consumed the buffer */
-        textiowrapper_set_decoded_chars(self, NULL);
-    }
-
-    if (line != NULL) {
-        /* Our line ends in the current buffer */
-        self->decoded_chars_used = endpos - offset_to_buffer;
-        if (start > 0 || endpos < PyUnicode_GET_LENGTH(line)) {
-            PyObject *s = PyUnicode_Substring(line, start, endpos);
-            Py_CLEAR(line);
-            if (s == NULL)
-                goto error;
-            line = s;
-        }
-    }
-    if (remaining != NULL) {
-        if (chunks == NULL) {
-            chunks = PyList_New(0);
-            if (chunks == NULL)
-                goto error;
-        }
-        if (PyList_Append(chunks, remaining) < 0)
-            goto error;
-        Py_CLEAR(remaining);
-    }
-    if (chunks != NULL) {
-        if (line != NULL) {
-            if (PyList_Append(chunks, line) < 0)
-                goto error;
-            Py_DECREF(line);
-        }
-        line = PyUnicode_Join(_PyIO_empty_str, chunks);
-        if (line == NULL)
-            goto error;
-        Py_CLEAR(chunks);
-    }
-    if (line == NULL) {
-        Py_INCREF(_PyIO_empty_str);
-        line = _PyIO_empty_str;
-    }
-
-    return line;
-
-  error:
-    Py_XDECREF(chunks);
-    Py_XDECREF(remaining);
-    Py_XDECREF(line);
-    return NULL;
-}
-
-static PyObject *
-textiowrapper_readline(textio *self, PyObject *args)
-{
-    Py_ssize_t limit = -1;
-
-    CHECK_ATTACHED(self);
-    if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
-        return NULL;
-    }
-    return _textiowrapper_readline(self, limit);
-}
-
-/* Seek and Tell */
-
-typedef struct {
-    Py_off_t start_pos;
-    int dec_flags;
-    int bytes_to_feed;
-    int chars_to_skip;
-    char need_eof;
-} cookie_type;
-
-/*
-   To speed up cookie packing/unpacking, we store the fields in a temporary
-   string and call _PyLong_FromByteArray() or _PyLong_AsByteArray (resp.).
-   The following macros define at which offsets in the intermediary byte
-   string the various CookieStruct fields will be stored.
- */
-
-#define COOKIE_BUF_LEN      (sizeof(Py_off_t) + 3 * sizeof(int) + sizeof(char))
-
-#if PY_BIG_ENDIAN
-/* We want the least significant byte of start_pos to also be the least
-   significant byte of the cookie, which means that in big-endian mode we
-   must copy the fields in reverse order. */
-
-# define OFF_START_POS      (sizeof(char) + 3 * sizeof(int))
-# define OFF_DEC_FLAGS      (sizeof(char) + 2 * sizeof(int))
-# define OFF_BYTES_TO_FEED  (sizeof(char) + sizeof(int))
-# define OFF_CHARS_TO_SKIP  (sizeof(char))
-# define OFF_NEED_EOF       0
-
-#else
-/* Little-endian mode: the least significant byte of start_pos will
-   naturally end up the least significant byte of the cookie. */
-
-# define OFF_START_POS      0
-# define OFF_DEC_FLAGS      (sizeof(Py_off_t))
-# define OFF_BYTES_TO_FEED  (sizeof(Py_off_t) + sizeof(int))
-# define OFF_CHARS_TO_SKIP  (sizeof(Py_off_t) + 2 * sizeof(int))
-# define OFF_NEED_EOF       (sizeof(Py_off_t) + 3 * sizeof(int))
-
-#endif
-
-static int
-textiowrapper_parse_cookie(cookie_type *cookie, PyObject *cookieObj)
-{
-    unsigned char buffer[COOKIE_BUF_LEN];
-    PyLongObject *cookieLong = (PyLongObject *)PyNumber_Long(cookieObj);
-    if (cookieLong == NULL)
-        return -1;
-
-    if (_PyLong_AsByteArray(cookieLong, buffer, sizeof(buffer),
-                            PY_LITTLE_ENDIAN, 0) < 0) {
-        Py_DECREF(cookieLong);
-        return -1;
-    }
-    Py_DECREF(cookieLong);
-
-    memcpy(&cookie->start_pos, buffer + OFF_START_POS, sizeof(cookie->start_pos));
-    memcpy(&cookie->dec_flags, buffer + OFF_DEC_FLAGS, sizeof(cookie->dec_flags));
-    memcpy(&cookie->bytes_to_feed, buffer + OFF_BYTES_TO_FEED, sizeof(cookie->bytes_to_feed));
-    memcpy(&cookie->chars_to_skip, buffer + OFF_CHARS_TO_SKIP, sizeof(cookie->chars_to_skip));
-    memcpy(&cookie->need_eof, buffer + OFF_NEED_EOF, sizeof(cookie->need_eof));
-
-    return 0;
-}
-
-static PyObject *
-textiowrapper_build_cookie(cookie_type *cookie)
-{
-    unsigned char buffer[COOKIE_BUF_LEN];
-
-    memcpy(buffer + OFF_START_POS, &cookie->start_pos, sizeof(cookie->start_pos));
-    memcpy(buffer + OFF_DEC_FLAGS, &cookie->dec_flags, sizeof(cookie->dec_flags));
-    memcpy(buffer + OFF_BYTES_TO_FEED, &cookie->bytes_to_feed, sizeof(cookie->bytes_to_feed));
-    memcpy(buffer + OFF_CHARS_TO_SKIP, &cookie->chars_to_skip, sizeof(cookie->chars_to_skip));
-    memcpy(buffer + OFF_NEED_EOF, &cookie->need_eof, sizeof(cookie->need_eof));
-
-    return _PyLong_FromByteArray(buffer, sizeof(buffer),
-                                 PY_LITTLE_ENDIAN, 0);
-}
-
-static int
-_textiowrapper_decoder_setstate(textio *self, cookie_type *cookie)
-{
-    PyObject *res;
-    /* When seeking to the start of the stream, we call decoder.reset()
-       rather than decoder.getstate().
-       This is for a few decoders such as utf-16 for which the state value
-       at start is not (b"", 0) but e.g. (b"", 2) (meaning, in the case of
-       utf-16, that we are expecting a BOM).
-    */
-    if (cookie->start_pos == 0 && cookie->dec_flags == 0)
-        res = PyObject_CallMethodObjArgs(self->decoder, _PyIO_str_reset, NULL);
-    else
-        res = _PyObject_CallMethodId(self->decoder, &PyId_setstate,
-                                     "((yi))", "", cookie->dec_flags);
-    if (res == NULL)
-        return -1;
-    Py_DECREF(res);
-    return 0;
-}
-
-static int
-_textiowrapper_encoder_reset(textio *self, int start_of_stream)
-{
-    PyObject *res;
-    if (start_of_stream) {
-        res = PyObject_CallMethodObjArgs(self->encoder, _PyIO_str_reset, NULL);
-        self->encoding_start_of_stream = 1;
-    }
-    else {
-        res = PyObject_CallMethodObjArgs(self->encoder, _PyIO_str_setstate,
-                                         _PyIO_zero, NULL);
-        self->encoding_start_of_stream = 0;
-    }
-    if (res == NULL)
-        return -1;
-    Py_DECREF(res);
-    return 0;
-}
-
-static int
-_textiowrapper_encoder_setstate(textio *self, cookie_type *cookie)
-{
-    /* Same as _textiowrapper_decoder_setstate() above. */
-    return _textiowrapper_encoder_reset(
-        self, cookie->start_pos == 0 && cookie->dec_flags == 0);
-}
-
-static PyObject *
-textiowrapper_seek(textio *self, PyObject *args)
-{
-    PyObject *cookieObj, *posobj;
-    cookie_type cookie;
-    int whence = 0;
-    PyObject *res;
-    int cmp;
-
-    CHECK_ATTACHED(self);
-
-    if (!PyArg_ParseTuple(args, "O|i:seek", &cookieObj, &whence))
-        return NULL;
-    CHECK_CLOSED(self);
-
-    Py_INCREF(cookieObj);
-
-    if (!self->seekable) {
-        _unsupported("underlying stream is not seekable");
-        goto fail;
-    }
-
-    if (whence == 1) {
-        /* seek relative to current position */
-        cmp = PyObject_RichCompareBool(cookieObj, _PyIO_zero, Py_EQ);
-        if (cmp < 0)
-            goto fail;
-
-        if (cmp == 0) {
-            _unsupported("can't do nonzero cur-relative seeks");
-            goto fail;
-        }
-
-        /* Seeking to the current position should attempt to
-         * sync the underlying buffer with the current position.
-         */
-        Py_DECREF(cookieObj);
-        cookieObj = _PyObject_CallMethodId((PyObject *)self, &PyId_tell, NULL);
-        if (cookieObj == NULL)
-            goto fail;
-    }
-    else if (whence == 2) {
-        /* seek relative to end of file */
-        cmp = PyObject_RichCompareBool(cookieObj, _PyIO_zero, Py_EQ);
-        if (cmp < 0)
-            goto fail;
-
-        if (cmp == 0) {
-            _unsupported("can't do nonzero end-relative seeks");
-            goto fail;
-        }
-
-        res = _PyObject_CallMethodId((PyObject *)self, &PyId_flush, NULL);
-        if (res == NULL)
-            goto fail;
-        Py_DECREF(res);
-
-        textiowrapper_set_decoded_chars(self, NULL);
-        Py_CLEAR(self->snapshot);
-        if (self->decoder) {
-            res = _PyObject_CallMethodId(self->decoder, &PyId_reset, NULL);
-            if (res == NULL)
-                goto fail;
-            Py_DECREF(res);
-        }
-
-        res = _PyObject_CallMethodId(self->buffer, &PyId_seek, "ii", 0, 2);
-        Py_CLEAR(cookieObj);
-        if (res == NULL)
-            goto fail;
-        if (self->encoder) {
-            /* If seek() == 0, we are at the start of stream, otherwise not */
-            cmp = PyObject_RichCompareBool(res, _PyIO_zero, Py_EQ);
-            if (cmp < 0 || _textiowrapper_encoder_reset(self, cmp)) {
-                Py_DECREF(res);
-                goto fail;
-            }
-        }
-        return res;
-    }
-    else if (whence != 0) {
-        PyErr_Format(PyExc_ValueError,
-                     "invalid whence (%d, should be 0, 1 or 2)", whence);
-        goto fail;
-    }
-
-    cmp = PyObject_RichCompareBool(cookieObj, _PyIO_zero, Py_LT);
-    if (cmp < 0)
-        goto fail;
-
-    if (cmp == 1) {
-        PyErr_Format(PyExc_ValueError,
-                     "negative seek position %R", cookieObj);
-        goto fail;
-    }
-
-    res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL);
-    if (res == NULL)
-        goto fail;
-    Py_DECREF(res);
-
-    /* The strategy of seek() is to go back to the safe start point
-     * and replay the effect of read(chars_to_skip) from there.
-     */
-    if (textiowrapper_parse_cookie(&cookie, cookieObj) < 0)
-        goto fail;
-
-    /* Seek back to the safe start point. */
-    posobj = PyLong_FromOff_t(cookie.start_pos);
-    if (posobj == NULL)
-        goto fail;
-    res = PyObject_CallMethodObjArgs(self->buffer,
-                                     _PyIO_str_seek, posobj, NULL);
-    Py_DECREF(posobj);
-    if (res == NULL)
-        goto fail;
-    Py_DECREF(res);
-
-    textiowrapper_set_decoded_chars(self, NULL);
-    Py_CLEAR(self->snapshot);
-
-    /* Restore the decoder to its state from the safe start point. */
-    if (self->decoder) {
-        if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
-            goto fail;
-    }
-
-    if (cookie.chars_to_skip) {
-        /* Just like _read_chunk, feed the decoder and save a snapshot. */
-        PyObject *input_chunk = _PyObject_CallMethodId(
-            self->buffer, &PyId_read, "i", cookie.bytes_to_feed);
-        PyObject *decoded;
-
-        if (input_chunk == NULL)
-            goto fail;
-
-        if (!PyBytes_Check(input_chunk)) {
-            PyErr_Format(PyExc_TypeError,
-                         "underlying read() should have returned a bytes "
-                         "object, not '%.200s'",
-                         Py_TYPE(input_chunk)->tp_name);
-            Py_DECREF(input_chunk);
-            goto fail;
-        }
-
-        self->snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
-        if (self->snapshot == NULL) {
-            Py_DECREF(input_chunk);
-            goto fail;
-        }
-
-        decoded = _PyObject_CallMethodId(self->decoder, &PyId_decode,
-            "Oi", input_chunk, (int)cookie.need_eof);
-
-        if (check_decoded(decoded) < 0)
-            goto fail;
-
-        textiowrapper_set_decoded_chars(self, decoded);
-
-        /* Skip chars_to_skip of the decoded characters. */
-        if (PyUnicode_GetLength(self->decoded_chars) < cookie.chars_to_skip) {
-            PyErr_SetString(PyExc_IOError, "can't restore logical file position");
-            goto fail;
-        }
-        self->decoded_chars_used = cookie.chars_to_skip;
-    }
-    else {
-        self->snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
-        if (self->snapshot == NULL)
-            goto fail;
-    }
-
-    /* Finally, reset the encoder (merely useful for proper BOM handling) */
-    if (self->encoder) {
-        if (_textiowrapper_encoder_setstate(self, &cookie) < 0)
-            goto fail;
-    }
-    return cookieObj;
-  fail:
-    Py_XDECREF(cookieObj);
-    return NULL;
-
-}
-
-static PyObject *
-textiowrapper_tell(textio *self, PyObject *args)
-{
-    PyObject *res;
-    PyObject *posobj = NULL;
-    cookie_type cookie = {0,0,0,0,0};
-    PyObject *next_input;
-    Py_ssize_t chars_to_skip, chars_decoded;
-    Py_ssize_t skip_bytes, skip_back;
-    PyObject *saved_state = NULL;
-    char *input, *input_end;
-    char *dec_buffer;
-    Py_ssize_t dec_buffer_len;
-    int dec_flags;
-
-    CHECK_ATTACHED(self);
-    CHECK_CLOSED(self);
-
-    if (!self->seekable) {
-        _unsupported("underlying stream is not seekable");
-        goto fail;
-    }
-    if (!self->telling) {
-        PyErr_SetString(PyExc_IOError,
-                        "telling position disabled by next() call");
-        goto fail;
-    }
-
-    if (_textiowrapper_writeflush(self) < 0)
-        return NULL;
-    res = _PyObject_CallMethodId((PyObject *)self, &PyId_flush, NULL);
-    if (res == NULL)
-        goto fail;
-    Py_DECREF(res);
-
-    posobj = _PyObject_CallMethodId(self->buffer, &PyId_tell, NULL);
-    if (posobj == NULL)
-        goto fail;
-
-    if (self->decoder == NULL || self->snapshot == NULL) {
-        assert (self->decoded_chars == NULL || PyUnicode_GetLength(self->decoded_chars) == 0);
-        return posobj;
-    }
-
-#if defined(HAVE_LARGEFILE_SUPPORT)
-    cookie.start_pos = PyLong_AsLongLong(posobj);
-#else
-    cookie.start_pos = PyLong_AsLong(posobj);
-#endif
-    Py_DECREF(posobj);
-    if (PyErr_Occurred())
-        goto fail;
-
-    /* Skip backward to the snapshot point (see _read_chunk). */
-    if (!PyArg_Parse(self->snapshot, "(iO)", &cookie.dec_flags, &next_input))
-        goto fail;
-
-    assert (PyBytes_Check(next_input));
-
-    cookie.start_pos -= PyBytes_GET_SIZE(next_input);
-
-    /* How many decoded characters have been used up since the snapshot? */
-    if (self->decoded_chars_used == 0)  {
-        /* We haven't moved from the snapshot point. */
-        return textiowrapper_build_cookie(&cookie);
-    }
-
-    chars_to_skip = self->decoded_chars_used;
-
-    /* Decoder state will be restored at the end */
-    saved_state = PyObject_CallMethodObjArgs(self->decoder,
-                                             _PyIO_str_getstate, NULL);
-    if (saved_state == NULL)
-        goto fail;
-
-#define DECODER_GETSTATE() do { \
-        PyObject *_state = PyObject_CallMethodObjArgs(self->decoder, \
-            _PyIO_str_getstate, NULL); \
-        if (_state == NULL) \
-            goto fail; \
-        if (!PyArg_Parse(_state, "(y#i)", &dec_buffer, &dec_buffer_len, &dec_flags)) { \
-            Py_DECREF(_state); \
-            goto fail; \
-        } \
-        Py_DECREF(_state); \
-    } while (0)
-
-#define DECODER_DECODE(start, len, res) do { \
-        PyObject *_decoded = _PyObject_CallMethodId( \
-            self->decoder, &PyId_decode, "y#", start, len); \
-        if (check_decoded(_decoded) < 0) \
-            goto fail; \
-        res = PyUnicode_GET_LENGTH(_decoded); \
-        Py_DECREF(_decoded); \
-    } while (0)
-
-    /* Fast search for an acceptable start point, close to our
-       current pos */
-    skip_bytes = (Py_ssize_t) (self->b2cratio * chars_to_skip);
-    skip_back = 1;
-    assert(skip_back <= PyBytes_GET_SIZE(next_input));
-    input = PyBytes_AS_STRING(next_input);
-    while (skip_bytes > 0) {
-        /* Decode up to temptative start point */
-        if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
-            goto fail;
-        DECODER_DECODE(input, skip_bytes, chars_decoded);
-        if (chars_decoded <= chars_to_skip) {
-            DECODER_GETSTATE();
-            if (dec_buffer_len == 0) {
-                /* Before pos and no bytes buffered in decoder => OK */
-                cookie.dec_flags = dec_flags;
-                chars_to_skip -= chars_decoded;
-                break;
-            }
-            /* Skip back by buffered amount and reset heuristic */
-            skip_bytes -= dec_buffer_len;
-            skip_back = 1;
-        }
-        else {
-            /* We're too far ahead, skip back a bit */
-            skip_bytes -= skip_back;
-            skip_back *= 2;
-        }
-    }
-    if (skip_bytes <= 0) {
-        skip_bytes = 0;
-        if (_textiowrapper_decoder_setstate(self, &cookie) < 0)
-            goto fail;
-    }
-
-    /* Note our initial start point. */
-    cookie.start_pos += skip_bytes;
-    cookie.chars_to_skip = Py_SAFE_DOWNCAST(chars_to_skip, Py_ssize_t, int);
-    if (chars_to_skip == 0)
-        goto finally;
-
-    /* We should be close to the desired position.  Now feed the decoder one
-     * byte at a time until we reach the `chars_to_skip` target.
-     * As we go, note the nearest "safe start point" before the current
-     * location (a point where the decoder has nothing buffered, so seek()
-     * can safely start from there and advance to this location).
-     */
-    chars_decoded = 0;
-    input = PyBytes_AS_STRING(next_input);
-    input_end = input + PyBytes_GET_SIZE(next_input);
-    input += skip_bytes;
-    while (input < input_end) {
-        Py_ssize_t n;
-
-        DECODER_DECODE(input, (Py_ssize_t)1, n);
-        /* We got n chars for 1 byte */
-        chars_decoded += n;
-        cookie.bytes_to_feed += 1;
-        DECODER_GETSTATE();
-
-        if (dec_buffer_len == 0 && chars_decoded <= chars_to_skip) {
-            /* Decoder buffer is empty, so this is a safe start point. */
-            cookie.start_pos += cookie.bytes_to_feed;
-            chars_to_skip -= chars_decoded;
-            cookie.dec_flags = dec_flags;
-            cookie.bytes_to_feed = 0;
-            chars_decoded = 0;
-        }
-        if (chars_decoded >= chars_to_skip)
-            break;
-        input++;
-    }
-    if (input == input_end) {
-        /* We didn't get enough decoded data; signal EOF to get more. */
-        PyObject *decoded = _PyObject_CallMethodId(
-            self->decoder, &PyId_decode, "yi", "", /* final = */ 1);
-        if (check_decoded(decoded) < 0)
-            goto fail;
-        chars_decoded += PyUnicode_GET_LENGTH(decoded);
-        Py_DECREF(decoded);
-        cookie.need_eof = 1;
-
-        if (chars_decoded < chars_to_skip) {
-            PyErr_SetString(PyExc_IOError,
-                            "can't reconstruct logical file position");
-            goto fail;
-        }
-    }
-
-finally:
-    res = _PyObject_CallMethodId(self->decoder, &PyId_setstate, "(O)", saved_state);
-    Py_DECREF(saved_state);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-
-    /* The returned cookie corresponds to the last safe start point. */
-    cookie.chars_to_skip = Py_SAFE_DOWNCAST(chars_to_skip, Py_ssize_t, int);
-    return textiowrapper_build_cookie(&cookie);
-
-fail:
-    if (saved_state) {
-        PyObject *type, *value, *traceback;
-        PyErr_Fetch(&type, &value, &traceback);
-        res = _PyObject_CallMethodId(self->decoder, &PyId_setstate, "(O)", saved_state);
-        _PyErr_ChainExceptions(type, value, traceback);
-        Py_DECREF(saved_state);
-        Py_XDECREF(res);
-    }
-    return NULL;
-}
-
-static PyObject *
-textiowrapper_truncate(textio *self, PyObject *args)
-{
-    PyObject *pos = Py_None;
-    PyObject *res;
-
-    CHECK_ATTACHED(self)
-    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
-        return NULL;
-    }
-
-    res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_flush, NULL);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-
-    return PyObject_CallMethodObjArgs(self->buffer, _PyIO_str_truncate, pos, NULL);
-}
-
-static PyObject *
-textiowrapper_repr(textio *self)
-{
-    PyObject *nameobj, *modeobj, *res, *s;
-
-    CHECK_INITIALIZED(self);
-
-    res = PyUnicode_FromString("<_io.TextIOWrapper");
-    if (res == NULL)
-        return NULL;
-
-    nameobj = _PyObject_GetAttrId((PyObject *) self, &PyId_name);
-    if (nameobj == NULL) {
-        if (PyErr_ExceptionMatches(PyExc_Exception))
-            PyErr_Clear();
-        else
-            goto error;
-    }
-    else {
-        s = PyUnicode_FromFormat(" name=%R", nameobj);
-        Py_DECREF(nameobj);
-        if (s == NULL)
-            goto error;
-        PyUnicode_AppendAndDel(&res, s);
-        if (res == NULL)
-            return NULL;
-    }
-    modeobj = _PyObject_GetAttrId((PyObject *) self, &PyId_mode);
-    if (modeobj == NULL) {
-        if (PyErr_ExceptionMatches(PyExc_Exception))
-            PyErr_Clear();
-        else
-            goto error;
-    }
-    else {
-        s = PyUnicode_FromFormat(" mode=%R", modeobj);
-        Py_DECREF(modeobj);
-        if (s == NULL)
-            goto error;
-        PyUnicode_AppendAndDel(&res, s);
-        if (res == NULL)
-            return NULL;
-    }
-    s = PyUnicode_FromFormat("%U encoding=%R>",
-                             res, self->encoding);
-    Py_DECREF(res);
-    return s;
-error:
-    Py_XDECREF(res);
-    return NULL;
-}
-
-
-/* Inquiries */
-
-static PyObject *
-textiowrapper_fileno(textio *self, PyObject *args)
-{
-    CHECK_ATTACHED(self);
-    return _PyObject_CallMethodId(self->buffer, &PyId_fileno, NULL);
-}
-
-static PyObject *
-textiowrapper_seekable(textio *self, PyObject *args)
-{
-    CHECK_ATTACHED(self);
-    return _PyObject_CallMethodId(self->buffer, &PyId_seekable, NULL);
-}
-
-static PyObject *
-textiowrapper_readable(textio *self, PyObject *args)
-{
-    CHECK_ATTACHED(self);
-    return _PyObject_CallMethodId(self->buffer, &PyId_readable, NULL);
-}
-
-static PyObject *
-textiowrapper_writable(textio *self, PyObject *args)
-{
-    CHECK_ATTACHED(self);
-    return _PyObject_CallMethodId(self->buffer, &PyId_writable, NULL);
-}
-
-static PyObject *
-textiowrapper_isatty(textio *self, PyObject *args)
-{
-    CHECK_ATTACHED(self);
-    return _PyObject_CallMethodId(self->buffer, &PyId_isatty, NULL);
-}
-
-static PyObject *
-textiowrapper_getstate(textio *self, PyObject *args)
-{
-    PyErr_Format(PyExc_TypeError,
-                 "cannot serialize '%s' object", Py_TYPE(self)->tp_name);
-    return NULL;
-}
-
-static PyObject *
-textiowrapper_flush(textio *self, PyObject *args)
-{
-    CHECK_ATTACHED(self);
-    CHECK_CLOSED(self);
-    self->telling = self->seekable;
-    if (_textiowrapper_writeflush(self) < 0)
-        return NULL;
-    return _PyObject_CallMethodId(self->buffer, &PyId_flush, NULL);
-}
-
-static PyObject *
-textiowrapper_close(textio *self, PyObject *args)
-{
-    PyObject *res;
-    int r;
-    CHECK_ATTACHED(self);
-
-    res = textiowrapper_closed_get(self, NULL);
-    if (res == NULL)
-        return NULL;
-    r = PyObject_IsTrue(res);
-    Py_DECREF(res);
-    if (r < 0)
-        return NULL;
-
-    if (r > 0) {
-        Py_RETURN_NONE; /* stream already closed */
-    }
-    else {
-        PyObject *exc = NULL, *val, *tb;
-        if (self->finalizing) {
-            res = _PyObject_CallMethodId(self->buffer, &PyId__dealloc_warn, "O", self);
-            if (res)
-                Py_DECREF(res);
-            else
-                PyErr_Clear();
-        }
-        res = _PyObject_CallMethodId((PyObject *)self, &PyId_flush, NULL);
-        if (res == NULL)
-            PyErr_Fetch(&exc, &val, &tb);
-        else
-            Py_DECREF(res);
-
-        res = _PyObject_CallMethodId(self->buffer, &PyId_close, NULL);
-        if (exc != NULL) {
-            _PyErr_ChainExceptions(exc, val, tb);
-            Py_CLEAR(res);
-        }
-        return res;
-    }
-}
-
-static PyObject *
-textiowrapper_iternext(textio *self)
-{
-    PyObject *line;
-
-    CHECK_ATTACHED(self);
-
-    self->telling = 0;
-    if (Py_TYPE(self) == &PyTextIOWrapper_Type) {
-        /* Skip method call overhead for speed */
-        line = _textiowrapper_readline(self, -1);
-    }
-    else {
-        line = PyObject_CallMethodObjArgs((PyObject *)self,
-                                           _PyIO_str_readline, NULL);
-        if (line && !PyUnicode_Check(line)) {
-            PyErr_Format(PyExc_IOError,
-                         "readline() should have returned an str object, "
-                         "not '%.200s'", Py_TYPE(line)->tp_name);
-            Py_DECREF(line);
-            return NULL;
-        }
-    }
-
-    if (line == NULL || PyUnicode_READY(line) == -1)
-        return NULL;
-
-    if (PyUnicode_GET_LENGTH(line) == 0) {
-        /* Reached EOF or would have blocked */
-        Py_DECREF(line);
-        Py_CLEAR(self->snapshot);
-        self->telling = self->seekable;
-        return NULL;
-    }
-
-    return line;
-}
-
-static PyObject *
-textiowrapper_name_get(textio *self, void *context)
-{
-    CHECK_ATTACHED(self);
-    return _PyObject_GetAttrId(self->buffer, &PyId_name);
-}
-
-static PyObject *
-textiowrapper_closed_get(textio *self, void *context)
-{
-    CHECK_ATTACHED(self);
-    return PyObject_GetAttr(self->buffer, _PyIO_str_closed);
-}
-
-static PyObject *
-textiowrapper_newlines_get(textio *self, void *context)
-{
-    PyObject *res;
-    CHECK_ATTACHED(self);
-    if (self->decoder == NULL)
-        Py_RETURN_NONE;
-    res = PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
-    if (res == NULL) {
-        if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
-            PyErr_Clear();
-            Py_RETURN_NONE;
-        }
-        else {
-            return NULL;
-        }
-    }
-    return res;
-}
-
-static PyObject *
-textiowrapper_errors_get(textio *self, void *context)
-{
-    CHECK_INITIALIZED(self);
-    return PyUnicode_FromString(PyBytes_AS_STRING(self->errors));
-}
-
-static PyObject *
-textiowrapper_chunk_size_get(textio *self, void *context)
-{
-    CHECK_ATTACHED(self);
-    return PyLong_FromSsize_t(self->chunk_size);
-}
-
-static int
-textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context)
-{
-    Py_ssize_t n;
-    CHECK_ATTACHED_INT(self);
-    n = PyNumber_AsSsize_t(arg, PyExc_ValueError);
-    if (n == -1 && PyErr_Occurred())
-        return -1;
-    if (n <= 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "a strictly positive integer is required");
-        return -1;
-    }
-    self->chunk_size = n;
-    return 0;
-}
-
-static PyMethodDef textiowrapper_methods[] = {
-    {"detach", (PyCFunction)textiowrapper_detach, METH_NOARGS},
-    {"write", (PyCFunction)textiowrapper_write, METH_VARARGS},
-    {"read", (PyCFunction)textiowrapper_read, METH_VARARGS},
-    {"readline", (PyCFunction)textiowrapper_readline, METH_VARARGS},
-    {"flush", (PyCFunction)textiowrapper_flush, METH_NOARGS},
-    {"close", (PyCFunction)textiowrapper_close, METH_NOARGS},
-
-    {"fileno", (PyCFunction)textiowrapper_fileno, METH_NOARGS},
-    {"seekable", (PyCFunction)textiowrapper_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)textiowrapper_readable, METH_NOARGS},
-    {"writable", (PyCFunction)textiowrapper_writable, METH_NOARGS},
-    {"isatty", (PyCFunction)textiowrapper_isatty, METH_NOARGS},
-    {"__getstate__", (PyCFunction)textiowrapper_getstate, METH_NOARGS},
-
-    {"seek", (PyCFunction)textiowrapper_seek, METH_VARARGS},
-    {"tell", (PyCFunction)textiowrapper_tell, METH_NOARGS},
-    {"truncate", (PyCFunction)textiowrapper_truncate, METH_VARARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef textiowrapper_members[] = {
-    {"encoding", T_OBJECT, offsetof(textio, encoding), READONLY},
-    {"buffer", T_OBJECT, offsetof(textio, buffer), READONLY},
-    {"line_buffering", T_BOOL, offsetof(textio, line_buffering), READONLY},
-    {"_finalizing", T_BOOL, offsetof(textio, finalizing), 0},
-    {NULL}
-};
-
-static PyGetSetDef textiowrapper_getset[] = {
-    {"name", (getter)textiowrapper_name_get, NULL, NULL},
-    {"closed", (getter)textiowrapper_closed_get, NULL, NULL},
-/*    {"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}
-};
-
-PyTypeObject PyTextIOWrapper_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.TextIOWrapper",        /*tp_name*/
-    sizeof(textio), /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)textiowrapper_dealloc, /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tps_etattr*/
-    0,                          /*tp_compare */
-    (reprfunc)textiowrapper_repr,/*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
-        | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
-    textiowrapper_doc,          /* tp_doc */
-    (traverseproc)textiowrapper_traverse, /* tp_traverse */
-    (inquiry)textiowrapper_clear, /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(textio, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    (iternextfunc)textiowrapper_iternext, /* tp_iternext */
-    textiowrapper_methods,      /* tp_methods */
-    textiowrapper_members,      /* tp_members */
-    textiowrapper_getset,       /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(textio, dict), /*tp_dictoffset*/
-    (initproc)textiowrapper_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-    0,                          /* tp_free */
-    0,                          /* tp_is_gc */
-    0,                          /* tp_bases */
-    0,                          /* tp_mro */
-    0,                          /* tp_cache */
-    0,                          /* tp_subclasses */
-    0,                          /* tp_weaklist */
-    0,                          /* tp_del */
-    0,                          /* tp_version_tag */
-    0,                          /* tp_finalize */
-};
+/*[clinic end generated code: output=a610bd3b694886c3 input=a9049054013a1b77]*/
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -43,6 +43,19 @@
 #define SMALLCHUNK BUFSIZ
 #endif
 
+/*[clinic input]
+module _io
+class _io.FileIO "fileio *" "&PyFileIO_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c77708b41fda70c]*/
+
+/*[python input]
+class io_ssize_t_converter(CConverter):
+    type = 'Py_ssize_t'
+    converter = '_PyIO_ConvertSsize_t'
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/
+
 typedef struct {
     PyObject_HEAD
     int fd;
@@ -126,8 +139,18 @@
     return 0;
 }
 
+/*[clinic input]
+_io.FileIO.close
+
+Close the file.
+
+A closed file cannot be used for further I/O operations.  close() may be
+called more than once without error.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_close(fileio *self)
+_io_FileIO_close_impl(fileio *self)
+/*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/
 {
     PyObject *res;
     PyObject *exc, *val, *tb;
@@ -183,15 +206,36 @@
 extern int _Py_open_cloexec_works;
 #endif
 
+/*[clinic input]
+_io.FileIO.__init__
+    file as nameobj: object
+    mode: str = "r"
+    closefd: int(c_default="1") = True
+    opener: object = None
+
+Open a file.
+
+The mode can be 'r' (default), 'w', 'x' or 'a' for reading,
+writing, exclusive creation or appending.  The file will be created if it
+doesn't exist when opened for writing or appending; it will be truncated
+when opened for writing.  A FileExistsError will be raised if it already
+exists when opened for creating. Opening a file for creating implies
+writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode
+to allow simultaneous reading and writing. A custom opener can be used by
+passing a callable as *opener*. The underlying file descriptor for the file
+object is then obtained by calling opener with (*name*, *flags*).
+*opener* must return an open file descriptor (passing os.open as *opener*
+results in functionality similar to passing None).
+[clinic start generated code]*/
+
 static int
-fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
+_io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode,
+                         int closefd, PyObject *opener)
+/*[clinic end generated code: output=23413f68e6484bbd input=193164e293d6c097]*/
 {
-    fileio *self = (fileio *) oself;
-    static char *kwlist[] = {"file", "mode", "closefd", "opener", NULL};
     const char *name = NULL;
-    PyObject *nameobj, *stringobj = NULL, *opener = Py_None;
-    char *mode = "r";
-    char *s;
+    PyObject *stringobj = NULL;
+    const char *s;
 #ifdef MS_WINDOWS
     Py_UNICODE *widename = NULL;
 #endif
@@ -199,7 +243,6 @@
     int rwa = 0, plus = 0;
     int flags = 0;
     int fd = -1;
-    int closefd = 1;
     int fd_is_own = 0;
 #ifdef O_CLOEXEC
     int *atomic_flag_works = &_Py_open_cloexec_works;
@@ -220,11 +263,6 @@
             self->fd = -1;
     }
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|siO:fileio",
-                                     kwlist, &nameobj, &mode, &closefd,
-                                     &opener))
-        return -1;
-
     if (PyFloat_Check(nameobj)) {
         PyErr_SetString(PyExc_TypeError,
                         "integer argument expected, got float");
@@ -494,32 +532,60 @@
     return NULL;
 }
 
+/*[clinic input]
+_io.FileIO.fileno
+
+Return the underlying file descriptor (an integer).
+[clinic start generated code]*/
+
 static PyObject *
-fileio_fileno(fileio *self)
+_io_FileIO_fileno_impl(fileio *self)
+/*[clinic end generated code: output=a9626ce5398ece90 input=0b9b2de67335ada3]*/
 {
     if (self->fd < 0)
         return err_closed();
     return PyLong_FromLong((long) self->fd);
 }
 
+/*[clinic input]
+_io.FileIO.readable
+
+True if file was opened in a read mode.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_readable(fileio *self)
+_io_FileIO_readable_impl(fileio *self)
+/*[clinic end generated code: output=640744a6150fe9ba input=a3fdfed6eea721c5]*/
 {
     if (self->fd < 0)
         return err_closed();
     return PyBool_FromLong((long) self->readable);
 }
 
+/*[clinic input]
+_io.FileIO.writable
+
+True if file was opened in a write mode.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_writable(fileio *self)
+_io_FileIO_writable_impl(fileio *self)
+/*[clinic end generated code: output=96cefc5446e89977 input=c204a808ca2e1748]*/
 {
     if (self->fd < 0)
         return err_closed();
     return PyBool_FromLong((long) self->writable);
 }
 
+/*[clinic input]
+_io.FileIO.seekable
+
+True if file supports random-access.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_seekable(fileio *self)
+_io_FileIO_seekable_impl(fileio *self)
+/*[clinic end generated code: output=47909ca0a42e9287 input=c8e5554d2fd63c7f]*/
 {
     if (self->fd < 0)
         return err_closed();
@@ -536,10 +602,18 @@
     return PyBool_FromLong((long) self->seekable);
 }
 
+/*[clinic input]
+_io.FileIO.readinto
+    buffer: Py_buffer(types={'rwbuffer'})
+    /
+
+Same as RawIOBase.readinto().
+[clinic start generated code]*/
+
 static PyObject *
-fileio_readinto(fileio *self, PyObject *args)
+_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer)
+/*[clinic end generated code: output=b01a5a22c8415cb4 input=5edd8327498d468c]*/
 {
-    Py_buffer pbuf;
     Py_ssize_t n;
     int err;
 
@@ -548,13 +622,9 @@
     if (!self->readable)
         return err_mode("reading");
 
-    if (!PyArg_ParseTuple(args, "w*", &pbuf))
-        return NULL;
-
-    n = _Py_read(self->fd, pbuf.buf, pbuf.len);
+    n = _Py_read(self->fd, buffer->buf, buffer->len);
     /* copy errno because PyBuffer_Release() can indirectly modify it */
     err = errno;
-    PyBuffer_Release(&pbuf);
 
     if (n == -1) {
         if (err == EAGAIN) {
@@ -586,8 +656,18 @@
     return addend + currentsize;
 }
 
+/*[clinic input]
+_io.FileIO.readall
+
+Read all data from the file, returned as bytes.
+
+In non-blocking mode, returns as much as is immediately available,
+or None if no data is available.  Return an empty bytes object at EOF.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_readall(fileio *self)
+_io_FileIO_readall_impl(fileio *self)
+/*[clinic end generated code: output=faa0292b213b4022 input=dbdc137f55602834]*/
 {
     struct _Py_stat_struct status;
     Py_off_t pos, end;
@@ -673,12 +753,24 @@
     return result;
 }
 
+/*[clinic input]
+_io.FileIO.read
+    size: io_ssize_t = -1
+    /
+
+Read at most size bytes, returned as bytes.
+
+Only makes one system call, so less data may be returned than requested.
+In non-blocking mode, returns None if no data is available.
+Return an empty bytes object at EOF.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_read(fileio *self, PyObject *args)
+_io_FileIO_read_impl(fileio *self, Py_ssize_t size)
+/*[clinic end generated code: output=42528d39dd0ca641 input=5c6caa5490c13a9b]*/
 {
     char *ptr;
     Py_ssize_t n;
-    Py_ssize_t size = -1;
     PyObject *bytes;
 
     if (self->fd < 0)
@@ -686,11 +778,8 @@
     if (!self->readable)
         return err_mode("reading");
 
-    if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size))
-        return NULL;
-
     if (size < 0)
-        return fileio_readall(self);
+        return _io_FileIO_readall_impl(self);
 
 #ifdef MS_WINDOWS
     /* On Windows, the count parameter of read() is an int */
@@ -725,10 +814,22 @@
     return (PyObject *) bytes;
 }
 
+/*[clinic input]
+_io.FileIO.write
+    b: Py_buffer
+    /
+
+Write bytes b to file, return number written.
+
+Only makes one system call, so not all of the data may be written.
+The number of bytes actually written is returned.  In non-blocking mode,
+returns None if the write would block.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_write(fileio *self, PyObject *args)
+_io_FileIO_write_impl(fileio *self, Py_buffer *b)
+/*[clinic end generated code: output=b4059db3d363a2f7 input=ffbd8834f447ac31]*/
 {
-    Py_buffer pbuf;
     Py_ssize_t n;
     int err;
 
@@ -737,13 +838,9 @@
     if (!self->writable)
         return err_mode("writing");
 
-    if (!PyArg_ParseTuple(args, "y*", &pbuf))
-        return NULL;
-
-    n = _Py_write(self->fd, pbuf.buf, pbuf.len);
+    n = _Py_write(self->fd, b->buf, b->len);
     /* copy errno because PyBuffer_Release() can indirectly modify it */
     err = errno;
-    PyBuffer_Release(&pbuf);
 
     if (n < 0) {
         if (err == EAGAIN) {
@@ -817,23 +914,44 @@
 #endif
 }
 
+/*[clinic input]
+_io.FileIO.seek
+    pos: object
+    whence: int = 0
+    /
+
+Move to new file position and return the file position.
+
+Argument offset is a byte count.  Optional argument whence defaults to
+SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values
+are SEEK_CUR or 1 (move relative to current position, positive or negative),
+and SEEK_END or 2 (move relative to end of file, usually negative, although
+many platforms allow seeking beyond the end of a file).
+
+Note that not all file objects are seekable.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_seek(fileio *self, PyObject *args)
+_io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence)
+/*[clinic end generated code: output=c976acdf054e6655 input=0439194b0774d454]*/
 {
-    PyObject *posobj;
-    int whence = 0;
-
     if (self->fd < 0)
         return err_closed();
 
-    if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence))
-        return NULL;
-
-    return portable_lseek(self->fd, posobj, whence);
+    return portable_lseek(self->fd, pos, whence);
 }
 
+/*[clinic input]
+_io.FileIO.tell
+
+Current file position.
+
+Can raise OSError for non seekable files.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_tell(fileio *self, PyObject *args)
+_io_FileIO_tell_impl(fileio *self)
+/*[clinic end generated code: output=ffe2147058809d0b input=807e24ead4cec2f9]*/
 {
     if (self->fd < 0)
         return err_closed();
@@ -842,10 +960,21 @@
 }
 
 #ifdef HAVE_FTRUNCATE
+/*[clinic input]
+_io.FileIO.truncate
+    size as posobj: object = NULL
+    /
+
+Truncate the file to at most size bytes and return the truncated size.
+
+Size defaults to the current file position, as returned by tell().
+The current file position is changed to the value of size.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_truncate(fileio *self, PyObject *args)
+_io_FileIO_truncate_impl(fileio *self, PyObject *posobj)
+/*[clinic end generated code: output=e49ca7a916c176fa input=9026af44686b7318]*/
 {
-    PyObject *posobj = NULL; /* the new size wanted by the user */
     Py_off_t pos;
     int ret;
     int fd;
@@ -856,9 +985,6 @@
     if (!self->writable)
         return err_mode("writing");
 
-    if (!PyArg_ParseTuple(args, "|O", &posobj))
-        return NULL;
-
     if (posobj == Py_None || posobj == NULL) {
         /* Get the current position. */
         posobj = portable_lseek(fd, NULL, 1);
@@ -952,8 +1078,15 @@
     return res;
 }
 
+/*[clinic input]
+_io.FileIO.isatty
+
+True if the file is connected to a TTY device.
+[clinic start generated code]*/
+
 static PyObject *
-fileio_isatty(fileio *self)
+_io_FileIO_isatty_impl(fileio *self)
+/*[clinic end generated code: output=932c39924e9a8070 input=cd94ca1f5e95e843]*/
 {
     long res;
 
@@ -978,110 +1111,22 @@
     return NULL;
 }
 
-
-PyDoc_STRVAR(fileio_doc,
-"file(name: str[, mode: str][, opener: None]) -> file IO object\n"
-"\n"
-"Open a file.  The mode can be 'r' (default), 'w', 'x' or 'a' for reading,\n"
-"writing, exclusive creation or appending.  The file will be created if it\n"
-"doesn't exist when opened for writing or appending; it will be truncated\n"
-"when opened for writing.  A FileExistsError will be raised if it already\n"
-"exists when opened for creating. Opening a file for creating implies\n"
-"writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode\n"
-"to allow simultaneous reading and writing. A custom opener can be used by\n"
-"passing a callable as *opener*. The underlying file descriptor for the file\n"
-"object is then obtained by calling opener with (*name*, *flags*).\n"
-"*opener* must return an open file descriptor (passing os.open as *opener*\n"
-"results in functionality similar to passing None).");
-
-PyDoc_STRVAR(read_doc,
-"read(size: int) -> bytes.  read at most size bytes, returned as bytes.\n"
-"\n"
-"Only makes one system call, so less data may be returned than requested\n"
-"In non-blocking mode, returns None if no data is available.\n"
-"Return an empty bytes object at EOF.");
-
-PyDoc_STRVAR(readall_doc,
-"readall() -> bytes.  read all data from the file, returned as bytes.\n"
-"\n"
-"In non-blocking mode, returns as much as is immediately available,\n"
-"or None if no data is available.  Return an empty bytes object at EOF.");
-
-PyDoc_STRVAR(write_doc,
-"write(b: bytes) -> int.  Write bytes b to file, return number written.\n"
-"\n"
-"Only makes one system call, so not all of the data may be written.\n"
-"The number of bytes actually written is returned.  In non-blocking mode,\n"
-"returns None if the write would block."
-);
-
-PyDoc_STRVAR(fileno_doc,
-"fileno() -> int.  Return the underlying file descriptor (an integer).");
-
-PyDoc_STRVAR(seek_doc,
-"seek(offset: int[, whence: int]) -> int.  Move to new file position and\n"
-"return the file position.\n"
-"\n"
-"Argument offset is a byte count.  Optional argument whence defaults to\n"
-"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n"
-"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n"
-"and SEEK_END or 2 (move relative to end of file, usually negative, although\n"
-"many platforms allow seeking beyond the end of a file).\n"
-"\n"
-"Note that not all file objects are seekable.");
-
-#ifdef HAVE_FTRUNCATE
-PyDoc_STRVAR(truncate_doc,
-"truncate([size: int]) -> int.  Truncate the file to at most size bytes\n"
-"and return the truncated size.\n"
-"\n"
-"Size defaults to the current file position, as returned by tell().\n"
-"The current file position is changed to the value of size.");
-#endif
-
-PyDoc_STRVAR(tell_doc,
-"tell() -> int.  Current file position.\n"
-"\n"
-"Can raise OSError for non seekable files."
-);
-
-PyDoc_STRVAR(readinto_doc,
-"readinto() -> Same as RawIOBase.readinto().");
-
-PyDoc_STRVAR(close_doc,
-"close() -> None.  Close the file.\n"
-"\n"
-"A closed file cannot be used for further I/O operations.  close() may be\n"
-"called more than once without error.");
-
-PyDoc_STRVAR(isatty_doc,
-"isatty() -> bool.  True if the file is connected to a TTY device.");
-
-PyDoc_STRVAR(seekable_doc,
-"seekable() -> bool.  True if file supports random-access.");
-
-PyDoc_STRVAR(readable_doc,
-"readable() -> bool.  True if file was opened in a read mode.");
-
-PyDoc_STRVAR(writable_doc,
-"writable() -> bool.  True if file was opened in a write mode.");
+#include "clinic/fileio.c.h"
 
 static PyMethodDef fileio_methods[] = {
-    {"read",     (PyCFunction)fileio_read,         METH_VARARGS, read_doc},
-    {"readall",  (PyCFunction)fileio_readall,  METH_NOARGS,  readall_doc},
-    {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc},
-    {"write",    (PyCFunction)fileio_write,        METH_VARARGS, write_doc},
-    {"seek",     (PyCFunction)fileio_seek,         METH_VARARGS, seek_doc},
-    {"tell",     (PyCFunction)fileio_tell,         METH_VARARGS, tell_doc},
-#ifdef HAVE_FTRUNCATE
-    {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc},
-#endif
-    {"close",    (PyCFunction)fileio_close,        METH_NOARGS,  close_doc},
-    {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS,      seekable_doc},
-    {"readable", (PyCFunction)fileio_readable, METH_NOARGS,      readable_doc},
-    {"writable", (PyCFunction)fileio_writable, METH_NOARGS,      writable_doc},
-    {"fileno",   (PyCFunction)fileio_fileno,   METH_NOARGS,      fileno_doc},
-    {"isatty",   (PyCFunction)fileio_isatty,   METH_NOARGS,      isatty_doc},
+    _IO_FILEIO_READ_METHODDEF
+    _IO_FILEIO_READALL_METHODDEF
+    _IO_FILEIO_READINTO_METHODDEF
+    _IO_FILEIO_WRITE_METHODDEF
+    _IO_FILEIO_SEEK_METHODDEF
+    _IO_FILEIO_TELL_METHODDEF
+    _IO_FILEIO_TRUNCATE_METHODDEF
+    _IO_FILEIO_CLOSE_METHODDEF
+    _IO_FILEIO_SEEKABLE_METHODDEF
+    _IO_FILEIO_READABLE_METHODDEF
+    _IO_FILEIO_WRITABLE_METHODDEF
+    _IO_FILEIO_FILENO_METHODDEF
+    _IO_FILEIO_ISATTY_METHODDEF
     {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL},
     {"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL},
     {NULL,           NULL}             /* sentinel */
@@ -1143,7 +1188,7 @@
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
         | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE,       /* tp_flags */
-    fileio_doc,                                 /* tp_doc */
+    _io_FileIO___init____doc__,                 /* tp_doc */
     (traverseproc)fileio_traverse,              /* tp_traverse */
     (inquiry)fileio_clear,                      /* tp_clear */
     0,                                          /* tp_richcompare */
@@ -1158,7 +1203,7 @@
     0,                                          /* tp_descr_get */
     0,                                          /* tp_descr_set */
     offsetof(fileio, dict),         /* tp_dictoffset */
-    fileio_init,                                /* tp_init */
+    _io_FileIO___init__,                        /* tp_init */
     PyType_GenericAlloc,                        /* tp_alloc */
     fileio_new,                                 /* tp_new */
     PyObject_GC_Del,                            /* tp_free */
diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/iobase.c
@@ -13,6 +13,20 @@
 #include "structmember.h"
 #include "_iomodule.h"
 
+/*[clinic input]
+module _io
+class _io._IOBase "PyObject *" "&PyIOBase_Type"
+class _io._RawIOBase "PyObject *" "&PyRawIOBase_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d29a4d076c2b211c]*/
+
+/*[python input]
+class io_ssize_t_converter(CConverter):
+    type = 'Py_ssize_t'
+    converter = '_PyIO_ConvertSsize_t'
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/
+
 /*
  * IOBase class, an abstract class
  */
@@ -96,11 +110,15 @@
     return iobase_unsupported("seek");
 }
 
-PyDoc_STRVAR(iobase_tell_doc,
-             "Return current stream position.");
+/*[clinic input]
+_io._IOBase.tell
+
+Return current stream position.
+[clinic start generated code]*/
 
 static PyObject *
-iobase_tell(PyObject *self, PyObject *args)
+_io__IOBase_tell_impl(PyObject *self)
+/*[clinic end generated code: output=89a1c0807935abe2 input=04e615fec128801f]*/
 {
     _Py_IDENTIFIER(seek);
 
@@ -121,13 +139,17 @@
 
 /* Flush and close methods */
 
-PyDoc_STRVAR(iobase_flush_doc,
-    "Flush write buffers, if applicable.\n"
-    "\n"
-    "This is not implemented for read-only and non-blocking streams.\n");
+/*[clinic input]
+_io._IOBase.flush
+
+Flush write buffers, if applicable.
+
+This is not implemented for read-only and non-blocking streams.
+[clinic start generated code]*/
 
 static PyObject *
-iobase_flush(PyObject *self, PyObject *args)
+_io__IOBase_flush_impl(PyObject *self)
+/*[clinic end generated code: output=7cef4b4d54656a3b input=773be121abe270aa]*/
 {
     /* XXX Should this return the number of bytes written??? */
     if (IS_CLOSED(self)) {
@@ -137,11 +159,6 @@
     Py_RETURN_NONE;
 }
 
-PyDoc_STRVAR(iobase_close_doc,
-    "Flush and close the IO object.\n"
-    "\n"
-    "This method has no effect if the file is already closed.\n");
-
 static int
 iobase_closed(PyObject *self)
 {
@@ -180,8 +197,17 @@
    `__IOBase_closed` and call flush() by itself, but it is redundant with
    whatever behaviour a non-trivial derived class will implement. */
 
+/*[clinic input]
+_io._IOBase.close
+
+Flush and close the IO object.
+
+This method has no effect if the file is already closed.
+[clinic start generated code]*/
+
 static PyObject *
-iobase_close(PyObject *self, PyObject *args)
+_io__IOBase_close_impl(PyObject *self)
+/*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/
 {
     PyObject *res;
 
@@ -304,14 +330,18 @@
 
 /* Inquiry methods */
 
-PyDoc_STRVAR(iobase_seekable_doc,
-    "Return whether object supports random access.\n"
-    "\n"
-    "If False, seek(), tell() and truncate() will raise UnsupportedOperation.\n"
-    "This method may need to do a test seek().");
+/*[clinic input]
+_io._IOBase.seekable
+
+Return whether object supports random access.
+
+If False, seek(), tell() and truncate() will raise UnsupportedOperation.
+This method may need to do a test seek().
+[clinic start generated code]*/
 
 static PyObject *
-iobase_seekable(PyObject *self, PyObject *args)
+_io__IOBase_seekable_impl(PyObject *self)
+/*[clinic end generated code: output=4c24c67f5f32a43d input=22676eebb81dcf1e]*/
 {
     Py_RETURN_FALSE;
 }
@@ -333,13 +363,17 @@
     return res;
 }
 
-PyDoc_STRVAR(iobase_readable_doc,
-    "Return whether object was opened for reading.\n"
-    "\n"
-    "If False, read() will raise UnsupportedOperation.");
+/*[clinic input]
+_io._IOBase.readable
+
+Return whether object was opened for reading.
+
+If False, read() will raise UnsupportedOperation.
+[clinic start generated code]*/
 
 static PyObject *
-iobase_readable(PyObject *self, PyObject *args)
+_io__IOBase_readable_impl(PyObject *self)
+/*[clinic end generated code: output=e48089250686388b input=12fc3d8f6be46434]*/
 {
     Py_RETURN_FALSE;
 }
@@ -362,13 +396,17 @@
     return res;
 }
 
-PyDoc_STRVAR(iobase_writable_doc,
-    "Return whether object was opened for writing.\n"
-    "\n"
-    "If False, write() will raise UnsupportedOperation.");
+/*[clinic input]
+_io._IOBase.writable
+
+Return whether object was opened for writing.
+
+If False, write() will raise UnsupportedOperation.
+[clinic start generated code]*/
 
 static PyObject *
-iobase_writable(PyObject *self, PyObject *args)
+_io__IOBase_writable_impl(PyObject *self)
+/*[clinic end generated code: output=406001d0985be14f input=c17a0bb6a8dfc590]*/
 {
     Py_RETURN_FALSE;
 }
@@ -413,24 +451,32 @@
 
 /* XXX Should these be present even if unimplemented? */
 
-PyDoc_STRVAR(iobase_fileno_doc,
-    "Returns underlying file descriptor if one exists.\n"
-    "\n"
-    "An IOError is raised if the IO object does not use a file descriptor.\n");
+/*[clinic input]
+_io._IOBase.fileno
+
+Returns underlying file descriptor if one exists.
+
+An IOError is raised if the IO object does not use a file descriptor.
+[clinic start generated code]*/
 
 static PyObject *
-iobase_fileno(PyObject *self, PyObject *args)
+_io__IOBase_fileno_impl(PyObject *self)
+/*[clinic end generated code: output=7cc0973f0f5f3b73 input=32773c5df4b7eede]*/
 {
     return iobase_unsupported("fileno");
 }
 
-PyDoc_STRVAR(iobase_isatty_doc,
-    "Return whether this is an 'interactive' stream.\n"
-    "\n"
-    "Return False if it can't be determined.\n");
+/*[clinic input]
+_io._IOBase.isatty
+
+Return whether this is an 'interactive' stream.
+
+Return False if it can't be determined.
+[clinic start generated code]*/
 
 static PyObject *
-iobase_isatty(PyObject *self, PyObject *args)
+_io__IOBase_isatty_impl(PyObject *self)
+/*[clinic end generated code: output=60cab77cede41cdd input=9ef76530d368458b]*/
 {
     if (_PyIOBase_check_closed(self, Py_True) == NULL)
         return NULL;
@@ -439,30 +485,31 @@
 
 /* Readline(s) and writelines */
 
-PyDoc_STRVAR(iobase_readline_doc,
-    "Read and return a line from the stream.\n"
-    "\n"
-    "If limit is specified, at most limit bytes will be read.\n"
-    "\n"
-    "The line terminator is always b'\\n' for binary files; for text\n"
-    "files, the newlines argument to open can be used to select the line\n"
-    "terminator(s) recognized.\n");
+/*[clinic input]
+_io._IOBase.readline
+    size as limit: io_ssize_t = -1
+    /
+
+Read and return a line from the stream.
+
+If size is specified, at most size bytes will be read.
+
+The line terminator is always b'\n' for binary files; for text
+files, the newlines argument to open can be used to select the line
+terminator(s) recognized.
+[clinic start generated code]*/
 
 static PyObject *
-iobase_readline(PyObject *self, PyObject *args)
+_io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit)
+/*[clinic end generated code: output=4479f79b58187840 input=df4cc8884f553cab]*/
 {
     /* For backwards compatibility, a (slowish) readline(). */
 
-    Py_ssize_t limit = -1;
     int has_peek = 0;
     PyObject *buffer, *result;
     Py_ssize_t old_size = -1;
     _Py_IDENTIFIER(peek);
 
-    if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit)) {
-        return NULL;
-    }
-
     if (_PyObject_HasAttrId(self, &PyId_peek))
         has_peek = 1;
 
@@ -585,23 +632,25 @@
     return line;
 }
 
-PyDoc_STRVAR(iobase_readlines_doc,
-    "Return a list of lines from the stream.\n"
-    "\n"
-    "hint can be specified to control the number of lines read: no more\n"
-    "lines will be read if the total size (in bytes/characters) of all\n"
-    "lines so far exceeds hint.");
+/*[clinic input]
+_io._IOBase.readlines
+    hint: io_ssize_t = -1
+    /
+
+Return a list of lines from the stream.
+
+hint can be specified to control the number of lines read: no more
+lines will be read if the total size (in bytes/characters) of all
+lines so far exceeds hint.
+[clinic start generated code]*/
 
 static PyObject *
-iobase_readlines(PyObject *self, PyObject *args)
+_io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint)
+/*[clinic end generated code: output=2f50421677fa3dea input=1961c4a95e96e661]*/
 {
-    Py_ssize_t hint = -1, length = 0;
+    Py_ssize_t length = 0;
     PyObject *result;
 
-    if (!PyArg_ParseTuple(args, "|O&:readlines", &_PyIO_ConvertSsize_t, &hint)) {
-        return NULL;
-    }
-
     result = PyList_New(0);
     if (result == NULL)
         return NULL;
@@ -646,14 +695,17 @@
     return result;
 }
 
+/*[clinic input]
+_io._IOBase.writelines
+    lines: object
+    /
+[clinic start generated code]*/
+
 static PyObject *
-iobase_writelines(PyObject *self, PyObject *args)
+_io__IOBase_writelines(PyObject *self, PyObject *lines)
+/*[clinic end generated code: output=976eb0a9b60a6628 input=432e729a8450b3cb]*/
 {
-    PyObject *lines, *iter, *res;
-
-    if (!PyArg_ParseTuple(args, "O:writelines", &lines)) {
-        return NULL;
-    }
+    PyObject *iter, *res;
 
     if (_PyIOBase_check_closed(self, Py_True) == NULL)
         return NULL;
@@ -688,31 +740,33 @@
     Py_RETURN_NONE;
 }
 
+#include "clinic/iobase.c.h"
+
 static PyMethodDef iobase_methods[] = {
     {"seek", iobase_seek, METH_VARARGS, iobase_seek_doc},
-    {"tell", iobase_tell, METH_NOARGS, iobase_tell_doc},
+    _IO__IOBASE_TELL_METHODDEF
     {"truncate", iobase_truncate, METH_VARARGS, iobase_truncate_doc},
-    {"flush", iobase_flush, METH_NOARGS, iobase_flush_doc},
-    {"close", iobase_close, METH_NOARGS, iobase_close_doc},
+    _IO__IOBASE_FLUSH_METHODDEF
+    _IO__IOBASE_CLOSE_METHODDEF
 
-    {"seekable", iobase_seekable, METH_NOARGS, iobase_seekable_doc},
-    {"readable", iobase_readable, METH_NOARGS, iobase_readable_doc},
-    {"writable", iobase_writable, METH_NOARGS, iobase_writable_doc},
+    _IO__IOBASE_SEEKABLE_METHODDEF
+    _IO__IOBASE_READABLE_METHODDEF
+    _IO__IOBASE_WRITABLE_METHODDEF
 
     {"_checkClosed",   _PyIOBase_check_closed, METH_NOARGS},
     {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS},
     {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS},
     {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS},
 
-    {"fileno", iobase_fileno, METH_NOARGS, iobase_fileno_doc},
-    {"isatty", iobase_isatty, METH_NOARGS, iobase_isatty_doc},
+    _IO__IOBASE_FILENO_METHODDEF
+    _IO__IOBASE_ISATTY_METHODDEF
 
     {"__enter__", iobase_enter, METH_NOARGS},
     {"__exit__", iobase_exit, METH_VARARGS},
 
-    {"readline", iobase_readline, METH_VARARGS, iobase_readline_doc},
-    {"readlines", iobase_readlines, METH_VARARGS, iobase_readlines_doc},
-    {"writelines", iobase_writelines, METH_VARARGS},
+    _IO__IOBASE_READLINE_METHODDEF
+    _IO__IOBASE_READLINES_METHODDEF
+    _IO__IOBASE_WRITELINES_METHODDEF
 
     {NULL, NULL}
 };
@@ -795,16 +849,18 @@
  * either.)
 */
 
+/*[clinic input]
+_io._RawIOBase.read
+    size as n: Py_ssize_t = -1
+    /
+[clinic start generated code]*/
+
 static PyObject *
-rawiobase_read(PyObject *self, PyObject *args)
+_io__RawIOBase_read_impl(PyObject *self, Py_ssize_t n)
+/*[clinic end generated code: output=6cdeb731e3c9f13c input=b6d0dcf6417d1374]*/
 {
-    Py_ssize_t n = -1;
     PyObject *b, *res;
 
-    if (!PyArg_ParseTuple(args, "|n:read", &n)) {
-        return NULL;
-    }
-
     if (n < 0) {
         _Py_IDENTIFIER(readall);
 
@@ -836,11 +892,15 @@
 }
 
 
-PyDoc_STRVAR(rawiobase_readall_doc,
-             "Read until EOF, using multiple read() call.");
+/*[clinic input]
+_io._RawIOBase.readall
+
+Read until EOF, using multiple read() call.
+[clinic start generated code]*/
 
 static PyObject *
-rawiobase_readall(PyObject *self, PyObject *args)
+_io__RawIOBase_readall_impl(PyObject *self)
+/*[clinic end generated code: output=1987b9ce929425a0 input=688874141213622a]*/
 {
     int r;
     PyObject *chunks = PyList_New(0);
@@ -893,8 +953,8 @@
 }
 
 static PyMethodDef rawiobase_methods[] = {
-    {"read", rawiobase_read, METH_VARARGS},
-    {"readall", rawiobase_readall, METH_NOARGS, rawiobase_readall_doc},
+    _IO__RAWIOBASE_READ_METHODDEF
+    _IO__RAWIOBASE_READALL_METHODDEF
     {NULL, NULL}
 };
 
diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c
--- a/Modules/_io/stringio.c
+++ b/Modules/_io/stringio.c
@@ -11,6 +11,12 @@
 #define STATE_REALIZED 1
 #define STATE_ACCUMULATING 2
 
+/*[clinic input]
+module _io
+class _io.StringIO "stringio *" "&PyStringIO_Type"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c17bc0f42165cd7d]*/
+
 typedef struct {
     PyObject_HEAD
     Py_UCS4 *buf;
@@ -39,6 +45,8 @@
     PyObject *weakreflist;
 } stringio;
 
+static int _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs);
+
 #define CHECK_INITIALIZED(self) \
     if (self->ok <= 0) { \
         PyErr_SetString(PyExc_ValueError, \
@@ -58,12 +66,6 @@
         return NULL; \
     }
 
-PyDoc_STRVAR(stringio_doc,
-    "Text I/O implementation using an in-memory buffer.\n"
-    "\n"
-    "The initial_value argument sets the value of object.  The newline\n"
-    "argument is like the one of TextIOWrapper's constructor.");
-
 
 /* Internal routine for changing the size, in terms of characters, of the
    buffer of StringIO objects.  The caller should ensure that the 'size'
@@ -264,11 +266,15 @@
     return -1;
 }
 
-PyDoc_STRVAR(stringio_getvalue_doc,
-    "Retrieve the entire contents of the object.");
+/*[clinic input]
+_io.StringIO.getvalue
+
+Retrieve the entire contents of the object.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_getvalue(stringio *self)
+_io_StringIO_getvalue_impl(stringio *self)
+/*[clinic end generated code: output=27b6a7bfeaebce01 input=d23cb81d6791cf88]*/
 {
     CHECK_INITIALIZED(self);
     CHECK_CLOSED(self);
@@ -278,33 +284,40 @@
                                      self->string_size);
 }
 
-PyDoc_STRVAR(stringio_tell_doc,
-    "Tell the current file position.");
+/*[clinic input]
+_io.StringIO.tell
+
+Tell the current file position.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_tell(stringio *self)
+_io_StringIO_tell_impl(stringio *self)
+/*[clinic end generated code: output=2e87ac67b116c77b input=ec866ebaff02f405]*/
 {
     CHECK_INITIALIZED(self);
     CHECK_CLOSED(self);
     return PyLong_FromSsize_t(self->pos);
 }
 
-PyDoc_STRVAR(stringio_read_doc,
-    "Read at most n characters, returned as a string.\n"
-    "\n"
-    "If the argument is negative or omitted, read until EOF\n"
-    "is reached. Return an empty string at EOF.\n");
+/*[clinic input]
+_io.StringIO.read
+    size as arg: object = None
+    /
+
+Read at most size characters, returned as a string.
+
+If the argument is negative or omitted, read until EOF
+is reached. Return an empty string at EOF.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_read(stringio *self, PyObject *args)
+_io_StringIO_read_impl(stringio *self, PyObject *arg)
+/*[clinic end generated code: output=3676864773746f68 input=9a319015f6f3965c]*/
 {
     Py_ssize_t size, n;
     Py_UCS4 *output;
-    PyObject *arg = Py_None;
 
     CHECK_INITIALIZED(self);
-    if (!PyArg_ParseTuple(args, "|O:read", &arg))
-        return NULL;
     CHECK_CLOSED(self);
 
     if (PyNumber_Check(arg)) {
@@ -373,20 +386,23 @@
     return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, start, len);
 }
 
-PyDoc_STRVAR(stringio_readline_doc,
-    "Read until newline or EOF.\n"
-    "\n"
-    "Returns an empty string if EOF is hit immediately.\n");
+/*[clinic input]
+_io.StringIO.readline
+    size as arg: object = None
+    /
+
+Read until newline or EOF.
+
+Returns an empty string if EOF is hit immediately.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_readline(stringio *self, PyObject *args)
+_io_StringIO_readline_impl(stringio *self, PyObject *arg)
+/*[clinic end generated code: output=99fdcac03a3dee81 input=e0e0ed4042040176]*/
 {
-    PyObject *arg = Py_None;
     Py_ssize_t limit = -1;
 
     CHECK_INITIALIZED(self);
-    if (!PyArg_ParseTuple(args, "|O:readline", &arg))
-        return NULL;
     CHECK_CLOSED(self);
     ENSURE_REALIZED(self);
 
@@ -441,22 +457,25 @@
     return line;
 }
 
-PyDoc_STRVAR(stringio_truncate_doc,
-    "Truncate size to pos.\n"
-    "\n"
-    "The pos argument defaults to the current file position, as\n"
-    "returned by tell().  The current file position is unchanged.\n"
-    "Returns the new absolute position.\n");
+/*[clinic input]
+_io.StringIO.truncate
+    pos as arg: object = None
+    /
+
+Truncate size to pos.
+
+The pos argument defaults to the current file position, as
+returned by tell().  The current file position is unchanged.
+Returns the new absolute position.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_truncate(stringio *self, PyObject *args)
+_io_StringIO_truncate_impl(stringio *self, PyObject *arg)
+/*[clinic end generated code: output=6072439c2b01d306 input=748619a494ba53ad]*/
 {
     Py_ssize_t size;
-    PyObject *arg = Py_None;
 
     CHECK_INITIALIZED(self);
-    if (!PyArg_ParseTuple(args, "|O:truncate", &arg))
-        return NULL;
     CHECK_CLOSED(self);
 
     if (PyNumber_Check(arg)) {
@@ -490,49 +509,51 @@
     return PyLong_FromSsize_t(size);
 }
 
-PyDoc_STRVAR(stringio_seek_doc,
-    "Change stream position.\n"
-    "\n"
-    "Seek to character offset pos relative to position indicated by whence:\n"
-    "    0  Start of stream (the default).  pos should be >= 0;\n"
-    "    1  Current position - pos must be 0;\n"
-    "    2  End of stream - pos must be 0.\n"
-    "Returns the new absolute position.\n");
+/*[clinic input]
+_io.StringIO.seek
+    pos: Py_ssize_t
+    whence: int = 0
+    /
+
+Change stream position.
+
+Seek to character offset pos relative to position indicated by whence:
+    0  Start of stream (the default).  pos should be >= 0;
+    1  Current position - pos must be 0;
+    2  End of stream - pos must be 0.
+Returns the new absolute position.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_seek(stringio *self, PyObject *args)
+_io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence)
+/*[clinic end generated code: output=e9e0ac9a8ae71c25 input=e3855b24e7cae06a]*/
 {
-    Py_ssize_t pos;
-    int mode = 0;
-
     CHECK_INITIALIZED(self);
-    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode))
-        return NULL;
     CHECK_CLOSED(self);
 
-    if (mode != 0 && mode != 1 && mode != 2) {
+    if (whence != 0 && whence != 1 && whence != 2) {
         PyErr_Format(PyExc_ValueError,
-                     "Invalid whence (%i, should be 0, 1 or 2)", mode);
+                     "Invalid whence (%i, should be 0, 1 or 2)", whence);
         return NULL;
     }
-    else if (pos < 0 && mode == 0) {
+    else if (pos < 0 && whence == 0) {
         PyErr_Format(PyExc_ValueError,
                      "Negative seek position %zd", pos);
         return NULL;
     }
-    else if (mode != 0 && pos != 0) {
+    else if (whence != 0 && pos != 0) {
         PyErr_SetString(PyExc_IOError,
                         "Can't do nonzero cur-relative seeks");
         return NULL;
     }
 
-    /* mode 0: offset relative to beginning of the string.
-       mode 1: no change to current position.
-       mode 2: change position to end of file. */
-    if (mode == 1) {
+    /* whence = 0: offset relative to beginning of the string.
+       whence = 1: no change to current position.
+       whence = 2: change position to end of file. */
+    if (whence == 1) {
         pos = self->pos;
     }
-    else if (mode == 2) {
+    else if (whence == 2) {
         pos = self->string_size;
     }
 
@@ -541,14 +562,20 @@
     return PyLong_FromSsize_t(self->pos);
 }
 
-PyDoc_STRVAR(stringio_write_doc,
-    "Write string to file.\n"
-    "\n"
-    "Returns the number of characters written, which is always equal to\n"
-    "the length of the string.\n");
+/*[clinic input]
+_io.StringIO.write
+    s as obj: object
+    /
+
+Write string to file.
+
+Returns the number of characters written, which is always equal to
+the length of the string.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_write(stringio *self, PyObject *obj)
+_io_StringIO_write(stringio *self, PyObject *obj)
+/*[clinic end generated code: output=0deaba91a15b94da input=cf96f3b16586e669]*/
 {
     Py_ssize_t size;
 
@@ -569,14 +596,20 @@
     return PyLong_FromSsize_t(size);
 }
 
-PyDoc_STRVAR(stringio_close_doc,
-    "Close the IO object. Attempting any further operation after the\n"
-    "object is closed will raise a ValueError.\n"
-    "\n"
-    "This method has no effect if the file is already closed.\n");
+/*[clinic input]
+_io.StringIO.close
+
+Close the IO object.
+
+Attempting any further operation after the object is closed
+will raise a ValueError.
+
+This method has no effect if the file is already closed.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_close(stringio *self)
+_io_StringIO_close_impl(stringio *self)
+/*[clinic end generated code: output=04399355cbe518f1 input=cbc10b45f35d6d46]*/
 {
     self->closed = 1;
     /* Free up some memory */
@@ -644,19 +677,25 @@
     return (PyObject *)self;
 }
 
+/*[clinic input]
+_io.StringIO.__init__
+    initial_value as value: object(c_default="NULL") = ''
+    newline as newline_obj: object(c_default="NULL") = '\n'
+
+Text I/O implementation using an in-memory buffer.
+
+The initial_value argument sets the value of object.  The newline
+argument is like the one of TextIOWrapper's constructor.
+[clinic start generated code]*/
+
 static int
-stringio_init(stringio *self, PyObject *args, PyObject *kwds)
+_io_StringIO___init___impl(stringio *self, PyObject *value,
+                           PyObject *newline_obj)
+/*[clinic end generated code: output=a421ea023b22ef4e input=cee2d9181b2577a3]*/
 {
-    char *kwlist[] = {"initial_value", "newline", NULL};
-    PyObject *value = NULL;
-    PyObject *newline_obj = NULL;
     char *newline = "\n";
     Py_ssize_t value_len;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:__init__", kwlist,
-                                     &value, &newline_obj))
-        return -1;
-
     /* Parse the newline argument. This used to be done with the 'z'
        specifier, however this allowed any object with the buffer interface to
        be converted. Thus we have to parse it manually since we only want to
@@ -761,33 +800,45 @@
 
 /* Properties and pseudo-properties */
 
-PyDoc_STRVAR(stringio_readable_doc,
-"readable() -> bool. Returns True if the IO object can be read.");
+/*[clinic input]
+_io.StringIO.readable
 
-PyDoc_STRVAR(stringio_writable_doc,
-"writable() -> bool. Returns True if the IO object can be written.");
-
-PyDoc_STRVAR(stringio_seekable_doc,
-"seekable() -> bool. Returns True if the IO object can be seeked.");
+Returns True if the IO object can be read.
+[clinic start generated code]*/
 
 static PyObject *
-stringio_seekable(stringio *self, PyObject *args)
+_io_StringIO_readable_impl(stringio *self)
+/*[clinic end generated code: output=b19d44dd8b1ceb99 input=39ce068b224c21ad]*/
 {
     CHECK_INITIALIZED(self);
     CHECK_CLOSED(self);
     Py_RETURN_TRUE;
 }
 
+/*[clinic input]
+_io.StringIO.writable
+
+Returns True if the IO object can be written.
+[clinic start generated code]*/
+
 static PyObject *
-stringio_readable(stringio *self, PyObject *args)
+_io_StringIO_writable_impl(stringio *self)
+/*[clinic end generated code: output=13e4dd77187074ca input=7a691353aac38835]*/
 {
     CHECK_INITIALIZED(self);
     CHECK_CLOSED(self);
     Py_RETURN_TRUE;
 }
 
+/*[clinic input]
+_io.StringIO.seekable
+
+Returns True if the IO object can be seeked.
+[clinic start generated code]*/
+
 static PyObject *
-stringio_writable(stringio *self, PyObject *args)
+_io_StringIO_seekable_impl(stringio *self)
+/*[clinic end generated code: output=4d20b4641c756879 input=4c606d05b32952e6]*/
 {
     CHECK_INITIALIZED(self);
     CHECK_CLOSED(self);
@@ -809,7 +860,7 @@
 static PyObject *
 stringio_getstate(stringio *self)
 {
-    PyObject *initvalue = stringio_getvalue(self);
+    PyObject *initvalue = _io_StringIO_getvalue_impl(self);
     PyObject *dict;
     PyObject *state;
 
@@ -857,7 +908,7 @@
     initarg = PyTuple_GetSlice(state, 0, 2);
     if (initarg == NULL)
         return NULL;
-    if (stringio_init(self, initarg, NULL) < 0) {
+    if (_io_StringIO___init__((PyObject *)self, initarg, NULL) < 0) {
         Py_DECREF(initarg);
         return NULL;
     }
@@ -959,19 +1010,21 @@
     return PyObject_GetAttr(self->decoder, _PyIO_str_newlines);
 }
 
+#include "clinic/stringio.c.h"
+
 static struct PyMethodDef stringio_methods[] = {
-    {"close",    (PyCFunction)stringio_close,    METH_NOARGS,  stringio_close_doc},
-    {"getvalue", (PyCFunction)stringio_getvalue, METH_NOARGS,  stringio_getvalue_doc},
-    {"read",     (PyCFunction)stringio_read,     METH_VARARGS, stringio_read_doc},
-    {"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc},
-    {"tell",     (PyCFunction)stringio_tell,     METH_NOARGS,  stringio_tell_doc},
-    {"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc},
-    {"seek",     (PyCFunction)stringio_seek,     METH_VARARGS, stringio_seek_doc},
-    {"write",    (PyCFunction)stringio_write,    METH_O,       stringio_write_doc},
+    _IO_STRINGIO_CLOSE_METHODDEF
+    _IO_STRINGIO_GETVALUE_METHODDEF
+    _IO_STRINGIO_READ_METHODDEF
+    _IO_STRINGIO_READLINE_METHODDEF
+    _IO_STRINGIO_TELL_METHODDEF
+    _IO_STRINGIO_TRUNCATE_METHODDEF
+    _IO_STRINGIO_SEEK_METHODDEF
+    _IO_STRINGIO_WRITE_METHODDEF
 
-    {"seekable", (PyCFunction)stringio_seekable, METH_NOARGS, stringio_seekable_doc},
-    {"readable", (PyCFunction)stringio_readable, METH_NOARGS, stringio_readable_doc},
-    {"writable", (PyCFunction)stringio_writable, METH_NOARGS, stringio_writable_doc},
+    _IO_STRINGIO_SEEKABLE_METHODDEF
+    _IO_STRINGIO_READABLE_METHODDEF
+    _IO_STRINGIO_WRITABLE_METHODDEF
 
     {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS},
     {"__setstate__", (PyCFunction)stringio_setstate, METH_O},
@@ -1013,7 +1066,7 @@
     0,                                         /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
                        | Py_TPFLAGS_HAVE_GC,   /*tp_flags*/
-    stringio_doc,                              /*tp_doc*/
+    _io_StringIO___init____doc__,              /*tp_doc*/
     (traverseproc)stringio_traverse,           /*tp_traverse*/
     (inquiry)stringio_clear,                   /*tp_clear*/
     0,                                         /*tp_richcompare*/
@@ -1028,7 +1081,7 @@
     0,                                         /*tp_descr_get*/
     0,                                         /*tp_descr_set*/
     offsetof(stringio, dict),                  /*tp_dictoffset*/
-    (initproc)stringio_init,                   /*tp_init*/
+    _io_StringIO___init__,                     /*tp_init*/
     0,                                         /*tp_alloc*/
     stringio_new,                              /*tp_new*/
 };
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -11,6 +11,20 @@
 #include "structmember.h"
 #include "_iomodule.h"
 
+/*[clinic input]
+module _io
+class _io.IncrementalNewlineDecoder "nldecoder_object *" "&PyIncrementalNewlineDecoder_Type"
+class _io.TextIOWrapper "textio *" "&TextIOWrapper_TYpe"
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2097a4fc85670c26]*/
+
+/*[python input]
+class io_ssize_t_converter(CConverter):
+    type = 'Py_ssize_t'
+    converter = '_PyIO_ConvertSsize_t'
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/
+
 _Py_IDENTIFIER(close);
 _Py_IDENTIFIER(_dealloc_warn);
 _Py_IDENTIFIER(decode);
@@ -210,16 +224,6 @@
 
 /* IncrementalNewlineDecoder */
 
-PyDoc_STRVAR(incrementalnewlinedecoder_doc,
-    "Codec used when reading a file in universal newlines mode.  It wraps\n"
-    "another incremental decoder, translating \\r\\n and \\r into \\n.  It also\n"
-    "records the types of newlines encountered.  When used with\n"
-    "translate=False, it ensures that the newline sequence is returned in\n"
-    "one piece. When used with decoder=None, it expects unicode strings as\n"
-    "decode input and translates newlines without first invoking an external\n"
-    "decoder.\n"
-    );
-
 typedef struct {
     PyObject_HEAD
     PyObject *decoder;
@@ -229,19 +233,28 @@
     unsigned int seennl: 3;
 } nldecoder_object;
 
+/*[clinic input]
+_io.IncrementalNewlineDecoder.__init__
+    decoder: object
+    translate: int
+    errors: object(c_default="NULL") = "strict"
+
+Codec used when reading a file in universal newlines mode.
+
+It wraps another incremental decoder, translating \r\n and \r into \n.
+It also records the types of newlines encountered.  When used with
+translate=False, it ensures that the newline sequence is returned in
+one piece. When used with decoder=None, it expects unicode strings as
+decode input and translates newlines without first invoking an external
+decoder.
+[clinic start generated code]*/
+
 static int
-incrementalnewlinedecoder_init(nldecoder_object *self,
-                               PyObject *args, PyObject *kwds)
+_io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self,
+                                            PyObject *decoder, int translate,
+                                            PyObject *errors)
+/*[clinic end generated code: output=fbd04d443e764ec2 input=89db6b19c6b126bf]*/
 {
-    PyObject *decoder;
-    int translate;
-    PyObject *errors = NULL;
-    char *kwlist[] = {"decoder", "translate", "errors", NULL};
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi|O:IncrementalNewlineDecoder",
-                                     kwlist, &decoder, &translate, &errors))
-        return -1;
-
     self->decoder = decoder;
     Py_INCREF(decoder);
 
@@ -495,22 +508,27 @@
     return NULL;
 }
 
+/*[clinic input]
+_io.IncrementalNewlineDecoder.decode
+    input: object
+    final: int(c_default="0") = False
+[clinic start generated code]*/
+
 static PyObject *
-incrementalnewlinedecoder_decode(nldecoder_object *self,
-                                 PyObject *args, PyObject *kwds)
+_io_IncrementalNewlineDecoder_decode_impl(nldecoder_object *self,
+                                          PyObject *input, int final)
+/*[clinic end generated code: output=0d486755bb37a66e input=d65677385bfd6827]*/
 {
-    char *kwlist[] = {"input", "final", NULL};
-    PyObject *input;
-    int final = 0;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:IncrementalNewlineDecoder",
-                                     kwlist, &input, &final))
-        return NULL;
     return _PyIncrementalNewlineDecoder_decode((PyObject *) self, input, final);
 }
 
+/*[clinic input]
+_io.IncrementalNewlineDecoder.getstate
+[clinic start generated code]*/
+
 static PyObject *
-incrementalnewlinedecoder_getstate(nldecoder_object *self, PyObject *args)
+_io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self)
+/*[clinic end generated code: output=f0d2c9c136f4e0d0 input=f8ff101825e32e7f]*/
 {
     PyObject *buffer;
     unsigned PY_LONG_LONG flag;
@@ -537,8 +555,16 @@
     return Py_BuildValue("NK", buffer, flag);
 }
 
+/*[clinic input]
+_io.IncrementalNewlineDecoder.setstate
+    state: object
+    /
+[clinic start generated code]*/
+
 static PyObject *
-incrementalnewlinedecoder_setstate(nldecoder_object *self, PyObject *state)
+_io_IncrementalNewlineDecoder_setstate(nldecoder_object *self,
+                                       PyObject *state)
+/*[clinic end generated code: output=c10c622508b576cb input=c53fb505a76dbbe2]*/
 {
     PyObject *buffer;
     unsigned PY_LONG_LONG flag;
@@ -556,8 +582,13 @@
         Py_RETURN_NONE;
 }
 
+/*[clinic input]
+_io.IncrementalNewlineDecoder.reset
+[clinic start generated code]*/
+
 static PyObject *
-incrementalnewlinedecoder_reset(nldecoder_object *self, PyObject *args)
+_io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self)
+/*[clinic end generated code: output=32fa40c7462aa8ff input=728678ddaea776df]*/
 {
     self->seennl = 0;
     self->pendingcr = 0;
@@ -591,95 +622,8 @@
 
 }
 
-
-static PyMethodDef incrementalnewlinedecoder_methods[] = {
-    {"decode", (PyCFunction)incrementalnewlinedecoder_decode, METH_VARARGS|METH_KEYWORDS},
-    {"getstate", (PyCFunction)incrementalnewlinedecoder_getstate, METH_NOARGS},
-    {"setstate", (PyCFunction)incrementalnewlinedecoder_setstate, METH_O},
-    {"reset", (PyCFunction)incrementalnewlinedecoder_reset, METH_NOARGS},
-    {NULL}
-};
-
-static PyGetSetDef incrementalnewlinedecoder_getset[] = {
-    {"newlines", (getter)incrementalnewlinedecoder_newlines_get, NULL, NULL},
-    {NULL}
-};
-
-PyTypeObject PyIncrementalNewlineDecoder_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "_io.IncrementalNewlineDecoder", /*tp_name*/
-    sizeof(nldecoder_object), /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)incrementalnewlinedecoder_dealloc, /*tp_dealloc*/
-    0,                          /*tp_print*/
-    0,                          /*tp_getattr*/
-    0,                          /*tp_setattr*/
-    0,                          /*tp_compare */
-    0,                          /*tp_repr*/
-    0,                          /*tp_as_number*/
-    0,                          /*tp_as_sequence*/
-    0,                          /*tp_as_mapping*/
-    0,                          /*tp_hash */
-    0,                          /*tp_call*/
-    0,                          /*tp_str*/
-    0,                          /*tp_getattro*/
-    0,                          /*tp_setattro*/
-    0,                          /*tp_as_buffer*/
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
-    incrementalnewlinedecoder_doc,          /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    incrementalnewlinedecoder_methods, /* tp_methods */
-    0,                          /* tp_members */
-    incrementalnewlinedecoder_getset, /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    0,                          /* tp_dictoffset */
-    (initproc)incrementalnewlinedecoder_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-};
-
-
 /* TextIOWrapper */
 
-PyDoc_STRVAR(textiowrapper_doc,
-    "Character and line based layer over a BufferedIOBase object, buffer.\n"
-    "\n"
-    "encoding gives the name of the encoding that the stream will be\n"
-    "decoded or encoded with. It defaults to locale.getpreferredencoding(False).\n"
-    "\n"
-    "errors determines the strictness of encoding and decoding (see\n"
-    "help(codecs.Codec) or the documentation for codecs.register) and\n"
-    "defaults to \"strict\".\n"
-    "\n"
-    "newline controls how line endings are handled. It can be None, '',\n"
-    "'\\n', '\\r', and '\\r\\n'.  It works as follows:\n"
-    "\n"
-    "* On input, if newline is None, universal newlines mode is\n"
-    "  enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n"
-    "  these are translated into '\\n' before being returned to the\n"
-    "  caller. If it is '', universal newline mode is enabled, but line\n"
-    "  endings are returned to the caller untranslated. If it has any of\n"
-    "  the other legal values, input lines are only terminated by the given\n"
-    "  string, and the line ending is returned to the caller untranslated.\n"
-    "\n"
-    "* On output, if newline is None, any '\\n' characters written are\n"
-    "  translated to the system default line separator, os.linesep. If\n"
-    "  newline is '' or '\\n', no translation takes place. If newline is any\n"
-    "  of the other legal values, any '\\n' characters written are translated\n"
-    "  to the given string.\n"
-    "\n"
-    "If line_buffering is True, a call to flush is implied when a call to\n"
-    "write contains a newline character."
-    );
-
 typedef PyObject *
         (*encodefunc_t)(PyObject *, PyObject *);
 
@@ -742,7 +686,6 @@
     PyObject *dict;
 } textio;
 
-
 /* A couple of specialized cases in order to bypass the slow incremental
    encoding methods for the most popular encodings. */
 
@@ -843,28 +786,59 @@
 };
 
 
+/*[clinic input]
+_io.TextIOWrapper.__init__
+    buffer: object
+    encoding: str(nullable=True) = NULL
+    errors: str(nullable=True) = NULL
+    newline: str(nullable=True) = NULL
+    line_buffering: int(c_default="0") = False
+    write_through: int(c_default="0") = False
+
+Character and line based layer over a BufferedIOBase object, buffer.
+
+encoding gives the name of the encoding that the stream will be
+decoded or encoded with. It defaults to locale.getpreferredencoding(False).
+
+errors determines the strictness of encoding and decoding (see
+help(codecs.Codec) or the documentation for codecs.register) and
+defaults to "strict".
+
+newline controls how line endings are handled. It can be None, '',
+'\n', '\r', and '\r\n'.  It works as follows:
+
+* On input, if newline is None, universal newlines mode is
+  enabled. Lines in the input can end in '\n', '\r', or '\r\n', and
+  these are translated into '\n' before being returned to the
+  caller. If it is '', universal newline mode is enabled, but line
+  endings are returned to the caller untranslated. If it has any of
+  the other legal values, input lines are only terminated by the given
+  string, and the line ending is returned to the caller untranslated.
+
+* On output, if newline is None, any '\n' characters written are
+  translated to the system default line separator, os.linesep. If
+  newline is '' or '\n', no translation takes place. If newline is any
+  of the other legal values, any '\n' characters written are translated
+  to the given string.
+
+If line_buffering is True, a call to flush is implied when a call to
+write contains a newline character.
+[clinic start generated code]*/
+
 static int
-textiowrapper_init(textio *self, PyObject *args, PyObject *kwds)
+_io_TextIOWrapper___init___impl(textio *self, PyObject *buffer,
+                                const char *encoding, const char *errors,
+                                const char *newline, int line_buffering,
+                                int write_through)
+/*[clinic end generated code: output=56a83402ce2a8381 input=1f20decb8d54a4ec]*/
 {
-    char *kwlist[] = {"buffer", "encoding", "errors",
-                      "newline", "line_buffering", "write_through",
-                      NULL};
-    PyObject *buffer, *raw, *codec_info = NULL;
-    char *encoding = NULL;
-    char *errors = NULL;
-    char *newline = NULL;
-    int line_buffering = 0, write_through = 0;
+    PyObject *raw, *codec_info = NULL;
     _PyIO_State *state = NULL;
-
     PyObject *res;
     int r;
 
     self->ok = 0;
     self->detached = 0;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|zzzii:fileio",
-                                     kwlist, &buffer, &encoding, &errors,
-                                     &newline, &line_buffering, &write_through))
-        return -1;
 
     if (newline && newline[0] != '\0'
         && !(newline[0] == '\n' && newline[1] == '\0')
@@ -1244,8 +1218,13 @@
     }
 
 
+/*[clinic input]
+_io.TextIOWrapper.detach
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_detach(textio *self)
+_io_TextIOWrapper_detach_impl(textio *self)
+/*[clinic end generated code: output=7ba3715cd032d5f2 input=e5a71fbda9e1d9f9]*/
 {
     PyObject *buffer, *res;
     CHECK_ATTACHED(self);
@@ -1290,25 +1269,26 @@
     return 0;
 }
 
+/*[clinic input]
+_io.TextIOWrapper.write
+    text: unicode
+    /
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_write(textio *self, PyObject *args)
+_io_TextIOWrapper_write_impl(textio *self, PyObject *text)
+/*[clinic end generated code: output=d2deb0d50771fcec input=fdf19153584a0e44]*/
 {
     PyObject *ret;
-    PyObject *text; /* owned reference */
     PyObject *b;
     Py_ssize_t textlen;
     int haslf = 0;
     int needflush = 0, text_needflush = 0;
 
-    CHECK_ATTACHED(self);
-
-    if (!PyArg_ParseTuple(args, "U:write", &text)) {
-        return NULL;
-    }
-
     if (PyUnicode_READY(text) == -1)
         return NULL;
 
+    CHECK_ATTACHED(self);
     CHECK_CLOSED(self);
 
     if (self->encoder == NULL)
@@ -1557,17 +1537,19 @@
     return -1;
 }
 
+/*[clinic input]
+_io.TextIOWrapper.read
+    size as n: io_ssize_t = -1
+    /
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_read(textio *self, PyObject *args)
+_io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n)
+/*[clinic end generated code: output=7e651ce6cc6a25a6 input=8c09398424085cca]*/
 {
-    Py_ssize_t n = -1;
     PyObject *result = NULL, *chunks = NULL;
 
     CHECK_ATTACHED(self);
-
-    if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n))
-        return NULL;
-
     CHECK_CLOSED(self);
 
     if (self->decoder == NULL)
@@ -1933,16 +1915,18 @@
     return NULL;
 }
 
+/*[clinic input]
+_io.TextIOWrapper.readline
+    size: Py_ssize_t = -1
+    /
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_readline(textio *self, PyObject *args)
+_io_TextIOWrapper_readline_impl(textio *self, Py_ssize_t size)
+/*[clinic end generated code: output=344afa98804e8b25 input=56c7172483b36db6]*/
 {
-    Py_ssize_t limit = -1;
-
     CHECK_ATTACHED(self);
-    if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
-        return NULL;
-    }
-    return _textiowrapper_readline(self, limit);
+    return _textiowrapper_readline(self, size);
 }
 
 /* Seek and Tell */
@@ -2074,19 +2058,23 @@
         self, cookie->start_pos == 0 && cookie->dec_flags == 0);
 }
 
+/*[clinic input]
+_io.TextIOWrapper.seek
+    cookie as cookieObj: object
+    whence: int = 0
+    /
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_seek(textio *self, PyObject *args)
+_io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
+/*[clinic end generated code: output=0a15679764e2d04d input=0458abeb3d7842be]*/
 {
-    PyObject *cookieObj, *posobj;
+    PyObject *posobj;
     cookie_type cookie;
-    int whence = 0;
     PyObject *res;
     int cmp;
 
     CHECK_ATTACHED(self);
-
-    if (!PyArg_ParseTuple(args, "O|i:seek", &cookieObj, &whence))
-        return NULL;
     CHECK_CLOSED(self);
 
     Py_INCREF(cookieObj);
@@ -2258,8 +2246,13 @@
 
 }
 
+/*[clinic input]
+_io.TextIOWrapper.tell
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_tell(textio *self, PyObject *args)
+_io_TextIOWrapper_tell_impl(textio *self)
+/*[clinic end generated code: output=4f168c08bf34ad5f input=9a2caf88c24f9ddf]*/
 {
     PyObject *res;
     PyObject *posobj = NULL;
@@ -2466,16 +2459,19 @@
     return NULL;
 }
 
+/*[clinic input]
+_io.TextIOWrapper.truncate
+    pos: object = None
+    /
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_truncate(textio *self, PyObject *args)
+_io_TextIOWrapper_truncate_impl(textio *self, PyObject *pos)
+/*[clinic end generated code: output=90ec2afb9bb7745f input=56ec8baa65aea377]*/
 {
-    PyObject *pos = Py_None;
     PyObject *res;
 
     CHECK_ATTACHED(self)
-    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
-        return NULL;
-    }
 
     res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_flush, NULL);
     if (res == NULL)
@@ -2540,36 +2536,61 @@
 
 /* Inquiries */
 
+/*[clinic input]
+_io.TextIOWrapper.fileno
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_fileno(textio *self, PyObject *args)
+_io_TextIOWrapper_fileno_impl(textio *self)
+/*[clinic end generated code: output=21490a4c3da13e6c input=c488ca83d0069f9b]*/
 {
     CHECK_ATTACHED(self);
     return _PyObject_CallMethodId(self->buffer, &PyId_fileno, NULL);
 }
 
+/*[clinic input]
+_io.TextIOWrapper.seekable
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_seekable(textio *self, PyObject *args)
+_io_TextIOWrapper_seekable_impl(textio *self)
+/*[clinic end generated code: output=ab223dbbcffc0f00 input=8b005ca06e1fca13]*/
 {
     CHECK_ATTACHED(self);
     return _PyObject_CallMethodId(self->buffer, &PyId_seekable, NULL);
 }
 
+/*[clinic input]
+_io.TextIOWrapper.readable
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_readable(textio *self, PyObject *args)
+_io_TextIOWrapper_readable_impl(textio *self)
+/*[clinic end generated code: output=72ff7ba289a8a91b input=0704ea7e01b0d3eb]*/
 {
     CHECK_ATTACHED(self);
     return _PyObject_CallMethodId(self->buffer, &PyId_readable, NULL);
 }
 
+/*[clinic input]
+_io.TextIOWrapper.writable
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_writable(textio *self, PyObject *args)
+_io_TextIOWrapper_writable_impl(textio *self)
+/*[clinic end generated code: output=a728c71790d03200 input=c41740bc9d8636e8]*/
 {
     CHECK_ATTACHED(self);
     return _PyObject_CallMethodId(self->buffer, &PyId_writable, NULL);
 }
 
+/*[clinic input]
+_io.TextIOWrapper.isatty
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_isatty(textio *self, PyObject *args)
+_io_TextIOWrapper_isatty_impl(textio *self)
+/*[clinic end generated code: output=12be1a35bace882e input=fb68d9f2c99bbfff]*/
 {
     CHECK_ATTACHED(self);
     return _PyObject_CallMethodId(self->buffer, &PyId_isatty, NULL);
@@ -2583,8 +2604,13 @@
     return NULL;
 }
 
+/*[clinic input]
+_io.TextIOWrapper.flush
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_flush(textio *self, PyObject *args)
+_io_TextIOWrapper_flush_impl(textio *self)
+/*[clinic end generated code: output=59de9165f9c2e4d2 input=928c60590694ab85]*/
 {
     CHECK_ATTACHED(self);
     CHECK_CLOSED(self);
@@ -2594,8 +2620,13 @@
     return _PyObject_CallMethodId(self->buffer, &PyId_flush, NULL);
 }
 
+/*[clinic input]
+_io.TextIOWrapper.close
+[clinic start generated code]*/
+
 static PyObject *
-textiowrapper_close(textio *self, PyObject *args)
+_io_TextIOWrapper_close_impl(textio *self)
+/*[clinic end generated code: output=056ccf8b4876e4f4 input=9c2114315eae1948]*/
 {
     PyObject *res;
     int r;
@@ -2739,24 +2770,81 @@
     return 0;
 }
 
+#include "clinic/textio.c.h"
+
+static PyMethodDef incrementalnewlinedecoder_methods[] = {
+    _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF
+    _IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF
+    _IO_INCREMENTALNEWLINEDECODER_SETSTATE_METHODDEF
+    _IO_INCREMENTALNEWLINEDECODER_RESET_METHODDEF
+    {NULL}
+};
+
+static PyGetSetDef incrementalnewlinedecoder_getset[] = {
+    {"newlines", (getter)incrementalnewlinedecoder_newlines_get, NULL, NULL},
+    {NULL}
+};
+
+PyTypeObject PyIncrementalNewlineDecoder_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_io.IncrementalNewlineDecoder", /*tp_name*/
+    sizeof(nldecoder_object), /*tp_basicsize*/
+    0,                          /*tp_itemsize*/
+    (destructor)incrementalnewlinedecoder_dealloc, /*tp_dealloc*/
+    0,                          /*tp_print*/
+    0,                          /*tp_getattr*/
+    0,                          /*tp_setattr*/
+    0,                          /*tp_compare */
+    0,                          /*tp_repr*/
+    0,                          /*tp_as_number*/
+    0,                          /*tp_as_sequence*/
+    0,                          /*tp_as_mapping*/
+    0,                          /*tp_hash */
+    0,                          /*tp_call*/
+    0,                          /*tp_str*/
+    0,                          /*tp_getattro*/
+    0,                          /*tp_setattro*/
+    0,                          /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
+    _io_IncrementalNewlineDecoder___init____doc__, /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    0,                          /*tp_weaklistoffset*/
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    incrementalnewlinedecoder_methods, /* tp_methods */
+    0,                          /* tp_members */
+    incrementalnewlinedecoder_getset, /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    0,                          /* tp_dictoffset */
+    _io_IncrementalNewlineDecoder___init__, /* tp_init */
+    0,                          /* tp_alloc */
+    PyType_GenericNew,          /* tp_new */
+};
+
+
 static PyMethodDef textiowrapper_methods[] = {
-    {"detach", (PyCFunction)textiowrapper_detach, METH_NOARGS},
-    {"write", (PyCFunction)textiowrapper_write, METH_VARARGS},
-    {"read", (PyCFunction)textiowrapper_read, METH_VARARGS},
-    {"readline", (PyCFunction)textiowrapper_readline, METH_VARARGS},
-    {"flush", (PyCFunction)textiowrapper_flush, METH_NOARGS},
-    {"close", (PyCFunction)textiowrapper_close, METH_NOARGS},
+    _IO_TEXTIOWRAPPER_DETACH_METHODDEF
+    _IO_TEXTIOWRAPPER_WRITE_METHODDEF
+    _IO_TEXTIOWRAPPER_READ_METHODDEF
+    _IO_TEXTIOWRAPPER_READLINE_METHODDEF
+    _IO_TEXTIOWRAPPER_FLUSH_METHODDEF
+    _IO_TEXTIOWRAPPER_CLOSE_METHODDEF
 
-    {"fileno", (PyCFunction)textiowrapper_fileno, METH_NOARGS},
-    {"seekable", (PyCFunction)textiowrapper_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)textiowrapper_readable, METH_NOARGS},
-    {"writable", (PyCFunction)textiowrapper_writable, METH_NOARGS},
-    {"isatty", (PyCFunction)textiowrapper_isatty, METH_NOARGS},
+    _IO_TEXTIOWRAPPER_FILENO_METHODDEF
+    _IO_TEXTIOWRAPPER_SEEKABLE_METHODDEF
+    _IO_TEXTIOWRAPPER_READABLE_METHODDEF
+    _IO_TEXTIOWRAPPER_WRITABLE_METHODDEF
+    _IO_TEXTIOWRAPPER_ISATTY_METHODDEF
     {"__getstate__", (PyCFunction)textiowrapper_getstate, METH_NOARGS},
 
-    {"seek", (PyCFunction)textiowrapper_seek, METH_VARARGS},
-    {"tell", (PyCFunction)textiowrapper_tell, METH_NOARGS},
-    {"truncate", (PyCFunction)textiowrapper_truncate, METH_VARARGS},
+    _IO_TEXTIOWRAPPER_SEEK_METHODDEF
+    _IO_TEXTIOWRAPPER_TELL_METHODDEF
+    _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF
     {NULL, NULL}
 };
 
@@ -2802,7 +2890,7 @@
     0,                          /*tp_as_buffer*/
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
         | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/
-    textiowrapper_doc,          /* tp_doc */
+    _io_TextIOWrapper___init____doc__, /* tp_doc */
     (traverseproc)textiowrapper_traverse, /* tp_traverse */
     (inquiry)textiowrapper_clear, /* tp_clear */
     0,                          /* tp_richcompare */
@@ -2817,7 +2905,7 @@
     0,                          /* tp_descr_get */
     0,                          /* tp_descr_set */
     offsetof(textio, dict), /*tp_dictoffset*/
-    (initproc)textiowrapper_init, /* tp_init */
+    _io_TextIOWrapper___init__, /* tp_init */
     0,                          /* tp_alloc */
     PyType_GenericNew,          /* tp_new */
     0,                          /* tp_free */

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list