From 0bfd278b80506ef796276b1dc117cb93308b6812 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 22:45:24 +0200 Subject: [PATCH 01/11] Refactor: replace query with parameter Pass module state as parameter to err_mode() --- Modules/_io/fileio.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index cc0e7307b9da77..2e323938d86902 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -549,13 +549,10 @@ err_closed(void) } static PyObject * -err_mode(const char *action) +err_mode(_PyIO_State *state, const char *action) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_Format(state->unsupported_operation, - "File not open for %s", action); - return NULL; + return PyErr_Format(state->unsupported_operation, + "File not open for %s", action); } /*[clinic input] @@ -646,8 +643,10 @@ _io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer) if (self->fd < 0) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = IO_STATE(); + return err_mode(state, "reading"); + } n = _Py_read(self->fd, buffer->buf, buffer->len); /* copy errno because PyBuffer_Release() can indirectly modify it */ @@ -804,8 +803,10 @@ _io_FileIO_read_impl(fileio *self, Py_ssize_t size) if (self->fd < 0) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = IO_STATE(); + return err_mode(state, "reading"); + } if (size < 0) return _io_FileIO_readall_impl(self); @@ -862,8 +863,10 @@ _io_FileIO_write_impl(fileio *self, Py_buffer *b) if (self->fd < 0) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = IO_STATE(); + return err_mode(state, "writing"); + } n = _Py_write(self->fd, b->buf, b->len); /* copy errno because PyBuffer_Release() can indirectly modify it */ @@ -1014,8 +1017,10 @@ _io_FileIO_truncate_impl(fileio *self, PyObject *posobj) fd = self->fd; if (fd < 0) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = IO_STATE(); + return err_mode(state, "writing"); + } if (posobj == Py_None) { /* Get the current position. */ From 8196135de1acd75b2ebadd70123a97f300f57836 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 22:48:36 +0200 Subject: [PATCH 02/11] Fetch module state by class in _io.FileIO.readinto --- Modules/_io/clinic/fileio.c.h | 34 ++++++++++++++++++++++++++-------- Modules/_io/fileio.c | 7 ++++--- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index dfad8a58c4723e..c40eaa366f692d 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -215,27 +215,45 @@ PyDoc_STRVAR(_io_FileIO_readinto__doc__, "Same as RawIOBase.readinto()."); #define _IO_FILEIO_READINTO_METHODDEF \ - {"readinto", (PyCFunction)_io_FileIO_readinto, METH_O, _io_FileIO_readinto__doc__}, + {"readinto", _PyCFunction_CAST(_io_FileIO_readinto), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_readinto__doc__}, static PyObject * -_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer); +_io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer); static PyObject * -_io_FileIO_readinto(fileio *self, PyObject *arg) +_io_FileIO_readinto(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "readinto", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer buffer = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &buffer, PyBUF_WRITABLE) < 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &buffer, PyBUF_WRITABLE) < 0) { PyErr_Clear(); - _PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg); + _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); goto exit; } if (!PyBuffer_IsContiguous(&buffer, 'C')) { - _PyArg_BadArgument("readinto", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("readinto", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io_FileIO_readinto_impl(self, &buffer); + return_value = _io_FileIO_readinto_impl(self, cls, &buffer); exit: /* Cleanup for buffer */ @@ -470,4 +488,4 @@ _io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=29ed2ae6c451c139 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3bdbb95958e7357b input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 2e323938d86902..fda6ea577c8041 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -628,6 +628,7 @@ _io_FileIO_seekable_impl(fileio *self) /*[clinic input] _io.FileIO.readinto + cls: defining_class buffer: Py_buffer(accept={rwbuffer}) / @@ -635,8 +636,8 @@ Same as RawIOBase.readinto(). [clinic start generated code]*/ static PyObject * -_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer) -/*[clinic end generated code: output=b01a5a22c8415cb4 input=4721d7b68b154eaf]*/ +_io_FileIO_readinto_impl(fileio *self, PyTypeObject *cls, Py_buffer *buffer) +/*[clinic end generated code: output=97f0f3d69534db34 input=fd20323e18ce1ec8]*/ { Py_ssize_t n; int err; @@ -644,7 +645,7 @@ _io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer) if (self->fd < 0) return err_closed(); if (!self->readable) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return err_mode(state, "reading"); } From 95840419560fb1417701f62e89ed83389a96c292 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 22:50:09 +0200 Subject: [PATCH 03/11] Fetch module state by class in _io.FileIO.read --- Modules/_io/clinic/fileio.c.h | 31 +++++++++++++++++++++++-------- Modules/_io/fileio.c | 7 ++++--- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index c40eaa366f692d..fee704d74382f8 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -296,28 +296,43 @@ PyDoc_STRVAR(_io_FileIO_read__doc__, "Return an empty bytes object at EOF."); #define _IO_FILEIO_READ_METHODDEF \ - {"read", _PyCFunction_CAST(_io_FileIO_read), METH_FASTCALL, _io_FileIO_read__doc__}, + {"read", _PyCFunction_CAST(_io_FileIO_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_read__doc__}, static PyObject * -_io_FileIO_read_impl(fileio *self, Py_ssize_t size); +_io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size); static PyObject * -_io_FileIO_read(fileio *self, PyObject *const *args, Py_ssize_t nargs) +_io_FileIO_read(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "read", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_ssize_t size = -1; - if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } if (!_Py_convert_optional_to_ssize_t(args[0], &size)) { goto exit; } -skip_optional: - return_value = _io_FileIO_read_impl(self, size); +skip_optional_posonly: + return_value = _io_FileIO_read_impl(self, cls, size); exit: return return_value; @@ -488,4 +503,4 @@ _io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=3bdbb95958e7357b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4a1259440192e021 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index fda6ea577c8041..6d0efc565273ae 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -784,6 +784,7 @@ _io_FileIO_readall_impl(fileio *self) /*[clinic input] _io.FileIO.read + cls: defining_class size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -795,8 +796,8 @@ Return an empty bytes object at EOF. [clinic start generated code]*/ static PyObject * -_io_FileIO_read_impl(fileio *self, Py_ssize_t size) -/*[clinic end generated code: output=42528d39dd0ca641 input=bec9a2c704ddcbc9]*/ +_io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size) +/*[clinic end generated code: output=bbd749c7c224143e input=f613d2057e4a1918]*/ { char *ptr; Py_ssize_t n; @@ -805,7 +806,7 @@ _io_FileIO_read_impl(fileio *self, Py_ssize_t size) if (self->fd < 0) return err_closed(); if (!self->readable) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return err_mode(state, "reading"); } From 097f14780081e26cc2fd4ecb90779626f09ace92 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 22:50:19 +0200 Subject: [PATCH 04/11] Fetch module state by class in _io.FileIO.write --- Modules/_io/clinic/fileio.c.h | 32 +++++++++++++++++++++++++------- Modules/_io/fileio.c | 7 ++++--- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index fee704d74382f8..0fd7be567692cd 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -349,25 +349,43 @@ PyDoc_STRVAR(_io_FileIO_write__doc__, "returns None if the write would block."); #define _IO_FILEIO_WRITE_METHODDEF \ - {"write", (PyCFunction)_io_FileIO_write, METH_O, _io_FileIO_write__doc__}, + {"write", _PyCFunction_CAST(_io_FileIO_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_write__doc__}, static PyObject * -_io_FileIO_write_impl(fileio *self, Py_buffer *b); +_io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b); static PyObject * -_io_FileIO_write(fileio *self, PyObject *arg) +_io_FileIO_write(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "write", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer b = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &b, PyBUF_SIMPLE) != 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&b, 'C')) { - _PyArg_BadArgument("write", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("write", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io_FileIO_write_impl(self, &b); + return_value = _io_FileIO_write_impl(self, cls, &b); exit: /* Cleanup for b */ @@ -503,4 +521,4 @@ _io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=4a1259440192e021 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=58ebd74e61e9c53d input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 6d0efc565273ae..fd1d087cbe7be6 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -846,6 +846,7 @@ _io_FileIO_read_impl(fileio *self, PyTypeObject *cls, Py_ssize_t size) /*[clinic input] _io.FileIO.write + cls: defining_class b: Py_buffer / @@ -857,8 +858,8 @@ returns None if the write would block. [clinic start generated code]*/ static PyObject * -_io_FileIO_write_impl(fileio *self, Py_buffer *b) -/*[clinic end generated code: output=b4059db3d363a2f7 input=6e7908b36f0ce74f]*/ +_io_FileIO_write_impl(fileio *self, PyTypeObject *cls, Py_buffer *b) +/*[clinic end generated code: output=927e25be80f3b77b input=2776314f043088f5]*/ { Py_ssize_t n; int err; @@ -866,7 +867,7 @@ _io_FileIO_write_impl(fileio *self, Py_buffer *b) if (self->fd < 0) return err_closed(); if (!self->writable) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return err_mode(state, "writing"); } From c4e0940955c6880d2be5f75017bbcbfaf7f5aa06 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 22:53:27 +0200 Subject: [PATCH 05/11] Fetch module state by class in _io.FileIO.truncate --- Modules/_io/clinic/fileio.c.h | 31 +++++++++++++++++++++++-------- Modules/_io/fileio.c | 7 ++++--- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index 0fd7be567692cd..33a37a389d223d 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -473,26 +473,41 @@ PyDoc_STRVAR(_io_FileIO_truncate__doc__, "The current file position is changed to the value of size."); #define _IO_FILEIO_TRUNCATE_METHODDEF \ - {"truncate", _PyCFunction_CAST(_io_FileIO_truncate), METH_FASTCALL, _io_FileIO_truncate__doc__}, + {"truncate", _PyCFunction_CAST(_io_FileIO_truncate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io_FileIO_truncate__doc__}, static PyObject * -_io_FileIO_truncate_impl(fileio *self, PyObject *posobj); +_io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj); static PyObject * -_io_FileIO_truncate(fileio *self, PyObject *const *args, Py_ssize_t nargs) +_io_FileIO_truncate(fileio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "truncate", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; PyObject *posobj = Py_None; - if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } posobj = args[0]; -skip_optional: - return_value = _io_FileIO_truncate_impl(self, posobj); +skip_optional_posonly: + return_value = _io_FileIO_truncate_impl(self, cls, posobj); exit: return return_value; @@ -521,4 +536,4 @@ _io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO_FILEIO_TRUNCATE_METHODDEF #define _IO_FILEIO_TRUNCATE_METHODDEF #endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ -/*[clinic end generated code: output=58ebd74e61e9c53d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bef47b31b644996a input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index fd1d087cbe7be6..473f0a8a6befcb 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -1000,6 +1000,7 @@ _io_FileIO_tell_impl(fileio *self) #ifdef HAVE_FTRUNCATE /*[clinic input] _io.FileIO.truncate + cls: defining_class size as posobj: object = None / @@ -1010,8 +1011,8 @@ The current file position is changed to the value of size. [clinic start generated code]*/ static PyObject * -_io_FileIO_truncate_impl(fileio *self, PyObject *posobj) -/*[clinic end generated code: output=e49ca7a916c176fa input=b0ac133939823875]*/ +_io_FileIO_truncate_impl(fileio *self, PyTypeObject *cls, PyObject *posobj) +/*[clinic end generated code: output=d936732a49e8d5a2 input=c367fb45d6bb2c18]*/ { Py_off_t pos; int ret; @@ -1021,7 +1022,7 @@ _io_FileIO_truncate_impl(fileio *self, PyObject *posobj) if (fd < 0) return err_closed(); if (!self->writable) { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); return err_mode(state, "writing"); } From 7f34d0afcb3a65772367cfefe243ecf1122d6fa8 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 23:06:47 +0200 Subject: [PATCH 06/11] Refactor: replace query with parameter Pass module state to _unsupported() in textio.c --- Modules/_io/textio.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 070687a83d1bc2..d2d2248a6b1102 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -34,11 +34,9 @@ PyDoc_STRVAR(textiobase_doc, ); static PyObject * -_unsupported(const char *message) +_unsupported(_PyIO_State *state, const char *message) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_SetString(state->unsupported_operation, message); + PyErr_SetString(state->unsupported_operation, message); return NULL; } @@ -52,7 +50,8 @@ PyDoc_STRVAR(textiobase_detach_doc, static PyObject * textiobase_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _unsupported("detach"); + _PyIO_State *state = IO_STATE(); + return _unsupported(state, "detach"); } PyDoc_STRVAR(textiobase_read_doc, @@ -65,7 +64,8 @@ PyDoc_STRVAR(textiobase_read_doc, static PyObject * textiobase_read(PyObject *self, PyObject *args) { - return _unsupported("read"); + _PyIO_State *state = IO_STATE(); + return _unsupported(state, "read"); } PyDoc_STRVAR(textiobase_readline_doc, @@ -77,7 +77,8 @@ PyDoc_STRVAR(textiobase_readline_doc, static PyObject * textiobase_readline(PyObject *self, PyObject *args) { - return _unsupported("readline"); + _PyIO_State *state = IO_STATE(); + return _unsupported(state, "readline"); } PyDoc_STRVAR(textiobase_write_doc, @@ -89,7 +90,8 @@ PyDoc_STRVAR(textiobase_write_doc, static PyObject * textiobase_write(PyObject *self, PyObject *args) { - return _unsupported("write"); + _PyIO_State *state = IO_STATE(); + return _unsupported(state, "write"); } PyDoc_STRVAR(textiobase_encoding_doc, @@ -1349,7 +1351,8 @@ _io_TextIOWrapper_reconfigure_impl(textio *self, PyObject *encoding, /* Check if something is in the read buffer */ if (self->decoded_chars != NULL) { if (encoding != Py_None || errors != Py_None || newline_obj != NULL) { - _unsupported("It is not possible to set the encoding or newline " + _unsupported(self->state, + "It is not possible to set the encoding or newline " "of stream after the first read"); return NULL; } @@ -1616,8 +1619,9 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) CHECK_ATTACHED(self); CHECK_CLOSED(self); - if (self->encoder == NULL) - return _unsupported("not writable"); + if (self->encoder == NULL) { + return _unsupported(self->state, "not writable"); + } Py_INCREF(text); @@ -1798,7 +1802,7 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) */ if (self->decoder == NULL) { - _unsupported("not readable"); + _unsupported(self->state, "not readable"); return -1; } @@ -1923,8 +1927,9 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) CHECK_ATTACHED(self); CHECK_CLOSED(self); - if (self->decoder == NULL) - return _unsupported("not readable"); + if (self->decoder == NULL) { + return _unsupported(self->state, "not readable"); + } if (_textiowrapper_writeflush(self) < 0) return NULL; @@ -2455,7 +2460,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) Py_INCREF(cookieObj); if (!self->seekable) { - _unsupported("underlying stream is not seekable"); + _unsupported(self->state, "underlying stream is not seekable"); goto fail; } @@ -2469,7 +2474,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) goto fail; if (cmp == 0) { - _unsupported("can't do nonzero cur-relative seeks"); + _unsupported(self->state, "can't do nonzero cur-relative seeks"); goto fail; } @@ -2489,7 +2494,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) goto fail; if (cmp == 0) { - _unsupported("can't do nonzero end-relative seeks"); + _unsupported(self->state, "can't do nonzero end-relative seeks"); goto fail; } @@ -2652,7 +2657,7 @@ _io_TextIOWrapper_tell_impl(textio *self) CHECK_CLOSED(self); if (!self->seekable) { - _unsupported("underlying stream is not seekable"); + _unsupported(self->state, "underlying stream is not seekable"); goto fail; } if (!self->telling) { From cc1c8f8854275a2cbe29c3c912e11cc625718c46 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 23:11:04 +0200 Subject: [PATCH 07/11] Fetch module state by class in _WindowsConsoleIO.close --- Modules/_io/clinic/winconsoleio.c.h | 14 +++++++++----- Modules/_io/winconsoleio.c | 10 +++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h index 4c5cd0892c4a6d..c71b133dc429ab 100644 --- a/Modules/_io/clinic/winconsoleio.c.h +++ b/Modules/_io/clinic/winconsoleio.c.h @@ -20,15 +20,19 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_close__doc__, "close() may be called more than once without error."); #define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF \ - {"close", (PyCFunction)_io__WindowsConsoleIO_close, METH_NOARGS, _io__WindowsConsoleIO_close__doc__}, + {"close", _PyCFunction_CAST(_io__WindowsConsoleIO_close), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_close__doc__}, static PyObject * -_io__WindowsConsoleIO_close_impl(winconsoleio *self); +_io__WindowsConsoleIO_close_impl(winconsoleio *self, PyTypeObject *cls); static PyObject * -_io__WindowsConsoleIO_close(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +_io__WindowsConsoleIO_close(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return _io__WindowsConsoleIO_close_impl(self); + if (nargs) { + PyErr_SetString(PyExc_TypeError, "close() takes no arguments"); + return NULL; + } + return _io__WindowsConsoleIO_close_impl(self, cls); } #endif /* defined(HAVE_WINDOWS_CONSOLE_IO) */ @@ -407,4 +411,4 @@ _io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ -/*[clinic end generated code: output=163e934aa9b0ef16 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=613612aca1861781 input=a9049054013a1b77]*/ diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 58d9f2963aa93c..fd2e6156762195 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -180,6 +180,8 @@ internal_close(winconsoleio *self) /*[clinic input] _io._WindowsConsoleIO.close + cls: defining_class + / Close the console object. @@ -188,13 +190,15 @@ close() may be called more than once without error. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_close_impl(winconsoleio *self) -/*[clinic end generated code: output=27ef95b66c29057b input=68c4e5754f8136c2]*/ +_io__WindowsConsoleIO_close_impl(winconsoleio *self, PyTypeObject *cls) +/*[clinic end generated code: output=e50c1808c063e1e2 input=161001bd2a649a4b]*/ { PyObject *res; PyObject *exc; int rc; - res = PyObject_CallMethodOneArg((PyObject*)&PyRawIOBase_Type, + + _PyIO_State *state = get_io_state_by_cls(cls); + res = PyObject_CallMethodOneArg((PyObject*)state->PyRawIOBase_Type, &_Py_ID(close), (PyObject*)self); if (!self->closefd) { self->fd = -1; From 0b3d5020efaa90da19c505fa30d486d6a803bad9 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 23:15:53 +0200 Subject: [PATCH 08/11] Refactor: replace query with parameter Pass module state to err_mode() in winconsoleio.c --- Modules/_io/winconsoleio.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index fd2e6156762195..65671258f5086d 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -457,13 +457,10 @@ err_closed(void) } static PyObject * -err_mode(const char *action) +err_mode(_PyIO_State *state, const char *action) { - _PyIO_State *state = IO_STATE(); - if (state != NULL) - PyErr_Format(state->unsupported_operation, - "Console buffer does not support %s", action); - return NULL; + return PyErr_Format(state->unsupported_operation, + "Console buffer does not support %s", action); } /*[clinic input] @@ -647,7 +644,8 @@ readinto(winconsoleio *self, char *buf, Py_ssize_t len) return -1; } if (!self->readable) { - err_mode("reading"); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + err_mode(state, "reading"); return -1; } if (len == 0) @@ -920,8 +918,10 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size) if (self->fd == -1) return err_closed(); - if (!self->readable) - return err_mode("reading"); + if (!self->readable) { + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return err_mode(state, "reading"); + } if (size < 0) return _io__WindowsConsoleIO_readall_impl(self); @@ -972,8 +972,10 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b) if (self->fd == -1) return err_closed(); - if (!self->writable) - return err_mode("writing"); + if (!self->writable) { + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + return err_mode(state, "writing"); + } handle = _Py_get_osfhandle(self->fd); if (handle == INVALID_HANDLE_VALUE) From c07026fe3e7a0acca5a3f5c977feb5de920feaa1 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 23:19:24 +0200 Subject: [PATCH 09/11] Refactor: change function declaration Pass defining class to: - _WindowsConsoleIO.read - _WindowsConsoleIO.readinto - _WindowsConsoleIO.write --- Modules/_io/clinic/winconsoleio.c.h | 96 ++++++++++++++++++++++------- Modules/_io/winconsoleio.c | 18 ++++-- 2 files changed, 87 insertions(+), 27 deletions(-) diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h index c71b133dc429ab..cd3348dc1227cd 100644 --- a/Modules/_io/clinic/winconsoleio.c.h +++ b/Modules/_io/clinic/winconsoleio.c.h @@ -212,27 +212,46 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_readinto__doc__, "Same as RawIOBase.readinto()."); #define _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF \ - {"readinto", (PyCFunction)_io__WindowsConsoleIO_readinto, METH_O, _io__WindowsConsoleIO_readinto__doc__}, + {"readinto", _PyCFunction_CAST(_io__WindowsConsoleIO_readinto), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_readinto__doc__}, static PyObject * -_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, Py_buffer *buffer); +_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *buffer); static PyObject * -_io__WindowsConsoleIO_readinto(winconsoleio *self, PyObject *arg) +_io__WindowsConsoleIO_readinto(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "readinto", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer buffer = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &buffer, PyBUF_WRITABLE) < 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &buffer, PyBUF_WRITABLE) < 0) { PyErr_Clear(); - _PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg); + _PyArg_BadArgument("readinto", "argument 1", "read-write bytes-like object", args[0]); goto exit; } if (!PyBuffer_IsContiguous(&buffer, 'C')) { - _PyArg_BadArgument("readinto", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("readinto", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io__WindowsConsoleIO_readinto_impl(self, &buffer); + return_value = _io__WindowsConsoleIO_readinto_impl(self, cls, &buffer); exit: /* Cleanup for buffer */ @@ -282,28 +301,44 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_read__doc__, "Return an empty bytes object at EOF."); #define _IO__WINDOWSCONSOLEIO_READ_METHODDEF \ - {"read", _PyCFunction_CAST(_io__WindowsConsoleIO_read), METH_FASTCALL, _io__WindowsConsoleIO_read__doc__}, + {"read", _PyCFunction_CAST(_io__WindowsConsoleIO_read), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_read__doc__}, static PyObject * -_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size); +_io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, + Py_ssize_t size); static PyObject * -_io__WindowsConsoleIO_read(winconsoleio *self, PyObject *const *args, Py_ssize_t nargs) +_io__WindowsConsoleIO_read(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "read", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_ssize_t size = -1; - if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { goto exit; } if (nargs < 1) { - goto skip_optional; + goto skip_optional_posonly; } if (!_Py_convert_optional_to_ssize_t(args[0], &size)) { goto exit; } -skip_optional: - return_value = _io__WindowsConsoleIO_read_impl(self, size); +skip_optional_posonly: + return_value = _io__WindowsConsoleIO_read_impl(self, cls, size); exit: return return_value; @@ -323,25 +358,44 @@ PyDoc_STRVAR(_io__WindowsConsoleIO_write__doc__, "The number of bytes actually written is returned."); #define _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF \ - {"write", (PyCFunction)_io__WindowsConsoleIO_write, METH_O, _io__WindowsConsoleIO_write__doc__}, + {"write", _PyCFunction_CAST(_io__WindowsConsoleIO_write), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _io__WindowsConsoleIO_write__doc__}, static PyObject * -_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b); +_io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *b); static PyObject * -_io__WindowsConsoleIO_write(winconsoleio *self, PyObject *arg) +_io__WindowsConsoleIO_write(winconsoleio *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else + # define KWTUPLE NULL + #endif + + static const char * const _keywords[] = {"", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "write", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; Py_buffer b = {NULL, NULL}; - if (PyObject_GetBuffer(arg, &b, PyBUF_SIMPLE) != 0) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &b, PyBUF_SIMPLE) != 0) { goto exit; } if (!PyBuffer_IsContiguous(&b, 'C')) { - _PyArg_BadArgument("write", "argument", "contiguous buffer", arg); + _PyArg_BadArgument("write", "argument 1", "contiguous buffer", args[0]); goto exit; } - return_value = _io__WindowsConsoleIO_write_impl(self, &b); + return_value = _io__WindowsConsoleIO_write_impl(self, cls, &b); exit: /* Cleanup for b */ @@ -411,4 +465,4 @@ _io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) #ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF #endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ -/*[clinic end generated code: output=613612aca1861781 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=235393758365c229 input=a9049054013a1b77]*/ diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 65671258f5086d..e52717e8396c82 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -735,6 +735,7 @@ readinto(winconsoleio *self, char *buf, Py_ssize_t len) /*[clinic input] _io._WindowsConsoleIO.readinto + cls: defining_class buffer: Py_buffer(accept={rwbuffer}) / @@ -742,8 +743,9 @@ Same as RawIOBase.readinto(). [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, Py_buffer *buffer) -/*[clinic end generated code: output=66d1bdfa3f20af39 input=4ed68da48a6baffe]*/ +_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *buffer) +/*[clinic end generated code: output=96717c74f6204b79 input=4b0627c3b1645f78]*/ { Py_ssize_t len = readinto(self, buffer->buf, buffer->len); if (len < 0) @@ -899,6 +901,7 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self) /*[clinic input] _io._WindowsConsoleIO.read + cls: defining_class size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -910,8 +913,9 @@ Return an empty bytes object at EOF. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size) -/*[clinic end generated code: output=57df68af9f4b22d0 input=8bc73bc15d0fa072]*/ +_io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, + Py_ssize_t size) +/*[clinic end generated code: output=7e569a586537c0ae input=a14570a5da273365]*/ { PyObject *bytes; Py_ssize_t bytes_size; @@ -952,6 +956,7 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size) /*[clinic input] _io._WindowsConsoleIO.write + cls: defining_class b: Py_buffer / @@ -962,8 +967,9 @@ The number of bytes actually written is returned. [clinic start generated code]*/ static PyObject * -_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b) -/*[clinic end generated code: output=775bdb16fbf9137b input=be35fb624f97c941]*/ +_io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, + Py_buffer *b) +/*[clinic end generated code: output=e8019f480243cb29 input=10ac37c19339dfbe]*/ { BOOL res = TRUE; wchar_t *wbuf; From 6fbda701ba735386d2a629d28b6e084632c9de72 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 23:24:07 +0200 Subject: [PATCH 10/11] Refactor: replace query with parameter Pass module state to readinto() in winconsoleio.c --- Modules/_io/winconsoleio.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index e52717e8396c82..847d5903f239e7 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -637,14 +637,13 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { static Py_ssize_t -readinto(winconsoleio *self, char *buf, Py_ssize_t len) +readinto(_PyIO_State *state, winconsoleio *self, char *buf, Py_ssize_t len) { if (self->fd == -1) { err_closed(); return -1; } if (!self->readable) { - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); err_mode(state, "reading"); return -1; } @@ -747,7 +746,8 @@ _io__WindowsConsoleIO_readinto_impl(winconsoleio *self, PyTypeObject *cls, Py_buffer *buffer) /*[clinic end generated code: output=96717c74f6204b79 input=4b0627c3b1645f78]*/ { - Py_ssize_t len = readinto(self, buffer->buf, buffer->len); + _PyIO_State *state = IO_STATE(); + Py_ssize_t len = readinto(state, self, buffer->buf, buffer->len); if (len < 0) return NULL; @@ -938,7 +938,9 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, if (bytes == NULL) return NULL; - bytes_size = readinto(self, PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes)); + _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + bytes_size = readinto(state, self, PyBytes_AS_STRING(bytes), + PyBytes_GET_SIZE(bytes)); if (bytes_size < 0) { Py_CLEAR(bytes); return NULL; From 50399abe42c3427a868246f7322d58b13fa2084d Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 10 May 2023 23:27:48 +0200 Subject: [PATCH 11/11] Fetch module state by class where possible in winconsoleio.c --- Modules/_io/winconsoleio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 847d5903f239e7..f341cb238ce85e 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -746,7 +746,7 @@ _io__WindowsConsoleIO_readinto_impl(winconsoleio *self, PyTypeObject *cls, Py_buffer *buffer) /*[clinic end generated code: output=96717c74f6204b79 input=4b0627c3b1645f78]*/ { - _PyIO_State *state = IO_STATE(); + _PyIO_State *state = get_io_state_by_cls(cls); Py_ssize_t len = readinto(state, self, buffer->buf, buffer->len); if (len < 0) return NULL; @@ -923,7 +923,7 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, if (self->fd == -1) return err_closed(); if (!self->readable) { - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); return err_mode(state, "reading"); } @@ -938,7 +938,7 @@ _io__WindowsConsoleIO_read_impl(winconsoleio *self, PyTypeObject *cls, if (bytes == NULL) return NULL; - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); bytes_size = readinto(state, self, PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes)); if (bytes_size < 0) { @@ -981,7 +981,7 @@ _io__WindowsConsoleIO_write_impl(winconsoleio *self, PyTypeObject *cls, if (self->fd == -1) return err_closed(); if (!self->writable) { - _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); + _PyIO_State *state = get_io_state_by_cls(cls); return err_mode(state, "writing"); }