[Python-checkins] r67130 - in sandbox/trunk/io-c: build.py io.c

amaury.forgeotdarc python-checkins at python.org
Thu Nov 6 23:33:03 CET 2008


Author: amaury.forgeotdarc
Date: Thu Nov  6 23:33:02 2008
New Revision: 67130

Log:
Set svn:eol-style = native


Modified:
   sandbox/trunk/io-c/build.py   (contents, props changed)
   sandbox/trunk/io-c/io.c   (contents, props changed)

Modified: sandbox/trunk/io-c/build.py
==============================================================================
--- sandbox/trunk/io-c/build.py	(original)
+++ sandbox/trunk/io-c/build.py	Thu Nov  6 23:33:02 2008
@@ -1,40 +1,40 @@
-import os, sys
-from distutils.core import Extension, Distribution
-from distutils.command.build_ext import build_ext
-
-def compile():
-    sources = ['io.c', '_fileio.c', '_bytesio.c']
-    sources = [os.path.join(os.path.dirname(__file__), s) for s in sources]
-    io_ext = Extension('_io', sources)
-    dist = Distribution({'name': '_io', 'ext_modules': [io_ext]})
-    cmd = build_ext(dist)
-    cmd.build_lib = os.path.dirname(__file__)
-    if os.name == "nt":
-        # On Windows, we must build a debug version iff running
-        # a debug build of Python
-        cmd.debug = sys.executable.endswith("_d.exe")
-
-    cmd.ensure_finalized()
-    cmd.run()
-
-def test():
-    import subprocess
-    env = os.environ.copy()
-    env['PYTHONPATH'] = os.path.abspath(os.path.dirname(__file__))
-
-    print("try importing module")
-    p = subprocess.Popen([sys.executable, "-c",
-                          "import io; print(io)"],
-                         env=env)
-    p.wait()
-
-    print("run the test suite")
-    p = subprocess.Popen([sys.executable, "-c",
-                          "from test.test_io import test_main; test_main()"],
-                         env=env)
-    p.wait()
-
-
-if __name__ == "__main__":
-    compile()
-    test()
+import os, sys
+from distutils.core import Extension, Distribution
+from distutils.command.build_ext import build_ext
+
+def compile():
+    sources = ['io.c', '_fileio.c', '_bytesio.c']
+    sources = [os.path.join(os.path.dirname(__file__), s) for s in sources]
+    io_ext = Extension('_io', sources)
+    dist = Distribution({'name': '_io', 'ext_modules': [io_ext]})
+    cmd = build_ext(dist)
+    cmd.build_lib = os.path.dirname(__file__)
+    if os.name == "nt":
+        # On Windows, we must build a debug version iff running
+        # a debug build of Python
+        cmd.debug = sys.executable.endswith("_d.exe")
+
+    cmd.ensure_finalized()
+    cmd.run()
+
+def test():
+    import subprocess
+    env = os.environ.copy()
+    env['PYTHONPATH'] = os.path.abspath(os.path.dirname(__file__))
+
+    print("try importing module")
+    p = subprocess.Popen([sys.executable, "-c",
+                          "import io; print(io)"],
+                         env=env)
+    p.wait()
+
+    print("run the test suite")
+    p = subprocess.Popen([sys.executable, "-c",
+                          "from test.test_io import test_main; test_main()"],
+                         env=env)
+    p.wait()
+
+
+if __name__ == "__main__":
+    compile()
+    test()

Modified: sandbox/trunk/io-c/io.c
==============================================================================
--- sandbox/trunk/io-c/io.c	(original)
+++ sandbox/trunk/io-c/io.c	Thu Nov  6 23:33:02 2008
@@ -1,3033 +1,3033 @@
-#include <python.h>
-#include "structmember.h"
-#include "pythread.h"
-
-extern PyTypeObject PyFileIO_Type;
-extern PyTypeObject PyBytesIO_Type;
-
-static PyObject *io_py_module;
-
-/* open() uses st_blksize whenever we can */
-#define DEFAULT_BUFFER_SIZE (8 * 1024)  /* bytes */
-
-
-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"
-"seperation between reading and writing to streams; implementations are\n"
-"allowed to throw 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 subc lasses 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"
-    );
-
-
-/*
- * BlockingIOError extends IOError
- */
-
-typedef struct {
-    PyException_HEAD
-    PyObject *myerrno;
-    PyObject *strerror;
-    PyObject *filename; /* Not used, but part of the IOError object */
-    Py_ssize_t written;
-} PyBlockingIOErrorObject;
-
-
-static int
-BlockingIOError_init(PyBlockingIOErrorObject *self, PyObject *args,
-                     PyObject *kwds)
-{
-    PyObject *myerrno = NULL, *strerror = NULL, *written;
-    PyObject *baseargs = NULL;
-
-    assert(PyTuple_Check(args));
-
-    if (PyTuple_GET_SIZE(args) <= 1 || PyTuple_GET_SIZE(args) > 3)
-        return 0;
-
-    baseargs = PyTuple_GetSlice(args, 0, 2);
-    if (baseargs == NULL)
-        return -1;
-
-    if (((PyTypeObject*)PyExc_IOError)->tp_init(
-                (PyObject*)self, baseargs, kwds) == -1) {
-        Py_DECREF(baseargs);
-        return -1;
-    }
-
-    Py_DECREF(baseargs);
-
-    if (!PyArg_UnpackTuple(args, "BlockingIOError", 2, 3,
-                           &myerrno, &strerror, &written)) {
-        return -1;
-    }
-
-    Py_INCREF(myerrno);
-    self->myerrno = myerrno;
-
-    Py_INCREF(strerror);
-    self->strerror = strerror;
-
-    self->written = PyNumber_AsSsize_t(written, PyExc_ValueError);
-    if(self->written == -1 && PyErr_Occurred())
-        return -1;
-
-    return 0;
-}
-
-static PyMemberDef BlockingIOError_members[] = {
-    {"characters_written", T_PYSSIZET, offsetof(PyBlockingIOErrorObject, written), 0},
-    {NULL}  /* Sentinel */
-};
-
-
-static PyTypeObject _PyExc_BlockingIOError = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "BlockingIOError", /*tp_name*/
-    sizeof(PyBlockingIOErrorObject), /*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_GC,  /*tp_flags*/
-    PyDoc_STR("Exception raised when I/O would block on a non-blocking I/O stream"), /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    0,                          /* tp_methods */
-    BlockingIOError_members,    /* tp_members */
-    0,                          /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    0,                          /* tp_dictoffset */
-    (initproc)BlockingIOError_init, /* tp_init */
-    0,                          /* tp_alloc */
-    0,                          /* tp_new */
-};
-PyObject *PyExc_BlockingIOError = (PyObject *)&_PyExc_BlockingIOError;
-
-
-/*
- * The main open() function
- */
-PyDoc_STRVAR(open_doc,
-"Open file and return a stream. If the file cannot be opened, an IOError is\n"
-"raised.\n"
-"\n"
-"file is either a string giving the name (and the path if the file\n"
-"isn't in the current working directory) of the file to be opened or an\n"
-"integer file descriptor of the file to be wrapped. (If a file\n"
-"descriptor is given, it is closed when the returned I/O object is\n"
-"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), and 'a' for appending (which on some Unix systems,\n"
-"means that all writes append to the end of the file regardless of the\n"
-"current seek position). In text mode, if encoding is not specified the\n"
-"encoding used is platform dependent. (For reading and writing raw\n"
-"bytes use binary mode and leave encoding unspecified.) The available\n"
-"modes are:\n"
-"\n"
-"========= ===============================================================\n"
-"Character Meaning\n"
-"--------- ---------------------------------------------------------------\n"
-"'r'       open for reading (default)\n"
-"'w'       open for writing, truncating the file first\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 (for backwards compatibility; unneeded\n"
-"          for new code)\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.\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"
-"buffering is an optional integer used to set the buffering policy. By\n"
-"default full buffering is on. Pass 0 to switch buffering off (only\n"
-"allowed in binary mode), 1 to set line buffering, and an integer > 1\n"
-"for full buffering.\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 for a list of the permitted\n"
-"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 '', no translation takes place. If newline is any of the\n"
-"  other legal values, any '\\n' characters written are translated to\n"
-"  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"
-"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"
-    );
-
-static PyObject *
-io_open(PyObject* self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"file", "mode", "buffering",
-                      "encoding", "errors", "newline",
-                      "closefd", NULL};
-    PyObject *file;
-    char *mode = "r";
-    int buffering = -1, closefd = 1;
-    char *encoding = NULL, *errors = NULL, *newline = NULL;
-    unsigned i;
-
-    int reading = 0, writing = 0, appending = 0, updating = 0;
-    int text = 0, binary = 0, universal = 0;
-
-    PyObject *FileIO_class;
-    char rawmode[5], *m;
-    int line_buffering, isatty;
-
-    PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzzi:open", kwlist,
-                                     &file, &mode, &buffering,
-                                     &encoding, &errors, &newline,
-                                     &closefd)) {
-        return NULL;
-    }
-
-    if (!PyUnicode_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 '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 (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;
-        }
-        reading = 1;
-    }
-
-    if (text && binary) {
-        PyErr_SetString(PyExc_ValueError,
-                        "can't have text and binary mode at once");
-        return NULL;
-    }
-
-    if (reading + writing + appending > 1) {
-        PyErr_SetString(PyExc_ValueError,
-                        "must have exactly one of 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 */
-    FileIO_class = PyObject_GetAttrString(io_py_module, "FileIO");
-    if (!FileIO_class)
-        return NULL;
-
-    raw = PyObject_CallFunction(FileIO_class, "Osi", file, rawmode, closefd);
-    Py_DECREF(FileIO_class);
-    if (raw == NULL)
-        return NULL;
-
-    modeobj = PyUnicode_FromString(mode);
-    if (modeobj == NULL)
-        goto error;
-
-    /* buffering */
-    {
-        PyObject *res = PyObject_CallMethod(raw, "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) {
-        buffering = DEFAULT_BUFFER_SIZE;
-#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
-        {
-            struct stat st;
-            long fileno;
-            PyObject *res = PyObject_CallMethod(raw, "fileno", NULL);
-            if (res == NULL)
-                goto error;
-
-            fileno = PyLong_AsLong(res);
-            Py_DECREF(res);
-            if (fileno == -1 && PyErr_Occurred())
-                goto error;
-
-            if (stat(fileno, &st) >= 0)
-                buffering = st->st_blksize;
-        }
-#endif
-    }
-    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;
-        }
-
-        if (PyObject_SetAttrString(raw, "_name", file) < 0)
-            goto error;
-        if (PyObject_SetAttrString(raw, "_mode", modeobj) < 0)
-            goto error;
-        Py_DECREF(modeobj);
-        return raw;
-    }
-
-    /* wraps into a buffered file */
-    {
-        char *Buffered_class_name;
-        PyObject *Buffered_class;
-
-        if (updating)
-            Buffered_class_name = "BufferedRandom";
-        else if (writing || appending)
-            Buffered_class_name = "BufferedWriter";
-        else if (reading)
-            Buffered_class_name = "BufferedReader";
-        else {
-            PyErr_Format(PyExc_ValueError,
-                         "unknown mode: '%s'", mode);
-            goto error;
-        }
-
-        Buffered_class = PyObject_GetAttrString(io_py_module,
-                                                Buffered_class_name);
-        if (Buffered_class == NULL)
-            goto error;
-
-        buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
-        Py_DECREF(Buffered_class);
-    }
-    Py_CLEAR(raw);
-    if (buffer == NULL)
-        goto error;
-
-
-    /* if binary, returns the buffered file */
-    if (binary) {
-        if (PyObject_SetAttrString(buffer, "_name", file) < 0)
-            goto error;
-        if (PyObject_SetAttrString(buffer, "_mode", modeobj) < 0)
-            goto error;
-        Py_DECREF(modeobj);
-        return buffer;
-    }
-
-    /* wraps into a TextIOWrapper */
-    {
-        PyObject *TextIOWrapper_class;
-        TextIOWrapper_class = PyObject_GetAttrString(io_py_module,
-                                                     "TextIOWrapper");
-        if (TextIOWrapper_class == NULL)
-            goto error;
-
-        wrapper = PyObject_CallFunction(TextIOWrapper_class, "Osssi",
-                                        buffer,
-                                        encoding, errors, newline,
-                                        line_buffering);
-        Py_DECREF(TextIOWrapper_class);
-    }
-    Py_CLEAR(buffer);
-    if (wrapper == NULL)
-        goto error;
-
-    if (PyObject_SetAttrString(wrapper, "name", file) < 0)
-        goto error;
-    if (PyObject_SetAttrString(wrapper, "mode", modeobj) < 0)
-        goto error;
-    Py_DECREF(modeobj);
-    return wrapper;
-
-  error:
-    Py_XDECREF(raw);
-    Py_XDECREF(modeobj);
-    Py_XDECREF(buffer);
-    Py_XDECREF(wrapper);
-    return NULL;
-}
-
-
-static PyObject* PyExc_UnsupportedOperation;
-
-/*
- * IOBase class, an abstract class
- */
-
-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 a IOError when operations they do not support are 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 (even inquiries) on a closed stream is\n"
-    "undefined. Implementations may raise IOError in this case.\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 statment is complete:\n"
-    "\n"
-    "with open('spam.txt', 'r') as fp:\n"
-    "    fp.write('Spam and eggs!')\n");
-
-/* Internal methods */
-static PyObject *
-IOBase_unsupported(const char* message)
-{
-    PyErr_SetString(PyExc_UnsupportedOperation, message);
-    return NULL;
-}
-
-/* Positionning */
-
-PyDoc_STRVAR(IOBase_seek_doc,
-    "Change stream position.\n"
-    "\n"
-    "Change the stream position to byte offset offset. 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.");
-
-static PyObject*
-IOBase_seek(PyObject *self, PyObject *args)
-{
-    return IOBase_unsupported("seek");
-}
-
-PyDoc_STRVAR(IOBase_tell_doc,
-             "Return current stream position.");
-
-static PyObject *
-IOBase_tell(PyObject *self, PyObject *args)
-{
-    return PyObject_CallMethod(self, "tell", "ii", 0, 1);
-}
-
-PyDoc_STRVAR(IOBase_truncate_doc,
-    "Truncate file to size bytes.\n"
-    "\n"
-    "Size defaults to the current IO position as reported by tell().  Return\n"
-    "the new size.");
-
-static PyObject*
-IOBase_truncate(PyObject *self, PyObject *args)
-{
-    return IOBase_unsupported("seek");
-}
-
-/* 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");
-
-static PyObject*
-IOBase_flush(PyObject *self, PyObject *args)
-{
-    /* XXX Should this return the number of bytes written??? */
-    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)
-{
-    return PyObject_HasAttrString(self, "__IOBase_closed");
-}
-
-static PyObject *
-IOBase_closed_get(PyObject *self, void *context)
-{
-    return PyBool_FromLong(IOBase_closed(self));
-}
-
-
-static PyObject *
-IOBase_checkClosed(PyObject *self, PyObject *unused)
-{
-    if (IOBase_closed(self)) {
-        PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
-        return NULL;
-    }
-    Py_RETURN_NONE;
-}
-
-static PyObject*
-IOBase_close(PyObject *self, PyObject *args)
-{
-    PyObject *res;
-
-    if (IOBase_closed(self))
-        Py_RETURN_NONE;
-
-    PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
-
-    res = PyObject_CallMethod(self, "flush", NULL);
-    if (res == NULL) {
-        /* If flush() fails, just give up */
-        if (PyErr_ExceptionMatches(PyExc_IOError))
-            PyErr_Clear();
-        else
-            return NULL;
-    }
-    Py_RETURN_NONE;
-}
-
-static void
-IOBase_del(PyObject *self)
-{
-    PyObject *res = PyObject_CallMethod(self, "flush", NULL);
-    if (res == NULL) {
-        /* At program exit time, it's possible that globals have already been
-         *  deleted, and then the close() call might fail.  Since there's
-         *  nothing we can do about such failures and they annoy the end
-         *  users, we suppress the traceback.
-         */
-        PyErr_Clear();
-    }
-}
-
-/* Inquiry methods */
-
-PyDoc_STRVAR(IOBase_seekable_doc,
-    "Return whether object supports random access.\n"
-    "\n"
-    "If False, seek(), tell() and truncate() will raise IOError.\n"
-    "This method may need to do a test seek().");
-
-static PyObject*
-IOBase_seekable(PyObject *self, PyObject *args)
-{
-    Py_RETURN_FALSE;
-}
-
-static PyObject*
-IOBase_checkSeekable(PyObject *self, PyObject *unused)
-{
-    PyObject *res  = PyObject_CallMethod(self, "seekable", NULL);
-    if (res == NULL)
-        return NULL;
-    if (res != Py_True) {
-        Py_CLEAR(res);
-        PyErr_SetString(PyExc_IOError, "File or stream is not seekable.");
-    }
-    return res;
-}
-
-PyDoc_STRVAR(IOBase_readable_doc,
-    "Return whether object was opened for reading.\n"
-    "\n"
-    "If False, read() will raise IOError.");
-
-static PyObject*
-IOBase_readable(PyObject *self, PyObject *args)
-{
-    Py_RETURN_FALSE;
-}
-
-/* May be called with any object */
-static PyObject*
-IOBase_checkReadable(PyObject *self, PyObject *unused)
-{
-    PyObject *res  = PyObject_CallMethod(self, "readable", NULL);
-    if (res == NULL)
-        return NULL;
-    if (res != Py_True) {
-        Py_CLEAR(res);
-        PyErr_SetString(PyExc_IOError, "File or stream is not readable.");
-    }
-    return res;
-}
-
-PyDoc_STRVAR(IOBase_writable_doc,
-    "Return whether object was opened for writing.\n"
-    "\n"
-    "If False, read() will raise IOError.");
-
-static PyObject*
-IOBase_writable(PyObject *self, PyObject *args)
-{
-    Py_RETURN_FALSE;
-}
-
-/* May be called with any object */
-static PyObject*
-IOBase_checkWritable(PyObject *self, PyObject *unused)
-{
-    PyObject *res  = PyObject_CallMethod(self, "writable", NULL);
-    if (res == NULL)
-        return NULL;
-    if (res != Py_True) {
-        Py_CLEAR(res);
-        PyErr_SetString(PyExc_IOError, "File or stream is not writable.");
-    }
-    return res;
-}
-
-/* Context manager */
-
-static PyObject *
-IOBase_enter(PyObject *self, PyObject *args)
-{
-    if (IOBase_checkClosed(self, NULL) == NULL)
-        return NULL;
-
-    Py_INCREF(self);
-    return self;
-}
-
-static PyObject *
-IOBase_exit(PyObject *self, PyObject *args)
-{
-    return PyObject_CallMethod(self, "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 (IOBase_checkClosed(self, NULL) == 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;
-
-    if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
-        return NULL;
-    }
-
-    if (IOBase_checkClosed(self, NULL) == NULL)
-        return NULL;
-
-    if (PyObject_HasAttrString(self, "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_CallMethod(self, "peek", "i", 1);
-
-            assert (PyBytes_Check(readahead));
-
-            if (readahead == NULL)
-                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')
-                        {
-                            n++;
-                            break;
-                        }
-                        n++;
-                    } while (1);
-                }
-                else {
-                    do {
-                        if (n >= PyBytes_GET_SIZE(readahead))
-                            break;
-                        if (buf[n] == '\n')
-                        {
-                            n++;
-                            break;
-                        }
-                        n++;
-                    } while (1);
-                }
-                nreadahead = n;
-            }
-        }
-
-        b = PyObject_CallMethod(self, "read", "n", nreadahead);
-
-        if (b == NULL)
-            goto fail;
-
-        assert (PyBytes_Check(b));
-
-        if (Py_SIZE(b) == 0)
-            break;
-
-        old_size = Py_SIZE(buffer);
-        PyByteArray_Resize(buffer, old_size + Py_SIZE(b));
-        memcpy(PyByteArray_AS_STRING(buffer) + old_size, PyBytes_AS_STRING(b), Py_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, PyObject *args)
-{
-    if (IOBase_checkClosed(self, NULL) == NULL)
-        return NULL;
-
-    Py_INCREF(self);
-    return self;
-}
-
-static PyObject *
-IOBase_next(PyObject *self, PyObject *args)
-{
-    PyObject *line = PyObject_CallMethod(self, "readline", NULL);
-
-    if (line == NULL)
-        return NULL;
-
-    assert (PyBytes_Check(line));
-
-    if (PyBytes_GET_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 *line, *result;
-
-    if (!PyArg_ParseTuple(args, "|n:readlines", &hint)) {
-        return NULL;
-    }
-
-    result = PyList_New(0);
-    if (result == NULL)
-        return NULL;
-
-    if (hint <= 0) {
-        PyObject *ret = PyObject_CallMethod(result, "extend", "O", self);
-        if( ret == NULL) {
-            Py_DECREF(result);
-            return NULL;
-        }
-        Py_DECREF(ret);
-        return result;
-    }
-
-    while (1) {
-        line = PyObject_CallMethod(self, "__next__", NULL);
-        if (line == NULL) {
-            if (PyErr_Occurred()) {
-                Py_DECREF(result);
-                return NULL;
-            }
-            else
-                break; /* SopIteration raised */
-        }
-        assert (PyBytes_Check(line));
-
-        if (PyList_Append(result, line) < 0) {
-            Py_DECREF(line);
-            Py_DECREF(result);
-            return NULL;
-        }
-        length += Py_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 (IOBase_checkClosed(self, NULL) == 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 = PyObject_CallMethod(self, "write", "O", line);
-        Py_DECREF(line);
-        if (res == NULL) {
-            Py_DECREF(iter);
-            return NULL;
-        }
-        Py_DECREF(res);
-    }
-    Py_RETURN_NONE;
-}
-
-static PyMethodDef IOBase_methods[] = {
-    {"seek", IOBase_seek, METH_VARARGS},
-    {"tell", IOBase_tell, METH_NOARGS},
-    {"truncate", IOBase_truncate, METH_VARARGS},
-    {"flush", IOBase_flush, METH_NOARGS},
-    {"close", IOBase_close, METH_NOARGS},
-
-    {"seekable", IOBase_seekable, METH_NOARGS},
-    {"readable", IOBase_readable, METH_NOARGS},
-    {"writable", IOBase_writable, METH_NOARGS},
-
-    {"_checkClosed",   IOBase_checkClosed, METH_NOARGS},
-    {"_checkSeekable", IOBase_checkSeekable, METH_NOARGS},
-    {"_checkReadable", IOBase_checkReadable, METH_NOARGS},
-    {"_checkWritable", IOBase_checkWritable, METH_NOARGS},
-
-    {"fileno", IOBase_fileno, METH_NOARGS},
-    {"isatty", IOBase_isatty, METH_NOARGS},
-
-    {"__enter__", IOBase_enter, METH_NOARGS},
-    {"__exit__", IOBase_exit, METH_VARARGS},
-
-    {"__iter__", IOBase_iter, METH_NOARGS},
-    {"__next__", IOBase_next, METH_NOARGS},
-
-    {"readline", IOBase_readline, METH_VARARGS},
-    {"readlines", IOBase_readlines, METH_VARARGS},
-    {"writelines", IOBase_readlines, METH_VARARGS},
-
-    {NULL, NULL}
-};
-
-static PyGetSetDef IOBase_getset[] = {
-    {"closed", (getter)IOBase_closed_get, NULL, NULL},
-    {0}
-};
-
-
-PyTypeObject _IOBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "IOBase",                   /*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,  /*tp_flags*/
-    IOBase_doc,                 /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    0,                          /* tp_weaklistoffset */
-    0,                          /* tp_iter */
-    0,                          /* 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 */
-    0,                          /* 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 */
-    IOBase_del,                 /* tp_del */
-};
-PyObject *PyIOBase = (PyObject*)&_IOBase_Type;
-
-
-
-/*
- * 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)
-        return PyObject_CallMethod(self, "readall", NULL);
-
-    b = PyByteArray_FromStringAndSize(NULL, n);
-    if (b == NULL)
-        return NULL;
-
-    res = PyObject_CallMethod(self, "readinto", "O", b);
-    if (res == NULL) {
-        Py_DECREF(b);
-        return NULL;
-    }
-
-    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)
-{
-    PyObject *b = NULL;
-    Py_ssize_t cursize = 0;
-
-    while (1) {
-        Py_ssize_t length;
-        PyObject *data = PyObject_CallMethod(self, "read",
-                                             "i", DEFAULT_BUFFER_SIZE);
-
-        if (!data) {
-            Py_XDECREF(b);
-            return NULL;
-        }
-
-        if (!PyBytes_Check(data)) {
-            Py_XDECREF(b);
-            Py_DECREF(data);
-            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
-            return NULL;
-        }
-
-        length = Py_SIZE(data);
-
-        if (b == NULL)
-            b = data;
-        else if (length != 0) {
-
-            _PyBytes_Resize(&b, cursize + length);
-            if (b == NULL) {
-                Py_DECREF(data);
-                return NULL;
-            }
-
-            memcpy(PyBytes_AS_STRING(b) + cursize,
-                   PyBytes_AS_STRING(data), length);
-            Py_DECREF(data);
-        }
-
-        if (length == 0)
-            break;
-    }
-
-    return b;
-
-}
-
-static PyMethodDef RawIOBase_methods[] = {
-    {"read", RawIOBase_read, METH_VARARGS},
-    {"readall", RawIOBase_readall, METH_NOARGS, RawIOBase_readall_doc},
-    {NULL, NULL}
-};
-
-PyTypeObject _RawIOBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "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,  /*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 */
-    &_IOBase_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 */
-};
-PyObject *PyRawIOBase = (PyObject*)&_RawIOBase_Type;
-
-
-/*
- * 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"
-    );
-
-static PyObject *
-BufferedIOBase_readinto(PyObject *self, PyObject *args)
-{
-    Py_buffer buf;
-    Py_ssize_t len;
-    PyObject *data;
-
-    if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) {
-        return NULL;
-    }
-
-    data = PyObject_CallMethod(self, "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);
-    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;
-}
-
-static PyMethodDef BufferedIOBase_methods[] = {
-    {"readinto", BufferedIOBase_readinto, METH_VARARGS},
-    {NULL, NULL}
-};
-
-PyTypeObject _BufferedIOBase_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "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,  /*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 */
-    &_IOBase_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 */
-};
-
-
-typedef struct {
-    PyObject_HEAD
-
-    PyObject *raw;
-
-    PyObject *name;
-    PyObject *mode;
-
-    PyObject *read_buf;
-    Py_ssize_t read_pos;
-    PyThread_type_lock read_lock;
-
-    PyObject *write_buf;
-    PyThread_type_lock write_lock;
-
-    Py_ssize_t buffer_size;
-    Py_ssize_t max_buffer_size;
-
-    PyObject *dict;
-    PyObject *weakreflist;
-} BufferedObject;
-
-static void
-BufferedObject_dealloc(BufferedObject *self)
-{
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject *)self);
-    Py_CLEAR(self->raw);
-    Py_CLEAR(self->name);
-    Py_CLEAR(self->mode);
-    Py_CLEAR(self->read_buf);
-    Py_CLEAR(self->write_buf);
-    Py_CLEAR(self->dict);
-}
-
-
-/*
- * _BufferedIOMixin methods
- * This is not a class, just a collection of methods that will be reused
- * by BufferedReader and BufferedWriter
- */
-
-/* Positioning */
-
-static PyObject*
-BufferedIOMixin_truncate(BufferedObject *self, PyObject *args)
-{
-    PyObject *pos = Py_None;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
-        return NULL;
-    }
-
-    /* Flush the stream.  We're mixing buffered I/O with lower-level I/O,
-     * and a flush may be necessary to synch both views of the current
-     *  file state.
-     */
-    res = PyObject_CallMethod(self->raw, "flush", NULL);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-
-    if (pos == Py_None)
-        pos = PyObject_CallMethod(self->raw, "tell", NULL);
-    else
-        Py_INCREF(pos);
-
-    /* XXX: Should seek() be used, instead of passing the position
-     * XXX  directly to truncate?
-     */
-    res = PyObject_CallMethod(self->raw, "truncate", "O", pos);
-    Py_DECREF(pos);
-
-    return res;
-}
-
-/* Flush and close */
-
-static PyObject*
-BufferedIOMixin_flush(BufferedObject *self, PyObject *args)
-{
-    return PyObject_CallMethod(self->raw, "flush", NULL);
-}
-
-static int
-BufferedIOMixin_closed(BufferedObject *self)
-{
-    int closed;
-    PyObject *res = PyObject_GetAttrString(self->raw, "closed");
-    if (res == NULL)
-        return 0;
-    closed = PyObject_IsTrue(res);
-    Py_DECREF(res);
-    return closed;
-}
-
-static PyObject *
-BufferedIOMixin_closed_get(BufferedObject *self, void *context)
-{
-    return PyObject_GetAttrString(self->raw, "closed");
-}
-
-
-static PyObject*
-BufferedIOMixin_close(BufferedObject *self, PyObject *args)
-{
-    PyObject *res;
-
-    if (BufferedIOMixin_closed(self))
-        Py_RETURN_NONE;
-
-    res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
-    if (res == NULL) {
-        /* If flush() fails, just give up */
-        if (PyErr_ExceptionMatches(PyExc_IOError))
-            PyErr_Clear();
-        else
-            return NULL;
-    }
-
-    return PyObject_CallMethod(self->raw, "close", NULL);
-}
-
-/* Inquiries */
-
-static PyObject*
-BufferedIOMixin_seekable(BufferedObject *self, PyObject *args)
-{
-    return PyObject_CallMethod(self->raw, "seekable", NULL);
-}
-
-static PyObject*
-BufferedIOMixin_readable(BufferedObject *self, PyObject *args)
-{
-    return PyObject_CallMethod(self->raw, "readable", NULL);
-}
-
-static PyObject*
-BufferedIOMixin_writable(BufferedObject *self, PyObject *args)
-{
-    return PyObject_CallMethod(self->raw, "writable", NULL);
-}
-
-/* Lower-level APIs */
-
-static PyObject*
-BufferedIOMixin_fileno(BufferedObject *self, PyObject *args)
-{
-    return PyObject_CallMethod(self->raw, "fileno", NULL);
-}
-
-static PyObject*
-BufferedIOMixin_isatty(BufferedObject *self, PyObject *args)
-{
-    return PyObject_CallMethod(self->raw, "isatty", NULL);
-}
-
-
-/*
- * class BufferedReader
- */
-
-PyDoc_STRVAR(BufferedReader_doc,
-             "Create a new buffered reader using the given readable raw IO object.");
-
-static int _BufferedReader_reset_read_buf(BufferedObject *self)
-{
-    PyObject *oldbuf = self->read_buf;
-
-    self->read_buf = PyBytes_FromStringAndSize(NULL, 0);
-    self->read_pos = 0;
-
-    Py_XDECREF(oldbuf);
-
-    if (self->read_buf == NULL)
-        return -1;
-
-    return 0;
-}
-
-static int
-BufferedReader_init(BufferedObject *self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"raw", "buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    PyObject *raw;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
-                                     &raw, &buffer_size)) {
-        return -1;
-    }
-
-    if (IOBase_checkReadable(raw, NULL) == NULL)
-        return -1;
-
-    Py_INCREF(raw);
-    self->raw = raw;
-
-    self->buffer_size = buffer_size;
-    self->read_buf = NULL;
-
-    if( _BufferedReader_reset_read_buf(self) < 0)
-        return -1;
-
-    self->read_lock = PyThread_allocate_lock();
-    if (self->read_lock == NULL) {
-                PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
-        return -1;
-    }
-
-    return 0;
-}
-
-static PyObject *
-_BufferedReader_read_unlocked(BufferedObject *self, Py_ssize_t n)
-{
-    PyObject *nodata_val = NULL;
-    PyObject *empty_values = NULL;
-
-    PyObject *buf = self->read_buf;
-    Py_ssize_t pos = self->read_pos;
-    PyObject *data, *chunks, *sep, *res;
-    Py_ssize_t current_size;
-
-    /* Special case for when the number of bytes to read is unspecified. */
-    if (n == -1) {
-        chunks = PyList_New(0);
-        if (chunks == NULL)
-            return NULL;
-
-                Py_INCREF(buf);
-        if (_BufferedReader_reset_read_buf(self) < 0)
-            return NULL;
-
-        /* Strip the consumed bytes */
-        current_size = Py_SIZE(buf) - pos;
-        data = NULL;
-        if (current_size) {
-            data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
-            if (data == NULL) {
-                                Py_DECREF(buf);
-                Py_DECREF(chunks);
-                return NULL;
-            }
-                        Py_DECREF(buf);
-        }
-
-        while (1) {
-            if (data) {
-                if (PyList_Append(chunks, data) < 0) {
-                    Py_DECREF(data);
-                    Py_DECREF(chunks);
-                    return NULL;
-                }
-                Py_DECREF(data);
-            }
-
-            /* Read until EOF or until read() would block. */
-            data = PyObject_CallMethod(self->raw, "read", NULL);
-
-            if (data == NULL) {
-                Py_DECREF(chunks);
-                return NULL;
-            }
-
-            if (data != Py_None && !PyBytes_Check(data)) {
-                Py_DECREF(data);
-                Py_DECREF(chunks);
-                PyErr_SetString(PyExc_TypeError, "read() should return bytes");
-                return NULL;
-            }
-
-            if (data == Py_None || Py_SIZE(data) == 0) {
-                if (current_size == 0) {
-                    Py_DECREF(chunks);
-                    return data;
-                }
-                else {
-                    Py_DECREF(data);
-                    sep = PyBytes_FromStringAndSize(NULL, 0);
-
-                    if (sep == NULL) {
-                        Py_DECREF(chunks);
-                        return NULL;
-                    }
-                    res =_PyBytes_Join(sep, chunks);
-                    Py_DECREF(sep);
-                    Py_DECREF(chunks);
-
-                    return res;
-                }
-            }
-
-                        current_size += Py_SIZE(data);
-        }
-    }
-
-    /* The number of bytes to read is specified, return at most n bytes. */
-
-    current_size = Py_SIZE(buf) - pos; /* Length of the available buffered data. */
-    if (n <= current_size) {
-        /* Fast path: the data to read is fully buffered. */
-        self->read_pos += n;
-        return PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, n);
-    }
-
-    /* Slow path: read from the stream until enough bytes are read,
-     * or until an EOF occurs or until read() would block.
-     */
-    chunks = PyList_New(0);
-    if (chunks == NULL)
-        return NULL;
-
-    data = NULL;
-
-    if (current_size)
-        data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
-
-    while (1) {
-        Py_ssize_t wanted;
-
-        if (data) {
-            if (PyList_Append(chunks, data) < 0) {
-                Py_DECREF(data);
-                Py_DECREF(chunks);
-                return NULL;
-            }
-            Py_DECREF(data);
-        }
-
-                if (current_size >= n)
-                        break;
-
-                wanted = n;
-        if (wanted < self->buffer_size)
-            wanted = self->buffer_size;
-
-        data = PyObject_CallMethod(self->raw, "read", "n", wanted);
-
-        if (data != Py_None && !PyBytes_Check(data)) {
-            Py_DECREF(data);
-            Py_DECREF(chunks);
-            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
-            return NULL;
-        }
-
-        if (data == Py_None || Py_SIZE(data) == 0) {
-            /* EOF occurred or read() would block. */
-
-            if (current_size == 0) {
-                Py_DECREF(chunks);
-
-                if( _BufferedReader_reset_read_buf(self) < 0) {
-                    Py_DECREF(data);
-                    return NULL;
-                }
-
-                return data;
-            }
-            else {
-                            Py_DECREF(data);
-                break;
-            }
-        }
-
-                current_size += Py_SIZE(data);
-    }
-
-    sep = PyBytes_FromStringAndSize(NULL, 0);
-
-    if (sep == NULL) {
-        Py_DECREF(chunks);
-        return NULL;
-    }
-
-    res =_PyBytes_Join(sep, chunks);
-    Py_DECREF(sep);
-    Py_DECREF(chunks);
-
-    if (Py_SIZE(res) > n) {
-        /* Save the extra data in the buffer. */
-        self->read_pos = 0;
-        buf = self->read_buf;
-        self->read_buf = PyBytes_FromStringAndSize(PyBytes_AS_STRING(res) + n, Py_SIZE(res) - n);
-        Py_DECREF(buf);
-        if (self->read_buf == NULL) {
-            Py_DECREF(res);
-            return NULL;
-        }
-
-        /* Truncate the result to the desired length */
-        buf = PyBytes_FromStringAndSize(PyBytes_AS_STRING(res), n);
-        if (buf == NULL) {
-            Py_DECREF(res);
-            return NULL;
-        }
-
-        Py_DECREF(res);
-        res = buf;
-    }
-
-    return res;
-}
-
-static PyObject *
-BufferedReader_read(BufferedObject *self, PyObject *args)
-{
-    Py_ssize_t n = -1;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "|n:read", &n)) {
-        return NULL;
-    }
-
-    Py_BEGIN_ALLOW_THREADS
-    PyThread_acquire_lock(self->read_lock, 1);
-    Py_END_ALLOW_THREADS
-
-    res = _BufferedReader_read_unlocked(self, n);
-
-    PyThread_release_lock(self->read_lock);
-
-    return res;
-}
-
-static PyObject *
-_BufferedReader_peek_unlocked(BufferedObject *self, Py_ssize_t n)
-{
-    Py_ssize_t have;
-
-    if (n > self->buffer_size)
-        n = self->buffer_size;
-
-    have = Py_SIZE(self->read_buf) - self->read_pos;
-
-    if (have < n) {
-        Py_ssize_t to_read = self->buffer_size - have;
-        PyObject *current = PyObject_CallMethod(self->raw, "read", "n", to_read);
-
-        if (current == NULL)
-            return NULL;
-
-        if (!PyBytes_Check(current)) {
-            Py_DECREF(current);
-            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
-            return NULL;
-        }
-
-        if (Py_SIZE(current) > 0) {
-            PyObject *oldbuf = self->read_buf;
-            self->read_buf = PyBytes_FromStringAndSize(NULL, have + Py_SIZE(current));
-            memcpy(PyBytes_AS_STRING(self->read_buf), PyBytes_AS_STRING(oldbuf) + self->read_pos, have);
-            memcpy(PyBytes_AS_STRING(self->read_buf) + have, PyBytes_AS_STRING(current), Py_SIZE(current));
-            self->read_pos = 0;
-        }
-        Py_DECREF(current);
-    }
-
-    if (self->read_pos == 0) {
-        Py_INCREF(self->read_buf);
-        return self->read_buf;
-    }
-    else {
-        return PyBytes_FromStringAndSize(
-            PyBytes_AS_STRING(self->read_buf) + self->read_pos,
-            Py_SIZE(self->read_buf) - self->read_pos);
-    }
-}
-
-static PyObject *
-BufferedReader_peek(BufferedObject *self, PyObject *args)
-{
-    Py_ssize_t n = 0;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
-        return NULL;
-    }
-
-        Py_BEGIN_ALLOW_THREADS
-        PyThread_acquire_lock(self->read_lock, 1);
-        Py_END_ALLOW_THREADS
-
-    res = _BufferedReader_peek_unlocked(self, n);
-
-    PyThread_release_lock(self->read_lock);
-
-    return res;
-}
-
-static PyObject *
-BufferedReader_read1(BufferedObject *self, PyObject *args)
-{
-    Py_ssize_t n, have;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "n:read1", &n)) {
-        return NULL;
-    }
-
-    if (n <= 0)
-        return PyBytes_FromStringAndSize(NULL, 0);
-
-        Py_BEGIN_ALLOW_THREADS
-        PyThread_acquire_lock(self->read_lock, 1);
-        Py_END_ALLOW_THREADS
-
-    res = _BufferedReader_peek_unlocked(self, 1);
-    if(res == NULL)
-        goto end;
-    Py_DECREF(res);
-
-    have = Py_SIZE(self->read_buf) - self->read_pos;
-    if (n > have)
-        n = have;
-
-    res = _BufferedReader_read_unlocked(self, n);
-
-  end:
-    PyThread_release_lock(self->read_lock);
-
-    return res;
-}
-
-static PyObject*
-BufferedReader_seek(BufferedObject *self, PyObject *args)
-{
-    Py_ssize_t pos;
-    int whence = 0;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
-        return NULL;
-    }
-
-    Py_BEGIN_ALLOW_THREADS
-    PyThread_acquire_lock(self->read_lock, 1);
-    Py_END_ALLOW_THREADS
-
-    if (whence == 1) {
-        pos -= Py_SIZE(self->read_buf) - self->read_pos;
-    }
-
-    res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
-    if (res == NULL)
-        return NULL;
-
-    if (_BufferedReader_reset_read_buf(self) < 0)
-        Py_CLEAR(res);
-
-    PyThread_release_lock(self->read_lock);
-
-    return res;
-}
-
-static PyObject*
-BufferedReader_tell(BufferedObject *self, PyObject *args)
-{
-    PyObject *op1, *op2, *res;
-
-    op1 = PyObject_CallMethod(self->raw, "tell", NULL);
-
-    if (op1 == NULL)
-        return NULL;
-
-    op2 = PyLong_FromSsize_t(Py_SIZE(self->read_buf) - self->read_pos);
-    if (op2 == NULL) {
-        Py_DECREF(op1);
-        return NULL;
-    }
-
-    res = PyNumber_Subtract(op1, op2);
-    Py_DECREF(op1);
-    Py_DECREF(op2);
-    return res;
-}
-
-static PyMethodDef BufferedReader_methods[] = {
-    /* BufferedIOMixin methods */
-    {"truncate", (PyCFunction)BufferedIOMixin_truncate, METH_VARARGS},
-    {"flush", (PyCFunction)BufferedIOMixin_flush, METH_NOARGS},
-    {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
-    {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
-    {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
-    {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
-    {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
-
-    {"read", (PyCFunction)BufferedReader_read, METH_VARARGS},
-    {"peek", (PyCFunction)BufferedReader_peek, METH_VARARGS},
-    {"read1", (PyCFunction)BufferedReader_read1, METH_VARARGS},
-    {"seek", (PyCFunction)BufferedReader_seek, METH_VARARGS},
-    {"tell", (PyCFunction)BufferedReader_tell, METH_NOARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef BufferedReader_members[] = {
-    {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
-    {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
-    {NULL}
-};
-
-static PyGetSetDef BufferedReader_getset[] = {
-    {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
-    {0}
-};
-
-
-PyTypeObject BufferedReader_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "BufferedReader",           /*tp_name*/
-    sizeof(BufferedObject),     /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)BufferedObject_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*/
-    BufferedReader_doc,         /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-        offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    0,                          /* 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(BufferedObject, dict), /* tp_dictoffset */
-    (initproc)BufferedReader_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-};
-
-
-/*
- * 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"
-    "DEAFULT_BUFFER_SIZE. If max_buffer_size is omitted, it defaults to\n"
-    "twice the buffer size.\n"
-    );
-
-static int
-BufferedWriter_init(BufferedObject *self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    Py_ssize_t max_buffer_size = -1;
-    PyObject *raw;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist,
-                                     &raw, &buffer_size, &max_buffer_size)) {
-        return -1;
-    }
-
-    if (IOBase_checkWritable(raw, NULL) == NULL)
-        return -1;
-
-    Py_INCREF(raw);
-    self->raw = raw;
-
-    if (max_buffer_size < 0)
-        max_buffer_size = buffer_size * 2;
-    self->buffer_size = buffer_size;
-    self->max_buffer_size = max_buffer_size;
-
-        self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
-    if (self->write_buf == NULL)
-        return -1;
-
-    self->write_lock = PyThread_allocate_lock();
-    if (self->write_lock == NULL) {
-                PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
-        return -1;
-    }
-
-    return 0;
-}
-
-static PyObject *
-_BufferedWriter_flush_unlocked(BufferedObject *self)
-{
-    Py_ssize_t written = 0;
-
-    if (BufferedIOMixin_closed(self)) {
-        PyErr_SetString(PyExc_ValueError, "flush of closed file");
-        return NULL;
-    }
-
-    while (Py_SIZE(self->write_buf) > 0) {
-        PyObject *slice, *res;
-        Py_ssize_t w;
-        PyObject *n = PyObject_CallMethod(self->raw, "write", "O", self->write_buf);
-
-        if (n == NULL) {
-            PyObject *type, *value, *traceback;
-            PyErr_Fetch(&type, &value, &traceback);
-
-            if (value == NULL ||
-                !PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
-                PyErr_Restore(type, value, traceback);
-                return NULL;
-            }
-
-            w = ((PyBlockingIOErrorObject *)value)->written;
-
-            /* del self->write_buf[:w] */
-            slice = _PySlice_FromIndices(0, w);
-            if (slice == NULL)
-                return NULL;
-            res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
-            Py_DECREF(slice);
-            if (res == NULL)
-                return NULL;
-            Py_DECREF(res);
-
-            written += w;
-            ((PyBlockingIOErrorObject *)value)->written = written;
-
-            PyErr_Restore(type, value, traceback);
-            return NULL;
-        }
-
-        /* del self->write_buf[:w] */
-        w = PyNumber_AsSsize_t(n, PyExc_ValueError);
-        Py_DECREF(n);
-        if (w == -1 && PyErr_Occurred())
-            return NULL;
-
-        slice = _PySlice_FromIndices(0, w);
-        if (slice == NULL)
-            return NULL;
-        res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
-        Py_DECREF(slice);
-        if (res == NULL)
-            return NULL;
-        Py_DECREF(res);
-
-        written += w;
-    }
-
-    Py_RETURN_NONE;
-}
-
-static PyObject *
-BufferedWriter_write(BufferedObject *self, PyObject *args)
-{
-    PyObject *res;
-    Py_buffer buf;
-    Py_ssize_t before, written;
-
-    if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
-        return NULL;
-    }
-
-    if (BufferedIOMixin_closed(self)) {
-        PyErr_SetString(PyExc_ValueError, "write to closed file");
-        PyBuffer_Release(&buf);
-        return NULL;
-    }
-
-        Py_BEGIN_ALLOW_THREADS
-        PyThread_acquire_lock(self->write_lock, 1);
-        Py_END_ALLOW_THREADS
-
-    /* XXX we can implement some more tricks to try and avoid
-     * partial writes
-     */
-
-    if (Py_SIZE(self->write_buf) > self->buffer_size) {
-        /* We're full, so let's pre-flush the buffer*/
-        res = _BufferedWriter_flush_unlocked(self);
-        if (res == NULL) {
-            /* We can't accept anything else. */
-            PyObject *type, *value, *traceback;
-            PyErr_Fetch(&type, &value, &traceback);
-
-            if (value != NULL &&
-                PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
-                ((PyBlockingIOErrorObject *)value)->written = 0;
-            }
-
-            PyErr_Restore(type, value, traceback);
-            goto fail;
-        }
-    }
-
-    written = buf.len;
-
-    before = Py_SIZE(self->write_buf);
-    if (PyByteArray_Resize(self->write_buf, before + written) < 0) {
-        res = NULL;
-        goto fail;
-    }
-    memcpy(PyByteArray_AS_STRING(self->write_buf) + before, buf.buf, written);
-
-    if (Py_SIZE(self->write_buf) > self->buffer_size) {
-        res = _BufferedWriter_flush_unlocked(self);
-        if (res == NULL) {
-            PyObject *type, *value, *traceback;
-            PyErr_Fetch(&type, &value, &traceback);
-
-            if (value != NULL &&
-                PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
-
-                Py_ssize_t overage =
-                    Py_SIZE(self->write_buf) - self->max_buffer_size;
-
-                if (overage > 0) {
-                    /* We've hit max_buffer_size. We have to accept a
-                     * partial write and cut back our buffer.
-                     */
-                    if (PyByteArray_Resize(self->write_buf, self->max_buffer_size) < 0)
-                        goto fail;
-                    ((PyBlockingIOErrorObject *)value)->written = overage;
-                }
-                else
-                {
-                    Py_CLEAR(type);
-                    Py_CLEAR(value);
-                    Py_CLEAR(traceback);
-                    goto end;
-                }
-            }
-
-            PyErr_Restore(type, value, traceback);
-            goto fail;
-        }
-    }
-
-  end:
-    res = PyLong_FromSsize_t(written);
-
-  fail:
-    PyThread_release_lock(self->write_lock);
-    PyBuffer_Release(&buf);
-    return res;
-}
-
-static PyObject *
-BufferedWriter_truncate(BufferedObject *self, PyObject *args)
-{
-    PyObject *pos = Py_None;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
-        return NULL;
-    }
-
-    Py_BEGIN_ALLOW_THREADS
-    PyThread_acquire_lock(self->write_lock, 1);
-    Py_END_ALLOW_THREADS
-
-    res = _BufferedWriter_flush_unlocked(self);
-    if (res == NULL)
-        goto end;
-    Py_DECREF(res);
-
-    res = BufferedIOMixin_truncate(self, args);
-
-  end:
-    PyThread_release_lock(self->write_lock);
-    return res;
-}
-
-static PyObject *
-BufferedWriter_flush(BufferedObject *self, PyObject *args)
-{
-    PyObject *res;
-
-        Py_BEGIN_ALLOW_THREADS
-        PyThread_acquire_lock(self->write_lock, 1);
-        Py_END_ALLOW_THREADS
-
-    res = _BufferedWriter_flush_unlocked(self);
-
-    PyThread_release_lock(self->write_lock);
-
-    return res;
-}
-
-static PyObject *
-BufferedWriter_tell(BufferedObject *self, PyObject *args)
-{
-    PyObject *op1, *op2, *res;
-
-    op1 = PyObject_CallMethod(self->raw, "tell", NULL);
-
-    op2 = PyLong_FromSsize_t(Py_SIZE(self->write_buf));
-    if (op2 == NULL) {
-        Py_DECREF(op1);
-        return NULL;
-    }
-
-    res = PyNumber_Add(op1, op2);
-    Py_DECREF(op1);
-    Py_DECREF(op2);
-    return res;
-}
-
-static PyObject *
-BufferedWriter_seek(BufferedObject *self, PyObject *args)
-{
-    Py_ssize_t pos;
-    int whence = 0;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
-        return NULL;
-    }
-
-        Py_BEGIN_ALLOW_THREADS
-        PyThread_acquire_lock(self->write_lock, 1);
-        Py_END_ALLOW_THREADS
-
-    res = _BufferedWriter_flush_unlocked(self);
-    if (res == NULL)
-        goto end;
-
-    res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
-
-  end:
-    PyThread_release_lock(self->write_lock);
-    return res;
-}
-
-static PyMethodDef BufferedWriter_methods[] = {
-    /* BufferedIOMixin methods */
-    {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
-    {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
-    {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
-    {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
-    {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
-
-    {"write", (PyCFunction)BufferedWriter_write, METH_VARARGS},
-    {"truncate", (PyCFunction)BufferedWriter_truncate, METH_VARARGS},
-    {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
-    {"seek", (PyCFunction)BufferedWriter_seek, METH_VARARGS},
-    {"tell", (PyCFunction)BufferedWriter_tell, METH_NOARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef BufferedWriter_members[] = {
-        {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
-        {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
-    {NULL}
-};
-
-static PyGetSetDef BufferedWriter_getset[] = {
-    {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
-    {0}
-};
-
-
-PyTypeObject BufferedWriter_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "BufferedWriter",           /*tp_name*/
-    sizeof(BufferedObject),     /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)BufferedObject_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*/
-    BufferedWriter_doc,         /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(BufferedObject, 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(BufferedObject, dict), /* tp_dictoffset */
-    (initproc)BufferedWriter_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-};
-
-
-
-/*
- * 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. The max_buffer_size (for the buffered writer)\n"
-    "defaults to twice the buffer size.\n"
-    );
-
-/* XXX The usefulness of this (compared to having two separate IO objects) is
- * questionable.
- */
-
-typedef struct {
-    PyObject_HEAD
-    BufferedObject *reader;
-    BufferedObject *writer;
-} BufferedRWPairObject;
-
-static int
-BufferedRWPair_init(BufferedRWPairObject *self, PyObject *args,
-                     PyObject *kwds)
-{
-    PyObject *reader, *writer;
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    Py_ssize_t max_buffer_size = -1;
-
-    if (!PyArg_ParseTuple(args, "OO|nn:BufferedRWPair", &reader, &writer,
-                          &buffer_size, &max_buffer_size)) {
-        return -1;
-    }
-
-    if (IOBase_checkReadable(reader, NULL) == NULL)
-        return -1;
-    if (IOBase_checkWritable(writer, NULL) == NULL)
-        return -1;
-
-    args = Py_BuildValue("(n)", buffer_size);
-    if (args == NULL) {
-        Py_CLEAR(self->reader);
-        return -1;
-    }
-    self->reader = (BufferedObject*)PyType_GenericNew(&BufferedReader_Type, args, NULL);
-    Py_DECREF(args);
-    if (self->reader == NULL)
-        return -1;
-
-    args = Py_BuildValue("(nn)", buffer_size, max_buffer_size);
-    if (args == NULL) {
-        Py_CLEAR(self->reader);
-        return -1;
-    }
-    self->writer = (BufferedObject*)PyType_GenericNew(&BufferedWriter_Type, args, NULL);
-    Py_DECREF(args);
-    if (self->writer == NULL) {
-        Py_CLEAR(self->reader);
-        return -1;
-    }
-    return 0;
-}
-
-static void
-BufferedRWPair_dealloc(BufferedRWPairObject *self)
-{
-    Py_CLEAR(self->reader);
-    Py_CLEAR(self->writer);
-}
-
-static PyObject *
-_forward_call(BufferedObject *self, const char* name, PyObject *args)
-{
-    PyObject *func = PyObject_GetAttrString((PyObject*)self, name);
-    PyObject *ret;
-
-    if (func == NULL) {
-        PyErr_SetString(PyExc_AttributeError, name);
-        return NULL;
-    }
-
-    ret = PyObject_CallObject(func, args);
-    Py_DECREF(func);
-    return ret;
-}
-
-static PyObject *
-BufferedRWPair_read(BufferedRWPairObject *self, PyObject *args)
-{
-    return _forward_call(self->reader, "read", args);
-}
-
-static PyObject *
-BufferedRWPair_peek(BufferedRWPairObject *self, PyObject *args)
-{
-    return _forward_call(self->reader, "peek", args);
-}
-
-static PyObject *
-BufferedRWPair_read1(BufferedRWPairObject *self, PyObject *args)
-{
-    return _forward_call(self->reader, "read1", args);
-}
-
-static PyObject *
-BufferedRWPair_write(BufferedRWPairObject *self, PyObject *args)
-{
-    return _forward_call(self->writer, "write", args);
-}
-
-static PyObject *
-BufferedRWPair_flush(BufferedRWPairObject *self, PyObject *args)
-{
-    return _forward_call(self->writer, "flush", args);
-}
-
-static PyObject *
-BufferedRWPair_readable(BufferedRWPairObject *self, PyObject *args)
-{
-    return _forward_call(self->reader, "readable", args);
-}
-
-static PyObject *
-BufferedRWPair_writable(BufferedRWPairObject *self, PyObject *args)
-{
-    return _forward_call(self->writer, "writable", args);
-}
-
-static PyObject *
-BufferedRWPair_close(BufferedRWPairObject *self, PyObject *args)
-{
-    PyObject *ret = _forward_call(self->writer, "close", args);
-    if (ret == NULL)
-        return NULL;
-    Py_DECREF(ret);
-
-    return _forward_call(self->reader, "close", args);
-}
-
-static PyObject *
-BufferedRWPair_isatty(BufferedRWPairObject *self, PyObject *args)
-{
-    PyObject *ret = _forward_call(self->writer, "isatty", args);
-
-    if (ret != Py_False) {
-        /* either True or exception */
-        return ret;
-    }
-    Py_DECREF(ret);
-
-    return _forward_call(self->reader, "isatty", args);
-}
-
-
-static PyMethodDef BufferedRWPair_methods[] = {
-    {"read", (PyCFunction)BufferedRWPair_read, METH_VARARGS},
-    {"peek", (PyCFunction)BufferedRWPair_peek, METH_VARARGS},
-    {"read1", (PyCFunction)BufferedRWPair_read1, 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},
-
-    {NULL, NULL}
-};
-
-PyTypeObject BufferedRWPair_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "BufferedRWPair",           /*tp_name*/
-    sizeof(BufferedRWPairObject),     /*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,  /*tp_flags*/
-    BufferedRWPair_doc,         /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    0,                          /* tp_iternext */
-    BufferedRWPair_methods,     /* tp_methods */
-    0,     /* tp_members */
-    0,      /* tp_getset */
-    0,                          /* tp_base */
-    0,                          /* tp_dict */
-    0,                          /* tp_descr_get */
-    0,                          /* tp_descr_set */
-    offsetof(BufferedObject, dict), /* tp_dictoffset */
-    (initproc)BufferedRWPair_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-};
-
-
-
-/*
- * 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. The max_buffer_size (for the buffered\n"
-    "writer) defaults to twice the buffer size.\n"
-    );
-
-static int
-BufferedRandom_init(BufferedObject *self, PyObject *args, PyObject *kwds)
-{
-    char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
-    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
-    Py_ssize_t max_buffer_size = -1;
-    PyObject *raw;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist,
-                                     &raw, &buffer_size, &max_buffer_size)) {
-        return -1;
-    }
-
-    if (IOBase_checkSeekable(raw, NULL) == NULL)
-        return -1;
-    if (IOBase_checkReadable(raw, NULL) == NULL)
-        return -1;
-    if (IOBase_checkWritable(raw, NULL) == NULL)
-        return -1;
-
-    Py_INCREF(raw);
-    self->raw = raw;
-
-    if (max_buffer_size < 0)
-        max_buffer_size = buffer_size * 2;
-    self->buffer_size = buffer_size;
-    self->max_buffer_size = max_buffer_size;
-
-    if( _BufferedReader_reset_read_buf(self) < 0)
-        return -1;
-
-    self->read_lock = PyThread_allocate_lock();
-    if (self->read_lock == NULL) {
-                PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
-        return -1;
-    }
-
-        self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
-    if (self->write_buf == NULL)
-        return -1;
-
-    self->write_lock = PyThread_allocate_lock();
-    if (self->write_lock == NULL) {
-                PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
-        return -1;
-    }
-
-    return 0;
-}
-
-static PyObject *
-BufferedRandom_tell(BufferedObject *self, PyObject *args)
-{
-    if (Py_SIZE(self->write_buf))
-        return BufferedWriter_tell(self, args);
-    else
-        return BufferedReader_tell(self, args);
-}
-
-static PyObject *
-BufferedRandom_seek(BufferedObject *self, PyObject *args)
-{
-    Py_ssize_t pos;
-    int whence = 0;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
-        return NULL;
-    }
-
-    res = PyObject_CallMethod((PyObject*)self, "flush", NULL);
-    if (res == NULL)
-        return NULL;
-
-    /* First do the raw seek, then empty the read buffer, so that
-     * if the raw seek fails, we don't lose buffered data forever.
-     */
-
-    res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
-    if (res == NULL)
-        return NULL;
-
-        Py_BEGIN_ALLOW_THREADS
-        PyThread_acquire_lock(self->read_lock, 1);
-        Py_END_ALLOW_THREADS
-
-    if( _BufferedReader_reset_read_buf(self) < 0)
-        Py_CLEAR(res);
-
-    PyThread_release_lock(self->read_lock);
-    return res;
-}
-
-static PyObject *
-BufferedRandom_truncate(BufferedObject *self, PyObject *args)
-{
-    PyObject *pos = Py_None;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
-        return NULL;
-    }
-
-    if (pos == Py_None)
-        pos = PyObject_CallMethod(self->raw, "tell", NULL);
-    else
-        Py_INCREF(pos);
-
-    /* Use seek to flush the read buffer. */
-    res = PyObject_CallMethod((PyObject *)self, "seek", "O", pos);
-    Py_DECREF(pos);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-
-    args = PyTuple_New(0);
-    if (args == NULL)
-        return NULL;
-    res = BufferedWriter_truncate(self, args);
-    Py_DECREF(args);
-
-    return res;
-}
-
-static PyObject *
-BufferedRandom_read(BufferedObject *self, PyObject *args)
-{
-    Py_ssize_t n = -1;
-    PyObject *res;
-
-    if (!PyArg_ParseTuple(args, "|n:read", &n)) {
-        return NULL;
-    }
-
-    res = BufferedWriter_flush(self, Py_None);
-    if (res == NULL)
-        return NULL;
-
-    return BufferedReader_read(self, args);
-}
-
-static PyObject *
-BufferedRandom_readinto(BufferedObject *self, PyObject *args)
-{
-    PyObject *res;
-
-    res = BufferedWriter_flush(self, Py_None);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-
-    return BufferedIOBase_readinto((PyObject *)self, args);
-}
-
-static PyObject *
-BufferedRandom_peek(BufferedObject *self, PyObject *args)
-{
-    PyObject *res = BufferedWriter_flush(self, Py_None);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-
-    return BufferedReader_peek(self, args);
-}
-
-static PyObject *
-BufferedRandom_read1(BufferedObject *self, PyObject *args)
-{
-    PyObject *res = BufferedWriter_flush(self, Py_None);
-    if (res == NULL)
-        return NULL;
-    Py_DECREF(res);
-
-    return BufferedReader_read1(self, args);
-}
-
-static PyObject *
-BufferedRandom_write(BufferedObject *self, PyObject *args)
-{
-    if (Py_SIZE(self->read_buf) > 0) {
-        PyObject *res;
-        /* Undo readahead */
-
-        Py_BEGIN_ALLOW_THREADS
-        PyThread_acquire_lock(self->read_lock, 1);
-        Py_END_ALLOW_THREADS
-
-        res = PyObject_CallMethod(self->raw, "seek", "ni",
-                                  self->read_pos - Py_SIZE(self->read_buf), 1);
-        Py_XDECREF(res);
-        if (res != NULL) {
-            if( _BufferedReader_reset_read_buf(self) < 0)
-                res = NULL;
-        }
-
-        PyThread_release_lock(self->read_lock);
-
-        if (res == NULL)
-            return NULL;
-    }
-
-    return BufferedWriter_write(self, args);
-}
-
-
-static PyMethodDef BufferedRandom_methods[] = {
-    /* BufferedIOMixin methods */
-    {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
-    {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
-    {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
-    {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
-    {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
-    {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
-
-    {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
-
-    {"seek", (PyCFunction)BufferedRandom_seek, METH_VARARGS},
-    {"tell", (PyCFunction)BufferedRandom_tell, METH_NOARGS},
-    {"truncate", (PyCFunction)BufferedRandom_truncate, METH_VARARGS},
-    {"read", (PyCFunction)BufferedRandom_read, METH_VARARGS},
-    {"readinto", (PyCFunction)BufferedRandom_readinto, METH_VARARGS},
-    {"peek", (PyCFunction)BufferedRandom_peek, METH_VARARGS},
-    {"read1", (PyCFunction)BufferedRandom_read1, METH_VARARGS},
-    {"write", (PyCFunction)BufferedRandom_write, METH_VARARGS},
-    {NULL, NULL}
-};
-
-static PyMemberDef BufferedRandom_members[] = {
-    {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
-    {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
-    {NULL}
-};
-
-static PyGetSetDef BufferedRandom_getset[] = {
-    {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
-    {0}
-};
-
-
-PyTypeObject BufferedRandom_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "BufferedRandom",           /*tp_name*/
-    sizeof(BufferedObject),     /*tp_basicsize*/
-    0,                          /*tp_itemsize*/
-    (destructor)BufferedObject_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*/
-    BufferedRandom_doc,         /* tp_doc */
-    0,                          /* tp_traverse */
-    0,                          /* tp_clear */
-    0,                          /* tp_richcompare */
-    offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
-    0,                          /* tp_iter */
-    0,                          /* 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(BufferedObject, dict), /*tp_dictoffset*/
-    (initproc)BufferedRandom_init, /* tp_init */
-    0,                          /* tp_alloc */
-    PyType_GenericNew,          /* tp_new */
-};
-
-/*
- * Module definition
- */
-
-static PyMethodDef module_methods[] = {
-    {"open", (PyCFunction)io_open, METH_VARARGS|METH_KEYWORDS, open_doc},
-    {NULL, NULL}
-};
-
-static struct PyModuleDef iomodule = {
-    PyModuleDef_HEAD_INIT,
-    "io",
-    module_doc,
-    -1,
-    module_methods,
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
-
-PyMODINIT_FUNC
-PyInit__io()
-{
-    PyObject *m = PyModule_Create(&iomodule);
-    PyTypeObject *base;
-    if (m == NULL)
-        goto fail;
-
-    io_py_module = PyImport_ImportModule("io");
-    if (io_py_module == NULL)
-        goto fail;
-
-    /* UnsupportedOperation inherits from ValueError and IOError */
-    PyExc_UnsupportedOperation = PyObject_CallFunction(
-        (PyObject*)&PyType_Type, "s(OO){}",
-        "UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
-    if (PyExc_UnsupportedOperation == NULL)
-        goto fail;
-    PyModule_AddObject(m, "UnsupportedOperation",
-                       PyExc_UnsupportedOperation);
-
-    /* BlockingIOError */
-    base = (PyTypeObject*)PyExc_IOError;
-    _PyExc_BlockingIOError.tp_base = base;
-    if (PyType_Ready(&_PyExc_BlockingIOError) < 0)
-        goto fail;
-    Py_INCREF(&_PyExc_BlockingIOError);
-    PyModule_AddObject(m, "BlockingIOError",
-                       (PyObject *)&_PyExc_BlockingIOError);
-
-    if (PyType_Ready(&_IOBase_Type) < 0)
-        goto fail;
-    Py_INCREF(&_IOBase_Type);
-    PyModule_AddObject(m, "IOBase",
-                       (PyObject *)&_IOBase_Type);
-
-    if (PyType_Ready(&_RawIOBase_Type) < 0)
-        goto fail;
-    Py_INCREF(&_RawIOBase_Type);
-    PyModule_AddObject(m, "RawIOBase",
-                       (PyObject *)&_RawIOBase_Type);
-
-    /* FileIO */
-    PyFileIO_Type.tp_base = &_RawIOBase_Type;
-    if (PyType_Ready(&PyFileIO_Type) < 0)
-        goto fail;
-    Py_INCREF(&PyFileIO_Type);
-    PyModule_AddObject(m, "FileIO", (PyObject *) &PyFileIO_Type);
-
-    /* BufferedIOBase */
-    if (PyType_Ready(&_BufferedIOBase_Type) < 0)
-        goto fail;
-    Py_INCREF(&_BufferedIOBase_Type);
-    PyModule_AddObject(m, "BufferedIOBase", (PyObject *) &_BufferedIOBase_Type);
-
-    /* BytesIO */
-    PyBytesIO_Type.tp_base = &_BufferedIOBase_Type;
-    if (PyType_Ready(&PyBytesIO_Type) < 0)
-        goto fail;
-    Py_INCREF(&PyBytesIO_Type);
-    PyModule_AddObject(m, "BytesIO", (PyObject *) &PyBytesIO_Type);
-
-    /* BufferedReader */
-    BufferedReader_Type.tp_base = &_BufferedIOBase_Type;
-    if (PyType_Ready(&BufferedReader_Type) < 0)
-        goto fail;
-    Py_INCREF(&BufferedReader_Type);
-    PyModule_AddObject(m, "BufferedReader", (PyObject *) &BufferedReader_Type);
-
-    /* BufferedWriter */
-    BufferedWriter_Type.tp_base = &_BufferedIOBase_Type;
-    if (PyType_Ready(&BufferedWriter_Type) < 0)
-        goto fail;
-    Py_INCREF(&BufferedWriter_Type);
-    PyModule_AddObject(m, "BufferedWriter", (PyObject *) &BufferedWriter_Type);
-
-    /* BufferedRWPair */
-    BufferedRWPair_Type.tp_base = &_BufferedIOBase_Type;
-    if (PyType_Ready(&BufferedRWPair_Type) < 0)
-        goto fail;
-    Py_INCREF(&BufferedRWPair_Type);
-    PyModule_AddObject(m, "BufferedRWPair", (PyObject *) &BufferedRWPair_Type);
-
-    /* BufferedRandom */
-    BufferedRandom_Type.tp_base = &_BufferedIOBase_Type;
-    if (PyType_Ready(&BufferedRandom_Type) < 0)
-        goto fail;
-    Py_INCREF(&BufferedRandom_Type);
-    PyModule_AddObject(m, "BufferedRandom", (PyObject *) &BufferedRandom_Type);
-
-    return m;
-
-  fail:
-    Py_XDECREF(m);
-    return NULL;
-}
+#include <python.h>
+#include "structmember.h"
+#include "pythread.h"
+
+extern PyTypeObject PyFileIO_Type;
+extern PyTypeObject PyBytesIO_Type;
+
+static PyObject *io_py_module;
+
+/* open() uses st_blksize whenever we can */
+#define DEFAULT_BUFFER_SIZE (8 * 1024)  /* bytes */
+
+
+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"
+"seperation between reading and writing to streams; implementations are\n"
+"allowed to throw 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 subc lasses 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"
+    );
+
+
+/*
+ * BlockingIOError extends IOError
+ */
+
+typedef struct {
+    PyException_HEAD
+    PyObject *myerrno;
+    PyObject *strerror;
+    PyObject *filename; /* Not used, but part of the IOError object */
+    Py_ssize_t written;
+} PyBlockingIOErrorObject;
+
+
+static int
+BlockingIOError_init(PyBlockingIOErrorObject *self, PyObject *args,
+                     PyObject *kwds)
+{
+    PyObject *myerrno = NULL, *strerror = NULL, *written;
+    PyObject *baseargs = NULL;
+
+    assert(PyTuple_Check(args));
+
+    if (PyTuple_GET_SIZE(args) <= 1 || PyTuple_GET_SIZE(args) > 3)
+        return 0;
+
+    baseargs = PyTuple_GetSlice(args, 0, 2);
+    if (baseargs == NULL)
+        return -1;
+
+    if (((PyTypeObject*)PyExc_IOError)->tp_init(
+                (PyObject*)self, baseargs, kwds) == -1) {
+        Py_DECREF(baseargs);
+        return -1;
+    }
+
+    Py_DECREF(baseargs);
+
+    if (!PyArg_UnpackTuple(args, "BlockingIOError", 2, 3,
+                           &myerrno, &strerror, &written)) {
+        return -1;
+    }
+
+    Py_INCREF(myerrno);
+    self->myerrno = myerrno;
+
+    Py_INCREF(strerror);
+    self->strerror = strerror;
+
+    self->written = PyNumber_AsSsize_t(written, PyExc_ValueError);
+    if(self->written == -1 && PyErr_Occurred())
+        return -1;
+
+    return 0;
+}
+
+static PyMemberDef BlockingIOError_members[] = {
+    {"characters_written", T_PYSSIZET, offsetof(PyBlockingIOErrorObject, written), 0},
+    {NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject _PyExc_BlockingIOError = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "BlockingIOError", /*tp_name*/
+    sizeof(PyBlockingIOErrorObject), /*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_GC,  /*tp_flags*/
+    PyDoc_STR("Exception raised when I/O would block on a non-blocking I/O stream"), /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    0,                          /* tp_weaklistoffset */
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    0,                          /* tp_methods */
+    BlockingIOError_members,    /* tp_members */
+    0,                          /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    0,                          /* tp_dictoffset */
+    (initproc)BlockingIOError_init, /* tp_init */
+    0,                          /* tp_alloc */
+    0,                          /* tp_new */
+};
+PyObject *PyExc_BlockingIOError = (PyObject *)&_PyExc_BlockingIOError;
+
+
+/*
+ * The main open() function
+ */
+PyDoc_STRVAR(open_doc,
+"Open file and return a stream. If the file cannot be opened, an IOError is\n"
+"raised.\n"
+"\n"
+"file is either a string giving the name (and the path if the file\n"
+"isn't in the current working directory) of the file to be opened or an\n"
+"integer file descriptor of the file to be wrapped. (If a file\n"
+"descriptor is given, it is closed when the returned I/O object is\n"
+"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), and 'a' for appending (which on some Unix systems,\n"
+"means that all writes append to the end of the file regardless of the\n"
+"current seek position). In text mode, if encoding is not specified the\n"
+"encoding used is platform dependent. (For reading and writing raw\n"
+"bytes use binary mode and leave encoding unspecified.) The available\n"
+"modes are:\n"
+"\n"
+"========= ===============================================================\n"
+"Character Meaning\n"
+"--------- ---------------------------------------------------------------\n"
+"'r'       open for reading (default)\n"
+"'w'       open for writing, truncating the file first\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 (for backwards compatibility; unneeded\n"
+"          for new code)\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.\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"
+"buffering is an optional integer used to set the buffering policy. By\n"
+"default full buffering is on. Pass 0 to switch buffering off (only\n"
+"allowed in binary mode), 1 to set line buffering, and an integer > 1\n"
+"for full buffering.\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 for a list of the permitted\n"
+"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 '', no translation takes place. If newline is any of the\n"
+"  other legal values, any '\\n' characters written are translated to\n"
+"  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"
+"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"
+    );
+
+static PyObject *
+io_open(PyObject* self, PyObject *args, PyObject *kwds)
+{
+    char *kwlist[] = {"file", "mode", "buffering",
+                      "encoding", "errors", "newline",
+                      "closefd", NULL};
+    PyObject *file;
+    char *mode = "r";
+    int buffering = -1, closefd = 1;
+    char *encoding = NULL, *errors = NULL, *newline = NULL;
+    unsigned i;
+
+    int reading = 0, writing = 0, appending = 0, updating = 0;
+    int text = 0, binary = 0, universal = 0;
+
+    PyObject *FileIO_class;
+    char rawmode[5], *m;
+    int line_buffering, isatty;
+
+    PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzzi:open", kwlist,
+                                     &file, &mode, &buffering,
+                                     &encoding, &errors, &newline,
+                                     &closefd)) {
+        return NULL;
+    }
+
+    if (!PyUnicode_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 '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 (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;
+        }
+        reading = 1;
+    }
+
+    if (text && binary) {
+        PyErr_SetString(PyExc_ValueError,
+                        "can't have text and binary mode at once");
+        return NULL;
+    }
+
+    if (reading + writing + appending > 1) {
+        PyErr_SetString(PyExc_ValueError,
+                        "must have exactly one of 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 */
+    FileIO_class = PyObject_GetAttrString(io_py_module, "FileIO");
+    if (!FileIO_class)
+        return NULL;
+
+    raw = PyObject_CallFunction(FileIO_class, "Osi", file, rawmode, closefd);
+    Py_DECREF(FileIO_class);
+    if (raw == NULL)
+        return NULL;
+
+    modeobj = PyUnicode_FromString(mode);
+    if (modeobj == NULL)
+        goto error;
+
+    /* buffering */
+    {
+        PyObject *res = PyObject_CallMethod(raw, "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) {
+        buffering = DEFAULT_BUFFER_SIZE;
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+        {
+            struct stat st;
+            long fileno;
+            PyObject *res = PyObject_CallMethod(raw, "fileno", NULL);
+            if (res == NULL)
+                goto error;
+
+            fileno = PyLong_AsLong(res);
+            Py_DECREF(res);
+            if (fileno == -1 && PyErr_Occurred())
+                goto error;
+
+            if (stat(fileno, &st) >= 0)
+                buffering = st->st_blksize;
+        }
+#endif
+    }
+    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;
+        }
+
+        if (PyObject_SetAttrString(raw, "_name", file) < 0)
+            goto error;
+        if (PyObject_SetAttrString(raw, "_mode", modeobj) < 0)
+            goto error;
+        Py_DECREF(modeobj);
+        return raw;
+    }
+
+    /* wraps into a buffered file */
+    {
+        char *Buffered_class_name;
+        PyObject *Buffered_class;
+
+        if (updating)
+            Buffered_class_name = "BufferedRandom";
+        else if (writing || appending)
+            Buffered_class_name = "BufferedWriter";
+        else if (reading)
+            Buffered_class_name = "BufferedReader";
+        else {
+            PyErr_Format(PyExc_ValueError,
+                         "unknown mode: '%s'", mode);
+            goto error;
+        }
+
+        Buffered_class = PyObject_GetAttrString(io_py_module,
+                                                Buffered_class_name);
+        if (Buffered_class == NULL)
+            goto error;
+
+        buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
+        Py_DECREF(Buffered_class);
+    }
+    Py_CLEAR(raw);
+    if (buffer == NULL)
+        goto error;
+
+
+    /* if binary, returns the buffered file */
+    if (binary) {
+        if (PyObject_SetAttrString(buffer, "_name", file) < 0)
+            goto error;
+        if (PyObject_SetAttrString(buffer, "_mode", modeobj) < 0)
+            goto error;
+        Py_DECREF(modeobj);
+        return buffer;
+    }
+
+    /* wraps into a TextIOWrapper */
+    {
+        PyObject *TextIOWrapper_class;
+        TextIOWrapper_class = PyObject_GetAttrString(io_py_module,
+                                                     "TextIOWrapper");
+        if (TextIOWrapper_class == NULL)
+            goto error;
+
+        wrapper = PyObject_CallFunction(TextIOWrapper_class, "Osssi",
+                                        buffer,
+                                        encoding, errors, newline,
+                                        line_buffering);
+        Py_DECREF(TextIOWrapper_class);
+    }
+    Py_CLEAR(buffer);
+    if (wrapper == NULL)
+        goto error;
+
+    if (PyObject_SetAttrString(wrapper, "name", file) < 0)
+        goto error;
+    if (PyObject_SetAttrString(wrapper, "mode", modeobj) < 0)
+        goto error;
+    Py_DECREF(modeobj);
+    return wrapper;
+
+  error:
+    Py_XDECREF(raw);
+    Py_XDECREF(modeobj);
+    Py_XDECREF(buffer);
+    Py_XDECREF(wrapper);
+    return NULL;
+}
+
+
+static PyObject* PyExc_UnsupportedOperation;
+
+/*
+ * IOBase class, an abstract class
+ */
+
+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 a IOError when operations they do not support are 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 (even inquiries) on a closed stream is\n"
+    "undefined. Implementations may raise IOError in this case.\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 statment is complete:\n"
+    "\n"
+    "with open('spam.txt', 'r') as fp:\n"
+    "    fp.write('Spam and eggs!')\n");
+
+/* Internal methods */
+static PyObject *
+IOBase_unsupported(const char* message)
+{
+    PyErr_SetString(PyExc_UnsupportedOperation, message);
+    return NULL;
+}
+
+/* Positionning */
+
+PyDoc_STRVAR(IOBase_seek_doc,
+    "Change stream position.\n"
+    "\n"
+    "Change the stream position to byte offset offset. 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.");
+
+static PyObject*
+IOBase_seek(PyObject *self, PyObject *args)
+{
+    return IOBase_unsupported("seek");
+}
+
+PyDoc_STRVAR(IOBase_tell_doc,
+             "Return current stream position.");
+
+static PyObject *
+IOBase_tell(PyObject *self, PyObject *args)
+{
+    return PyObject_CallMethod(self, "tell", "ii", 0, 1);
+}
+
+PyDoc_STRVAR(IOBase_truncate_doc,
+    "Truncate file to size bytes.\n"
+    "\n"
+    "Size defaults to the current IO position as reported by tell().  Return\n"
+    "the new size.");
+
+static PyObject*
+IOBase_truncate(PyObject *self, PyObject *args)
+{
+    return IOBase_unsupported("seek");
+}
+
+/* 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");
+
+static PyObject*
+IOBase_flush(PyObject *self, PyObject *args)
+{
+    /* XXX Should this return the number of bytes written??? */
+    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)
+{
+    return PyObject_HasAttrString(self, "__IOBase_closed");
+}
+
+static PyObject *
+IOBase_closed_get(PyObject *self, void *context)
+{
+    return PyBool_FromLong(IOBase_closed(self));
+}
+
+
+static PyObject *
+IOBase_checkClosed(PyObject *self, PyObject *unused)
+{
+    if (IOBase_closed(self)) {
+        PyErr_SetString(PyExc_ValueError, "I/O operation on closed file.");
+        return NULL;
+    }
+    Py_RETURN_NONE;
+}
+
+static PyObject*
+IOBase_close(PyObject *self, PyObject *args)
+{
+    PyObject *res;
+
+    if (IOBase_closed(self))
+        Py_RETURN_NONE;
+
+    PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
+
+    res = PyObject_CallMethod(self, "flush", NULL);
+    if (res == NULL) {
+        /* If flush() fails, just give up */
+        if (PyErr_ExceptionMatches(PyExc_IOError))
+            PyErr_Clear();
+        else
+            return NULL;
+    }
+    Py_RETURN_NONE;
+}
+
+static void
+IOBase_del(PyObject *self)
+{
+    PyObject *res = PyObject_CallMethod(self, "flush", NULL);
+    if (res == NULL) {
+        /* At program exit time, it's possible that globals have already been
+         *  deleted, and then the close() call might fail.  Since there's
+         *  nothing we can do about such failures and they annoy the end
+         *  users, we suppress the traceback.
+         */
+        PyErr_Clear();
+    }
+}
+
+/* Inquiry methods */
+
+PyDoc_STRVAR(IOBase_seekable_doc,
+    "Return whether object supports random access.\n"
+    "\n"
+    "If False, seek(), tell() and truncate() will raise IOError.\n"
+    "This method may need to do a test seek().");
+
+static PyObject*
+IOBase_seekable(PyObject *self, PyObject *args)
+{
+    Py_RETURN_FALSE;
+}
+
+static PyObject*
+IOBase_checkSeekable(PyObject *self, PyObject *unused)
+{
+    PyObject *res  = PyObject_CallMethod(self, "seekable", NULL);
+    if (res == NULL)
+        return NULL;
+    if (res != Py_True) {
+        Py_CLEAR(res);
+        PyErr_SetString(PyExc_IOError, "File or stream is not seekable.");
+    }
+    return res;
+}
+
+PyDoc_STRVAR(IOBase_readable_doc,
+    "Return whether object was opened for reading.\n"
+    "\n"
+    "If False, read() will raise IOError.");
+
+static PyObject*
+IOBase_readable(PyObject *self, PyObject *args)
+{
+    Py_RETURN_FALSE;
+}
+
+/* May be called with any object */
+static PyObject*
+IOBase_checkReadable(PyObject *self, PyObject *unused)
+{
+    PyObject *res  = PyObject_CallMethod(self, "readable", NULL);
+    if (res == NULL)
+        return NULL;
+    if (res != Py_True) {
+        Py_CLEAR(res);
+        PyErr_SetString(PyExc_IOError, "File or stream is not readable.");
+    }
+    return res;
+}
+
+PyDoc_STRVAR(IOBase_writable_doc,
+    "Return whether object was opened for writing.\n"
+    "\n"
+    "If False, read() will raise IOError.");
+
+static PyObject*
+IOBase_writable(PyObject *self, PyObject *args)
+{
+    Py_RETURN_FALSE;
+}
+
+/* May be called with any object */
+static PyObject*
+IOBase_checkWritable(PyObject *self, PyObject *unused)
+{
+    PyObject *res  = PyObject_CallMethod(self, "writable", NULL);
+    if (res == NULL)
+        return NULL;
+    if (res != Py_True) {
+        Py_CLEAR(res);
+        PyErr_SetString(PyExc_IOError, "File or stream is not writable.");
+    }
+    return res;
+}
+
+/* Context manager */
+
+static PyObject *
+IOBase_enter(PyObject *self, PyObject *args)
+{
+    if (IOBase_checkClosed(self, NULL) == NULL)
+        return NULL;
+
+    Py_INCREF(self);
+    return self;
+}
+
+static PyObject *
+IOBase_exit(PyObject *self, PyObject *args)
+{
+    return PyObject_CallMethod(self, "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 (IOBase_checkClosed(self, NULL) == 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;
+
+    if (!PyArg_ParseTuple(args, "|n:readline", &limit)) {
+        return NULL;
+    }
+
+    if (IOBase_checkClosed(self, NULL) == NULL)
+        return NULL;
+
+    if (PyObject_HasAttrString(self, "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_CallMethod(self, "peek", "i", 1);
+
+            assert (PyBytes_Check(readahead));
+
+            if (readahead == NULL)
+                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')
+                        {
+                            n++;
+                            break;
+                        }
+                        n++;
+                    } while (1);
+                }
+                else {
+                    do {
+                        if (n >= PyBytes_GET_SIZE(readahead))
+                            break;
+                        if (buf[n] == '\n')
+                        {
+                            n++;
+                            break;
+                        }
+                        n++;
+                    } while (1);
+                }
+                nreadahead = n;
+            }
+        }
+
+        b = PyObject_CallMethod(self, "read", "n", nreadahead);
+
+        if (b == NULL)
+            goto fail;
+
+        assert (PyBytes_Check(b));
+
+        if (Py_SIZE(b) == 0)
+            break;
+
+        old_size = Py_SIZE(buffer);
+        PyByteArray_Resize(buffer, old_size + Py_SIZE(b));
+        memcpy(PyByteArray_AS_STRING(buffer) + old_size, PyBytes_AS_STRING(b), Py_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, PyObject *args)
+{
+    if (IOBase_checkClosed(self, NULL) == NULL)
+        return NULL;
+
+    Py_INCREF(self);
+    return self;
+}
+
+static PyObject *
+IOBase_next(PyObject *self, PyObject *args)
+{
+    PyObject *line = PyObject_CallMethod(self, "readline", NULL);
+
+    if (line == NULL)
+        return NULL;
+
+    assert (PyBytes_Check(line));
+
+    if (PyBytes_GET_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 *line, *result;
+
+    if (!PyArg_ParseTuple(args, "|n:readlines", &hint)) {
+        return NULL;
+    }
+
+    result = PyList_New(0);
+    if (result == NULL)
+        return NULL;
+
+    if (hint <= 0) {
+        PyObject *ret = PyObject_CallMethod(result, "extend", "O", self);
+        if( ret == NULL) {
+            Py_DECREF(result);
+            return NULL;
+        }
+        Py_DECREF(ret);
+        return result;
+    }
+
+    while (1) {
+        line = PyObject_CallMethod(self, "__next__", NULL);
+        if (line == NULL) {
+            if (PyErr_Occurred()) {
+                Py_DECREF(result);
+                return NULL;
+            }
+            else
+                break; /* SopIteration raised */
+        }
+        assert (PyBytes_Check(line));
+
+        if (PyList_Append(result, line) < 0) {
+            Py_DECREF(line);
+            Py_DECREF(result);
+            return NULL;
+        }
+        length += Py_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 (IOBase_checkClosed(self, NULL) == 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 = PyObject_CallMethod(self, "write", "O", line);
+        Py_DECREF(line);
+        if (res == NULL) {
+            Py_DECREF(iter);
+            return NULL;
+        }
+        Py_DECREF(res);
+    }
+    Py_RETURN_NONE;
+}
+
+static PyMethodDef IOBase_methods[] = {
+    {"seek", IOBase_seek, METH_VARARGS},
+    {"tell", IOBase_tell, METH_NOARGS},
+    {"truncate", IOBase_truncate, METH_VARARGS},
+    {"flush", IOBase_flush, METH_NOARGS},
+    {"close", IOBase_close, METH_NOARGS},
+
+    {"seekable", IOBase_seekable, METH_NOARGS},
+    {"readable", IOBase_readable, METH_NOARGS},
+    {"writable", IOBase_writable, METH_NOARGS},
+
+    {"_checkClosed",   IOBase_checkClosed, METH_NOARGS},
+    {"_checkSeekable", IOBase_checkSeekable, METH_NOARGS},
+    {"_checkReadable", IOBase_checkReadable, METH_NOARGS},
+    {"_checkWritable", IOBase_checkWritable, METH_NOARGS},
+
+    {"fileno", IOBase_fileno, METH_NOARGS},
+    {"isatty", IOBase_isatty, METH_NOARGS},
+
+    {"__enter__", IOBase_enter, METH_NOARGS},
+    {"__exit__", IOBase_exit, METH_VARARGS},
+
+    {"__iter__", IOBase_iter, METH_NOARGS},
+    {"__next__", IOBase_next, METH_NOARGS},
+
+    {"readline", IOBase_readline, METH_VARARGS},
+    {"readlines", IOBase_readlines, METH_VARARGS},
+    {"writelines", IOBase_readlines, METH_VARARGS},
+
+    {NULL, NULL}
+};
+
+static PyGetSetDef IOBase_getset[] = {
+    {"closed", (getter)IOBase_closed_get, NULL, NULL},
+    {0}
+};
+
+
+PyTypeObject _IOBase_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "IOBase",                   /*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,  /*tp_flags*/
+    IOBase_doc,                 /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    0,                          /* tp_weaklistoffset */
+    0,                          /* tp_iter */
+    0,                          /* 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 */
+    0,                          /* 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 */
+    IOBase_del,                 /* tp_del */
+};
+PyObject *PyIOBase = (PyObject*)&_IOBase_Type;
+
+
+
+/*
+ * 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)
+        return PyObject_CallMethod(self, "readall", NULL);
+
+    b = PyByteArray_FromStringAndSize(NULL, n);
+    if (b == NULL)
+        return NULL;
+
+    res = PyObject_CallMethod(self, "readinto", "O", b);
+    if (res == NULL) {
+        Py_DECREF(b);
+        return NULL;
+    }
+
+    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)
+{
+    PyObject *b = NULL;
+    Py_ssize_t cursize = 0;
+
+    while (1) {
+        Py_ssize_t length;
+        PyObject *data = PyObject_CallMethod(self, "read",
+                                             "i", DEFAULT_BUFFER_SIZE);
+
+        if (!data) {
+            Py_XDECREF(b);
+            return NULL;
+        }
+
+        if (!PyBytes_Check(data)) {
+            Py_XDECREF(b);
+            Py_DECREF(data);
+            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+            return NULL;
+        }
+
+        length = Py_SIZE(data);
+
+        if (b == NULL)
+            b = data;
+        else if (length != 0) {
+
+            _PyBytes_Resize(&b, cursize + length);
+            if (b == NULL) {
+                Py_DECREF(data);
+                return NULL;
+            }
+
+            memcpy(PyBytes_AS_STRING(b) + cursize,
+                   PyBytes_AS_STRING(data), length);
+            Py_DECREF(data);
+        }
+
+        if (length == 0)
+            break;
+    }
+
+    return b;
+
+}
+
+static PyMethodDef RawIOBase_methods[] = {
+    {"read", RawIOBase_read, METH_VARARGS},
+    {"readall", RawIOBase_readall, METH_NOARGS, RawIOBase_readall_doc},
+    {NULL, NULL}
+};
+
+PyTypeObject _RawIOBase_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "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,  /*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 */
+    &_IOBase_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 */
+};
+PyObject *PyRawIOBase = (PyObject*)&_RawIOBase_Type;
+
+
+/*
+ * 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"
+    );
+
+static PyObject *
+BufferedIOBase_readinto(PyObject *self, PyObject *args)
+{
+    Py_buffer buf;
+    Py_ssize_t len;
+    PyObject *data;
+
+    if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) {
+        return NULL;
+    }
+
+    data = PyObject_CallMethod(self, "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);
+    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;
+}
+
+static PyMethodDef BufferedIOBase_methods[] = {
+    {"readinto", BufferedIOBase_readinto, METH_VARARGS},
+    {NULL, NULL}
+};
+
+PyTypeObject _BufferedIOBase_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "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,  /*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 */
+    &_IOBase_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 */
+};
+
+
+typedef struct {
+    PyObject_HEAD
+
+    PyObject *raw;
+
+    PyObject *name;
+    PyObject *mode;
+
+    PyObject *read_buf;
+    Py_ssize_t read_pos;
+    PyThread_type_lock read_lock;
+
+    PyObject *write_buf;
+    PyThread_type_lock write_lock;
+
+    Py_ssize_t buffer_size;
+    Py_ssize_t max_buffer_size;
+
+    PyObject *dict;
+    PyObject *weakreflist;
+} BufferedObject;
+
+static void
+BufferedObject_dealloc(BufferedObject *self)
+{
+    if (self->weakreflist != NULL)
+        PyObject_ClearWeakRefs((PyObject *)self);
+    Py_CLEAR(self->raw);
+    Py_CLEAR(self->name);
+    Py_CLEAR(self->mode);
+    Py_CLEAR(self->read_buf);
+    Py_CLEAR(self->write_buf);
+    Py_CLEAR(self->dict);
+}
+
+
+/*
+ * _BufferedIOMixin methods
+ * This is not a class, just a collection of methods that will be reused
+ * by BufferedReader and BufferedWriter
+ */
+
+/* Positioning */
+
+static PyObject*
+BufferedIOMixin_truncate(BufferedObject *self, PyObject *args)
+{
+    PyObject *pos = Py_None;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
+        return NULL;
+    }
+
+    /* Flush the stream.  We're mixing buffered I/O with lower-level I/O,
+     * and a flush may be necessary to synch both views of the current
+     *  file state.
+     */
+    res = PyObject_CallMethod(self->raw, "flush", NULL);
+    if (res == NULL)
+        return NULL;
+    Py_DECREF(res);
+
+    if (pos == Py_None)
+        pos = PyObject_CallMethod(self->raw, "tell", NULL);
+    else
+        Py_INCREF(pos);
+
+    /* XXX: Should seek() be used, instead of passing the position
+     * XXX  directly to truncate?
+     */
+    res = PyObject_CallMethod(self->raw, "truncate", "O", pos);
+    Py_DECREF(pos);
+
+    return res;
+}
+
+/* Flush and close */
+
+static PyObject*
+BufferedIOMixin_flush(BufferedObject *self, PyObject *args)
+{
+    return PyObject_CallMethod(self->raw, "flush", NULL);
+}
+
+static int
+BufferedIOMixin_closed(BufferedObject *self)
+{
+    int closed;
+    PyObject *res = PyObject_GetAttrString(self->raw, "closed");
+    if (res == NULL)
+        return 0;
+    closed = PyObject_IsTrue(res);
+    Py_DECREF(res);
+    return closed;
+}
+
+static PyObject *
+BufferedIOMixin_closed_get(BufferedObject *self, void *context)
+{
+    return PyObject_GetAttrString(self->raw, "closed");
+}
+
+
+static PyObject*
+BufferedIOMixin_close(BufferedObject *self, PyObject *args)
+{
+    PyObject *res;
+
+    if (BufferedIOMixin_closed(self))
+        Py_RETURN_NONE;
+
+    res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
+    if (res == NULL) {
+        /* If flush() fails, just give up */
+        if (PyErr_ExceptionMatches(PyExc_IOError))
+            PyErr_Clear();
+        else
+            return NULL;
+    }
+
+    return PyObject_CallMethod(self->raw, "close", NULL);
+}
+
+/* Inquiries */
+
+static PyObject*
+BufferedIOMixin_seekable(BufferedObject *self, PyObject *args)
+{
+    return PyObject_CallMethod(self->raw, "seekable", NULL);
+}
+
+static PyObject*
+BufferedIOMixin_readable(BufferedObject *self, PyObject *args)
+{
+    return PyObject_CallMethod(self->raw, "readable", NULL);
+}
+
+static PyObject*
+BufferedIOMixin_writable(BufferedObject *self, PyObject *args)
+{
+    return PyObject_CallMethod(self->raw, "writable", NULL);
+}
+
+/* Lower-level APIs */
+
+static PyObject*
+BufferedIOMixin_fileno(BufferedObject *self, PyObject *args)
+{
+    return PyObject_CallMethod(self->raw, "fileno", NULL);
+}
+
+static PyObject*
+BufferedIOMixin_isatty(BufferedObject *self, PyObject *args)
+{
+    return PyObject_CallMethod(self->raw, "isatty", NULL);
+}
+
+
+/*
+ * class BufferedReader
+ */
+
+PyDoc_STRVAR(BufferedReader_doc,
+             "Create a new buffered reader using the given readable raw IO object.");
+
+static int _BufferedReader_reset_read_buf(BufferedObject *self)
+{
+    PyObject *oldbuf = self->read_buf;
+
+    self->read_buf = PyBytes_FromStringAndSize(NULL, 0);
+    self->read_pos = 0;
+
+    Py_XDECREF(oldbuf);
+
+    if (self->read_buf == NULL)
+        return -1;
+
+    return 0;
+}
+
+static int
+BufferedReader_init(BufferedObject *self, PyObject *args, PyObject *kwds)
+{
+    char *kwlist[] = {"raw", "buffer_size", NULL};
+    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+    PyObject *raw;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist,
+                                     &raw, &buffer_size)) {
+        return -1;
+    }
+
+    if (IOBase_checkReadable(raw, NULL) == NULL)
+        return -1;
+
+    Py_INCREF(raw);
+    self->raw = raw;
+
+    self->buffer_size = buffer_size;
+    self->read_buf = NULL;
+
+    if( _BufferedReader_reset_read_buf(self) < 0)
+        return -1;
+
+    self->read_lock = PyThread_allocate_lock();
+    if (self->read_lock == NULL) {
+                PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
+        return -1;
+    }
+
+    return 0;
+}
+
+static PyObject *
+_BufferedReader_read_unlocked(BufferedObject *self, Py_ssize_t n)
+{
+    PyObject *nodata_val = NULL;
+    PyObject *empty_values = NULL;
+
+    PyObject *buf = self->read_buf;
+    Py_ssize_t pos = self->read_pos;
+    PyObject *data, *chunks, *sep, *res;
+    Py_ssize_t current_size;
+
+    /* Special case for when the number of bytes to read is unspecified. */
+    if (n == -1) {
+        chunks = PyList_New(0);
+        if (chunks == NULL)
+            return NULL;
+
+                Py_INCREF(buf);
+        if (_BufferedReader_reset_read_buf(self) < 0)
+            return NULL;
+
+        /* Strip the consumed bytes */
+        current_size = Py_SIZE(buf) - pos;
+        data = NULL;
+        if (current_size) {
+            data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
+            if (data == NULL) {
+                                Py_DECREF(buf);
+                Py_DECREF(chunks);
+                return NULL;
+            }
+                        Py_DECREF(buf);
+        }
+
+        while (1) {
+            if (data) {
+                if (PyList_Append(chunks, data) < 0) {
+                    Py_DECREF(data);
+                    Py_DECREF(chunks);
+                    return NULL;
+                }
+                Py_DECREF(data);
+            }
+
+            /* Read until EOF or until read() would block. */
+            data = PyObject_CallMethod(self->raw, "read", NULL);
+
+            if (data == NULL) {
+                Py_DECREF(chunks);
+                return NULL;
+            }
+
+            if (data != Py_None && !PyBytes_Check(data)) {
+                Py_DECREF(data);
+                Py_DECREF(chunks);
+                PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+                return NULL;
+            }
+
+            if (data == Py_None || Py_SIZE(data) == 0) {
+                if (current_size == 0) {
+                    Py_DECREF(chunks);
+                    return data;
+                }
+                else {
+                    Py_DECREF(data);
+                    sep = PyBytes_FromStringAndSize(NULL, 0);
+
+                    if (sep == NULL) {
+                        Py_DECREF(chunks);
+                        return NULL;
+                    }
+                    res =_PyBytes_Join(sep, chunks);
+                    Py_DECREF(sep);
+                    Py_DECREF(chunks);
+
+                    return res;
+                }
+            }
+
+                        current_size += Py_SIZE(data);
+        }
+    }
+
+    /* The number of bytes to read is specified, return at most n bytes. */
+
+    current_size = Py_SIZE(buf) - pos; /* Length of the available buffered data. */
+    if (n <= current_size) {
+        /* Fast path: the data to read is fully buffered. */
+        self->read_pos += n;
+        return PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, n);
+    }
+
+    /* Slow path: read from the stream until enough bytes are read,
+     * or until an EOF occurs or until read() would block.
+     */
+    chunks = PyList_New(0);
+    if (chunks == NULL)
+        return NULL;
+
+    data = NULL;
+
+    if (current_size)
+        data = PyBytes_FromStringAndSize(PyBytes_AS_STRING(buf) + pos, current_size);
+
+    while (1) {
+        Py_ssize_t wanted;
+
+        if (data) {
+            if (PyList_Append(chunks, data) < 0) {
+                Py_DECREF(data);
+                Py_DECREF(chunks);
+                return NULL;
+            }
+            Py_DECREF(data);
+        }
+
+                if (current_size >= n)
+                        break;
+
+                wanted = n;
+        if (wanted < self->buffer_size)
+            wanted = self->buffer_size;
+
+        data = PyObject_CallMethod(self->raw, "read", "n", wanted);
+
+        if (data != Py_None && !PyBytes_Check(data)) {
+            Py_DECREF(data);
+            Py_DECREF(chunks);
+            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+            return NULL;
+        }
+
+        if (data == Py_None || Py_SIZE(data) == 0) {
+            /* EOF occurred or read() would block. */
+
+            if (current_size == 0) {
+                Py_DECREF(chunks);
+
+                if( _BufferedReader_reset_read_buf(self) < 0) {
+                    Py_DECREF(data);
+                    return NULL;
+                }
+
+                return data;
+            }
+            else {
+                            Py_DECREF(data);
+                break;
+            }
+        }
+
+                current_size += Py_SIZE(data);
+    }
+
+    sep = PyBytes_FromStringAndSize(NULL, 0);
+
+    if (sep == NULL) {
+        Py_DECREF(chunks);
+        return NULL;
+    }
+
+    res =_PyBytes_Join(sep, chunks);
+    Py_DECREF(sep);
+    Py_DECREF(chunks);
+
+    if (Py_SIZE(res) > n) {
+        /* Save the extra data in the buffer. */
+        self->read_pos = 0;
+        buf = self->read_buf;
+        self->read_buf = PyBytes_FromStringAndSize(PyBytes_AS_STRING(res) + n, Py_SIZE(res) - n);
+        Py_DECREF(buf);
+        if (self->read_buf == NULL) {
+            Py_DECREF(res);
+            return NULL;
+        }
+
+        /* Truncate the result to the desired length */
+        buf = PyBytes_FromStringAndSize(PyBytes_AS_STRING(res), n);
+        if (buf == NULL) {
+            Py_DECREF(res);
+            return NULL;
+        }
+
+        Py_DECREF(res);
+        res = buf;
+    }
+
+    return res;
+}
+
+static PyObject *
+BufferedReader_read(BufferedObject *self, PyObject *args)
+{
+    Py_ssize_t n = -1;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "|n:read", &n)) {
+        return NULL;
+    }
+
+    Py_BEGIN_ALLOW_THREADS
+    PyThread_acquire_lock(self->read_lock, 1);
+    Py_END_ALLOW_THREADS
+
+    res = _BufferedReader_read_unlocked(self, n);
+
+    PyThread_release_lock(self->read_lock);
+
+    return res;
+}
+
+static PyObject *
+_BufferedReader_peek_unlocked(BufferedObject *self, Py_ssize_t n)
+{
+    Py_ssize_t have;
+
+    if (n > self->buffer_size)
+        n = self->buffer_size;
+
+    have = Py_SIZE(self->read_buf) - self->read_pos;
+
+    if (have < n) {
+        Py_ssize_t to_read = self->buffer_size - have;
+        PyObject *current = PyObject_CallMethod(self->raw, "read", "n", to_read);
+
+        if (current == NULL)
+            return NULL;
+
+        if (!PyBytes_Check(current)) {
+            Py_DECREF(current);
+            PyErr_SetString(PyExc_TypeError, "read() should return bytes");
+            return NULL;
+        }
+
+        if (Py_SIZE(current) > 0) {
+            PyObject *oldbuf = self->read_buf;
+            self->read_buf = PyBytes_FromStringAndSize(NULL, have + Py_SIZE(current));
+            memcpy(PyBytes_AS_STRING(self->read_buf), PyBytes_AS_STRING(oldbuf) + self->read_pos, have);
+            memcpy(PyBytes_AS_STRING(self->read_buf) + have, PyBytes_AS_STRING(current), Py_SIZE(current));
+            self->read_pos = 0;
+        }
+        Py_DECREF(current);
+    }
+
+    if (self->read_pos == 0) {
+        Py_INCREF(self->read_buf);
+        return self->read_buf;
+    }
+    else {
+        return PyBytes_FromStringAndSize(
+            PyBytes_AS_STRING(self->read_buf) + self->read_pos,
+            Py_SIZE(self->read_buf) - self->read_pos);
+    }
+}
+
+static PyObject *
+BufferedReader_peek(BufferedObject *self, PyObject *args)
+{
+    Py_ssize_t n = 0;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "|n:peek", &n)) {
+        return NULL;
+    }
+
+        Py_BEGIN_ALLOW_THREADS
+        PyThread_acquire_lock(self->read_lock, 1);
+        Py_END_ALLOW_THREADS
+
+    res = _BufferedReader_peek_unlocked(self, n);
+
+    PyThread_release_lock(self->read_lock);
+
+    return res;
+}
+
+static PyObject *
+BufferedReader_read1(BufferedObject *self, PyObject *args)
+{
+    Py_ssize_t n, have;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "n:read1", &n)) {
+        return NULL;
+    }
+
+    if (n <= 0)
+        return PyBytes_FromStringAndSize(NULL, 0);
+
+        Py_BEGIN_ALLOW_THREADS
+        PyThread_acquire_lock(self->read_lock, 1);
+        Py_END_ALLOW_THREADS
+
+    res = _BufferedReader_peek_unlocked(self, 1);
+    if(res == NULL)
+        goto end;
+    Py_DECREF(res);
+
+    have = Py_SIZE(self->read_buf) - self->read_pos;
+    if (n > have)
+        n = have;
+
+    res = _BufferedReader_read_unlocked(self, n);
+
+  end:
+    PyThread_release_lock(self->read_lock);
+
+    return res;
+}
+
+static PyObject*
+BufferedReader_seek(BufferedObject *self, PyObject *args)
+{
+    Py_ssize_t pos;
+    int whence = 0;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
+        return NULL;
+    }
+
+    Py_BEGIN_ALLOW_THREADS
+    PyThread_acquire_lock(self->read_lock, 1);
+    Py_END_ALLOW_THREADS
+
+    if (whence == 1) {
+        pos -= Py_SIZE(self->read_buf) - self->read_pos;
+    }
+
+    res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
+    if (res == NULL)
+        return NULL;
+
+    if (_BufferedReader_reset_read_buf(self) < 0)
+        Py_CLEAR(res);
+
+    PyThread_release_lock(self->read_lock);
+
+    return res;
+}
+
+static PyObject*
+BufferedReader_tell(BufferedObject *self, PyObject *args)
+{
+    PyObject *op1, *op2, *res;
+
+    op1 = PyObject_CallMethod(self->raw, "tell", NULL);
+
+    if (op1 == NULL)
+        return NULL;
+
+    op2 = PyLong_FromSsize_t(Py_SIZE(self->read_buf) - self->read_pos);
+    if (op2 == NULL) {
+        Py_DECREF(op1);
+        return NULL;
+    }
+
+    res = PyNumber_Subtract(op1, op2);
+    Py_DECREF(op1);
+    Py_DECREF(op2);
+    return res;
+}
+
+static PyMethodDef BufferedReader_methods[] = {
+    /* BufferedIOMixin methods */
+    {"truncate", (PyCFunction)BufferedIOMixin_truncate, METH_VARARGS},
+    {"flush", (PyCFunction)BufferedIOMixin_flush, METH_NOARGS},
+    {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
+    {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
+    {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
+    {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
+    {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
+    {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
+
+    {"read", (PyCFunction)BufferedReader_read, METH_VARARGS},
+    {"peek", (PyCFunction)BufferedReader_peek, METH_VARARGS},
+    {"read1", (PyCFunction)BufferedReader_read1, METH_VARARGS},
+    {"seek", (PyCFunction)BufferedReader_seek, METH_VARARGS},
+    {"tell", (PyCFunction)BufferedReader_tell, METH_NOARGS},
+    {NULL, NULL}
+};
+
+static PyMemberDef BufferedReader_members[] = {
+    {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
+    {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
+    {NULL}
+};
+
+static PyGetSetDef BufferedReader_getset[] = {
+    {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
+    {0}
+};
+
+
+PyTypeObject BufferedReader_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "BufferedReader",           /*tp_name*/
+    sizeof(BufferedObject),     /*tp_basicsize*/
+    0,                          /*tp_itemsize*/
+    (destructor)BufferedObject_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*/
+    BufferedReader_doc,         /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+        offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
+    0,                          /* tp_iter */
+    0,                          /* 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(BufferedObject, dict), /* tp_dictoffset */
+    (initproc)BufferedReader_init, /* tp_init */
+    0,                          /* tp_alloc */
+    PyType_GenericNew,          /* tp_new */
+};
+
+
+/*
+ * 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"
+    "DEAFULT_BUFFER_SIZE. If max_buffer_size is omitted, it defaults to\n"
+    "twice the buffer size.\n"
+    );
+
+static int
+BufferedWriter_init(BufferedObject *self, PyObject *args, PyObject *kwds)
+{
+    char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
+    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+    Py_ssize_t max_buffer_size = -1;
+    PyObject *raw;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist,
+                                     &raw, &buffer_size, &max_buffer_size)) {
+        return -1;
+    }
+
+    if (IOBase_checkWritable(raw, NULL) == NULL)
+        return -1;
+
+    Py_INCREF(raw);
+    self->raw = raw;
+
+    if (max_buffer_size < 0)
+        max_buffer_size = buffer_size * 2;
+    self->buffer_size = buffer_size;
+    self->max_buffer_size = max_buffer_size;
+
+        self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
+    if (self->write_buf == NULL)
+        return -1;
+
+    self->write_lock = PyThread_allocate_lock();
+    if (self->write_lock == NULL) {
+                PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
+        return -1;
+    }
+
+    return 0;
+}
+
+static PyObject *
+_BufferedWriter_flush_unlocked(BufferedObject *self)
+{
+    Py_ssize_t written = 0;
+
+    if (BufferedIOMixin_closed(self)) {
+        PyErr_SetString(PyExc_ValueError, "flush of closed file");
+        return NULL;
+    }
+
+    while (Py_SIZE(self->write_buf) > 0) {
+        PyObject *slice, *res;
+        Py_ssize_t w;
+        PyObject *n = PyObject_CallMethod(self->raw, "write", "O", self->write_buf);
+
+        if (n == NULL) {
+            PyObject *type, *value, *traceback;
+            PyErr_Fetch(&type, &value, &traceback);
+
+            if (value == NULL ||
+                !PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
+                PyErr_Restore(type, value, traceback);
+                return NULL;
+            }
+
+            w = ((PyBlockingIOErrorObject *)value)->written;
+
+            /* del self->write_buf[:w] */
+            slice = _PySlice_FromIndices(0, w);
+            if (slice == NULL)
+                return NULL;
+            res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
+            Py_DECREF(slice);
+            if (res == NULL)
+                return NULL;
+            Py_DECREF(res);
+
+            written += w;
+            ((PyBlockingIOErrorObject *)value)->written = written;
+
+            PyErr_Restore(type, value, traceback);
+            return NULL;
+        }
+
+        /* del self->write_buf[:w] */
+        w = PyNumber_AsSsize_t(n, PyExc_ValueError);
+        Py_DECREF(n);
+        if (w == -1 && PyErr_Occurred())
+            return NULL;
+
+        slice = _PySlice_FromIndices(0, w);
+        if (slice == NULL)
+            return NULL;
+        res = PyObject_CallMethod(self->write_buf, "__delitem__", "O", slice);
+        Py_DECREF(slice);
+        if (res == NULL)
+            return NULL;
+        Py_DECREF(res);
+
+        written += w;
+    }
+
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+BufferedWriter_write(BufferedObject *self, PyObject *args)
+{
+    PyObject *res;
+    Py_buffer buf;
+    Py_ssize_t before, written;
+
+    if (!PyArg_ParseTuple(args, "y*:write", &buf)) {
+        return NULL;
+    }
+
+    if (BufferedIOMixin_closed(self)) {
+        PyErr_SetString(PyExc_ValueError, "write to closed file");
+        PyBuffer_Release(&buf);
+        return NULL;
+    }
+
+        Py_BEGIN_ALLOW_THREADS
+        PyThread_acquire_lock(self->write_lock, 1);
+        Py_END_ALLOW_THREADS
+
+    /* XXX we can implement some more tricks to try and avoid
+     * partial writes
+     */
+
+    if (Py_SIZE(self->write_buf) > self->buffer_size) {
+        /* We're full, so let's pre-flush the buffer*/
+        res = _BufferedWriter_flush_unlocked(self);
+        if (res == NULL) {
+            /* We can't accept anything else. */
+            PyObject *type, *value, *traceback;
+            PyErr_Fetch(&type, &value, &traceback);
+
+            if (value != NULL &&
+                PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
+                ((PyBlockingIOErrorObject *)value)->written = 0;
+            }
+
+            PyErr_Restore(type, value, traceback);
+            goto fail;
+        }
+    }
+
+    written = buf.len;
+
+    before = Py_SIZE(self->write_buf);
+    if (PyByteArray_Resize(self->write_buf, before + written) < 0) {
+        res = NULL;
+        goto fail;
+    }
+    memcpy(PyByteArray_AS_STRING(self->write_buf) + before, buf.buf, written);
+
+    if (Py_SIZE(self->write_buf) > self->buffer_size) {
+        res = _BufferedWriter_flush_unlocked(self);
+        if (res == NULL) {
+            PyObject *type, *value, *traceback;
+            PyErr_Fetch(&type, &value, &traceback);
+
+            if (value != NULL &&
+                PyErr_GivenExceptionMatches(value, PyExc_BlockingIOError)) {
+
+                Py_ssize_t overage =
+                    Py_SIZE(self->write_buf) - self->max_buffer_size;
+
+                if (overage > 0) {
+                    /* We've hit max_buffer_size. We have to accept a
+                     * partial write and cut back our buffer.
+                     */
+                    if (PyByteArray_Resize(self->write_buf, self->max_buffer_size) < 0)
+                        goto fail;
+                    ((PyBlockingIOErrorObject *)value)->written = overage;
+                }
+                else
+                {
+                    Py_CLEAR(type);
+                    Py_CLEAR(value);
+                    Py_CLEAR(traceback);
+                    goto end;
+                }
+            }
+
+            PyErr_Restore(type, value, traceback);
+            goto fail;
+        }
+    }
+
+  end:
+    res = PyLong_FromSsize_t(written);
+
+  fail:
+    PyThread_release_lock(self->write_lock);
+    PyBuffer_Release(&buf);
+    return res;
+}
+
+static PyObject *
+BufferedWriter_truncate(BufferedObject *self, PyObject *args)
+{
+    PyObject *pos = Py_None;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
+        return NULL;
+    }
+
+    Py_BEGIN_ALLOW_THREADS
+    PyThread_acquire_lock(self->write_lock, 1);
+    Py_END_ALLOW_THREADS
+
+    res = _BufferedWriter_flush_unlocked(self);
+    if (res == NULL)
+        goto end;
+    Py_DECREF(res);
+
+    res = BufferedIOMixin_truncate(self, args);
+
+  end:
+    PyThread_release_lock(self->write_lock);
+    return res;
+}
+
+static PyObject *
+BufferedWriter_flush(BufferedObject *self, PyObject *args)
+{
+    PyObject *res;
+
+        Py_BEGIN_ALLOW_THREADS
+        PyThread_acquire_lock(self->write_lock, 1);
+        Py_END_ALLOW_THREADS
+
+    res = _BufferedWriter_flush_unlocked(self);
+
+    PyThread_release_lock(self->write_lock);
+
+    return res;
+}
+
+static PyObject *
+BufferedWriter_tell(BufferedObject *self, PyObject *args)
+{
+    PyObject *op1, *op2, *res;
+
+    op1 = PyObject_CallMethod(self->raw, "tell", NULL);
+
+    op2 = PyLong_FromSsize_t(Py_SIZE(self->write_buf));
+    if (op2 == NULL) {
+        Py_DECREF(op1);
+        return NULL;
+    }
+
+    res = PyNumber_Add(op1, op2);
+    Py_DECREF(op1);
+    Py_DECREF(op2);
+    return res;
+}
+
+static PyObject *
+BufferedWriter_seek(BufferedObject *self, PyObject *args)
+{
+    Py_ssize_t pos;
+    int whence = 0;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
+        return NULL;
+    }
+
+        Py_BEGIN_ALLOW_THREADS
+        PyThread_acquire_lock(self->write_lock, 1);
+        Py_END_ALLOW_THREADS
+
+    res = _BufferedWriter_flush_unlocked(self);
+    if (res == NULL)
+        goto end;
+
+    res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
+
+  end:
+    PyThread_release_lock(self->write_lock);
+    return res;
+}
+
+static PyMethodDef BufferedWriter_methods[] = {
+    /* BufferedIOMixin methods */
+    {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
+    {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
+    {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
+    {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
+    {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
+    {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
+
+    {"write", (PyCFunction)BufferedWriter_write, METH_VARARGS},
+    {"truncate", (PyCFunction)BufferedWriter_truncate, METH_VARARGS},
+    {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
+    {"seek", (PyCFunction)BufferedWriter_seek, METH_VARARGS},
+    {"tell", (PyCFunction)BufferedWriter_tell, METH_NOARGS},
+    {NULL, NULL}
+};
+
+static PyMemberDef BufferedWriter_members[] = {
+        {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
+        {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
+    {NULL}
+};
+
+static PyGetSetDef BufferedWriter_getset[] = {
+    {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
+    {0}
+};
+
+
+PyTypeObject BufferedWriter_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "BufferedWriter",           /*tp_name*/
+    sizeof(BufferedObject),     /*tp_basicsize*/
+    0,                          /*tp_itemsize*/
+    (destructor)BufferedObject_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*/
+    BufferedWriter_doc,         /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    offsetof(BufferedObject, 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(BufferedObject, dict), /* tp_dictoffset */
+    (initproc)BufferedWriter_init, /* tp_init */
+    0,                          /* tp_alloc */
+    PyType_GenericNew,          /* tp_new */
+};
+
+
+
+/*
+ * 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. The max_buffer_size (for the buffered writer)\n"
+    "defaults to twice the buffer size.\n"
+    );
+
+/* XXX The usefulness of this (compared to having two separate IO objects) is
+ * questionable.
+ */
+
+typedef struct {
+    PyObject_HEAD
+    BufferedObject *reader;
+    BufferedObject *writer;
+} BufferedRWPairObject;
+
+static int
+BufferedRWPair_init(BufferedRWPairObject *self, PyObject *args,
+                     PyObject *kwds)
+{
+    PyObject *reader, *writer;
+    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+    Py_ssize_t max_buffer_size = -1;
+
+    if (!PyArg_ParseTuple(args, "OO|nn:BufferedRWPair", &reader, &writer,
+                          &buffer_size, &max_buffer_size)) {
+        return -1;
+    }
+
+    if (IOBase_checkReadable(reader, NULL) == NULL)
+        return -1;
+    if (IOBase_checkWritable(writer, NULL) == NULL)
+        return -1;
+
+    args = Py_BuildValue("(n)", buffer_size);
+    if (args == NULL) {
+        Py_CLEAR(self->reader);
+        return -1;
+    }
+    self->reader = (BufferedObject*)PyType_GenericNew(&BufferedReader_Type, args, NULL);
+    Py_DECREF(args);
+    if (self->reader == NULL)
+        return -1;
+
+    args = Py_BuildValue("(nn)", buffer_size, max_buffer_size);
+    if (args == NULL) {
+        Py_CLEAR(self->reader);
+        return -1;
+    }
+    self->writer = (BufferedObject*)PyType_GenericNew(&BufferedWriter_Type, args, NULL);
+    Py_DECREF(args);
+    if (self->writer == NULL) {
+        Py_CLEAR(self->reader);
+        return -1;
+    }
+    return 0;
+}
+
+static void
+BufferedRWPair_dealloc(BufferedRWPairObject *self)
+{
+    Py_CLEAR(self->reader);
+    Py_CLEAR(self->writer);
+}
+
+static PyObject *
+_forward_call(BufferedObject *self, const char* name, PyObject *args)
+{
+    PyObject *func = PyObject_GetAttrString((PyObject*)self, name);
+    PyObject *ret;
+
+    if (func == NULL) {
+        PyErr_SetString(PyExc_AttributeError, name);
+        return NULL;
+    }
+
+    ret = PyObject_CallObject(func, args);
+    Py_DECREF(func);
+    return ret;
+}
+
+static PyObject *
+BufferedRWPair_read(BufferedRWPairObject *self, PyObject *args)
+{
+    return _forward_call(self->reader, "read", args);
+}
+
+static PyObject *
+BufferedRWPair_peek(BufferedRWPairObject *self, PyObject *args)
+{
+    return _forward_call(self->reader, "peek", args);
+}
+
+static PyObject *
+BufferedRWPair_read1(BufferedRWPairObject *self, PyObject *args)
+{
+    return _forward_call(self->reader, "read1", args);
+}
+
+static PyObject *
+BufferedRWPair_write(BufferedRWPairObject *self, PyObject *args)
+{
+    return _forward_call(self->writer, "write", args);
+}
+
+static PyObject *
+BufferedRWPair_flush(BufferedRWPairObject *self, PyObject *args)
+{
+    return _forward_call(self->writer, "flush", args);
+}
+
+static PyObject *
+BufferedRWPair_readable(BufferedRWPairObject *self, PyObject *args)
+{
+    return _forward_call(self->reader, "readable", args);
+}
+
+static PyObject *
+BufferedRWPair_writable(BufferedRWPairObject *self, PyObject *args)
+{
+    return _forward_call(self->writer, "writable", args);
+}
+
+static PyObject *
+BufferedRWPair_close(BufferedRWPairObject *self, PyObject *args)
+{
+    PyObject *ret = _forward_call(self->writer, "close", args);
+    if (ret == NULL)
+        return NULL;
+    Py_DECREF(ret);
+
+    return _forward_call(self->reader, "close", args);
+}
+
+static PyObject *
+BufferedRWPair_isatty(BufferedRWPairObject *self, PyObject *args)
+{
+    PyObject *ret = _forward_call(self->writer, "isatty", args);
+
+    if (ret != Py_False) {
+        /* either True or exception */
+        return ret;
+    }
+    Py_DECREF(ret);
+
+    return _forward_call(self->reader, "isatty", args);
+}
+
+
+static PyMethodDef BufferedRWPair_methods[] = {
+    {"read", (PyCFunction)BufferedRWPair_read, METH_VARARGS},
+    {"peek", (PyCFunction)BufferedRWPair_peek, METH_VARARGS},
+    {"read1", (PyCFunction)BufferedRWPair_read1, 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},
+
+    {NULL, NULL}
+};
+
+PyTypeObject BufferedRWPair_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "BufferedRWPair",           /*tp_name*/
+    sizeof(BufferedRWPairObject),     /*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,  /*tp_flags*/
+    BufferedRWPair_doc,         /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    BufferedRWPair_methods,     /* tp_methods */
+    0,     /* tp_members */
+    0,      /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    offsetof(BufferedObject, dict), /* tp_dictoffset */
+    (initproc)BufferedRWPair_init, /* tp_init */
+    0,                          /* tp_alloc */
+    PyType_GenericNew,          /* tp_new */
+};
+
+
+
+/*
+ * 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. The max_buffer_size (for the buffered\n"
+    "writer) defaults to twice the buffer size.\n"
+    );
+
+static int
+BufferedRandom_init(BufferedObject *self, PyObject *args, PyObject *kwds)
+{
+    char *kwlist[] = {"raw", "buffer_size", "max_buffer_size", NULL};
+    Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE;
+    Py_ssize_t max_buffer_size = -1;
+    PyObject *raw;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|nn:BufferedReader", kwlist,
+                                     &raw, &buffer_size, &max_buffer_size)) {
+        return -1;
+    }
+
+    if (IOBase_checkSeekable(raw, NULL) == NULL)
+        return -1;
+    if (IOBase_checkReadable(raw, NULL) == NULL)
+        return -1;
+    if (IOBase_checkWritable(raw, NULL) == NULL)
+        return -1;
+
+    Py_INCREF(raw);
+    self->raw = raw;
+
+    if (max_buffer_size < 0)
+        max_buffer_size = buffer_size * 2;
+    self->buffer_size = buffer_size;
+    self->max_buffer_size = max_buffer_size;
+
+    if( _BufferedReader_reset_read_buf(self) < 0)
+        return -1;
+
+    self->read_lock = PyThread_allocate_lock();
+    if (self->read_lock == NULL) {
+                PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock");
+        return -1;
+    }
+
+        self->write_buf = PyByteArray_FromStringAndSize(NULL, 0);
+    if (self->write_buf == NULL)
+        return -1;
+
+    self->write_lock = PyThread_allocate_lock();
+    if (self->write_lock == NULL) {
+                PyErr_SetString(PyExc_RuntimeError, "can't allocate write lock");
+        return -1;
+    }
+
+    return 0;
+}
+
+static PyObject *
+BufferedRandom_tell(BufferedObject *self, PyObject *args)
+{
+    if (Py_SIZE(self->write_buf))
+        return BufferedWriter_tell(self, args);
+    else
+        return BufferedReader_tell(self, args);
+}
+
+static PyObject *
+BufferedRandom_seek(BufferedObject *self, PyObject *args)
+{
+    Py_ssize_t pos;
+    int whence = 0;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) {
+        return NULL;
+    }
+
+    res = PyObject_CallMethod((PyObject*)self, "flush", NULL);
+    if (res == NULL)
+        return NULL;
+
+    /* First do the raw seek, then empty the read buffer, so that
+     * if the raw seek fails, we don't lose buffered data forever.
+     */
+
+    res = PyObject_CallMethod(self->raw, "seek", "ni", pos, whence);
+    if (res == NULL)
+        return NULL;
+
+        Py_BEGIN_ALLOW_THREADS
+        PyThread_acquire_lock(self->read_lock, 1);
+        Py_END_ALLOW_THREADS
+
+    if( _BufferedReader_reset_read_buf(self) < 0)
+        Py_CLEAR(res);
+
+    PyThread_release_lock(self->read_lock);
+    return res;
+}
+
+static PyObject *
+BufferedRandom_truncate(BufferedObject *self, PyObject *args)
+{
+    PyObject *pos = Py_None;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) {
+        return NULL;
+    }
+
+    if (pos == Py_None)
+        pos = PyObject_CallMethod(self->raw, "tell", NULL);
+    else
+        Py_INCREF(pos);
+
+    /* Use seek to flush the read buffer. */
+    res = PyObject_CallMethod((PyObject *)self, "seek", "O", pos);
+    Py_DECREF(pos);
+    if (res == NULL)
+        return NULL;
+    Py_DECREF(res);
+
+    args = PyTuple_New(0);
+    if (args == NULL)
+        return NULL;
+    res = BufferedWriter_truncate(self, args);
+    Py_DECREF(args);
+
+    return res;
+}
+
+static PyObject *
+BufferedRandom_read(BufferedObject *self, PyObject *args)
+{
+    Py_ssize_t n = -1;
+    PyObject *res;
+
+    if (!PyArg_ParseTuple(args, "|n:read", &n)) {
+        return NULL;
+    }
+
+    res = BufferedWriter_flush(self, Py_None);
+    if (res == NULL)
+        return NULL;
+
+    return BufferedReader_read(self, args);
+}
+
+static PyObject *
+BufferedRandom_readinto(BufferedObject *self, PyObject *args)
+{
+    PyObject *res;
+
+    res = BufferedWriter_flush(self, Py_None);
+    if (res == NULL)
+        return NULL;
+    Py_DECREF(res);
+
+    return BufferedIOBase_readinto((PyObject *)self, args);
+}
+
+static PyObject *
+BufferedRandom_peek(BufferedObject *self, PyObject *args)
+{
+    PyObject *res = BufferedWriter_flush(self, Py_None);
+    if (res == NULL)
+        return NULL;
+    Py_DECREF(res);
+
+    return BufferedReader_peek(self, args);
+}
+
+static PyObject *
+BufferedRandom_read1(BufferedObject *self, PyObject *args)
+{
+    PyObject *res = BufferedWriter_flush(self, Py_None);
+    if (res == NULL)
+        return NULL;
+    Py_DECREF(res);
+
+    return BufferedReader_read1(self, args);
+}
+
+static PyObject *
+BufferedRandom_write(BufferedObject *self, PyObject *args)
+{
+    if (Py_SIZE(self->read_buf) > 0) {
+        PyObject *res;
+        /* Undo readahead */
+
+        Py_BEGIN_ALLOW_THREADS
+        PyThread_acquire_lock(self->read_lock, 1);
+        Py_END_ALLOW_THREADS
+
+        res = PyObject_CallMethod(self->raw, "seek", "ni",
+                                  self->read_pos - Py_SIZE(self->read_buf), 1);
+        Py_XDECREF(res);
+        if (res != NULL) {
+            if( _BufferedReader_reset_read_buf(self) < 0)
+                res = NULL;
+        }
+
+        PyThread_release_lock(self->read_lock);
+
+        if (res == NULL)
+            return NULL;
+    }
+
+    return BufferedWriter_write(self, args);
+}
+
+
+static PyMethodDef BufferedRandom_methods[] = {
+    /* BufferedIOMixin methods */
+    {"close", (PyCFunction)BufferedIOMixin_close, METH_NOARGS},
+    {"seekable", (PyCFunction)BufferedIOMixin_seekable, METH_NOARGS},
+    {"readable", (PyCFunction)BufferedIOMixin_readable, METH_NOARGS},
+    {"writable", (PyCFunction)BufferedIOMixin_writable, METH_NOARGS},
+    {"fileno", (PyCFunction)BufferedIOMixin_fileno, METH_NOARGS},
+    {"isatty", (PyCFunction)BufferedIOMixin_isatty, METH_NOARGS},
+
+    {"flush", (PyCFunction)BufferedWriter_flush, METH_NOARGS},
+
+    {"seek", (PyCFunction)BufferedRandom_seek, METH_VARARGS},
+    {"tell", (PyCFunction)BufferedRandom_tell, METH_NOARGS},
+    {"truncate", (PyCFunction)BufferedRandom_truncate, METH_VARARGS},
+    {"read", (PyCFunction)BufferedRandom_read, METH_VARARGS},
+    {"readinto", (PyCFunction)BufferedRandom_readinto, METH_VARARGS},
+    {"peek", (PyCFunction)BufferedRandom_peek, METH_VARARGS},
+    {"read1", (PyCFunction)BufferedRandom_read1, METH_VARARGS},
+    {"write", (PyCFunction)BufferedRandom_write, METH_VARARGS},
+    {NULL, NULL}
+};
+
+static PyMemberDef BufferedRandom_members[] = {
+    {"_name", T_OBJECT, offsetof(BufferedObject, name), 0},
+    {"_mode", T_OBJECT, offsetof(BufferedObject, mode), 0},
+    {NULL}
+};
+
+static PyGetSetDef BufferedRandom_getset[] = {
+    {"closed", (getter)BufferedIOMixin_closed_get, NULL, NULL},
+    {0}
+};
+
+
+PyTypeObject BufferedRandom_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "BufferedRandom",           /*tp_name*/
+    sizeof(BufferedObject),     /*tp_basicsize*/
+    0,                          /*tp_itemsize*/
+    (destructor)BufferedObject_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*/
+    BufferedRandom_doc,         /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    offsetof(BufferedObject, weakreflist), /*tp_weaklistoffset*/
+    0,                          /* tp_iter */
+    0,                          /* 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(BufferedObject, dict), /*tp_dictoffset*/
+    (initproc)BufferedRandom_init, /* tp_init */
+    0,                          /* tp_alloc */
+    PyType_GenericNew,          /* tp_new */
+};
+
+/*
+ * Module definition
+ */
+
+static PyMethodDef module_methods[] = {
+    {"open", (PyCFunction)io_open, METH_VARARGS|METH_KEYWORDS, open_doc},
+    {NULL, NULL}
+};
+
+static struct PyModuleDef iomodule = {
+    PyModuleDef_HEAD_INIT,
+    "io",
+    module_doc,
+    -1,
+    module_methods,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+PyMODINIT_FUNC
+PyInit__io()
+{
+    PyObject *m = PyModule_Create(&iomodule);
+    PyTypeObject *base;
+    if (m == NULL)
+        goto fail;
+
+    io_py_module = PyImport_ImportModule("io");
+    if (io_py_module == NULL)
+        goto fail;
+
+    /* UnsupportedOperation inherits from ValueError and IOError */
+    PyExc_UnsupportedOperation = PyObject_CallFunction(
+        (PyObject*)&PyType_Type, "s(OO){}",
+        "UnsupportedOperation", PyExc_ValueError, PyExc_IOError);
+    if (PyExc_UnsupportedOperation == NULL)
+        goto fail;
+    PyModule_AddObject(m, "UnsupportedOperation",
+                       PyExc_UnsupportedOperation);
+
+    /* BlockingIOError */
+    base = (PyTypeObject*)PyExc_IOError;
+    _PyExc_BlockingIOError.tp_base = base;
+    if (PyType_Ready(&_PyExc_BlockingIOError) < 0)
+        goto fail;
+    Py_INCREF(&_PyExc_BlockingIOError);
+    PyModule_AddObject(m, "BlockingIOError",
+                       (PyObject *)&_PyExc_BlockingIOError);
+
+    if (PyType_Ready(&_IOBase_Type) < 0)
+        goto fail;
+    Py_INCREF(&_IOBase_Type);
+    PyModule_AddObject(m, "IOBase",
+                       (PyObject *)&_IOBase_Type);
+
+    if (PyType_Ready(&_RawIOBase_Type) < 0)
+        goto fail;
+    Py_INCREF(&_RawIOBase_Type);
+    PyModule_AddObject(m, "RawIOBase",
+                       (PyObject *)&_RawIOBase_Type);
+
+    /* FileIO */
+    PyFileIO_Type.tp_base = &_RawIOBase_Type;
+    if (PyType_Ready(&PyFileIO_Type) < 0)
+        goto fail;
+    Py_INCREF(&PyFileIO_Type);
+    PyModule_AddObject(m, "FileIO", (PyObject *) &PyFileIO_Type);
+
+    /* BufferedIOBase */
+    if (PyType_Ready(&_BufferedIOBase_Type) < 0)
+        goto fail;
+    Py_INCREF(&_BufferedIOBase_Type);
+    PyModule_AddObject(m, "BufferedIOBase", (PyObject *) &_BufferedIOBase_Type);
+
+    /* BytesIO */
+    PyBytesIO_Type.tp_base = &_BufferedIOBase_Type;
+    if (PyType_Ready(&PyBytesIO_Type) < 0)
+        goto fail;
+    Py_INCREF(&PyBytesIO_Type);
+    PyModule_AddObject(m, "BytesIO", (PyObject *) &PyBytesIO_Type);
+
+    /* BufferedReader */
+    BufferedReader_Type.tp_base = &_BufferedIOBase_Type;
+    if (PyType_Ready(&BufferedReader_Type) < 0)
+        goto fail;
+    Py_INCREF(&BufferedReader_Type);
+    PyModule_AddObject(m, "BufferedReader", (PyObject *) &BufferedReader_Type);
+
+    /* BufferedWriter */
+    BufferedWriter_Type.tp_base = &_BufferedIOBase_Type;
+    if (PyType_Ready(&BufferedWriter_Type) < 0)
+        goto fail;
+    Py_INCREF(&BufferedWriter_Type);
+    PyModule_AddObject(m, "BufferedWriter", (PyObject *) &BufferedWriter_Type);
+
+    /* BufferedRWPair */
+    BufferedRWPair_Type.tp_base = &_BufferedIOBase_Type;
+    if (PyType_Ready(&BufferedRWPair_Type) < 0)
+        goto fail;
+    Py_INCREF(&BufferedRWPair_Type);
+    PyModule_AddObject(m, "BufferedRWPair", (PyObject *) &BufferedRWPair_Type);
+
+    /* BufferedRandom */
+    BufferedRandom_Type.tp_base = &_BufferedIOBase_Type;
+    if (PyType_Ready(&BufferedRandom_Type) < 0)
+        goto fail;
+    Py_INCREF(&BufferedRandom_Type);
+    PyModule_AddObject(m, "BufferedRandom", (PyObject *) &BufferedRandom_Type);
+
+    return m;
+
+  fail:
+    Py_XDECREF(m);
+    return NULL;
+}


More information about the Python-checkins mailing list