From cf4386a23eeb4c7e599da6f95cdc1b5acde2ed62 Mon Sep 17 00:00:00 2001 From: RydertHuGlIfE Date: Sun, 4 Jan 2026 13:48:20 +0530 Subject: [PATCH 1/2] gh-143412: Fix TypeError: _IOBase.readlines() takes no keyword arguments Enable keyword arguments for _IOBase.readline() and _IOBase.readlines() by removing the positional-only parameter marker. --- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 4 + Modules/_io/clinic/iobase.c.h | 93 ++++++++++++++++--- Modules/_io/iobase.c | 7 +- 6 files changed, 88 insertions(+), 19 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index e625bf2fef1912..c43dd4de842b38 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1790,6 +1790,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(header)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(headers)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hi)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hint)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hook)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hour)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(hours)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 771f0f8cb4ad87..4bf9f017a1733e 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -513,6 +513,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(header) STRUCT_FOR_ID(headers) STRUCT_FOR_ID(hi) + STRUCT_FOR_ID(hint) STRUCT_FOR_ID(hook) STRUCT_FOR_ID(hour) STRUCT_FOR_ID(hours) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 499a2569b9a06c..02ee7fd50eedb1 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1788,6 +1788,7 @@ extern "C" { INIT_ID(header), \ INIT_ID(headers), \ INIT_ID(hi), \ + INIT_ID(hint), \ INIT_ID(hook), \ INIT_ID(hour), \ INIT_ID(hours), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 1375f46018f943..33a62c2aa37535 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1832,6 +1832,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(hint); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(hook); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 402448545dfc51..09bcfbd1128b14 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -3,6 +3,7 @@ preserve [clinic start generated code]*/ #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) +# include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_SINGLETON() #endif #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() @@ -295,7 +296,7 @@ _io__IOBase_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(_io__IOBase_readline__doc__, -"readline($self, size=-1, /)\n" +"readline($self, /, size=-1)\n" "--\n" "\n" "Read and return a line from the stream.\n" @@ -307,27 +308,58 @@ PyDoc_STRVAR(_io__IOBase_readline__doc__, "terminator(s) recognized."); #define _IO__IOBASE_READLINE_METHODDEF \ - {"readline", _PyCFunction_CAST(_io__IOBase_readline), METH_FASTCALL, _io__IOBase_readline__doc__}, + {"readline", _PyCFunction_CAST(_io__IOBase_readline), METH_FASTCALL|METH_KEYWORDS, _io__IOBase_readline__doc__}, static PyObject * _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit); static PyObject * -_io__IOBase_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +_io__IOBase_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(size), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"size", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "readline", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; Py_ssize_t limit = -1; - if (!_PyArg_CheckPositional("readline", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } - if (nargs < 1) { - goto skip_optional; + if (!noptargs) { + goto skip_optional_pos; } if (!_Py_convert_optional_to_ssize_t(args[0], &limit)) { goto exit; } -skip_optional: +skip_optional_pos: return_value = _io__IOBase_readline_impl(self, limit); exit: @@ -335,7 +367,7 @@ _io__IOBase_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(_io__IOBase_readlines__doc__, -"readlines($self, hint=-1, /)\n" +"readlines($self, /, hint=-1)\n" "--\n" "\n" "Return a list of lines from the stream.\n" @@ -345,27 +377,58 @@ PyDoc_STRVAR(_io__IOBase_readlines__doc__, "lines so far exceeds hint."); #define _IO__IOBASE_READLINES_METHODDEF \ - {"readlines", _PyCFunction_CAST(_io__IOBase_readlines), METH_FASTCALL, _io__IOBase_readlines__doc__}, + {"readlines", _PyCFunction_CAST(_io__IOBase_readlines), METH_FASTCALL|METH_KEYWORDS, _io__IOBase_readlines__doc__}, static PyObject * _io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint); static PyObject * -_io__IOBase_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +_io__IOBase_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + Py_hash_t ob_hash; + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_hash = -1, + .ob_item = { &_Py_ID(hint), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"hint", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "readlines", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; Py_ssize_t hint = -1; - if (!_PyArg_CheckPositional("readlines", nargs, 0, 1)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 0, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } - if (nargs < 1) { - goto skip_optional; + if (!noptargs) { + goto skip_optional_pos; } if (!_Py_convert_optional_to_ssize_t(args[0], &hint)) { goto exit; } -skip_optional: +skip_optional_pos: return_value = _io__IOBase_readlines_impl(self, hint); exit: @@ -443,4 +506,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=9359e74d95534bef input=a9049054013a1b77]*/ +/*[clinic end generated code: output=051a5ea82eed3dc3 input=a9049054013a1b77]*/ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index f036ea503b11e8..e7f9250f56a151 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -553,7 +553,6 @@ _io__IOBase_isatty_impl(PyObject *self) /*[clinic input] _io._IOBase.readline size as limit: Py_ssize_t(accept={int, NoneType}) = -1 - / Read and return a line from the stream. @@ -566,7 +565,7 @@ terminator(s) recognized. static PyObject * _io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit) -/*[clinic end generated code: output=4479f79b58187840 input=d0c596794e877bff]*/ +/*[clinic end generated code: output=4479f79b58187840 input=5ed037c83054bf41]*/ { /* For backwards compatibility, a (slowish) readline(). */ @@ -703,7 +702,7 @@ iobase_iternext(PyObject *self) /*[clinic input] _io._IOBase.readlines hint: Py_ssize_t(accept={int, NoneType}) = -1 - / + Return a list of lines from the stream. @@ -714,7 +713,7 @@ lines so far exceeds hint. static PyObject * _io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint) -/*[clinic end generated code: output=2f50421677fa3dea input=9400c786ea9dc416]*/ +/*[clinic end generated code: output=2f50421677fa3dea input=ca109061c220173b]*/ { Py_ssize_t length = 0; PyObject *result, *it = NULL; From 9bf210dd38adfe6b6d9036a5ae62454dfb643fb1 Mon Sep 17 00:00:00 2001 From: RydertHuGlIfE Date: Sun, 4 Jan 2026 13:57:09 +0530 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=20Add=20NEWS=20entry=20for=20g?= =?UTF-8?q?h-143412?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-01-04-13-56-00.gh-issue-143412.RydertHuGlIfE.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-04-13-56-00.gh-issue-143412.RydertHuGlIfE.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-04-13-56-00.gh-issue-143412.RydertHuGlIfE.rst b/Misc/NEWS.d/next/Library/2026-01-04-13-56-00.gh-issue-143412.RydertHuGlIfE.rst new file mode 100644 index 00000000000000..35e81e300b77eb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-04-13-56-00.gh-issue-143412.RydertHuGlIfE.rst @@ -0,0 +1,2 @@ +Allow passing ``hint`` and ``size`` as keyword arguments to +:meth:`io.IOBase.readlines` and :meth:`io.IOBase.readline` respectively.