From 9226d49d3e77e75b1e645e14be91c37fa43b6df1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 10 Aug 2026 22:04:12 +0300 Subject: [PATCH 1/6] gh-155496: Use Argument Clinic for more functions of the _io module --- ...-08-10-19-49-11.gh-issue-155496.B4rMR1.rst | 3 + Modules/_io/bufferedio.c | 161 ++++++++---- Modules/_io/bytesio.c | 35 ++- Modules/_io/clinic/bufferedio.c.h | 243 +++++++++++++++++- Modules/_io/clinic/bytesio.c.h | 58 ++++- Modules/_io/clinic/fileio.c.h | 40 ++- Modules/_io/clinic/iobase.c.h | 135 +++++++++- Modules/_io/fileio.c | 25 +- Modules/_io/iobase.c | 91 +++++-- 9 files changed, 708 insertions(+), 83 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-08-10-19-49-11.gh-issue-155496.B4rMR1.rst diff --git a/Misc/NEWS.d/next/Library/2026-08-10-19-49-11.gh-issue-155496.B4rMR1.rst b/Misc/NEWS.d/next/Library/2026-08-10-19-49-11.gh-issue-155496.B4rMR1.rst new file mode 100644 index 00000000000000..75f0f987127b19 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-10-19-49-11.gh-issue-155496.B4rMR1.rst @@ -0,0 +1,3 @@ +:meth:`io.RawIOBase.readinto` and :meth:`io.RawIOBase.write` now raise +:exc:`TypeError` instead of :exc:`NotImplementedError` +if they are called without the required argument. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 5537947f6a51c1..cbabf50c332f2d 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2334,7 +2334,8 @@ bufferedrwpair_dealloc(PyObject *op) } static PyObject * -_forward_call(buffered *self, PyObject *name, PyObject *args) +_forward_call(buffered *self, PyObject *name, PyObject *const *args, + Py_ssize_t nargs) { PyObject *func, *ret; if (self == NULL) { @@ -2349,87 +2350,147 @@ _forward_call(buffered *self, PyObject *name, PyObject *args) return NULL; } - ret = PyObject_CallObject(func, args); + ret = PyObject_Vectorcall(func, args, nargs, NULL); Py_DECREF(func); return ret; } +/* The optional argument is only passed if it is specified, so that the + default of the underlying method is used otherwise. */ static PyObject * -bufferedrwpair_read(PyObject *op, PyObject *args) +_forward_call_opt(buffered *self, PyObject *name, PyObject *arg) { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(read), args); + return _forward_call(self, name, &arg, arg != NULL); } +/*[clinic input] +_io.BufferedRWPair.read + size: object(c_default="NULL") = -1 + / +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_peek(PyObject *op, PyObject *args) +_io_BufferedRWPair_read_impl(rwpair *self, PyObject *size) +/*[clinic end generated code: output=0668e3c5dbd3e93d input=eddb5e52aba9ebe5]*/ { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(peek), args); + return _forward_call_opt(self->reader, &_Py_ID(read), size); } +/*[clinic input] +_io.BufferedRWPair.peek + size: object(c_default="NULL") = 0 + / +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_read1(PyObject *op, PyObject *args) +_io_BufferedRWPair_peek_impl(rwpair *self, PyObject *size) +/*[clinic end generated code: output=190a267bd694efa0 input=36af95964bebe355]*/ { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(read1), args); + return _forward_call_opt(self->reader, &_Py_ID(peek), size); } +/*[clinic input] +_io.BufferedRWPair.read1 + size: object(c_default="NULL") = -1 + / +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_readinto(PyObject *op, PyObject *args) +_io_BufferedRWPair_read1_impl(rwpair *self, PyObject *size) +/*[clinic end generated code: output=17ec19608f2bb825 input=9e94db423e490b58]*/ { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(readinto), args); + return _forward_call_opt(self->reader, &_Py_ID(read1), size); } +/*[clinic input] +_io.BufferedRWPair.readinto + buffer: object + / +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_readinto1(PyObject *op, PyObject *args) +_io_BufferedRWPair_readinto_impl(rwpair *self, PyObject *buffer) +/*[clinic end generated code: output=16c86b071015f7a4 input=ccd86ce2666261f7]*/ { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(readinto1), args); + return _forward_call(self->reader, &_Py_ID(readinto), &buffer, 1); } +/*[clinic input] +_io.BufferedRWPair.readinto1 + buffer: object + / +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_write(PyObject *op, PyObject *args) +_io_BufferedRWPair_readinto1_impl(rwpair *self, PyObject *buffer) +/*[clinic end generated code: output=f1577b6f54c2b02a input=613d9bf127f88a4a]*/ { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->writer, &_Py_ID(write), args); + return _forward_call(self->reader, &_Py_ID(readinto1), &buffer, 1); +} + +/*[clinic input] +_io.BufferedRWPair.write + buffer: object + / +[clinic start generated code]*/ + +static PyObject * +_io_BufferedRWPair_write_impl(rwpair *self, PyObject *buffer) +/*[clinic end generated code: output=6f7509a747410c68 input=66c602422e3ec36f]*/ +{ + return _forward_call(self->writer, &_Py_ID(write), &buffer, 1); } +/*[clinic input] +_io.BufferedRWPair.flush +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_flush(PyObject *op, PyObject *Py_UNUSED(dummy)) +_io_BufferedRWPair_flush_impl(rwpair *self) +/*[clinic end generated code: output=0b2dcbe828718d6b input=e853da796ee61df1]*/ { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->writer, &_Py_ID(flush), NULL); + return _forward_call(self->writer, &_Py_ID(flush), NULL, 0); } +/*[clinic input] +_io.BufferedRWPair.readable +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_readable(PyObject *op, PyObject *Py_UNUSED(dummy)) +_io_BufferedRWPair_readable_impl(rwpair *self) +/*[clinic end generated code: output=615967d4aa58f122 input=0475ed73d0a3167f]*/ { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->reader, &_Py_ID(readable), NULL); + return _forward_call(self->reader, &_Py_ID(readable), NULL, 0); } +/*[clinic input] +_io.BufferedRWPair.writable +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_writable(PyObject *op, PyObject *Py_UNUSED(dummy)) +_io_BufferedRWPair_writable_impl(rwpair *self) +/*[clinic end generated code: output=c5a43c84e0195c11 input=3cfd44fb4757082f]*/ { - rwpair *self = rwpair_CAST(op); - return _forward_call(self->writer, &_Py_ID(writable), NULL); + return _forward_call(self->writer, &_Py_ID(writable), NULL, 0); } +/*[clinic input] +_io.BufferedRWPair.close +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_close(PyObject *op, PyObject *Py_UNUSED(dummy)) +_io_BufferedRWPair_close_impl(rwpair *self) +/*[clinic end generated code: output=5924ba5ecc78752a input=4087d69f2d8fc368]*/ { - rwpair *self = rwpair_CAST(op); PyObject *exc = NULL; - PyObject *ret = _forward_call(self->writer, &_Py_ID(close), NULL); + PyObject *ret = _forward_call(self->writer, &_Py_ID(close), NULL, 0); if (ret == NULL) { exc = PyErr_GetRaisedException(); } else { Py_DECREF(ret); } - ret = _forward_call(self->reader, &_Py_ID(close), NULL); + ret = _forward_call(self->reader, &_Py_ID(close), NULL, 0); if (exc != NULL) { _PyErr_ChainExceptions1(exc); Py_CLEAR(ret); @@ -2437,11 +2498,15 @@ bufferedrwpair_close(PyObject *op, PyObject *Py_UNUSED(dummy)) return ret; } +/*[clinic input] +_io.BufferedRWPair.isatty +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_isatty(PyObject *op, PyObject *Py_UNUSED(dummy)) +_io_BufferedRWPair_isatty_impl(rwpair *self) +/*[clinic end generated code: output=d017c621ed879cb7 input=92833e3d60586e14]*/ { - rwpair *self = rwpair_CAST(op); - PyObject *ret = _forward_call(self->writer, &_Py_ID(isatty), NULL); + PyObject *ret = _forward_call(self->writer, &_Py_ID(isatty), NULL, 0); if (ret != Py_False) { /* either True or exception */ @@ -2449,7 +2514,7 @@ bufferedrwpair_isatty(PyObject *op, PyObject *Py_UNUSED(dummy)) } Py_DECREF(ret); - return _forward_call(self->reader, &_Py_ID(isatty), NULL); + return _forward_call(self->reader, &_Py_ID(isatty), NULL, 0); } static PyObject * @@ -2670,20 +2735,20 @@ PyType_Spec _Py_bufferedwriter_spec = { }; static PyMethodDef bufferedrwpair_methods[] = { - {"read", bufferedrwpair_read, METH_VARARGS}, - {"peek", bufferedrwpair_peek, METH_VARARGS}, - {"read1", bufferedrwpair_read1, METH_VARARGS}, - {"readinto", bufferedrwpair_readinto, METH_VARARGS}, - {"readinto1", bufferedrwpair_readinto1, METH_VARARGS}, + _IO_BUFFEREDRWPAIR_READ_METHODDEF + _IO_BUFFEREDRWPAIR_PEEK_METHODDEF + _IO_BUFFEREDRWPAIR_READ1_METHODDEF + _IO_BUFFEREDRWPAIR_READINTO_METHODDEF + _IO_BUFFEREDRWPAIR_READINTO1_METHODDEF - {"write", bufferedrwpair_write, METH_VARARGS}, - {"flush", bufferedrwpair_flush, METH_NOARGS}, + _IO_BUFFEREDRWPAIR_WRITE_METHODDEF + _IO_BUFFEREDRWPAIR_FLUSH_METHODDEF - {"readable", bufferedrwpair_readable, METH_NOARGS}, - {"writable", bufferedrwpair_writable, METH_NOARGS}, + _IO_BUFFEREDRWPAIR_READABLE_METHODDEF + _IO_BUFFEREDRWPAIR_WRITABLE_METHODDEF - {"close", bufferedrwpair_close, METH_NOARGS}, - {"isatty", bufferedrwpair_isatty, METH_NOARGS}, + _IO_BUFFEREDRWPAIR_CLOSE_METHODDEF + _IO_BUFFEREDRWPAIR_ISATTY_METHODDEF {NULL, NULL} }; diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 7d6053d85cd9e4..755c2c1fdb54db 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -973,9 +973,15 @@ _io_BytesIO_close_impl(bytesio *self) return state; } +/*[clinic input] +_io.BytesIO.__getstate__ +[clinic start generated code]*/ + static PyObject * -bytesio_getstate(PyObject *op, PyObject *Py_UNUSED(dummy)) +_io_BytesIO___getstate___impl(bytesio *self) +/*[clinic end generated code: output=4a776270c8443b85 input=6e3cd9132f0cacdd]*/ { + PyObject *op = (PyObject *)self; PyObject *ret; Py_BEGIN_CRITICAL_SECTION(op); ret = bytesio_getstate_lock_held(op); @@ -1063,9 +1069,18 @@ bytesio_setstate_lock_held(PyObject *op, PyObject *state) Py_RETURN_NONE; } +/*[clinic input] +_io.BytesIO.__setstate__ + + state: object + / +[clinic start generated code]*/ + static PyObject * -bytesio_setstate(PyObject *op, PyObject *state) +_io_BytesIO___setstate___impl(bytesio *self, PyObject *state) +/*[clinic end generated code: output=3605abdec171bb98 input=7d4339f5be0039ba]*/ { + PyObject *op = (PyObject *)self; PyObject *ret; Py_BEGIN_CRITICAL_SECTION(op); ret = bytesio_setstate_lock_held(op, state); @@ -1170,9 +1185,17 @@ bytesio_sizeof_lock_held(PyObject *op) return PyLong_FromSize_t(res); } +/*[clinic input] +_io.BytesIO.__sizeof__ + +Size of object in memory, in bytes. +[clinic start generated code]*/ + static PyObject * -bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy)) +_io_BytesIO___sizeof___impl(bytesio *self) +/*[clinic end generated code: output=f61b601bd055c4de input=097b24a2755a7b0b]*/ { + PyObject *op = (PyObject *)self; PyObject *ret; Py_BEGIN_CRITICAL_SECTION(op); ret = bytesio_sizeof_lock_held(op); @@ -1232,9 +1255,9 @@ static struct PyMethodDef bytesio_methods[] = { _IO_BYTESIO_GETVALUE_METHODDEF _IO_BYTESIO_SEEK_METHODDEF _IO_BYTESIO_TRUNCATE_METHODDEF - {"__getstate__", bytesio_getstate, METH_NOARGS, NULL}, - {"__setstate__", bytesio_setstate, METH_O, NULL}, - {"__sizeof__", bytesio_sizeof, METH_NOARGS, NULL}, + _IO_BYTESIO___GETSTATE___METHODDEF + _IO_BYTESIO___SETSTATE___METHODDEF + _IO_BYTESIO___SIZEOF___METHODDEF {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index b7c0ca2c4b919b..33ba747ccbcd03 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -1186,6 +1186,247 @@ _io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs) return return_value; } +PyDoc_STRVAR(_io_BufferedRWPair_read__doc__, +"read($self, size=-1, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_READ_METHODDEF \ + {"read", _PyCFunction_CAST(_io_BufferedRWPair_read), METH_FASTCALL, _io_BufferedRWPair_read__doc__}, + +static PyObject * +_io_BufferedRWPair_read_impl(rwpair *self, PyObject *size); + +static PyObject * +_io_BufferedRWPair_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *size = NULL; + + if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + size = args[0]; +skip_optional: + return_value = _io_BufferedRWPair_read_impl((rwpair *)self, size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BufferedRWPair_peek__doc__, +"peek($self, size=0, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_PEEK_METHODDEF \ + {"peek", _PyCFunction_CAST(_io_BufferedRWPair_peek), METH_FASTCALL, _io_BufferedRWPair_peek__doc__}, + +static PyObject * +_io_BufferedRWPair_peek_impl(rwpair *self, PyObject *size); + +static PyObject * +_io_BufferedRWPair_peek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *size = NULL; + + if (!_PyArg_CheckPositional("peek", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + size = args[0]; +skip_optional: + return_value = _io_BufferedRWPair_peek_impl((rwpair *)self, size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BufferedRWPair_read1__doc__, +"read1($self, size=-1, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_READ1_METHODDEF \ + {"read1", _PyCFunction_CAST(_io_BufferedRWPair_read1), METH_FASTCALL, _io_BufferedRWPair_read1__doc__}, + +static PyObject * +_io_BufferedRWPair_read1_impl(rwpair *self, PyObject *size); + +static PyObject * +_io_BufferedRWPair_read1(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *size = NULL; + + if (!_PyArg_CheckPositional("read1", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + size = args[0]; +skip_optional: + return_value = _io_BufferedRWPair_read1_impl((rwpair *)self, size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BufferedRWPair_readinto__doc__, +"readinto($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_READINTO_METHODDEF \ + {"readinto", (PyCFunction)_io_BufferedRWPair_readinto, METH_O, _io_BufferedRWPair_readinto__doc__}, + +static PyObject * +_io_BufferedRWPair_readinto_impl(rwpair *self, PyObject *buffer); + +static PyObject * +_io_BufferedRWPair_readinto(PyObject *self, PyObject *buffer) +{ + PyObject *return_value = NULL; + + return_value = _io_BufferedRWPair_readinto_impl((rwpair *)self, buffer); + + return return_value; +} + +PyDoc_STRVAR(_io_BufferedRWPair_readinto1__doc__, +"readinto1($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_READINTO1_METHODDEF \ + {"readinto1", (PyCFunction)_io_BufferedRWPair_readinto1, METH_O, _io_BufferedRWPair_readinto1__doc__}, + +static PyObject * +_io_BufferedRWPair_readinto1_impl(rwpair *self, PyObject *buffer); + +static PyObject * +_io_BufferedRWPair_readinto1(PyObject *self, PyObject *buffer) +{ + PyObject *return_value = NULL; + + return_value = _io_BufferedRWPair_readinto1_impl((rwpair *)self, buffer); + + return return_value; +} + +PyDoc_STRVAR(_io_BufferedRWPair_write__doc__, +"write($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_WRITE_METHODDEF \ + {"write", (PyCFunction)_io_BufferedRWPair_write, METH_O, _io_BufferedRWPair_write__doc__}, + +static PyObject * +_io_BufferedRWPair_write_impl(rwpair *self, PyObject *buffer); + +static PyObject * +_io_BufferedRWPair_write(PyObject *self, PyObject *buffer) +{ + PyObject *return_value = NULL; + + return_value = _io_BufferedRWPair_write_impl((rwpair *)self, buffer); + + return return_value; +} + +PyDoc_STRVAR(_io_BufferedRWPair_flush__doc__, +"flush($self, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_io_BufferedRWPair_flush, METH_NOARGS, _io_BufferedRWPair_flush__doc__}, + +static PyObject * +_io_BufferedRWPair_flush_impl(rwpair *self); + +static PyObject * +_io_BufferedRWPair_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BufferedRWPair_flush_impl((rwpair *)self); +} + +PyDoc_STRVAR(_io_BufferedRWPair_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io_BufferedRWPair_readable, METH_NOARGS, _io_BufferedRWPair_readable__doc__}, + +static PyObject * +_io_BufferedRWPair_readable_impl(rwpair *self); + +static PyObject * +_io_BufferedRWPair_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BufferedRWPair_readable_impl((rwpair *)self); +} + +PyDoc_STRVAR(_io_BufferedRWPair_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io_BufferedRWPair_writable, METH_NOARGS, _io_BufferedRWPair_writable__doc__}, + +static PyObject * +_io_BufferedRWPair_writable_impl(rwpair *self); + +static PyObject * +_io_BufferedRWPair_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BufferedRWPair_writable_impl((rwpair *)self); +} + +PyDoc_STRVAR(_io_BufferedRWPair_close__doc__, +"close($self, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io_BufferedRWPair_close, METH_NOARGS, _io_BufferedRWPair_close__doc__}, + +static PyObject * +_io_BufferedRWPair_close_impl(rwpair *self); + +static PyObject * +_io_BufferedRWPair_close(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BufferedRWPair_close_impl((rwpair *)self); +} + +PyDoc_STRVAR(_io_BufferedRWPair_isatty__doc__, +"isatty($self, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDRWPAIR_ISATTY_METHODDEF \ + {"isatty", (PyCFunction)_io_BufferedRWPair_isatty, METH_NOARGS, _io_BufferedRWPair_isatty__doc__}, + +static PyObject * +_io_BufferedRWPair_isatty_impl(rwpair *self); + +static PyObject * +_io_BufferedRWPair_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BufferedRWPair_isatty_impl((rwpair *)self); +} + PyDoc_STRVAR(_io_BufferedRandom___init____doc__, "BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n" "--\n" @@ -1265,4 +1506,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=3ee17211d2010462 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=eed4ac9f76174342 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index a0159c063b5859..73136ea139eb3c 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -621,6 +621,44 @@ _io_BytesIO_close(PyObject *self, PyObject *Py_UNUSED(ignored)) return return_value; } +PyDoc_STRVAR(_io_BytesIO___getstate____doc__, +"__getstate__($self, /)\n" +"--\n" +"\n"); + +#define _IO_BYTESIO___GETSTATE___METHODDEF \ + {"__getstate__", (PyCFunction)_io_BytesIO___getstate__, METH_NOARGS, _io_BytesIO___getstate____doc__}, + +static PyObject * +_io_BytesIO___getstate___impl(bytesio *self); + +static PyObject * +_io_BytesIO___getstate__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO___getstate___impl((bytesio *)self); +} + +PyDoc_STRVAR(_io_BytesIO___setstate____doc__, +"__setstate__($self, state, /)\n" +"--\n" +"\n"); + +#define _IO_BYTESIO___SETSTATE___METHODDEF \ + {"__setstate__", (PyCFunction)_io_BytesIO___setstate__, METH_O, _io_BytesIO___setstate____doc__}, + +static PyObject * +_io_BytesIO___setstate___impl(bytesio *self, PyObject *state); + +static PyObject * +_io_BytesIO___setstate__(PyObject *self, PyObject *state) +{ + PyObject *return_value = NULL; + + return_value = _io_BytesIO___setstate___impl((bytesio *)self, state); + + return return_value; +} + PyDoc_STRVAR(_io_BytesIO___init____doc__, "BytesIO(initial_bytes=b\'\')\n" "--\n" @@ -684,4 +722,22 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=b5e625e31b2a82f0 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_io_BytesIO___sizeof____doc__, +"__sizeof__($self, /)\n" +"--\n" +"\n" +"Size of object in memory, in bytes."); + +#define _IO_BYTESIO___SIZEOF___METHODDEF \ + {"__sizeof__", (PyCFunction)_io_BytesIO___sizeof__, METH_NOARGS, _io_BytesIO___sizeof____doc__}, + +static PyObject * +_io_BytesIO___sizeof___impl(bytesio *self); + +static PyObject * +_io_BytesIO___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO___sizeof___impl((bytesio *)self); +} +/*[clinic end generated code: output=37e0318a34125084 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index 890b6bc3fac9d5..5a23972890059e 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -9,6 +9,27 @@ preserve #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() +PyDoc_STRVAR(_io_FileIO__dealloc_warn__doc__, +"_dealloc_warn($self, source, /)\n" +"--\n" +"\n"); + +#define _IO_FILEIO__DEALLOC_WARN_METHODDEF \ + {"_dealloc_warn", (PyCFunction)_io_FileIO__dealloc_warn, METH_O, _io_FileIO__dealloc_warn__doc__}, + +static PyObject * +_io_FileIO__dealloc_warn_impl(fileio *self, PyObject *source); + +static PyObject * +_io_FileIO__dealloc_warn(PyObject *self, PyObject *source) +{ + PyObject *return_value = NULL; + + return_value = _io_FileIO__dealloc_warn_impl((fileio *)self, source); + + return return_value; +} + PyDoc_STRVAR(_io_FileIO_close__doc__, "close($self, /)\n" "--\n" @@ -550,7 +571,24 @@ _io_FileIO_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io_FileIO_isatty_impl((fileio *)self); } +PyDoc_STRVAR(_io_FileIO__isatty_open_only__doc__, +"_isatty_open_only($self, /)\n" +"--\n" +"\n"); + +#define _IO_FILEIO__ISATTY_OPEN_ONLY_METHODDEF \ + {"_isatty_open_only", (PyCFunction)_io_FileIO__isatty_open_only, METH_NOARGS, _io_FileIO__isatty_open_only__doc__}, + +static PyObject * +_io_FileIO__isatty_open_only_impl(fileio *self); + +static PyObject * +_io_FileIO__isatty_open_only(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO__isatty_open_only_impl((fileio *)self); +} + #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=453d584e2e72f986 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a4d50af066c7ceb0 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index e4438c26431aa8..0fc8a849a0c750 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -171,6 +171,74 @@ _io__IOBase_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_flush_impl(self); } +PyDoc_STRVAR(_io__IOBase__checkClosed__doc__, +"_checkClosed($self, /)\n" +"--\n" +"\n"); + +#define _IO__IOBASE__CHECKCLOSED_METHODDEF \ + {"_checkClosed", (PyCFunction)_io__IOBase__checkClosed, METH_NOARGS, _io__IOBase__checkClosed__doc__}, + +static PyObject * +_io__IOBase__checkClosed_impl(PyObject *self); + +static PyObject * +_io__IOBase__checkClosed(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase__checkClosed_impl(self); +} + +PyDoc_STRVAR(_io__IOBase__checkSeekable__doc__, +"_checkSeekable($self, /)\n" +"--\n" +"\n"); + +#define _IO__IOBASE__CHECKSEEKABLE_METHODDEF \ + {"_checkSeekable", (PyCFunction)_io__IOBase__checkSeekable, METH_NOARGS, _io__IOBase__checkSeekable__doc__}, + +static PyObject * +_io__IOBase__checkSeekable_impl(PyObject *self); + +static PyObject * +_io__IOBase__checkSeekable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase__checkSeekable_impl(self); +} + +PyDoc_STRVAR(_io__IOBase__checkReadable__doc__, +"_checkReadable($self, /)\n" +"--\n" +"\n"); + +#define _IO__IOBASE__CHECKREADABLE_METHODDEF \ + {"_checkReadable", (PyCFunction)_io__IOBase__checkReadable, METH_NOARGS, _io__IOBase__checkReadable__doc__}, + +static PyObject * +_io__IOBase__checkReadable_impl(PyObject *self); + +static PyObject * +_io__IOBase__checkReadable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase__checkReadable_impl(self); +} + +PyDoc_STRVAR(_io__IOBase__checkWritable__doc__, +"_checkWritable($self, /)\n" +"--\n" +"\n"); + +#define _IO__IOBASE__CHECKWRITABLE_METHODDEF \ + {"_checkWritable", (PyCFunction)_io__IOBase__checkWritable, METH_NOARGS, _io__IOBase__checkWritable__doc__}, + +static PyObject * +_io__IOBase__checkWritable_impl(PyObject *self); + +static PyObject * +_io__IOBase__checkWritable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase__checkWritable_impl(self); +} + PyDoc_STRVAR(_io__IOBase_close__doc__, "close($self, /)\n" "--\n" @@ -252,6 +320,55 @@ _io__IOBase_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_writable_impl(self); } +PyDoc_STRVAR(_io__IOBase___enter____doc__, +"__enter__($self, /)\n" +"--\n" +"\n" +"Context management protocol. Returns the stream itself."); + +#define _IO__IOBASE___ENTER___METHODDEF \ + {"__enter__", (PyCFunction)_io__IOBase___enter__, METH_NOARGS, _io__IOBase___enter____doc__}, + +static PyObject * +_io__IOBase___enter___impl(PyObject *self); + +static PyObject * +_io__IOBase___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase___enter___impl(self); +} + +PyDoc_STRVAR(_io__IOBase___exit____doc__, +"__exit__($self, /, *args)\n" +"--\n" +"\n" +"Context management protocol. Calls close()."); + +#define _IO__IOBASE___EXIT___METHODDEF \ + {"__exit__", _PyCFunction_CAST(_io__IOBase___exit__), METH_FASTCALL, _io__IOBase___exit____doc__}, + +static PyObject * +_io__IOBase___exit___impl(PyObject *self, PyObject *args); + +static PyObject * +_io__IOBase___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + return_value = _io__IOBase___exit___impl(self, __clinic_args); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + PyDoc_STRVAR(_io__IOBase_fileno__doc__, "fileno($self, /)\n" "--\n" @@ -445,4 +562,20 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=28c06bb6db32c096 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_io__RawIOBase_readinto__doc__, +"readinto($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO__RAWIOBASE_READINTO_METHODDEF \ + {"readinto", (PyCFunction)_io__RawIOBase_readinto, METH_O, _io__RawIOBase_readinto__doc__}, + +PyDoc_STRVAR(_io__RawIOBase_write__doc__, +"write($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO__RAWIOBASE_WRITE_METHODDEF \ + {"write", (PyCFunction)_io__RawIOBase_write, METH_O, _io__RawIOBase_write__doc__}, +/*[clinic end generated code: output=a42eede543e39a09 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 3aeb30dfe24a35..cfed32bc17872a 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -99,10 +99,17 @@ _PyFileIO_closed(PyObject *self) /* Because this can call arbitrary code, it shouldn't be called when the refcount is 0 (that is, not directly from tp_dealloc unless the refcount has been temporarily re-incremented). */ +/*[clinic input] +_io.FileIO._dealloc_warn + + source: object + / +[clinic start generated code]*/ + static PyObject * -fileio_dealloc_warn(PyObject *op, PyObject *source) +_io_FileIO__dealloc_warn_impl(fileio *self, PyObject *source) +/*[clinic end generated code: output=c7b7d122decd6575 input=3ea7e1cc0685edc2]*/ { - fileio *self = PyFileIO_CAST(op); if (self->fd >= 0 && self->closefd) { PyObject *exc = PyErr_GetRaisedException(); if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) { @@ -176,7 +183,7 @@ _io_FileIO_close_impl(fileio *self, PyTypeObject *cls) exc = PyErr_GetRaisedException(); } if (self->finalizing) { - PyObject *r = fileio_dealloc_warn((PyObject*)self, (PyObject *) self); + PyObject *r = _io_FileIO__dealloc_warn_impl(self, (PyObject *)self); if (r) { Py_DECREF(r); } @@ -1243,10 +1250,14 @@ _io_FileIO_isatty_impl(fileio *self) information. Use the stat result to skip a system call. Outside of that context TOCTOU issues (the fd could be arbitrarily modified by surrounding code). */ +/*[clinic input] +_io.FileIO._isatty_open_only +[clinic start generated code]*/ + static PyObject * -_io_FileIO_isatty_open_only(PyObject *op, PyObject *Py_UNUSED(dummy)) +_io_FileIO__isatty_open_only_impl(fileio *self) +/*[clinic end generated code: output=2b4689154d4b8b84 input=228767ff567cdfb6]*/ { - fileio *self = PyFileIO_CAST(op); if (self->stat_atopen != NULL && !S_ISCHR(self->stat_atopen->st_mode)) { Py_RETURN_FALSE; } @@ -1269,8 +1280,8 @@ static PyMethodDef fileio_methods[] = { _IO_FILEIO_WRITABLE_METHODDEF _IO_FILEIO_FILENO_METHODDEF _IO_FILEIO_ISATTY_METHODDEF - {"_isatty_open_only", _io_FileIO_isatty_open_only, METH_NOARGS}, - {"_dealloc_warn", fileio_dealloc_warn, METH_O, NULL}, + _IO_FILEIO__ISATTY_OPEN_ONLY_METHODDEF + _IO_FILEIO__DEALLOC_WARN_METHODDEF {"__getstate__", _PyIOBase_cannot_pickle, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 1253f124108bdb..38bbf8185d3826 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -225,25 +225,51 @@ _PyIOBase_check_closed(PyObject *self, PyObject *args) Py_RETURN_NONE; } +/*[clinic input] +_io._IOBase._checkClosed +[clinic start generated code]*/ + +static PyObject * +_io__IOBase__checkClosed_impl(PyObject *self) +/*[clinic end generated code: output=8fb8412185623f1a input=8d18d2e67b2270bb]*/ +{ + return _PyIOBase_check_closed(self, NULL); +} + +/*[clinic input] +_io._IOBase._checkSeekable +[clinic start generated code]*/ + static PyObject * -iobase_check_seekable(PyObject *self, PyObject *args) +_io__IOBase__checkSeekable_impl(PyObject *self) +/*[clinic end generated code: output=10f09b515a9f4c4f input=479853eded776b0e]*/ { _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); - return _PyIOBase_check_seekable(state, self, args); + return _PyIOBase_check_seekable(state, self, NULL); } +/*[clinic input] +_io._IOBase._checkReadable +[clinic start generated code]*/ + static PyObject * -iobase_check_readable(PyObject *self, PyObject *args) +_io__IOBase__checkReadable_impl(PyObject *self) +/*[clinic end generated code: output=33ccab8a7c4550fb input=63fbf50b36772323]*/ { _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); - return _PyIOBase_check_readable(state, self, args); + return _PyIOBase_check_readable(state, self, NULL); } +/*[clinic input] +_io._IOBase._checkWritable +[clinic start generated code]*/ + static PyObject * -iobase_check_writable(PyObject *self, PyObject *args) +_io__IOBase__checkWritable_impl(PyObject *self) +/*[clinic end generated code: output=8cfc6b4b2469d2a3 input=2758c7291cf5911e]*/ { _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); - return _PyIOBase_check_writable(state, self, args); + return _PyIOBase_check_writable(state, self, NULL); } PyObject * @@ -495,8 +521,15 @@ _PyIOBase_check_writable(_PyIO_State *state, PyObject *self, PyObject *args) /* Context manager */ +/*[clinic input] +_io._IOBase.__enter__ + +Context management protocol. Returns the stream itself. +[clinic start generated code]*/ + static PyObject * -iobase_enter(PyObject *self, PyObject *args) +_io__IOBase___enter___impl(PyObject *self) +/*[clinic end generated code: output=d1e8e5b58bde3680 input=92e2d5e34ee714e5]*/ { if (iobase_check_closed(self)) return NULL; @@ -504,8 +537,16 @@ iobase_enter(PyObject *self, PyObject *args) return Py_NewRef(self); } +/*[clinic input] +_io._IOBase.__exit__ + *args: tuple + +Context management protocol. Calls close(). +[clinic start generated code]*/ + static PyObject * -iobase_exit(PyObject *self, PyObject *args) +_io__IOBase___exit___impl(PyObject *self, PyObject *args) +/*[clinic end generated code: output=452f3e33a34e2c5c input=fd3f46a32773a170]*/ { return PyObject_CallMethodNoArgs(self, &_Py_ID(close)); } @@ -841,16 +882,16 @@ static PyMethodDef iobase_methods[] = { _IO__IOBASE_READABLE_METHODDEF _IO__IOBASE_WRITABLE_METHODDEF - {"_checkClosed", _PyIOBase_check_closed, METH_NOARGS}, - {"_checkSeekable", iobase_check_seekable, METH_NOARGS}, - {"_checkReadable", iobase_check_readable, METH_NOARGS}, - {"_checkWritable", iobase_check_writable, METH_NOARGS}, + _IO__IOBASE__CHECKCLOSED_METHODDEF + _IO__IOBASE__CHECKSEEKABLE_METHODDEF + _IO__IOBASE__CHECKREADABLE_METHODDEF + _IO__IOBASE__CHECKWRITABLE_METHODDEF _IO__IOBASE_FILENO_METHODDEF _IO__IOBASE_ISATTY_METHODDEF - {"__enter__", iobase_enter, METH_NOARGS}, - {"__exit__", iobase_exit, METH_VARARGS}, + _IO__IOBASE___ENTER___METHODDEF + _IO__IOBASE___EXIT___METHODDEF _IO__IOBASE_READLINE_METHODDEF _IO__IOBASE_READLINES_METHODDEF @@ -1018,15 +1059,29 @@ _io__RawIOBase_readall_impl(PyObject *self) return PyBytesWriter_Finish(writer); } +/*[clinic input] +_io._RawIOBase.readinto + buffer: object + / +[clinic start generated code]*/ + static PyObject * -rawiobase_readinto(PyObject *self, PyObject *args) +_io__RawIOBase_readinto(PyObject *self, PyObject *buffer) +/*[clinic end generated code: output=081b8cdfaf3a40ff input=99d4bea2acd659c8]*/ { PyErr_SetNone(PyExc_NotImplementedError); return NULL; } +/*[clinic input] +_io._RawIOBase.write + buffer: object + / +[clinic start generated code]*/ + static PyObject * -rawiobase_write(PyObject *self, PyObject *args) +_io__RawIOBase_write(PyObject *self, PyObject *buffer) +/*[clinic end generated code: output=7add3f2c8715c3a8 input=e6a1534adb876fe2]*/ { PyErr_SetNone(PyExc_NotImplementedError); return NULL; @@ -1035,8 +1090,8 @@ rawiobase_write(PyObject *self, PyObject *args) static PyMethodDef rawiobase_methods[] = { _IO__RAWIOBASE_READ_METHODDEF _IO__RAWIOBASE_READALL_METHODDEF - {"readinto", rawiobase_readinto, METH_VARARGS}, - {"write", rawiobase_write, METH_VARARGS}, + _IO__RAWIOBASE_READINTO_METHODDEF + _IO__RAWIOBASE_WRITE_METHODDEF {NULL, NULL} }; From 7e279ce358b992a705c546f89f790b1e9bdfc5e9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 13 Aug 2026 21:05:10 +0300 Subject: [PATCH 2/6] Update test_inspect for the new signatures --- Lib/test/test_inspect/test_inspect.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 844811692df2d6..49b8f57aab78a0 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -6280,11 +6280,7 @@ def test_gc_module_has_signatures(self): self._test_module_has_signatures(gc, no_signature) def test_io_module_has_signatures(self): - methods_no_signature = { - 'BufferedRWPair': {'read', 'peek', 'read1', 'readinto', 'readinto1', 'write'}, - } - self._test_module_has_signatures(io, - methods_no_signature=methods_no_signature) + self._test_module_has_signatures(io) def test_itertools_module_has_signatures(self): import itertools From de988eff3864c0091db99f22dccce8c9833ea381 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 13 Aug 2026 21:18:18 +0300 Subject: [PATCH 3/6] Use the C API for calling a method PyObject_CallMethodNoArgs() and PyObject_CallMethodOneArg() look up the method and call it in one step, without creating a bound method object. --- Modules/_io/bufferedio.c | 52 ++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index cbabf50c332f2d..869af2e64c0869 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2333,34 +2333,22 @@ bufferedrwpair_dealloc(PyObject *op) Py_DECREF(tp); } +/* Call the method of the underlying reader or writer. The argument is + only passed if it is not NULL, so that the default of that method is + used otherwise. */ static PyObject * -_forward_call(buffered *self, PyObject *name, PyObject *const *args, - Py_ssize_t nargs) +_forward_call(buffered *self, PyObject *name, PyObject *arg) { - PyObject *func, *ret; if (self == NULL) { PyErr_SetString(PyExc_ValueError, "I/O operation on uninitialized object"); return NULL; } - func = PyObject_GetAttr((PyObject *)self, name); - if (func == NULL) { - PyErr_SetObject(PyExc_AttributeError, name); - return NULL; + if (arg == NULL) { + return PyObject_CallMethodNoArgs((PyObject *)self, name); } - - ret = PyObject_Vectorcall(func, args, nargs, NULL); - Py_DECREF(func); - return ret; -} - -/* The optional argument is only passed if it is specified, so that the - default of the underlying method is used otherwise. */ -static PyObject * -_forward_call_opt(buffered *self, PyObject *name, PyObject *arg) -{ - return _forward_call(self, name, &arg, arg != NULL); + return PyObject_CallMethodOneArg((PyObject *)self, name, arg); } /*[clinic input] @@ -2373,7 +2361,7 @@ static PyObject * _io_BufferedRWPair_read_impl(rwpair *self, PyObject *size) /*[clinic end generated code: output=0668e3c5dbd3e93d input=eddb5e52aba9ebe5]*/ { - return _forward_call_opt(self->reader, &_Py_ID(read), size); + return _forward_call(self->reader, &_Py_ID(read), size); } /*[clinic input] @@ -2386,7 +2374,7 @@ static PyObject * _io_BufferedRWPair_peek_impl(rwpair *self, PyObject *size) /*[clinic end generated code: output=190a267bd694efa0 input=36af95964bebe355]*/ { - return _forward_call_opt(self->reader, &_Py_ID(peek), size); + return _forward_call(self->reader, &_Py_ID(peek), size); } /*[clinic input] @@ -2399,7 +2387,7 @@ static PyObject * _io_BufferedRWPair_read1_impl(rwpair *self, PyObject *size) /*[clinic end generated code: output=17ec19608f2bb825 input=9e94db423e490b58]*/ { - return _forward_call_opt(self->reader, &_Py_ID(read1), size); + return _forward_call(self->reader, &_Py_ID(read1), size); } /*[clinic input] @@ -2412,7 +2400,7 @@ static PyObject * _io_BufferedRWPair_readinto_impl(rwpair *self, PyObject *buffer) /*[clinic end generated code: output=16c86b071015f7a4 input=ccd86ce2666261f7]*/ { - return _forward_call(self->reader, &_Py_ID(readinto), &buffer, 1); + return _forward_call(self->reader, &_Py_ID(readinto), buffer); } /*[clinic input] @@ -2425,7 +2413,7 @@ static PyObject * _io_BufferedRWPair_readinto1_impl(rwpair *self, PyObject *buffer) /*[clinic end generated code: output=f1577b6f54c2b02a input=613d9bf127f88a4a]*/ { - return _forward_call(self->reader, &_Py_ID(readinto1), &buffer, 1); + return _forward_call(self->reader, &_Py_ID(readinto1), buffer); } /*[clinic input] @@ -2438,7 +2426,7 @@ static PyObject * _io_BufferedRWPair_write_impl(rwpair *self, PyObject *buffer) /*[clinic end generated code: output=6f7509a747410c68 input=66c602422e3ec36f]*/ { - return _forward_call(self->writer, &_Py_ID(write), &buffer, 1); + return _forward_call(self->writer, &_Py_ID(write), buffer); } /*[clinic input] @@ -2449,7 +2437,7 @@ static PyObject * _io_BufferedRWPair_flush_impl(rwpair *self) /*[clinic end generated code: output=0b2dcbe828718d6b input=e853da796ee61df1]*/ { - return _forward_call(self->writer, &_Py_ID(flush), NULL, 0); + return _forward_call(self->writer, &_Py_ID(flush), NULL); } /*[clinic input] @@ -2460,7 +2448,7 @@ static PyObject * _io_BufferedRWPair_readable_impl(rwpair *self) /*[clinic end generated code: output=615967d4aa58f122 input=0475ed73d0a3167f]*/ { - return _forward_call(self->reader, &_Py_ID(readable), NULL, 0); + return _forward_call(self->reader, &_Py_ID(readable), NULL); } /*[clinic input] @@ -2471,7 +2459,7 @@ static PyObject * _io_BufferedRWPair_writable_impl(rwpair *self) /*[clinic end generated code: output=c5a43c84e0195c11 input=3cfd44fb4757082f]*/ { - return _forward_call(self->writer, &_Py_ID(writable), NULL, 0); + return _forward_call(self->writer, &_Py_ID(writable), NULL); } /*[clinic input] @@ -2483,14 +2471,14 @@ _io_BufferedRWPair_close_impl(rwpair *self) /*[clinic end generated code: output=5924ba5ecc78752a input=4087d69f2d8fc368]*/ { PyObject *exc = NULL; - PyObject *ret = _forward_call(self->writer, &_Py_ID(close), NULL, 0); + PyObject *ret = _forward_call(self->writer, &_Py_ID(close), NULL); if (ret == NULL) { exc = PyErr_GetRaisedException(); } else { Py_DECREF(ret); } - ret = _forward_call(self->reader, &_Py_ID(close), NULL, 0); + ret = _forward_call(self->reader, &_Py_ID(close), NULL); if (exc != NULL) { _PyErr_ChainExceptions1(exc); Py_CLEAR(ret); @@ -2506,7 +2494,7 @@ static PyObject * _io_BufferedRWPair_isatty_impl(rwpair *self) /*[clinic end generated code: output=d017c621ed879cb7 input=92833e3d60586e14]*/ { - PyObject *ret = _forward_call(self->writer, &_Py_ID(isatty), NULL, 0); + PyObject *ret = _forward_call(self->writer, &_Py_ID(isatty), NULL); if (ret != Py_False) { /* either True or exception */ @@ -2514,7 +2502,7 @@ _io_BufferedRWPair_isatty_impl(rwpair *self) } Py_DECREF(ret); - return _forward_call(self->reader, &_Py_ID(isatty), NULL, 0); + return _forward_call(self->reader, &_Py_ID(isatty), NULL); } static PyObject * From e650b492f3c81dfd4b3ca4d794627606380a1715 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 13 Aug 2026 21:26:10 +0300 Subject: [PATCH 4/6] Use the @critical_section decorator in BytesIO The pickling support and __sizeof__() of BytesIO no longer need separate "lock held" functions. --- Modules/_io/bytesio.c | 122 ++++++++++++--------------------- Modules/_io/clinic/bytesio.c.h | 20 +++++- 2 files changed, 60 insertions(+), 82 deletions(-) diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 755c2c1fdb54db..f38b833115e1b0 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -945,60 +945,55 @@ _io_BytesIO_close_impl(bytesio *self) function to use the efficient instance representation of PEP 307. */ - static PyObject * - bytesio_getstate_lock_held(PyObject *op) - { - _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); - - bytesio *self = bytesio_CAST(op); - PyObject *initvalue = _io_BytesIO_getvalue_impl(self); - PyObject *dict; - PyObject *state; - - if (initvalue == NULL) - return NULL; - if (self->dict == NULL) { - dict = Py_NewRef(Py_None); - } - else { - dict = PyDict_Copy(self->dict); - if (dict == NULL) { - Py_DECREF(initvalue); - return NULL; - } - } - - state = Py_BuildValue("(OnN)", initvalue, self->pos, dict); - Py_DECREF(initvalue); - return state; -} /*[clinic input] +@critical_section _io.BytesIO.__getstate__ [clinic start generated code]*/ static PyObject * _io_BytesIO___getstate___impl(bytesio *self) -/*[clinic end generated code: output=4a776270c8443b85 input=6e3cd9132f0cacdd]*/ +/*[clinic end generated code: output=4a776270c8443b85 input=f41e5bc9731475c4]*/ { - PyObject *op = (PyObject *)self; - PyObject *ret; - Py_BEGIN_CRITICAL_SECTION(op); - ret = bytesio_getstate_lock_held(op); - Py_END_CRITICAL_SECTION(); - return ret; + PyObject *initvalue = _io_BytesIO_getvalue_impl(self); + PyObject *dict; + PyObject *state; + + if (initvalue == NULL) + return NULL; + if (self->dict == NULL) { + dict = Py_NewRef(Py_None); + } + else { + dict = PyDict_Copy(self->dict); + if (dict == NULL) { + Py_DECREF(initvalue); + return NULL; + } + } + + state = Py_BuildValue("(OnN)", initvalue, self->pos, dict); + Py_DECREF(initvalue); + return state; } + +/*[clinic input] +@critical_section +_io.BytesIO.__setstate__ + + state: object + / +[clinic start generated code]*/ + static PyObject * -bytesio_setstate_lock_held(PyObject *op, PyObject *state) +_io_BytesIO___setstate___impl(bytesio *self, PyObject *state) +/*[clinic end generated code: output=3605abdec171bb98 input=82a189599ba75083]*/ { - _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); - PyObject *result; PyObject *position_obj; PyObject *dict; Py_ssize_t pos; - bytesio *self = bytesio_CAST(op); assert(state != NULL); @@ -1069,25 +1064,6 @@ bytesio_setstate_lock_held(PyObject *op, PyObject *state) Py_RETURN_NONE; } -/*[clinic input] -_io.BytesIO.__setstate__ - - state: object - / -[clinic start generated code]*/ - -static PyObject * -_io_BytesIO___setstate___impl(bytesio *self, PyObject *state) -/*[clinic end generated code: output=3605abdec171bb98 input=7d4339f5be0039ba]*/ -{ - PyObject *op = (PyObject *)self; - PyObject *ret; - Py_BEGIN_CRITICAL_SECTION(op); - ret = bytesio_setstate_lock_held(op, state); - Py_END_CRITICAL_SECTION(); - return ret; -} - static void bytesio_dealloc(PyObject *op) { @@ -1168,12 +1144,18 @@ _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue) return 0; } + +/*[clinic input] +@critical_section +_io.BytesIO.__sizeof__ + +Size of object in memory, in bytes. +[clinic start generated code]*/ + static PyObject * -bytesio_sizeof_lock_held(PyObject *op) +_io_BytesIO___sizeof___impl(bytesio *self) +/*[clinic end generated code: output=f61b601bd055c4de input=6f01c36e6ff64c17]*/ { - _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); - - bytesio *self = bytesio_CAST(op); size_t res = _PyObject_SIZE(Py_TYPE(self)); if (self->buf && !SHARED_BUF(self)) { size_t s = _PySys_GetSizeOf(self->buf); @@ -1185,24 +1167,6 @@ bytesio_sizeof_lock_held(PyObject *op) return PyLong_FromSize_t(res); } -/*[clinic input] -_io.BytesIO.__sizeof__ - -Size of object in memory, in bytes. -[clinic start generated code]*/ - -static PyObject * -_io_BytesIO___sizeof___impl(bytesio *self) -/*[clinic end generated code: output=f61b601bd055c4de input=097b24a2755a7b0b]*/ -{ - PyObject *op = (PyObject *)self; - PyObject *ret; - Py_BEGIN_CRITICAL_SECTION(op); - ret = bytesio_sizeof_lock_held(op); - Py_END_CRITICAL_SECTION(); - return ret; -} - static int bytesio_traverse(PyObject *op, visitproc visit, void *arg) { diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 73136ea139eb3c..823a94c2a79dd8 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -635,7 +635,13 @@ _io_BytesIO___getstate___impl(bytesio *self); static PyObject * _io_BytesIO___getstate__(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _io_BytesIO___getstate___impl((bytesio *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_BytesIO___getstate___impl((bytesio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_BytesIO___setstate____doc__, @@ -654,7 +660,9 @@ _io_BytesIO___setstate__(PyObject *self, PyObject *state) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO___setstate___impl((bytesio *)self, state); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -738,6 +746,12 @@ _io_BytesIO___sizeof___impl(bytesio *self); static PyObject * _io_BytesIO___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _io_BytesIO___sizeof___impl((bytesio *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_BytesIO___sizeof___impl((bytesio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } -/*[clinic end generated code: output=37e0318a34125084 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=65de7170154f6b5c input=a9049054013a1b77]*/ From c7184e471d179508cb0ab37f17c866c9def26899 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 13 Aug 2026 21:32:41 +0300 Subject: [PATCH 5/6] Use Argument Clinic for getters in the _io module The getters of _WindowsConsoleIO are left as they are, because Argument Clinic fails for an accessor in a preprocessor conditional block. --- Modules/_io/bufferedio.c | 11 +++- Modules/_io/bytesio.c | 26 ++++---- Modules/_io/clinic/bufferedio.c.h | 21 +++++- Modules/_io/clinic/bytesio.c.h | 34 +++++++++- Modules/_io/clinic/fileio.c.h | 106 +++++++++++++++++++++++++++++- Modules/_io/clinic/iobase.c.h | 28 +++++++- Modules/_io/clinic/textio.c.h | 21 +++++- Modules/_io/fileio.c | 53 +++++++++++---- Modules/_io/iobase.c | 12 +++- Modules/_io/textio.c | 11 +++- 10 files changed, 283 insertions(+), 40 deletions(-) diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 869af2e64c0869..2cc3774e75c9da 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -2505,10 +2505,15 @@ _io_BufferedRWPair_isatty_impl(rwpair *self) return _forward_call(self->reader, &_Py_ID(isatty), NULL); } +/*[clinic input] +@getter +_io.BufferedRWPair.closed +[clinic start generated code]*/ + static PyObject * -bufferedrwpair_closed_get(PyObject *op, void *Py_UNUSED(dummy)) +_io_BufferedRWPair_closed_get_impl(rwpair *self) +/*[clinic end generated code: output=4117400c74766f21 input=8248430ac54e5b25]*/ { - rwpair *self = rwpair_CAST(op); if (self->writer == NULL) { PyErr_SetString(PyExc_RuntimeError, "the BufferedRWPair object is being garbage-collected"); @@ -2748,7 +2753,7 @@ static PyMemberDef bufferedrwpair_members[] = { }; static PyGetSetDef bufferedrwpair_getset[] = { - {"closed", bufferedrwpair_closed_get, NULL, NULL}, + _IO_BUFFEREDRWPAIR_CLOSED_GETSETDEF {NULL} }; diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index f38b833115e1b0..22a903c8978684 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -295,20 +295,19 @@ write_bytes_lock_held(bytesio *self, PyObject *b) return len; } +/*[clinic input] +@critical_section +@getter +_io.BytesIO.closed + +True if the file is closed. +[clinic start generated code]*/ + static PyObject * -bytesio_get_closed(PyObject *op, void *Py_UNUSED(closure)) +_io_BytesIO_closed_get_impl(bytesio *self) +/*[clinic end generated code: output=3210245d480df846 input=53d116fdfe4e7580]*/ { - PyObject *ret; - bytesio *self = bytesio_CAST(op); - Py_BEGIN_CRITICAL_SECTION(self); - if (self->buf == NULL) { - ret = Py_True; - } - else { - ret = Py_False; - } - Py_END_CRITICAL_SECTION(); - return ret; + return PyBool_FromLong(self->buf == NULL); } /*[clinic input] @@ -1194,8 +1193,7 @@ bytesio_clear(PyObject *op) #undef clinic_state static PyGetSetDef bytesio_getsetlist[] = { - {"closed", bytesio_get_closed, NULL, - "True if the file is closed."}, + _IO_BYTESIO_CLOSED_GETSETDEF {NULL}, /* sentinel */ }; diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index 33ba747ccbcd03..4db5e7d5cc26a6 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -1427,6 +1427,25 @@ _io_BufferedRWPair_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io_BufferedRWPair_isatty_impl((rwpair *)self); } +#if !defined(_io_BufferedRWPair_closed_DOCSTR) +# define _io_BufferedRWPair_closed_DOCSTR NULL +#endif +#if defined(_IO_BUFFEREDRWPAIR_CLOSED_GETSETDEF) +# undef _IO_BUFFEREDRWPAIR_CLOSED_GETSETDEF +# define _IO_BUFFEREDRWPAIR_CLOSED_GETSETDEF {"closed", (getter)_io_BufferedRWPair_closed_get, (setter)_io_BufferedRWPair_closed_set, _io_BufferedRWPair_closed_DOCSTR}, +#else +# define _IO_BUFFEREDRWPAIR_CLOSED_GETSETDEF {"closed", (getter)_io_BufferedRWPair_closed_get, NULL, _io_BufferedRWPair_closed_DOCSTR}, +#endif + +static PyObject * +_io_BufferedRWPair_closed_get_impl(rwpair *self); + +static PyObject * +_io_BufferedRWPair_closed_get(PyObject *self, void *Py_UNUSED(context)) +{ + return _io_BufferedRWPair_closed_get_impl((rwpair *)self); +} + PyDoc_STRVAR(_io_BufferedRandom___init____doc__, "BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n" "--\n" @@ -1506,4 +1525,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=eed4ac9f76174342 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=aa42e059c43be3fd input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 823a94c2a79dd8..47690c84bddc81 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -10,6 +10,38 @@ preserve #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_CheckPositional() +PyDoc_STRVAR(_io_BytesIO_closed__doc__, +"True if the file is closed."); +#if defined(_io_BytesIO_closed_DOCSTR) +# undef _io_BytesIO_closed_DOCSTR +#endif +#define _io_BytesIO_closed_DOCSTR _io_BytesIO_closed__doc__ + +#if !defined(_io_BytesIO_closed_DOCSTR) +# define _io_BytesIO_closed_DOCSTR NULL +#endif +#if defined(_IO_BYTESIO_CLOSED_GETSETDEF) +# undef _IO_BYTESIO_CLOSED_GETSETDEF +# define _IO_BYTESIO_CLOSED_GETSETDEF {"closed", (getter)_io_BytesIO_closed_get, (setter)_io_BytesIO_closed_set, _io_BytesIO_closed_DOCSTR}, +#else +# define _IO_BYTESIO_CLOSED_GETSETDEF {"closed", (getter)_io_BytesIO_closed_get, NULL, _io_BytesIO_closed_DOCSTR}, +#endif + +static PyObject * +_io_BytesIO_closed_get_impl(bytesio *self); + +static PyObject * +_io_BytesIO_closed_get(PyObject *self, void *Py_UNUSED(context)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_BytesIO_closed_get_impl((bytesio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + PyDoc_STRVAR(_io_BytesIO_readable__doc__, "readable($self, /)\n" "--\n" @@ -754,4 +786,4 @@ _io_BytesIO___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) return return_value; } -/*[clinic end generated code: output=65de7170154f6b5c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=62ce36f0c6400579 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index 5a23972890059e..9560a2ebbd3acf 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -588,7 +588,111 @@ _io_FileIO__isatty_open_only(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io_FileIO__isatty_open_only_impl((fileio *)self); } +PyDoc_STRVAR(_io_FileIO_closed__doc__, +"True if the file is closed."); +#if defined(_io_FileIO_closed_DOCSTR) +# undef _io_FileIO_closed_DOCSTR +#endif +#define _io_FileIO_closed_DOCSTR _io_FileIO_closed__doc__ + +#if !defined(_io_FileIO_closed_DOCSTR) +# define _io_FileIO_closed_DOCSTR NULL +#endif +#if defined(_IO_FILEIO_CLOSED_GETSETDEF) +# undef _IO_FILEIO_CLOSED_GETSETDEF +# define _IO_FILEIO_CLOSED_GETSETDEF {"closed", (getter)_io_FileIO_closed_get, (setter)_io_FileIO_closed_set, _io_FileIO_closed_DOCSTR}, +#else +# define _IO_FILEIO_CLOSED_GETSETDEF {"closed", (getter)_io_FileIO_closed_get, NULL, _io_FileIO_closed_DOCSTR}, +#endif + +static PyObject * +_io_FileIO_closed_get_impl(fileio *self); + +static PyObject * +_io_FileIO_closed_get(PyObject *self, void *Py_UNUSED(context)) +{ + return _io_FileIO_closed_get_impl((fileio *)self); +} + +PyDoc_STRVAR(_io_FileIO_closefd__doc__, +"True if the file descriptor will be closed by close()."); +#if defined(_io_FileIO_closefd_DOCSTR) +# undef _io_FileIO_closefd_DOCSTR +#endif +#define _io_FileIO_closefd_DOCSTR _io_FileIO_closefd__doc__ + +#if !defined(_io_FileIO_closefd_DOCSTR) +# define _io_FileIO_closefd_DOCSTR NULL +#endif +#if defined(_IO_FILEIO_CLOSEFD_GETSETDEF) +# undef _IO_FILEIO_CLOSEFD_GETSETDEF +# define _IO_FILEIO_CLOSEFD_GETSETDEF {"closefd", (getter)_io_FileIO_closefd_get, (setter)_io_FileIO_closefd_set, _io_FileIO_closefd_DOCSTR}, +#else +# define _IO_FILEIO_CLOSEFD_GETSETDEF {"closefd", (getter)_io_FileIO_closefd_get, NULL, _io_FileIO_closefd_DOCSTR}, +#endif + +static PyObject * +_io_FileIO_closefd_get_impl(fileio *self); + +static PyObject * +_io_FileIO_closefd_get(PyObject *self, void *Py_UNUSED(context)) +{ + return _io_FileIO_closefd_get_impl((fileio *)self); +} + +PyDoc_STRVAR(_io_FileIO_mode__doc__, +"String giving the file mode."); +#if defined(_io_FileIO_mode_DOCSTR) +# undef _io_FileIO_mode_DOCSTR +#endif +#define _io_FileIO_mode_DOCSTR _io_FileIO_mode__doc__ + +#if !defined(_io_FileIO_mode_DOCSTR) +# define _io_FileIO_mode_DOCSTR NULL +#endif +#if defined(_IO_FILEIO_MODE_GETSETDEF) +# undef _IO_FILEIO_MODE_GETSETDEF +# define _IO_FILEIO_MODE_GETSETDEF {"mode", (getter)_io_FileIO_mode_get, (setter)_io_FileIO_mode_set, _io_FileIO_mode_DOCSTR}, +#else +# define _IO_FILEIO_MODE_GETSETDEF {"mode", (getter)_io_FileIO_mode_get, NULL, _io_FileIO_mode_DOCSTR}, +#endif + +static PyObject * +_io_FileIO_mode_get_impl(fileio *self); + +static PyObject * +_io_FileIO_mode_get(PyObject *self, void *Py_UNUSED(context)) +{ + return _io_FileIO_mode_get_impl((fileio *)self); +} + +PyDoc_STRVAR(_io_FileIO__blksize__doc__, +"Stat st_blksize if available."); +#if defined(_io_FileIO__blksize_DOCSTR) +# undef _io_FileIO__blksize_DOCSTR +#endif +#define _io_FileIO__blksize_DOCSTR _io_FileIO__blksize__doc__ + +#if !defined(_io_FileIO__blksize_DOCSTR) +# define _io_FileIO__blksize_DOCSTR NULL +#endif +#if defined(_IO_FILEIO__BLKSIZE_GETSETDEF) +# undef _IO_FILEIO__BLKSIZE_GETSETDEF +# define _IO_FILEIO__BLKSIZE_GETSETDEF {"_blksize", (getter)_io_FileIO__blksize_get, (setter)_io_FileIO__blksize_set, _io_FileIO__blksize_DOCSTR}, +#else +# define _IO_FILEIO__BLKSIZE_GETSETDEF {"_blksize", (getter)_io_FileIO__blksize_get, NULL, _io_FileIO__blksize_DOCSTR}, +#endif + +static PyObject * +_io_FileIO__blksize_get_impl(fileio *self); + +static PyObject * +_io_FileIO__blksize_get(PyObject *self, void *Py_UNUSED(context)) +{ + return _io_FileIO__blksize_get_impl((fileio *)self); +} + #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=a4d50af066c7ceb0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=45d4d67aea21cf1b input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 0fc8a849a0c750..caceccc4309db6 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -171,6 +171,32 @@ _io__IOBase_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) return _io__IOBase_flush_impl(self); } +PyDoc_STRVAR(_io__IOBase_closed__doc__, +"True if the file is closed."); +#if defined(_io__IOBase_closed_DOCSTR) +# undef _io__IOBase_closed_DOCSTR +#endif +#define _io__IOBase_closed_DOCSTR _io__IOBase_closed__doc__ + +#if !defined(_io__IOBase_closed_DOCSTR) +# define _io__IOBase_closed_DOCSTR NULL +#endif +#if defined(_IO__IOBASE_CLOSED_GETSETDEF) +# undef _IO__IOBASE_CLOSED_GETSETDEF +# define _IO__IOBASE_CLOSED_GETSETDEF {"closed", (getter)_io__IOBase_closed_get, (setter)_io__IOBase_closed_set, _io__IOBase_closed_DOCSTR}, +#else +# define _IO__IOBASE_CLOSED_GETSETDEF {"closed", (getter)_io__IOBase_closed_get, NULL, _io__IOBase_closed_DOCSTR}, +#endif + +static PyObject * +_io__IOBase_closed_get_impl(PyObject *self); + +static PyObject * +_io__IOBase_closed_get(PyObject *self, void *Py_UNUSED(context)) +{ + return _io__IOBase_closed_get_impl(self); +} + PyDoc_STRVAR(_io__IOBase__checkClosed__doc__, "_checkClosed($self, /)\n" "--\n" @@ -578,4 +604,4 @@ PyDoc_STRVAR(_io__RawIOBase_write__doc__, #define _IO__RAWIOBASE_WRITE_METHODDEF \ {"write", (PyCFunction)_io__RawIOBase_write, METH_O, _io__RawIOBase_write__doc__}, -/*[clinic end generated code: output=a42eede543e39a09 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=cdf6f5a0ad8852e0 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 3c682cb2f271ae..596144597efa2c 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -509,6 +509,25 @@ _io_IncrementalNewlineDecoder_reset(PyObject *self, PyObject *Py_UNUSED(ignored) return return_value; } +#if !defined(_io_IncrementalNewlineDecoder_newlines_DOCSTR) +# define _io_IncrementalNewlineDecoder_newlines_DOCSTR NULL +#endif +#if defined(_IO_INCREMENTALNEWLINEDECODER_NEWLINES_GETSETDEF) +# undef _IO_INCREMENTALNEWLINEDECODER_NEWLINES_GETSETDEF +# define _IO_INCREMENTALNEWLINEDECODER_NEWLINES_GETSETDEF {"newlines", (getter)_io_IncrementalNewlineDecoder_newlines_get, (setter)_io_IncrementalNewlineDecoder_newlines_set, _io_IncrementalNewlineDecoder_newlines_DOCSTR}, +#else +# define _IO_INCREMENTALNEWLINEDECODER_NEWLINES_GETSETDEF {"newlines", (getter)_io_IncrementalNewlineDecoder_newlines_get, NULL, _io_IncrementalNewlineDecoder_newlines_DOCSTR}, +#endif + +static PyObject * +_io_IncrementalNewlineDecoder_newlines_get_impl(nldecoder_object *self); + +static PyObject * +_io_IncrementalNewlineDecoder_newlines_get(PyObject *self, void *Py_UNUSED(context)) +{ + return _io_IncrementalNewlineDecoder_newlines_get_impl((nldecoder_object *)self); +} + PyDoc_STRVAR(_io_TextIOWrapper___init____doc__, "TextIOWrapper(buffer, encoding=None, errors=None, newline=None,\n" " line_buffering=False, write_through=False)\n" @@ -1356,4 +1375,4 @@ _io_TextIOWrapper_buffer_get(PyObject *self, void *Py_UNUSED(context)) return return_value; } -/*[clinic end generated code: output=e34c75e1d2a12084 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9ed6f17dc7fa30f6 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index cfed32bc17872a..20e150e77f9530 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -1288,32 +1288,60 @@ static PyMethodDef fileio_methods[] = { /* 'closed' and 'mode' are attributes for backwards compatibility reasons. */ +/*[clinic input] +@getter +_io.FileIO.closed + +True if the file is closed. +[clinic start generated code]*/ + static PyObject * -fileio_get_closed(PyObject *op, void *closure) +_io_FileIO_closed_get_impl(fileio *self) +/*[clinic end generated code: output=6605122cc0377bf6 input=4696b7fb11103a0f]*/ { - fileio *self = PyFileIO_CAST(op); return PyBool_FromLong((long)(self->fd < 0)); } +/*[clinic input] +@getter +_io.FileIO.closefd + +True if the file descriptor will be closed by close(). +[clinic start generated code]*/ + static PyObject * -fileio_get_closefd(PyObject *op, void *closure) +_io_FileIO_closefd_get_impl(fileio *self) +/*[clinic end generated code: output=f9932a0320687395 input=fc4d979307a724b6]*/ { - fileio *self = PyFileIO_CAST(op); return PyBool_FromLong((long)(self->closefd)); } +/*[clinic input] +@getter +_io.FileIO.mode + +String giving the file mode. +[clinic start generated code]*/ + static PyObject * -fileio_get_mode(PyObject *op, void *closure) +_io_FileIO_mode_get_impl(fileio *self) +/*[clinic end generated code: output=d5178215493e2e7e input=300a448fc9b2fea4]*/ { - fileio *self = PyFileIO_CAST(op); return PyUnicode_FromString(mode_string(self)); } +/*[clinic input] +@getter +_io.FileIO._blksize + +Stat st_blksize if available. +[clinic start generated code]*/ + static PyObject * -fileio_get_blksize(PyObject *op, void *closure) +_io_FileIO__blksize_get_impl(fileio *self) +/*[clinic end generated code: output=885b8dcac7f47ab7 input=0020e9e6a591f2a2]*/ { #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - fileio *self = PyFileIO_CAST(op); if (self->stat_atopen != NULL && self->stat_atopen->st_blksize > 1) { return PyLong_FromLong(self->stat_atopen->st_blksize); } @@ -1322,11 +1350,10 @@ fileio_get_blksize(PyObject *op, void *closure) } static PyGetSetDef fileio_getsetlist[] = { - {"closed", fileio_get_closed, NULL, "True if the file is closed"}, - {"closefd", fileio_get_closefd, NULL, - "True if the file descriptor will be closed by close()."}, - {"mode", fileio_get_mode, NULL, "String giving the file mode"}, - {"_blksize", fileio_get_blksize, NULL, "Stat st_blksize if available"}, + _IO_FILEIO_CLOSED_GETSETDEF + _IO_FILEIO_CLOSEFD_GETSETDEF + _IO_FILEIO_MODE_GETSETDEF + _IO_FILEIO__BLKSIZE_GETSETDEF {NULL}, }; diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 38bbf8185d3826..bb9c91b673826b 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -184,8 +184,16 @@ _io__IOBase_flush_impl(PyObject *self) return NULL; } +/*[clinic input] +@getter +_io._IOBase.closed + +True if the file is closed. +[clinic start generated code]*/ + static PyObject * -iobase_closed_get(PyObject *self, void *context) +_io__IOBase_closed_get_impl(PyObject *self) +/*[clinic end generated code: output=cb72a562de7b4082 input=8b68e9a4e2950776]*/ { int closed = iobase_is_closed(self); if (closed < 0) { @@ -902,7 +910,7 @@ static PyMethodDef iobase_methods[] = { static PyGetSetDef iobase_getset[] = { {"__dict__", PyObject_GenericGetDict, NULL, NULL}, - {"closed", iobase_closed_get, NULL, NULL}, + _IO__IOBASE_CLOSED_GETSETDEF {NULL} }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index ea8ed2713d8a14..241c8b7ff75ef3 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -635,10 +635,15 @@ _io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self) Py_RETURN_NONE; } +/*[clinic input] +@getter +_io.IncrementalNewlineDecoder.newlines +[clinic start generated code]*/ + static PyObject * -incrementalnewlinedecoder_newlines_get(PyObject *op, void *Py_UNUSED(context)) +_io_IncrementalNewlineDecoder_newlines_get_impl(nldecoder_object *self) +/*[clinic end generated code: output=4370cf5202a83d08 input=040f9a26aef317a8]*/ { - nldecoder_object *self = nldecoder_object_CAST(op); CHECK_INITIALIZED_DECODER(self); switch (self->seennl) { @@ -3446,7 +3451,7 @@ static PyMethodDef incrementalnewlinedecoder_methods[] = { }; static PyGetSetDef incrementalnewlinedecoder_getset[] = { - {"newlines", incrementalnewlinedecoder_newlines_get, NULL, NULL}, + _IO_INCREMENTALNEWLINEDECODER_NEWLINES_GETSETDEF {NULL} }; From c7d915ee70ef6977efcd1b5bb47287c686347fe8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 13 Aug 2026 21:44:35 +0300 Subject: [PATCH 6/6] Fix the FileIO.closed docstring assertion in test_descr --- Lib/test/test_descr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 7ac22455541fe2..a6ebda5bf4e5df 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3405,7 +3405,7 @@ def test_descrdoc(self): from _io import FileIO def check(descr, what): self.assertEqual(descr.__doc__, what) - check(FileIO.closed, "True if the file is closed") # getset descriptor + check(FileIO.closed, "True if the file is closed.") # getset descriptor check(complex.real, "the real part of a complex number") # member descriptor def test_doc_descriptor(self):