/src/cpython/Modules/_io/iobase.c
Line | Count | Source |
1 | | /* |
2 | | An implementation of the I/O abstract base classes hierarchy |
3 | | as defined by PEP 3116 - "New I/O" |
4 | | |
5 | | Classes defined here: IOBase, RawIOBase. |
6 | | |
7 | | Written by Amaury Forgeot d'Arc and Antoine Pitrou |
8 | | */ |
9 | | |
10 | | |
11 | | #include "Python.h" |
12 | | #include "pycore_call.h" // _PyObject_CallMethod() |
13 | | #include "pycore_fileutils.h" // _PyFile_Flush |
14 | | #include "pycore_long.h" // _PyLong_GetOne() |
15 | | #include "pycore_object.h" // _PyType_HasFeature() |
16 | | #include "pycore_pyerrors.h" // _PyErr_ChainExceptions1() |
17 | | #include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() |
18 | | |
19 | | #include <stddef.h> // offsetof() |
20 | | #include "_iomodule.h" |
21 | | |
22 | | /*[clinic input] |
23 | | module _io |
24 | | class _io._IOBase "PyObject *" "clinic_state()->PyIOBase_Type" |
25 | | class _io._RawIOBase "PyObject *" "clinic_state()->PyRawIOBase_Type" |
26 | | [clinic start generated code]*/ |
27 | | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=9006b7802ab8ea85]*/ |
28 | | |
29 | | /* |
30 | | * IOBase class, an abstract class |
31 | | */ |
32 | | |
33 | | typedef struct { |
34 | | PyObject_HEAD |
35 | | |
36 | | PyObject *dict; |
37 | | PyObject *weakreflist; |
38 | | } iobase; |
39 | | |
40 | 50.5k | #define iobase_CAST(op) ((iobase *)(op)) |
41 | | |
42 | | PyDoc_STRVAR(iobase_doc, |
43 | | "The abstract base class for all I/O classes.\n" |
44 | | "\n" |
45 | | "This class provides dummy implementations for many methods that\n" |
46 | | "derived classes can override selectively; the default implementations\n" |
47 | | "represent a file that cannot be read, written or seeked.\n" |
48 | | "\n" |
49 | | "Even though IOBase does not declare read, readinto, or write because\n" |
50 | | "their signatures will vary, implementations and clients should\n" |
51 | | "consider those methods part of the interface. Also, implementations\n" |
52 | | "may raise UnsupportedOperation when operations they do not support are\n" |
53 | | "called.\n" |
54 | | "\n" |
55 | | "The basic type used for binary data read from or written to a file is\n" |
56 | | "bytes. Other bytes-like objects are accepted as method arguments too.\n" |
57 | | "In some cases (such as readinto), a writable object is required. Text\n" |
58 | | "I/O classes work with str data.\n" |
59 | | "\n" |
60 | | "Note that calling any method (except additional calls to close(),\n" |
61 | | "which are ignored) on a closed stream should raise a ValueError.\n" |
62 | | "\n" |
63 | | "IOBase (and its subclasses) support the iterator protocol, meaning\n" |
64 | | "that an IOBase object can be iterated over yielding the lines in a\n" |
65 | | "stream.\n" |
66 | | "\n" |
67 | | "IOBase also supports the :keyword:`with` statement. In this example,\n" |
68 | | "fp is closed after the suite of the with statement is complete:\n" |
69 | | "\n" |
70 | | "with open('spam.txt', 'r') as fp:\n" |
71 | | " fp.write('Spam and eggs!')\n"); |
72 | | |
73 | | |
74 | | /* Internal methods */ |
75 | | |
76 | | /* Use this function whenever you want to check the internal `closed` status |
77 | | of the IOBase object rather than the virtual `closed` attribute as returned |
78 | | by whatever subclass. */ |
79 | | |
80 | | static int |
81 | | iobase_is_closed(PyObject *self) |
82 | 8.68M | { |
83 | 8.68M | return PyObject_HasAttrWithError(self, &_Py_ID(__IOBase_closed)); |
84 | 8.68M | } |
85 | | |
86 | | static PyObject * |
87 | | iobase_unsupported(_PyIO_State *state, const char *message) |
88 | 5 | { |
89 | 5 | PyErr_SetString(state->unsupported_operation, message); |
90 | 5 | return NULL; |
91 | 5 | } |
92 | | |
93 | | /* Positioning */ |
94 | | |
95 | | /*[clinic input] |
96 | | _io._IOBase.seek |
97 | | cls: defining_class |
98 | | offset: int(unused=True) |
99 | | The stream position, relative to 'whence'. |
100 | | whence: int(unused=True, c_default='0') = os.SEEK_SET |
101 | | The relative position to seek from. |
102 | | / |
103 | | |
104 | | Change the stream position to the given byte offset. |
105 | | |
106 | | The offset is interpreted relative to the position indicated by |
107 | | whence. Values for whence are: |
108 | | |
109 | | * os.SEEK_SET or 0 -- start of stream (the default); offset should |
110 | | be zero or positive |
111 | | * os.SEEK_CUR or 1 -- current stream position; offset may be |
112 | | negative |
113 | | * os.SEEK_END or 2 -- end of stream; offset is usually negative |
114 | | |
115 | | Return the new absolute position. |
116 | | [clinic start generated code]*/ |
117 | | |
118 | | static PyObject * |
119 | | _io__IOBase_seek_impl(PyObject *self, PyTypeObject *cls, |
120 | | int Py_UNUSED(offset), int Py_UNUSED(whence)) |
121 | | /*[clinic end generated code: output=8bd74ea6538ded53 input=22eaf07a7a0ee289]*/ |
122 | 5 | { |
123 | 5 | _PyIO_State *state = get_io_state_by_cls(cls); |
124 | 5 | return iobase_unsupported(state, "seek"); |
125 | 5 | } |
126 | | |
127 | | /*[clinic input] |
128 | | _io._IOBase.tell |
129 | | |
130 | | Return current stream position. |
131 | | [clinic start generated code]*/ |
132 | | |
133 | | static PyObject * |
134 | | _io__IOBase_tell_impl(PyObject *self) |
135 | | /*[clinic end generated code: output=89a1c0807935abe2 input=04e615fec128801f]*/ |
136 | 1.37M | { |
137 | 1.37M | return _PyObject_CallMethod(self, &_Py_ID(seek), "ii", 0, 1); |
138 | 1.37M | } |
139 | | |
140 | | /*[clinic input] |
141 | | _io._IOBase.truncate |
142 | | cls: defining_class |
143 | | size: object(unused=True) = None |
144 | | / |
145 | | |
146 | | Truncate file to size bytes. |
147 | | |
148 | | File pointer is left unchanged. Size defaults to the current IO |
149 | | position as reported by tell(). Return the new size. |
150 | | [clinic start generated code]*/ |
151 | | |
152 | | static PyObject * |
153 | | _io__IOBase_truncate_impl(PyObject *self, PyTypeObject *cls, |
154 | | PyObject *Py_UNUSED(size)) |
155 | | /*[clinic end generated code: output=2013179bff1fe8ef input=5b3b6ab3c7abd806]*/ |
156 | 0 | { |
157 | 0 | _PyIO_State *state = get_io_state_by_cls(cls); |
158 | 0 | return iobase_unsupported(state, "truncate"); |
159 | 0 | } |
160 | | |
161 | | /* Flush and close methods */ |
162 | | |
163 | | /*[clinic input] |
164 | | _io._IOBase.flush |
165 | | |
166 | | Flush write buffers, if applicable. |
167 | | |
168 | | This is not implemented for read-only and non-blocking streams. |
169 | | [clinic start generated code]*/ |
170 | | |
171 | | static PyObject * |
172 | | _io__IOBase_flush_impl(PyObject *self) |
173 | | /*[clinic end generated code: output=7cef4b4d54656a3b input=773be121abe270aa]*/ |
174 | 1.44M | { |
175 | | /* XXX Should this return the number of bytes written??? */ |
176 | 1.44M | int closed = iobase_is_closed(self); |
177 | | |
178 | 1.44M | if (!closed) { |
179 | 1.44M | Py_RETURN_NONE; |
180 | 1.44M | } |
181 | 0 | if (closed > 0) { |
182 | 0 | PyErr_SetString(PyExc_ValueError, "I/O operation on closed file."); |
183 | 0 | } |
184 | 0 | return NULL; |
185 | 1.44M | } |
186 | | |
187 | | /*[clinic input] |
188 | | @getter |
189 | | _io._IOBase.closed -> bool |
190 | | |
191 | | True if the file is closed. |
192 | | [clinic start generated code]*/ |
193 | | |
194 | | static int |
195 | | _io__IOBase_closed_get_impl(PyObject *self) |
196 | | /*[clinic end generated code: output=561af4ea236d16d9 input=e730fe4ccc4c096c]*/ |
197 | 7.17M | { |
198 | 7.17M | return iobase_is_closed(self); |
199 | 7.17M | } |
200 | | |
201 | | static int |
202 | | iobase_check_closed(PyObject *self) |
203 | 94.7k | { |
204 | 94.7k | PyObject *res; |
205 | 94.7k | int closed; |
206 | | /* This gets the derived attribute, which is *not* __IOBase_closed |
207 | | in most cases! */ |
208 | 94.7k | closed = PyObject_GetOptionalAttr(self, &_Py_ID(closed), &res); |
209 | 94.7k | if (closed > 0) { |
210 | 94.7k | closed = PyObject_IsTrue(res); |
211 | 94.7k | Py_DECREF(res); |
212 | 94.7k | if (closed > 0) { |
213 | 0 | PyErr_SetString(PyExc_ValueError, "I/O operation on closed file."); |
214 | 0 | return -1; |
215 | 0 | } |
216 | 94.7k | } |
217 | 94.7k | return closed; |
218 | 94.7k | } |
219 | | |
220 | | PyObject * |
221 | | _PyIOBase_check_closed(PyObject *self, PyObject *args) |
222 | 0 | { |
223 | 0 | if (iobase_check_closed(self)) { |
224 | 0 | return NULL; |
225 | 0 | } |
226 | 0 | if (args == Py_True) { |
227 | 0 | return Py_None; |
228 | 0 | } |
229 | 0 | Py_RETURN_NONE; |
230 | 0 | } |
231 | | |
232 | | /*[clinic input] |
233 | | _io._IOBase._checkClosed |
234 | | [clinic start generated code]*/ |
235 | | |
236 | | static PyObject * |
237 | | _io__IOBase__checkClosed_impl(PyObject *self) |
238 | | /*[clinic end generated code: output=8fb8412185623f1a input=8d18d2e67b2270bb]*/ |
239 | 0 | { |
240 | 0 | return _PyIOBase_check_closed(self, NULL); |
241 | 0 | } |
242 | | |
243 | | /*[clinic input] |
244 | | _io._IOBase._checkSeekable |
245 | | [clinic start generated code]*/ |
246 | | |
247 | | static PyObject * |
248 | | _io__IOBase__checkSeekable_impl(PyObject *self) |
249 | | /*[clinic end generated code: output=10f09b515a9f4c4f input=479853eded776b0e]*/ |
250 | 0 | { |
251 | 0 | _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); |
252 | 0 | return _PyIOBase_check_seekable(state, self, NULL); |
253 | 0 | } |
254 | | |
255 | | /*[clinic input] |
256 | | _io._IOBase._checkReadable |
257 | | [clinic start generated code]*/ |
258 | | |
259 | | static PyObject * |
260 | | _io__IOBase__checkReadable_impl(PyObject *self) |
261 | | /*[clinic end generated code: output=33ccab8a7c4550fb input=63fbf50b36772323]*/ |
262 | 0 | { |
263 | 0 | _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); |
264 | 0 | return _PyIOBase_check_readable(state, self, NULL); |
265 | 0 | } |
266 | | |
267 | | /*[clinic input] |
268 | | _io._IOBase._checkWritable |
269 | | [clinic start generated code]*/ |
270 | | |
271 | | static PyObject * |
272 | | _io__IOBase__checkWritable_impl(PyObject *self) |
273 | | /*[clinic end generated code: output=8cfc6b4b2469d2a3 input=2758c7291cf5911e]*/ |
274 | 0 | { |
275 | 0 | _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); |
276 | 0 | return _PyIOBase_check_writable(state, self, NULL); |
277 | 0 | } |
278 | | |
279 | | PyObject * |
280 | | _PyIOBase_cannot_pickle(PyObject *self, PyObject *args) |
281 | 0 | { |
282 | 0 | PyErr_Format(PyExc_TypeError, |
283 | 0 | "cannot pickle '%.100s' instances", _PyType_Name(Py_TYPE(self))); |
284 | 0 | return NULL; |
285 | 0 | } |
286 | | |
287 | | /* XXX: IOBase thinks it has to maintain its own internal state in |
288 | | `__IOBase_closed` and call flush() by itself, but it is redundant with |
289 | | whatever behaviour a non-trivial derived class will implement. */ |
290 | | |
291 | | /*[clinic input] |
292 | | _io._IOBase.close |
293 | | |
294 | | Flush and close the IO object. |
295 | | |
296 | | This method has no effect if the file is already closed. |
297 | | [clinic start generated code]*/ |
298 | | |
299 | | static PyObject * |
300 | | _io__IOBase_close_impl(PyObject *self) |
301 | | /*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/ |
302 | 65.1k | { |
303 | 65.1k | int rc1, rc2, closed = iobase_is_closed(self); |
304 | | |
305 | 65.1k | if (closed < 0) { |
306 | 0 | return NULL; |
307 | 0 | } |
308 | 65.1k | if (closed) { |
309 | 0 | Py_RETURN_NONE; |
310 | 0 | } |
311 | | |
312 | 65.1k | rc1 = _PyFile_Flush(self); |
313 | 65.1k | PyObject *exc = PyErr_GetRaisedException(); |
314 | 65.1k | rc2 = PyObject_SetAttr(self, &_Py_ID(__IOBase_closed), Py_True); |
315 | 65.1k | _PyErr_ChainExceptions1(exc); |
316 | 65.1k | if (rc1 < 0 || rc2 < 0) { |
317 | 0 | return NULL; |
318 | 0 | } |
319 | | |
320 | 65.1k | Py_RETURN_NONE; |
321 | 65.1k | } |
322 | | |
323 | | /* Finalization and garbage collection support */ |
324 | | |
325 | | static void |
326 | | iobase_finalize(PyObject *self) |
327 | 99.4k | { |
328 | 99.4k | PyObject *res; |
329 | 99.4k | int closed; |
330 | | |
331 | | /* Save the current exception, if any. */ |
332 | 99.4k | PyObject *exc = PyErr_GetRaisedException(); |
333 | | |
334 | | /* If `closed` doesn't exist or can't be evaluated as bool, then the |
335 | | object is probably in an unusable state, so ignore. */ |
336 | 99.4k | if (PyObject_GetOptionalAttr(self, &_Py_ID(closed), &res) <= 0) { |
337 | 0 | PyErr_Clear(); |
338 | 0 | closed = -1; |
339 | 0 | } |
340 | 99.4k | else { |
341 | 99.4k | closed = PyObject_IsTrue(res); |
342 | 99.4k | Py_DECREF(res); |
343 | 99.4k | if (closed == -1) |
344 | 0 | PyErr_Clear(); |
345 | 99.4k | } |
346 | 99.4k | if (closed == 0) { |
347 | | /* Signal close() that it was called as part of the object |
348 | | finalization process. */ |
349 | 9.43k | if (PyObject_SetAttr(self, &_Py_ID(_finalizing), Py_True)) |
350 | 0 | PyErr_Clear(); |
351 | 9.43k | res = PyObject_CallMethodNoArgs((PyObject *)self, &_Py_ID(close)); |
352 | 9.43k | if (res == NULL) { |
353 | 0 | PyErr_FormatUnraisable("Exception ignored " |
354 | 0 | "while finalizing file %R", self); |
355 | 0 | } |
356 | 9.43k | else { |
357 | 9.43k | Py_DECREF(res); |
358 | 9.43k | } |
359 | 9.43k | } |
360 | | |
361 | | /* Restore the saved exception. */ |
362 | 99.4k | PyErr_SetRaisedException(exc); |
363 | 99.4k | } |
364 | | |
365 | | int |
366 | | _PyIOBase_finalize(PyObject *self) |
367 | 99.4k | { |
368 | 99.4k | int is_zombie; |
369 | | |
370 | | /* If _PyIOBase_finalize() is called from a destructor, we need to |
371 | | resurrect the object as calling close() can invoke arbitrary code. */ |
372 | 99.4k | is_zombie = (Py_REFCNT(self) == 0); |
373 | 99.4k | if (is_zombie) |
374 | 99.4k | return PyObject_CallFinalizerFromDealloc(self); |
375 | 0 | else { |
376 | 0 | PyObject_CallFinalizer(self); |
377 | 0 | return 0; |
378 | 0 | } |
379 | 99.4k | } |
380 | | |
381 | | static int |
382 | | iobase_traverse(PyObject *op, visitproc visit, void *arg) |
383 | 5.07k | { |
384 | 5.07k | iobase *self = iobase_CAST(op); |
385 | 5.07k | Py_VISIT(Py_TYPE(self)); |
386 | 5.07k | Py_VISIT(self->dict); |
387 | 5.07k | return 0; |
388 | 5.07k | } |
389 | | |
390 | | static int |
391 | | iobase_clear(PyObject *op) |
392 | 0 | { |
393 | 0 | iobase *self = iobase_CAST(op); |
394 | 0 | Py_CLEAR(self->dict); |
395 | 0 | return 0; |
396 | 0 | } |
397 | | |
398 | | /* Destructor */ |
399 | | |
400 | | static void |
401 | | iobase_dealloc(PyObject *op) |
402 | 45.4k | { |
403 | | /* NOTE: since IOBaseObject has its own dict, Python-defined attributes |
404 | | are still available here for close() to use. |
405 | | However, if the derived class declares a __slots__, those slots are |
406 | | already gone. |
407 | | */ |
408 | 45.4k | iobase *self = iobase_CAST(op); |
409 | 45.4k | if (_PyIOBase_finalize(op) < 0) { |
410 | | /* When called from a heap type's dealloc, the type will be |
411 | | decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ |
412 | 0 | if (_PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) { |
413 | 0 | Py_INCREF(Py_TYPE(self)); |
414 | 0 | } |
415 | 0 | return; |
416 | 0 | } |
417 | 45.4k | PyTypeObject *tp = Py_TYPE(self); |
418 | 45.4k | _PyObject_GC_UNTRACK(self); |
419 | 45.4k | FT_CLEAR_WEAKREFS(op, self->weakreflist); |
420 | 45.4k | Py_CLEAR(self->dict); |
421 | 45.4k | tp->tp_free(self); |
422 | 45.4k | Py_DECREF(tp); |
423 | 45.4k | } |
424 | | |
425 | | /* Inquiry methods */ |
426 | | |
427 | | /*[clinic input] |
428 | | _io._IOBase.seekable |
429 | | |
430 | | Return whether object supports random access. |
431 | | |
432 | | If False, seek(), tell() and truncate() will raise OSError. |
433 | | This method may need to do a test seek(). |
434 | | [clinic start generated code]*/ |
435 | | |
436 | | static PyObject * |
437 | | _io__IOBase_seekable_impl(PyObject *self) |
438 | | /*[clinic end generated code: output=4c24c67f5f32a43d input=b976622f7fdf3063]*/ |
439 | 0 | { |
440 | 0 | Py_RETURN_FALSE; |
441 | 0 | } |
442 | | |
443 | | PyObject * |
444 | | _PyIOBase_check_seekable(_PyIO_State *state, PyObject *self, PyObject *args) |
445 | 1.37M | { |
446 | 1.37M | PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(seekable)); |
447 | 1.37M | if (res == NULL) |
448 | 0 | return NULL; |
449 | 1.37M | if (res != Py_True) { |
450 | 0 | Py_CLEAR(res); |
451 | 0 | iobase_unsupported(state, "File or stream is not seekable."); |
452 | 0 | return NULL; |
453 | 0 | } |
454 | 1.37M | if (args == Py_True) { |
455 | 1.37M | Py_DECREF(res); |
456 | 1.37M | } |
457 | 1.37M | return res; |
458 | 1.37M | } |
459 | | |
460 | | /*[clinic input] |
461 | | _io._IOBase.readable |
462 | | |
463 | | Return whether object was opened for reading. |
464 | | |
465 | | If False, read() will raise OSError. |
466 | | [clinic start generated code]*/ |
467 | | |
468 | | static PyObject * |
469 | | _io__IOBase_readable_impl(PyObject *self) |
470 | | /*[clinic end generated code: output=e48089250686388b input=285b3b866a0ec35f]*/ |
471 | 75 | { |
472 | 75 | Py_RETURN_FALSE; |
473 | 75 | } |
474 | | |
475 | | /* May be called with any object */ |
476 | | PyObject * |
477 | | _PyIOBase_check_readable(_PyIO_State *state, PyObject *self, PyObject *args) |
478 | 10.6k | { |
479 | 10.6k | PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(readable)); |
480 | 10.6k | if (res == NULL) |
481 | 0 | return NULL; |
482 | 10.6k | if (res != Py_True) { |
483 | 0 | Py_CLEAR(res); |
484 | 0 | iobase_unsupported(state, "File or stream is not readable."); |
485 | 0 | return NULL; |
486 | 0 | } |
487 | 10.6k | if (args == Py_True) { |
488 | 10.6k | Py_DECREF(res); |
489 | 10.6k | } |
490 | 10.6k | return res; |
491 | 10.6k | } |
492 | | |
493 | | /*[clinic input] |
494 | | _io._IOBase.writable |
495 | | |
496 | | Return whether object was opened for writing. |
497 | | |
498 | | If False, write() will raise OSError. |
499 | | [clinic start generated code]*/ |
500 | | |
501 | | static PyObject * |
502 | | _io__IOBase_writable_impl(PyObject *self) |
503 | | /*[clinic end generated code: output=406001d0985be14f input=9dcac18a013a05b5]*/ |
504 | 55 | { |
505 | 55 | Py_RETURN_FALSE; |
506 | 55 | } |
507 | | |
508 | | /* May be called with any object */ |
509 | | PyObject * |
510 | | _PyIOBase_check_writable(_PyIO_State *state, PyObject *self, PyObject *args) |
511 | 18.8k | { |
512 | 18.8k | PyObject *res = PyObject_CallMethodNoArgs(self, &_Py_ID(writable)); |
513 | 18.8k | if (res == NULL) |
514 | 0 | return NULL; |
515 | 18.8k | if (res != Py_True) { |
516 | 0 | Py_CLEAR(res); |
517 | 0 | iobase_unsupported(state, "File or stream is not writable."); |
518 | 0 | return NULL; |
519 | 0 | } |
520 | 18.8k | if (args == Py_True) { |
521 | 18.8k | Py_DECREF(res); |
522 | 18.8k | } |
523 | 18.8k | return res; |
524 | 18.8k | } |
525 | | |
526 | | /* Context manager */ |
527 | | |
528 | | /*[clinic input] |
529 | | _io._IOBase.__enter__ |
530 | | |
531 | | Context management protocol. Returns the stream itself. |
532 | | [clinic start generated code]*/ |
533 | | |
534 | | static PyObject * |
535 | | _io__IOBase___enter___impl(PyObject *self) |
536 | | /*[clinic end generated code: output=d1e8e5b58bde3680 input=92e2d5e34ee714e5]*/ |
537 | 50.8k | { |
538 | 50.8k | if (iobase_check_closed(self)) |
539 | 0 | return NULL; |
540 | | |
541 | 50.8k | return Py_NewRef(self); |
542 | 50.8k | } |
543 | | |
544 | | /*[clinic input] |
545 | | _io._IOBase.__exit__ |
546 | | *args: tuple |
547 | | |
548 | | Context management protocol. Calls close(). |
549 | | [clinic start generated code]*/ |
550 | | |
551 | | static PyObject * |
552 | | _io__IOBase___exit___impl(PyObject *self, PyObject *args) |
553 | | /*[clinic end generated code: output=452f3e33a34e2c5c input=fd3f46a32773a170]*/ |
554 | 50.8k | { |
555 | 50.8k | return PyObject_CallMethodNoArgs(self, &_Py_ID(close)); |
556 | 50.8k | } |
557 | | |
558 | | /* Lower-level APIs */ |
559 | | |
560 | | /* XXX Should these be present even if unimplemented? */ |
561 | | |
562 | | /*[clinic input] |
563 | | _io._IOBase.fileno |
564 | | cls: defining_class |
565 | | / |
566 | | |
567 | | Return underlying file descriptor if one exists. |
568 | | |
569 | | Raise OSError if the IO object does not use a file descriptor. |
570 | | [clinic start generated code]*/ |
571 | | |
572 | | static PyObject * |
573 | | _io__IOBase_fileno_impl(PyObject *self, PyTypeObject *cls) |
574 | | /*[clinic end generated code: output=7caaa32a6f4ada3d input=1927c8bea5c85099]*/ |
575 | 0 | { |
576 | 0 | _PyIO_State *state = get_io_state_by_cls(cls); |
577 | 0 | return iobase_unsupported(state, "fileno"); |
578 | 0 | } |
579 | | |
580 | | /*[clinic input] |
581 | | _io._IOBase.isatty |
582 | | |
583 | | Return whether this is an 'interactive' stream. |
584 | | |
585 | | Return False if it can't be determined. |
586 | | [clinic start generated code]*/ |
587 | | |
588 | | static PyObject * |
589 | | _io__IOBase_isatty_impl(PyObject *self) |
590 | | /*[clinic end generated code: output=60cab77cede41cdd input=9ef76530d368458b]*/ |
591 | 0 | { |
592 | 0 | if (iobase_check_closed(self)) |
593 | 0 | return NULL; |
594 | 0 | Py_RETURN_FALSE; |
595 | 0 | } |
596 | | |
597 | | /* Readline(s) and writelines */ |
598 | | |
599 | | /*[clinic input] |
600 | | _io._IOBase.readline |
601 | | size as limit: Py_ssize_t(accept={int, NoneType}) = -1 |
602 | | / |
603 | | |
604 | | Read and return a line from the stream. |
605 | | |
606 | | If size is specified, at most size bytes will be read. |
607 | | |
608 | | The line terminator is always b'\n' for binary files; for text |
609 | | files, the newlines argument to open can be used to select the line |
610 | | terminator(s) recognized. |
611 | | [clinic start generated code]*/ |
612 | | |
613 | | static PyObject * |
614 | | _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit) |
615 | | /*[clinic end generated code: output=4479f79b58187840 input=d0c596794e877bff]*/ |
616 | 0 | { |
617 | | /* For backwards compatibility, a (slowish) readline(). */ |
618 | |
|
619 | 0 | PyObject *peek; |
620 | |
|
621 | 0 | if (PyObject_GetOptionalAttr(self, &_Py_ID(peek), &peek) < 0) { |
622 | 0 | return NULL; |
623 | 0 | } |
624 | | |
625 | 0 | PyBytesWriter *writer = PyBytesWriter_Create(0); |
626 | 0 | if (writer == NULL) { |
627 | 0 | Py_XDECREF(peek); |
628 | 0 | return NULL; |
629 | 0 | } |
630 | | |
631 | 0 | while (limit < 0 || PyBytesWriter_GetSize(writer) < limit) { |
632 | 0 | Py_ssize_t nreadahead = 1; |
633 | 0 | PyObject *b; |
634 | |
|
635 | 0 | if (peek != NULL) { |
636 | 0 | PyObject *readahead = PyObject_CallOneArg(peek, _PyLong_GetOne()); |
637 | 0 | if (readahead == NULL) { |
638 | | /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() |
639 | | when EINTR occurs so we needn't do it ourselves. */ |
640 | 0 | if (_PyIO_trap_eintr()) { |
641 | 0 | continue; |
642 | 0 | } |
643 | 0 | goto fail; |
644 | 0 | } |
645 | 0 | if (!PyBytes_Check(readahead)) { |
646 | 0 | PyErr_Format(PyExc_OSError, |
647 | 0 | "peek() should have returned a bytes object, " |
648 | 0 | "not '%.200s'", Py_TYPE(readahead)->tp_name); |
649 | 0 | Py_DECREF(readahead); |
650 | 0 | goto fail; |
651 | 0 | } |
652 | 0 | if (PyBytes_GET_SIZE(readahead) > 0) { |
653 | 0 | Py_ssize_t n = 0; |
654 | 0 | const char *buf = PyBytes_AS_STRING(readahead); |
655 | 0 | if (limit >= 0) { |
656 | 0 | do { |
657 | 0 | if (n >= PyBytes_GET_SIZE(readahead) || n >= limit) |
658 | 0 | break; |
659 | 0 | if (buf[n++] == '\n') |
660 | 0 | break; |
661 | 0 | } while (1); |
662 | 0 | } |
663 | 0 | else { |
664 | 0 | do { |
665 | 0 | if (n >= PyBytes_GET_SIZE(readahead)) |
666 | 0 | break; |
667 | 0 | if (buf[n++] == '\n') |
668 | 0 | break; |
669 | 0 | } while (1); |
670 | 0 | } |
671 | 0 | nreadahead = n; |
672 | 0 | } |
673 | 0 | Py_DECREF(readahead); |
674 | 0 | } |
675 | | |
676 | 0 | b = _PyObject_CallMethod(self, &_Py_ID(read), "n", nreadahead); |
677 | 0 | if (b == NULL) { |
678 | | /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() |
679 | | when EINTR occurs so we needn't do it ourselves. */ |
680 | 0 | if (_PyIO_trap_eintr()) { |
681 | 0 | continue; |
682 | 0 | } |
683 | 0 | goto fail; |
684 | 0 | } |
685 | 0 | if (!PyBytes_Check(b)) { |
686 | 0 | PyErr_Format(PyExc_OSError, |
687 | 0 | "read() should have returned a bytes object, " |
688 | 0 | "not '%.200s'", Py_TYPE(b)->tp_name); |
689 | 0 | Py_DECREF(b); |
690 | 0 | goto fail; |
691 | 0 | } |
692 | 0 | if (PyBytes_GET_SIZE(b) == 0) { |
693 | 0 | Py_DECREF(b); |
694 | 0 | break; |
695 | 0 | } |
696 | | |
697 | 0 | if (PyBytesWriter_WriteBytes(writer, |
698 | 0 | PyBytes_AS_STRING(b), |
699 | 0 | PyBytes_GET_SIZE(b)) < 0) { |
700 | 0 | Py_DECREF(b); |
701 | 0 | goto fail; |
702 | 0 | } |
703 | | |
704 | 0 | Py_DECREF(b); |
705 | |
|
706 | 0 | char *data = PyBytesWriter_GetData(writer); |
707 | 0 | if (data[PyBytesWriter_GetSize(writer) - 1] == '\n') |
708 | 0 | break; |
709 | 0 | } |
710 | | |
711 | 0 | Py_XDECREF(peek); |
712 | 0 | return PyBytesWriter_Finish(writer); |
713 | 0 | fail: |
714 | 0 | Py_XDECREF(peek); |
715 | 0 | PyBytesWriter_Discard(writer); |
716 | 0 | return NULL; |
717 | 0 | } |
718 | | |
719 | | static PyObject * |
720 | | iobase_iter(PyObject *self) |
721 | 43.8k | { |
722 | 43.8k | if (iobase_check_closed(self)) |
723 | 0 | return NULL; |
724 | | |
725 | 43.8k | return Py_NewRef(self); |
726 | 43.8k | } |
727 | | |
728 | | static PyObject * |
729 | | iobase_iternext(PyObject *self) |
730 | 0 | { |
731 | 0 | PyObject *line = PyObject_CallMethodNoArgs(self, &_Py_ID(readline)); |
732 | |
|
733 | 0 | if (line == NULL) |
734 | 0 | return NULL; |
735 | | |
736 | 0 | if (PyObject_Size(line) <= 0) { |
737 | | /* Error or empty */ |
738 | 0 | Py_DECREF(line); |
739 | 0 | return NULL; |
740 | 0 | } |
741 | | |
742 | 0 | return line; |
743 | 0 | } |
744 | | |
745 | | /*[clinic input] |
746 | | _io._IOBase.readlines |
747 | | hint: Py_ssize_t(accept={int, NoneType}) = -1 |
748 | | / |
749 | | |
750 | | Return a list of lines from the stream. |
751 | | |
752 | | hint can be specified to control the number of lines read: no more |
753 | | lines will be read if the total size (in bytes/characters) of all |
754 | | lines so far exceeds hint. |
755 | | [clinic start generated code]*/ |
756 | | |
757 | | static PyObject * |
758 | | _io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint) |
759 | | /*[clinic end generated code: output=2f50421677fa3dea input=9400c786ea9dc416]*/ |
760 | 38.0k | { |
761 | 38.0k | Py_ssize_t length = 0; |
762 | 38.0k | PyObject *result, *it = NULL; |
763 | | |
764 | 38.0k | result = PyList_New(0); |
765 | 38.0k | if (result == NULL) |
766 | 0 | return NULL; |
767 | | |
768 | 38.0k | if (hint <= 0) { |
769 | | /* XXX special-casing this made sense in the Python version in order |
770 | | to remove the bytecode interpretation overhead, but it could |
771 | | probably be removed here. */ |
772 | 38.0k | PyObject *ret = PyObject_CallMethodObjArgs(result, &_Py_ID(extend), |
773 | 38.0k | self, NULL); |
774 | 38.0k | if (ret == NULL) { |
775 | 0 | goto error; |
776 | 0 | } |
777 | 38.0k | Py_DECREF(ret); |
778 | 38.0k | return result; |
779 | 38.0k | } |
780 | | |
781 | 0 | it = PyObject_GetIter(self); |
782 | 0 | if (it == NULL) { |
783 | 0 | goto error; |
784 | 0 | } |
785 | | |
786 | 0 | while (1) { |
787 | 0 | Py_ssize_t line_length; |
788 | 0 | PyObject *line = PyIter_Next(it); |
789 | 0 | if (line == NULL) { |
790 | 0 | if (PyErr_Occurred()) { |
791 | 0 | goto error; |
792 | 0 | } |
793 | 0 | else |
794 | 0 | break; /* StopIteration raised */ |
795 | 0 | } |
796 | | |
797 | 0 | if (PyList_Append(result, line) < 0) { |
798 | 0 | Py_DECREF(line); |
799 | 0 | goto error; |
800 | 0 | } |
801 | 0 | line_length = PyObject_Size(line); |
802 | 0 | Py_DECREF(line); |
803 | 0 | if (line_length < 0) { |
804 | 0 | goto error; |
805 | 0 | } |
806 | 0 | if (line_length > hint - length) |
807 | 0 | break; |
808 | 0 | length += line_length; |
809 | 0 | } |
810 | | |
811 | 0 | Py_DECREF(it); |
812 | 0 | return result; |
813 | | |
814 | 0 | error: |
815 | 0 | Py_XDECREF(it); |
816 | 0 | Py_DECREF(result); |
817 | 0 | return NULL; |
818 | 0 | } |
819 | | |
820 | | /*[clinic input] |
821 | | _io._IOBase.writelines |
822 | | lines: object |
823 | | / |
824 | | |
825 | | Write a list of lines to stream. |
826 | | |
827 | | Line separators are not added, so it is usual for each of the |
828 | | lines provided to have a line separator at the end. |
829 | | [clinic start generated code]*/ |
830 | | |
831 | | static PyObject * |
832 | | _io__IOBase_writelines(PyObject *self, PyObject *lines) |
833 | | /*[clinic end generated code: output=976eb0a9b60a6628 input=cac3fc8864183359]*/ |
834 | 0 | { |
835 | 0 | PyObject *iter, *res; |
836 | |
|
837 | 0 | if (iobase_check_closed(self)) |
838 | 0 | return NULL; |
839 | | |
840 | 0 | iter = PyObject_GetIter(lines); |
841 | 0 | if (iter == NULL) |
842 | 0 | return NULL; |
843 | | |
844 | 0 | while (1) { |
845 | 0 | PyObject *line = PyIter_Next(iter); |
846 | 0 | if (line == NULL) { |
847 | 0 | if (PyErr_Occurred()) { |
848 | 0 | Py_DECREF(iter); |
849 | 0 | return NULL; |
850 | 0 | } |
851 | 0 | else |
852 | 0 | break; /* Stop Iteration */ |
853 | 0 | } |
854 | | |
855 | 0 | res = NULL; |
856 | 0 | do { |
857 | 0 | res = PyObject_CallMethodObjArgs(self, &_Py_ID(write), line, NULL); |
858 | 0 | } while (res == NULL && _PyIO_trap_eintr()); |
859 | 0 | Py_DECREF(line); |
860 | 0 | if (res == NULL) { |
861 | 0 | Py_DECREF(iter); |
862 | 0 | return NULL; |
863 | 0 | } |
864 | 0 | Py_DECREF(res); |
865 | 0 | } |
866 | 0 | Py_DECREF(iter); |
867 | 0 | Py_RETURN_NONE; |
868 | 0 | } |
869 | | |
870 | | #define clinic_state() (find_io_state_by_def(Py_TYPE(self))) |
871 | | #include "clinic/iobase.c.h" |
872 | | #undef clinic_state |
873 | | |
874 | | static PyMethodDef iobase_methods[] = { |
875 | | _IO__IOBASE_SEEK_METHODDEF |
876 | | _IO__IOBASE_TELL_METHODDEF |
877 | | _IO__IOBASE_TRUNCATE_METHODDEF |
878 | | _IO__IOBASE_FLUSH_METHODDEF |
879 | | _IO__IOBASE_CLOSE_METHODDEF |
880 | | |
881 | | _IO__IOBASE_SEEKABLE_METHODDEF |
882 | | _IO__IOBASE_READABLE_METHODDEF |
883 | | _IO__IOBASE_WRITABLE_METHODDEF |
884 | | |
885 | | _IO__IOBASE__CHECKCLOSED_METHODDEF |
886 | | _IO__IOBASE__CHECKSEEKABLE_METHODDEF |
887 | | _IO__IOBASE__CHECKREADABLE_METHODDEF |
888 | | _IO__IOBASE__CHECKWRITABLE_METHODDEF |
889 | | |
890 | | _IO__IOBASE_FILENO_METHODDEF |
891 | | _IO__IOBASE_ISATTY_METHODDEF |
892 | | |
893 | | _IO__IOBASE___ENTER___METHODDEF |
894 | | _IO__IOBASE___EXIT___METHODDEF |
895 | | |
896 | | _IO__IOBASE_READLINE_METHODDEF |
897 | | _IO__IOBASE_READLINES_METHODDEF |
898 | | _IO__IOBASE_WRITELINES_METHODDEF |
899 | | |
900 | | {NULL, NULL} |
901 | | }; |
902 | | |
903 | | static PyGetSetDef iobase_getset[] = { |
904 | | {"__dict__", PyObject_GenericGetDict, NULL, NULL}, |
905 | | _IO__IOBASE_CLOSED_GETSETDEF |
906 | | {NULL} |
907 | | }; |
908 | | |
909 | | static struct PyMemberDef iobase_members[] = { |
910 | | {"__weaklistoffset__", Py_T_PYSSIZET, offsetof(iobase, weakreflist), Py_READONLY}, |
911 | | {"__dictoffset__", Py_T_PYSSIZET, offsetof(iobase, dict), Py_READONLY}, |
912 | | {NULL}, |
913 | | }; |
914 | | |
915 | | |
916 | | static PyType_Slot iobase_slots[] = { |
917 | | {Py_tp_dealloc, iobase_dealloc}, |
918 | | {Py_tp_doc, (void *)iobase_doc}, |
919 | | {Py_tp_traverse, iobase_traverse}, |
920 | | {Py_tp_clear, iobase_clear}, |
921 | | {Py_tp_iter, iobase_iter}, |
922 | | {Py_tp_iternext, iobase_iternext}, |
923 | | {Py_tp_methods, iobase_methods}, |
924 | | {Py_tp_members, iobase_members}, |
925 | | {Py_tp_getset, iobase_getset}, |
926 | | {Py_tp_finalize, iobase_finalize}, |
927 | | {0, NULL}, |
928 | | }; |
929 | | |
930 | | PyType_Spec _Py_iobase_spec = { |
931 | | .name = "_io._IOBase", |
932 | | .basicsize = sizeof(iobase), |
933 | | .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | |
934 | | Py_TPFLAGS_IMMUTABLETYPE), |
935 | | .slots = iobase_slots, |
936 | | }; |
937 | | |
938 | | /* |
939 | | * RawIOBase class, Inherits from IOBase. |
940 | | */ |
941 | | PyDoc_STRVAR(rawiobase_doc, |
942 | | "Base class for raw binary I/O."); |
943 | | |
944 | | /* |
945 | | * The read() method is implemented by calling readinto(); derived classes |
946 | | * that want to support read() only need to implement readinto() as a |
947 | | * primitive operation. In general, readinto() can be more efficient than |
948 | | * read(). |
949 | | * |
950 | | * (It would be tempting to also provide an implementation of readinto() in |
951 | | * terms of read(), in case the latter is a more suitable primitive operation, |
952 | | * but that would lead to nasty recursion in case a subclass doesn't implement |
953 | | * either.) |
954 | | */ |
955 | | |
956 | | /*[clinic input] |
957 | | _io._RawIOBase.read |
958 | | size as n: Py_ssize_t = -1 |
959 | | / |
960 | | [clinic start generated code]*/ |
961 | | |
962 | | static PyObject * |
963 | | _io__RawIOBase_read_impl(PyObject *self, Py_ssize_t n) |
964 | | /*[clinic end generated code: output=6cdeb731e3c9f13c input=b6d0dcf6417d1374]*/ |
965 | 0 | { |
966 | 0 | PyObject *b, *res; |
967 | |
|
968 | 0 | if (n < 0) { |
969 | 0 | return PyObject_CallMethodNoArgs(self, &_Py_ID(readall)); |
970 | 0 | } |
971 | | |
972 | 0 | b = PyByteArray_FromStringAndSize(NULL, n); |
973 | 0 | if (b == NULL) { |
974 | 0 | return NULL; |
975 | 0 | } |
976 | | |
977 | 0 | res = PyObject_CallMethodObjArgs(self, &_Py_ID(readinto), b, NULL); |
978 | 0 | if (res == NULL || res == Py_None) { |
979 | 0 | goto cleanup; |
980 | 0 | } |
981 | | |
982 | 0 | Py_ssize_t bytes_filled = PyNumber_AsSsize_t(res, PyExc_ValueError); |
983 | 0 | Py_CLEAR(res); |
984 | 0 | if (bytes_filled == -1 && PyErr_Occurred()) { |
985 | 0 | goto cleanup; |
986 | 0 | } |
987 | 0 | if (bytes_filled < 0 || bytes_filled > n) { |
988 | 0 | PyErr_Format(PyExc_ValueError, |
989 | 0 | "readinto returned %zd outside buffer size %zd", |
990 | 0 | bytes_filled, n); |
991 | 0 | goto cleanup; |
992 | 0 | } |
993 | 0 | if (PyByteArray_Resize(b, bytes_filled) < 0) { |
994 | 0 | goto cleanup; |
995 | 0 | } |
996 | 0 | res = PyObject_CallMethodNoArgs(b, &_Py_ID(take_bytes)); |
997 | |
|
998 | 0 | cleanup: |
999 | 0 | Py_DECREF(b); |
1000 | 0 | return res; |
1001 | 0 | } |
1002 | | |
1003 | | |
1004 | | /*[clinic input] |
1005 | | _io._RawIOBase.readall |
1006 | | |
1007 | | Read until EOF, using multiple read() call. |
1008 | | [clinic start generated code]*/ |
1009 | | |
1010 | | static PyObject * |
1011 | | _io__RawIOBase_readall_impl(PyObject *self) |
1012 | | /*[clinic end generated code: output=1987b9ce929425a0 input=688874141213622a]*/ |
1013 | 0 | { |
1014 | 0 | PyBytesWriter *writer = PyBytesWriter_Create(0); |
1015 | 0 | if (writer == NULL) { |
1016 | 0 | return NULL; |
1017 | 0 | } |
1018 | | |
1019 | 0 | while (1) { |
1020 | 0 | PyObject *data = _PyObject_CallMethod(self, &_Py_ID(read), |
1021 | 0 | "i", DEFAULT_BUFFER_SIZE); |
1022 | 0 | if (!data) { |
1023 | | /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() |
1024 | | when EINTR occurs so we needn't do it ourselves. */ |
1025 | 0 | if (_PyIO_trap_eintr()) { |
1026 | 0 | continue; |
1027 | 0 | } |
1028 | 0 | PyBytesWriter_Discard(writer); |
1029 | 0 | return NULL; |
1030 | 0 | } |
1031 | 0 | if (data == Py_None) { |
1032 | 0 | if (PyBytesWriter_GetSize(writer) == 0) { |
1033 | 0 | PyBytesWriter_Discard(writer); |
1034 | 0 | return data; |
1035 | 0 | } |
1036 | 0 | Py_DECREF(data); |
1037 | 0 | break; |
1038 | 0 | } |
1039 | 0 | if (!PyBytes_Check(data)) { |
1040 | 0 | Py_DECREF(data); |
1041 | 0 | PyErr_SetString(PyExc_TypeError, "read() should return bytes"); |
1042 | 0 | PyBytesWriter_Discard(writer); |
1043 | 0 | return NULL; |
1044 | 0 | } |
1045 | 0 | if (PyBytes_GET_SIZE(data) == 0) { |
1046 | | /* EOF */ |
1047 | 0 | Py_DECREF(data); |
1048 | 0 | break; |
1049 | 0 | } |
1050 | 0 | if (PyBytesWriter_WriteBytes(writer, |
1051 | 0 | PyBytes_AS_STRING(data), |
1052 | 0 | PyBytes_GET_SIZE(data)) < 0) { |
1053 | 0 | Py_DECREF(data); |
1054 | 0 | PyBytesWriter_Discard(writer); |
1055 | 0 | return NULL; |
1056 | 0 | } |
1057 | 0 | Py_DECREF(data); |
1058 | 0 | } |
1059 | 0 | return PyBytesWriter_Finish(writer); |
1060 | 0 | } |
1061 | | |
1062 | | /*[clinic input] |
1063 | | _io._RawIOBase.readinto |
1064 | | buffer: object |
1065 | | / |
1066 | | [clinic start generated code]*/ |
1067 | | |
1068 | | static PyObject * |
1069 | | _io__RawIOBase_readinto(PyObject *self, PyObject *buffer) |
1070 | | /*[clinic end generated code: output=081b8cdfaf3a40ff input=99d4bea2acd659c8]*/ |
1071 | 0 | { |
1072 | 0 | PyErr_SetNone(PyExc_NotImplementedError); |
1073 | 0 | return NULL; |
1074 | 0 | } |
1075 | | |
1076 | | /*[clinic input] |
1077 | | _io._RawIOBase.write |
1078 | | buffer: object |
1079 | | / |
1080 | | [clinic start generated code]*/ |
1081 | | |
1082 | | static PyObject * |
1083 | | _io__RawIOBase_write(PyObject *self, PyObject *buffer) |
1084 | | /*[clinic end generated code: output=7add3f2c8715c3a8 input=e6a1534adb876fe2]*/ |
1085 | 0 | { |
1086 | 0 | PyErr_SetNone(PyExc_NotImplementedError); |
1087 | | return NULL; |
1088 | 0 | } |
1089 | | |
1090 | | static PyMethodDef rawiobase_methods[] = { |
1091 | | _IO__RAWIOBASE_READ_METHODDEF |
1092 | | _IO__RAWIOBASE_READALL_METHODDEF |
1093 | | _IO__RAWIOBASE_READINTO_METHODDEF |
1094 | | _IO__RAWIOBASE_WRITE_METHODDEF |
1095 | | {NULL, NULL} |
1096 | | }; |
1097 | | |
1098 | | static PyType_Slot rawiobase_slots[] = { |
1099 | | {Py_tp_doc, (void *)rawiobase_doc}, |
1100 | | {Py_tp_methods, rawiobase_methods}, |
1101 | | {0, NULL}, |
1102 | | }; |
1103 | | |
1104 | | /* Do not set Py_TPFLAGS_HAVE_GC so that tp_traverse and tp_clear are inherited */ |
1105 | | PyType_Spec _Py_rawiobase_spec = { |
1106 | | .name = "_io._RawIOBase", |
1107 | | .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | |
1108 | | Py_TPFLAGS_IMMUTABLETYPE), |
1109 | | .slots = rawiobase_slots, |
1110 | | }; |