aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Modules/_io/_iomodule.c
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.com>2024-02-19 02:38:52 +0300
committerthegeorg <thegeorg@yandex-team.com>2024-02-19 02:50:43 +0300
commitd96fa07134c06472bfee6718b5cfd1679196fc99 (patch)
tree31ec344fa9d3ff8dc038692516b6438dfbdb8a2d /contrib/tools/python3/Modules/_io/_iomodule.c
parent452cf9e068aef7110e35e654c5d47eb80111ef89 (diff)
downloadydb-d96fa07134c06472bfee6718b5cfd1679196fc99.tar.gz
Sync contrib/tools/python3 layout with upstream
* Move src/ subdir contents to the top of the layout * Rename self-written lib -> lib2 to avoid CaseFolding warning from the VCS * Regenerate contrib/libs/python proxy-headers accordingly 4ccc62ac1511abcf0fed14ccade38e984e088f1e
Diffstat (limited to 'contrib/tools/python3/Modules/_io/_iomodule.c')
-rw-r--r--contrib/tools/python3/Modules/_io/_iomodule.c739
1 files changed, 739 insertions, 0 deletions
diff --git a/contrib/tools/python3/Modules/_io/_iomodule.c b/contrib/tools/python3/Modules/_io/_iomodule.c
new file mode 100644
index 0000000000..7b06c1bee5
--- /dev/null
+++ b/contrib/tools/python3/Modules/_io/_iomodule.c
@@ -0,0 +1,739 @@
+/*
+ An implementation of the new I/O lib as defined by PEP 3116 - "New I/O"
+
+ Classes defined here: UnsupportedOperation, BlockingIOError.
+ Functions defined here: open().
+
+ Mostly written by Amaury Forgeot d'Arc
+*/
+
+#define PY_SSIZE_T_CLEAN
+#include "Python.h"
+#include "_iomodule.h"
+#include "pycore_pystate.h" // _PyInterpreterState_GET()
+#include "pycore_initconfig.h" // _PyStatus_OK()
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif /* HAVE_SYS_STAT_H */
+
+#ifdef MS_WINDOWS
+#include <windows.h>
+#endif
+
+PyDoc_STRVAR(module_doc,
+"The io module provides the Python interfaces to stream handling. The\n"
+"builtin open function is defined in this module.\n"
+"\n"
+"At the top of the I/O hierarchy is the abstract base class IOBase. It\n"
+"defines the basic interface to a stream. Note, however, that there is no\n"
+"separation between reading and writing to streams; implementations are\n"
+"allowed to raise an OSError if they do not support a given operation.\n"
+"\n"
+"Extending IOBase is RawIOBase which deals simply with the reading and\n"
+"writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide\n"
+"an interface to OS files.\n"
+"\n"
+"BufferedIOBase deals with buffering on a raw byte stream (RawIOBase). Its\n"
+"subclasses, BufferedWriter, BufferedReader, and BufferedRWPair buffer\n"
+"streams that are readable, writable, and both respectively.\n"
+"BufferedRandom provides a buffered interface to random access\n"
+"streams. BytesIO is a simple stream of in-memory bytes.\n"
+"\n"
+"Another IOBase subclass, TextIOBase, deals with the encoding and decoding\n"
+"of streams into text. TextIOWrapper, which extends it, is a buffered text\n"
+"interface to a buffered raw stream (`BufferedIOBase`). Finally, StringIO\n"
+"is an in-memory stream for text.\n"
+"\n"
+"Argument names are not part of the specification, and only the arguments\n"
+"of open() are intended to be used as keyword arguments.\n"
+"\n"
+"data:\n"
+"\n"
+"DEFAULT_BUFFER_SIZE\n"
+"\n"
+" An int containing the default buffer size used by the module's buffered\n"
+" I/O classes. open() uses the file's blksize (as obtained by os.stat) if\n"
+" possible.\n"
+ );
+
+
+/*
+ * The main open() function
+ */
+/*[clinic input]
+module _io
+
+_io.open
+ file: object
+ mode: str = "r"
+ buffering: int = -1
+ encoding: str(accept={str, NoneType}) = None
+ errors: str(accept={str, NoneType}) = None
+ newline: str(accept={str, NoneType}) = None
+ closefd: bool = True
+ opener: object = None
+
+Open file and return a stream. Raise OSError upon failure.
+
+file is either a text or byte string giving the name (and the path
+if the file isn't in the current working directory) of the file to
+be opened or an integer file descriptor of the file to be
+wrapped. (If a file descriptor is given, it is closed when the
+returned I/O object is closed, unless closefd is set to False.)
+
+mode is an optional string that specifies the mode in which the file
+is opened. It defaults to 'r' which means open for reading in text
+mode. Other common values are 'w' for writing (truncating the file if
+it already exists), 'x' for creating and writing to a new file, and
+'a' for appending (which on some Unix systems, means that all writes
+append to the end of the file regardless of the current seek position).
+In text mode, if encoding is not specified the encoding used is platform
+dependent: locale.getencoding() is called to get the current locale encoding.
+(For reading and writing raw bytes use binary mode and leave encoding
+unspecified.) The available modes are:
+
+========= ===============================================================
+Character Meaning
+--------- ---------------------------------------------------------------
+'r' open for reading (default)
+'w' open for writing, truncating the file first
+'x' create a new file and open it for writing
+'a' open for writing, appending to the end of the file if it exists
+'b' binary mode
+'t' text mode (default)
+'+' open a disk file for updating (reading and writing)
+========= ===============================================================
+
+The default mode is 'rt' (open for reading text). For binary random
+access, the mode 'w+b' opens and truncates the file to 0 bytes, while
+'r+b' opens the file without truncation. The 'x' mode implies 'w' and
+raises an `FileExistsError` if the file already exists.
+
+Python distinguishes between files opened in binary and text modes,
+even when the underlying operating system doesn't. Files opened in
+binary mode (appending 'b' to the mode argument) return contents as
+bytes objects without any decoding. In text mode (the default, or when
+'t' is appended to the mode argument), the contents of the file are
+returned as strings, the bytes having been first decoded using a
+platform-dependent encoding or using the specified encoding if given.
+
+buffering is an optional integer used to set the buffering policy.
+Pass 0 to switch buffering off (only allowed in binary mode), 1 to select
+line buffering (only usable in text mode), and an integer > 1 to indicate
+the size of a fixed-size chunk buffer. When no buffering argument is
+given, the default buffering policy works as follows:
+
+* Binary files are buffered in fixed-size chunks; the size of the buffer
+ is chosen using a heuristic trying to determine the underlying device's
+ "block size" and falling back on `io.DEFAULT_BUFFER_SIZE`.
+ On many systems, the buffer will typically be 4096 or 8192 bytes long.
+
+* "Interactive" text files (files for which isatty() returns True)
+ use line buffering. Other text files use the policy described above
+ for binary files.
+
+encoding is the name of the encoding used to decode or encode the
+file. This should only be used in text mode. The default encoding is
+platform dependent, but any encoding supported by Python can be
+passed. See the codecs module for the list of supported encodings.
+
+errors is an optional string that specifies how encoding errors are to
+be handled---this argument should not be used in binary mode. Pass
+'strict' to raise a ValueError exception if there is an encoding error
+(the default of None has the same effect), or pass 'ignore' to ignore
+errors. (Note that ignoring encoding errors can lead to data loss.)
+See the documentation for codecs.register or run 'help(codecs.Codec)'
+for a list of the permitted encoding error strings.
+
+newline controls how universal newlines works (it only applies to text
+mode). It can be None, '', '\n', '\r', and '\r\n'. It works as
+follows:
+
+* On input, if newline is None, universal newlines mode is
+ enabled. Lines in the input can end in '\n', '\r', or '\r\n', and
+ these are translated into '\n' before being returned to the
+ caller. If it is '', universal newline mode is enabled, but line
+ endings are returned to the caller untranslated. If it has any of
+ the other legal values, input lines are only terminated by the given
+ string, and the line ending is returned to the caller untranslated.
+
+* On output, if newline is None, any '\n' characters written are
+ translated to the system default line separator, os.linesep. If
+ newline is '' or '\n', no translation takes place. If newline is any
+ of the other legal values, any '\n' characters written are translated
+ to the given string.
+
+If closefd is False, the underlying file descriptor will be kept open
+when the file is closed. This does not work when a file name is given
+and must be True in that case.
+
+A custom opener can be used by passing a callable as *opener*. The
+underlying file descriptor for the file object is then obtained by
+calling *opener* with (*file*, *flags*). *opener* must return an open
+file descriptor (passing os.open as *opener* results in functionality
+similar to passing None).
+
+open() returns a file object whose type depends on the mode, and
+through which the standard file operations such as reading and writing
+are performed. When open() is used to open a file in a text mode ('w',
+'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open
+a file in a binary mode, the returned class varies: in read binary
+mode, it returns a BufferedReader; in write binary and append binary
+modes, it returns a BufferedWriter, and in read/write mode, it returns
+a BufferedRandom.
+
+It is also possible to use a string or bytearray as a file for both
+reading and writing. For strings StringIO can be used like a file
+opened in a text mode, and for bytes a BytesIO can be used like a file
+opened in a binary mode.
+[clinic start generated code]*/
+
+static PyObject *
+_io_open_impl(PyObject *module, PyObject *file, const char *mode,
+ int buffering, const char *encoding, const char *errors,
+ const char *newline, int closefd, PyObject *opener)
+/*[clinic end generated code: output=aefafc4ce2b46dc0 input=cd034e7cdfbf4e78]*/
+{
+ unsigned i;
+
+ int creating = 0, reading = 0, writing = 0, appending = 0, updating = 0;
+ int text = 0, binary = 0;
+
+ char rawmode[6], *m;
+ int line_buffering, is_number, isatty = 0;
+
+ PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL, *path_or_fd = NULL;
+
+ is_number = PyNumber_Check(file);
+
+ if (is_number) {
+ path_or_fd = Py_NewRef(file);
+ } else {
+ path_or_fd = PyOS_FSPath(file);
+ if (path_or_fd == NULL) {
+ return NULL;
+ }
+ }
+
+ if (!is_number &&
+ !PyUnicode_Check(path_or_fd) &&
+ !PyBytes_Check(path_or_fd)) {
+ PyErr_Format(PyExc_TypeError, "invalid file: %R", file);
+ goto error;
+ }
+
+ /* Decode mode */
+ for (i = 0; i < strlen(mode); i++) {
+ char c = mode[i];
+
+ switch (c) {
+ case 'x':
+ creating = 1;
+ break;
+ case 'r':
+ reading = 1;
+ break;
+ case 'w':
+ writing = 1;
+ break;
+ case 'a':
+ appending = 1;
+ break;
+ case '+':
+ updating = 1;
+ break;
+ case 't':
+ text = 1;
+ break;
+ case 'b':
+ binary = 1;
+ break;
+ 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);
+ goto error;
+ }
+
+ }
+
+ m = rawmode;
+ if (creating) *(m++) = 'x';
+ if (reading) *(m++) = 'r';
+ if (writing) *(m++) = 'w';
+ if (appending) *(m++) = 'a';
+ if (updating) *(m++) = '+';
+ *m = '\0';
+
+ /* Parameters validation */
+ if (text && binary) {
+ PyErr_SetString(PyExc_ValueError,
+ "can't have text and binary mode at once");
+ goto error;
+ }
+
+ if (creating + reading + writing + appending > 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "must have exactly one of create/read/write/append mode");
+ goto error;
+ }
+
+ if (binary && encoding != NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "binary mode doesn't take an encoding argument");
+ goto error;
+ }
+
+ if (binary && errors != NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "binary mode doesn't take an errors argument");
+ goto error;
+ }
+
+ if (binary && newline != NULL) {
+ PyErr_SetString(PyExc_ValueError,
+ "binary mode doesn't take a newline argument");
+ goto error;
+ }
+
+ if (binary && buffering == 1) {
+ if (PyErr_WarnEx(PyExc_RuntimeWarning,
+ "line buffering (buffering=1) isn't supported in "
+ "binary mode, the default buffer size will be used",
+ 1) < 0) {
+ goto error;
+ }
+ }
+
+ /* Create the Raw file stream */
+ _PyIO_State *state = get_io_state(module);
+ {
+ PyObject *RawIO_class = (PyObject *)state->PyFileIO_Type;
+#ifdef HAVE_WINDOWS_CONSOLE_IO
+ const PyConfig *config = _Py_GetConfig();
+ if (!config->legacy_windows_stdio && _PyIO_get_console_type(path_or_fd) != '\0') {
+ RawIO_class = (PyObject *)state->PyWindowsConsoleIO_Type;
+ encoding = "utf-8";
+ }
+#endif
+ raw = PyObject_CallFunction(RawIO_class, "OsOO",
+ path_or_fd, rawmode,
+ closefd ? Py_True : Py_False,
+ opener);
+ }
+
+ if (raw == NULL)
+ goto error;
+ result = raw;
+
+ Py_SETREF(path_or_fd, NULL);
+
+ modeobj = PyUnicode_FromString(mode);
+ if (modeobj == NULL)
+ goto error;
+
+ /* buffering */
+ if (buffering < 0) {
+ PyObject *res = PyObject_CallMethodNoArgs(raw, &_Py_ID(isatty));
+ if (res == NULL)
+ goto error;
+ isatty = PyObject_IsTrue(res);
+ Py_DECREF(res);
+ if (isatty < 0)
+ goto error;
+ }
+
+ if (buffering == 1 || isatty) {
+ buffering = -1;
+ line_buffering = 1;
+ }
+ else
+ line_buffering = 0;
+
+ if (buffering < 0) {
+ PyObject *blksize_obj;
+ blksize_obj = PyObject_GetAttr(raw, &_Py_ID(_blksize));
+ if (blksize_obj == NULL)
+ goto error;
+ buffering = PyLong_AsLong(blksize_obj);
+ Py_DECREF(blksize_obj);
+ if (buffering == -1 && PyErr_Occurred())
+ goto error;
+ }
+ if (buffering < 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "invalid buffering size");
+ goto error;
+ }
+
+ /* if not buffering, returns the raw file object */
+ if (buffering == 0) {
+ if (!binary) {
+ PyErr_SetString(PyExc_ValueError,
+ "can't have unbuffered text I/O");
+ goto error;
+ }
+
+ Py_DECREF(modeobj);
+ return result;
+ }
+
+ /* wraps into a buffered file */
+ {
+ PyObject *Buffered_class;
+
+ if (updating) {
+ Buffered_class = (PyObject *)state->PyBufferedRandom_Type;
+ }
+ else if (creating || writing || appending) {
+ Buffered_class = (PyObject *)state->PyBufferedWriter_Type;
+ }
+ else if (reading) {
+ Buffered_class = (PyObject *)state->PyBufferedReader_Type;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "unknown mode: '%s'", mode);
+ goto error;
+ }
+
+ buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
+ }
+ if (buffer == NULL)
+ goto error;
+ result = buffer;
+ Py_DECREF(raw);
+
+
+ /* if binary, returns the buffered file */
+ if (binary) {
+ Py_DECREF(modeobj);
+ return result;
+ }
+
+ /* wraps into a TextIOWrapper */
+ wrapper = PyObject_CallFunction((PyObject *)state->PyTextIOWrapper_Type,
+ "OsssO",
+ buffer,
+ encoding, errors, newline,
+ line_buffering ? Py_True : Py_False);
+ if (wrapper == NULL)
+ goto error;
+ result = wrapper;
+ Py_DECREF(buffer);
+
+ if (PyObject_SetAttr(wrapper, &_Py_ID(mode), modeobj) < 0)
+ goto error;
+ Py_DECREF(modeobj);
+ return result;
+
+ error:
+ if (result != NULL) {
+ PyObject *exc = PyErr_GetRaisedException();
+ PyObject *close_result = PyObject_CallMethodNoArgs(result, &_Py_ID(close));
+ _PyErr_ChainExceptions1(exc);
+ Py_XDECREF(close_result);
+ Py_DECREF(result);
+ }
+ Py_XDECREF(path_or_fd);
+ Py_XDECREF(modeobj);
+ return NULL;
+}
+
+
+/*[clinic input]
+_io.text_encoding
+ encoding: object
+ stacklevel: int = 2
+ /
+
+A helper function to choose the text encoding.
+
+When encoding is not None, this function returns it.
+Otherwise, this function returns the default text encoding
+(i.e. "locale" or "utf-8" depends on UTF-8 mode).
+
+This function emits an EncodingWarning if encoding is None and
+sys.flags.warn_default_encoding is true.
+
+This can be used in APIs with an encoding=None parameter.
+However, please consider using encoding="utf-8" for new APIs.
+[clinic start generated code]*/
+
+static PyObject *
+_io_text_encoding_impl(PyObject *module, PyObject *encoding, int stacklevel)
+/*[clinic end generated code: output=91b2cfea6934cc0c input=4999aa8b3d90f3d4]*/
+{
+ if (encoding == NULL || encoding == Py_None) {
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ if (_PyInterpreterState_GetConfig(interp)->warn_default_encoding) {
+ if (PyErr_WarnEx(PyExc_EncodingWarning,
+ "'encoding' argument not specified", stacklevel)) {
+ return NULL;
+ }
+ }
+ const PyPreConfig *preconfig = &_PyRuntime.preconfig;
+ if (preconfig->utf8_mode) {
+ _Py_DECLARE_STR(utf_8, "utf-8");
+ encoding = &_Py_STR(utf_8);
+ }
+ else {
+ encoding = &_Py_ID(locale);
+ }
+ }
+ return Py_NewRef(encoding);
+}
+
+
+/*[clinic input]
+_io.open_code
+
+ path : unicode
+
+Opens the provided file with the intent to import the contents.
+
+This may perform extra validation beyond open(), but is otherwise interchangeable
+with calling open(path, 'rb').
+
+[clinic start generated code]*/
+
+static PyObject *
+_io_open_code_impl(PyObject *module, PyObject *path)
+/*[clinic end generated code: output=2fe4ecbd6f3d6844 input=f5c18e23f4b2ed9f]*/
+{
+ return PyFile_OpenCodeObject(path);
+}
+
+/*
+ * Private helpers for the io module.
+ */
+
+Py_off_t
+PyNumber_AsOff_t(PyObject *item, PyObject *err)
+{
+ Py_off_t result;
+ PyObject *runerr;
+ PyObject *value = _PyNumber_Index(item);
+ if (value == NULL)
+ return -1;
+
+ /* We're done if PyLong_AsSsize_t() returns without error. */
+ result = PyLong_AsOff_t(value);
+ if (result != -1 || !(runerr = PyErr_Occurred()))
+ goto finish;
+
+ /* Error handling code -- only manage OverflowError differently */
+ if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError))
+ goto finish;
+
+ PyErr_Clear();
+ /* If no error-handling desired then the default clipping
+ is sufficient.
+ */
+ if (!err) {
+ assert(PyLong_Check(value));
+ /* Whether or not it is less than or equal to
+ zero is determined by the sign of ob_size
+ */
+ if (_PyLong_Sign(value) < 0)
+ result = PY_OFF_T_MIN;
+ else
+ result = PY_OFF_T_MAX;
+ }
+ else {
+ /* Otherwise replace the error with caller's error object. */
+ PyErr_Format(err,
+ "cannot fit '%.200s' into an offset-sized integer",
+ Py_TYPE(item)->tp_name);
+ }
+
+ finish:
+ Py_DECREF(value);
+ return result;
+}
+
+static int
+iomodule_traverse(PyObject *mod, visitproc visit, void *arg) {
+ _PyIO_State *state = get_io_state(mod);
+ Py_VISIT(state->unsupported_operation);
+
+ Py_VISIT(state->PyIOBase_Type);
+ Py_VISIT(state->PyIncrementalNewlineDecoder_Type);
+ Py_VISIT(state->PyRawIOBase_Type);
+ Py_VISIT(state->PyBufferedIOBase_Type);
+ Py_VISIT(state->PyBufferedRWPair_Type);
+ Py_VISIT(state->PyBufferedRandom_Type);
+ Py_VISIT(state->PyBufferedReader_Type);
+ Py_VISIT(state->PyBufferedWriter_Type);
+ Py_VISIT(state->PyBytesIOBuffer_Type);
+ Py_VISIT(state->PyBytesIO_Type);
+ Py_VISIT(state->PyFileIO_Type);
+ Py_VISIT(state->PyStringIO_Type);
+ Py_VISIT(state->PyTextIOBase_Type);
+ Py_VISIT(state->PyTextIOWrapper_Type);
+#ifdef HAVE_WINDOWS_CONSOLE_IO
+ Py_VISIT(state->PyWindowsConsoleIO_Type);
+#endif
+ return 0;
+}
+
+
+static int
+iomodule_clear(PyObject *mod) {
+ _PyIO_State *state = get_io_state(mod);
+ Py_CLEAR(state->unsupported_operation);
+
+ Py_CLEAR(state->PyIOBase_Type);
+ Py_CLEAR(state->PyIncrementalNewlineDecoder_Type);
+ Py_CLEAR(state->PyRawIOBase_Type);
+ Py_CLEAR(state->PyBufferedIOBase_Type);
+ Py_CLEAR(state->PyBufferedRWPair_Type);
+ Py_CLEAR(state->PyBufferedRandom_Type);
+ Py_CLEAR(state->PyBufferedReader_Type);
+ Py_CLEAR(state->PyBufferedWriter_Type);
+ Py_CLEAR(state->PyBytesIOBuffer_Type);
+ Py_CLEAR(state->PyBytesIO_Type);
+ Py_CLEAR(state->PyFileIO_Type);
+ Py_CLEAR(state->PyStringIO_Type);
+ Py_CLEAR(state->PyTextIOBase_Type);
+ Py_CLEAR(state->PyTextIOWrapper_Type);
+#ifdef HAVE_WINDOWS_CONSOLE_IO
+ Py_CLEAR(state->PyWindowsConsoleIO_Type);
+#endif
+ return 0;
+}
+
+static void
+iomodule_free(void *mod)
+{
+ (void)iomodule_clear((PyObject *)mod);
+}
+
+
+/*
+ * Module definition
+ */
+
+#define clinic_state() (get_io_state(module))
+#include "clinic/_iomodule.c.h"
+#undef clinic_state
+
+static PyMethodDef module_methods[] = {
+ _IO_OPEN_METHODDEF
+ _IO_TEXT_ENCODING_METHODDEF
+ _IO_OPEN_CODE_METHODDEF
+ {NULL, NULL}
+};
+
+#define ADD_TYPE(module, type, spec, base) \
+do { \
+ type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, \
+ (PyObject *)base); \
+ if (type == NULL) { \
+ return -1; \
+ } \
+ if (PyModule_AddType(module, type) < 0) { \
+ return -1; \
+ } \
+} while (0)
+
+static int
+iomodule_exec(PyObject *m)
+{
+ _PyIO_State *state = get_io_state(m);
+
+ /* DEFAULT_BUFFER_SIZE */
+ if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
+ return -1;
+
+ /* UnsupportedOperation inherits from ValueError and OSError */
+ state->unsupported_operation = PyObject_CallFunction(
+ (PyObject *)&PyType_Type, "s(OO){}",
+ "UnsupportedOperation", PyExc_OSError, PyExc_ValueError);
+ if (state->unsupported_operation == NULL)
+ return -1;
+ if (PyModule_AddObjectRef(m, "UnsupportedOperation",
+ state->unsupported_operation) < 0)
+ {
+ return -1;
+ }
+
+ /* BlockingIOError, for compatibility */
+ if (PyModule_AddObjectRef(m, "BlockingIOError",
+ (PyObject *) PyExc_BlockingIOError) < 0) {
+ return -1;
+ }
+
+ // Base classes
+ ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL);
+ ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL);
+ ADD_TYPE(m, state->PyIOBase_Type, &iobase_spec, NULL);
+
+ // PyIOBase_Type subclasses
+ ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec,
+ state->PyIOBase_Type);
+ ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec,
+ state->PyIOBase_Type);
+ ADD_TYPE(m, state->PyRawIOBase_Type, &rawiobase_spec,
+ state->PyIOBase_Type);
+
+ // PyBufferedIOBase_Type(PyIOBase_Type) subclasses
+ ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, state->PyBufferedIOBase_Type);
+ ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec,
+ state->PyBufferedIOBase_Type);
+ ADD_TYPE(m, state->PyBufferedReader_Type, &bufferedreader_spec,
+ state->PyBufferedIOBase_Type);
+ ADD_TYPE(m, state->PyBufferedRWPair_Type, &bufferedrwpair_spec,
+ state->PyBufferedIOBase_Type);
+ ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec,
+ state->PyBufferedIOBase_Type);
+
+ // PyRawIOBase_Type(PyIOBase_Type) subclasses
+ ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type);
+
+#ifdef HAVE_WINDOWS_CONSOLE_IO
+ ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec,
+ state->PyRawIOBase_Type);
+#endif
+
+ // PyTextIOBase_Type(PyIOBase_Type) subclasses
+ ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, state->PyTextIOBase_Type);
+ ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec,
+ state->PyTextIOBase_Type);
+
+#undef ADD_TYPE
+ return 0;
+}
+
+static struct PyModuleDef_Slot iomodule_slots[] = {
+ {Py_mod_exec, iomodule_exec},
+ {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+ {0, NULL},
+};
+
+struct PyModuleDef _PyIO_Module = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "io",
+ .m_doc = module_doc,
+ .m_size = sizeof(_PyIO_State),
+ .m_methods = module_methods,
+ .m_traverse = iomodule_traverse,
+ .m_clear = iomodule_clear,
+ .m_free = iomodule_free,
+ .m_slots = iomodule_slots,
+};
+
+PyMODINIT_FUNC
+PyInit__io(void)
+{
+ return PyModuleDef_Init(&_PyIO_Module);
+}