Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Modules/_io/_iomodule.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
    An implementation of the new I/O lib as defined by PEP 3116 - "New I/O"
3
4
    Classes defined here: UnsupportedOperation, BlockingIOError.
5
    Functions defined here: open().
6
7
    Mostly written by Amaury Forgeot d'Arc
8
*/
9
10
#include "Python.h"
11
#include "pycore_abstract.h"      // _PyNumber_Index()
12
#include "pycore_interp.h"        // _PyInterpreterState_GetConfig()
13
#include "pycore_long.h"          // _PyLong_IsNegative()
14
#include "pycore_pyerrors.h"      // _PyErr_ChainExceptions1()
15
#include "pycore_pystate.h"       // _PyInterpreterState_GET()
16
17
#include "_iomodule.h"
18
19
#ifdef HAVE_SYS_TYPES_H
20
#include <sys/types.h>
21
#endif /* HAVE_SYS_TYPES_H */
22
23
#ifdef HAVE_SYS_STAT_H
24
#include <sys/stat.h>
25
#endif /* HAVE_SYS_STAT_H */
26
27
#ifdef MS_WINDOWS
28
#include <windows.h>
29
#endif
30
31
PyDoc_STRVAR(module_doc,
32
"The io module provides the Python interfaces to stream handling. The\n"
33
"builtin open function is defined in this module.\n"
34
"\n"
35
"At the top of the I/O hierarchy is the abstract base class IOBase. It\n"
36
"defines the basic interface to a stream. Note, however, that there is no\n"
37
"separation between reading and writing to streams; implementations are\n"
38
"allowed to raise an OSError if they do not support a given operation.\n"
39
"\n"
40
"Extending IOBase is RawIOBase which deals simply with the reading and\n"
41
"writing of raw bytes to a stream. FileIO subclasses RawIOBase to provide\n"
42
"an interface to OS files.\n"
43
"\n"
44
"BufferedIOBase deals with buffering on a raw byte stream (RawIOBase). Its\n"
45
"subclasses, BufferedWriter, BufferedReader, and BufferedRWPair buffer\n"
46
"streams that are readable, writable, and both respectively.\n"
47
"BufferedRandom provides a buffered interface to random access\n"
48
"streams. BytesIO is a simple stream of in-memory bytes.\n"
49
"\n"
50
"Another IOBase subclass, TextIOBase, deals with the encoding and decoding\n"
51
"of streams into text. TextIOWrapper, which extends it, is a buffered text\n"
52
"interface to a buffered raw stream (`BufferedIOBase`). Finally, StringIO\n"
53
"is an in-memory stream for text.\n"
54
"\n"
55
"Argument names are not part of the specification, and only the arguments\n"
56
"of open() are intended to be used as keyword arguments.\n"
57
"\n"
58
"data:\n"
59
"\n"
60
"DEFAULT_BUFFER_SIZE\n"
61
"\n"
62
"   An int containing the default buffer size used by the module's buffered\n"
63
"   I/O classes.\n"
64
    );
65
66
67
/*
68
 * The main open() function
69
 */
70
/*[clinic input]
71
module _io
72
73
_io.open
74
    file: object
75
    mode: str = "r"
76
    buffering: int = -1
77
    encoding: str(accept={str, NoneType}) = None
78
    errors: str(accept={str, NoneType}) = None
79
    newline: str(accept={str, NoneType}) = None
80
    closefd: bool = True
81
    opener: object = None
82
83
Open file and return a stream.  Raise OSError upon failure.
84
85
file is either a text or byte string giving the name (and the path
86
if the file isn't in the current working directory) of the file to
87
be opened or an integer file descriptor of the file to be
88
wrapped. (If a file descriptor is given, it is closed when the
89
returned I/O object is closed, unless closefd is set to False.)
90
91
mode is an optional string that specifies the mode in which the file
92
is opened. It defaults to 'r' which means open for reading in text
93
mode.  Other common values are 'w' for writing (truncating the file if
94
it already exists), 'x' for creating and writing to a new file, and
95
'a' for appending (which on some Unix systems, means that all writes
96
append to the end of the file regardless of the current seek position).
97
In text mode, if encoding is not specified the encoding used is platform
98
dependent: locale.getencoding() is called to get the current locale encoding.
99
(For reading and writing raw bytes use binary mode and leave encoding
100
unspecified.) The available modes are:
101
102
========= ===============================================================
103
Character Meaning
104
--------- ---------------------------------------------------------------
105
'r'       open for reading (default)
106
'w'       open for writing, truncating the file first
107
'x'       create a new file and open it for writing
108
'a'       open for writing, appending to the end of the file if it exists
109
'b'       binary mode
110
't'       text mode (default)
111
'+'       open a disk file for updating (reading and writing)
112
========= ===============================================================
113
114
The default mode is 'rt' (open for reading text). For binary random
115
access, the mode 'w+b' opens and truncates the file to 0 bytes, while
116
'r+b' opens the file without truncation. The 'x' mode implies 'w' and
117
raises an `FileExistsError` if the file already exists.
118
119
Python distinguishes between files opened in binary and text modes,
120
even when the underlying operating system doesn't. Files opened in
121
binary mode (appending 'b' to the mode argument) return contents as
122
bytes objects without any decoding. In text mode (the default, or when
123
't' is appended to the mode argument), the contents of the file are
124
returned as strings, the bytes having been first decoded using a
125
platform-dependent encoding or using the specified encoding if given.
126
127
buffering is an optional integer used to set the buffering policy.
128
Pass 0 to switch buffering off (only allowed in binary mode), 1 to select
129
line buffering (only usable in text mode), and an integer > 1 to indicate
130
the size of a fixed-size chunk buffer.  When no buffering argument is
131
given, the default buffering policy works as follows:
132
133
* Binary files are buffered in fixed-size chunks; the size of the buffer
134
 is max(min(blocksize, 8 MiB), DEFAULT_BUFFER_SIZE)
135
 when the device block size is available.
136
 On most systems, the buffer will typically be 128 kilobytes long.
137
138
* "Interactive" text files (files for which isatty() returns True)
139
  use line buffering.  Other text files use the policy described above
140
  for binary files.
141
142
encoding is the name of the encoding used to decode or encode the
143
file. This should only be used in text mode. The default encoding is
144
platform dependent, but any encoding supported by Python can be
145
passed.  See the codecs module for the list of supported encodings.
146
147
errors is an optional string that specifies how encoding errors are to
148
be handled---this argument should not be used in binary mode. Pass
149
'strict' to raise a ValueError exception if there is an encoding error
150
(the default of None has the same effect), or pass 'ignore' to ignore
151
errors. (Note that ignoring encoding errors can lead to data loss.)
152
See the documentation for codecs.register or run 'help(codecs.Codec)'
153
for a list of the permitted encoding error strings.
154
155
newline controls how universal newlines works (it only applies to text
156
mode). It can be None, '', '\n', '\r', and '\r\n'.  It works as
157
follows:
158
159
* On input, if newline is None, universal newlines mode is
160
  enabled. Lines in the input can end in '\n', '\r', or '\r\n', and
161
  these are translated into '\n' before being returned to the
162
  caller. If it is '', universal newline mode is enabled, but line
163
  endings are returned to the caller untranslated. If it has any of
164
  the other legal values, input lines are only terminated by the given
165
  string, and the line ending is returned to the caller untranslated.
166
167
* On output, if newline is None, any '\n' characters written are
168
  translated to the system default line separator, os.linesep. If
169
  newline is '' or '\n', no translation takes place. If newline is any
170
  of the other legal values, any '\n' characters written are translated
171
  to the given string.
172
173
If closefd is False, the underlying file descriptor will be kept open
174
when the file is closed. This does not work when a file name is given
175
and must be True in that case.
176
177
A custom opener can be used by passing a callable as *opener*. The
178
underlying file descriptor for the file object is then obtained by
179
calling *opener* with (*file*, *flags*). *opener* must return an open
180
file descriptor (passing os.open as *opener* results in functionality
181
similar to passing None).
182
183
open() returns a file object whose type depends on the mode, and
184
through which the standard file operations such as reading and writing
185
are performed. When open() is used to open a file in a text mode ('w',
186
'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open
187
a file in a binary mode, the returned class varies: in read binary
188
mode, it returns a BufferedReader; in write binary and append binary
189
modes, it returns a BufferedWriter, and in read/write mode, it returns
190
a BufferedRandom.
191
192
It is also possible to use a string or bytearray as a file for both
193
reading and writing. For strings StringIO can be used like a file
194
opened in a text mode, and for bytes a BytesIO can be used like a file
195
opened in a binary mode.
196
[clinic start generated code]*/
197
198
static PyObject *
199
_io_open_impl(PyObject *module, PyObject *file, const char *mode,
200
              int buffering, const char *encoding, const char *errors,
201
              const char *newline, int closefd, PyObject *opener)
202
/*[clinic end generated code: output=aefafc4ce2b46dc0 input=28027fdaabb8d744]*/
203
992
{
204
992
    size_t i;
205
206
992
    int creating = 0, reading = 0, writing = 0, appending = 0, updating = 0;
207
992
    int text = 0, binary = 0;
208
209
992
    char rawmode[6], *m;
210
992
    int line_buffering, is_number, isatty = 0;
211
212
992
    PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL, *path_or_fd = NULL;
213
214
992
    is_number = PyNumber_Check(file);
215
216
992
    if (is_number) {
217
48
        path_or_fd = Py_NewRef(file);
218
944
    } else {
219
944
        path_or_fd = PyOS_FSPath(file);
220
944
        if (path_or_fd == NULL) {
221
0
            return NULL;
222
0
        }
223
944
    }
224
225
992
    if (!is_number &&
226
992
        !PyUnicode_Check(path_or_fd) &&
227
992
        !PyBytes_Check(path_or_fd)) {
228
0
        PyErr_Format(PyExc_TypeError, "invalid file: %R", file);
229
0
        goto error;
230
0
    }
231
232
    /* Decode mode */
233
2.97k
    for (i = 0; i < strlen(mode); i++) {
234
1.98k
        char c = mode[i];
235
236
1.98k
        switch (c) {
237
0
        case 'x':
238
0
            creating = 1;
239
0
            break;
240
960
        case 'r':
241
960
            reading = 1;
242
960
            break;
243
32
        case 'w':
244
32
            writing = 1;
245
32
            break;
246
0
        case 'a':
247
0
            appending = 1;
248
0
            break;
249
0
        case '+':
250
0
            updating = 1;
251
0
            break;
252
0
        case 't':
253
0
            text = 1;
254
0
            break;
255
992
        case 'b':
256
992
            binary = 1;
257
992
            break;
258
0
        default:
259
0
            goto invalid_mode;
260
1.98k
        }
261
262
        /* c must not be duplicated */
263
1.98k
        if (strchr(mode+i+1, c)) {
264
0
          invalid_mode:
265
0
            PyErr_Format(PyExc_ValueError, "invalid mode: '%s'", mode);
266
0
            goto error;
267
0
        }
268
269
1.98k
    }
270
271
992
    m = rawmode;
272
992
    if (creating)  *(m++) = 'x';
273
992
    if (reading)   *(m++) = 'r';
274
992
    if (writing)   *(m++) = 'w';
275
992
    if (appending) *(m++) = 'a';
276
992
    if (updating)  *(m++) = '+';
277
992
    *m = '\0';
278
279
    /* Parameters validation */
280
992
    if (text && binary) {
281
0
        PyErr_SetString(PyExc_ValueError,
282
0
                        "can't have text and binary mode at once");
283
0
        goto error;
284
0
    }
285
286
992
    if (creating + reading + writing + appending > 1) {
287
0
        PyErr_SetString(PyExc_ValueError,
288
0
                        "must have exactly one of create/read/write/append mode");
289
0
        goto error;
290
0
    }
291
292
992
    if (binary && encoding != NULL) {
293
0
        PyErr_SetString(PyExc_ValueError,
294
0
                        "binary mode doesn't take an encoding argument");
295
0
        goto error;
296
0
    }
297
298
992
    if (binary && errors != NULL) {
299
0
        PyErr_SetString(PyExc_ValueError,
300
0
                        "binary mode doesn't take an errors argument");
301
0
        goto error;
302
0
    }
303
304
992
    if (binary && newline != NULL) {
305
0
        PyErr_SetString(PyExc_ValueError,
306
0
                        "binary mode doesn't take a newline argument");
307
0
        goto error;
308
0
    }
309
310
992
    if (binary && buffering == 1) {
311
0
        if (PyErr_WarnEx(PyExc_RuntimeWarning,
312
0
                         "line buffering (buffering=1) isn't supported in "
313
0
                         "binary mode, the default buffer size will be used",
314
0
                         1) < 0) {
315
0
           goto error;
316
0
        }
317
0
    }
318
319
    /* Create the Raw file stream */
320
992
    _PyIO_State *state = get_io_state(module);
321
992
    {
322
992
        PyObject *RawIO_class = (PyObject *)state->PyFileIO_Type;
323
#ifdef HAVE_WINDOWS_CONSOLE_IO
324
        const PyConfig *config = _Py_GetConfig();
325
        if (!config->legacy_windows_stdio && _PyIO_get_console_type(path_or_fd) != '\0') {
326
            RawIO_class = (PyObject *)state->PyWindowsConsoleIO_Type;
327
            encoding = "utf-8";
328
        }
329
#endif
330
992
        raw = PyObject_CallFunction(RawIO_class, "OsOO",
331
992
                                    path_or_fd, rawmode,
332
992
                                    closefd ? Py_True : Py_False,
333
992
                                    opener);
334
992
    }
335
336
992
    if (raw == NULL)
337
0
        goto error;
338
992
    result = raw;
339
340
992
    Py_SETREF(path_or_fd, NULL);
341
342
992
    modeobj = PyUnicode_FromString(mode);
343
992
    if (modeobj == NULL)
344
0
        goto error;
345
346
    /* buffering */
347
992
    if (buffering < 0) {
348
992
        PyObject *res = PyObject_CallMethodNoArgs(raw, &_Py_ID(_isatty_open_only));
349
992
        if (res == NULL)
350
0
            goto error;
351
992
        isatty = PyObject_IsTrue(res);
352
992
        Py_DECREF(res);
353
992
        if (isatty < 0)
354
0
            goto error;
355
992
    }
356
357
992
    if (buffering == 1 || isatty) {
358
0
        buffering = -1;
359
0
        line_buffering = 1;
360
0
    }
361
992
    else
362
992
        line_buffering = 0;
363
364
992
    if (buffering < 0) {
365
992
        PyObject *blksize_obj;
366
992
        blksize_obj = PyObject_GetAttr(raw, &_Py_ID(_blksize));
367
992
        if (blksize_obj == NULL)
368
0
            goto error;
369
992
        buffering = PyLong_AsLong(blksize_obj);
370
992
        Py_DECREF(blksize_obj);
371
992
        if (buffering == -1 && PyErr_Occurred())
372
0
            goto error;
373
992
        buffering = Py_MAX(Py_MIN(buffering, 8192 * 1024), DEFAULT_BUFFER_SIZE);
374
992
    }
375
992
    if (buffering < 0) {
376
0
        PyErr_SetString(PyExc_ValueError,
377
0
                        "invalid buffering size");
378
0
        goto error;
379
0
    }
380
381
    /* if not buffering, returns the raw file object */
382
992
    if (buffering == 0) {
383
0
        if (!binary) {
384
0
            PyErr_SetString(PyExc_ValueError,
385
0
                            "can't have unbuffered text I/O");
386
0
            goto error;
387
0
        }
388
389
0
        Py_DECREF(modeobj);
390
0
        return result;
391
0
    }
392
393
    /* wraps into a buffered file */
394
992
    {
395
992
        PyObject *Buffered_class;
396
397
992
        if (updating) {
398
0
            Buffered_class = (PyObject *)state->PyBufferedRandom_Type;
399
0
        }
400
992
        else if (creating || writing || appending) {
401
32
            Buffered_class = (PyObject *)state->PyBufferedWriter_Type;
402
32
        }
403
960
        else if (reading) {
404
960
            Buffered_class = (PyObject *)state->PyBufferedReader_Type;
405
960
        }
406
0
        else {
407
0
            PyErr_Format(PyExc_ValueError,
408
0
                         "unknown mode: '%s'", mode);
409
0
            goto error;
410
0
        }
411
412
992
        buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering);
413
992
    }
414
992
    if (buffer == NULL)
415
0
        goto error;
416
992
    result = buffer;
417
992
    Py_DECREF(raw);
418
419
420
    /* if binary, returns the buffered file */
421
992
    if (binary) {
422
992
        Py_DECREF(modeobj);
423
992
        return result;
424
992
    }
425
426
    /* wraps into a TextIOWrapper */
427
0
    wrapper = PyObject_CallFunction((PyObject *)state->PyTextIOWrapper_Type,
428
0
                                    "OsssO",
429
0
                                    buffer,
430
0
                                    encoding, errors, newline,
431
0
                                    line_buffering ? Py_True : Py_False);
432
0
    if (wrapper == NULL)
433
0
        goto error;
434
0
    result = wrapper;
435
0
    Py_DECREF(buffer);
436
437
0
    if (PyObject_SetAttr(wrapper, &_Py_ID(mode), modeobj) < 0)
438
0
        goto error;
439
0
    Py_DECREF(modeobj);
440
0
    return result;
441
442
0
  error:
443
0
    if (result != NULL) {
444
0
        PyObject *exc = PyErr_GetRaisedException();
445
0
        PyObject *close_result = PyObject_CallMethodNoArgs(result, &_Py_ID(close));
446
0
        _PyErr_ChainExceptions1(exc);
447
0
        Py_XDECREF(close_result);
448
0
        Py_DECREF(result);
449
0
    }
450
0
    Py_XDECREF(path_or_fd);
451
0
    Py_XDECREF(modeobj);
452
0
    return NULL;
453
0
}
454
455
456
/*[clinic input]
457
_io.text_encoding
458
    encoding: object
459
    stacklevel: int = 2
460
    /
461
462
A helper function to choose the text encoding.
463
464
When encoding is not None, this function returns it.
465
Otherwise, this function returns the default text encoding
466
(i.e. "locale" or "utf-8" depends on UTF-8 mode).
467
468
This function emits an EncodingWarning if encoding is None and
469
sys.flags.warn_default_encoding is true.
470
471
This can be used in APIs with an encoding=None parameter.
472
However, please consider using encoding="utf-8" for new APIs.
473
[clinic start generated code]*/
474
475
static PyObject *
476
_io_text_encoding_impl(PyObject *module, PyObject *encoding, int stacklevel)
477
/*[clinic end generated code: output=91b2cfea6934cc0c input=4999aa8b3d90f3d4]*/
478
0
{
479
0
    if (encoding == NULL || encoding == Py_None) {
480
0
        PyInterpreterState *interp = _PyInterpreterState_GET();
481
0
        if (_PyInterpreterState_GetConfig(interp)->warn_default_encoding) {
482
0
            if (PyErr_WarnEx(PyExc_EncodingWarning,
483
0
                             "'encoding' argument not specified", stacklevel)) {
484
0
                return NULL;
485
0
            }
486
0
        }
487
0
        const PyPreConfig *preconfig = &_PyRuntime.preconfig;
488
0
        if (preconfig->utf8_mode) {
489
0
            _Py_DECLARE_STR(utf_8, "utf-8");
490
0
            encoding = &_Py_STR(utf_8);
491
0
        }
492
0
        else {
493
0
            encoding = &_Py_ID(locale);
494
0
        }
495
0
    }
496
0
    return Py_NewRef(encoding);
497
0
}
498
499
500
/*[clinic input]
501
_io.open_code
502
503
    path : unicode
504
505
Opens the provided file with the intent to import the contents.
506
507
This may perform extra validation beyond open(), but is otherwise interchangeable
508
with calling open(path, 'rb').
509
510
[clinic start generated code]*/
511
512
static PyObject *
513
_io_open_code_impl(PyObject *module, PyObject *path)
514
/*[clinic end generated code: output=2fe4ecbd6f3d6844 input=f5c18e23f4b2ed9f]*/
515
944
{
516
944
    return PyFile_OpenCodeObject(path);
517
944
}
518
519
/*
520
 * Private helpers for the io module.
521
 */
522
523
Py_off_t
524
PyNumber_AsOff_t(PyObject *item, PyObject *err)
525
1.04k
{
526
1.04k
    Py_off_t result;
527
1.04k
    PyObject *runerr;
528
1.04k
    PyObject *value = _PyNumber_Index(item);
529
1.04k
    if (value == NULL)
530
0
        return -1;
531
532
    /* We're done if PyLong_AsSsize_t() returns without error. */
533
1.04k
    result = PyLong_AsOff_t(value);
534
1.04k
    if (result != -1 || !(runerr = PyErr_Occurred()))
535
1.04k
        goto finish;
536
537
    /* Error handling code -- only manage OverflowError differently */
538
0
    if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError))
539
0
        goto finish;
540
541
0
    PyErr_Clear();
542
    /* If no error-handling desired then the default clipping
543
       is sufficient.
544
     */
545
0
    if (!err) {
546
0
        assert(PyLong_Check(value));
547
0
        if (_PyLong_IsNegative((PyLongObject *)value))
548
0
            result = PY_OFF_T_MIN;
549
0
        else
550
0
            result = PY_OFF_T_MAX;
551
0
    }
552
0
    else {
553
        /* Otherwise replace the error with caller's error object. */
554
0
        PyErr_Format(err,
555
0
                     "cannot fit '%.200s' into an offset-sized integer",
556
0
                     Py_TYPE(item)->tp_name);
557
0
    }
558
559
1.04k
 finish:
560
1.04k
    Py_DECREF(value);
561
1.04k
    return result;
562
0
}
563
564
static int
565
5.58k
iomodule_traverse(PyObject *mod, visitproc visit, void *arg) {
566
5.58k
    _PyIO_State *state = get_io_state(mod);
567
5.58k
    Py_VISIT(state->unsupported_operation);
568
569
5.58k
    Py_VISIT(state->PyIOBase_Type);
570
5.58k
    Py_VISIT(state->PyIncrementalNewlineDecoder_Type);
571
5.58k
    Py_VISIT(state->PyRawIOBase_Type);
572
5.58k
    Py_VISIT(state->PyBufferedIOBase_Type);
573
5.58k
    Py_VISIT(state->PyBufferedRWPair_Type);
574
5.58k
    Py_VISIT(state->PyBufferedRandom_Type);
575
5.58k
    Py_VISIT(state->PyBufferedReader_Type);
576
5.58k
    Py_VISIT(state->PyBufferedWriter_Type);
577
5.58k
    Py_VISIT(state->PyBytesIOBuffer_Type);
578
5.58k
    Py_VISIT(state->PyBytesIO_Type);
579
5.58k
    Py_VISIT(state->PyFileIO_Type);
580
5.58k
    Py_VISIT(state->PyStringIO_Type);
581
5.58k
    Py_VISIT(state->PyTextIOBase_Type);
582
5.58k
    Py_VISIT(state->PyTextIOWrapper_Type);
583
#ifdef HAVE_WINDOWS_CONSOLE_IO
584
    Py_VISIT(state->PyWindowsConsoleIO_Type);
585
#endif
586
5.58k
    return 0;
587
5.58k
}
588
589
590
static int
591
0
iomodule_clear(PyObject *mod) {
592
0
    _PyIO_State *state = get_io_state(mod);
593
0
    Py_CLEAR(state->unsupported_operation);
594
595
0
    Py_CLEAR(state->PyIOBase_Type);
596
0
    Py_CLEAR(state->PyIncrementalNewlineDecoder_Type);
597
0
    Py_CLEAR(state->PyRawIOBase_Type);
598
0
    Py_CLEAR(state->PyBufferedIOBase_Type);
599
0
    Py_CLEAR(state->PyBufferedRWPair_Type);
600
0
    Py_CLEAR(state->PyBufferedRandom_Type);
601
0
    Py_CLEAR(state->PyBufferedReader_Type);
602
0
    Py_CLEAR(state->PyBufferedWriter_Type);
603
0
    Py_CLEAR(state->PyBytesIOBuffer_Type);
604
0
    Py_CLEAR(state->PyBytesIO_Type);
605
0
    Py_CLEAR(state->PyFileIO_Type);
606
0
    Py_CLEAR(state->PyStringIO_Type);
607
0
    Py_CLEAR(state->PyTextIOBase_Type);
608
0
    Py_CLEAR(state->PyTextIOWrapper_Type);
609
#ifdef HAVE_WINDOWS_CONSOLE_IO
610
    Py_CLEAR(state->PyWindowsConsoleIO_Type);
611
#endif
612
0
    return 0;
613
0
}
614
615
static void
616
iomodule_free(void *mod)
617
0
{
618
0
    (void)iomodule_clear((PyObject *)mod);
619
0
}
620
621
622
/*
623
 * Module definition
624
 */
625
626
#define clinic_state() (get_io_state(module))
627
#include "clinic/_iomodule.c.h"
628
#undef clinic_state
629
630
static PyMethodDef module_methods[] = {
631
    _IO_OPEN_METHODDEF
632
    _IO_TEXT_ENCODING_METHODDEF
633
    _IO_OPEN_CODE_METHODDEF
634
    {NULL, NULL}
635
};
636
637
224
#define ADD_TYPE(module, type, spec, base)                               \
638
224
do {                                                                     \
639
224
    type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec,        \
640
224
                                                    (PyObject *)base);   \
641
224
    if (type == NULL) {                                                  \
642
0
        return -1;                                                       \
643
0
    }                                                                    \
644
224
    if (PyModule_AddType(module, type) < 0) {                            \
645
0
        return -1;                                                       \
646
0
    }                                                                    \
647
224
} while (0)
648
649
static int
650
iomodule_exec(PyObject *m)
651
16
{
652
16
    _PyIO_State *state = get_io_state(m);
653
654
    /* DEFAULT_BUFFER_SIZE */
655
16
    if (PyModule_AddIntMacro(m, DEFAULT_BUFFER_SIZE) < 0)
656
0
        return -1;
657
658
    /* UnsupportedOperation inherits from ValueError and OSError */
659
16
    state->unsupported_operation = PyObject_CallFunction(
660
16
        (PyObject *)&PyType_Type, "s(OO){}",
661
16
        "UnsupportedOperation", PyExc_OSError, PyExc_ValueError);
662
16
    if (state->unsupported_operation == NULL)
663
0
        return -1;
664
16
    if (PyObject_SetAttrString(state->unsupported_operation,
665
16
                               "__module__", &_Py_ID(io)) < 0)
666
0
    {
667
0
        return -1;
668
0
    }
669
16
    if (PyModule_AddObjectRef(m, "UnsupportedOperation",
670
16
                              state->unsupported_operation) < 0)
671
0
    {
672
0
        return -1;
673
0
    }
674
675
    /* BlockingIOError, for compatibility */
676
16
    if (PyModule_AddObjectRef(m, "BlockingIOError",
677
16
                              (PyObject *) PyExc_BlockingIOError) < 0) {
678
0
        return -1;
679
0
    }
680
681
    // Base classes
682
16
    ADD_TYPE(m, state->PyIncrementalNewlineDecoder_Type, &nldecoder_spec, NULL);
683
16
    ADD_TYPE(m, state->PyBytesIOBuffer_Type, &bytesiobuf_spec, NULL);
684
16
    ADD_TYPE(m, state->PyIOBase_Type, &iobase_spec, NULL);
685
686
    // PyIOBase_Type subclasses
687
16
    ADD_TYPE(m, state->PyTextIOBase_Type, &textiobase_spec,
688
16
             state->PyIOBase_Type);
689
16
    ADD_TYPE(m, state->PyBufferedIOBase_Type, &bufferediobase_spec,
690
16
             state->PyIOBase_Type);
691
16
    ADD_TYPE(m, state->PyRawIOBase_Type, &rawiobase_spec,
692
16
             state->PyIOBase_Type);
693
694
    // PyBufferedIOBase_Type(PyIOBase_Type) subclasses
695
16
    ADD_TYPE(m, state->PyBytesIO_Type, &bytesio_spec, state->PyBufferedIOBase_Type);
696
16
    ADD_TYPE(m, state->PyBufferedWriter_Type, &bufferedwriter_spec,
697
16
             state->PyBufferedIOBase_Type);
698
16
    ADD_TYPE(m, state->PyBufferedReader_Type, &bufferedreader_spec,
699
16
             state->PyBufferedIOBase_Type);
700
16
    ADD_TYPE(m, state->PyBufferedRWPair_Type, &bufferedrwpair_spec,
701
16
             state->PyBufferedIOBase_Type);
702
16
    ADD_TYPE(m, state->PyBufferedRandom_Type, &bufferedrandom_spec,
703
16
             state->PyBufferedIOBase_Type);
704
705
    // PyRawIOBase_Type(PyIOBase_Type) subclasses
706
16
    ADD_TYPE(m, state->PyFileIO_Type, &fileio_spec, state->PyRawIOBase_Type);
707
708
#ifdef HAVE_WINDOWS_CONSOLE_IO
709
    ADD_TYPE(m, state->PyWindowsConsoleIO_Type, &winconsoleio_spec,
710
             state->PyRawIOBase_Type);
711
#endif
712
713
    // PyTextIOBase_Type(PyIOBase_Type) subclasses
714
16
    ADD_TYPE(m, state->PyStringIO_Type, &stringio_spec, state->PyTextIOBase_Type);
715
16
    ADD_TYPE(m, state->PyTextIOWrapper_Type, &textiowrapper_spec,
716
16
             state->PyTextIOBase_Type);
717
718
16
#undef ADD_TYPE
719
16
    return 0;
720
16
}
721
722
static struct PyModuleDef_Slot iomodule_slots[] = {
723
    {Py_mod_exec, iomodule_exec},
724
    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
725
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
726
    {0, NULL},
727
};
728
729
struct PyModuleDef _PyIO_Module = {
730
    .m_base = PyModuleDef_HEAD_INIT,
731
    .m_name = "io",
732
    .m_doc = module_doc,
733
    .m_size = sizeof(_PyIO_State),
734
    .m_methods = module_methods,
735
    .m_traverse = iomodule_traverse,
736
    .m_clear = iomodule_clear,
737
    .m_free = iomodule_free,
738
    .m_slots = iomodule_slots,
739
};
740
741
PyMODINIT_FUNC
742
PyInit__io(void)
743
16
{
744
16
    return PyModuleDef_Init(&_PyIO_Module);
745
16
}