From 563838be24bb081331ccb946b9d4c1b9a3a92aa8 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Tue, 29 Apr 2014 10:14:02 +0200 Subject: Issue #21057: TextIOWrapper now allows the underlying binary stream's read() or read1() method to return an arbitrary bytes-like object (such as a memoryview). Patch by Nikolaus Rath. --- Modules/_io/textio.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 5739bc4d01..d5c7339b96 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1439,6 +1439,7 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) PyObject *dec_buffer = NULL; PyObject *dec_flags = NULL; PyObject *input_chunk = NULL; + Py_buffer input_chunk_buf; PyObject *decoded_chars, *chunk_size; Py_ssize_t nbytes, nchars; int eof; @@ -1470,6 +1471,15 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) Py_DECREF(state); return -1; } + + if (!PyBytes_Check(dec_buffer)) { + PyErr_Format(PyExc_TypeError, + "decoder getstate() should have returned a bytes " + "object, not '%.200s'", + Py_TYPE(dec_buffer)->tp_name); + Py_DECREF(state); + return -1; + } Py_INCREF(dec_buffer); Py_INCREF(dec_flags); Py_DECREF(state); @@ -1482,23 +1492,24 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) chunk_size = PyLong_FromSsize_t(Py_MAX(self->chunk_size, size_hint)); if (chunk_size == NULL) goto fail; + input_chunk = PyObject_CallMethodObjArgs(self->buffer, (self->has_read1 ? _PyIO_str_read1: _PyIO_str_read), chunk_size, NULL); Py_DECREF(chunk_size); if (input_chunk == NULL) goto fail; - if (!PyBytes_Check(input_chunk)) { + + if (PyObject_GetBuffer(input_chunk, &input_chunk_buf, 0) != 0) { PyErr_Format(PyExc_TypeError, - "underlying %s() should have returned a bytes object, " + "underlying %s() should have returned a bytes-like object, " "not '%.200s'", (self->has_read1 ? "read1": "read"), Py_TYPE(input_chunk)->tp_name); goto fail; } - nbytes = PyBytes_Size(input_chunk); + nbytes = input_chunk_buf.len; eof = (nbytes == 0); - if (Py_TYPE(self->decoder) == &PyIncrementalNewlineDecoder_Type) { decoded_chars = _PyIncrementalNewlineDecoder_decode( self->decoder, input_chunk, eof); @@ -1507,6 +1518,7 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) decoded_chars = PyObject_CallMethodObjArgs(self->decoder, _PyIO_str_decode, input_chunk, eof ? Py_True : Py_False, NULL); } + PyBuffer_Release(&input_chunk_buf); if (check_decoded(decoded_chars) < 0) goto fail; @@ -1523,18 +1535,12 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) /* At the snapshot point, len(dec_buffer) bytes before the read, the * next input to be decoded is dec_buffer + input_chunk. */ - PyObject *next_input = PyNumber_Add(dec_buffer, input_chunk); - if (next_input == NULL) - goto fail; - if (!PyBytes_Check(next_input)) { - PyErr_Format(PyExc_TypeError, - "decoder getstate() should have returned a bytes " - "object, not '%.200s'", - Py_TYPE(next_input)->tp_name); - Py_DECREF(next_input); + PyObject *next_input = dec_buffer; + PyBytes_Concat(&next_input, input_chunk); + if (next_input == NULL) { + dec_buffer = NULL; /* Reference lost to PyBytes_Concat */ goto fail; } - Py_DECREF(dec_buffer); Py_CLEAR(self->snapshot); self->snapshot = Py_BuildValue("NN", dec_flags, next_input); } -- cgit v1.2.1 From 531431bce7b7b8484e092eaa4b0790552b4b48d3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Jun 2014 23:31:25 +0200 Subject: Issue #10310: Use "unsigned int field:1" instead of "signed int field:1" in a private structure of the _io module to fix a compiler warning (overflow when assigning the value 1). Fix also a cast in incrementalnewlinedecoder_setstate(). Patch written by Hallvard B Furuseth. --- Modules/_io/textio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 140688fe22..aed5b2d606 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -224,8 +224,8 @@ typedef struct { PyObject_HEAD PyObject *decoder; PyObject *errors; - signed int pendingcr: 1; - signed int translate: 1; + unsigned int pendingcr: 1; + unsigned int translate: 1; unsigned int seennl: 3; } nldecoder_object; @@ -546,7 +546,7 @@ incrementalnewlinedecoder_setstate(nldecoder_object *self, PyObject *state) if (!PyArg_Parse(state, "(OK)", &buffer, &flag)) return NULL; - self->pendingcr = (int) flag & 1; + self->pendingcr = (int) (flag & 1); flag >>= 1; if (self->decoder != Py_None) -- cgit v1.2.1 From f89b06cb9e9169495342e996c37134783c54a4ba Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sun, 22 Jun 2014 14:17:44 -0700 Subject: add BufferedIOBase.readinto1 (closes #20578) Patch by Nikolaus Rath. --- Modules/_io/bufferedio.c | 66 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 6 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 4c0262e25a..2feda5a350 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -24,6 +24,7 @@ _Py_IDENTIFIER(read); _Py_IDENTIFIER(read1); _Py_IDENTIFIER(readable); _Py_IDENTIFIER(readinto); +_Py_IDENTIFIER(readinto1); _Py_IDENTIFIER(writable); _Py_IDENTIFIER(write); @@ -47,17 +48,21 @@ PyDoc_STRVAR(bufferediobase_doc, ); static PyObject * -bufferediobase_readinto(PyObject *self, PyObject *args) +_bufferediobase_readinto_generic(PyObject *self, PyObject *args, char readinto1) { Py_buffer buf; Py_ssize_t len; PyObject *data; - if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) { + if (!PyArg_ParseTuple(args, + readinto1 ? "w*:readinto1" : "w*:readinto", + &buf)) { return NULL; } - data = _PyObject_CallMethodId(self, &PyId_read, "n", buf.len); + data = _PyObject_CallMethodId(self, + readinto1 ? &PyId_read1 : &PyId_read, + "n", buf.len); if (data == NULL) goto error; @@ -88,6 +93,18 @@ bufferediobase_readinto(PyObject *self, PyObject *args) return NULL; } +static PyObject * +bufferediobase_readinto(PyObject *self, PyObject *args) +{ + return _bufferediobase_readinto_generic(self, args, 0); +} + +static PyObject * +bufferediobase_readinto1(PyObject *self, PyObject *args) +{ + return _bufferediobase_readinto_generic(self, args, 1); +} + static PyObject * bufferediobase_unsupported(const char *message) { @@ -167,6 +184,7 @@ static PyMethodDef bufferediobase_methods[] = { {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc}, {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc}, {"readinto", bufferediobase_readinto, METH_VARARGS, NULL}, + {"readinto1", bufferediobase_readinto1, METH_VARARGS, NULL}, {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc}, {NULL, NULL} }; @@ -989,7 +1007,7 @@ buffered_read1(buffered *self, PyObject *args) } static PyObject * -buffered_readinto(buffered *self, PyObject *args) +_buffered_readinto_generic(buffered *self, PyObject *args, char readinto1) { Py_buffer buf; Py_ssize_t n, written = 0, remaining; @@ -997,7 +1015,9 @@ buffered_readinto(buffered *self, PyObject *args) CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) + if (!PyArg_ParseTuple(args, + readinto1 ? "w*:readinto1" : "w*:readinto", + &buf)) return NULL; n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); @@ -1035,7 +1055,10 @@ buffered_readinto(buffered *self, PyObject *args) n = _bufferedreader_raw_read(self, (char *) buf.buf + written, remaining); } - else { + + /* In readinto1 mode, we do not want to fill the internal + buffer if we already have some data to return */ + else if (!(readinto1 && written)) { n = _bufferedreader_fill_buffer(self); if (n > 0) { if (n > remaining) @@ -1046,6 +1069,9 @@ buffered_readinto(buffered *self, PyObject *args) continue; /* short circuit */ } } + else + n = 0; + if (n == 0 || (n == -2 && written > 0)) break; if (n < 0) { @@ -1055,6 +1081,12 @@ buffered_readinto(buffered *self, PyObject *args) } goto end; } + + /* At most one read in readinto1 mode */ + if (readinto1) { + written += n; + break; + } } res = PyLong_FromSsize_t(written); @@ -1065,6 +1097,19 @@ end_unlocked: return res; } +static PyObject * +buffered_readinto(buffered *self, PyObject *args) +{ + return _buffered_readinto_generic(self, args, 0); +} + +static PyObject * +buffered_readinto1(buffered *self, PyObject *args) +{ + return _buffered_readinto_generic(self, args, 1); +} + + static PyObject * _buffered_readline(buffered *self, Py_ssize_t limit) { @@ -1750,6 +1795,7 @@ static PyMethodDef bufferedreader_methods[] = { {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"read1", (PyCFunction)buffered_read1, METH_VARARGS}, {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS}, + {"readinto1", (PyCFunction)buffered_readinto1, METH_VARARGS}, {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, @@ -2348,6 +2394,12 @@ bufferedrwpair_readinto(rwpair *self, PyObject *args) return _forward_call(self->reader, &PyId_readinto, args); } +static PyObject * +bufferedrwpair_readinto1(rwpair *self, PyObject *args) +{ + return _forward_call(self->reader, &PyId_readinto1, args); +} + static PyObject * bufferedrwpair_write(rwpair *self, PyObject *args) { @@ -2413,6 +2465,7 @@ static PyMethodDef bufferedrwpair_methods[] = { {"peek", (PyCFunction)bufferedrwpair_peek, METH_VARARGS}, {"read1", (PyCFunction)bufferedrwpair_read1, METH_VARARGS}, {"readinto", (PyCFunction)bufferedrwpair_readinto, METH_VARARGS}, + {"readinto1", (PyCFunction)bufferedrwpair_readinto1, METH_VARARGS}, {"write", (PyCFunction)bufferedrwpair_write, METH_VARARGS}, {"flush", (PyCFunction)bufferedrwpair_flush, METH_NOARGS}, @@ -2561,6 +2614,7 @@ static PyMethodDef bufferedrandom_methods[] = { {"read", (PyCFunction)buffered_read, METH_VARARGS}, {"read1", (PyCFunction)buffered_read1, METH_VARARGS}, {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS}, + {"readinto1", (PyCFunction)buffered_readinto1, METH_VARARGS}, {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, -- cgit v1.2.1 From b46526728f13e548ee7cef8b2c0510efbbb57da3 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sun, 29 Jun 2014 20:07:28 -0400 Subject: Issue #21679: Prevent extraneous fstat() calls during open(). Patch by Bohuslav Kabrda. --- Modules/_io/_iomodule.c | 28 +++++++++------------------- Modules/_io/fileio.c | 46 +++++++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 40 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 660ff1fe58..9e14b4ff40 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -237,8 +237,8 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL; + _Py_IDENTIFIER(_blksize); _Py_IDENTIFIER(isatty); - _Py_IDENTIFIER(fileno); _Py_IDENTIFIER(mode); _Py_IDENTIFIER(close); @@ -380,24 +380,14 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) line_buffering = 0; if (buffering < 0) { - buffering = DEFAULT_BUFFER_SIZE; -#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - { - struct stat st; - long fileno; - PyObject *res = _PyObject_CallMethodId(raw, &PyId_fileno, NULL); - if (res == NULL) - goto error; - - fileno = PyLong_AsLong(res); - Py_DECREF(res); - if (fileno == -1 && PyErr_Occurred()) - goto error; - - if (fstat(fileno, &st) >= 0 && st.st_blksize > 1) - buffering = st.st_blksize; - } -#endif + PyObject *blksize_obj; + blksize_obj = _PyObject_GetAttrId(raw, &PyId__blksize); + if (blksize_obj == NULL) + goto error; + buffering = PyLong_AsLong(blksize_obj); + Py_DECREF(blksize_obj); + if (buffering == -1 && PyErr_Occurred()) + goto error; } if (buffering < 0) { PyErr_SetString(PyExc_ValueError, diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index cbb2daf5c2..038b2c6459 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -53,6 +53,7 @@ typedef struct { signed int seekable : 2; /* -1 means unknown */ unsigned int closefd : 1; char finalizing; + unsigned int blksize; PyObject *weakreflist; PyObject *dict; } fileio; @@ -161,6 +162,7 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) self->writable = 0; self->appending = 0; self->seekable = -1; + self->blksize = 0; self->closefd = 1; self->weakreflist = NULL; } @@ -168,26 +170,6 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *) self; } -/* On Unix, open will succeed for directories. - In Python, there should be no file objects referring to - directories, so we need a check. */ - -static int -dircheck(fileio* self, PyObject *nameobj) -{ -#if defined(HAVE_FSTAT) && defined(S_ISDIR) && defined(EISDIR) - struct stat buf; - if (self->fd < 0) - return 0; - if (fstat(self->fd, &buf) == 0 && S_ISDIR(buf.st_mode)) { - errno = EISDIR; - PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); - return -1; - } -#endif - return 0; -} - static int check_fd(int fd) { @@ -233,6 +215,9 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) #elif !defined(MS_WINDOWS) int *atomic_flag_works = NULL; #endif +#ifdef HAVE_FSTAT + struct stat fdfstat; +#endif assert(PyFileIO_Check(oself)); if (self->fd >= 0) { @@ -421,8 +406,26 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) goto error; #endif } - if (dircheck(self, nameobj) < 0) + + self->blksize = DEFAULT_BUFFER_SIZE; +#ifdef HAVE_FSTAT + if (fstat(self->fd, &fdfstat) < 0) goto error; +#if defined(S_ISDIR) && defined(EISDIR) + /* On Unix, open will succeed for directories. + In Python, there should be no file objects referring to + directories, so we need a check. */ + if (S_ISDIR(fdfstat.st_mode)) { + errno = EISDIR; + PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); + goto error; + } +#endif /* defined(S_ISDIR) */ +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + if (fdfstat.st_blksize > 1) + self->blksize = fdfstat.st_blksize; +#endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ +#endif /* HAVE_FSTAT */ #if defined(MS_WINDOWS) || defined(__CYGWIN__) /* don't translate newlines (\r\n <=> \n) */ @@ -1216,6 +1219,7 @@ static PyGetSetDef fileio_getsetlist[] = { }; static PyMemberDef fileio_members[] = { + {"_blksize", T_UINT, offsetof(fileio, blksize), 0}, {"_finalizing", T_BOOL, offsetof(fileio, finalizing), 0}, {NULL} }; -- cgit v1.2.1 From 75f17e79ab6400664e161ae87c6d70a2e4d46ce1 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 4 Jul 2014 17:00:25 -0700 Subject: properly decref the return value of close() --- Modules/_io/_iomodule.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 9e14b4ff40..6f7af41382 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -455,11 +455,13 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) error: if (result != NULL) { - PyObject *exc, *val, *tb; + PyObject *exc, *val, *tb, *close_result; PyErr_Fetch(&exc, &val, &tb); - if (_PyObject_CallMethodId(result, &PyId_close, NULL) != NULL) + close_result = _PyObject_CallMethodId(result, &PyId_close, NULL); + if (close_result != NULL) { + Py_DECREF(close_result); PyErr_Restore(exc, val, tb); - else { + } else { PyObject *exc2, *val2, *tb2; PyErr_Fetch(&exc2, &val2, &tb2); PyErr_NormalizeException(&exc, &val, &tb); -- cgit v1.2.1 From babec53dc28831060a20bff1d83d002403fcb859 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Tue, 29 Jul 2014 19:41:11 -0400 Subject: Issue #22003: When initialized from a bytes object, io.BytesIO() now defers making a copy until it is mutated, improving performance and memory use on some use cases. Patch by David Wilson. --- Modules/_io/bytesio.c | 202 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 151 insertions(+), 51 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 54840bb88a..d8de916185 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -11,6 +11,10 @@ typedef struct { PyObject *dict; PyObject *weakreflist; Py_ssize_t exports; + /** If `initvalue' != NULL, `buf' is a read-only pointer into the PyBytes + * referenced by `initvalue'. It must be copied prior to mutation, and + * released during finalization */ + PyObject *initvalue; } bytesio; typedef struct { @@ -19,11 +23,11 @@ typedef struct { } bytesiobuf; -#define CHECK_CLOSED(self) \ +#define CHECK_CLOSED(self, ret) \ if ((self)->buf == NULL) { \ PyErr_SetString(PyExc_ValueError, \ "I/O operation on closed file."); \ - return NULL; \ + return ret; \ } #define CHECK_EXPORTS(self) \ @@ -33,6 +37,45 @@ typedef struct { return NULL; \ } +/* Ensure we have a buffer suitable for writing, in the case that an initvalue + * object was provided, and we're currently borrowing its buffer. `size' + * indicates the new buffer size allocated as part of unsharing, to avoid a + * redundant reallocation caused by any subsequent mutation. `truncate' + * indicates whether truncation should occur if `size` < self->string_size. + * + * Do nothing if the buffer wasn't shared. Returns 0 on success, or sets an + * exception and returns -1 on failure. Existing state is preserved on failure. + */ +static int +unshare(bytesio *self, size_t preferred_size, int truncate) +{ + if (self->initvalue) { + Py_ssize_t copy_size; + char *new_buf; + + if((! truncate) && preferred_size < self->string_size) { + preferred_size = self->string_size; + } + + new_buf = (char *)PyMem_Malloc(preferred_size); + if (new_buf == NULL) { + PyErr_NoMemory(); + return -1; + } + + copy_size = self->string_size; + if (copy_size > preferred_size) { + copy_size = preferred_size; + } + + memcpy(new_buf, self->buf, copy_size); + Py_CLEAR(self->initvalue); + self->buf = new_buf; + self->buf_size = preferred_size; + self->string_size = (Py_ssize_t) copy_size; + } + return 0; +} /* Internal routine to get a line from the buffer of a BytesIO object. Returns the length between the current position to the @@ -125,11 +168,18 @@ resize_buffer(bytesio *self, size_t size) static Py_ssize_t write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) { + size_t desired; + assert(self->buf != NULL); assert(self->pos >= 0); assert(len >= 0); - if ((size_t)self->pos + len > self->buf_size) { + desired = (size_t)self->pos + len; + if (unshare(self, desired, 0) < 0) { + return -1; + } + + if (desired > self->buf_size) { if (resize_buffer(self, (size_t)self->pos + len) < 0) return -1; } @@ -160,6 +210,74 @@ write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) return len; } +/* Release or free any existing buffer, and place the BytesIO in the closed + * state. */ +static void +reset(bytesio *self) +{ + if (self->initvalue) { + Py_CLEAR(self->initvalue); + } else if (self->buf) { + PyMem_Free(self->buf); + } + self->buf = NULL; + self->string_size = 0; + self->pos = 0; +} + +/* Reinitialize with a new heap-allocated buffer of size `size`. Returns 0 on + * success, or sets an exception and returns -1 on failure. Existing state is + * preserved on failure. */ +static int +reinit_private(bytesio *self, Py_ssize_t size) +{ + char *tmp = (char *)PyMem_Malloc(size); + if (tmp == NULL) { + PyErr_NoMemory(); + return -1; + } + reset(self); + self->buf = tmp; + self->buf_size = size; + return 0; +} + +/* Internal version of BytesIO.__init__; resets the object to its initial + * (closed) state before repopulating it, optionally by sharing a PyBytes + * buffer provided by `initvalue'. Returns 0 on success, or sets an exception + * and returns -1 on failure. */ +static int +reinit(bytesio *self, PyObject *initvalue) +{ + CHECK_CLOSED(self, -1); + + if (initvalue == NULL || initvalue == Py_None) { + if (reinit_private(self, 0) < 0) { + return -1; + } + } else if (PyBytes_CheckExact(initvalue)) { + reset(self); + Py_INCREF(initvalue); + self->initvalue = initvalue; + self->buf = PyBytes_AS_STRING(initvalue); + self->buf_size = PyBytes_GET_SIZE(initvalue); + self->string_size = PyBytes_GET_SIZE(initvalue); + } else { + Py_buffer buf; + if (PyObject_GetBuffer(initvalue, &buf, PyBUF_CONTIG_RO) < 0) { + return -1; + } + if (reinit_private(self, buf.len) < 0) { + PyBuffer_Release(&buf); + return -1; + } + memcpy(self->buf, buf.buf, buf.len); + self->string_size = buf.len; + PyBuffer_Release(&buf); + } + return 0; +} + static PyObject * bytesio_get_closed(bytesio *self) { @@ -184,7 +302,7 @@ PyDoc_STRVAR(seekable_doc, static PyObject * return_not_closed(bytesio *self) { - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); Py_RETURN_TRUE; } @@ -194,7 +312,7 @@ PyDoc_STRVAR(flush_doc, static PyObject * bytesio_flush(bytesio *self) { - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); Py_RETURN_NONE; } @@ -210,7 +328,7 @@ bytesio_getbuffer(bytesio *self) bytesiobuf *buf; PyObject *view; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); buf = (bytesiobuf *) type->tp_alloc(type, 0); if (buf == NULL) @@ -230,7 +348,7 @@ PyDoc_STRVAR(getval_doc, static PyObject * bytesio_getvalue(bytesio *self) { - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); return PyBytes_FromStringAndSize(self->buf, self->string_size); } @@ -243,7 +361,7 @@ PyDoc_STRVAR(isatty_doc, static PyObject * bytesio_isatty(bytesio *self) { - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); Py_RETURN_FALSE; } @@ -253,7 +371,7 @@ PyDoc_STRVAR(tell_doc, static PyObject * bytesio_tell(bytesio *self) { - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); return PyLong_FromSsize_t(self->pos); } @@ -270,7 +388,7 @@ bytesio_read(bytesio *self, PyObject *args) char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); if (!PyArg_ParseTuple(args, "|O:read", &arg)) return NULL; @@ -339,7 +457,7 @@ bytesio_readline(bytesio *self, PyObject *args) char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); if (!PyArg_ParseTuple(args, "|O:readline", &arg)) return NULL; @@ -385,7 +503,7 @@ bytesio_readlines(bytesio *self, PyObject *args) char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); if (!PyArg_ParseTuple(args, "|O:readlines", &arg)) return NULL; @@ -442,7 +560,7 @@ bytesio_readinto(bytesio *self, PyObject *buffer) void *raw_buffer; Py_ssize_t len, n; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); if (PyObject_AsWriteBuffer(buffer, &raw_buffer, &len) == -1) return NULL; @@ -475,7 +593,7 @@ bytesio_truncate(bytesio *self, PyObject *args) Py_ssize_t size; PyObject *arg = Py_None; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); CHECK_EXPORTS(self); if (!PyArg_ParseTuple(args, "|O:truncate", &arg)) @@ -502,6 +620,10 @@ bytesio_truncate(bytesio *self, PyObject *args) return NULL; } + if (unshare(self, size, 1) < 0) { + return NULL; + } + if (size < self->string_size) { self->string_size = size; if (resize_buffer(self, size) < 0) @@ -517,7 +639,7 @@ bytesio_iternext(bytesio *self) char *next; Py_ssize_t n; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); n = get_line(self, &next); @@ -542,7 +664,7 @@ bytesio_seek(bytesio *self, PyObject *args) Py_ssize_t pos; int mode = 0; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode)) return NULL; @@ -597,7 +719,7 @@ bytesio_write(bytesio *self, PyObject *obj) Py_buffer buf; PyObject *result = NULL; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); CHECK_EXPORTS(self); if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0) @@ -625,7 +747,7 @@ bytesio_writelines(bytesio *self, PyObject *v) PyObject *it, *item; PyObject *ret; - CHECK_CLOSED(self); + CHECK_CLOSED(self, NULL); it = PyObject_GetIter(v); if (it == NULL) @@ -655,10 +777,7 @@ PyDoc_STRVAR(close_doc, static PyObject * bytesio_close(bytesio *self) { - if (self->buf != NULL) { - PyMem_Free(self->buf); - self->buf = NULL; - } + reset(self); Py_RETURN_NONE; } @@ -706,11 +825,11 @@ bytesio_getstate(bytesio *self) static PyObject * bytesio_setstate(bytesio *self, PyObject *state) { - PyObject *result; PyObject *position_obj; PyObject *dict; Py_ssize_t pos; + CHECK_EXPORTS(self); assert(state != NULL); /* We allow the state tuple to be longer than 3, because we may need @@ -722,18 +841,13 @@ bytesio_setstate(bytesio *self, PyObject *state) Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name); return NULL; } - CHECK_EXPORTS(self); - /* Reset the object to its default state. This is only needed to handle - the case of repeated calls to __setstate__. */ - self->string_size = 0; - self->pos = 0; - /* Set the value of the internal buffer. If state[0] does not support the - buffer protocol, bytesio_write will raise the appropriate TypeError. */ - result = bytesio_write(self, PyTuple_GET_ITEM(state, 0)); - if (result == NULL) + /* Reset the object to its default state and set the value of the internal + * buffer. If state[0] does not support the buffer protocol, reinit() will + * raise the appropriate TypeError. */ + if (reinit(self, PyTuple_GET_ITEM(state, 0)) < 0) { return NULL; - Py_DECREF(result); + } /* Set carefully the position value. Alternatively, we could use the seek method instead of modifying self->pos directly to better protect the @@ -788,10 +902,9 @@ bytesio_dealloc(bytesio *self) "deallocated BytesIO object has exported buffers"); PyErr_Print(); } - if (self->buf != NULL) { - PyMem_Free(self->buf); - self->buf = NULL; - } + + reset(self); + Py_CLEAR(self->dict); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -830,20 +943,7 @@ bytesio_init(bytesio *self, PyObject *args, PyObject *kwds) &initvalue)) return -1; - /* In case, __init__ is called multiple times. */ - self->string_size = 0; - self->pos = 0; - - if (initvalue && initvalue != Py_None) { - PyObject *res; - res = bytesio_write(self, initvalue); - if (res == NULL) - return -1; - Py_DECREF(res); - self->pos = 0; - } - - return 0; + return reinit(self, initvalue); } static PyObject * -- cgit v1.2.1 From a6ad9ce216d87e879777535690610ef5e262c79b Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 14 Aug 2014 22:26:38 +0300 Subject: Issue #15381: Optimized line reading in io.BytesIO. --- Modules/_io/bytesio.c | 56 +++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index d8de916185..d07da08421 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -81,31 +81,28 @@ unshare(bytesio *self, size_t preferred_size, int truncate) object. Returns the length between the current position to the next newline character. */ static Py_ssize_t -get_line(bytesio *self, char **output) +scan_eol(bytesio *self, Py_ssize_t len) { - char *n; - const char *str_end; - Py_ssize_t len; + const char *start, *n; + Py_ssize_t maxlen; assert(self->buf != NULL); /* Move to the end of the line, up to the end of the string, s. */ - str_end = self->buf + self->string_size; - for (n = self->buf + self->pos; - n < str_end && *n != '\n'; - n++); - - /* Skip the newline character */ - if (n < str_end) - n++; - - /* Get the length from the current position to the end of the line. */ - len = n - (self->buf + self->pos); - *output = self->buf + self->pos; - + start = self->buf + self->pos; + maxlen = self->string_size - self->pos; + if (len < 0 || len > maxlen) + len = maxlen; + + if (len) { + n = memchr(start, '\n', len); + if (n) + /* Get the length from the current position to the end of + the line. */ + len = n - start + 1; + } assert(len >= 0); assert(self->pos < PY_SSIZE_T_MAX - len); - self->pos += len; return len; } @@ -477,14 +474,10 @@ bytesio_readline(bytesio *self, PyObject *args) return NULL; } - n = get_line(self, &output); - - if (size >= 0 && size < n) { - size = n - size; - n -= size; - self->pos -= size; - } + n = scan_eol(self, size); + output = self->buf + self->pos; + self->pos += n; return PyBytes_FromStringAndSize(output, n); } @@ -528,7 +521,9 @@ bytesio_readlines(bytesio *self, PyObject *args) if (!result) return NULL; - while ((n = get_line(self, &output)) != 0) { + output = self->buf + self->pos; + while ((n = scan_eol(self, -1)) != 0) { + self->pos += n; line = PyBytes_FromStringAndSize(output, n); if (!line) goto on_error; @@ -540,6 +535,7 @@ bytesio_readlines(bytesio *self, PyObject *args) size += n; if (maxsize > 0 && size >= maxsize) break; + output += n; } return result; @@ -636,16 +632,18 @@ bytesio_truncate(bytesio *self, PyObject *args) static PyObject * bytesio_iternext(bytesio *self) { - char *next; + const char *next; Py_ssize_t n; CHECK_CLOSED(self, NULL); - n = get_line(self, &next); + n = scan_eol(self, -1); - if (!next || n == 0) + if (n == 0) return NULL; + next = self->buf + self->pos; + self->pos += n; return PyBytes_FromStringAndSize(next, n); } -- cgit v1.2.1 From 5b0efc37029d1ed25416801b1f78e306aa01670e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 16 Aug 2014 01:03:39 +0200 Subject: Issue #22156: Fix some "comparison between signed and unsigned integers" compiler warnings in the Modules/ subdirectory. --- Modules/_io/bytesio.c | 6 ++++-- Modules/_io/textio.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index d07da08421..56ad788d3f 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -53,10 +53,12 @@ unshare(bytesio *self, size_t preferred_size, int truncate) Py_ssize_t copy_size; char *new_buf; - if((! truncate) && preferred_size < self->string_size) { + if((! truncate) && preferred_size < (size_t)self->string_size) { preferred_size = self->string_size; } + /* PyMem_Malloc() returns NULL if preferred_size is bigger + than PY_SSIZE_T_MAX */ new_buf = (char *)PyMem_Malloc(preferred_size); if (new_buf == NULL) { PyErr_NoMemory(); @@ -64,7 +66,7 @@ unshare(bytesio *self, size_t preferred_size, int truncate) } copy_size = self->string_size; - if (copy_size > preferred_size) { + if ((size_t)copy_size > preferred_size) { copy_size = preferred_size; } diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index aed5b2d606..b4c3c406d3 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1730,7 +1730,7 @@ _PyIO_find_line_ending( else { /* Non-universal mode. */ Py_ssize_t readnl_len = PyUnicode_GET_LENGTH(readnl); - char *nl = PyUnicode_DATA(readnl); + Py_UCS1 *nl = PyUnicode_1BYTE_DATA(readnl); /* Assume that readnl is an ASCII character. */ assert(PyUnicode_KIND(readnl) == PyUnicode_1BYTE_KIND); if (readnl_len == 1) { -- cgit v1.2.1 From b6c677f13497ce8dabc8aad7fb272b09dfeccb56 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 6 Sep 2014 20:07:17 +0300 Subject: Issue #22215: Now ValueError is raised instead of TypeError when str or bytes argument contains not permitted null character or byte. --- Modules/_io/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 280523bc2b..84d2ff35b0 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -256,7 +256,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) int rv = _PyUnicode_HasNULChars(nameobj); if (rv) { if (rv != -1) - PyErr_SetString(PyExc_TypeError, "embedded NUL character"); + PyErr_SetString(PyExc_ValueError, "embedded null character"); return -1; } widename = PyUnicode_AsUnicode(nameobj); -- cgit v1.2.1 From 6b9433d629dbe56f8d96896813fb158297b008e7 Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Sat, 18 Oct 2014 13:32:43 +1300 Subject: Issue #17401: document closefd in io.FileIO docs and add to repr closefd was documented in the open docs but not the matching FileIO class documented. Further, closefd, part of the core state for the object was not shown. In review it was noted that the open docs are a little confusing about the interaction between closefd and paths, so tweaked them at the same time. --- Modules/_io/fileio.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 2e0fbf9535..5c1316e9f4 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -1054,12 +1054,14 @@ fileio_repr(fileio *self) PyErr_Clear(); else return NULL; - res = PyUnicode_FromFormat("<_io.FileIO fd=%d mode='%s'>", - self->fd, mode_string(self)); + res = PyUnicode_FromFormat( + "<_io.FileIO fd=%d mode='%s' closefd='%d'>", + self->fd, mode_string(self), self->closefd); } else { - res = PyUnicode_FromFormat("<_io.FileIO name=%R mode='%s'>", - nameobj, mode_string(self)); + res = PyUnicode_FromFormat( + "<_io.FileIO name=%R mode='%s' closefd='%d'>", + nameobj, mode_string(self), self->closefd); Py_DECREF(nameobj); } return res; -- cgit v1.2.1 From 43abb9b2590a83b4804d2213c27827ab9654f4e8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 2 Dec 2014 23:39:56 +0200 Subject: Issue #17401: Output the closefd attribute as boolean. --- Modules/_io/fileio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 5c1316e9f4..80af83a7a4 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -1055,13 +1055,13 @@ fileio_repr(fileio *self) else return NULL; res = PyUnicode_FromFormat( - "<_io.FileIO fd=%d mode='%s' closefd='%d'>", - self->fd, mode_string(self), self->closefd); + "<_io.FileIO fd=%d mode='%s' closefd=%s>", + self->fd, mode_string(self), self->closefd ? "True" : "False"); } else { res = PyUnicode_FromFormat( - "<_io.FileIO name=%R mode='%s' closefd='%d'>", - nameobj, mode_string(self), self->closefd); + "<_io.FileIO name=%R mode='%s' closefd=%s>", + nameobj, mode_string(self), self->closefd ? "True" : "False"); Py_DECREF(nameobj); } return res; -- cgit v1.2.1 From 0b0d24a94f1f6d0e65e5f0e2ad63398fb82f54f2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 3 Feb 2015 11:30:10 +0200 Subject: Issue #15381: Optimized io.BytesIO to make less allocations and copyings. --- Modules/_io/bytesio.c | 338 +++++++++++++++++++++++--------------------------- 1 file changed, 152 insertions(+), 186 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 7bbcb6eb2a..ca5156b84b 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -4,17 +4,12 @@ typedef struct { PyObject_HEAD - char *buf; + PyObject *buf; Py_ssize_t pos; Py_ssize_t string_size; - size_t buf_size; PyObject *dict; PyObject *weakreflist; Py_ssize_t exports; - /** If `initvalue' != NULL, `buf' is a read-only pointer into the PyBytes - * referenced by `initvalue'. It must be copied prior to mutation, and - * released during finalization */ - PyObject *initvalue; } bytesio; typedef struct { @@ -22,12 +17,18 @@ typedef struct { bytesio *source; } bytesiobuf; +/* The bytesio object can be in three states: + * Py_REFCNT(buf) == 1, exports == 0. + * Py_REFCNT(buf) > 1. exports == 0, string_size == PyBytes_GET_SIZE(buf), + first modification or export causes the internal buffer copying. + * exports > 0. Py_REFCNT(buf) == 1, any modifications are forbidden. +*/ -#define CHECK_CLOSED(self, ret) \ +#define CHECK_CLOSED(self) \ if ((self)->buf == NULL) { \ PyErr_SetString(PyExc_ValueError, \ "I/O operation on closed file."); \ - return ret; \ + return NULL; \ } #define CHECK_EXPORTS(self) \ @@ -37,47 +38,8 @@ typedef struct { return NULL; \ } -/* Ensure we have a buffer suitable for writing, in the case that an initvalue - * object was provided, and we're currently borrowing its buffer. `size' - * indicates the new buffer size allocated as part of unsharing, to avoid a - * redundant reallocation caused by any subsequent mutation. `truncate' - * indicates whether truncation should occur if `size` < self->string_size. - * - * Do nothing if the buffer wasn't shared. Returns 0 on success, or sets an - * exception and returns -1 on failure. Existing state is preserved on failure. - */ -static int -unshare(bytesio *self, size_t preferred_size, int truncate) -{ - if (self->initvalue) { - Py_ssize_t copy_size; - char *new_buf; - - if((! truncate) && preferred_size < (size_t)self->string_size) { - preferred_size = self->string_size; - } - - /* PyMem_Malloc() returns NULL if preferred_size is bigger - than PY_SSIZE_T_MAX */ - new_buf = (char *)PyMem_Malloc(preferred_size); - if (new_buf == NULL) { - PyErr_NoMemory(); - return -1; - } +#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1) - copy_size = self->string_size; - if ((size_t)copy_size > preferred_size) { - copy_size = preferred_size; - } - - memcpy(new_buf, self->buf, copy_size); - Py_CLEAR(self->initvalue); - self->buf = new_buf; - self->buf_size = preferred_size; - self->string_size = (Py_ssize_t) copy_size; - } - return 0; -} /* Internal routine to get a line from the buffer of a BytesIO object. Returns the length between the current position to the @@ -91,7 +53,7 @@ scan_eol(bytesio *self, Py_ssize_t len) assert(self->buf != NULL); /* Move to the end of the line, up to the end of the string, s. */ - start = self->buf + self->pos; + start = PyBytes_AS_STRING(self->buf) + self->pos; maxlen = self->string_size - self->pos; if (len < 0 || len > maxlen) len = maxlen; @@ -109,6 +71,27 @@ scan_eol(bytesio *self, Py_ssize_t len) return len; } +/* Internal routine for detaching the shared buffer of BytesIO objects. + The caller should ensure that the 'size' argument is non-negative and + not lesser than self->string_size. Returns 0 on success, -1 otherwise. */ +static int +unshare_buffer(bytesio *self, size_t size) +{ + PyObject *new_buf, *old_buf; + assert(SHARED_BUF(self)); + assert(self->exports == 0); + assert(size >= (size_t)self->string_size); + new_buf = PyBytes_FromStringAndSize(NULL, size); + if (new_buf == NULL) + return -1; + memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf), + self->string_size); + old_buf = self->buf; + self->buf = new_buf; + Py_DECREF(old_buf); + return 0; +} + /* Internal routine for changing the size of the buffer of BytesIO objects. The caller should ensure that the 'size' argument is non-negative. Returns 0 on success, -1 otherwise. */ @@ -117,8 +100,7 @@ resize_buffer(bytesio *self, size_t size) { /* Here, unsigned types are used to avoid dealing with signed integer overflow, which is undefined in C. */ - size_t alloc = self->buf_size; - char *new_buf = NULL; + size_t alloc = PyBytes_GET_SIZE(self->buf); assert(self->buf != NULL); @@ -146,13 +128,15 @@ resize_buffer(bytesio *self, size_t size) if (alloc > ((size_t)-1) / sizeof(char)) goto overflow; - new_buf = (char *)PyMem_Realloc(self->buf, alloc * sizeof(char)); - if (new_buf == NULL) { - PyErr_NoMemory(); - return -1; + + if (SHARED_BUF(self)) { + if (unshare_buffer(self, alloc) < 0) + return -1; + } + else { + if (_PyBytes_Resize(&self->buf, alloc) < 0) + return -1; } - self->buf_size = alloc; - self->buf = new_buf; return 0; @@ -167,21 +151,18 @@ resize_buffer(bytesio *self, size_t size) static Py_ssize_t write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) { - size_t desired; - assert(self->buf != NULL); assert(self->pos >= 0); assert(len >= 0); - desired = (size_t)self->pos + len; - if (unshare(self, desired, 0) < 0) { - return -1; - } - - if (desired > self->buf_size) { + if ((size_t)self->pos + len > (size_t)PyBytes_GET_SIZE(self->buf)) { if (resize_buffer(self, (size_t)self->pos + len) < 0) return -1; } + else if (SHARED_BUF(self)) { + if (unshare_buffer(self, self->string_size) < 0) + return -1; + } if (self->pos > self->string_size) { /* In case of overseek, pad with null bytes the buffer region between @@ -192,13 +173,13 @@ write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) | | <--to pad-->|<---to write---> | 0 buf position */ - memset(self->buf + self->string_size, '\0', + memset(PyBytes_AS_STRING(self->buf) + self->string_size, '\0', (self->pos - self->string_size) * sizeof(char)); } /* Copy the data to the internal buffer, overwriting some of the existing data if self->pos < self->string_size. */ - memcpy(self->buf + self->pos, bytes, len); + memcpy(PyBytes_AS_STRING(self->buf) + self->pos, bytes, len); self->pos += len; /* Set the new length of the internal string if it has changed. */ @@ -209,74 +190,6 @@ write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) return len; } -/* Release or free any existing buffer, and place the BytesIO in the closed - * state. */ -static void -reset(bytesio *self) -{ - if (self->initvalue) { - Py_CLEAR(self->initvalue); - } else if (self->buf) { - PyMem_Free(self->buf); - } - self->buf = NULL; - self->string_size = 0; - self->pos = 0; -} - -/* Reinitialize with a new heap-allocated buffer of size `size`. Returns 0 on - * success, or sets an exception and returns -1 on failure. Existing state is - * preserved on failure. */ -static int -reinit_private(bytesio *self, Py_ssize_t size) -{ - char *tmp = (char *)PyMem_Malloc(size); - if (tmp == NULL) { - PyErr_NoMemory(); - return -1; - } - reset(self); - self->buf = tmp; - self->buf_size = size; - return 0; -} - -/* Internal version of BytesIO.__init__; resets the object to its initial - * (closed) state before repopulating it, optionally by sharing a PyBytes - * buffer provided by `initvalue'. Returns 0 on success, or sets an exception - * and returns -1 on failure. */ -static int -reinit(bytesio *self, PyObject *initvalue) -{ - CHECK_CLOSED(self, -1); - - if (initvalue == NULL || initvalue == Py_None) { - if (reinit_private(self, 0) < 0) { - return -1; - } - } else if (PyBytes_CheckExact(initvalue)) { - reset(self); - Py_INCREF(initvalue); - self->initvalue = initvalue; - self->buf = PyBytes_AS_STRING(initvalue); - self->buf_size = PyBytes_GET_SIZE(initvalue); - self->string_size = PyBytes_GET_SIZE(initvalue); - } else { - Py_buffer buf; - if (PyObject_GetBuffer(initvalue, &buf, PyBUF_CONTIG_RO) < 0) { - return -1; - } - if (reinit_private(self, buf.len) < 0) { - PyBuffer_Release(&buf); - return -1; - } - memcpy(self->buf, buf.buf, buf.len); - self->string_size = buf.len; - PyBuffer_Release(&buf); - } - return 0; -} - static PyObject * bytesio_get_closed(bytesio *self) { @@ -301,7 +214,7 @@ PyDoc_STRVAR(seekable_doc, static PyObject * return_not_closed(bytesio *self) { - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); Py_RETURN_TRUE; } @@ -311,7 +224,7 @@ PyDoc_STRVAR(flush_doc, static PyObject * bytesio_flush(bytesio *self) { - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); Py_RETURN_NONE; } @@ -327,7 +240,7 @@ bytesio_getbuffer(bytesio *self) bytesiobuf *buf; PyObject *view; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); buf = (bytesiobuf *) type->tp_alloc(type, 0); if (buf == NULL) @@ -347,8 +260,23 @@ PyDoc_STRVAR(getval_doc, static PyObject * bytesio_getvalue(bytesio *self) { - CHECK_CLOSED(self, NULL); - return PyBytes_FromStringAndSize(self->buf, self->string_size); + CHECK_CLOSED(self); + if (self->string_size <= 1 || self->exports > 0) + return PyBytes_FromStringAndSize(PyBytes_AS_STRING(self->buf), + self->string_size); + + if (self->string_size != PyBytes_GET_SIZE(self->buf)) { + if (SHARED_BUF(self)) { + if (unshare_buffer(self, self->string_size) < 0) + return NULL; + } + else { + if (_PyBytes_Resize(&self->buf, self->string_size) < 0) + return NULL; + } + } + Py_INCREF(self->buf); + return self->buf; } PyDoc_STRVAR(isatty_doc, @@ -360,7 +288,7 @@ PyDoc_STRVAR(isatty_doc, static PyObject * bytesio_isatty(bytesio *self) { - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); Py_RETURN_FALSE; } @@ -370,10 +298,29 @@ PyDoc_STRVAR(tell_doc, static PyObject * bytesio_tell(bytesio *self) { - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); return PyLong_FromSsize_t(self->pos); } +static PyObject * +read_bytes(bytesio *self, Py_ssize_t size) +{ + char *output; + + assert(self->buf != NULL); + if (size > 1 && + self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) && + self->exports == 0) { + self->pos += size; + Py_INCREF(self->buf); + return self->buf; + } + + output = PyBytes_AS_STRING(self->buf) + self->pos; + self->pos += size; + return PyBytes_FromStringAndSize(output, size); +} + PyDoc_STRVAR(read_doc, "read([size]) -> read at most size bytes, returned as a string.\n" "\n" @@ -384,10 +331,9 @@ static PyObject * bytesio_read(bytesio *self, PyObject *args) { Py_ssize_t size, n; - char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_ParseTuple(args, "|O:read", &arg)) return NULL; @@ -415,11 +361,7 @@ bytesio_read(bytesio *self, PyObject *args) size = 0; } - assert(self->buf != NULL); - output = self->buf + self->pos; - self->pos += size; - - return PyBytes_FromStringAndSize(output, size); + return read_bytes(self, size); } @@ -453,10 +395,9 @@ static PyObject * bytesio_readline(bytesio *self, PyObject *args) { Py_ssize_t size, n; - char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_ParseTuple(args, "|O:readline", &arg)) return NULL; @@ -478,9 +419,7 @@ bytesio_readline(bytesio *self, PyObject *args) n = scan_eol(self, size); - output = self->buf + self->pos; - self->pos += n; - return PyBytes_FromStringAndSize(output, n); + return read_bytes(self, n); } PyDoc_STRVAR(readlines_doc, @@ -498,7 +437,7 @@ bytesio_readlines(bytesio *self, PyObject *args) char *output; PyObject *arg = Py_None; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_ParseTuple(args, "|O:readlines", &arg)) return NULL; @@ -523,7 +462,7 @@ bytesio_readlines(bytesio *self, PyObject *args) if (!result) return NULL; - output = self->buf + self->pos; + output = PyBytes_AS_STRING(self->buf) + self->pos; while ((n = scan_eol(self, -1)) != 0) { self->pos += n; line = PyBytes_FromStringAndSize(output, n); @@ -558,7 +497,7 @@ bytesio_readinto(bytesio *self, PyObject *arg) Py_buffer buffer; Py_ssize_t len, n; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_Parse(arg, "w*", &buffer)) return NULL; @@ -572,7 +511,7 @@ bytesio_readinto(bytesio *self, PyObject *arg) len = 0; } - memcpy(buffer.buf, self->buf + self->pos, len); + memcpy(buffer.buf, PyBytes_AS_STRING(self->buf) + self->pos, len); assert(self->pos + len < PY_SSIZE_T_MAX); assert(len >= 0); self->pos += len; @@ -593,7 +532,7 @@ bytesio_truncate(bytesio *self, PyObject *args) Py_ssize_t size; PyObject *arg = Py_None; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); CHECK_EXPORTS(self); if (!PyArg_ParseTuple(args, "|O:truncate", &arg)) @@ -620,10 +559,6 @@ bytesio_truncate(bytesio *self, PyObject *args) return NULL; } - if (unshare(self, size, 1) < 0) { - return NULL; - } - if (size < self->string_size) { self->string_size = size; if (resize_buffer(self, size) < 0) @@ -636,19 +571,16 @@ bytesio_truncate(bytesio *self, PyObject *args) static PyObject * bytesio_iternext(bytesio *self) { - const char *next; Py_ssize_t n; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); n = scan_eol(self, -1); if (n == 0) return NULL; - next = self->buf + self->pos; - self->pos += n; - return PyBytes_FromStringAndSize(next, n); + return read_bytes(self, n); } PyDoc_STRVAR(seek_doc, @@ -666,7 +598,7 @@ bytesio_seek(bytesio *self, PyObject *args) Py_ssize_t pos; int mode = 0; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode)) return NULL; @@ -721,7 +653,7 @@ bytesio_write(bytesio *self, PyObject *obj) Py_buffer buf; PyObject *result = NULL; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); CHECK_EXPORTS(self); if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0) @@ -749,7 +681,7 @@ bytesio_writelines(bytesio *self, PyObject *v) PyObject *it, *item; PyObject *ret; - CHECK_CLOSED(self, NULL); + CHECK_CLOSED(self); it = PyObject_GetIter(v); if (it == NULL) @@ -780,7 +712,7 @@ static PyObject * bytesio_close(bytesio *self) { CHECK_EXPORTS(self); - reset(self); + Py_CLEAR(self->buf); Py_RETURN_NONE; } @@ -828,11 +760,11 @@ bytesio_getstate(bytesio *self) static PyObject * bytesio_setstate(bytesio *self, PyObject *state) { + PyObject *result; PyObject *position_obj; PyObject *dict; Py_ssize_t pos; - CHECK_EXPORTS(self); assert(state != NULL); /* We allow the state tuple to be longer than 3, because we may need @@ -844,13 +776,18 @@ bytesio_setstate(bytesio *self, PyObject *state) Py_TYPE(self)->tp_name, Py_TYPE(state)->tp_name); return NULL; } + CHECK_EXPORTS(self); + /* Reset the object to its default state. This is only needed to handle + the case of repeated calls to __setstate__. */ + self->string_size = 0; + self->pos = 0; - /* Reset the object to its default state and set the value of the internal - * buffer. If state[0] does not support the buffer protocol, reinit() will - * raise the appropriate TypeError. */ - if (reinit(self, PyTuple_GET_ITEM(state, 0)) < 0) { + /* Set the value of the internal buffer. If state[0] does not support the + buffer protocol, bytesio_write will raise the appropriate TypeError. */ + result = bytesio_write(self, PyTuple_GET_ITEM(state, 0)); + if (result == NULL) return NULL; - } + Py_DECREF(result); /* Set carefully the position value. Alternatively, we could use the seek method instead of modifying self->pos directly to better protect the @@ -905,9 +842,7 @@ bytesio_dealloc(bytesio *self) "deallocated BytesIO object has exported buffers"); PyErr_Print(); } - - reset(self); - + Py_CLEAR(self->buf); Py_CLEAR(self->dict); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -927,7 +862,7 @@ bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) /* tp_alloc initializes all the fields to zero. So we don't have to initialize them here. */ - self->buf = (char *)PyMem_Malloc(0); + self->buf = PyBytes_FromStringAndSize(NULL, 0); if (self->buf == NULL) { Py_DECREF(self); return PyErr_NoMemory(); @@ -946,7 +881,33 @@ bytesio_init(bytesio *self, PyObject *args, PyObject *kwds) &initvalue)) return -1; - return reinit(self, initvalue); + /* In case, __init__ is called multiple times. */ + self->string_size = 0; + self->pos = 0; + + if (self->exports > 0) { + PyErr_SetString(PyExc_BufferError, + "Existing exports of data: object cannot be re-sized"); + return -1; + } + if (initvalue && initvalue != Py_None) { + if (PyBytes_CheckExact(initvalue)) { + Py_INCREF(initvalue); + Py_XDECREF(self->buf); + self->buf = initvalue; + self->string_size = PyBytes_GET_SIZE(initvalue); + } + else { + PyObject *res; + res = bytesio_write(self, initvalue); + if (res == NULL) + return -1; + Py_DECREF(res); + self->pos = 0; + } + } + + return 0; } static PyObject * @@ -955,8 +916,8 @@ bytesio_sizeof(bytesio *self, void *unused) Py_ssize_t res; res = sizeof(bytesio); - if (self->buf) - res += self->buf_size; + if (self->buf && !SHARED_BUF(self)) + res += _PySys_GetSizeOf(self->buf); return PyLong_FromSsize_t(res); } @@ -1066,11 +1027,16 @@ bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags) { int ret; bytesio *b = (bytesio *) obj->source; + if (SHARED_BUF(b)) { + if (unshare_buffer(b, b->string_size) < 0) + return -1; + } if (view == NULL) { b->exports++; return 0; } - ret = PyBuffer_FillInfo(view, (PyObject*)obj, b->buf, b->string_size, + ret = PyBuffer_FillInfo(view, (PyObject*)obj, + PyBytes_AS_STRING(b->buf), b->string_size, 0, flags); if (ret >= 0) { b->exports++; -- cgit v1.2.1 From 8506dd20ea12862ef165f610554d7cae6eed0a95 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 3 Feb 2015 14:57:49 +0200 Subject: Issue #15381: Try to fix refcount bug. Empty and 1-byte buffers are always shared. --- Modules/_io/bytesio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index ca5156b84b..1638f943d0 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -38,7 +38,8 @@ typedef struct { return NULL; \ } -#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1) +#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1 || \ + PyBytes_GET_SIZE((self)->buf) <= 1) /* Internal routine to get a line from the buffer of a BytesIO @@ -308,6 +309,7 @@ read_bytes(bytesio *self, Py_ssize_t size) char *output; assert(self->buf != NULL); + assert(size <= self->string_size); if (size > 1 && self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) && self->exports == 0) { -- cgit v1.2.1 From 2cc2f792a75edb7f0eec1e9c6de6dffb6dc8de3c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 3 Feb 2015 18:51:58 +0200 Subject: Issue #15381: Fixed a bug in BytesIO.write(). It was expected that string_size == PyBytes_GET_SIZE(buf) if the buffer is shared, but truncate() and __setstate__() can set string_size without unsharing the buffer. --- Modules/_io/bytesio.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 1638f943d0..0a272ecc7a 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -19,7 +19,7 @@ typedef struct { /* The bytesio object can be in three states: * Py_REFCNT(buf) == 1, exports == 0. - * Py_REFCNT(buf) > 1. exports == 0, string_size == PyBytes_GET_SIZE(buf), + * Py_REFCNT(buf) > 1. exports == 0, first modification or export causes the internal buffer copying. * exports > 0. Py_REFCNT(buf) == 1, any modifications are forbidden. */ @@ -38,8 +38,7 @@ typedef struct { return NULL; \ } -#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1 || \ - PyBytes_GET_SIZE((self)->buf) <= 1) +#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1) /* Internal routine to get a line from the buffer of a BytesIO @@ -152,16 +151,18 @@ resize_buffer(bytesio *self, size_t size) static Py_ssize_t write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) { + size_t endpos; assert(self->buf != NULL); assert(self->pos >= 0); assert(len >= 0); - if ((size_t)self->pos + len > (size_t)PyBytes_GET_SIZE(self->buf)) { - if (resize_buffer(self, (size_t)self->pos + len) < 0) + endpos = (size_t)self->pos + len; + if (endpos > (size_t)PyBytes_GET_SIZE(self->buf)) { + if (resize_buffer(self, endpos) < 0) return -1; } else if (SHARED_BUF(self)) { - if (unshare_buffer(self, self->string_size) < 0) + if (unshare_buffer(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) return -1; } @@ -181,11 +182,11 @@ write_bytes(bytesio *self, const char *bytes, Py_ssize_t len) /* Copy the data to the internal buffer, overwriting some of the existing data if self->pos < self->string_size. */ memcpy(PyBytes_AS_STRING(self->buf) + self->pos, bytes, len); - self->pos += len; + self->pos = endpos; /* Set the new length of the internal string if it has changed. */ - if (self->string_size < self->pos) { - self->string_size = self->pos; + if ((size_t)self->string_size < endpos) { + self->string_size = endpos; } return len; -- cgit v1.2.1 From cd7ad1a7a0c6de5a46c47bfdd03ff3aad0dc3200 Mon Sep 17 00:00:00 2001 From: Stefan Krah Date: Tue, 3 Feb 2015 21:43:23 +0100 Subject: Issue #14203: Remove obsolete support for view==NULL in bytesiobuf_getbuffer() and array_buffer_getbuf(). --- Modules/_io/bytesio.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 0a272ecc7a..fc4ea74b23 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -1028,23 +1028,24 @@ PyTypeObject PyBytesIO_Type = { static int bytesiobuf_getbuffer(bytesiobuf *obj, Py_buffer *view, int flags) { - int ret; bytesio *b = (bytesio *) obj->source; + + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, + "bytesiobuf_getbuffer: view==NULL argument is obsolete"); + return -1; + } if (SHARED_BUF(b)) { if (unshare_buffer(b, b->string_size) < 0) return -1; } - if (view == NULL) { - b->exports++; - return 0; - } - ret = PyBuffer_FillInfo(view, (PyObject*)obj, + + /* cannot fail if view != NULL and readonly == 0 */ + (void)PyBuffer_FillInfo(view, (PyObject*)obj, PyBytes_AS_STRING(b->buf), b->string_size, 0, flags); - if (ret >= 0) { - b->exports++; - } - return ret; + b->exports++; + return 0; } static void -- cgit v1.2.1 From 166a57a01b10a5398290e02aa4ad6142cf9dc41e Mon Sep 17 00:00:00 2001 From: Charles-Fran?ois Natali Date: Sat, 7 Feb 2015 13:27:50 +0000 Subject: Issue #23285: PEP 475 -- Retry system calls failing with EINTR. --- Modules/_io/fileio.c | 125 ++++++++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 55 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 80af83a7a4..2435513400 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -218,6 +218,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) #ifdef HAVE_FSTAT struct stat fdfstat; #endif + int async_err = 0; assert(PyFileIO_Check(oself)); if (self->fd >= 0) { @@ -360,15 +361,18 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) errno = 0; if (opener == Py_None) { - Py_BEGIN_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS - if (widename != NULL) - self->fd = _wopen(widename, flags, 0666); - else + if (widename != NULL) + self->fd = _wopen(widename, flags, 0666); + else #endif - self->fd = open(name, flags, 0666); + self->fd = open(name, flags, 0666); - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (self->fd < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); } else { PyObject *fdobj; @@ -397,7 +401,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) fd_is_own = 1; if (self->fd < 0) { - PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); + if (!async_err) + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); goto error; } @@ -550,7 +555,7 @@ fileio_readinto(fileio *self, PyObject *args) { Py_buffer pbuf; Py_ssize_t n, len; - int err; + int err, async_err = 0; if (self->fd < 0) return err_closed(); @@ -562,16 +567,19 @@ fileio_readinto(fileio *self, PyObject *args) if (_PyVerify_fd(self->fd)) { len = pbuf.len; - Py_BEGIN_ALLOW_THREADS - errno = 0; + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - n = read(self->fd, pbuf.buf, (int)len); + if (len > INT_MAX) + len = INT_MAX; + n = read(self->fd, pbuf.buf, (int)len); #else - n = read(self->fd, pbuf.buf, len); + n = read(self->fd, pbuf.buf, len); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); } else n = -1; err = errno; @@ -580,7 +588,8 @@ fileio_readinto(fileio *self, PyObject *args) if (err == EAGAIN) Py_RETURN_NONE; errno = err; - PyErr_SetFromErrno(PyExc_IOError); + if (!async_err) + PyErr_SetFromErrno(PyExc_IOError); return NULL; } @@ -627,6 +636,7 @@ fileio_readall(fileio *self) Py_ssize_t bytes_read = 0; Py_ssize_t n; size_t bufsize; + int async_err = 0; if (self->fd < 0) return err_closed(); @@ -673,27 +683,23 @@ fileio_readall(fileio *self) return NULL; } } - Py_BEGIN_ALLOW_THREADS - errno = 0; - n = bufsize - bytes_read; + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; + n = bufsize - bytes_read; #ifdef MS_WINDOWS - if (n > INT_MAX) - n = INT_MAX; - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n); + if (n > INT_MAX) + n = INT_MAX; + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n); #else - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n); + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); if (n == 0) break; if (n < 0) { - if (errno == EINTR) { - if (PyErr_CheckSignals()) { - Py_DECREF(result); - return NULL; - } - continue; - } if (errno == EAGAIN) { if (bytes_read > 0) break; @@ -701,7 +707,8 @@ fileio_readall(fileio *self) Py_RETURN_NONE; } Py_DECREF(result); - PyErr_SetFromErrno(PyExc_IOError); + if (!async_err) + PyErr_SetFromErrno(PyExc_IOError); return NULL; } bytes_read += n; @@ -723,6 +730,7 @@ fileio_read(fileio *self, PyObject *args) char *ptr; Py_ssize_t n; Py_ssize_t size = -1; + int async_err = 0; PyObject *bytes; if (self->fd < 0) @@ -747,14 +755,17 @@ fileio_read(fileio *self, PyObject *args) ptr = PyBytes_AS_STRING(bytes); if (_PyVerify_fd(self->fd)) { - Py_BEGIN_ALLOW_THREADS - errno = 0; + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; #ifdef MS_WINDOWS - n = read(self->fd, ptr, (int)size); + n = read(self->fd, ptr, (int)size); #else - n = read(self->fd, ptr, size); + n = read(self->fd, ptr, size); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); } else n = -1; @@ -764,7 +775,8 @@ fileio_read(fileio *self, PyObject *args) if (err == EAGAIN) Py_RETURN_NONE; errno = err; - PyErr_SetFromErrno(PyExc_IOError); + if (!async_err) + PyErr_SetFromErrno(PyExc_IOError); return NULL; } @@ -783,7 +795,7 @@ fileio_write(fileio *self, PyObject *args) { Py_buffer pbuf; Py_ssize_t n, len; - int err; + int err, async_err = 0; if (self->fd < 0) return err_closed(); @@ -794,24 +806,26 @@ fileio_write(fileio *self, PyObject *args) return NULL; if (_PyVerify_fd(self->fd)) { - Py_BEGIN_ALLOW_THREADS - errno = 0; - len = pbuf.len; + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; + len = pbuf.len; #ifdef MS_WINDOWS - if (len > 32767 && isatty(self->fd)) { - /* Issue #11395: the Windows console returns an error (12: not - enough space error) on writing into stdout if stdout mode is - binary and the length is greater than 66,000 bytes (or less, - depending on heap usage). */ - len = 32767; - } - else if (len > INT_MAX) - len = INT_MAX; - n = write(self->fd, pbuf.buf, (int)len); + if (len > 32767 && isatty(self->fd)) { + /* Issue #11395: the Windows console returns an error (12: not + enough space error) on writing into stdout if stdout mode is + binary and the length is greater than 66,000 bytes (or less, + depending on heap usage). */ + len = 32767; + } else if (len > INT_MAX) + len = INT_MAX; + n = write(self->fd, pbuf.buf, (int)len); #else - n = write(self->fd, pbuf.buf, len); + n = write(self->fd, pbuf.buf, len); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); } else n = -1; err = errno; @@ -822,7 +836,8 @@ fileio_write(fileio *self, PyObject *args) if (err == EAGAIN) Py_RETURN_NONE; errno = err; - PyErr_SetFromErrno(PyExc_IOError); + if (!async_err) + PyErr_SetFromErrno(PyExc_IOError); return NULL; } -- cgit v1.2.1 From b0a85d474df68ed8e72a01506fa74ceca3587aef Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 17 Feb 2015 10:14:30 +0200 Subject: Issue #22883: Got rid of outdated references to PyInt and PyString in comments. --- Modules/_io/_iomodule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 8927864e8c..9d5205ec30 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -69,7 +69,7 @@ extern int _PyIO_trap_eintr(void); * Offset type for positioning. */ -/* Printing a variable of type off_t (with e.g., PyString_FromFormat) +/* Printing a variable of type off_t (with e.g., PyUnicode_FromFormat) correctly and without producing compiler warnings is surprisingly painful. We identify an integer type whose size matches off_t and then: (1) cast the off_t to that integer type and (2) use the appropriate conversion -- cgit v1.2.1 From 4b5c8edd294f02afef7407d9fd5236789bd4bc34 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 21 Feb 2015 08:44:05 -0800 Subject: Issue #23152: Implement _Py_fstat() to support files larger than 2 GB on Windows. fstat() may fail with EOVERFLOW on files larger than 2 GB because the file size type is an signed 32-bit integer. --- Modules/_io/fileio.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 9c67394cbe..ff88e40973 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -180,9 +180,9 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static int check_fd(int fd) { -#if defined(HAVE_FSTAT) - struct stat buf; - if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) { +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) + struct _Py_stat_struct buf; + if (!_PyVerify_fd(fd) || (_Py_fstat(fd, &buf) < 0 && errno == EBADF)) { PyObject *exc; char *msg = strerror(EBADF); exc = PyObject_CallFunction(PyExc_OSError, "(is)", @@ -222,8 +222,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) #elif !defined(MS_WINDOWS) int *atomic_flag_works = NULL; #endif -#ifdef HAVE_FSTAT - struct stat fdfstat; +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) + struct _Py_stat_struct fdfstat; #endif int async_err = 0; @@ -420,9 +420,11 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) } self->blksize = DEFAULT_BUFFER_SIZE; -#ifdef HAVE_FSTAT - if (fstat(self->fd, &fdfstat) < 0) +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) + if (_Py_fstat(self->fd, &fdfstat) < 0) { + PyErr_SetFromErrno(PyExc_OSError); goto error; + } #if defined(S_ISDIR) && defined(EISDIR) /* On Unix, open will succeed for directories. In Python, there should be no file objects referring to @@ -437,7 +439,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) if (fdfstat.st_blksize > 1) self->blksize = fdfstat.st_blksize; #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ -#endif /* HAVE_FSTAT */ +#endif /* HAVE_FSTAT || MS_WINDOWS */ #if defined(MS_WINDOWS) || defined(__CYGWIN__) /* don't translate newlines (\r\n <=> \n) */ @@ -603,17 +605,7 @@ fileio_readinto(fileio *self, PyObject *args) return PyLong_FromSsize_t(n); } -#ifndef HAVE_FSTAT - -static PyObject * -fileio_readall(fileio *self) -{ - _Py_IDENTIFIER(readall); - return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, - &PyId_readall, "O", self); -} - -#else +#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) static size_t new_buffersize(fileio *self, size_t currentsize) @@ -637,7 +629,7 @@ new_buffersize(fileio *self, size_t currentsize) static PyObject * fileio_readall(fileio *self) { - struct stat st; + struct _Py_stat_struct st; Py_off_t pos, end; PyObject *result; Py_ssize_t bytes_read = 0; @@ -655,7 +647,7 @@ fileio_readall(fileio *self) #else pos = lseek(self->fd, 0L, SEEK_CUR); #endif - if (fstat(self->fd, &st) == 0) + if (_Py_fstat(self->fd, &st) == 0) end = st.st_size; else end = (Py_off_t)-1; @@ -729,7 +721,17 @@ fileio_readall(fileio *self) return result; } -#endif /* HAVE_FSTAT */ +#else + +static PyObject * +fileio_readall(fileio *self) +{ + _Py_IDENTIFIER(readall); + return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_readall, "O", self); +} + +#endif /* HAVE_FSTAT || MS_WINDOWS */ static PyObject * fileio_read(fileio *self, PyObject *args) -- cgit v1.2.1 From 3c1a62e64f25ffeb99fc7a6f46480c6299956e78 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Mar 2015 18:40:10 +0100 Subject: Issue #23285: Fix handling of EINTR in fileio.c Fix handling of EINTR: don't return None if PyErr_CheckSignals() raised an exception. Initialize also the length outside the loop to only initialize it once. --- Modules/_io/fileio.c | 74 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 28 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index ff88e40973..c44423180c 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -376,10 +376,12 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) else #endif self->fd = open(name, flags, 0666); - Py_END_ALLOW_THREADS } while (self->fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (async_err) + goto error; } else { PyObject *fdobj; @@ -408,8 +410,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) fd_is_own = 1; if (self->fd < 0) { - if (!async_err) - PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj); goto error; } @@ -576,12 +577,15 @@ fileio_readinto(fileio *self, PyObject *args) if (_PyVerify_fd(self->fd)) { len = pbuf.len; +#ifdef MS_WINDOWS + if (len > INT_MAX) + len = INT_MAX; +#endif + do { Py_BEGIN_ALLOW_THREADS errno = 0; #ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; n = read(self->fd, pbuf.buf, (int)len); #else n = read(self->fd, pbuf.buf, len); @@ -589,6 +593,9 @@ fileio_readinto(fileio *self, PyObject *args) Py_END_ALLOW_THREADS } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (async_err) + return NULL; } else n = -1; err = errno; @@ -597,8 +604,7 @@ fileio_readinto(fileio *self, PyObject *args) if (err == EAGAIN) Py_RETURN_NONE; errno = err; - if (!async_err) - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_IOError); return NULL; } @@ -633,7 +639,7 @@ fileio_readall(fileio *self) Py_off_t pos, end; PyObject *result; Py_ssize_t bytes_read = 0; - Py_ssize_t n; + Py_ssize_t len, n; size_t bufsize; int async_err = 0; @@ -682,20 +688,26 @@ fileio_readall(fileio *self) return NULL; } } + + len = bufsize - bytes_read; +#ifdef MS_WINDOWS + if (len > INT_MAX) + len = INT_MAX; +#endif do { Py_BEGIN_ALLOW_THREADS errno = 0; - n = bufsize - bytes_read; #ifdef MS_WINDOWS - if (n > INT_MAX) - n = INT_MAX; - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n); + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)len); #else - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n); + n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, len); #endif Py_END_ALLOW_THREADS } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (async_err) + return NULL; if (n == 0) break; if (n < 0) { @@ -706,8 +718,7 @@ fileio_readall(fileio *self) Py_RETURN_NONE; } Py_DECREF(result); - if (!async_err) - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_IOError); return NULL; } bytes_read += n; @@ -775,6 +786,9 @@ fileio_read(fileio *self, PyObject *args) Py_END_ALLOW_THREADS } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (async_err) + return NULL; } else n = -1; @@ -784,8 +798,7 @@ fileio_read(fileio *self, PyObject *args) if (err == EAGAIN) Py_RETURN_NONE; errno = err; - if (!async_err) - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_IOError); return NULL; } @@ -815,19 +828,22 @@ fileio_write(fileio *self, PyObject *args) return NULL; if (_PyVerify_fd(self->fd)) { + len = pbuf.len; +#ifdef MS_WINDOWS + if (len > 32767 && isatty(self->fd)) { + /* Issue #11395: the Windows console returns an error (12: not + enough space error) on writing into stdout if stdout mode is + binary and the length is greater than 66,000 bytes (or less, + depending on heap usage). */ + len = 32767; + } else if (len > INT_MAX) + len = INT_MAX; +#endif + do { Py_BEGIN_ALLOW_THREADS errno = 0; - len = pbuf.len; #ifdef MS_WINDOWS - if (len > 32767 && isatty(self->fd)) { - /* Issue #11395: the Windows console returns an error (12: not - enough space error) on writing into stdout if stdout mode is - binary and the length is greater than 66,000 bytes (or less, - depending on heap usage). */ - len = 32767; - } else if (len > INT_MAX) - len = INT_MAX; n = write(self->fd, pbuf.buf, (int)len); #else n = write(self->fd, pbuf.buf, len); @@ -835,6 +851,9 @@ fileio_write(fileio *self, PyObject *args) Py_END_ALLOW_THREADS } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (async_err) + return NULL; } else n = -1; err = errno; @@ -845,8 +864,7 @@ fileio_write(fileio *self, PyObject *args) if (err == EAGAIN) Py_RETURN_NONE; errno = err; - if (!async_err) - PyErr_SetFromErrno(PyExc_IOError); + PyErr_SetFromErrno(PyExc_IOError); return NULL; } -- cgit v1.2.1 From 6139bc8c6c02db0e084b495d1fe5ac9707635ecb Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 6 Mar 2015 14:47:02 -0800 Subject: Issue #23524: Replace _PyVerify_fd function with calling _set_thread_local_invalid_parameter_handler on every thread. --- Modules/_io/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index c44423180c..ab9eb8c061 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -182,7 +182,7 @@ check_fd(int fd) { #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) struct _Py_stat_struct buf; - if (!_PyVerify_fd(fd) || (_Py_fstat(fd, &buf) < 0 && errno == EBADF)) { + if (_Py_fstat(fd, &buf) < 0 && errno == EBADF) { PyObject *exc; char *msg = strerror(EBADF); exc = PyObject_CallFunction(PyExc_OSError, "(is)", -- cgit v1.2.1 From ef35d11c6986437b4eac74a6657377607c34841a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 6 Mar 2015 23:35:27 +0100 Subject: Issue #23571: PyObject_Call(), PyCFunction_Call() and call_function() now raise a SystemError if a function returns a result and raises an exception. The SystemError is chained to the previous exception. Refactor also PyObject_Call() and PyCFunction_Call() to make them more readable. Remove some checks which became useless (duplicate checks). Change reviewed by Serhiy Storchaka. --- Modules/_io/bufferedio.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 692ce41cf9..370bb5ec45 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -680,11 +680,7 @@ static void _set_BlockingIOError(char *msg, Py_ssize_t written) { PyObject *err; -#ifdef Py_DEBUG - /* in debug mode, PyEval_EvalFrameEx() fails with an assertion error - if an exception is set when it is called */ PyErr_Clear(); -#endif err = PyObject_CallFunction(PyExc_BlockingIOError, "isn", errno, msg, written); if (err) -- cgit v1.2.1 From 2d72ea4b9806468c66ac0562db71d5b4faeaea58 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 7 Mar 2015 18:14:07 -0800 Subject: Issue #23524: Change back to using Windows errors for _Py_fstat instead of the errno shim. --- Modules/_io/fileio.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index ab9eb8c061..0f226eafbf 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -182,7 +182,13 @@ check_fd(int fd) { #if defined(HAVE_FSTAT) || defined(MS_WINDOWS) struct _Py_stat_struct buf; - if (_Py_fstat(fd, &buf) < 0 && errno == EBADF) { + if (_Py_fstat(fd, &buf) < 0 && +#ifdef MS_WINDOWS + GetLastError() == ERROR_INVALID_HANDLE +#else + errno == EBADF +#endif + ) { PyObject *exc; char *msg = strerror(EBADF); exc = PyObject_CallFunction(PyExc_OSError, "(is)", -- cgit v1.2.1 From ab401006bd13992bf70ebf394f974c20001c2f4f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 18 Mar 2015 21:53:15 +0200 Subject: Removed unintentional trailing spaces in non-external and non-generated C files. --- Modules/_io/bufferedio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 370bb5ec45..358a94dce2 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1055,7 +1055,7 @@ _buffered_readinto_generic(buffered *self, PyObject *args, char readinto1) } else n = 0; - + if (n == 0 || (n == -2 && written > 0)) break; if (n < 0) { @@ -1065,7 +1065,7 @@ _buffered_readinto_generic(buffered *self, PyObject *args, char readinto1) } goto end; } - + /* At most one read in readinto1 mode */ if (readinto1) { written += n; -- cgit v1.2.1 From 00471d560c71a73624b8983caf1707ed1610e84d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 19 Mar 2015 22:53:20 +0100 Subject: Issue #23708: Add _Py_read() and _Py_write() functions to factorize code handle EINTR error and special cases for Windows. These functions now truncate the length to PY_SSIZE_T_MAX to have a portable and reliable behaviour. For example, read() result is undefined if counter is greater than PY_SSIZE_T_MAX on Linux. --- Modules/_io/fileio.c | 142 +++++++++++---------------------------------------- 1 file changed, 31 insertions(+), 111 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 0f226eafbf..6152cde464 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -570,8 +570,8 @@ static PyObject * fileio_readinto(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n, len; - int err, async_err = 0; + Py_ssize_t n; + int err; if (self->fd < 0) return err_closed(); @@ -581,36 +581,16 @@ fileio_readinto(fileio *self, PyObject *args) if (!PyArg_ParseTuple(args, "w*", &pbuf)) return NULL; - if (_PyVerify_fd(self->fd)) { - len = pbuf.len; -#ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; -#endif - - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - n = read(self->fd, pbuf.buf, (int)len); -#else - n = read(self->fd, pbuf.buf, len); -#endif - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); - - if (async_err) - return NULL; - } else - n = -1; + n = _Py_read(self->fd, pbuf.buf, pbuf.len); + /* copy errno because PyBuffer_Release() can indirectly modify it */ err = errno; PyBuffer_Release(&pbuf); - if (n < 0) { - if (err == EAGAIN) + + if (n == -1) { + if (err == EAGAIN) { + PyErr_Clear(); Py_RETURN_NONE; - errno = err; - PyErr_SetFromErrno(PyExc_IOError); + } return NULL; } @@ -645,9 +625,8 @@ fileio_readall(fileio *self) Py_off_t pos, end; PyObject *result; Py_ssize_t bytes_read = 0; - Py_ssize_t len, n; + Py_ssize_t n; size_t bufsize; - int async_err = 0; if (self->fd < 0) return err_closed(); @@ -695,36 +674,21 @@ fileio_readall(fileio *self) } } - len = bufsize - bytes_read; -#ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; -#endif - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)len); -#else - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, len); -#endif - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); + n = _Py_read(self->fd, + PyBytes_AS_STRING(result) + bytes_read, + bufsize - bytes_read); - if (async_err) - return NULL; if (n == 0) break; - if (n < 0) { + if (n == -1) { if (errno == EAGAIN) { + PyErr_Clear(); if (bytes_read > 0) break; Py_DECREF(result); Py_RETURN_NONE; } Py_DECREF(result); - PyErr_SetFromErrno(PyExc_IOError); return NULL; } bytes_read += n; @@ -756,7 +720,6 @@ fileio_read(fileio *self, PyObject *args) char *ptr; Py_ssize_t n; Py_ssize_t size = -1; - int async_err = 0; PyObject *bytes; if (self->fd < 0) @@ -767,44 +730,29 @@ fileio_read(fileio *self, PyObject *args) if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size)) return NULL; - if (size < 0) { + if (size < 0) return fileio_readall(self); - } #ifdef MS_WINDOWS + /* On Windows, the count parameter of read() is an int */ if (size > INT_MAX) size = INT_MAX; #endif + bytes = PyBytes_FromStringAndSize(NULL, size); if (bytes == NULL) return NULL; ptr = PyBytes_AS_STRING(bytes); - if (_PyVerify_fd(self->fd)) { - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - n = read(self->fd, ptr, (int)size); -#else - n = read(self->fd, ptr, size); -#endif - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); - - if (async_err) - return NULL; - } else - n = -1; - - if (n < 0) { + n = _Py_read(self->fd, ptr, size); + if (n == -1) { + /* copy errno because Py_DECREF() can indirectly modify it */ int err = errno; Py_DECREF(bytes); - if (err == EAGAIN) + if (err == EAGAIN) { + PyErr_Clear(); Py_RETURN_NONE; - errno = err; - PyErr_SetFromErrno(PyExc_IOError); + } return NULL; } @@ -822,8 +770,8 @@ static PyObject * fileio_write(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n, len; - int err, async_err = 0; + Py_ssize_t n; + int err; if (self->fd < 0) return err_closed(); @@ -833,44 +781,16 @@ fileio_write(fileio *self, PyObject *args) if (!PyArg_ParseTuple(args, "y*", &pbuf)) return NULL; - if (_PyVerify_fd(self->fd)) { - len = pbuf.len; -#ifdef MS_WINDOWS - if (len > 32767 && isatty(self->fd)) { - /* Issue #11395: the Windows console returns an error (12: not - enough space error) on writing into stdout if stdout mode is - binary and the length is greater than 66,000 bytes (or less, - depending on heap usage). */ - len = 32767; - } else if (len > INT_MAX) - len = INT_MAX; -#endif - - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - n = write(self->fd, pbuf.buf, (int)len); -#else - n = write(self->fd, pbuf.buf, len); -#endif - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); - - if (async_err) - return NULL; - } else - n = -1; + n = _Py_write(self->fd, pbuf.buf, pbuf.len); + /* copy errno because PyBuffer_Release() can indirectly modify it */ err = errno; - PyBuffer_Release(&pbuf); if (n < 0) { - if (err == EAGAIN) + if (err == EAGAIN) { + PyErr_Clear(); Py_RETURN_NONE; - errno = err; - PyErr_SetFromErrno(PyExc_IOError); + } return NULL; } -- cgit v1.2.1 From eaf93d5dbe0a159d1d0908fab4f627934abbe6b1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 24 Mar 2015 10:27:50 +0100 Subject: Issue #23753: Python doesn't support anymore platforms without stat() or fstat(), these functions are always required. Remove HAVE_STAT and HAVE_FSTAT defines, and stop supporting DONT_HAVE_STAT and DONT_HAVE_FSTAT. --- Modules/_io/fileio.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 6152cde464..b35a51b4e1 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -180,7 +180,6 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static int check_fd(int fd) { -#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) struct _Py_stat_struct buf; if (_Py_fstat(fd, &buf) < 0 && #ifdef MS_WINDOWS @@ -197,7 +196,6 @@ check_fd(int fd) Py_XDECREF(exc); return -1; } -#endif return 0; } @@ -228,9 +226,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) #elif !defined(MS_WINDOWS) int *atomic_flag_works = NULL; #endif -#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) struct _Py_stat_struct fdfstat; -#endif int async_err = 0; assert(PyFileIO_Check(oself)); @@ -427,7 +423,6 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) } self->blksize = DEFAULT_BUFFER_SIZE; -#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) if (_Py_fstat(self->fd, &fdfstat) < 0) { PyErr_SetFromErrno(PyExc_OSError); goto error; @@ -446,7 +441,6 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) if (fdfstat.st_blksize > 1) self->blksize = fdfstat.st_blksize; #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ -#endif /* HAVE_FSTAT || MS_WINDOWS */ #if defined(MS_WINDOWS) || defined(__CYGWIN__) /* don't translate newlines (\r\n <=> \n) */ @@ -597,8 +591,6 @@ fileio_readinto(fileio *self, PyObject *args) return PyLong_FromSsize_t(n); } -#if defined(HAVE_FSTAT) || defined(MS_WINDOWS) - static size_t new_buffersize(fileio *self, size_t currentsize) { @@ -702,18 +694,6 @@ fileio_readall(fileio *self) return result; } -#else - -static PyObject * -fileio_readall(fileio *self) -{ - _Py_IDENTIFIER(readall); - return _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, - &PyId_readall, "O", self); -} - -#endif /* HAVE_FSTAT || MS_WINDOWS */ - static PyObject * fileio_read(fileio *self, PyObject *args) { -- cgit v1.2.1 From 87f62f6ed268dea48663d7e806f34ff958bea7b5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 30 Mar 2015 03:21:06 +0200 Subject: Issue #23752: When built from an existing file descriptor, io.FileIO() now only calls fstat() once. Before fstat() was called twice, which was not necessary. --- Modules/_io/fileio.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index b35a51b4e1..595f99ee85 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -177,28 +177,6 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *) self; } -static int -check_fd(int fd) -{ - struct _Py_stat_struct buf; - if (_Py_fstat(fd, &buf) < 0 && -#ifdef MS_WINDOWS - GetLastError() == ERROR_INVALID_HANDLE -#else - errno == EBADF -#endif - ) { - PyObject *exc; - char *msg = strerror(EBADF); - exc = PyObject_CallFunction(PyExc_OSError, "(is)", - EBADF, msg); - PyErr_SetObject(PyExc_OSError, exc); - Py_XDECREF(exc); - return -1; - } - return 0; -} - #ifdef O_CLOEXEC extern int _Py_open_cloexec_works; #endif @@ -355,8 +333,6 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) #endif if (fd >= 0) { - if (check_fd(fd)) - goto error; self->fd = fd; self->closefd = closefd; } -- cgit v1.2.1 From 0600ebc4d9a0fbb0f16689fb2c1d6a09482594cc Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 30 Mar 2015 10:09:31 +0200 Subject: Issue #23752: _Py_fstat() is now responsible to raise the Python exception Add _Py_fstat_noraise() function when a Python exception is not welcome. --- Modules/_io/fileio.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 595f99ee85..b56a9c3f43 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -399,10 +399,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) } self->blksize = DEFAULT_BUFFER_SIZE; - if (_Py_fstat(self->fd, &fdfstat) < 0) { - PyErr_SetFromErrno(PyExc_OSError); + if (_Py_fstat(self->fd, &fdfstat) < 0) goto error; - } #if defined(S_ISDIR) && defined(EISDIR) /* On Unix, open will succeed for directories. In Python, there should be no file objects referring to @@ -589,7 +587,7 @@ new_buffersize(fileio *self, size_t currentsize) static PyObject * fileio_readall(fileio *self) { - struct _Py_stat_struct st; + struct _Py_stat_struct status; Py_off_t pos, end; PyObject *result; Py_ssize_t bytes_read = 0; @@ -606,8 +604,8 @@ fileio_readall(fileio *self) #else pos = lseek(self->fd, 0L, SEEK_CUR); #endif - if (_Py_fstat(self->fd, &st) == 0) - end = st.st_size; + if (_Py_fstat_noraise(self->fd, &status) == 0) + end = status.st_size; else end = (Py_off_t)-1; -- cgit v1.2.1 From 652487fbda9903abe14257e157348074ffff75e0 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 20 Mar 2015 19:50:46 -0700 Subject: Issue #23668: Adds support for os.truncate and os.ftruncate on Windows --- Modules/_io/fileio.c | 54 ++++------------------------------------------------ 1 file changed, 4 insertions(+), 50 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 5108fc759c..bb3e9b9f94 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -839,9 +839,7 @@ static PyObject * fileio_truncate(fileio *self, PyObject *args) { PyObject *posobj = NULL; /* the new size wanted by the user */ -#ifndef MS_WINDOWS Py_off_t pos; -#endif int ret; int fd; @@ -864,52 +862,6 @@ fileio_truncate(fileio *self, PyObject *args) Py_INCREF(posobj); } -#ifdef MS_WINDOWS - /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, - so don't even try using it. */ - { - PyObject *oldposobj, *tempposobj; - HANDLE hFile; - - /* we save the file pointer position */ - oldposobj = portable_lseek(fd, NULL, 1); - if (oldposobj == NULL) { - Py_DECREF(posobj); - return NULL; - } - - /* we then move to the truncation position */ - tempposobj = portable_lseek(fd, posobj, 0); - if (tempposobj == NULL) { - Py_DECREF(oldposobj); - Py_DECREF(posobj); - return NULL; - } - Py_DECREF(tempposobj); - - /* Truncate. Note that this may grow the file! */ - Py_BEGIN_ALLOW_THREADS - errno = 0; - hFile = (HANDLE)_get_osfhandle(fd); - ret = hFile == (HANDLE)-1; /* testing for INVALID_HANDLE value */ - if (ret == 0) { - ret = SetEndOfFile(hFile) == 0; - if (ret) - errno = EACCES; - } - Py_END_ALLOW_THREADS - - /* we restore the file pointer position in any case */ - tempposobj = portable_lseek(fd, oldposobj, 0); - Py_DECREF(oldposobj); - if (tempposobj == NULL) { - Py_DECREF(posobj); - return NULL; - } - Py_DECREF(tempposobj); - } -#else - #if defined(HAVE_LARGEFILE_SUPPORT) pos = PyLong_AsLongLong(posobj); #else @@ -922,11 +874,13 @@ fileio_truncate(fileio *self, PyObject *args) Py_BEGIN_ALLOW_THREADS errno = 0; +#ifdef MS_WINDOWS + ret = _chsize_s(fd, pos); +#else ret = ftruncate(fd, pos); +#endif Py_END_ALLOW_THREADS -#endif /* !MS_WINDOWS */ - if (ret != 0) { Py_DECREF(posobj); PyErr_SetFromErrno(PyExc_IOError); -- cgit v1.2.1 From e07a52f272f00b6707b40f557e481749b73dd0fd Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sun, 12 Apr 2015 00:26:27 -0400 Subject: Issue #23524: Replace _PyVerify_fd function with calls to _set_thread_local_invalid_parameter_handler. --- Modules/_io/fileio.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index bb3e9b9f94..186319bfdf 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -107,9 +107,11 @@ internal_close(fileio *self) /* fd is accessible and someone else may have closed it */ if (_PyVerify_fd(fd)) { Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_SUPPRESS_IPH err = close(fd); if (err < 0) save_errno = errno; + _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS } else { save_errno = errno; @@ -599,11 +601,14 @@ fileio_readall(fileio *self) if (!_PyVerify_fd(self->fd)) return PyErr_SetFromErrno(PyExc_IOError); + _Py_BEGIN_SUPPRESS_IPH #ifdef MS_WINDOWS pos = _lseeki64(self->fd, 0L, SEEK_CUR); #else pos = lseek(self->fd, 0L, SEEK_CUR); #endif + _Py_END_SUPPRESS_IPH + if (_Py_fstat_noraise(self->fd, &status) == 0) end = status.st_size; else @@ -792,11 +797,13 @@ portable_lseek(int fd, PyObject *posobj, int whence) if (_PyVerify_fd(fd)) { Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_SUPPRESS_IPH #ifdef MS_WINDOWS res = _lseeki64(fd, pos, whence); #else res = lseek(fd, pos, whence); #endif + _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS } else res = -1; @@ -951,7 +958,12 @@ fileio_isatty(fileio *self) if (self->fd < 0) return err_closed(); Py_BEGIN_ALLOW_THREADS - res = isatty(self->fd); + _Py_BEGIN_SUPPRESS_IPH + if (_PyVerify_fd(self->fd)) + res = isatty(self->fd); + else + res = 0; + _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS return PyBool_FromLong(res); } -- cgit v1.2.1 From 7e564d6d12b9da79756ee26e863efc0c6954ed16 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sun, 12 Apr 2015 00:26:43 -0400 Subject: Issue #23668: Suppresses invalid parameter handler around chsize calls. --- Modules/_io/fileio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 186319bfdf..af93499cae 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -880,12 +880,14 @@ fileio_truncate(fileio *self, PyObject *args) } Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_SUPPRESS_IPH errno = 0; #ifdef MS_WINDOWS ret = _chsize_s(fd, pos); #else ret = ftruncate(fd, pos); #endif + _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS if (ret != 0) { -- cgit v1.2.1 From 518540be31f07ac3fb6f575c4e56a72a31475f54 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 16 Apr 2015 11:19:43 +0300 Subject: Issue #20175: Converted the _io module to Argument Clinic. --- Modules/_io/_iomodule.c | 278 +++++----- Modules/_io/bufferedio.c | 1007 +++++++++++++++++++------------------ Modules/_io/bytesio.c | 427 +++++++++------- Modules/_io/clinic/_iomodule.c.h | 160 ++++++ Modules/_io/clinic/bufferedio.c.h | 474 +++++++++++++++++ Modules/_io/clinic/bytesio.c.h | 426 ++++++++++++++++ Modules/_io/clinic/fileio.c.h | 374 ++++++++++++++ Modules/_io/clinic/iobase.c.h | 282 +++++++++++ Modules/_io/clinic/stringio.c.h | 288 +++++++++++ Modules/_io/clinic/textio.c.h | 464 +++++++++++++++++ Modules/_io/fileio.c | 359 +++++++------ Modules/_io/iobase.c | 248 +++++---- Modules/_io/stringio.c | 269 ++++++---- Modules/_io/textio.c | 476 +++++++++++------- 14 files changed, 4177 insertions(+), 1355 deletions(-) create mode 100644 Modules/_io/clinic/_iomodule.c.h create mode 100644 Modules/_io/clinic/bufferedio.c.h create mode 100644 Modules/_io/clinic/bytesio.c.h create mode 100644 Modules/_io/clinic/fileio.c.h create mode 100644 Modules/_io/clinic/iobase.c.h create mode 100644 Modules/_io/clinic/stringio.c.h create mode 100644 Modules/_io/clinic/textio.c.h (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index e70c4b7611..ea727f25c5 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -93,140 +93,145 @@ PyDoc_STRVAR(module_doc, /* * The main open() function */ -PyDoc_STRVAR(open_doc, -"open(file, mode='r', buffering=-1, encoding=None,\n" -" errors=None, newline=None, closefd=True, opener=None) -> file object\n" -"\n" -"Open file and return a stream. Raise IOError upon failure.\n" -"\n" -"file is either a text or byte string giving the name (and the path\n" -"if the file isn't in the current working directory) of the file to\n" -"be opened or an integer file descriptor of the file to be\n" -"wrapped. (If a file descriptor is given, it is closed when the\n" -"returned I/O object is closed, unless closefd is set to False.)\n" -"\n" -"mode is an optional string that specifies the mode in which the file\n" -"is opened. It defaults to 'r' which means open for reading in text\n" -"mode. Other common values are 'w' for writing (truncating the file if\n" -"it already exists), 'x' for creating and writing to a new file, and\n" -"'a' for appending (which on some Unix systems, means that all writes\n" -"append to the end of the file regardless of the current seek position).\n" -"In text mode, if encoding is not specified the encoding used is platform\n" -"dependent: locale.getpreferredencoding(False) is called to get the\n" -"current locale encoding. (For reading and writing raw bytes use binary\n" -"mode and leave encoding unspecified.) The available modes are:\n" -"\n" -"========= ===============================================================\n" -"Character Meaning\n" -"--------- ---------------------------------------------------------------\n" -"'r' open for reading (default)\n" -"'w' open for writing, truncating the file first\n" -"'x' create a new file and open it for writing\n" -"'a' open for writing, appending to the end of the file if it exists\n" -"'b' binary mode\n" -"'t' text mode (default)\n" -"'+' open a disk file for updating (reading and writing)\n" -"'U' universal newline mode (deprecated)\n" -"========= ===============================================================\n" -"\n" -"The default mode is 'rt' (open for reading text). For binary random\n" -"access, the mode 'w+b' opens and truncates the file to 0 bytes, while\n" -"'r+b' opens the file without truncation. The 'x' mode implies 'w' and\n" -"raises an `FileExistsError` if the file already exists.\n" -"\n" -"Python distinguishes between files opened in binary and text modes,\n" -"even when the underlying operating system doesn't. Files opened in\n" -"binary mode (appending 'b' to the mode argument) return contents as\n" -"bytes objects without any decoding. In text mode (the default, or when\n" -"'t' is appended to the mode argument), the contents of the file are\n" -"returned as strings, the bytes having been first decoded using a\n" -"platform-dependent encoding or using the specified encoding if given.\n" -"\n" -"'U' mode is deprecated and will raise an exception in future versions\n" -"of Python. It has no effect in Python 3. Use newline to control\n" -"universal newlines mode.\n" -"\n" -"buffering is an optional integer used to set the buffering policy.\n" -"Pass 0 to switch buffering off (only allowed in binary mode), 1 to select\n" -"line buffering (only usable in text mode), and an integer > 1 to indicate\n" -"the size of a fixed-size chunk buffer. When no buffering argument is\n" -"given, the default buffering policy works as follows:\n" -"\n" -"* Binary files are buffered in fixed-size chunks; the size of the buffer\n" -" is chosen using a heuristic trying to determine the underlying device's\n" -" \"block size\" and falling back on `io.DEFAULT_BUFFER_SIZE`.\n" -" On many systems, the buffer will typically be 4096 or 8192 bytes long.\n" -"\n" -"* \"Interactive\" text files (files for which isatty() returns True)\n" -" use line buffering. Other text files use the policy described above\n" -" for binary files.\n" -"\n" -"encoding is the name of the encoding used to decode or encode the\n" -"file. This should only be used in text mode. The default encoding is\n" -"platform dependent, but any encoding supported by Python can be\n" -"passed. See the codecs module for the list of supported encodings.\n" -"\n" -"errors is an optional string that specifies how encoding errors are to\n" -"be handled---this argument should not be used in binary mode. Pass\n" -"'strict' to raise a ValueError exception if there is an encoding error\n" -"(the default of None has the same effect), or pass 'ignore' to ignore\n" -"errors. (Note that ignoring encoding errors can lead to data loss.)\n" -"See the documentation for codecs.register or run 'help(codecs.Codec)'\n" -"for a list of the permitted encoding error strings.\n" -"\n" -"newline controls how universal newlines works (it only applies to text\n" -"mode). It can be None, '', '\\n', '\\r', and '\\r\\n'. It works as\n" -"follows:\n" -"\n" -"* On input, if newline is None, universal newlines mode is\n" -" enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n" -" these are translated into '\\n' before being returned to the\n" -" caller. If it is '', universal newline mode is enabled, but line\n" -" endings are returned to the caller untranslated. If it has any of\n" -" the other legal values, input lines are only terminated by the given\n" -" string, and the line ending is returned to the caller untranslated.\n" -"\n" -"* On output, if newline is None, any '\\n' characters written are\n" -" translated to the system default line separator, os.linesep. If\n" -" newline is '' or '\\n', no translation takes place. If newline is any\n" -" of the other legal values, any '\\n' characters written are translated\n" -" to the given string.\n" -"\n" -"If closefd is False, the underlying file descriptor will be kept open\n" -"when the file is closed. This does not work when a file name is given\n" -"and must be True in that case.\n" -"\n" -"A custom opener can be used by passing a callable as *opener*. The\n" -"underlying file descriptor for the file object is then obtained by\n" -"calling *opener* with (*file*, *flags*). *opener* must return an open\n" -"file descriptor (passing os.open as *opener* results in functionality\n" -"similar to passing None).\n" -"\n" -"open() returns a file object whose type depends on the mode, and\n" -"through which the standard file operations such as reading and writing\n" -"are performed. When open() is used to open a file in a text mode ('w',\n" -"'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open\n" -"a file in a binary mode, the returned class varies: in read binary\n" -"mode, it returns a BufferedReader; in write binary and append binary\n" -"modes, it returns a BufferedWriter, and in read/write mode, it returns\n" -"a BufferedRandom.\n" -"\n" -"It is also possible to use a string or bytearray as a file for both\n" -"reading and writing. For strings StringIO can be used like a file\n" -"opened in a text mode, and for bytes a BytesIO can be used like a file\n" -"opened in a binary mode.\n" - ); +/*[clinic input] +module _io + +_io.open + file: object + mode: str = "r" + buffering: int = -1 + encoding: str(nullable=True) = NULL + errors: str(nullable=True) = NULL + newline: str(nullable=True) = NULL + closefd: int(c_default="1") = True + opener: object = None + +Open file and return a stream. Raise IOError upon failure. + +file is either a text or byte string giving the name (and the path +if the file isn't in the current working directory) of the file to +be opened or an integer file descriptor of the file to be +wrapped. (If a file descriptor is given, it is closed when the +returned I/O object is closed, unless closefd is set to False.) + +mode is an optional string that specifies the mode in which the file +is opened. It defaults to 'r' which means open for reading in text +mode. Other common values are 'w' for writing (truncating the file if +it already exists), 'x' for creating and writing to a new file, and +'a' for appending (which on some Unix systems, means that all writes +append to the end of the file regardless of the current seek position). +In text mode, if encoding is not specified the encoding used is platform +dependent: locale.getpreferredencoding(False) is called to get the +current locale encoding. (For reading and writing raw bytes use binary +mode and leave encoding unspecified.) The available modes are: + +========= =============================================================== +Character Meaning +--------- --------------------------------------------------------------- +'r' open for reading (default) +'w' open for writing, truncating the file first +'x' create a new file and open it for writing +'a' open for writing, appending to the end of the file if it exists +'b' binary mode +'t' text mode (default) +'+' open a disk file for updating (reading and writing) +'U' universal newline mode (deprecated) +========= =============================================================== + +The default mode is 'rt' (open for reading text). For binary random +access, the mode 'w+b' opens and truncates the file to 0 bytes, while +'r+b' opens the file without truncation. The 'x' mode implies 'w' and +raises an `FileExistsError` if the file already exists. + +Python distinguishes between files opened in binary and text modes, +even when the underlying operating system doesn't. Files opened in +binary mode (appending 'b' to the mode argument) return contents as +bytes objects without any decoding. In text mode (the default, or when +'t' is appended to the mode argument), the contents of the file are +returned as strings, the bytes having been first decoded using a +platform-dependent encoding or using the specified encoding if given. + +'U' mode is deprecated and will raise an exception in future versions +of Python. It has no effect in Python 3. Use newline to control +universal newlines mode. + +buffering is an optional integer used to set the buffering policy. +Pass 0 to switch buffering off (only allowed in binary mode), 1 to select +line buffering (only usable in text mode), and an integer > 1 to indicate +the size of a fixed-size chunk buffer. When no buffering argument is +given, the default buffering policy works as follows: + +* Binary files are buffered in fixed-size chunks; the size of the buffer + is chosen using a heuristic trying to determine the underlying device's + "block size" and falling back on `io.DEFAULT_BUFFER_SIZE`. + On many systems, the buffer will typically be 4096 or 8192 bytes long. + +* "Interactive" text files (files for which isatty() returns True) + use line buffering. Other text files use the policy described above + for binary files. + +encoding is the name of the encoding used to decode or encode the +file. This should only be used in text mode. The default encoding is +platform dependent, but any encoding supported by Python can be +passed. See the codecs module for the list of supported encodings. + +errors is an optional string that specifies how encoding errors are to +be handled---this argument should not be used in binary mode. Pass +'strict' to raise a ValueError exception if there is an encoding error +(the default of None has the same effect), or pass 'ignore' to ignore +errors. (Note that ignoring encoding errors can lead to data loss.) +See the documentation for codecs.register or run 'help(codecs.Codec)' +for a list of the permitted encoding error strings. + +newline controls how universal newlines works (it only applies to text +mode). It can be None, '', '\n', '\r', and '\r\n'. It works as +follows: + +* On input, if newline is None, universal newlines mode is + enabled. Lines in the input can end in '\n', '\r', or '\r\n', and + these are translated into '\n' before being returned to the + caller. If it is '', universal newline mode is enabled, but line + endings are returned to the caller untranslated. If it has any of + the other legal values, input lines are only terminated by the given + string, and the line ending is returned to the caller untranslated. + +* On output, if newline is None, any '\n' characters written are + translated to the system default line separator, os.linesep. If + newline is '' or '\n', no translation takes place. If newline is any + of the other legal values, any '\n' characters written are translated + to the given string. + +If closefd is False, the underlying file descriptor will be kept open +when the file is closed. This does not work when a file name is given +and must be True in that case. + +A custom opener can be used by passing a callable as *opener*. The +underlying file descriptor for the file object is then obtained by +calling *opener* with (*file*, *flags*). *opener* must return an open +file descriptor (passing os.open as *opener* results in functionality +similar to passing None). + +open() returns a file object whose type depends on the mode, and +through which the standard file operations such as reading and writing +are performed. When open() is used to open a file in a text mode ('w', +'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open +a file in a binary mode, the returned class varies: in read binary +mode, it returns a BufferedReader; in write binary and append binary +modes, it returns a BufferedWriter, and in read/write mode, it returns +a BufferedRandom. + +It is also possible to use a string or bytearray as a file for both +reading and writing. For strings StringIO can be used like a file +opened in a text mode, and for bytes a BytesIO can be used like a file +opened in a binary mode. +[clinic start generated code]*/ static PyObject * -io_open(PyObject *self, PyObject *args, PyObject *kwds) +_io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, + int buffering, const char *encoding, const char *errors, + const char *newline, int closefd, PyObject *opener) +/*[clinic end generated code: output=7615d0d746eb14d2 input=0541ce15691a82f2]*/ { - char *kwlist[] = {"file", "mode", "buffering", - "encoding", "errors", "newline", - "closefd", "opener", NULL}; - PyObject *file, *opener = Py_None; - char *mode = "r"; - int buffering = -1, closefd = 1; - char *encoding = NULL, *errors = NULL, *newline = NULL; unsigned i; int creating = 0, reading = 0, writing = 0, appending = 0, updating = 0; @@ -242,13 +247,6 @@ io_open(PyObject *self, PyObject *args, PyObject *kwds) _Py_IDENTIFIER(mode); _Py_IDENTIFIER(close); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzziO:open", kwlist, - &file, &mode, &buffering, - &encoding, &errors, &newline, - &closefd, &opener)) { - return NULL; - } - if (!PyUnicode_Check(file) && !PyBytes_Check(file) && !PyNumber_Check(file)) { @@ -611,8 +609,10 @@ iomodule_free(PyObject *mod) { * Module definition */ +#include "clinic/_iomodule.c.h" + static PyMethodDef module_methods[] = { - {"open", (PyCFunction)io_open, METH_VARARGS|METH_KEYWORDS, open_doc}, + _IO_OPEN_METHODDEF {NULL, NULL} }; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 7cf5ddaf00..916353bdf7 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -13,6 +13,24 @@ #include "pythread.h" #include "_iomodule.h" +/*[clinic input] +module _io +class _io._BufferedIOBase "PyObject *" "&PyBufferedIOBase_Type" +class _io._Buffered "buffered *" "&PyBufferedIOBase_Type" +class _io.BufferedReader "buffered *" "&PyBufferedReader_Type" +class _io.BufferedWriter "buffered *" "&PyBufferedWriter_Type" +class _io.BufferedRWPair "rwpair *" "&PyBufferedRWPair_Type" +class _io.BufferedRandom "buffered *" "&PyBufferedRandom_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=59460b9c5639984d]*/ + +/*[python input] +class io_ssize_t_converter(CConverter): + type = 'Py_ssize_t' + converter = '_PyIO_ConvertSsize_t' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/ + _Py_IDENTIFIER(close); _Py_IDENTIFIER(_dealloc_warn); _Py_IDENTIFIER(flush); @@ -48,61 +66,63 @@ PyDoc_STRVAR(bufferediobase_doc, ); static PyObject * -_bufferediobase_readinto_generic(PyObject *self, PyObject *args, char readinto1) +_bufferediobase_readinto_generic(PyObject *self, Py_buffer *buffer, char readinto1) { - Py_buffer buf; Py_ssize_t len; PyObject *data; - if (!PyArg_ParseTuple(args, - readinto1 ? "w*:readinto1" : "w*:readinto", - &buf)) { - return NULL; - } - data = _PyObject_CallMethodId(self, readinto1 ? &PyId_read1 : &PyId_read, - "n", buf.len); + "n", buffer->len); if (data == NULL) - goto error; + return NULL; if (!PyBytes_Check(data)) { Py_DECREF(data); PyErr_SetString(PyExc_TypeError, "read() should return bytes"); - goto error; + return NULL; } len = Py_SIZE(data); - if (len > buf.len) { + if (len > buffer->len) { PyErr_Format(PyExc_ValueError, "read() returned too much data: " "%zd bytes requested, %zd returned", - buf.len, len); + buffer->len, len); Py_DECREF(data); - goto error; + return NULL; } - memcpy(buf.buf, PyBytes_AS_STRING(data), len); + memcpy(buffer->buf, PyBytes_AS_STRING(data), len); - PyBuffer_Release(&buf); Py_DECREF(data); return PyLong_FromSsize_t(len); - - error: - PyBuffer_Release(&buf); - return NULL; } +/*[clinic input] +_io._BufferedIOBase.readinto + buffer: Py_buffer(types={'rwbuffer'}) + / +[clinic start generated code]*/ + static PyObject * -bufferediobase_readinto(PyObject *self, PyObject *args) +_io__BufferedIOBase_readinto_impl(PyObject *self, Py_buffer *buffer) +/*[clinic end generated code: output=8c8cda6684af8038 input=f8242a06c21763a0]*/ { - return _bufferediobase_readinto_generic(self, args, 0); + return _bufferediobase_readinto_generic(self, buffer, 0); } +/*[clinic input] +_io._BufferedIOBase.readinto1 + buffer: Py_buffer(types={'rwbuffer'}) + / +[clinic start generated code]*/ + static PyObject * -bufferediobase_readinto1(PyObject *self, PyObject *args) +_io__BufferedIOBase_readinto1_impl(PyObject *self, Py_buffer *buffer) +/*[clinic end generated code: output=358623e4fd2b69d3 input=2003e706c730bd21]*/ { - return _bufferediobase_readinto_generic(self, args, 1); + return _bufferediobase_readinto_generic(self, buffer, 1); } static PyObject * @@ -114,14 +134,18 @@ bufferediobase_unsupported(const char *message) return NULL; } -PyDoc_STRVAR(bufferediobase_detach_doc, - "Disconnect this buffer from its underlying raw stream and return it.\n" - "\n" - "After the raw stream has been detached, the buffer is in an unusable\n" - "state.\n"); +/*[clinic input] +_io._BufferedIOBase.detach + +Disconnect this buffer from its underlying raw stream and return it. + +After the raw stream has been detached, the buffer is in an unusable +state. +[clinic start generated code]*/ static PyObject * -bufferediobase_detach(PyObject *self) +_io__BufferedIOBase_detach_impl(PyObject *self) +/*[clinic end generated code: output=754977c8d10ed88c input=822427fb58fe4169]*/ { return bufferediobase_unsupported("detach"); } @@ -179,69 +203,6 @@ bufferediobase_write(PyObject *self, PyObject *args) } -static PyMethodDef bufferediobase_methods[] = { - {"detach", (PyCFunction)bufferediobase_detach, METH_NOARGS, bufferediobase_detach_doc}, - {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc}, - {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc}, - {"readinto", bufferediobase_readinto, METH_VARARGS, NULL}, - {"readinto1", bufferediobase_readinto1, METH_VARARGS, NULL}, - {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc}, - {NULL, NULL} -}; - -PyTypeObject PyBufferedIOBase_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io._BufferedIOBase", /*tp_name*/ - 0, /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare */ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ - bufferediobase_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - bufferediobase_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - &PyIOBase_Type, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* tp_version_tag */ - 0, /* tp_finalize */ -}; - - typedef struct { PyObject_HEAD @@ -896,17 +857,20 @@ buffered_flush(buffered *self, PyObject *args) return res; } +/*[clinic input] +_io._Buffered.peek + size: Py_ssize_t = 0 + / + +[clinic start generated code]*/ + static PyObject * -buffered_peek(buffered *self, PyObject *args) +_io__Buffered_peek_impl(buffered *self, Py_ssize_t size) +/*[clinic end generated code: output=ba7a097ca230102b input=37ffb97d06ff4adb]*/ { - Py_ssize_t n = 0; PyObject *res = NULL; CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, "|n:peek", &n)) { - return NULL; - } - if (!ENTER_BUFFERED(self)) return NULL; @@ -923,16 +887,19 @@ end: return res; } +/*[clinic input] +_io._Buffered.read + size as n: io_ssize_t = -1 + / +[clinic start generated code]*/ + static PyObject * -buffered_read(buffered *self, PyObject *args) +_io__Buffered_read_impl(buffered *self, Py_ssize_t n) +/*[clinic end generated code: output=f41c78bb15b9bbe9 input=c0939ec7f9e9354f]*/ { - Py_ssize_t n = -1; PyObject *res; CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) { - return NULL; - } if (n < -1) { PyErr_SetString(PyExc_ValueError, "read length must be positive or -1"); @@ -961,17 +928,20 @@ buffered_read(buffered *self, PyObject *args) return res; } +/*[clinic input] +_io._Buffered.read1 + size as n: Py_ssize_t + / +[clinic start generated code]*/ + static PyObject * -buffered_read1(buffered *self, PyObject *args) +_io__Buffered_read1_impl(buffered *self, Py_ssize_t n) +/*[clinic end generated code: output=bcc4fb4e54d103a3 input=8d2869c18b983184]*/ { - Py_ssize_t n, have, r; + Py_ssize_t have, r; PyObject *res = NULL; CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, "n:read1", &n)) { - return NULL; - } - if (n < 0) { PyErr_SetString(PyExc_ValueError, "read length must be positive"); @@ -1012,34 +982,27 @@ buffered_read1(buffered *self, PyObject *args) } static PyObject * -_buffered_readinto_generic(buffered *self, PyObject *args, char readinto1) +_buffered_readinto_generic(buffered *self, Py_buffer *buffer, char readinto1) { - Py_buffer buf; Py_ssize_t n, written = 0, remaining; PyObject *res = NULL; CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, - readinto1 ? "w*:readinto1" : "w*:readinto", - &buf)) - return NULL; - n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); if (n > 0) { - if (n >= buf.len) { - memcpy(buf.buf, self->buffer + self->pos, buf.len); - self->pos += buf.len; - res = PyLong_FromSsize_t(buf.len); - goto end_unlocked; + if (n >= buffer->len) { + memcpy(buffer->buf, self->buffer + self->pos, buffer->len); + self->pos += buffer->len; + return PyLong_FromSsize_t(buffer->len); } - memcpy(buf.buf, self->buffer + self->pos, n); + memcpy(buffer->buf, self->buffer + self->pos, n); self->pos += n; written = n; } if (!ENTER_BUFFERED(self)) - goto end_unlocked; + return NULL; if (self->writable) { res = buffered_flush_and_rewind_unlocked(self); @@ -1051,13 +1014,13 @@ _buffered_readinto_generic(buffered *self, PyObject *args, char readinto1) _bufferedreader_reset_buf(self); self->pos = 0; - for (remaining = buf.len - written; + for (remaining = buffer->len - written; remaining > 0; written += n, remaining -= n) { /* If remaining bytes is larger than internal buffer size, copy * directly into caller's buffer. */ if (remaining > self->buffer_size) { - n = _bufferedreader_raw_read(self, (char *) buf.buf + written, + n = _bufferedreader_raw_read(self, (char *) buffer->buf + written, remaining); } @@ -1068,7 +1031,7 @@ _buffered_readinto_generic(buffered *self, PyObject *args, char readinto1) if (n > 0) { if (n > remaining) n = remaining; - memcpy((char *) buf.buf + written, + memcpy((char *) buffer->buf + written, self->buffer + self->pos, n); self->pos += n; continue; /* short circuit */ @@ -1097,21 +1060,33 @@ _buffered_readinto_generic(buffered *self, PyObject *args, char readinto1) end: LEAVE_BUFFERED(self); -end_unlocked: - PyBuffer_Release(&buf); return res; } +/*[clinic input] +_io._Buffered.readinto + buffer: Py_buffer(types={'rwbuffer'}) + / +[clinic start generated code]*/ + static PyObject * -buffered_readinto(buffered *self, PyObject *args) +_io__Buffered_readinto_impl(buffered *self, Py_buffer *buffer) +/*[clinic end generated code: output=bcb376580b1d8170 input=962b7496eac38b3a]*/ { - return _buffered_readinto_generic(self, args, 0); + return _buffered_readinto_generic(self, buffer, 0); } +/*[clinic input] +_io._Buffered.readinto1 + buffer: Py_buffer(types={'rwbuffer'}) + / +[clinic start generated code]*/ + static PyObject * -buffered_readinto1(buffered *self, PyObject *args) +_io__Buffered_readinto1_impl(buffered *self, Py_buffer *buffer) +/*[clinic end generated code: output=6e5c6ac5868205d6 input=834614d93f0adeb5]*/ { - return _buffered_readinto_generic(self, args, 1); + return _buffered_readinto_generic(self, buffer, 1); } @@ -1226,15 +1201,18 @@ end_unlocked: return res; } +/*[clinic input] +_io._Buffered.readline + size: io_ssize_t = -1 + / +[clinic start generated code]*/ + static PyObject * -buffered_readline(buffered *self, PyObject *args) +_io__Buffered_readline_impl(buffered *self, Py_ssize_t size) +/*[clinic end generated code: output=24dd2aa6e33be83c input=ff1e0df821cb4e5c]*/ { - Py_ssize_t limit = -1; - CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit)) - return NULL; - return _buffered_readline(self, limit); + return _buffered_readline(self, size); } @@ -1252,17 +1230,21 @@ buffered_tell(buffered *self, PyObject *args) return PyLong_FromOff_t(pos); } +/*[clinic input] +_io._Buffered.seek + target as targetobj: object + whence: int = 0 + / +[clinic start generated code]*/ + static PyObject * -buffered_seek(buffered *self, PyObject *args) +_io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence) +/*[clinic end generated code: output=7ae0e8dc46efdefb input=a9c4920bfcba6163]*/ { Py_off_t target, n; - int whence = 0; - PyObject *targetobj, *res = NULL; + PyObject *res = NULL; CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, "O|i:seek", &targetobj, &whence)) { - return NULL; - } /* Do some error checking instead of trusting OS 'seek()' ** error detection, just in case. @@ -1344,17 +1326,19 @@ end: return res; } +/*[clinic input] +_io._Buffered.truncate + pos: object = None + / +[clinic start generated code]*/ + static PyObject * -buffered_truncate(buffered *self, PyObject *args) +_io__Buffered_truncate_impl(buffered *self, PyObject *pos) +/*[clinic end generated code: output=667ca03c60c270de input=8a1be34d57cca2d3]*/ { - PyObject *pos = Py_None; PyObject *res = NULL; CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) { - return NULL; - } - if (!ENTER_BUFFERED(self)) return NULL; @@ -1439,29 +1423,27 @@ buffered_repr(buffered *self) * class BufferedReader */ -PyDoc_STRVAR(bufferedreader_doc, - "Create a new buffered reader using the given readable raw IO object."); - static void _bufferedreader_reset_buf(buffered *self) { self->read_end = -1; } +/*[clinic input] +_io.BufferedReader.__init__ + raw: object + buffer_size: Py_ssize_t(c_default="DEFAULT_BUFFER_SIZE") = DEFAULT_BUFFER_SIZE + +Create a new buffered reader using the given readable raw IO object. +[clinic start generated code]*/ + static int -bufferedreader_init(buffered *self, PyObject *args, PyObject *kwds) +_io_BufferedReader___init___impl(buffered *self, PyObject *raw, + Py_ssize_t buffer_size) +/*[clinic end generated code: output=cddcfefa0ed294c4 input=fb887e06f11b4e48]*/ { - char *kwlist[] = {"raw", "buffer_size", NULL}; - Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - PyObject *raw; - self->ok = 0; self->detached = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedReader", kwlist, - &raw, &buffer_size)) { - return -1; - } - if (_PyIOBase_check_readable(raw, Py_True) == NULL) return -1; @@ -1782,112 +1764,12 @@ _bufferedreader_peek_unlocked(buffered *self) self->pos = 0; return PyBytes_FromStringAndSize(self->buffer, r); } - -static PyMethodDef bufferedreader_methods[] = { - /* BufferedIOMixin methods */ - {"detach", (PyCFunction)buffered_detach, METH_NOARGS}, - {"flush", (PyCFunction)buffered_simple_flush, METH_NOARGS}, - {"close", (PyCFunction)buffered_close, METH_NOARGS}, - {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS}, - {"readable", (PyCFunction)buffered_readable, METH_NOARGS}, - {"writable", (PyCFunction)buffered_writable, METH_NOARGS}, - {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, - {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, - {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, - {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS}, - - {"read", (PyCFunction)buffered_read, METH_VARARGS}, - {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, - {"read1", (PyCFunction)buffered_read1, METH_VARARGS}, - {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS}, - {"readinto1", (PyCFunction)buffered_readinto1, METH_VARARGS}, - {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, - {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, - {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, - {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, - {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, - {NULL, NULL} -}; - -static PyMemberDef bufferedreader_members[] = { - {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, - {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, - {NULL} -}; - -static PyGetSetDef bufferedreader_getset[] = { - {"closed", (getter)buffered_closed_get, NULL, NULL}, - {"name", (getter)buffered_name_get, NULL, NULL}, - {"mode", (getter)buffered_mode_get, NULL, NULL}, - {NULL} -}; - - -PyTypeObject PyBufferedReader_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.BufferedReader", /*tp_name*/ - sizeof(buffered), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)buffered_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare */ - (reprfunc)buffered_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ - bufferedreader_doc, /* tp_doc */ - (traverseproc)buffered_traverse, /* tp_traverse */ - (inquiry)buffered_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(buffered, weakreflist), /*tp_weaklistoffset*/ - 0, /* tp_iter */ - (iternextfunc)buffered_iternext, /* tp_iternext */ - bufferedreader_methods, /* tp_methods */ - bufferedreader_members, /* tp_members */ - bufferedreader_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(buffered, dict), /* tp_dictoffset */ - (initproc)bufferedreader_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* tp_version_tag */ - 0, /* tp_finalize */ -}; /* * class BufferedWriter */ -PyDoc_STRVAR(bufferedwriter_doc, - "A buffer for a writeable sequential RawIO object.\n" - "\n" - "The constructor creates a BufferedWriter for the given writeable raw\n" - "stream. If the buffer_size is not given, it defaults to\n" - "DEFAULT_BUFFER_SIZE.\n" - ); - static void _bufferedwriter_reset_buf(buffered *self) { @@ -1895,21 +1777,26 @@ _bufferedwriter_reset_buf(buffered *self) self->write_end = -1; } +/*[clinic input] +_io.BufferedWriter.__init__ + raw: object + buffer_size: Py_ssize_t(c_default="DEFAULT_BUFFER_SIZE") = DEFAULT_BUFFER_SIZE + +A buffer for a writeable sequential RawIO object. + +The constructor creates a BufferedWriter for the given writeable raw +stream. If the buffer_size is not given, it defaults to +DEFAULT_BUFFER_SIZE. +[clinic start generated code]*/ + static int -bufferedwriter_init(buffered *self, PyObject *args, PyObject *kwds) +_io_BufferedWriter___init___impl(buffered *self, PyObject *raw, + Py_ssize_t buffer_size) +/*[clinic end generated code: output=c8942a020c0dee64 input=914be9b95e16007b]*/ { - char *kwlist[] = {"raw", "buffer_size", NULL}; - Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - PyObject *raw; - self->ok = 0; self->detached = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedWriter", kwlist, - &raw, &buffer_size)) { - return -1; - } - if (_PyIOBase_check_writable(raw, Py_True) == NULL) return -1; @@ -2030,29 +1917,28 @@ error: return NULL; } +/*[clinic input] +_io.BufferedWriter.write + buffer: Py_buffer + / +[clinic start generated code]*/ + static PyObject * -bufferedwriter_write(buffered *self, PyObject *args) +_io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer) +/*[clinic end generated code: output=7f8d1365759bfc6b input=dd87dd85fc7f8850]*/ { PyObject *res = NULL; - Py_buffer buf; Py_ssize_t written, avail, remaining; Py_off_t offset; CHECK_INITIALIZED(self) - if (!PyArg_ParseTuple(args, "y*:write", &buf)) { - return NULL; - } - if (IS_CLOSED(self)) { PyErr_SetString(PyExc_ValueError, "write to closed file"); - PyBuffer_Release(&buf); return NULL; } - if (!ENTER_BUFFERED(self)) { - PyBuffer_Release(&buf); + if (!ENTER_BUFFERED(self)) return NULL; - } /* Fast path: the data to write can be fully buffered. */ if (!VALID_READ_BUFFER(self) && !VALID_WRITE_BUFFER(self)) { @@ -2060,15 +1946,15 @@ bufferedwriter_write(buffered *self, PyObject *args) self->raw_pos = 0; } avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t); - if (buf.len <= avail) { - memcpy(self->buffer + self->pos, buf.buf, buf.len); + if (buffer->len <= avail) { + memcpy(self->buffer + self->pos, buffer->buf, buffer->len); if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) { self->write_pos = self->pos; } - ADJUST_POSITION(self, self->pos + buf.len); + ADJUST_POSITION(self, self->pos + buffer->len); if (self->pos > self->write_end) self->write_end = self->pos; - written = buf.len; + written = buffer->len; goto end; } @@ -2091,17 +1977,17 @@ bufferedwriter_write(buffered *self, PyObject *args) self->write_pos = 0; avail = Py_SAFE_DOWNCAST(self->buffer_size - self->write_end, Py_off_t, Py_ssize_t); - if (buf.len <= avail) { + if (buffer->len <= avail) { /* Everything can be buffered */ PyErr_Clear(); - memcpy(self->buffer + self->write_end, buf.buf, buf.len); - self->write_end += buf.len; - self->pos += buf.len; - written = buf.len; + memcpy(self->buffer + self->write_end, buffer->buf, buffer->len); + self->write_end += buffer->len; + self->pos += buffer->len; + written = buffer->len; goto end; } /* Buffer as much as possible. */ - memcpy(self->buffer + self->write_end, buf.buf, avail); + memcpy(self->buffer + self->write_end, buffer->buf, avail); self->write_end += avail; self->pos += avail; /* XXX Modifying the existing exception e using the pointer w @@ -2127,11 +2013,11 @@ bufferedwriter_write(buffered *self, PyObject *args) } /* Then write buf itself. At this point the buffer has been emptied. */ - remaining = buf.len; + remaining = buffer->len; written = 0; while (remaining > self->buffer_size) { Py_ssize_t n = _bufferedwriter_raw_write( - self, (char *) buf.buf + written, buf.len - written); + self, (char *) buffer->buf + written, buffer->len - written); if (n == -1) { goto error; } else if (n == -2) { @@ -2139,7 +2025,7 @@ bufferedwriter_write(buffered *self, PyObject *args) if (remaining > self->buffer_size) { /* Can't buffer everything, still buffer as much as possible */ memcpy(self->buffer, - (char *) buf.buf + written, self->buffer_size); + (char *) buffer->buf + written, self->buffer_size); self->raw_pos = 0; ADJUST_POSITION(self, self->buffer_size); self->write_end = self->buffer_size; @@ -2162,7 +2048,7 @@ bufferedwriter_write(buffered *self, PyObject *args) if (self->readable) _bufferedreader_reset_buf(self); if (remaining > 0) { - memcpy(self->buffer, (char *) buf.buf + written, remaining); + memcpy(self->buffer, (char *) buffer->buf + written, remaining); written += remaining; } self->write_pos = 0; @@ -2176,118 +2062,18 @@ end: error: LEAVE_BUFFERED(self) - PyBuffer_Release(&buf); return res; } + -static PyMethodDef bufferedwriter_methods[] = { - /* BufferedIOMixin methods */ - {"close", (PyCFunction)buffered_close, METH_NOARGS}, - {"detach", (PyCFunction)buffered_detach, METH_NOARGS}, - {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS}, - {"readable", (PyCFunction)buffered_readable, METH_NOARGS}, - {"writable", (PyCFunction)buffered_writable, METH_NOARGS}, - {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, - {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, - {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, - {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS}, - - {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, - {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, - {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, - {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, - {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, - {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, - {NULL, NULL} -}; - -static PyMemberDef bufferedwriter_members[] = { - {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, - {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, - {NULL} -}; -static PyGetSetDef bufferedwriter_getset[] = { - {"closed", (getter)buffered_closed_get, NULL, NULL}, - {"name", (getter)buffered_name_get, NULL, NULL}, - {"mode", (getter)buffered_mode_get, NULL, NULL}, - {NULL} -}; +/* + * BufferedRWPair + */ - -PyTypeObject PyBufferedWriter_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.BufferedWriter", /*tp_name*/ - sizeof(buffered), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)buffered_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare */ - (reprfunc)buffered_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ - bufferedwriter_doc, /* tp_doc */ - (traverseproc)buffered_traverse, /* tp_traverse */ - (inquiry)buffered_clear, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(buffered, weakreflist), /*tp_weaklistoffset*/ - 0, /* tp_iter */ - 0, /* tp_iternext */ - bufferedwriter_methods, /* tp_methods */ - bufferedwriter_members, /* tp_members */ - bufferedwriter_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(buffered, dict), /* tp_dictoffset */ - (initproc)bufferedwriter_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ - 0, /* tp_free */ - 0, /* tp_is_gc */ - 0, /* tp_bases */ - 0, /* tp_mro */ - 0, /* tp_cache */ - 0, /* tp_subclasses */ - 0, /* tp_weaklist */ - 0, /* tp_del */ - 0, /* tp_version_tag */ - 0, /* tp_finalize */ -}; - - - -/* - * BufferedRWPair - */ - -PyDoc_STRVAR(bufferedrwpair_doc, - "A buffered reader and writer object together.\n" - "\n" - "A buffered reader object and buffered writer object put together to\n" - "form a sequential IO object that can read and write. This is typically\n" - "used with a socket or two-way pipe.\n" - "\n" - "reader and writer are RawIOBase objects that are readable and\n" - "writeable respectively. If the buffer_size is omitted it defaults to\n" - "DEFAULT_BUFFER_SIZE.\n" - ); - -/* XXX The usefulness of this (compared to having two separate IO objects) is - * questionable. - */ +/* XXX The usefulness of this (compared to having two separate IO objects) is + * questionable. + */ typedef struct { PyObject_HEAD @@ -2297,17 +2083,29 @@ typedef struct { PyObject *weakreflist; } rwpair; -static int -bufferedrwpair_init(rwpair *self, PyObject *args, PyObject *kwds) -{ - PyObject *reader, *writer; - Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; +/*[clinic input] +_io.BufferedRWPair.__init__ + reader: object + writer: object + buffer_size: Py_ssize_t(c_default="DEFAULT_BUFFER_SIZE") = DEFAULT_BUFFER_SIZE + / - if (!PyArg_ParseTuple(args, "OO|n:BufferedRWPair", &reader, &writer, - &buffer_size)) { - return -1; - } +A buffered reader and writer object together. +A buffered reader object and buffered writer object put together to +form a sequential IO object that can read and write. This is typically +used with a socket or two-way pipe. + +reader and writer are RawIOBase objects that are readable and +writeable respectively. If the buffer_size is omitted it defaults to +DEFAULT_BUFFER_SIZE. +[clinic start generated code]*/ + +static int +_io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader, + PyObject *writer, Py_ssize_t buffer_size) +/*[clinic end generated code: output=327e73d1aee8f984 input=620d42d71f33a031]*/ +{ if (_PyIOBase_check_readable(reader, Py_True) == NULL) return -1; if (_PyIOBase_check_writable(writer, Py_True) == NULL) @@ -2472,6 +2270,306 @@ bufferedrwpair_closed_get(rwpair *self, void *context) } return PyObject_GetAttr((PyObject *) self->writer, _PyIO_str_closed); } + + + +/* + * BufferedRandom + */ + +/*[clinic input] +_io.BufferedRandom.__init__ + raw: object + buffer_size: Py_ssize_t(c_default="DEFAULT_BUFFER_SIZE") = DEFAULT_BUFFER_SIZE + +A buffered interface to random access streams. + +The constructor creates a reader and writer for a seekable stream, +raw, given in the first argument. If the buffer_size is omitted it +defaults to DEFAULT_BUFFER_SIZE. +[clinic start generated code]*/ + +static int +_io_BufferedRandom___init___impl(buffered *self, PyObject *raw, + Py_ssize_t buffer_size) +/*[clinic end generated code: output=d3d64eb0f64e64a3 input=a4e818fb86d0e50c]*/ +{ + self->ok = 0; + self->detached = 0; + + if (_PyIOBase_check_seekable(raw, Py_True) == NULL) + return -1; + if (_PyIOBase_check_readable(raw, Py_True) == NULL) + return -1; + if (_PyIOBase_check_writable(raw, Py_True) == NULL) + return -1; + + Py_CLEAR(self->raw); + Py_INCREF(raw); + self->raw = raw; + self->buffer_size = buffer_size; + self->readable = 1; + self->writable = 1; + + if (_buffered_init(self) < 0) + return -1; + _bufferedreader_reset_buf(self); + _bufferedwriter_reset_buf(self); + self->pos = 0; + + self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedRandom_Type && + Py_TYPE(raw) == &PyFileIO_Type); + + self->ok = 1; + return 0; +} + +#include "clinic/bufferedio.c.h" + + +static PyMethodDef bufferediobase_methods[] = { + _IO__BUFFEREDIOBASE_DETACH_METHODDEF + {"read", bufferediobase_read, METH_VARARGS, bufferediobase_read_doc}, + {"read1", bufferediobase_read1, METH_VARARGS, bufferediobase_read1_doc}, + _IO__BUFFEREDIOBASE_READINTO_METHODDEF + _IO__BUFFEREDIOBASE_READINTO1_METHODDEF + {"write", bufferediobase_write, METH_VARARGS, bufferediobase_write_doc}, + {NULL, NULL} +}; + +PyTypeObject PyBufferedIOBase_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_io._BufferedIOBase", /*tp_name*/ + 0, /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare */ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + bufferediobase_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + bufferediobase_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyIOBase_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ +}; + + +static PyMethodDef bufferedreader_methods[] = { + /* BufferedIOMixin methods */ + {"detach", (PyCFunction)buffered_detach, METH_NOARGS}, + {"flush", (PyCFunction)buffered_simple_flush, METH_NOARGS}, + {"close", (PyCFunction)buffered_close, METH_NOARGS}, + {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS}, + {"readable", (PyCFunction)buffered_readable, METH_NOARGS}, + {"writable", (PyCFunction)buffered_writable, METH_NOARGS}, + {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, + {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, + {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, + {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS}, + + _IO__BUFFERED_READ_METHODDEF + _IO__BUFFERED_PEEK_METHODDEF + _IO__BUFFERED_READ1_METHODDEF + _IO__BUFFERED_READINTO_METHODDEF + _IO__BUFFERED_READINTO1_METHODDEF + _IO__BUFFERED_READLINE_METHODDEF + _IO__BUFFERED_SEEK_METHODDEF + {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, + _IO__BUFFERED_TRUNCATE_METHODDEF + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, + {NULL, NULL} +}; + +static PyMemberDef bufferedreader_members[] = { + {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, + {NULL} +}; + +static PyGetSetDef bufferedreader_getset[] = { + {"closed", (getter)buffered_closed_get, NULL, NULL}, + {"name", (getter)buffered_name_get, NULL, NULL}, + {"mode", (getter)buffered_mode_get, NULL, NULL}, + {NULL} +}; + + +PyTypeObject PyBufferedReader_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_io.BufferedReader", /*tp_name*/ + sizeof(buffered), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)buffered_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare */ + (reprfunc)buffered_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + _io_BufferedReader___init____doc__, /* tp_doc */ + (traverseproc)buffered_traverse, /* tp_traverse */ + (inquiry)buffered_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(buffered, weakreflist), /*tp_weaklistoffset*/ + 0, /* tp_iter */ + (iternextfunc)buffered_iternext, /* tp_iternext */ + bufferedreader_methods, /* tp_methods */ + bufferedreader_members, /* tp_members */ + bufferedreader_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(buffered, dict), /* tp_dictoffset */ + _io_BufferedReader___init__, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ +}; + + +static PyMethodDef bufferedwriter_methods[] = { + /* BufferedIOMixin methods */ + {"close", (PyCFunction)buffered_close, METH_NOARGS}, + {"detach", (PyCFunction)buffered_detach, METH_NOARGS}, + {"seekable", (PyCFunction)buffered_seekable, METH_NOARGS}, + {"readable", (PyCFunction)buffered_readable, METH_NOARGS}, + {"writable", (PyCFunction)buffered_writable, METH_NOARGS}, + {"fileno", (PyCFunction)buffered_fileno, METH_NOARGS}, + {"isatty", (PyCFunction)buffered_isatty, METH_NOARGS}, + {"_dealloc_warn", (PyCFunction)buffered_dealloc_warn, METH_O}, + {"__getstate__", (PyCFunction)buffered_getstate, METH_NOARGS}, + + _IO_BUFFEREDWRITER_WRITE_METHODDEF + _IO__BUFFERED_TRUNCATE_METHODDEF + {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, + _IO__BUFFERED_SEEK_METHODDEF + {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, + {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, + {NULL, NULL} +}; + +static PyMemberDef bufferedwriter_members[] = { + {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, + {"_finalizing", T_BOOL, offsetof(buffered, finalizing), 0}, + {NULL} +}; + +static PyGetSetDef bufferedwriter_getset[] = { + {"closed", (getter)buffered_closed_get, NULL, NULL}, + {"name", (getter)buffered_name_get, NULL, NULL}, + {"mode", (getter)buffered_mode_get, NULL, NULL}, + {NULL} +}; + + +PyTypeObject PyBufferedWriter_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_io.BufferedWriter", /*tp_name*/ + sizeof(buffered), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)buffered_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare */ + (reprfunc)buffered_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ + _io_BufferedWriter___init____doc__, /* tp_doc */ + (traverseproc)buffered_traverse, /* tp_traverse */ + (inquiry)buffered_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(buffered, weakreflist), /*tp_weaklistoffset*/ + 0, /* tp_iter */ + 0, /* tp_iternext */ + bufferedwriter_methods, /* tp_methods */ + bufferedwriter_members, /* tp_members */ + bufferedwriter_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(buffered, dict), /* tp_dictoffset */ + _io_BufferedWriter___init__, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ +}; + static PyMethodDef bufferedrwpair_methods[] = { {"read", (PyCFunction)bufferedrwpair_read, METH_VARARGS}, @@ -2521,7 +2619,7 @@ PyTypeObject PyBufferedRWPair_Type = { 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ - bufferedrwpair_doc, /* tp_doc */ + _io_BufferedRWPair___init____doc__, /* tp_doc */ (traverseproc)bufferedrwpair_traverse, /* tp_traverse */ (inquiry)bufferedrwpair_clear, /* tp_clear */ 0, /* tp_richcompare */ @@ -2536,7 +2634,7 @@ PyTypeObject PyBufferedRWPair_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(rwpair, dict), /* tp_dictoffset */ - (initproc)bufferedrwpair_init, /* tp_init */ + _io_BufferedRWPair___init__, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ 0, /* tp_free */ @@ -2550,62 +2648,7 @@ PyTypeObject PyBufferedRWPair_Type = { 0, /* tp_version_tag */ 0, /* tp_finalize */ }; - - - -/* - * BufferedRandom - */ - -PyDoc_STRVAR(bufferedrandom_doc, - "A buffered interface to random access streams.\n" - "\n" - "The constructor creates a reader and writer for a seekable stream,\n" - "raw, given in the first argument. If the buffer_size is omitted it\n" - "defaults to DEFAULT_BUFFER_SIZE.\n" - ); - -static int -bufferedrandom_init(buffered *self, PyObject *args, PyObject *kwds) -{ - char *kwlist[] = {"raw", "buffer_size", NULL}; - Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - PyObject *raw; - - self->ok = 0; - self->detached = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|n:BufferedRandom", kwlist, - &raw, &buffer_size)) { - return -1; - } - - if (_PyIOBase_check_seekable(raw, Py_True) == NULL) - return -1; - if (_PyIOBase_check_readable(raw, Py_True) == NULL) - return -1; - if (_PyIOBase_check_writable(raw, Py_True) == NULL) - return -1; - - Py_CLEAR(self->raw); - Py_INCREF(raw); - self->raw = raw; - self->buffer_size = buffer_size; - self->readable = 1; - self->writable = 1; - if (_buffered_init(self) < 0) - return -1; - _bufferedreader_reset_buf(self); - _bufferedwriter_reset_buf(self); - self->pos = 0; - - self->fast_closed_checks = (Py_TYPE(self) == &PyBufferedRandom_Type && - Py_TYPE(raw) == &PyFileIO_Type); - - self->ok = 1; - return 0; -} static PyMethodDef bufferedrandom_methods[] = { /* BufferedIOMixin methods */ @@ -2621,16 +2664,16 @@ static PyMethodDef bufferedrandom_methods[] = { {"flush", (PyCFunction)buffered_flush, METH_NOARGS}, - {"seek", (PyCFunction)buffered_seek, METH_VARARGS}, + _IO__BUFFERED_SEEK_METHODDEF {"tell", (PyCFunction)buffered_tell, METH_NOARGS}, - {"truncate", (PyCFunction)buffered_truncate, METH_VARARGS}, - {"read", (PyCFunction)buffered_read, METH_VARARGS}, - {"read1", (PyCFunction)buffered_read1, METH_VARARGS}, - {"readinto", (PyCFunction)buffered_readinto, METH_VARARGS}, - {"readinto1", (PyCFunction)buffered_readinto1, METH_VARARGS}, - {"readline", (PyCFunction)buffered_readline, METH_VARARGS}, - {"peek", (PyCFunction)buffered_peek, METH_VARARGS}, - {"write", (PyCFunction)bufferedwriter_write, METH_VARARGS}, + _IO__BUFFERED_TRUNCATE_METHODDEF + _IO__BUFFERED_READ_METHODDEF + _IO__BUFFERED_READ1_METHODDEF + _IO__BUFFERED_READINTO_METHODDEF + _IO__BUFFERED_READINTO1_METHODDEF + _IO__BUFFERED_READLINE_METHODDEF + _IO__BUFFERED_PEEK_METHODDEF + _IO_BUFFEREDWRITER_WRITE_METHODDEF {"__sizeof__", (PyCFunction)buffered_sizeof, METH_NOARGS}, {NULL, NULL} }; @@ -2671,7 +2714,7 @@ PyTypeObject PyBufferedRandom_Type = { 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ - bufferedrandom_doc, /* tp_doc */ + _io_BufferedRandom___init____doc__, /* tp_doc */ (traverseproc)buffered_traverse, /* tp_traverse */ (inquiry)buffered_clear, /* tp_clear */ 0, /* tp_richcompare */ @@ -2686,7 +2729,7 @@ PyTypeObject PyBufferedRandom_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(buffered, dict), /*tp_dictoffset*/ - (initproc)bufferedrandom_init, /* tp_init */ + _io_BufferedRandom___init__, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ 0, /* tp_free */ diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 974e33ac2a..42dfe2404a 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -2,6 +2,12 @@ #include "structmember.h" /* for offsetof() */ #include "_iomodule.h" +/*[clinic input] +module _io +class _io.BytesIO "bytesio *" "&PyBytesIO_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7f50ec034f5c0b26]*/ + typedef struct { PyObject_HEAD PyObject *buf; @@ -203,40 +209,71 @@ bytesio_get_closed(bytesio *self) } } -PyDoc_STRVAR(readable_doc, -"readable() -> bool. Returns True if the IO object can be read."); +/*[clinic input] +_io.BytesIO.readable -PyDoc_STRVAR(writable_doc, -"writable() -> bool. Returns True if the IO object can be written."); +Returns True if the IO object can be read. +[clinic start generated code]*/ -PyDoc_STRVAR(seekable_doc, -"seekable() -> bool. Returns True if the IO object can be seeked."); +static PyObject * +_io_BytesIO_readable_impl(bytesio *self) +/*[clinic end generated code: output=4e93822ad5b62263 input=96c5d0cccfb29f5c]*/ +{ + CHECK_CLOSED(self); + Py_RETURN_TRUE; +} + +/*[clinic input] +_io.BytesIO.writable + +Returns True if the IO object can be written. +[clinic start generated code]*/ -/* Generic getter for the writable, readable and seekable properties */ static PyObject * -return_not_closed(bytesio *self) +_io_BytesIO_writable_impl(bytesio *self) +/*[clinic end generated code: output=64ff6a254b1150b8 input=700eed808277560a]*/ { CHECK_CLOSED(self); Py_RETURN_TRUE; } -PyDoc_STRVAR(flush_doc, -"flush() -> None. Does nothing."); +/*[clinic input] +_io.BytesIO.seekable + +Returns True if the IO object can be seeked. +[clinic start generated code]*/ + +static PyObject * +_io_BytesIO_seekable_impl(bytesio *self) +/*[clinic end generated code: output=6b417f46dcc09b56 input=9421f65627a344dd]*/ +{ + CHECK_CLOSED(self); + Py_RETURN_TRUE; +} + +/*[clinic input] +_io.BytesIO.flush + +Does nothing. +[clinic start generated code]*/ static PyObject * -bytesio_flush(bytesio *self) +_io_BytesIO_flush_impl(bytesio *self) +/*[clinic end generated code: output=187e3d781ca134a0 input=561ea490be4581a7]*/ { CHECK_CLOSED(self); Py_RETURN_NONE; } -PyDoc_STRVAR(getbuffer_doc, -"getbuffer() -> bytes.\n" -"\n" -"Get a read-write view over the contents of the BytesIO object."); +/*[clinic input] +_io.BytesIO.getbuffer + +Get a read-write view over the contents of the BytesIO object. +[clinic start generated code]*/ static PyObject * -bytesio_getbuffer(bytesio *self) +_io_BytesIO_getbuffer_impl(bytesio *self) +/*[clinic end generated code: output=72cd7c6e13aa09ed input=8f738ef615865176]*/ { PyTypeObject *type = &_PyBytesIOBuffer_Type; bytesiobuf *buf; @@ -254,13 +291,15 @@ bytesio_getbuffer(bytesio *self) return view; } -PyDoc_STRVAR(getval_doc, -"getvalue() -> bytes.\n" -"\n" -"Retrieve the entire contents of the BytesIO object."); +/*[clinic input] +_io.BytesIO.getvalue + +Retrieve the entire contents of the BytesIO object. +[clinic start generated code]*/ static PyObject * -bytesio_getvalue(bytesio *self) +_io_BytesIO_getvalue_impl(bytesio *self) +/*[clinic end generated code: output=b3f6a3233c8fd628 input=4b403ac0af3973ed]*/ { CHECK_CLOSED(self); if (self->string_size <= 1 || self->exports > 0) @@ -281,24 +320,31 @@ bytesio_getvalue(bytesio *self) return self->buf; } -PyDoc_STRVAR(isatty_doc, -"isatty() -> False.\n" -"\n" -"Always returns False since BytesIO objects are not connected\n" -"to a tty-like device."); +/*[clinic input] +_io.BytesIO.isatty + +Always returns False. + +BytesIO objects are not connected to a TTY-like device. +[clinic start generated code]*/ static PyObject * -bytesio_isatty(bytesio *self) +_io_BytesIO_isatty_impl(bytesio *self) +/*[clinic end generated code: output=df67712e669f6c8f input=6f97f0985d13f827]*/ { CHECK_CLOSED(self); Py_RETURN_FALSE; } -PyDoc_STRVAR(tell_doc, -"tell() -> current file position, an integer\n"); +/*[clinic input] +_io.BytesIO.tell + +Current file position, an integer. +[clinic start generated code]*/ static PyObject * -bytesio_tell(bytesio *self) +_io_BytesIO_tell_impl(bytesio *self) +/*[clinic end generated code: output=b54b0f93cd0e5e1d input=b106adf099cb3657]*/ { CHECK_CLOSED(self); return PyLong_FromSsize_t(self->pos); @@ -324,23 +370,25 @@ read_bytes(bytesio *self, Py_ssize_t size) return PyBytes_FromStringAndSize(output, size); } -PyDoc_STRVAR(read_doc, -"read([size]) -> read at most size bytes, returned as a bytes object.\n" -"\n" -"If the size argument is negative, read until EOF is reached.\n" -"Return an empty bytes object at EOF."); +/*[clinic input] +_io.BytesIO.read + size as arg: object = None + / + +Read at most size bytes, returned as a bytes object. + +If the size argument is negative, read until EOF is reached. +Return an empty bytes object at EOF. +[clinic start generated code]*/ static PyObject * -bytesio_read(bytesio *self, PyObject *args) +_io_BytesIO_read_impl(bytesio *self, PyObject *arg) +/*[clinic end generated code: output=85dacb535c1e1781 input=cc7ba4a797bb1555]*/ { Py_ssize_t size, n; - PyObject *arg = Py_None; CHECK_CLOSED(self); - if (!PyArg_ParseTuple(args, "|O:read", &arg)) - return NULL; - if (PyLong_Check(arg)) { size = PyLong_AsSsize_t(arg); if (size == -1 && PyErr_Occurred()) @@ -368,43 +416,44 @@ bytesio_read(bytesio *self, PyObject *args) } -PyDoc_STRVAR(read1_doc, -"read1(size) -> read at most size bytes, returned as a bytes object.\n" -"\n" -"If the size argument is negative or omitted, read until EOF is reached.\n" -"Return an empty bytes object at EOF."); +/*[clinic input] +_io.BytesIO.read1 + size: object + / + +Read at most size bytes, returned as a bytes object. + +If the size argument is negative or omitted, read until EOF is reached. +Return an empty bytes object at EOF. +[clinic start generated code]*/ static PyObject * -bytesio_read1(bytesio *self, PyObject *n) +_io_BytesIO_read1(bytesio *self, PyObject *size) +/*[clinic end generated code: output=16021f5d0ac3d4e2 input=d4f40bb8f2f99418]*/ { - PyObject *arg, *res; - - arg = PyTuple_Pack(1, n); - if (arg == NULL) - return NULL; - res = bytesio_read(self, arg); - Py_DECREF(arg); - return res; + return _io_BytesIO_read_impl(self, size); } -PyDoc_STRVAR(readline_doc, -"readline([size]) -> next line from the file, as a bytes object.\n" -"\n" -"Retain newline. A non-negative size argument limits the maximum\n" -"number of bytes to return (an incomplete line may be returned then).\n" -"Return an empty bytes object at EOF.\n"); +/*[clinic input] +_io.BytesIO.readline + size as arg: object = None + / + +Next line from the file, as a bytes object. + +Retain newline. A non-negative size argument limits the maximum +number of bytes to return (an incomplete line may be returned then). +Return an empty bytes object at EOF. +[clinic start generated code]*/ static PyObject * -bytesio_readline(bytesio *self, PyObject *args) +_io_BytesIO_readline_impl(bytesio *self, PyObject *arg) +/*[clinic end generated code: output=1c2115534a4f9276 input=ca31f06de6eab257]*/ { Py_ssize_t size, n; - PyObject *arg = Py_None; CHECK_CLOSED(self); - if (!PyArg_ParseTuple(args, "|O:readline", &arg)) - return NULL; - if (PyLong_Check(arg)) { size = PyLong_AsSsize_t(arg); if (size == -1 && PyErr_Occurred()) @@ -425,26 +474,28 @@ bytesio_readline(bytesio *self, PyObject *args) return read_bytes(self, n); } -PyDoc_STRVAR(readlines_doc, -"readlines([size]) -> list of strings, each a line from the file.\n" -"\n" -"Call readline() repeatedly and return a list of the lines so read.\n" -"The optional size argument, if given, is an approximate bound on the\n" -"total number of bytes in the lines returned.\n"); +/*[clinic input] +_io.BytesIO.readlines + size as arg: object = None + / + +List of bytes objects, each a line from the file. + +Call readline() repeatedly and return a list of the lines so read. +The optional size argument, if given, is an approximate bound on the +total number of bytes in the lines returned. +[clinic start generated code]*/ static PyObject * -bytesio_readlines(bytesio *self, PyObject *args) +_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg) +/*[clinic end generated code: output=09b8e34c880808ff input=691aa1314f2c2a87]*/ { Py_ssize_t maxsize, size, n; PyObject *result, *line; char *output; - PyObject *arg = Py_None; CHECK_CLOSED(self); - if (!PyArg_ParseTuple(args, "|O:readlines", &arg)) - return NULL; - if (PyLong_Check(arg)) { maxsize = PyLong_AsSsize_t(arg); if (maxsize == -1 && PyErr_Occurred()) @@ -488,25 +539,27 @@ bytesio_readlines(bytesio *self, PyObject *args) return NULL; } -PyDoc_STRVAR(readinto_doc, -"readinto(bytearray) -> int. Read up to len(b) bytes into b.\n" -"\n" -"Returns number of bytes read (0 for EOF), or None if the object\n" -"is set not to block as has no data to read."); +/*[clinic input] +_io.BytesIO.readinto + buffer: Py_buffer(types={'rwbuffer'}) + / + +Read up to len(buffer) bytes into buffer. + +Returns number of bytes read (0 for EOF), or None if the object +is set not to block as has no data to read. +[clinic start generated code]*/ static PyObject * -bytesio_readinto(bytesio *self, PyObject *arg) +_io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer) +/*[clinic end generated code: output=a5d407217dcf0639 input=d289da851c7c4159]*/ { - Py_buffer buffer; Py_ssize_t len, n; CHECK_CLOSED(self); - if (!PyArg_Parse(arg, "w*", &buffer)) - return NULL; - /* adjust invalid sizes */ - len = buffer.len; + len = buffer->len; n = self->string_size - self->pos; if (len > n) { len = n; @@ -514,33 +567,34 @@ bytesio_readinto(bytesio *self, PyObject *arg) len = 0; } - memcpy(buffer.buf, PyBytes_AS_STRING(self->buf) + self->pos, len); + memcpy(buffer->buf, PyBytes_AS_STRING(self->buf) + self->pos, len); assert(self->pos + len < PY_SSIZE_T_MAX); assert(len >= 0); self->pos += len; - PyBuffer_Release(&buffer); return PyLong_FromSsize_t(len); } -PyDoc_STRVAR(truncate_doc, -"truncate([size]) -> int. Truncate the file to at most size bytes.\n" -"\n" -"Size defaults to the current file position, as returned by tell().\n" -"The current file position is unchanged. Returns the new size.\n"); +/*[clinic input] +_io.BytesIO.truncate + size as arg: object = None + / + +Truncate the file to at most size bytes. + +Size defaults to the current file position, as returned by tell(). +The current file position is unchanged. Returns the new size. +[clinic start generated code]*/ static PyObject * -bytesio_truncate(bytesio *self, PyObject *args) +_io_BytesIO_truncate_impl(bytesio *self, PyObject *arg) +/*[clinic end generated code: output=81e6be60e67ddd66 input=11ed1966835462ba]*/ { Py_ssize_t size; - PyObject *arg = Py_None; CHECK_CLOSED(self); CHECK_EXPORTS(self); - if (!PyArg_ParseTuple(args, "|O:truncate", &arg)) - return NULL; - if (PyLong_Check(arg)) { size = PyLong_AsSsize_t(arg); if (size == -1 && PyErr_Occurred()) @@ -586,36 +640,37 @@ bytesio_iternext(bytesio *self) return read_bytes(self, n); } -PyDoc_STRVAR(seek_doc, -"seek(pos, whence=0) -> int. Change stream position.\n" -"\n" -"Seek to byte offset pos relative to position indicated by whence:\n" -" 0 Start of stream (the default). pos should be >= 0;\n" -" 1 Current position - pos may be negative;\n" -" 2 End of stream - pos usually negative.\n" -"Returns the new absolute position."); +/*[clinic input] +_io.BytesIO.seek + pos: Py_ssize_t + whence: int = 0 + / + +Change stream position. + +Seek to byte offset pos relative to position indicated by whence: + 0 Start of stream (the default). pos should be >= 0; + 1 Current position - pos may be negative; + 2 End of stream - pos usually negative. +Returns the new absolute position. +[clinic start generated code]*/ static PyObject * -bytesio_seek(bytesio *self, PyObject *args) +_io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence) +/*[clinic end generated code: output=c26204a68e9190e4 input=1e875e6ebc652948]*/ { - Py_ssize_t pos; - int mode = 0; - CHECK_CLOSED(self); - if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode)) - return NULL; - - if (pos < 0 && mode == 0) { + if (pos < 0 && whence == 0) { PyErr_Format(PyExc_ValueError, "negative seek value %zd", pos); return NULL; } - /* mode 0: offset relative to beginning of the string. - mode 1: offset relative to current position. - mode 2: offset relative the end of the string. */ - if (mode == 1) { + /* whence = 0: offset relative to beginning of the string. + whence = 1: offset relative to current position. + whence = 2: offset relative the end of the string. */ + if (whence == 1) { if (pos > PY_SSIZE_T_MAX - self->pos) { PyErr_SetString(PyExc_OverflowError, "new position too large"); @@ -623,7 +678,7 @@ bytesio_seek(bytesio *self, PyObject *args) } pos += self->pos; } - else if (mode == 2) { + else if (whence == 2) { if (pos > PY_SSIZE_T_MAX - self->string_size) { PyErr_SetString(PyExc_OverflowError, "new position too large"); @@ -631,9 +686,9 @@ bytesio_seek(bytesio *self, PyObject *args) } pos += self->string_size; } - else if (mode != 0) { + else if (whence != 0) { PyErr_Format(PyExc_ValueError, - "invalid whence (%i, should be 0, 1 or 2)", mode); + "invalid whence (%i, should be 0, 1 or 2)", whence); return NULL; } @@ -644,54 +699,63 @@ bytesio_seek(bytesio *self, PyObject *args) return PyLong_FromSsize_t(self->pos); } -PyDoc_STRVAR(write_doc, -"write(bytes) -> int. Write bytes to file.\n" -"\n" -"Return the number of bytes written."); +/*[clinic input] +_io.BytesIO.write + b: object + / + +Write bytes to file. + +Return the number of bytes written. +[clinic start generated code]*/ static PyObject * -bytesio_write(bytesio *self, PyObject *obj) +_io_BytesIO_write(bytesio *self, PyObject *b) +/*[clinic end generated code: output=53316d99800a0b95 input=f5ec7c8c64ed720a]*/ { Py_ssize_t n = 0; Py_buffer buf; - PyObject *result = NULL; CHECK_CLOSED(self); CHECK_EXPORTS(self); - if (PyObject_GetBuffer(obj, &buf, PyBUF_CONTIG_RO) < 0) + if (PyObject_GetBuffer(b, &buf, PyBUF_CONTIG_RO) < 0) return NULL; if (buf.len != 0) n = write_bytes(self, buf.buf, buf.len); - if (n >= 0) - result = PyLong_FromSsize_t(n); PyBuffer_Release(&buf); - return result; + return n >= 0 ? PyLong_FromSsize_t(n) : NULL; } -PyDoc_STRVAR(writelines_doc, -"writelines(lines) -> None. Write bytes objects to the file.\n" -"\n" -"Note that newlines are not added. The argument can be any iterable\n" -"object producing bytes objects. This is equivalent to calling write() for\n" -"each bytes object."); +/*[clinic input] +_io.BytesIO.writelines + lines: object + / + +Write lines to the file. + +Note that newlines are not added. lines can be any iterable object +producing bytes-like objects. This is equivalent to calling write() for +each element. +[clinic start generated code]*/ static PyObject * -bytesio_writelines(bytesio *self, PyObject *v) +_io_BytesIO_writelines(bytesio *self, PyObject *lines) +/*[clinic end generated code: output=7f33aa3271c91752 input=e972539176fc8fc1]*/ { PyObject *it, *item; PyObject *ret; CHECK_CLOSED(self); - it = PyObject_GetIter(v); + it = PyObject_GetIter(lines); if (it == NULL) return NULL; while ((item = PyIter_Next(it)) != NULL) { - ret = bytesio_write(self, item); + ret = _io_BytesIO_write(self, item); Py_DECREF(item); if (ret == NULL) { Py_DECREF(it); @@ -708,11 +772,15 @@ bytesio_writelines(bytesio *self, PyObject *v) Py_RETURN_NONE; } -PyDoc_STRVAR(close_doc, -"close() -> None. Disable all I/O operations."); +/*[clinic input] +_io.BytesIO.close + +Disable all I/O operations. +[clinic start generated code]*/ static PyObject * -bytesio_close(bytesio *self) +_io_BytesIO_close_impl(bytesio *self) +/*[clinic end generated code: output=1471bb9411af84a0 input=37e1f55556e61f60]*/ { CHECK_EXPORTS(self); Py_CLEAR(self->buf); @@ -737,7 +805,7 @@ bytesio_close(bytesio *self) static PyObject * bytesio_getstate(bytesio *self) { - PyObject *initvalue = bytesio_getvalue(self); + PyObject *initvalue = _io_BytesIO_getvalue_impl(self); PyObject *dict; PyObject *state; @@ -787,7 +855,7 @@ bytesio_setstate(bytesio *self, PyObject *state) /* Set the value of the internal buffer. If state[0] does not support the buffer protocol, bytesio_write will raise the appropriate TypeError. */ - result = bytesio_write(self, PyTuple_GET_ITEM(state, 0)); + result = _io_BytesIO_write(self, PyTuple_GET_ITEM(state, 0)); if (result == NULL) return NULL; Py_DECREF(result); @@ -874,16 +942,17 @@ bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)self; } -static int -bytesio_init(bytesio *self, PyObject *args, PyObject *kwds) -{ - char *kwlist[] = {"initial_bytes", NULL}; - PyObject *initvalue = NULL; +/*[clinic input] +_io.BytesIO.__init__ + initial_bytes as initvalue: object(c_default="NULL") = b'' - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:BytesIO", kwlist, - &initvalue)) - return -1; +Buffered I/O implementation using an in-memory bytes buffer. +[clinic start generated code]*/ +static int +_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue) +/*[clinic end generated code: output=65c0c51e24c5b621 input=aac7f31b67bf0fb6]*/ +{ /* In case, __init__ is called multiple times. */ self->string_size = 0; self->pos = 0; @@ -902,7 +971,7 @@ bytesio_init(bytesio *self, PyObject *args, PyObject *kwds) } else { PyObject *res; - res = bytesio_write(self, initvalue); + res = _io_BytesIO_write(self, initvalue); if (res == NULL) return -1; Py_DECREF(res); @@ -939,6 +1008,8 @@ bytesio_clear(bytesio *self) } +#include "clinic/bytesio.c.h" + static PyGetSetDef bytesio_getsetlist[] = { {"closed", (getter)bytesio_get_closed, NULL, "True if the file is closed."}, @@ -946,36 +1017,30 @@ static PyGetSetDef bytesio_getsetlist[] = { }; static struct PyMethodDef bytesio_methods[] = { - {"readable", (PyCFunction)return_not_closed, METH_NOARGS, readable_doc}, - {"seekable", (PyCFunction)return_not_closed, METH_NOARGS, seekable_doc}, - {"writable", (PyCFunction)return_not_closed, METH_NOARGS, writable_doc}, - {"close", (PyCFunction)bytesio_close, METH_NOARGS, close_doc}, - {"flush", (PyCFunction)bytesio_flush, METH_NOARGS, flush_doc}, - {"isatty", (PyCFunction)bytesio_isatty, METH_NOARGS, isatty_doc}, - {"tell", (PyCFunction)bytesio_tell, METH_NOARGS, tell_doc}, - {"write", (PyCFunction)bytesio_write, METH_O, write_doc}, - {"writelines", (PyCFunction)bytesio_writelines, METH_O, writelines_doc}, - {"read1", (PyCFunction)bytesio_read1, METH_O, read1_doc}, - {"readinto", (PyCFunction)bytesio_readinto, METH_O, readinto_doc}, - {"readline", (PyCFunction)bytesio_readline, METH_VARARGS, readline_doc}, - {"readlines", (PyCFunction)bytesio_readlines, METH_VARARGS, readlines_doc}, - {"read", (PyCFunction)bytesio_read, METH_VARARGS, read_doc}, - {"getbuffer", (PyCFunction)bytesio_getbuffer, METH_NOARGS, getbuffer_doc}, - {"getvalue", (PyCFunction)bytesio_getvalue, METH_NOARGS, getval_doc}, - {"seek", (PyCFunction)bytesio_seek, METH_VARARGS, seek_doc}, - {"truncate", (PyCFunction)bytesio_truncate, METH_VARARGS, truncate_doc}, + _IO_BYTESIO_READABLE_METHODDEF + _IO_BYTESIO_SEEKABLE_METHODDEF + _IO_BYTESIO_WRITABLE_METHODDEF + _IO_BYTESIO_CLOSE_METHODDEF + _IO_BYTESIO_FLUSH_METHODDEF + _IO_BYTESIO_ISATTY_METHODDEF + _IO_BYTESIO_TELL_METHODDEF + _IO_BYTESIO_WRITE_METHODDEF + _IO_BYTESIO_WRITELINES_METHODDEF + _IO_BYTESIO_READ1_METHODDEF + _IO_BYTESIO_READINTO_METHODDEF + _IO_BYTESIO_READLINE_METHODDEF + _IO_BYTESIO_READLINES_METHODDEF + _IO_BYTESIO_READ_METHODDEF + _IO_BYTESIO_GETBUFFER_METHODDEF + _IO_BYTESIO_GETVALUE_METHODDEF + _IO_BYTESIO_SEEK_METHODDEF + _IO_BYTESIO_TRUNCATE_METHODDEF {"__getstate__", (PyCFunction)bytesio_getstate, METH_NOARGS, NULL}, {"__setstate__", (PyCFunction)bytesio_setstate, METH_O, NULL}, {"__sizeof__", (PyCFunction)bytesio_sizeof, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; -PyDoc_STRVAR(bytesio_doc, -"BytesIO([buffer]) -> object\n" -"\n" -"Create a buffered I/O implementation using an in-memory bytes\n" -"buffer, ready for reading and writing."); - PyTypeObject PyBytesIO_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_io.BytesIO", /*tp_name*/ @@ -998,7 +1063,7 @@ PyTypeObject PyBytesIO_Type = { 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - bytesio_doc, /*tp_doc*/ + _io_BytesIO___init____doc__, /*tp_doc*/ (traverseproc)bytesio_traverse, /*tp_traverse*/ (inquiry)bytesio_clear, /*tp_clear*/ 0, /*tp_richcompare*/ @@ -1013,7 +1078,7 @@ PyTypeObject PyBytesIO_Type = { 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ offsetof(bytesio, dict), /*tp_dictoffset*/ - (initproc)bytesio_init, /*tp_init*/ + _io_BytesIO___init__, /*tp_init*/ 0, /*tp_alloc*/ bytesio_new, /*tp_new*/ }; diff --git a/Modules/_io/clinic/_iomodule.c.h b/Modules/_io/clinic/_iomodule.c.h new file mode 100644 index 0000000000..df877a5b28 --- /dev/null +++ b/Modules/_io/clinic/_iomodule.c.h @@ -0,0 +1,160 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_io_open__doc__, +"open($module, /, file, mode=\'r\', buffering=-1, encoding=None,\n" +" errors=None, newline=None, closefd=True, opener=None)\n" +"--\n" +"\n" +"Open file and return a stream. Raise IOError upon failure.\n" +"\n" +"file is either a text or byte string giving the name (and the path\n" +"if the file isn\'t in the current working directory) of the file to\n" +"be opened or an integer file descriptor of the file to be\n" +"wrapped. (If a file descriptor is given, it is closed when the\n" +"returned I/O object is closed, unless closefd is set to False.)\n" +"\n" +"mode is an optional string that specifies the mode in which the file\n" +"is opened. It defaults to \'r\' which means open for reading in text\n" +"mode. Other common values are \'w\' for writing (truncating the file if\n" +"it already exists), \'x\' for creating and writing to a new file, and\n" +"\'a\' for appending (which on some Unix systems, means that all writes\n" +"append to the end of the file regardless of the current seek position).\n" +"In text mode, if encoding is not specified the encoding used is platform\n" +"dependent: locale.getpreferredencoding(False) is called to get the\n" +"current locale encoding. (For reading and writing raw bytes use binary\n" +"mode and leave encoding unspecified.) The available modes are:\n" +"\n" +"========= ===============================================================\n" +"Character Meaning\n" +"--------- ---------------------------------------------------------------\n" +"\'r\' open for reading (default)\n" +"\'w\' open for writing, truncating the file first\n" +"\'x\' create a new file and open it for writing\n" +"\'a\' open for writing, appending to the end of the file if it exists\n" +"\'b\' binary mode\n" +"\'t\' text mode (default)\n" +"\'+\' open a disk file for updating (reading and writing)\n" +"\'U\' universal newline mode (deprecated)\n" +"========= ===============================================================\n" +"\n" +"The default mode is \'rt\' (open for reading text). For binary random\n" +"access, the mode \'w+b\' opens and truncates the file to 0 bytes, while\n" +"\'r+b\' opens the file without truncation. The \'x\' mode implies \'w\' and\n" +"raises an `FileExistsError` if the file already exists.\n" +"\n" +"Python distinguishes between files opened in binary and text modes,\n" +"even when the underlying operating system doesn\'t. Files opened in\n" +"binary mode (appending \'b\' to the mode argument) return contents as\n" +"bytes objects without any decoding. In text mode (the default, or when\n" +"\'t\' is appended to the mode argument), the contents of the file are\n" +"returned as strings, the bytes having been first decoded using a\n" +"platform-dependent encoding or using the specified encoding if given.\n" +"\n" +"\'U\' mode is deprecated and will raise an exception in future versions\n" +"of Python. It has no effect in Python 3. Use newline to control\n" +"universal newlines mode.\n" +"\n" +"buffering is an optional integer used to set the buffering policy.\n" +"Pass 0 to switch buffering off (only allowed in binary mode), 1 to select\n" +"line buffering (only usable in text mode), and an integer > 1 to indicate\n" +"the size of a fixed-size chunk buffer. When no buffering argument is\n" +"given, the default buffering policy works as follows:\n" +"\n" +"* Binary files are buffered in fixed-size chunks; the size of the buffer\n" +" is chosen using a heuristic trying to determine the underlying device\'s\n" +" \"block size\" and falling back on `io.DEFAULT_BUFFER_SIZE`.\n" +" On many systems, the buffer will typically be 4096 or 8192 bytes long.\n" +"\n" +"* \"Interactive\" text files (files for which isatty() returns True)\n" +" use line buffering. Other text files use the policy described above\n" +" for binary files.\n" +"\n" +"encoding is the name of the encoding used to decode or encode the\n" +"file. This should only be used in text mode. The default encoding is\n" +"platform dependent, but any encoding supported by Python can be\n" +"passed. See the codecs module for the list of supported encodings.\n" +"\n" +"errors is an optional string that specifies how encoding errors are to\n" +"be handled---this argument should not be used in binary mode. Pass\n" +"\'strict\' to raise a ValueError exception if there is an encoding error\n" +"(the default of None has the same effect), or pass \'ignore\' to ignore\n" +"errors. (Note that ignoring encoding errors can lead to data loss.)\n" +"See the documentation for codecs.register or run \'help(codecs.Codec)\'\n" +"for a list of the permitted encoding error strings.\n" +"\n" +"newline controls how universal newlines works (it only applies to text\n" +"mode). It can be None, \'\', \'\\n\', \'\\r\', and \'\\r\\n\'. It works as\n" +"follows:\n" +"\n" +"* On input, if newline is None, universal newlines mode is\n" +" enabled. Lines in the input can end in \'\\n\', \'\\r\', or \'\\r\\n\', and\n" +" these are translated into \'\\n\' before being returned to the\n" +" caller. If it is \'\', universal newline mode is enabled, but line\n" +" endings are returned to the caller untranslated. If it has any of\n" +" the other legal values, input lines are only terminated by the given\n" +" string, and the line ending is returned to the caller untranslated.\n" +"\n" +"* On output, if newline is None, any \'\\n\' characters written are\n" +" translated to the system default line separator, os.linesep. If\n" +" newline is \'\' or \'\\n\', no translation takes place. If newline is any\n" +" of the other legal values, any \'\\n\' characters written are translated\n" +" to the given string.\n" +"\n" +"If closefd is False, the underlying file descriptor will be kept open\n" +"when the file is closed. This does not work when a file name is given\n" +"and must be True in that case.\n" +"\n" +"A custom opener can be used by passing a callable as *opener*. The\n" +"underlying file descriptor for the file object is then obtained by\n" +"calling *opener* with (*file*, *flags*). *opener* must return an open\n" +"file descriptor (passing os.open as *opener* results in functionality\n" +"similar to passing None).\n" +"\n" +"open() returns a file object whose type depends on the mode, and\n" +"through which the standard file operations such as reading and writing\n" +"are performed. When open() is used to open a file in a text mode (\'w\',\n" +"\'r\', \'wt\', \'rt\', etc.), it returns a TextIOWrapper. When used to open\n" +"a file in a binary mode, the returned class varies: in read binary\n" +"mode, it returns a BufferedReader; in write binary and append binary\n" +"modes, it returns a BufferedWriter, and in read/write mode, it returns\n" +"a BufferedRandom.\n" +"\n" +"It is also possible to use a string or bytearray as a file for both\n" +"reading and writing. For strings StringIO can be used like a file\n" +"opened in a text mode, and for bytes a BytesIO can be used like a file\n" +"opened in a binary mode."); + +#define _IO_OPEN_METHODDEF \ + {"open", (PyCFunction)_io_open, METH_VARARGS|METH_KEYWORDS, _io_open__doc__}, + +static PyObject * +_io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, + int buffering, const char *encoding, const char *errors, + const char *newline, int closefd, PyObject *opener); + +static PyObject * +_io_open(PyModuleDef *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"file", "mode", "buffering", "encoding", "errors", "newline", "closefd", "opener", NULL}; + PyObject *file; + const char *mode = "r"; + int buffering = -1; + const char *encoding = NULL; + const char *errors = NULL; + const char *newline = NULL; + int closefd = 1; + PyObject *opener = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|sizzziO:open", _keywords, + &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener)) + goto exit; + return_value = _io_open_impl(module, file, mode, buffering, encoding, errors, newline, closefd, opener); + +exit: + return return_value; +} +/*[clinic end generated code: output=c51a5a443c11f02b input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h new file mode 100644 index 0000000000..b79b8d56c4 --- /dev/null +++ b/Modules/_io/clinic/bufferedio.c.h @@ -0,0 +1,474 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_io__BufferedIOBase_readinto__doc__, +"readinto($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFEREDIOBASE_READINTO_METHODDEF \ + {"readinto", (PyCFunction)_io__BufferedIOBase_readinto, METH_O, _io__BufferedIOBase_readinto__doc__}, + +static PyObject * +_io__BufferedIOBase_readinto_impl(PyObject *self, Py_buffer *buffer); + +static PyObject * +_io__BufferedIOBase_readinto(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, + "w*:readinto", + &buffer)) + goto exit; + return_value = _io__BufferedIOBase_readinto_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) + PyBuffer_Release(&buffer); + + return return_value; +} + +PyDoc_STRVAR(_io__BufferedIOBase_readinto1__doc__, +"readinto1($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFEREDIOBASE_READINTO1_METHODDEF \ + {"readinto1", (PyCFunction)_io__BufferedIOBase_readinto1, METH_O, _io__BufferedIOBase_readinto1__doc__}, + +static PyObject * +_io__BufferedIOBase_readinto1_impl(PyObject *self, Py_buffer *buffer); + +static PyObject * +_io__BufferedIOBase_readinto1(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, + "w*:readinto1", + &buffer)) + goto exit; + return_value = _io__BufferedIOBase_readinto1_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) + PyBuffer_Release(&buffer); + + return return_value; +} + +PyDoc_STRVAR(_io__BufferedIOBase_detach__doc__, +"detach($self, /)\n" +"--\n" +"\n" +"Disconnect this buffer from its underlying raw stream and return it.\n" +"\n" +"After the raw stream has been detached, the buffer is in an unusable\n" +"state."); + +#define _IO__BUFFEREDIOBASE_DETACH_METHODDEF \ + {"detach", (PyCFunction)_io__BufferedIOBase_detach, METH_NOARGS, _io__BufferedIOBase_detach__doc__}, + +static PyObject * +_io__BufferedIOBase_detach_impl(PyObject *self); + +static PyObject * +_io__BufferedIOBase_detach(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__BufferedIOBase_detach_impl(self); +} + +PyDoc_STRVAR(_io__Buffered_peek__doc__, +"peek($self, size=0, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_PEEK_METHODDEF \ + {"peek", (PyCFunction)_io__Buffered_peek, METH_VARARGS, _io__Buffered_peek__doc__}, + +static PyObject * +_io__Buffered_peek_impl(buffered *self, Py_ssize_t size); + +static PyObject * +_io__Buffered_peek(buffered *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t size = 0; + + if (!PyArg_ParseTuple(args, + "|n:peek", + &size)) + goto exit; + return_value = _io__Buffered_peek_impl(self, size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io__Buffered_read__doc__, +"read($self, size=-1, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_READ_METHODDEF \ + {"read", (PyCFunction)_io__Buffered_read, METH_VARARGS, _io__Buffered_read__doc__}, + +static PyObject * +_io__Buffered_read_impl(buffered *self, Py_ssize_t n); + +static PyObject * +_io__Buffered_read(buffered *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t n = -1; + + if (!PyArg_ParseTuple(args, + "|O&:read", + _PyIO_ConvertSsize_t, &n)) + goto exit; + return_value = _io__Buffered_read_impl(self, n); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io__Buffered_read1__doc__, +"read1($self, size, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_READ1_METHODDEF \ + {"read1", (PyCFunction)_io__Buffered_read1, METH_O, _io__Buffered_read1__doc__}, + +static PyObject * +_io__Buffered_read1_impl(buffered *self, Py_ssize_t n); + +static PyObject * +_io__Buffered_read1(buffered *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_ssize_t n; + + if (!PyArg_Parse(arg, + "n:read1", + &n)) + goto exit; + return_value = _io__Buffered_read1_impl(self, n); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io__Buffered_readinto__doc__, +"readinto($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_READINTO_METHODDEF \ + {"readinto", (PyCFunction)_io__Buffered_readinto, METH_O, _io__Buffered_readinto__doc__}, + +static PyObject * +_io__Buffered_readinto_impl(buffered *self, Py_buffer *buffer); + +static PyObject * +_io__Buffered_readinto(buffered *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, + "w*:readinto", + &buffer)) + goto exit; + return_value = _io__Buffered_readinto_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) + PyBuffer_Release(&buffer); + + return return_value; +} + +PyDoc_STRVAR(_io__Buffered_readinto1__doc__, +"readinto1($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_READINTO1_METHODDEF \ + {"readinto1", (PyCFunction)_io__Buffered_readinto1, METH_O, _io__Buffered_readinto1__doc__}, + +static PyObject * +_io__Buffered_readinto1_impl(buffered *self, Py_buffer *buffer); + +static PyObject * +_io__Buffered_readinto1(buffered *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, + "w*:readinto1", + &buffer)) + goto exit; + return_value = _io__Buffered_readinto1_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) + PyBuffer_Release(&buffer); + + return return_value; +} + +PyDoc_STRVAR(_io__Buffered_readline__doc__, +"readline($self, size=-1, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_READLINE_METHODDEF \ + {"readline", (PyCFunction)_io__Buffered_readline, METH_VARARGS, _io__Buffered_readline__doc__}, + +static PyObject * +_io__Buffered_readline_impl(buffered *self, Py_ssize_t size); + +static PyObject * +_io__Buffered_readline(buffered *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t size = -1; + + if (!PyArg_ParseTuple(args, + "|O&:readline", + _PyIO_ConvertSsize_t, &size)) + goto exit; + return_value = _io__Buffered_readline_impl(self, size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io__Buffered_seek__doc__, +"seek($self, target, whence=0, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_SEEK_METHODDEF \ + {"seek", (PyCFunction)_io__Buffered_seek, METH_VARARGS, _io__Buffered_seek__doc__}, + +static PyObject * +_io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence); + +static PyObject * +_io__Buffered_seek(buffered *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *targetobj; + int whence = 0; + + if (!PyArg_ParseTuple(args, + "O|i:seek", + &targetobj, &whence)) + goto exit; + return_value = _io__Buffered_seek_impl(self, targetobj, whence); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io__Buffered_truncate__doc__, +"truncate($self, pos=None, /)\n" +"--\n" +"\n"); + +#define _IO__BUFFERED_TRUNCATE_METHODDEF \ + {"truncate", (PyCFunction)_io__Buffered_truncate, METH_VARARGS, _io__Buffered_truncate__doc__}, + +static PyObject * +_io__Buffered_truncate_impl(buffered *self, PyObject *pos); + +static PyObject * +_io__Buffered_truncate(buffered *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *pos = Py_None; + + if (!PyArg_UnpackTuple(args, "truncate", + 0, 1, + &pos)) + goto exit; + return_value = _io__Buffered_truncate_impl(self, pos); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BufferedReader___init____doc__, +"BufferedReader(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n" +"--\n" +"\n" +"Create a new buffered reader using the given readable raw IO object."); + +static int +_io_BufferedReader___init___impl(buffered *self, PyObject *raw, + Py_ssize_t buffer_size); + +static int +_io_BufferedReader___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"raw", "buffer_size", NULL}; + PyObject *raw; + Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|n:BufferedReader", _keywords, + &raw, &buffer_size)) + goto exit; + return_value = _io_BufferedReader___init___impl((buffered *)self, raw, buffer_size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BufferedWriter___init____doc__, +"BufferedWriter(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n" +"--\n" +"\n" +"A buffer for a writeable sequential RawIO object.\n" +"\n" +"The constructor creates a BufferedWriter for the given writeable raw\n" +"stream. If the buffer_size is not given, it defaults to\n" +"DEFAULT_BUFFER_SIZE."); + +static int +_io_BufferedWriter___init___impl(buffered *self, PyObject *raw, + Py_ssize_t buffer_size); + +static int +_io_BufferedWriter___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"raw", "buffer_size", NULL}; + PyObject *raw; + Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|n:BufferedWriter", _keywords, + &raw, &buffer_size)) + goto exit; + return_value = _io_BufferedWriter___init___impl((buffered *)self, raw, buffer_size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BufferedWriter_write__doc__, +"write($self, buffer, /)\n" +"--\n" +"\n"); + +#define _IO_BUFFEREDWRITER_WRITE_METHODDEF \ + {"write", (PyCFunction)_io_BufferedWriter_write, METH_O, _io_BufferedWriter_write__doc__}, + +static PyObject * +_io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer); + +static PyObject * +_io_BufferedWriter_write(buffered *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, + "y*:write", + &buffer)) + goto exit; + return_value = _io_BufferedWriter_write_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) + PyBuffer_Release(&buffer); + + return return_value; +} + +PyDoc_STRVAR(_io_BufferedRWPair___init____doc__, +"BufferedRWPair(reader, writer, buffer_size=DEFAULT_BUFFER_SIZE, /)\n" +"--\n" +"\n" +"A buffered reader and writer object together.\n" +"\n" +"A buffered reader object and buffered writer object put together to\n" +"form a sequential IO object that can read and write. This is typically\n" +"used with a socket or two-way pipe.\n" +"\n" +"reader and writer are RawIOBase objects that are readable and\n" +"writeable respectively. If the buffer_size is omitted it defaults to\n" +"DEFAULT_BUFFER_SIZE."); + +static int +_io_BufferedRWPair___init___impl(rwpair *self, PyObject *reader, + PyObject *writer, Py_ssize_t buffer_size); + +static int +_io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + PyObject *reader; + PyObject *writer; + Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; + + if ((Py_TYPE(self) == &PyBufferedRWPair_Type) && + !_PyArg_NoKeywords("BufferedRWPair", kwargs)) + goto exit; + if (!PyArg_ParseTuple(args, + "OO|n:BufferedRWPair", + &reader, &writer, &buffer_size)) + goto exit; + return_value = _io_BufferedRWPair___init___impl((rwpair *)self, reader, writer, buffer_size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BufferedRandom___init____doc__, +"BufferedRandom(raw, buffer_size=DEFAULT_BUFFER_SIZE)\n" +"--\n" +"\n" +"A buffered interface to random access streams.\n" +"\n" +"The constructor creates a reader and writer for a seekable stream,\n" +"raw, given in the first argument. If the buffer_size is omitted it\n" +"defaults to DEFAULT_BUFFER_SIZE."); + +static int +_io_BufferedRandom___init___impl(buffered *self, PyObject *raw, + Py_ssize_t buffer_size); + +static int +_io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"raw", "buffer_size", NULL}; + PyObject *raw; + Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|n:BufferedRandom", _keywords, + &raw, &buffer_size)) + goto exit; + return_value = _io_BufferedRandom___init___impl((buffered *)self, raw, buffer_size); + +exit: + return return_value; +} +/*[clinic end generated code: output=78808e39f36e3fa9 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h new file mode 100644 index 0000000000..695c46a7b3 --- /dev/null +++ b/Modules/_io/clinic/bytesio.c.h @@ -0,0 +1,426 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_io_BytesIO_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n" +"Returns True if the IO object can be read."); + +#define _IO_BYTESIO_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io_BytesIO_readable, METH_NOARGS, _io_BytesIO_readable__doc__}, + +static PyObject * +_io_BytesIO_readable_impl(bytesio *self); + +static PyObject * +_io_BytesIO_readable(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_readable_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n" +"Returns True if the IO object can be written."); + +#define _IO_BYTESIO_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io_BytesIO_writable, METH_NOARGS, _io_BytesIO_writable__doc__}, + +static PyObject * +_io_BytesIO_writable_impl(bytesio *self); + +static PyObject * +_io_BytesIO_writable(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_writable_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO_seekable__doc__, +"seekable($self, /)\n" +"--\n" +"\n" +"Returns True if the IO object can be seeked."); + +#define _IO_BYTESIO_SEEKABLE_METHODDEF \ + {"seekable", (PyCFunction)_io_BytesIO_seekable, METH_NOARGS, _io_BytesIO_seekable__doc__}, + +static PyObject * +_io_BytesIO_seekable_impl(bytesio *self); + +static PyObject * +_io_BytesIO_seekable(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_seekable_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO_flush__doc__, +"flush($self, /)\n" +"--\n" +"\n" +"Does nothing."); + +#define _IO_BYTESIO_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_io_BytesIO_flush, METH_NOARGS, _io_BytesIO_flush__doc__}, + +static PyObject * +_io_BytesIO_flush_impl(bytesio *self); + +static PyObject * +_io_BytesIO_flush(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_flush_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO_getbuffer__doc__, +"getbuffer($self, /)\n" +"--\n" +"\n" +"Get a read-write view over the contents of the BytesIO object."); + +#define _IO_BYTESIO_GETBUFFER_METHODDEF \ + {"getbuffer", (PyCFunction)_io_BytesIO_getbuffer, METH_NOARGS, _io_BytesIO_getbuffer__doc__}, + +static PyObject * +_io_BytesIO_getbuffer_impl(bytesio *self); + +static PyObject * +_io_BytesIO_getbuffer(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_getbuffer_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO_getvalue__doc__, +"getvalue($self, /)\n" +"--\n" +"\n" +"Retrieve the entire contents of the BytesIO object."); + +#define _IO_BYTESIO_GETVALUE_METHODDEF \ + {"getvalue", (PyCFunction)_io_BytesIO_getvalue, METH_NOARGS, _io_BytesIO_getvalue__doc__}, + +static PyObject * +_io_BytesIO_getvalue_impl(bytesio *self); + +static PyObject * +_io_BytesIO_getvalue(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_getvalue_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO_isatty__doc__, +"isatty($self, /)\n" +"--\n" +"\n" +"Always returns False.\n" +"\n" +"BytesIO objects are not connected to a TTY-like device."); + +#define _IO_BYTESIO_ISATTY_METHODDEF \ + {"isatty", (PyCFunction)_io_BytesIO_isatty, METH_NOARGS, _io_BytesIO_isatty__doc__}, + +static PyObject * +_io_BytesIO_isatty_impl(bytesio *self); + +static PyObject * +_io_BytesIO_isatty(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_isatty_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO_tell__doc__, +"tell($self, /)\n" +"--\n" +"\n" +"Current file position, an integer."); + +#define _IO_BYTESIO_TELL_METHODDEF \ + {"tell", (PyCFunction)_io_BytesIO_tell, METH_NOARGS, _io_BytesIO_tell__doc__}, + +static PyObject * +_io_BytesIO_tell_impl(bytesio *self); + +static PyObject * +_io_BytesIO_tell(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_tell_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO_read__doc__, +"read($self, size=None, /)\n" +"--\n" +"\n" +"Read at most size bytes, returned as a bytes object.\n" +"\n" +"If the size argument is negative, read until EOF is reached.\n" +"Return an empty bytes object at EOF."); + +#define _IO_BYTESIO_READ_METHODDEF \ + {"read", (PyCFunction)_io_BytesIO_read, METH_VARARGS, _io_BytesIO_read__doc__}, + +static PyObject * +_io_BytesIO_read_impl(bytesio *self, PyObject *arg); + +static PyObject * +_io_BytesIO_read(bytesio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *arg = Py_None; + + if (!PyArg_UnpackTuple(args, "read", + 0, 1, + &arg)) + goto exit; + return_value = _io_BytesIO_read_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BytesIO_read1__doc__, +"read1($self, size, /)\n" +"--\n" +"\n" +"Read at most size bytes, returned as a bytes object.\n" +"\n" +"If the size argument is negative or omitted, read until EOF is reached.\n" +"Return an empty bytes object at EOF."); + +#define _IO_BYTESIO_READ1_METHODDEF \ + {"read1", (PyCFunction)_io_BytesIO_read1, METH_O, _io_BytesIO_read1__doc__}, + +PyDoc_STRVAR(_io_BytesIO_readline__doc__, +"readline($self, size=None, /)\n" +"--\n" +"\n" +"Next line from the file, as a bytes object.\n" +"\n" +"Retain newline. A non-negative size argument limits the maximum\n" +"number of bytes to return (an incomplete line may be returned then).\n" +"Return an empty bytes object at EOF."); + +#define _IO_BYTESIO_READLINE_METHODDEF \ + {"readline", (PyCFunction)_io_BytesIO_readline, METH_VARARGS, _io_BytesIO_readline__doc__}, + +static PyObject * +_io_BytesIO_readline_impl(bytesio *self, PyObject *arg); + +static PyObject * +_io_BytesIO_readline(bytesio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *arg = Py_None; + + if (!PyArg_UnpackTuple(args, "readline", + 0, 1, + &arg)) + goto exit; + return_value = _io_BytesIO_readline_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BytesIO_readlines__doc__, +"readlines($self, size=None, /)\n" +"--\n" +"\n" +"List of bytes objects, each a line from the file.\n" +"\n" +"Call readline() repeatedly and return a list of the lines so read.\n" +"The optional size argument, if given, is an approximate bound on the\n" +"total number of bytes in the lines returned."); + +#define _IO_BYTESIO_READLINES_METHODDEF \ + {"readlines", (PyCFunction)_io_BytesIO_readlines, METH_VARARGS, _io_BytesIO_readlines__doc__}, + +static PyObject * +_io_BytesIO_readlines_impl(bytesio *self, PyObject *arg); + +static PyObject * +_io_BytesIO_readlines(bytesio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *arg = Py_None; + + if (!PyArg_UnpackTuple(args, "readlines", + 0, 1, + &arg)) + goto exit; + return_value = _io_BytesIO_readlines_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BytesIO_readinto__doc__, +"readinto($self, buffer, /)\n" +"--\n" +"\n" +"Read up to len(buffer) bytes into buffer.\n" +"\n" +"Returns number of bytes read (0 for EOF), or None if the object\n" +"is set not to block as has no data to read."); + +#define _IO_BYTESIO_READINTO_METHODDEF \ + {"readinto", (PyCFunction)_io_BytesIO_readinto, METH_O, _io_BytesIO_readinto__doc__}, + +static PyObject * +_io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer); + +static PyObject * +_io_BytesIO_readinto(bytesio *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, + "w*:readinto", + &buffer)) + goto exit; + return_value = _io_BytesIO_readinto_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) + PyBuffer_Release(&buffer); + + return return_value; +} + +PyDoc_STRVAR(_io_BytesIO_truncate__doc__, +"truncate($self, size=None, /)\n" +"--\n" +"\n" +"Truncate the file to at most size bytes.\n" +"\n" +"Size defaults to the current file position, as returned by tell().\n" +"The current file position is unchanged. Returns the new size."); + +#define _IO_BYTESIO_TRUNCATE_METHODDEF \ + {"truncate", (PyCFunction)_io_BytesIO_truncate, METH_VARARGS, _io_BytesIO_truncate__doc__}, + +static PyObject * +_io_BytesIO_truncate_impl(bytesio *self, PyObject *arg); + +static PyObject * +_io_BytesIO_truncate(bytesio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *arg = Py_None; + + if (!PyArg_UnpackTuple(args, "truncate", + 0, 1, + &arg)) + goto exit; + return_value = _io_BytesIO_truncate_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BytesIO_seek__doc__, +"seek($self, pos, whence=0, /)\n" +"--\n" +"\n" +"Change stream position.\n" +"\n" +"Seek to byte offset pos relative to position indicated by whence:\n" +" 0 Start of stream (the default). pos should be >= 0;\n" +" 1 Current position - pos may be negative;\n" +" 2 End of stream - pos usually negative.\n" +"Returns the new absolute position."); + +#define _IO_BYTESIO_SEEK_METHODDEF \ + {"seek", (PyCFunction)_io_BytesIO_seek, METH_VARARGS, _io_BytesIO_seek__doc__}, + +static PyObject * +_io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence); + +static PyObject * +_io_BytesIO_seek(bytesio *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t pos; + int whence = 0; + + if (!PyArg_ParseTuple(args, + "n|i:seek", + &pos, &whence)) + goto exit; + return_value = _io_BytesIO_seek_impl(self, pos, whence); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_BytesIO_write__doc__, +"write($self, b, /)\n" +"--\n" +"\n" +"Write bytes to file.\n" +"\n" +"Return the number of bytes written."); + +#define _IO_BYTESIO_WRITE_METHODDEF \ + {"write", (PyCFunction)_io_BytesIO_write, METH_O, _io_BytesIO_write__doc__}, + +PyDoc_STRVAR(_io_BytesIO_writelines__doc__, +"writelines($self, lines, /)\n" +"--\n" +"\n" +"Write lines to the file.\n" +"\n" +"Note that newlines are not added. lines can be any iterable object\n" +"producing bytes-like objects. This is equivalent to calling write() for\n" +"each element."); + +#define _IO_BYTESIO_WRITELINES_METHODDEF \ + {"writelines", (PyCFunction)_io_BytesIO_writelines, METH_O, _io_BytesIO_writelines__doc__}, + +PyDoc_STRVAR(_io_BytesIO_close__doc__, +"close($self, /)\n" +"--\n" +"\n" +"Disable all I/O operations."); + +#define _IO_BYTESIO_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io_BytesIO_close, METH_NOARGS, _io_BytesIO_close__doc__}, + +static PyObject * +_io_BytesIO_close_impl(bytesio *self); + +static PyObject * +_io_BytesIO_close(bytesio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_BytesIO_close_impl(self); +} + +PyDoc_STRVAR(_io_BytesIO___init____doc__, +"BytesIO(initial_bytes=b\'\')\n" +"--\n" +"\n" +"Buffered I/O implementation using an in-memory bytes buffer."); + +static int +_io_BytesIO___init___impl(bytesio *self, PyObject *initvalue); + +static int +_io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"initial_bytes", NULL}; + PyObject *initvalue = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|O:BytesIO", _keywords, + &initvalue)) + goto exit; + return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue); + +exit: + return return_value; +} +/*[clinic end generated code: output=e22697ada514f4eb input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h new file mode 100644 index 0000000000..bb68cc9926 --- /dev/null +++ b/Modules/_io/clinic/fileio.c.h @@ -0,0 +1,374 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_io_FileIO_close__doc__, +"close($self, /)\n" +"--\n" +"\n" +"Close the file.\n" +"\n" +"A closed file cannot be used for further I/O operations. close() may be\n" +"called more than once without error."); + +#define _IO_FILEIO_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io_FileIO_close, METH_NOARGS, _io_FileIO_close__doc__}, + +static PyObject * +_io_FileIO_close_impl(fileio *self); + +static PyObject * +_io_FileIO_close(fileio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO_close_impl(self); +} + +PyDoc_STRVAR(_io_FileIO___init____doc__, +"FileIO(file, mode=\'r\', closefd=True, opener=None)\n" +"--\n" +"\n" +"Open a file.\n" +"\n" +"The mode can be \'r\' (default), \'w\', \'x\' or \'a\' for reading,\n" +"writing, exclusive creation or appending. The file will be created if it\n" +"doesn\'t exist when opened for writing or appending; it will be truncated\n" +"when opened for writing. A FileExistsError will be raised if it already\n" +"exists when opened for creating. Opening a file for creating implies\n" +"writing so this mode behaves in a similar way to \'w\'.Add a \'+\' to the mode\n" +"to allow simultaneous reading and writing. A custom opener can be used by\n" +"passing a callable as *opener*. The underlying file descriptor for the file\n" +"object is then obtained by calling opener with (*name*, *flags*).\n" +"*opener* must return an open file descriptor (passing os.open as *opener*\n" +"results in functionality similar to passing None)."); + +static int +_io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, + int closefd, PyObject *opener); + +static int +_io_FileIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"file", "mode", "closefd", "opener", NULL}; + PyObject *nameobj; + const char *mode = "r"; + int closefd = 1; + PyObject *opener = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|siO:FileIO", _keywords, + &nameobj, &mode, &closefd, &opener)) + goto exit; + return_value = _io_FileIO___init___impl((fileio *)self, nameobj, mode, closefd, opener); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_FileIO_fileno__doc__, +"fileno($self, /)\n" +"--\n" +"\n" +"Return the underlying file descriptor (an integer)."); + +#define _IO_FILEIO_FILENO_METHODDEF \ + {"fileno", (PyCFunction)_io_FileIO_fileno, METH_NOARGS, _io_FileIO_fileno__doc__}, + +static PyObject * +_io_FileIO_fileno_impl(fileio *self); + +static PyObject * +_io_FileIO_fileno(fileio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO_fileno_impl(self); +} + +PyDoc_STRVAR(_io_FileIO_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n" +"True if file was opened in a read mode."); + +#define _IO_FILEIO_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io_FileIO_readable, METH_NOARGS, _io_FileIO_readable__doc__}, + +static PyObject * +_io_FileIO_readable_impl(fileio *self); + +static PyObject * +_io_FileIO_readable(fileio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO_readable_impl(self); +} + +PyDoc_STRVAR(_io_FileIO_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n" +"True if file was opened in a write mode."); + +#define _IO_FILEIO_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io_FileIO_writable, METH_NOARGS, _io_FileIO_writable__doc__}, + +static PyObject * +_io_FileIO_writable_impl(fileio *self); + +static PyObject * +_io_FileIO_writable(fileio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO_writable_impl(self); +} + +PyDoc_STRVAR(_io_FileIO_seekable__doc__, +"seekable($self, /)\n" +"--\n" +"\n" +"True if file supports random-access."); + +#define _IO_FILEIO_SEEKABLE_METHODDEF \ + {"seekable", (PyCFunction)_io_FileIO_seekable, METH_NOARGS, _io_FileIO_seekable__doc__}, + +static PyObject * +_io_FileIO_seekable_impl(fileio *self); + +static PyObject * +_io_FileIO_seekable(fileio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO_seekable_impl(self); +} + +PyDoc_STRVAR(_io_FileIO_readinto__doc__, +"readinto($self, buffer, /)\n" +"--\n" +"\n" +"Same as RawIOBase.readinto()."); + +#define _IO_FILEIO_READINTO_METHODDEF \ + {"readinto", (PyCFunction)_io_FileIO_readinto, METH_O, _io_FileIO_readinto__doc__}, + +static PyObject * +_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer); + +static PyObject * +_io_FileIO_readinto(fileio *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, + "w*:readinto", + &buffer)) + goto exit; + return_value = _io_FileIO_readinto_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) + PyBuffer_Release(&buffer); + + return return_value; +} + +PyDoc_STRVAR(_io_FileIO_readall__doc__, +"readall($self, /)\n" +"--\n" +"\n" +"Read all data from the file, returned as bytes.\n" +"\n" +"In non-blocking mode, returns as much as is immediately available,\n" +"or None if no data is available. Return an empty bytes object at EOF."); + +#define _IO_FILEIO_READALL_METHODDEF \ + {"readall", (PyCFunction)_io_FileIO_readall, METH_NOARGS, _io_FileIO_readall__doc__}, + +static PyObject * +_io_FileIO_readall_impl(fileio *self); + +static PyObject * +_io_FileIO_readall(fileio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO_readall_impl(self); +} + +PyDoc_STRVAR(_io_FileIO_read__doc__, +"read($self, size=-1, /)\n" +"--\n" +"\n" +"Read at most size bytes, returned as bytes.\n" +"\n" +"Only makes one system call, so less data may be returned than requested.\n" +"In non-blocking mode, returns None if no data is available.\n" +"Return an empty bytes object at EOF."); + +#define _IO_FILEIO_READ_METHODDEF \ + {"read", (PyCFunction)_io_FileIO_read, METH_VARARGS, _io_FileIO_read__doc__}, + +static PyObject * +_io_FileIO_read_impl(fileio *self, Py_ssize_t size); + +static PyObject * +_io_FileIO_read(fileio *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t size = -1; + + if (!PyArg_ParseTuple(args, + "|O&:read", + _PyIO_ConvertSsize_t, &size)) + goto exit; + return_value = _io_FileIO_read_impl(self, size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_FileIO_write__doc__, +"write($self, b, /)\n" +"--\n" +"\n" +"Write bytes b to file, return number written.\n" +"\n" +"Only makes one system call, so not all of the data may be written.\n" +"The number of bytes actually written is returned. In non-blocking mode,\n" +"returns None if the write would block."); + +#define _IO_FILEIO_WRITE_METHODDEF \ + {"write", (PyCFunction)_io_FileIO_write, METH_O, _io_FileIO_write__doc__}, + +static PyObject * +_io_FileIO_write_impl(fileio *self, Py_buffer *b); + +static PyObject * +_io_FileIO_write(fileio *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer b = {NULL, NULL}; + + if (!PyArg_Parse(arg, + "y*:write", + &b)) + goto exit; + return_value = _io_FileIO_write_impl(self, &b); + +exit: + /* Cleanup for b */ + if (b.obj) + PyBuffer_Release(&b); + + return return_value; +} + +PyDoc_STRVAR(_io_FileIO_seek__doc__, +"seek($self, pos, whence=0, /)\n" +"--\n" +"\n" +"Move to new file position and return the file position.\n" +"\n" +"Argument offset is a byte count. Optional argument whence defaults to\n" +"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n" +"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n" +"and SEEK_END or 2 (move relative to end of file, usually negative, although\n" +"many platforms allow seeking beyond the end of a file).\n" +"\n" +"Note that not all file objects are seekable."); + +#define _IO_FILEIO_SEEK_METHODDEF \ + {"seek", (PyCFunction)_io_FileIO_seek, METH_VARARGS, _io_FileIO_seek__doc__}, + +static PyObject * +_io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence); + +static PyObject * +_io_FileIO_seek(fileio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *pos; + int whence = 0; + + if (!PyArg_ParseTuple(args, + "O|i:seek", + &pos, &whence)) + goto exit; + return_value = _io_FileIO_seek_impl(self, pos, whence); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_FileIO_tell__doc__, +"tell($self, /)\n" +"--\n" +"\n" +"Current file position.\n" +"\n" +"Can raise OSError for non seekable files."); + +#define _IO_FILEIO_TELL_METHODDEF \ + {"tell", (PyCFunction)_io_FileIO_tell, METH_NOARGS, _io_FileIO_tell__doc__}, + +static PyObject * +_io_FileIO_tell_impl(fileio *self); + +static PyObject * +_io_FileIO_tell(fileio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO_tell_impl(self); +} + +#if defined(HAVE_FTRUNCATE) + +PyDoc_STRVAR(_io_FileIO_truncate__doc__, +"truncate($self, size=None, /)\n" +"--\n" +"\n" +"Truncate the file to at most size bytes and return the truncated size.\n" +"\n" +"Size defaults to the current file position, as returned by tell().\n" +"The current file position is changed to the value of size."); + +#define _IO_FILEIO_TRUNCATE_METHODDEF \ + {"truncate", (PyCFunction)_io_FileIO_truncate, METH_VARARGS, _io_FileIO_truncate__doc__}, + +static PyObject * +_io_FileIO_truncate_impl(fileio *self, PyObject *posobj); + +static PyObject * +_io_FileIO_truncate(fileio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *posobj = NULL; + + if (!PyArg_UnpackTuple(args, "truncate", + 0, 1, + &posobj)) + goto exit; + return_value = _io_FileIO_truncate_impl(self, posobj); + +exit: + return return_value; +} + +#endif /* defined(HAVE_FTRUNCATE) */ + +PyDoc_STRVAR(_io_FileIO_isatty__doc__, +"isatty($self, /)\n" +"--\n" +"\n" +"True if the file is connected to a TTY device."); + +#define _IO_FILEIO_ISATTY_METHODDEF \ + {"isatty", (PyCFunction)_io_FileIO_isatty, METH_NOARGS, _io_FileIO_isatty__doc__}, + +static PyObject * +_io_FileIO_isatty_impl(fileio *self); + +static PyObject * +_io_FileIO_isatty(fileio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_FileIO_isatty_impl(self); +} + +#ifndef _IO_FILEIO_TRUNCATE_METHODDEF + #define _IO_FILEIO_TRUNCATE_METHODDEF +#endif /* !defined(_IO_FILEIO_TRUNCATE_METHODDEF) */ +/*[clinic end generated code: output=c6708e1980f6e02d input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h new file mode 100644 index 0000000000..ce47faadc4 --- /dev/null +++ b/Modules/_io/clinic/iobase.c.h @@ -0,0 +1,282 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_io__IOBase_tell__doc__, +"tell($self, /)\n" +"--\n" +"\n" +"Return current stream position."); + +#define _IO__IOBASE_TELL_METHODDEF \ + {"tell", (PyCFunction)_io__IOBase_tell, METH_NOARGS, _io__IOBase_tell__doc__}, + +static PyObject * +_io__IOBase_tell_impl(PyObject *self); + +static PyObject * +_io__IOBase_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase_tell_impl(self); +} + +PyDoc_STRVAR(_io__IOBase_flush__doc__, +"flush($self, /)\n" +"--\n" +"\n" +"Flush write buffers, if applicable.\n" +"\n" +"This is not implemented for read-only and non-blocking streams."); + +#define _IO__IOBASE_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_io__IOBase_flush, METH_NOARGS, _io__IOBase_flush__doc__}, + +static PyObject * +_io__IOBase_flush_impl(PyObject *self); + +static PyObject * +_io__IOBase_flush(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase_flush_impl(self); +} + +PyDoc_STRVAR(_io__IOBase_close__doc__, +"close($self, /)\n" +"--\n" +"\n" +"Flush and close the IO object.\n" +"\n" +"This method has no effect if the file is already closed."); + +#define _IO__IOBASE_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io__IOBase_close, METH_NOARGS, _io__IOBase_close__doc__}, + +static PyObject * +_io__IOBase_close_impl(PyObject *self); + +static PyObject * +_io__IOBase_close(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase_close_impl(self); +} + +PyDoc_STRVAR(_io__IOBase_seekable__doc__, +"seekable($self, /)\n" +"--\n" +"\n" +"Return whether object supports random access.\n" +"\n" +"If False, seek(), tell() and truncate() will raise UnsupportedOperation.\n" +"This method may need to do a test seek()."); + +#define _IO__IOBASE_SEEKABLE_METHODDEF \ + {"seekable", (PyCFunction)_io__IOBase_seekable, METH_NOARGS, _io__IOBase_seekable__doc__}, + +static PyObject * +_io__IOBase_seekable_impl(PyObject *self); + +static PyObject * +_io__IOBase_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase_seekable_impl(self); +} + +PyDoc_STRVAR(_io__IOBase_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n" +"Return whether object was opened for reading.\n" +"\n" +"If False, read() will raise UnsupportedOperation."); + +#define _IO__IOBASE_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io__IOBase_readable, METH_NOARGS, _io__IOBase_readable__doc__}, + +static PyObject * +_io__IOBase_readable_impl(PyObject *self); + +static PyObject * +_io__IOBase_readable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase_readable_impl(self); +} + +PyDoc_STRVAR(_io__IOBase_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n" +"Return whether object was opened for writing.\n" +"\n" +"If False, write() will raise UnsupportedOperation."); + +#define _IO__IOBASE_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io__IOBase_writable, METH_NOARGS, _io__IOBase_writable__doc__}, + +static PyObject * +_io__IOBase_writable_impl(PyObject *self); + +static PyObject * +_io__IOBase_writable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase_writable_impl(self); +} + +PyDoc_STRVAR(_io__IOBase_fileno__doc__, +"fileno($self, /)\n" +"--\n" +"\n" +"Returns underlying file descriptor if one exists.\n" +"\n" +"An IOError is raised if the IO object does not use a file descriptor."); + +#define _IO__IOBASE_FILENO_METHODDEF \ + {"fileno", (PyCFunction)_io__IOBase_fileno, METH_NOARGS, _io__IOBase_fileno__doc__}, + +static PyObject * +_io__IOBase_fileno_impl(PyObject *self); + +static PyObject * +_io__IOBase_fileno(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase_fileno_impl(self); +} + +PyDoc_STRVAR(_io__IOBase_isatty__doc__, +"isatty($self, /)\n" +"--\n" +"\n" +"Return whether this is an \'interactive\' stream.\n" +"\n" +"Return False if it can\'t be determined."); + +#define _IO__IOBASE_ISATTY_METHODDEF \ + {"isatty", (PyCFunction)_io__IOBase_isatty, METH_NOARGS, _io__IOBase_isatty__doc__}, + +static PyObject * +_io__IOBase_isatty_impl(PyObject *self); + +static PyObject * +_io__IOBase_isatty(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__IOBase_isatty_impl(self); +} + +PyDoc_STRVAR(_io__IOBase_readline__doc__, +"readline($self, size=-1, /)\n" +"--\n" +"\n" +"Read and return a line from the stream.\n" +"\n" +"If size is specified, at most size bytes will be read.\n" +"\n" +"The line terminator is always b\'\\n\' for binary files; for text\n" +"files, the newlines argument to open can be used to select the line\n" +"terminator(s) recognized."); + +#define _IO__IOBASE_READLINE_METHODDEF \ + {"readline", (PyCFunction)_io__IOBase_readline, METH_VARARGS, _io__IOBase_readline__doc__}, + +static PyObject * +_io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit); + +static PyObject * +_io__IOBase_readline(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t limit = -1; + + if (!PyArg_ParseTuple(args, + "|O&:readline", + _PyIO_ConvertSsize_t, &limit)) + goto exit; + return_value = _io__IOBase_readline_impl(self, limit); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io__IOBase_readlines__doc__, +"readlines($self, hint=-1, /)\n" +"--\n" +"\n" +"Return a list of lines from the stream.\n" +"\n" +"hint can be specified to control the number of lines read: no more\n" +"lines will be read if the total size (in bytes/characters) of all\n" +"lines so far exceeds hint."); + +#define _IO__IOBASE_READLINES_METHODDEF \ + {"readlines", (PyCFunction)_io__IOBase_readlines, METH_VARARGS, _io__IOBase_readlines__doc__}, + +static PyObject * +_io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint); + +static PyObject * +_io__IOBase_readlines(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t hint = -1; + + if (!PyArg_ParseTuple(args, + "|O&:readlines", + _PyIO_ConvertSsize_t, &hint)) + goto exit; + return_value = _io__IOBase_readlines_impl(self, hint); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io__IOBase_writelines__doc__, +"writelines($self, lines, /)\n" +"--\n" +"\n"); + +#define _IO__IOBASE_WRITELINES_METHODDEF \ + {"writelines", (PyCFunction)_io__IOBase_writelines, METH_O, _io__IOBase_writelines__doc__}, + +PyDoc_STRVAR(_io__RawIOBase_read__doc__, +"read($self, size=-1, /)\n" +"--\n" +"\n"); + +#define _IO__RAWIOBASE_READ_METHODDEF \ + {"read", (PyCFunction)_io__RawIOBase_read, METH_VARARGS, _io__RawIOBase_read__doc__}, + +static PyObject * +_io__RawIOBase_read_impl(PyObject *self, Py_ssize_t n); + +static PyObject * +_io__RawIOBase_read(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t n = -1; + + if (!PyArg_ParseTuple(args, + "|n:read", + &n)) + goto exit; + return_value = _io__RawIOBase_read_impl(self, n); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io__RawIOBase_readall__doc__, +"readall($self, /)\n" +"--\n" +"\n" +"Read until EOF, using multiple read() call."); + +#define _IO__RAWIOBASE_READALL_METHODDEF \ + {"readall", (PyCFunction)_io__RawIOBase_readall, METH_NOARGS, _io__RawIOBase_readall__doc__}, + +static PyObject * +_io__RawIOBase_readall_impl(PyObject *self); + +static PyObject * +_io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__RawIOBase_readall_impl(self); +} +/*[clinic end generated code: output=84eef4b7541f54b7 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h new file mode 100644 index 0000000000..b830c6d3fb --- /dev/null +++ b/Modules/_io/clinic/stringio.c.h @@ -0,0 +1,288 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_io_StringIO_getvalue__doc__, +"getvalue($self, /)\n" +"--\n" +"\n" +"Retrieve the entire contents of the object."); + +#define _IO_STRINGIO_GETVALUE_METHODDEF \ + {"getvalue", (PyCFunction)_io_StringIO_getvalue, METH_NOARGS, _io_StringIO_getvalue__doc__}, + +static PyObject * +_io_StringIO_getvalue_impl(stringio *self); + +static PyObject * +_io_StringIO_getvalue(stringio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_StringIO_getvalue_impl(self); +} + +PyDoc_STRVAR(_io_StringIO_tell__doc__, +"tell($self, /)\n" +"--\n" +"\n" +"Tell the current file position."); + +#define _IO_STRINGIO_TELL_METHODDEF \ + {"tell", (PyCFunction)_io_StringIO_tell, METH_NOARGS, _io_StringIO_tell__doc__}, + +static PyObject * +_io_StringIO_tell_impl(stringio *self); + +static PyObject * +_io_StringIO_tell(stringio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_StringIO_tell_impl(self); +} + +PyDoc_STRVAR(_io_StringIO_read__doc__, +"read($self, size=None, /)\n" +"--\n" +"\n" +"Read at most size characters, returned as a string.\n" +"\n" +"If the argument is negative or omitted, read until EOF\n" +"is reached. Return an empty string at EOF."); + +#define _IO_STRINGIO_READ_METHODDEF \ + {"read", (PyCFunction)_io_StringIO_read, METH_VARARGS, _io_StringIO_read__doc__}, + +static PyObject * +_io_StringIO_read_impl(stringio *self, PyObject *arg); + +static PyObject * +_io_StringIO_read(stringio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *arg = Py_None; + + if (!PyArg_UnpackTuple(args, "read", + 0, 1, + &arg)) + goto exit; + return_value = _io_StringIO_read_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_StringIO_readline__doc__, +"readline($self, size=None, /)\n" +"--\n" +"\n" +"Read until newline or EOF.\n" +"\n" +"Returns an empty string if EOF is hit immediately."); + +#define _IO_STRINGIO_READLINE_METHODDEF \ + {"readline", (PyCFunction)_io_StringIO_readline, METH_VARARGS, _io_StringIO_readline__doc__}, + +static PyObject * +_io_StringIO_readline_impl(stringio *self, PyObject *arg); + +static PyObject * +_io_StringIO_readline(stringio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *arg = Py_None; + + if (!PyArg_UnpackTuple(args, "readline", + 0, 1, + &arg)) + goto exit; + return_value = _io_StringIO_readline_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_StringIO_truncate__doc__, +"truncate($self, pos=None, /)\n" +"--\n" +"\n" +"Truncate size to pos.\n" +"\n" +"The pos argument defaults to the current file position, as\n" +"returned by tell(). The current file position is unchanged.\n" +"Returns the new absolute position."); + +#define _IO_STRINGIO_TRUNCATE_METHODDEF \ + {"truncate", (PyCFunction)_io_StringIO_truncate, METH_VARARGS, _io_StringIO_truncate__doc__}, + +static PyObject * +_io_StringIO_truncate_impl(stringio *self, PyObject *arg); + +static PyObject * +_io_StringIO_truncate(stringio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *arg = Py_None; + + if (!PyArg_UnpackTuple(args, "truncate", + 0, 1, + &arg)) + goto exit; + return_value = _io_StringIO_truncate_impl(self, arg); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_StringIO_seek__doc__, +"seek($self, pos, whence=0, /)\n" +"--\n" +"\n" +"Change stream position.\n" +"\n" +"Seek to character offset pos relative to position indicated by whence:\n" +" 0 Start of stream (the default). pos should be >= 0;\n" +" 1 Current position - pos must be 0;\n" +" 2 End of stream - pos must be 0.\n" +"Returns the new absolute position."); + +#define _IO_STRINGIO_SEEK_METHODDEF \ + {"seek", (PyCFunction)_io_StringIO_seek, METH_VARARGS, _io_StringIO_seek__doc__}, + +static PyObject * +_io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence); + +static PyObject * +_io_StringIO_seek(stringio *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t pos; + int whence = 0; + + if (!PyArg_ParseTuple(args, + "n|i:seek", + &pos, &whence)) + goto exit; + return_value = _io_StringIO_seek_impl(self, pos, whence); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_StringIO_write__doc__, +"write($self, s, /)\n" +"--\n" +"\n" +"Write string to file.\n" +"\n" +"Returns the number of characters written, which is always equal to\n" +"the length of the string."); + +#define _IO_STRINGIO_WRITE_METHODDEF \ + {"write", (PyCFunction)_io_StringIO_write, METH_O, _io_StringIO_write__doc__}, + +PyDoc_STRVAR(_io_StringIO_close__doc__, +"close($self, /)\n" +"--\n" +"\n" +"Close the IO object.\n" +"\n" +"Attempting any further operation after the object is closed\n" +"will raise a ValueError.\n" +"\n" +"This method has no effect if the file is already closed."); + +#define _IO_STRINGIO_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io_StringIO_close, METH_NOARGS, _io_StringIO_close__doc__}, + +static PyObject * +_io_StringIO_close_impl(stringio *self); + +static PyObject * +_io_StringIO_close(stringio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_StringIO_close_impl(self); +} + +PyDoc_STRVAR(_io_StringIO___init____doc__, +"StringIO(initial_value=\'\', newline=\'\\n\')\n" +"--\n" +"\n" +"Text I/O implementation using an in-memory buffer.\n" +"\n" +"The initial_value argument sets the value of object. The newline\n" +"argument is like the one of TextIOWrapper\'s constructor."); + +static int +_io_StringIO___init___impl(stringio *self, PyObject *value, + PyObject *newline_obj); + +static int +_io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"initial_value", "newline", NULL}; + PyObject *value = NULL; + PyObject *newline_obj = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|OO:StringIO", _keywords, + &value, &newline_obj)) + goto exit; + return_value = _io_StringIO___init___impl((stringio *)self, value, newline_obj); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_StringIO_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n" +"Returns True if the IO object can be read."); + +#define _IO_STRINGIO_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io_StringIO_readable, METH_NOARGS, _io_StringIO_readable__doc__}, + +static PyObject * +_io_StringIO_readable_impl(stringio *self); + +static PyObject * +_io_StringIO_readable(stringio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_StringIO_readable_impl(self); +} + +PyDoc_STRVAR(_io_StringIO_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n" +"Returns True if the IO object can be written."); + +#define _IO_STRINGIO_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io_StringIO_writable, METH_NOARGS, _io_StringIO_writable__doc__}, + +static PyObject * +_io_StringIO_writable_impl(stringio *self); + +static PyObject * +_io_StringIO_writable(stringio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_StringIO_writable_impl(self); +} + +PyDoc_STRVAR(_io_StringIO_seekable__doc__, +"seekable($self, /)\n" +"--\n" +"\n" +"Returns True if the IO object can be seeked."); + +#define _IO_STRINGIO_SEEKABLE_METHODDEF \ + {"seekable", (PyCFunction)_io_StringIO_seekable, METH_NOARGS, _io_StringIO_seekable__doc__}, + +static PyObject * +_io_StringIO_seekable_impl(stringio *self); + +static PyObject * +_io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_StringIO_seekable_impl(self); +} +/*[clinic end generated code: output=f3062096d357c652 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h new file mode 100644 index 0000000000..62603bd739 --- /dev/null +++ b/Modules/_io/clinic/textio.c.h @@ -0,0 +1,464 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_io_IncrementalNewlineDecoder___init____doc__, +"IncrementalNewlineDecoder(decoder, translate, errors=\'strict\')\n" +"--\n" +"\n" +"Codec used when reading a file in universal newlines mode.\n" +"\n" +"It wraps another incremental decoder, translating \\r\\n and \\r into \\n.\n" +"It also records the types of newlines encountered. When used with\n" +"translate=False, it ensures that the newline sequence is returned in\n" +"one piece. When used with decoder=None, it expects unicode strings as\n" +"decode input and translates newlines without first invoking an external\n" +"decoder."); + +static int +_io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self, + PyObject *decoder, int translate, + PyObject *errors); + +static int +_io_IncrementalNewlineDecoder___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"decoder", "translate", "errors", NULL}; + PyObject *decoder; + int translate; + PyObject *errors = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "Oi|O:IncrementalNewlineDecoder", _keywords, + &decoder, &translate, &errors)) + goto exit; + return_value = _io_IncrementalNewlineDecoder___init___impl((nldecoder_object *)self, decoder, translate, errors); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_IncrementalNewlineDecoder_decode__doc__, +"decode($self, /, input, final=False)\n" +"--\n" +"\n"); + +#define _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF \ + {"decode", (PyCFunction)_io_IncrementalNewlineDecoder_decode, METH_VARARGS|METH_KEYWORDS, _io_IncrementalNewlineDecoder_decode__doc__}, + +static PyObject * +_io_IncrementalNewlineDecoder_decode_impl(nldecoder_object *self, + PyObject *input, int final); + +static PyObject * +_io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"input", "final", NULL}; + PyObject *input; + int final = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|i:decode", _keywords, + &input, &final)) + goto exit; + return_value = _io_IncrementalNewlineDecoder_decode_impl(self, input, final); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_IncrementalNewlineDecoder_getstate__doc__, +"getstate($self, /)\n" +"--\n" +"\n"); + +#define _IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF \ + {"getstate", (PyCFunction)_io_IncrementalNewlineDecoder_getstate, METH_NOARGS, _io_IncrementalNewlineDecoder_getstate__doc__}, + +static PyObject * +_io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self); + +static PyObject * +_io_IncrementalNewlineDecoder_getstate(nldecoder_object *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_IncrementalNewlineDecoder_getstate_impl(self); +} + +PyDoc_STRVAR(_io_IncrementalNewlineDecoder_setstate__doc__, +"setstate($self, state, /)\n" +"--\n" +"\n"); + +#define _IO_INCREMENTALNEWLINEDECODER_SETSTATE_METHODDEF \ + {"setstate", (PyCFunction)_io_IncrementalNewlineDecoder_setstate, METH_O, _io_IncrementalNewlineDecoder_setstate__doc__}, + +PyDoc_STRVAR(_io_IncrementalNewlineDecoder_reset__doc__, +"reset($self, /)\n" +"--\n" +"\n"); + +#define _IO_INCREMENTALNEWLINEDECODER_RESET_METHODDEF \ + {"reset", (PyCFunction)_io_IncrementalNewlineDecoder_reset, METH_NOARGS, _io_IncrementalNewlineDecoder_reset__doc__}, + +static PyObject * +_io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self); + +static PyObject * +_io_IncrementalNewlineDecoder_reset(nldecoder_object *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_IncrementalNewlineDecoder_reset_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper___init____doc__, +"TextIOWrapper(buffer, encoding=None, errors=None, newline=None,\n" +" line_buffering=False, write_through=False)\n" +"--\n" +"\n" +"Character and line based layer over a BufferedIOBase object, buffer.\n" +"\n" +"encoding gives the name of the encoding that the stream will be\n" +"decoded or encoded with. It defaults to locale.getpreferredencoding(False).\n" +"\n" +"errors determines the strictness of encoding and decoding (see\n" +"help(codecs.Codec) or the documentation for codecs.register) and\n" +"defaults to \"strict\".\n" +"\n" +"newline controls how line endings are handled. It can be None, \'\',\n" +"\'\\n\', \'\\r\', and \'\\r\\n\'. It works as follows:\n" +"\n" +"* On input, if newline is None, universal newlines mode is\n" +" enabled. Lines in the input can end in \'\\n\', \'\\r\', or \'\\r\\n\', and\n" +" these are translated into \'\\n\' before being returned to the\n" +" caller. If it is \'\', universal newline mode is enabled, but line\n" +" endings are returned to the caller untranslated. If it has any of\n" +" the other legal values, input lines are only terminated by the given\n" +" string, and the line ending is returned to the caller untranslated.\n" +"\n" +"* On output, if newline is None, any \'\\n\' characters written are\n" +" translated to the system default line separator, os.linesep. If\n" +" newline is \'\' or \'\\n\', no translation takes place. If newline is any\n" +" of the other legal values, any \'\\n\' characters written are translated\n" +" to the given string.\n" +"\n" +"If line_buffering is True, a call to flush is implied when a call to\n" +"write contains a newline character."); + +static int +_io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, + const char *encoding, const char *errors, + const char *newline, int line_buffering, + int write_through); + +static int +_io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static char *_keywords[] = {"buffer", "encoding", "errors", "newline", "line_buffering", "write_through", NULL}; + PyObject *buffer; + const char *encoding = NULL; + const char *errors = NULL; + const char *newline = NULL; + int line_buffering = 0; + int write_through = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|zzzii:TextIOWrapper", _keywords, + &buffer, &encoding, &errors, &newline, &line_buffering, &write_through)) + goto exit; + return_value = _io_TextIOWrapper___init___impl((textio *)self, buffer, encoding, errors, newline, line_buffering, write_through); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_TextIOWrapper_detach__doc__, +"detach($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_DETACH_METHODDEF \ + {"detach", (PyCFunction)_io_TextIOWrapper_detach, METH_NOARGS, _io_TextIOWrapper_detach__doc__}, + +static PyObject * +_io_TextIOWrapper_detach_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_detach(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_detach_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper_write__doc__, +"write($self, text, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_WRITE_METHODDEF \ + {"write", (PyCFunction)_io_TextIOWrapper_write, METH_O, _io_TextIOWrapper_write__doc__}, + +static PyObject * +_io_TextIOWrapper_write_impl(textio *self, PyObject *text); + +static PyObject * +_io_TextIOWrapper_write(textio *self, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *text; + + if (!PyArg_Parse(arg, + "U:write", + &text)) + goto exit; + return_value = _io_TextIOWrapper_write_impl(self, text); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_TextIOWrapper_read__doc__, +"read($self, size=-1, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_READ_METHODDEF \ + {"read", (PyCFunction)_io_TextIOWrapper_read, METH_VARARGS, _io_TextIOWrapper_read__doc__}, + +static PyObject * +_io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n); + +static PyObject * +_io_TextIOWrapper_read(textio *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t n = -1; + + if (!PyArg_ParseTuple(args, + "|O&:read", + _PyIO_ConvertSsize_t, &n)) + goto exit; + return_value = _io_TextIOWrapper_read_impl(self, n); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_TextIOWrapper_readline__doc__, +"readline($self, size=-1, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_READLINE_METHODDEF \ + {"readline", (PyCFunction)_io_TextIOWrapper_readline, METH_VARARGS, _io_TextIOWrapper_readline__doc__}, + +static PyObject * +_io_TextIOWrapper_readline_impl(textio *self, Py_ssize_t size); + +static PyObject * +_io_TextIOWrapper_readline(textio *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t size = -1; + + if (!PyArg_ParseTuple(args, + "|n:readline", + &size)) + goto exit; + return_value = _io_TextIOWrapper_readline_impl(self, size); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_TextIOWrapper_seek__doc__, +"seek($self, cookie, whence=0, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_SEEK_METHODDEF \ + {"seek", (PyCFunction)_io_TextIOWrapper_seek, METH_VARARGS, _io_TextIOWrapper_seek__doc__}, + +static PyObject * +_io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence); + +static PyObject * +_io_TextIOWrapper_seek(textio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *cookieObj; + int whence = 0; + + if (!PyArg_ParseTuple(args, + "O|i:seek", + &cookieObj, &whence)) + goto exit; + return_value = _io_TextIOWrapper_seek_impl(self, cookieObj, whence); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_TextIOWrapper_tell__doc__, +"tell($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_TELL_METHODDEF \ + {"tell", (PyCFunction)_io_TextIOWrapper_tell, METH_NOARGS, _io_TextIOWrapper_tell__doc__}, + +static PyObject * +_io_TextIOWrapper_tell_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_tell(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_tell_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper_truncate__doc__, +"truncate($self, pos=None, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF \ + {"truncate", (PyCFunction)_io_TextIOWrapper_truncate, METH_VARARGS, _io_TextIOWrapper_truncate__doc__}, + +static PyObject * +_io_TextIOWrapper_truncate_impl(textio *self, PyObject *pos); + +static PyObject * +_io_TextIOWrapper_truncate(textio *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *pos = Py_None; + + if (!PyArg_UnpackTuple(args, "truncate", + 0, 1, + &pos)) + goto exit; + return_value = _io_TextIOWrapper_truncate_impl(self, pos); + +exit: + return return_value; +} + +PyDoc_STRVAR(_io_TextIOWrapper_fileno__doc__, +"fileno($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_FILENO_METHODDEF \ + {"fileno", (PyCFunction)_io_TextIOWrapper_fileno, METH_NOARGS, _io_TextIOWrapper_fileno__doc__}, + +static PyObject * +_io_TextIOWrapper_fileno_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_fileno(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_fileno_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper_seekable__doc__, +"seekable($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_SEEKABLE_METHODDEF \ + {"seekable", (PyCFunction)_io_TextIOWrapper_seekable, METH_NOARGS, _io_TextIOWrapper_seekable__doc__}, + +static PyObject * +_io_TextIOWrapper_seekable_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_seekable(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_seekable_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io_TextIOWrapper_readable, METH_NOARGS, _io_TextIOWrapper_readable__doc__}, + +static PyObject * +_io_TextIOWrapper_readable_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_readable(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_readable_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io_TextIOWrapper_writable, METH_NOARGS, _io_TextIOWrapper_writable__doc__}, + +static PyObject * +_io_TextIOWrapper_writable_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_writable(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_writable_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper_isatty__doc__, +"isatty($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_ISATTY_METHODDEF \ + {"isatty", (PyCFunction)_io_TextIOWrapper_isatty, METH_NOARGS, _io_TextIOWrapper_isatty__doc__}, + +static PyObject * +_io_TextIOWrapper_isatty_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_isatty(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_isatty_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper_flush__doc__, +"flush($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_FLUSH_METHODDEF \ + {"flush", (PyCFunction)_io_TextIOWrapper_flush, METH_NOARGS, _io_TextIOWrapper_flush__doc__}, + +static PyObject * +_io_TextIOWrapper_flush_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_flush(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_flush_impl(self); +} + +PyDoc_STRVAR(_io_TextIOWrapper_close__doc__, +"close($self, /)\n" +"--\n" +"\n"); + +#define _IO_TEXTIOWRAPPER_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io_TextIOWrapper_close, METH_NOARGS, _io_TextIOWrapper_close__doc__}, + +static PyObject * +_io_TextIOWrapper_close_impl(textio *self); + +static PyObject * +_io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io_TextIOWrapper_close_impl(self); +} +/*[clinic end generated code: output=a610bd3b694886c3 input=a9049054013a1b77]*/ diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index af93499cae..3c52c802e3 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -43,6 +43,19 @@ #define SMALLCHUNK BUFSIZ #endif +/*[clinic input] +module _io +class _io.FileIO "fileio *" "&PyFileIO_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1c77708b41fda70c]*/ + +/*[python input] +class io_ssize_t_converter(CConverter): + type = 'Py_ssize_t' + converter = '_PyIO_ConvertSsize_t' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/ + typedef struct { PyObject_HEAD int fd; @@ -126,8 +139,18 @@ internal_close(fileio *self) return 0; } +/*[clinic input] +_io.FileIO.close + +Close the file. + +A closed file cannot be used for further I/O operations. close() may be +called more than once without error. +[clinic start generated code]*/ + static PyObject * -fileio_close(fileio *self) +_io_FileIO_close_impl(fileio *self) +/*[clinic end generated code: output=7737a319ef3bad0b input=f35231760d54a522]*/ { PyObject *res; PyObject *exc, *val, *tb; @@ -183,15 +206,36 @@ fileio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) extern int _Py_open_cloexec_works; #endif +/*[clinic input] +_io.FileIO.__init__ + file as nameobj: object + mode: str = "r" + closefd: int(c_default="1") = True + opener: object = None + +Open a file. + +The mode can be 'r' (default), 'w', 'x' or 'a' for reading, +writing, exclusive creation or appending. The file will be created if it +doesn't exist when opened for writing or appending; it will be truncated +when opened for writing. A FileExistsError will be raised if it already +exists when opened for creating. Opening a file for creating implies +writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode +to allow simultaneous reading and writing. A custom opener can be used by +passing a callable as *opener*. The underlying file descriptor for the file +object is then obtained by calling opener with (*name*, *flags*). +*opener* must return an open file descriptor (passing os.open as *opener* +results in functionality similar to passing None). +[clinic start generated code]*/ + static int -fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) +_io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, + int closefd, PyObject *opener) +/*[clinic end generated code: output=23413f68e6484bbd input=193164e293d6c097]*/ { - fileio *self = (fileio *) oself; - static char *kwlist[] = {"file", "mode", "closefd", "opener", NULL}; const char *name = NULL; - PyObject *nameobj, *stringobj = NULL, *opener = Py_None; - char *mode = "r"; - char *s; + PyObject *stringobj = NULL; + const char *s; #ifdef MS_WINDOWS Py_UNICODE *widename = NULL; #endif @@ -199,7 +243,6 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) int rwa = 0, plus = 0; int flags = 0; int fd = -1; - int closefd = 1; int fd_is_own = 0; #ifdef O_CLOEXEC int *atomic_flag_works = &_Py_open_cloexec_works; @@ -220,11 +263,6 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) self->fd = -1; } - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|siO:fileio", - kwlist, &nameobj, &mode, &closefd, - &opener)) - return -1; - if (PyFloat_Check(nameobj)) { PyErr_SetString(PyExc_TypeError, "integer argument expected, got float"); @@ -494,32 +532,60 @@ err_mode(char *action) return NULL; } +/*[clinic input] +_io.FileIO.fileno + +Return the underlying file descriptor (an integer). +[clinic start generated code]*/ + static PyObject * -fileio_fileno(fileio *self) +_io_FileIO_fileno_impl(fileio *self) +/*[clinic end generated code: output=a9626ce5398ece90 input=0b9b2de67335ada3]*/ { if (self->fd < 0) return err_closed(); return PyLong_FromLong((long) self->fd); } +/*[clinic input] +_io.FileIO.readable + +True if file was opened in a read mode. +[clinic start generated code]*/ + static PyObject * -fileio_readable(fileio *self) +_io_FileIO_readable_impl(fileio *self) +/*[clinic end generated code: output=640744a6150fe9ba input=a3fdfed6eea721c5]*/ { if (self->fd < 0) return err_closed(); return PyBool_FromLong((long) self->readable); } +/*[clinic input] +_io.FileIO.writable + +True if file was opened in a write mode. +[clinic start generated code]*/ + static PyObject * -fileio_writable(fileio *self) +_io_FileIO_writable_impl(fileio *self) +/*[clinic end generated code: output=96cefc5446e89977 input=c204a808ca2e1748]*/ { if (self->fd < 0) return err_closed(); return PyBool_FromLong((long) self->writable); } +/*[clinic input] +_io.FileIO.seekable + +True if file supports random-access. +[clinic start generated code]*/ + static PyObject * -fileio_seekable(fileio *self) +_io_FileIO_seekable_impl(fileio *self) +/*[clinic end generated code: output=47909ca0a42e9287 input=c8e5554d2fd63c7f]*/ { if (self->fd < 0) return err_closed(); @@ -536,10 +602,18 @@ fileio_seekable(fileio *self) return PyBool_FromLong((long) self->seekable); } +/*[clinic input] +_io.FileIO.readinto + buffer: Py_buffer(types={'rwbuffer'}) + / + +Same as RawIOBase.readinto(). +[clinic start generated code]*/ + static PyObject * -fileio_readinto(fileio *self, PyObject *args) +_io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer) +/*[clinic end generated code: output=b01a5a22c8415cb4 input=5edd8327498d468c]*/ { - Py_buffer pbuf; Py_ssize_t n; int err; @@ -548,13 +622,9 @@ fileio_readinto(fileio *self, PyObject *args) if (!self->readable) return err_mode("reading"); - if (!PyArg_ParseTuple(args, "w*", &pbuf)) - return NULL; - - n = _Py_read(self->fd, pbuf.buf, pbuf.len); + n = _Py_read(self->fd, buffer->buf, buffer->len); /* copy errno because PyBuffer_Release() can indirectly modify it */ err = errno; - PyBuffer_Release(&pbuf); if (n == -1) { if (err == EAGAIN) { @@ -586,8 +656,18 @@ new_buffersize(fileio *self, size_t currentsize) return addend + currentsize; } +/*[clinic input] +_io.FileIO.readall + +Read all data from the file, returned as bytes. + +In non-blocking mode, returns as much as is immediately available, +or None if no data is available. Return an empty bytes object at EOF. +[clinic start generated code]*/ + static PyObject * -fileio_readall(fileio *self) +_io_FileIO_readall_impl(fileio *self) +/*[clinic end generated code: output=faa0292b213b4022 input=dbdc137f55602834]*/ { struct _Py_stat_struct status; Py_off_t pos, end; @@ -673,12 +753,24 @@ fileio_readall(fileio *self) return result; } +/*[clinic input] +_io.FileIO.read + size: io_ssize_t = -1 + / + +Read at most size bytes, returned as bytes. + +Only makes one system call, so less data may be returned than requested. +In non-blocking mode, returns None if no data is available. +Return an empty bytes object at EOF. +[clinic start generated code]*/ + static PyObject * -fileio_read(fileio *self, PyObject *args) +_io_FileIO_read_impl(fileio *self, Py_ssize_t size) +/*[clinic end generated code: output=42528d39dd0ca641 input=5c6caa5490c13a9b]*/ { char *ptr; Py_ssize_t n; - Py_ssize_t size = -1; PyObject *bytes; if (self->fd < 0) @@ -686,11 +778,8 @@ fileio_read(fileio *self, PyObject *args) if (!self->readable) return err_mode("reading"); - if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size)) - return NULL; - if (size < 0) - return fileio_readall(self); + return _io_FileIO_readall_impl(self); #ifdef MS_WINDOWS /* On Windows, the count parameter of read() is an int */ @@ -725,10 +814,22 @@ fileio_read(fileio *self, PyObject *args) return (PyObject *) bytes; } +/*[clinic input] +_io.FileIO.write + b: Py_buffer + / + +Write bytes b to file, return number written. + +Only makes one system call, so not all of the data may be written. +The number of bytes actually written is returned. In non-blocking mode, +returns None if the write would block. +[clinic start generated code]*/ + static PyObject * -fileio_write(fileio *self, PyObject *args) +_io_FileIO_write_impl(fileio *self, Py_buffer *b) +/*[clinic end generated code: output=b4059db3d363a2f7 input=ffbd8834f447ac31]*/ { - Py_buffer pbuf; Py_ssize_t n; int err; @@ -737,13 +838,9 @@ fileio_write(fileio *self, PyObject *args) if (!self->writable) return err_mode("writing"); - if (!PyArg_ParseTuple(args, "y*", &pbuf)) - return NULL; - - n = _Py_write(self->fd, pbuf.buf, pbuf.len); + n = _Py_write(self->fd, b->buf, b->len); /* copy errno because PyBuffer_Release() can indirectly modify it */ err = errno; - PyBuffer_Release(&pbuf); if (n < 0) { if (err == EAGAIN) { @@ -817,23 +914,44 @@ portable_lseek(int fd, PyObject *posobj, int whence) #endif } +/*[clinic input] +_io.FileIO.seek + pos: object + whence: int = 0 + / + +Move to new file position and return the file position. + +Argument offset is a byte count. Optional argument whence defaults to +SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values +are SEEK_CUR or 1 (move relative to current position, positive or negative), +and SEEK_END or 2 (move relative to end of file, usually negative, although +many platforms allow seeking beyond the end of a file). + +Note that not all file objects are seekable. +[clinic start generated code]*/ + static PyObject * -fileio_seek(fileio *self, PyObject *args) +_io_FileIO_seek_impl(fileio *self, PyObject *pos, int whence) +/*[clinic end generated code: output=c976acdf054e6655 input=0439194b0774d454]*/ { - PyObject *posobj; - int whence = 0; - if (self->fd < 0) return err_closed(); - if (!PyArg_ParseTuple(args, "O|i", &posobj, &whence)) - return NULL; - - return portable_lseek(self->fd, posobj, whence); + return portable_lseek(self->fd, pos, whence); } +/*[clinic input] +_io.FileIO.tell + +Current file position. + +Can raise OSError for non seekable files. +[clinic start generated code]*/ + static PyObject * -fileio_tell(fileio *self, PyObject *args) +_io_FileIO_tell_impl(fileio *self) +/*[clinic end generated code: output=ffe2147058809d0b input=807e24ead4cec2f9]*/ { if (self->fd < 0) return err_closed(); @@ -842,10 +960,21 @@ fileio_tell(fileio *self, PyObject *args) } #ifdef HAVE_FTRUNCATE +/*[clinic input] +_io.FileIO.truncate + size as posobj: object = NULL + / + +Truncate the file to at most size bytes and return the truncated size. + +Size defaults to the current file position, as returned by tell(). +The current file position is changed to the value of size. +[clinic start generated code]*/ + static PyObject * -fileio_truncate(fileio *self, PyObject *args) +_io_FileIO_truncate_impl(fileio *self, PyObject *posobj) +/*[clinic end generated code: output=e49ca7a916c176fa input=9026af44686b7318]*/ { - PyObject *posobj = NULL; /* the new size wanted by the user */ Py_off_t pos; int ret; int fd; @@ -856,9 +985,6 @@ fileio_truncate(fileio *self, PyObject *args) if (!self->writable) return err_mode("writing"); - if (!PyArg_ParseTuple(args, "|O", &posobj)) - return NULL; - if (posobj == Py_None || posobj == NULL) { /* Get the current position. */ posobj = portable_lseek(fd, NULL, 1); @@ -952,8 +1078,15 @@ fileio_repr(fileio *self) return res; } +/*[clinic input] +_io.FileIO.isatty + +True if the file is connected to a TTY device. +[clinic start generated code]*/ + static PyObject * -fileio_isatty(fileio *self) +_io_FileIO_isatty_impl(fileio *self) +/*[clinic end generated code: output=932c39924e9a8070 input=cd94ca1f5e95e843]*/ { long res; @@ -978,110 +1111,22 @@ fileio_getstate(fileio *self) return NULL; } - -PyDoc_STRVAR(fileio_doc, -"file(name: str[, mode: str][, opener: None]) -> file IO object\n" -"\n" -"Open a file. The mode can be 'r' (default), 'w', 'x' or 'a' for reading,\n" -"writing, exclusive creation or appending. The file will be created if it\n" -"doesn't exist when opened for writing or appending; it will be truncated\n" -"when opened for writing. A FileExistsError will be raised if it already\n" -"exists when opened for creating. Opening a file for creating implies\n" -"writing so this mode behaves in a similar way to 'w'.Add a '+' to the mode\n" -"to allow simultaneous reading and writing. A custom opener can be used by\n" -"passing a callable as *opener*. The underlying file descriptor for the file\n" -"object is then obtained by calling opener with (*name*, *flags*).\n" -"*opener* must return an open file descriptor (passing os.open as *opener*\n" -"results in functionality similar to passing None)."); - -PyDoc_STRVAR(read_doc, -"read(size: int) -> bytes. read at most size bytes, returned as bytes.\n" -"\n" -"Only makes one system call, so less data may be returned than requested\n" -"In non-blocking mode, returns None if no data is available.\n" -"Return an empty bytes object at EOF."); - -PyDoc_STRVAR(readall_doc, -"readall() -> bytes. read all data from the file, returned as bytes.\n" -"\n" -"In non-blocking mode, returns as much as is immediately available,\n" -"or None if no data is available. Return an empty bytes object at EOF."); - -PyDoc_STRVAR(write_doc, -"write(b: bytes) -> int. Write bytes b to file, return number written.\n" -"\n" -"Only makes one system call, so not all of the data may be written.\n" -"The number of bytes actually written is returned. In non-blocking mode,\n" -"returns None if the write would block." -); - -PyDoc_STRVAR(fileno_doc, -"fileno() -> int. Return the underlying file descriptor (an integer)."); - -PyDoc_STRVAR(seek_doc, -"seek(offset: int[, whence: int]) -> int. Move to new file position and\n" -"return the file position.\n" -"\n" -"Argument offset is a byte count. Optional argument whence defaults to\n" -"SEEK_SET or 0 (offset from start of file, offset should be >= 0); other values\n" -"are SEEK_CUR or 1 (move relative to current position, positive or negative),\n" -"and SEEK_END or 2 (move relative to end of file, usually negative, although\n" -"many platforms allow seeking beyond the end of a file).\n" -"\n" -"Note that not all file objects are seekable."); - -#ifdef HAVE_FTRUNCATE -PyDoc_STRVAR(truncate_doc, -"truncate([size: int]) -> int. Truncate the file to at most size bytes\n" -"and return the truncated size.\n" -"\n" -"Size defaults to the current file position, as returned by tell().\n" -"The current file position is changed to the value of size."); -#endif - -PyDoc_STRVAR(tell_doc, -"tell() -> int. Current file position.\n" -"\n" -"Can raise OSError for non seekable files." -); - -PyDoc_STRVAR(readinto_doc, -"readinto() -> Same as RawIOBase.readinto()."); - -PyDoc_STRVAR(close_doc, -"close() -> None. Close the file.\n" -"\n" -"A closed file cannot be used for further I/O operations. close() may be\n" -"called more than once without error."); - -PyDoc_STRVAR(isatty_doc, -"isatty() -> bool. True if the file is connected to a TTY device."); - -PyDoc_STRVAR(seekable_doc, -"seekable() -> bool. True if file supports random-access."); - -PyDoc_STRVAR(readable_doc, -"readable() -> bool. True if file was opened in a read mode."); - -PyDoc_STRVAR(writable_doc, -"writable() -> bool. True if file was opened in a write mode."); +#include "clinic/fileio.c.h" static PyMethodDef fileio_methods[] = { - {"read", (PyCFunction)fileio_read, METH_VARARGS, read_doc}, - {"readall", (PyCFunction)fileio_readall, METH_NOARGS, readall_doc}, - {"readinto", (PyCFunction)fileio_readinto, METH_VARARGS, readinto_doc}, - {"write", (PyCFunction)fileio_write, METH_VARARGS, write_doc}, - {"seek", (PyCFunction)fileio_seek, METH_VARARGS, seek_doc}, - {"tell", (PyCFunction)fileio_tell, METH_VARARGS, tell_doc}, -#ifdef HAVE_FTRUNCATE - {"truncate", (PyCFunction)fileio_truncate, METH_VARARGS, truncate_doc}, -#endif - {"close", (PyCFunction)fileio_close, METH_NOARGS, close_doc}, - {"seekable", (PyCFunction)fileio_seekable, METH_NOARGS, seekable_doc}, - {"readable", (PyCFunction)fileio_readable, METH_NOARGS, readable_doc}, - {"writable", (PyCFunction)fileio_writable, METH_NOARGS, writable_doc}, - {"fileno", (PyCFunction)fileio_fileno, METH_NOARGS, fileno_doc}, - {"isatty", (PyCFunction)fileio_isatty, METH_NOARGS, isatty_doc}, + _IO_FILEIO_READ_METHODDEF + _IO_FILEIO_READALL_METHODDEF + _IO_FILEIO_READINTO_METHODDEF + _IO_FILEIO_WRITE_METHODDEF + _IO_FILEIO_SEEK_METHODDEF + _IO_FILEIO_TELL_METHODDEF + _IO_FILEIO_TRUNCATE_METHODDEF + _IO_FILEIO_CLOSE_METHODDEF + _IO_FILEIO_SEEKABLE_METHODDEF + _IO_FILEIO_READABLE_METHODDEF + _IO_FILEIO_WRITABLE_METHODDEF + _IO_FILEIO_FILENO_METHODDEF + _IO_FILEIO_ISATTY_METHODDEF {"_dealloc_warn", (PyCFunction)fileio_dealloc_warn, METH_O, NULL}, {"__getstate__", (PyCFunction)fileio_getstate, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ @@ -1143,7 +1188,7 @@ PyTypeObject PyFileIO_Type = { 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ - fileio_doc, /* tp_doc */ + _io_FileIO___init____doc__, /* tp_doc */ (traverseproc)fileio_traverse, /* tp_traverse */ (inquiry)fileio_clear, /* tp_clear */ 0, /* tp_richcompare */ @@ -1158,7 +1203,7 @@ PyTypeObject PyFileIO_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(fileio, dict), /* tp_dictoffset */ - fileio_init, /* tp_init */ + _io_FileIO___init__, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ fileio_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index ef06b43ca6..79d716a98a 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -13,6 +13,20 @@ #include "structmember.h" #include "_iomodule.h" +/*[clinic input] +module _io +class _io._IOBase "PyObject *" "&PyIOBase_Type" +class _io._RawIOBase "PyObject *" "&PyRawIOBase_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d29a4d076c2b211c]*/ + +/*[python input] +class io_ssize_t_converter(CConverter): + type = 'Py_ssize_t' + converter = '_PyIO_ConvertSsize_t' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/ + /* * IOBase class, an abstract class */ @@ -96,11 +110,15 @@ iobase_seek(PyObject *self, PyObject *args) return iobase_unsupported("seek"); } -PyDoc_STRVAR(iobase_tell_doc, - "Return current stream position."); +/*[clinic input] +_io._IOBase.tell + +Return current stream position. +[clinic start generated code]*/ static PyObject * -iobase_tell(PyObject *self, PyObject *args) +_io__IOBase_tell_impl(PyObject *self) +/*[clinic end generated code: output=89a1c0807935abe2 input=04e615fec128801f]*/ { _Py_IDENTIFIER(seek); @@ -121,13 +139,17 @@ iobase_truncate(PyObject *self, PyObject *args) /* Flush and close methods */ -PyDoc_STRVAR(iobase_flush_doc, - "Flush write buffers, if applicable.\n" - "\n" - "This is not implemented for read-only and non-blocking streams.\n"); +/*[clinic input] +_io._IOBase.flush + +Flush write buffers, if applicable. + +This is not implemented for read-only and non-blocking streams. +[clinic start generated code]*/ static PyObject * -iobase_flush(PyObject *self, PyObject *args) +_io__IOBase_flush_impl(PyObject *self) +/*[clinic end generated code: output=7cef4b4d54656a3b input=773be121abe270aa]*/ { /* XXX Should this return the number of bytes written??? */ if (IS_CLOSED(self)) { @@ -137,11 +159,6 @@ iobase_flush(PyObject *self, PyObject *args) Py_RETURN_NONE; } -PyDoc_STRVAR(iobase_close_doc, - "Flush and close the IO object.\n" - "\n" - "This method has no effect if the file is already closed.\n"); - static int iobase_closed(PyObject *self) { @@ -180,8 +197,17 @@ _PyIOBase_check_closed(PyObject *self, PyObject *args) `__IOBase_closed` and call flush() by itself, but it is redundant with whatever behaviour a non-trivial derived class will implement. */ +/*[clinic input] +_io._IOBase.close + +Flush and close the IO object. + +This method has no effect if the file is already closed. +[clinic start generated code]*/ + static PyObject * -iobase_close(PyObject *self, PyObject *args) +_io__IOBase_close_impl(PyObject *self) +/*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/ { PyObject *res; @@ -304,14 +330,18 @@ iobase_dealloc(iobase *self) /* Inquiry methods */ -PyDoc_STRVAR(iobase_seekable_doc, - "Return whether object supports random access.\n" - "\n" - "If False, seek(), tell() and truncate() will raise UnsupportedOperation.\n" - "This method may need to do a test seek()."); +/*[clinic input] +_io._IOBase.seekable + +Return whether object supports random access. + +If False, seek(), tell() and truncate() will raise UnsupportedOperation. +This method may need to do a test seek(). +[clinic start generated code]*/ static PyObject * -iobase_seekable(PyObject *self, PyObject *args) +_io__IOBase_seekable_impl(PyObject *self) +/*[clinic end generated code: output=4c24c67f5f32a43d input=22676eebb81dcf1e]*/ { Py_RETURN_FALSE; } @@ -333,13 +363,17 @@ _PyIOBase_check_seekable(PyObject *self, PyObject *args) return res; } -PyDoc_STRVAR(iobase_readable_doc, - "Return whether object was opened for reading.\n" - "\n" - "If False, read() will raise UnsupportedOperation."); +/*[clinic input] +_io._IOBase.readable + +Return whether object was opened for reading. + +If False, read() will raise UnsupportedOperation. +[clinic start generated code]*/ static PyObject * -iobase_readable(PyObject *self, PyObject *args) +_io__IOBase_readable_impl(PyObject *self) +/*[clinic end generated code: output=e48089250686388b input=12fc3d8f6be46434]*/ { Py_RETURN_FALSE; } @@ -362,13 +396,17 @@ _PyIOBase_check_readable(PyObject *self, PyObject *args) return res; } -PyDoc_STRVAR(iobase_writable_doc, - "Return whether object was opened for writing.\n" - "\n" - "If False, write() will raise UnsupportedOperation."); +/*[clinic input] +_io._IOBase.writable + +Return whether object was opened for writing. + +If False, write() will raise UnsupportedOperation. +[clinic start generated code]*/ static PyObject * -iobase_writable(PyObject *self, PyObject *args) +_io__IOBase_writable_impl(PyObject *self) +/*[clinic end generated code: output=406001d0985be14f input=c17a0bb6a8dfc590]*/ { Py_RETURN_FALSE; } @@ -413,24 +451,32 @@ iobase_exit(PyObject *self, PyObject *args) /* XXX Should these be present even if unimplemented? */ -PyDoc_STRVAR(iobase_fileno_doc, - "Returns underlying file descriptor if one exists.\n" - "\n" - "An IOError is raised if the IO object does not use a file descriptor.\n"); +/*[clinic input] +_io._IOBase.fileno + +Returns underlying file descriptor if one exists. + +An IOError is raised if the IO object does not use a file descriptor. +[clinic start generated code]*/ static PyObject * -iobase_fileno(PyObject *self, PyObject *args) +_io__IOBase_fileno_impl(PyObject *self) +/*[clinic end generated code: output=7cc0973f0f5f3b73 input=32773c5df4b7eede]*/ { return iobase_unsupported("fileno"); } -PyDoc_STRVAR(iobase_isatty_doc, - "Return whether this is an 'interactive' stream.\n" - "\n" - "Return False if it can't be determined.\n"); +/*[clinic input] +_io._IOBase.isatty + +Return whether this is an 'interactive' stream. + +Return False if it can't be determined. +[clinic start generated code]*/ static PyObject * -iobase_isatty(PyObject *self, PyObject *args) +_io__IOBase_isatty_impl(PyObject *self) +/*[clinic end generated code: output=60cab77cede41cdd input=9ef76530d368458b]*/ { if (_PyIOBase_check_closed(self, Py_True) == NULL) return NULL; @@ -439,30 +485,31 @@ iobase_isatty(PyObject *self, PyObject *args) /* Readline(s) and writelines */ -PyDoc_STRVAR(iobase_readline_doc, - "Read and return a line from the stream.\n" - "\n" - "If limit is specified, at most limit bytes will be read.\n" - "\n" - "The line terminator is always b'\\n' for binary files; for text\n" - "files, the newlines argument to open can be used to select the line\n" - "terminator(s) recognized.\n"); +/*[clinic input] +_io._IOBase.readline + size as limit: io_ssize_t = -1 + / + +Read and return a line from the stream. + +If size is specified, at most size bytes will be read. + +The line terminator is always b'\n' for binary files; for text +files, the newlines argument to open can be used to select the line +terminator(s) recognized. +[clinic start generated code]*/ static PyObject * -iobase_readline(PyObject *self, PyObject *args) +_io__IOBase_readline_impl(PyObject *self, Py_ssize_t limit) +/*[clinic end generated code: output=4479f79b58187840 input=df4cc8884f553cab]*/ { /* For backwards compatibility, a (slowish) readline(). */ - Py_ssize_t limit = -1; int has_peek = 0; PyObject *buffer, *result; Py_ssize_t old_size = -1; _Py_IDENTIFIER(peek); - if (!PyArg_ParseTuple(args, "|O&:readline", &_PyIO_ConvertSsize_t, &limit)) { - return NULL; - } - if (_PyObject_HasAttrId(self, &PyId_peek)) has_peek = 1; @@ -585,23 +632,25 @@ iobase_iternext(PyObject *self) return line; } -PyDoc_STRVAR(iobase_readlines_doc, - "Return a list of lines from the stream.\n" - "\n" - "hint can be specified to control the number of lines read: no more\n" - "lines will be read if the total size (in bytes/characters) of all\n" - "lines so far exceeds hint."); +/*[clinic input] +_io._IOBase.readlines + hint: io_ssize_t = -1 + / + +Return a list of lines from the stream. + +hint can be specified to control the number of lines read: no more +lines will be read if the total size (in bytes/characters) of all +lines so far exceeds hint. +[clinic start generated code]*/ static PyObject * -iobase_readlines(PyObject *self, PyObject *args) +_io__IOBase_readlines_impl(PyObject *self, Py_ssize_t hint) +/*[clinic end generated code: output=2f50421677fa3dea input=1961c4a95e96e661]*/ { - Py_ssize_t hint = -1, length = 0; + Py_ssize_t length = 0; PyObject *result; - if (!PyArg_ParseTuple(args, "|O&:readlines", &_PyIO_ConvertSsize_t, &hint)) { - return NULL; - } - result = PyList_New(0); if (result == NULL) return NULL; @@ -646,14 +695,17 @@ iobase_readlines(PyObject *self, PyObject *args) return result; } +/*[clinic input] +_io._IOBase.writelines + lines: object + / +[clinic start generated code]*/ + static PyObject * -iobase_writelines(PyObject *self, PyObject *args) +_io__IOBase_writelines(PyObject *self, PyObject *lines) +/*[clinic end generated code: output=976eb0a9b60a6628 input=432e729a8450b3cb]*/ { - PyObject *lines, *iter, *res; - - if (!PyArg_ParseTuple(args, "O:writelines", &lines)) { - return NULL; - } + PyObject *iter, *res; if (_PyIOBase_check_closed(self, Py_True) == NULL) return NULL; @@ -688,31 +740,33 @@ iobase_writelines(PyObject *self, PyObject *args) Py_RETURN_NONE; } +#include "clinic/iobase.c.h" + static PyMethodDef iobase_methods[] = { {"seek", iobase_seek, METH_VARARGS, iobase_seek_doc}, - {"tell", iobase_tell, METH_NOARGS, iobase_tell_doc}, + _IO__IOBASE_TELL_METHODDEF {"truncate", iobase_truncate, METH_VARARGS, iobase_truncate_doc}, - {"flush", iobase_flush, METH_NOARGS, iobase_flush_doc}, - {"close", iobase_close, METH_NOARGS, iobase_close_doc}, + _IO__IOBASE_FLUSH_METHODDEF + _IO__IOBASE_CLOSE_METHODDEF - {"seekable", iobase_seekable, METH_NOARGS, iobase_seekable_doc}, - {"readable", iobase_readable, METH_NOARGS, iobase_readable_doc}, - {"writable", iobase_writable, METH_NOARGS, iobase_writable_doc}, + _IO__IOBASE_SEEKABLE_METHODDEF + _IO__IOBASE_READABLE_METHODDEF + _IO__IOBASE_WRITABLE_METHODDEF {"_checkClosed", _PyIOBase_check_closed, METH_NOARGS}, {"_checkSeekable", _PyIOBase_check_seekable, METH_NOARGS}, {"_checkReadable", _PyIOBase_check_readable, METH_NOARGS}, {"_checkWritable", _PyIOBase_check_writable, METH_NOARGS}, - {"fileno", iobase_fileno, METH_NOARGS, iobase_fileno_doc}, - {"isatty", iobase_isatty, METH_NOARGS, iobase_isatty_doc}, + _IO__IOBASE_FILENO_METHODDEF + _IO__IOBASE_ISATTY_METHODDEF {"__enter__", iobase_enter, METH_NOARGS}, {"__exit__", iobase_exit, METH_VARARGS}, - {"readline", iobase_readline, METH_VARARGS, iobase_readline_doc}, - {"readlines", iobase_readlines, METH_VARARGS, iobase_readlines_doc}, - {"writelines", iobase_writelines, METH_VARARGS}, + _IO__IOBASE_READLINE_METHODDEF + _IO__IOBASE_READLINES_METHODDEF + _IO__IOBASE_WRITELINES_METHODDEF {NULL, NULL} }; @@ -795,16 +849,18 @@ PyDoc_STRVAR(rawiobase_doc, * either.) */ +/*[clinic input] +_io._RawIOBase.read + size as n: Py_ssize_t = -1 + / +[clinic start generated code]*/ + static PyObject * -rawiobase_read(PyObject *self, PyObject *args) +_io__RawIOBase_read_impl(PyObject *self, Py_ssize_t n) +/*[clinic end generated code: output=6cdeb731e3c9f13c input=b6d0dcf6417d1374]*/ { - Py_ssize_t n = -1; PyObject *b, *res; - if (!PyArg_ParseTuple(args, "|n:read", &n)) { - return NULL; - } - if (n < 0) { _Py_IDENTIFIER(readall); @@ -836,11 +892,15 @@ rawiobase_read(PyObject *self, PyObject *args) } -PyDoc_STRVAR(rawiobase_readall_doc, - "Read until EOF, using multiple read() call."); +/*[clinic input] +_io._RawIOBase.readall + +Read until EOF, using multiple read() call. +[clinic start generated code]*/ static PyObject * -rawiobase_readall(PyObject *self, PyObject *args) +_io__RawIOBase_readall_impl(PyObject *self) +/*[clinic end generated code: output=1987b9ce929425a0 input=688874141213622a]*/ { int r; PyObject *chunks = PyList_New(0); @@ -893,8 +953,8 @@ rawiobase_readall(PyObject *self, PyObject *args) } static PyMethodDef rawiobase_methods[] = { - {"read", rawiobase_read, METH_VARARGS}, - {"readall", rawiobase_readall, METH_NOARGS, rawiobase_readall_doc}, + _IO__RAWIOBASE_READ_METHODDEF + _IO__RAWIOBASE_READALL_METHODDEF {NULL, NULL} }; diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 9d73884f73..8315ab8e70 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -11,6 +11,12 @@ #define STATE_REALIZED 1 #define STATE_ACCUMULATING 2 +/*[clinic input] +module _io +class _io.StringIO "stringio *" "&PyStringIO_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c17bc0f42165cd7d]*/ + typedef struct { PyObject_HEAD Py_UCS4 *buf; @@ -39,6 +45,8 @@ typedef struct { PyObject *weakreflist; } stringio; +static int _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs); + #define CHECK_INITIALIZED(self) \ if (self->ok <= 0) { \ PyErr_SetString(PyExc_ValueError, \ @@ -58,12 +66,6 @@ typedef struct { return NULL; \ } -PyDoc_STRVAR(stringio_doc, - "Text I/O implementation using an in-memory buffer.\n" - "\n" - "The initial_value argument sets the value of object. The newline\n" - "argument is like the one of TextIOWrapper's constructor."); - /* Internal routine for changing the size, in terms of characters, of the buffer of StringIO objects. The caller should ensure that the 'size' @@ -264,11 +266,15 @@ fail: return -1; } -PyDoc_STRVAR(stringio_getvalue_doc, - "Retrieve the entire contents of the object."); +/*[clinic input] +_io.StringIO.getvalue + +Retrieve the entire contents of the object. +[clinic start generated code]*/ static PyObject * -stringio_getvalue(stringio *self) +_io_StringIO_getvalue_impl(stringio *self) +/*[clinic end generated code: output=27b6a7bfeaebce01 input=d23cb81d6791cf88]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -278,33 +284,40 @@ stringio_getvalue(stringio *self) self->string_size); } -PyDoc_STRVAR(stringio_tell_doc, - "Tell the current file position."); +/*[clinic input] +_io.StringIO.tell + +Tell the current file position. +[clinic start generated code]*/ static PyObject * -stringio_tell(stringio *self) +_io_StringIO_tell_impl(stringio *self) +/*[clinic end generated code: output=2e87ac67b116c77b input=ec866ebaff02f405]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); return PyLong_FromSsize_t(self->pos); } -PyDoc_STRVAR(stringio_read_doc, - "Read at most n characters, returned as a string.\n" - "\n" - "If the argument is negative or omitted, read until EOF\n" - "is reached. Return an empty string at EOF.\n"); +/*[clinic input] +_io.StringIO.read + size as arg: object = None + / + +Read at most size characters, returned as a string. + +If the argument is negative or omitted, read until EOF +is reached. Return an empty string at EOF. +[clinic start generated code]*/ static PyObject * -stringio_read(stringio *self, PyObject *args) +_io_StringIO_read_impl(stringio *self, PyObject *arg) +/*[clinic end generated code: output=3676864773746f68 input=9a319015f6f3965c]*/ { Py_ssize_t size, n; Py_UCS4 *output; - PyObject *arg = Py_None; CHECK_INITIALIZED(self); - if (!PyArg_ParseTuple(args, "|O:read", &arg)) - return NULL; CHECK_CLOSED(self); if (PyNumber_Check(arg)) { @@ -373,20 +386,23 @@ _stringio_readline(stringio *self, Py_ssize_t limit) return PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, start, len); } -PyDoc_STRVAR(stringio_readline_doc, - "Read until newline or EOF.\n" - "\n" - "Returns an empty string if EOF is hit immediately.\n"); +/*[clinic input] +_io.StringIO.readline + size as arg: object = None + / + +Read until newline or EOF. + +Returns an empty string if EOF is hit immediately. +[clinic start generated code]*/ static PyObject * -stringio_readline(stringio *self, PyObject *args) +_io_StringIO_readline_impl(stringio *self, PyObject *arg) +/*[clinic end generated code: output=99fdcac03a3dee81 input=e0e0ed4042040176]*/ { - PyObject *arg = Py_None; Py_ssize_t limit = -1; CHECK_INITIALIZED(self); - if (!PyArg_ParseTuple(args, "|O:readline", &arg)) - return NULL; CHECK_CLOSED(self); ENSURE_REALIZED(self); @@ -441,22 +457,25 @@ stringio_iternext(stringio *self) return line; } -PyDoc_STRVAR(stringio_truncate_doc, - "Truncate size to pos.\n" - "\n" - "The pos argument defaults to the current file position, as\n" - "returned by tell(). The current file position is unchanged.\n" - "Returns the new absolute position.\n"); +/*[clinic input] +_io.StringIO.truncate + pos as arg: object = None + / + +Truncate size to pos. + +The pos argument defaults to the current file position, as +returned by tell(). The current file position is unchanged. +Returns the new absolute position. +[clinic start generated code]*/ static PyObject * -stringio_truncate(stringio *self, PyObject *args) +_io_StringIO_truncate_impl(stringio *self, PyObject *arg) +/*[clinic end generated code: output=6072439c2b01d306 input=748619a494ba53ad]*/ { Py_ssize_t size; - PyObject *arg = Py_None; CHECK_INITIALIZED(self); - if (!PyArg_ParseTuple(args, "|O:truncate", &arg)) - return NULL; CHECK_CLOSED(self); if (PyNumber_Check(arg)) { @@ -490,49 +509,51 @@ stringio_truncate(stringio *self, PyObject *args) return PyLong_FromSsize_t(size); } -PyDoc_STRVAR(stringio_seek_doc, - "Change stream position.\n" - "\n" - "Seek to character offset pos relative to position indicated by whence:\n" - " 0 Start of stream (the default). pos should be >= 0;\n" - " 1 Current position - pos must be 0;\n" - " 2 End of stream - pos must be 0.\n" - "Returns the new absolute position.\n"); +/*[clinic input] +_io.StringIO.seek + pos: Py_ssize_t + whence: int = 0 + / + +Change stream position. + +Seek to character offset pos relative to position indicated by whence: + 0 Start of stream (the default). pos should be >= 0; + 1 Current position - pos must be 0; + 2 End of stream - pos must be 0. +Returns the new absolute position. +[clinic start generated code]*/ static PyObject * -stringio_seek(stringio *self, PyObject *args) +_io_StringIO_seek_impl(stringio *self, Py_ssize_t pos, int whence) +/*[clinic end generated code: output=e9e0ac9a8ae71c25 input=e3855b24e7cae06a]*/ { - Py_ssize_t pos; - int mode = 0; - CHECK_INITIALIZED(self); - if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &mode)) - return NULL; CHECK_CLOSED(self); - if (mode != 0 && mode != 1 && mode != 2) { + if (whence != 0 && whence != 1 && whence != 2) { PyErr_Format(PyExc_ValueError, - "Invalid whence (%i, should be 0, 1 or 2)", mode); + "Invalid whence (%i, should be 0, 1 or 2)", whence); return NULL; } - else if (pos < 0 && mode == 0) { + else if (pos < 0 && whence == 0) { PyErr_Format(PyExc_ValueError, "Negative seek position %zd", pos); return NULL; } - else if (mode != 0 && pos != 0) { + else if (whence != 0 && pos != 0) { PyErr_SetString(PyExc_IOError, "Can't do nonzero cur-relative seeks"); return NULL; } - /* mode 0: offset relative to beginning of the string. - mode 1: no change to current position. - mode 2: change position to end of file. */ - if (mode == 1) { + /* whence = 0: offset relative to beginning of the string. + whence = 1: no change to current position. + whence = 2: change position to end of file. */ + if (whence == 1) { pos = self->pos; } - else if (mode == 2) { + else if (whence == 2) { pos = self->string_size; } @@ -541,14 +562,20 @@ stringio_seek(stringio *self, PyObject *args) return PyLong_FromSsize_t(self->pos); } -PyDoc_STRVAR(stringio_write_doc, - "Write string to file.\n" - "\n" - "Returns the number of characters written, which is always equal to\n" - "the length of the string.\n"); +/*[clinic input] +_io.StringIO.write + s as obj: object + / + +Write string to file. + +Returns the number of characters written, which is always equal to +the length of the string. +[clinic start generated code]*/ static PyObject * -stringio_write(stringio *self, PyObject *obj) +_io_StringIO_write(stringio *self, PyObject *obj) +/*[clinic end generated code: output=0deaba91a15b94da input=cf96f3b16586e669]*/ { Py_ssize_t size; @@ -569,14 +596,20 @@ stringio_write(stringio *self, PyObject *obj) return PyLong_FromSsize_t(size); } -PyDoc_STRVAR(stringio_close_doc, - "Close the IO object. Attempting any further operation after the\n" - "object is closed will raise a ValueError.\n" - "\n" - "This method has no effect if the file is already closed.\n"); +/*[clinic input] +_io.StringIO.close + +Close the IO object. + +Attempting any further operation after the object is closed +will raise a ValueError. + +This method has no effect if the file is already closed. +[clinic start generated code]*/ static PyObject * -stringio_close(stringio *self) +_io_StringIO_close_impl(stringio *self) +/*[clinic end generated code: output=04399355cbe518f1 input=cbc10b45f35d6d46]*/ { self->closed = 1; /* Free up some memory */ @@ -644,19 +677,25 @@ stringio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)self; } +/*[clinic input] +_io.StringIO.__init__ + initial_value as value: object(c_default="NULL") = '' + newline as newline_obj: object(c_default="NULL") = '\n' + +Text I/O implementation using an in-memory buffer. + +The initial_value argument sets the value of object. The newline +argument is like the one of TextIOWrapper's constructor. +[clinic start generated code]*/ + static int -stringio_init(stringio *self, PyObject *args, PyObject *kwds) +_io_StringIO___init___impl(stringio *self, PyObject *value, + PyObject *newline_obj) +/*[clinic end generated code: output=a421ea023b22ef4e input=cee2d9181b2577a3]*/ { - char *kwlist[] = {"initial_value", "newline", NULL}; - PyObject *value = NULL; - PyObject *newline_obj = NULL; char *newline = "\n"; Py_ssize_t value_len; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:__init__", kwlist, - &value, &newline_obj)) - return -1; - /* Parse the newline argument. This used to be done with the 'z' specifier, however this allowed any object with the buffer interface to be converted. Thus we have to parse it manually since we only want to @@ -761,33 +800,45 @@ stringio_init(stringio *self, PyObject *args, PyObject *kwds) /* Properties and pseudo-properties */ -PyDoc_STRVAR(stringio_readable_doc, -"readable() -> bool. Returns True if the IO object can be read."); +/*[clinic input] +_io.StringIO.readable -PyDoc_STRVAR(stringio_writable_doc, -"writable() -> bool. Returns True if the IO object can be written."); - -PyDoc_STRVAR(stringio_seekable_doc, -"seekable() -> bool. Returns True if the IO object can be seeked."); +Returns True if the IO object can be read. +[clinic start generated code]*/ static PyObject * -stringio_seekable(stringio *self, PyObject *args) +_io_StringIO_readable_impl(stringio *self) +/*[clinic end generated code: output=b19d44dd8b1ceb99 input=39ce068b224c21ad]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); Py_RETURN_TRUE; } +/*[clinic input] +_io.StringIO.writable + +Returns True if the IO object can be written. +[clinic start generated code]*/ + static PyObject * -stringio_readable(stringio *self, PyObject *args) +_io_StringIO_writable_impl(stringio *self) +/*[clinic end generated code: output=13e4dd77187074ca input=7a691353aac38835]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); Py_RETURN_TRUE; } +/*[clinic input] +_io.StringIO.seekable + +Returns True if the IO object can be seeked. +[clinic start generated code]*/ + static PyObject * -stringio_writable(stringio *self, PyObject *args) +_io_StringIO_seekable_impl(stringio *self) +/*[clinic end generated code: output=4d20b4641c756879 input=4c606d05b32952e6]*/ { CHECK_INITIALIZED(self); CHECK_CLOSED(self); @@ -809,7 +860,7 @@ stringio_writable(stringio *self, PyObject *args) static PyObject * stringio_getstate(stringio *self) { - PyObject *initvalue = stringio_getvalue(self); + PyObject *initvalue = _io_StringIO_getvalue_impl(self); PyObject *dict; PyObject *state; @@ -857,7 +908,7 @@ stringio_setstate(stringio *self, PyObject *state) initarg = PyTuple_GetSlice(state, 0, 2); if (initarg == NULL) return NULL; - if (stringio_init(self, initarg, NULL) < 0) { + if (_io_StringIO___init__((PyObject *)self, initarg, NULL) < 0) { Py_DECREF(initarg); return NULL; } @@ -959,19 +1010,21 @@ stringio_newlines(stringio *self, void *context) return PyObject_GetAttr(self->decoder, _PyIO_str_newlines); } +#include "clinic/stringio.c.h" + static struct PyMethodDef stringio_methods[] = { - {"close", (PyCFunction)stringio_close, METH_NOARGS, stringio_close_doc}, - {"getvalue", (PyCFunction)stringio_getvalue, METH_NOARGS, stringio_getvalue_doc}, - {"read", (PyCFunction)stringio_read, METH_VARARGS, stringio_read_doc}, - {"readline", (PyCFunction)stringio_readline, METH_VARARGS, stringio_readline_doc}, - {"tell", (PyCFunction)stringio_tell, METH_NOARGS, stringio_tell_doc}, - {"truncate", (PyCFunction)stringio_truncate, METH_VARARGS, stringio_truncate_doc}, - {"seek", (PyCFunction)stringio_seek, METH_VARARGS, stringio_seek_doc}, - {"write", (PyCFunction)stringio_write, METH_O, stringio_write_doc}, - - {"seekable", (PyCFunction)stringio_seekable, METH_NOARGS, stringio_seekable_doc}, - {"readable", (PyCFunction)stringio_readable, METH_NOARGS, stringio_readable_doc}, - {"writable", (PyCFunction)stringio_writable, METH_NOARGS, stringio_writable_doc}, + _IO_STRINGIO_CLOSE_METHODDEF + _IO_STRINGIO_GETVALUE_METHODDEF + _IO_STRINGIO_READ_METHODDEF + _IO_STRINGIO_READLINE_METHODDEF + _IO_STRINGIO_TELL_METHODDEF + _IO_STRINGIO_TRUNCATE_METHODDEF + _IO_STRINGIO_SEEK_METHODDEF + _IO_STRINGIO_WRITE_METHODDEF + + _IO_STRINGIO_SEEKABLE_METHODDEF + _IO_STRINGIO_READABLE_METHODDEF + _IO_STRINGIO_WRITABLE_METHODDEF {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS}, {"__setstate__", (PyCFunction)stringio_setstate, METH_O}, @@ -1013,7 +1066,7 @@ PyTypeObject PyStringIO_Type = { 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - stringio_doc, /*tp_doc*/ + _io_StringIO___init____doc__, /*tp_doc*/ (traverseproc)stringio_traverse, /*tp_traverse*/ (inquiry)stringio_clear, /*tp_clear*/ 0, /*tp_richcompare*/ @@ -1028,7 +1081,7 @@ PyTypeObject PyStringIO_Type = { 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ offsetof(stringio, dict), /*tp_dictoffset*/ - (initproc)stringio_init, /*tp_init*/ + _io_StringIO___init__, /*tp_init*/ 0, /*tp_alloc*/ stringio_new, /*tp_new*/ }; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 67ac4457d5..b5990f3060 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -11,6 +11,20 @@ #include "structmember.h" #include "_iomodule.h" +/*[clinic input] +module _io +class _io.IncrementalNewlineDecoder "nldecoder_object *" "&PyIncrementalNewlineDecoder_Type" +class _io.TextIOWrapper "textio *" "&TextIOWrapper_TYpe" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2097a4fc85670c26]*/ + +/*[python input] +class io_ssize_t_converter(CConverter): + type = 'Py_ssize_t' + converter = '_PyIO_ConvertSsize_t' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/ + _Py_IDENTIFIER(close); _Py_IDENTIFIER(_dealloc_warn); _Py_IDENTIFIER(decode); @@ -210,16 +224,6 @@ PyTypeObject PyTextIOBase_Type = { /* IncrementalNewlineDecoder */ -PyDoc_STRVAR(incrementalnewlinedecoder_doc, - "Codec used when reading a file in universal newlines mode. It wraps\n" - "another incremental decoder, translating \\r\\n and \\r into \\n. It also\n" - "records the types of newlines encountered. When used with\n" - "translate=False, it ensures that the newline sequence is returned in\n" - "one piece. When used with decoder=None, it expects unicode strings as\n" - "decode input and translates newlines without first invoking an external\n" - "decoder.\n" - ); - typedef struct { PyObject_HEAD PyObject *decoder; @@ -229,19 +233,28 @@ typedef struct { unsigned int seennl: 3; } nldecoder_object; -static int -incrementalnewlinedecoder_init(nldecoder_object *self, - PyObject *args, PyObject *kwds) -{ - PyObject *decoder; - int translate; - PyObject *errors = NULL; - char *kwlist[] = {"decoder", "translate", "errors", NULL}; +/*[clinic input] +_io.IncrementalNewlineDecoder.__init__ + decoder: object + translate: int + errors: object(c_default="NULL") = "strict" - if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi|O:IncrementalNewlineDecoder", - kwlist, &decoder, &translate, &errors)) - return -1; +Codec used when reading a file in universal newlines mode. + +It wraps another incremental decoder, translating \r\n and \r into \n. +It also records the types of newlines encountered. When used with +translate=False, it ensures that the newline sequence is returned in +one piece. When used with decoder=None, it expects unicode strings as +decode input and translates newlines without first invoking an external +decoder. +[clinic start generated code]*/ +static int +_io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self, + PyObject *decoder, int translate, + PyObject *errors) +/*[clinic end generated code: output=fbd04d443e764ec2 input=89db6b19c6b126bf]*/ +{ self->decoder = decoder; Py_INCREF(decoder); @@ -495,22 +508,27 @@ _PyIncrementalNewlineDecoder_decode(PyObject *myself, return NULL; } +/*[clinic input] +_io.IncrementalNewlineDecoder.decode + input: object + final: int(c_default="0") = False +[clinic start generated code]*/ + static PyObject * -incrementalnewlinedecoder_decode(nldecoder_object *self, - PyObject *args, PyObject *kwds) +_io_IncrementalNewlineDecoder_decode_impl(nldecoder_object *self, + PyObject *input, int final) +/*[clinic end generated code: output=0d486755bb37a66e input=d65677385bfd6827]*/ { - char *kwlist[] = {"input", "final", NULL}; - PyObject *input; - int final = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:IncrementalNewlineDecoder", - kwlist, &input, &final)) - return NULL; return _PyIncrementalNewlineDecoder_decode((PyObject *) self, input, final); } +/*[clinic input] +_io.IncrementalNewlineDecoder.getstate +[clinic start generated code]*/ + static PyObject * -incrementalnewlinedecoder_getstate(nldecoder_object *self, PyObject *args) +_io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self) +/*[clinic end generated code: output=f0d2c9c136f4e0d0 input=f8ff101825e32e7f]*/ { PyObject *buffer; unsigned PY_LONG_LONG flag; @@ -537,8 +555,16 @@ incrementalnewlinedecoder_getstate(nldecoder_object *self, PyObject *args) return Py_BuildValue("NK", buffer, flag); } +/*[clinic input] +_io.IncrementalNewlineDecoder.setstate + state: object + / +[clinic start generated code]*/ + static PyObject * -incrementalnewlinedecoder_setstate(nldecoder_object *self, PyObject *state) +_io_IncrementalNewlineDecoder_setstate(nldecoder_object *self, + PyObject *state) +/*[clinic end generated code: output=c10c622508b576cb input=c53fb505a76dbbe2]*/ { PyObject *buffer; unsigned PY_LONG_LONG flag; @@ -556,8 +582,13 @@ incrementalnewlinedecoder_setstate(nldecoder_object *self, PyObject *state) Py_RETURN_NONE; } +/*[clinic input] +_io.IncrementalNewlineDecoder.reset +[clinic start generated code]*/ + static PyObject * -incrementalnewlinedecoder_reset(nldecoder_object *self, PyObject *args) +_io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self) +/*[clinic end generated code: output=32fa40c7462aa8ff input=728678ddaea776df]*/ { self->seennl = 0; self->pendingcr = 0; @@ -591,95 +622,8 @@ incrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context) } - -static PyMethodDef incrementalnewlinedecoder_methods[] = { - {"decode", (PyCFunction)incrementalnewlinedecoder_decode, METH_VARARGS|METH_KEYWORDS}, - {"getstate", (PyCFunction)incrementalnewlinedecoder_getstate, METH_NOARGS}, - {"setstate", (PyCFunction)incrementalnewlinedecoder_setstate, METH_O}, - {"reset", (PyCFunction)incrementalnewlinedecoder_reset, METH_NOARGS}, - {NULL} -}; - -static PyGetSetDef incrementalnewlinedecoder_getset[] = { - {"newlines", (getter)incrementalnewlinedecoder_newlines_get, NULL, NULL}, - {NULL} -}; - -PyTypeObject PyIncrementalNewlineDecoder_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_io.IncrementalNewlineDecoder", /*tp_name*/ - sizeof(nldecoder_object), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)incrementalnewlinedecoder_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare */ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - incrementalnewlinedecoder_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /*tp_weaklistoffset*/ - 0, /* tp_iter */ - 0, /* tp_iternext */ - incrementalnewlinedecoder_methods, /* tp_methods */ - 0, /* tp_members */ - incrementalnewlinedecoder_getset, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)incrementalnewlinedecoder_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ -}; - - /* TextIOWrapper */ -PyDoc_STRVAR(textiowrapper_doc, - "Character and line based layer over a BufferedIOBase object, buffer.\n" - "\n" - "encoding gives the name of the encoding that the stream will be\n" - "decoded or encoded with. It defaults to locale.getpreferredencoding(False).\n" - "\n" - "errors determines the strictness of encoding and decoding (see\n" - "help(codecs.Codec) or the documentation for codecs.register) and\n" - "defaults to \"strict\".\n" - "\n" - "newline controls how line endings are handled. It can be None, '',\n" - "'\\n', '\\r', and '\\r\\n'. It works as follows:\n" - "\n" - "* On input, if newline is None, universal newlines mode is\n" - " enabled. Lines in the input can end in '\\n', '\\r', or '\\r\\n', and\n" - " these are translated into '\\n' before being returned to the\n" - " caller. If it is '', universal newline mode is enabled, but line\n" - " endings are returned to the caller untranslated. If it has any of\n" - " the other legal values, input lines are only terminated by the given\n" - " string, and the line ending is returned to the caller untranslated.\n" - "\n" - "* On output, if newline is None, any '\\n' characters written are\n" - " translated to the system default line separator, os.linesep. If\n" - " newline is '' or '\\n', no translation takes place. If newline is any\n" - " of the other legal values, any '\\n' characters written are translated\n" - " to the given string.\n" - "\n" - "If line_buffering is True, a call to flush is implied when a call to\n" - "write contains a newline character." - ); - typedef PyObject * (*encodefunc_t)(PyObject *, PyObject *); @@ -742,7 +686,6 @@ typedef struct PyObject *dict; } textio; - /* A couple of specialized cases in order to bypass the slow incremental encoding methods for the most popular encodings. */ @@ -843,28 +786,59 @@ static encodefuncentry encodefuncs[] = { }; +/*[clinic input] +_io.TextIOWrapper.__init__ + buffer: object + encoding: str(nullable=True) = NULL + errors: str(nullable=True) = NULL + newline: str(nullable=True) = NULL + line_buffering: int(c_default="0") = False + write_through: int(c_default="0") = False + +Character and line based layer over a BufferedIOBase object, buffer. + +encoding gives the name of the encoding that the stream will be +decoded or encoded with. It defaults to locale.getpreferredencoding(False). + +errors determines the strictness of encoding and decoding (see +help(codecs.Codec) or the documentation for codecs.register) and +defaults to "strict". + +newline controls how line endings are handled. It can be None, '', +'\n', '\r', and '\r\n'. It works as follows: + +* On input, if newline is None, universal newlines mode is + enabled. Lines in the input can end in '\n', '\r', or '\r\n', and + these are translated into '\n' before being returned to the + caller. If it is '', universal newline mode is enabled, but line + endings are returned to the caller untranslated. If it has any of + the other legal values, input lines are only terminated by the given + string, and the line ending is returned to the caller untranslated. + +* On output, if newline is None, any '\n' characters written are + translated to the system default line separator, os.linesep. If + newline is '' or '\n', no translation takes place. If newline is any + of the other legal values, any '\n' characters written are translated + to the given string. + +If line_buffering is True, a call to flush is implied when a call to +write contains a newline character. +[clinic start generated code]*/ + static int -textiowrapper_init(textio *self, PyObject *args, PyObject *kwds) -{ - char *kwlist[] = {"buffer", "encoding", "errors", - "newline", "line_buffering", "write_through", - NULL}; - PyObject *buffer, *raw, *codec_info = NULL; - char *encoding = NULL; - char *errors = NULL; - char *newline = NULL; - int line_buffering = 0, write_through = 0; +_io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, + const char *encoding, const char *errors, + const char *newline, int line_buffering, + int write_through) +/*[clinic end generated code: output=56a83402ce2a8381 input=1f20decb8d54a4ec]*/ +{ + PyObject *raw, *codec_info = NULL; _PyIO_State *state = NULL; - PyObject *res; int r; self->ok = 0; self->detached = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|zzzii:fileio", - kwlist, &buffer, &encoding, &errors, - &newline, &line_buffering, &write_through)) - return -1; if (newline && newline[0] != '\0' && !(newline[0] == '\n' && newline[1] == '\0') @@ -1244,8 +1218,13 @@ textiowrapper_closed_get(textio *self, void *context); } +/*[clinic input] +_io.TextIOWrapper.detach +[clinic start generated code]*/ + static PyObject * -textiowrapper_detach(textio *self) +_io_TextIOWrapper_detach_impl(textio *self) +/*[clinic end generated code: output=7ba3715cd032d5f2 input=e5a71fbda9e1d9f9]*/ { PyObject *buffer, *res; CHECK_ATTACHED(self); @@ -1290,25 +1269,26 @@ _textiowrapper_writeflush(textio *self) return 0; } +/*[clinic input] +_io.TextIOWrapper.write + text: unicode + / +[clinic start generated code]*/ + static PyObject * -textiowrapper_write(textio *self, PyObject *args) +_io_TextIOWrapper_write_impl(textio *self, PyObject *text) +/*[clinic end generated code: output=d2deb0d50771fcec input=fdf19153584a0e44]*/ { PyObject *ret; - PyObject *text; /* owned reference */ PyObject *b; Py_ssize_t textlen; int haslf = 0; int needflush = 0, text_needflush = 0; - CHECK_ATTACHED(self); - - if (!PyArg_ParseTuple(args, "U:write", &text)) { - return NULL; - } - if (PyUnicode_READY(text) == -1) return NULL; + CHECK_ATTACHED(self); CHECK_CLOSED(self); if (self->encoder == NULL) @@ -1557,17 +1537,19 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) return -1; } +/*[clinic input] +_io.TextIOWrapper.read + size as n: io_ssize_t = -1 + / +[clinic start generated code]*/ + static PyObject * -textiowrapper_read(textio *self, PyObject *args) +_io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) +/*[clinic end generated code: output=7e651ce6cc6a25a6 input=8c09398424085cca]*/ { - Py_ssize_t n = -1; PyObject *result = NULL, *chunks = NULL; CHECK_ATTACHED(self); - - if (!PyArg_ParseTuple(args, "|O&:read", &_PyIO_ConvertSsize_t, &n)) - return NULL; - CHECK_CLOSED(self); if (self->decoder == NULL) @@ -1933,16 +1915,18 @@ _textiowrapper_readline(textio *self, Py_ssize_t limit) return NULL; } +/*[clinic input] +_io.TextIOWrapper.readline + size: Py_ssize_t = -1 + / +[clinic start generated code]*/ + static PyObject * -textiowrapper_readline(textio *self, PyObject *args) +_io_TextIOWrapper_readline_impl(textio *self, Py_ssize_t size) +/*[clinic end generated code: output=344afa98804e8b25 input=56c7172483b36db6]*/ { - Py_ssize_t limit = -1; - CHECK_ATTACHED(self); - if (!PyArg_ParseTuple(args, "|n:readline", &limit)) { - return NULL; - } - return _textiowrapper_readline(self, limit); + return _textiowrapper_readline(self, size); } /* Seek and Tell */ @@ -2074,19 +2058,23 @@ _textiowrapper_encoder_setstate(textio *self, cookie_type *cookie) self, cookie->start_pos == 0 && cookie->dec_flags == 0); } +/*[clinic input] +_io.TextIOWrapper.seek + cookie as cookieObj: object + whence: int = 0 + / +[clinic start generated code]*/ + static PyObject * -textiowrapper_seek(textio *self, PyObject *args) +_io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence) +/*[clinic end generated code: output=0a15679764e2d04d input=0458abeb3d7842be]*/ { - PyObject *cookieObj, *posobj; + PyObject *posobj; cookie_type cookie; - int whence = 0; PyObject *res; int cmp; CHECK_ATTACHED(self); - - if (!PyArg_ParseTuple(args, "O|i:seek", &cookieObj, &whence)) - return NULL; CHECK_CLOSED(self); Py_INCREF(cookieObj); @@ -2258,8 +2246,13 @@ textiowrapper_seek(textio *self, PyObject *args) } +/*[clinic input] +_io.TextIOWrapper.tell +[clinic start generated code]*/ + static PyObject * -textiowrapper_tell(textio *self, PyObject *args) +_io_TextIOWrapper_tell_impl(textio *self) +/*[clinic end generated code: output=4f168c08bf34ad5f input=9a2caf88c24f9ddf]*/ { PyObject *res; PyObject *posobj = NULL; @@ -2466,16 +2459,19 @@ fail: return NULL; } +/*[clinic input] +_io.TextIOWrapper.truncate + pos: object = None + / +[clinic start generated code]*/ + static PyObject * -textiowrapper_truncate(textio *self, PyObject *args) +_io_TextIOWrapper_truncate_impl(textio *self, PyObject *pos) +/*[clinic end generated code: output=90ec2afb9bb7745f input=56ec8baa65aea377]*/ { - PyObject *pos = Py_None; PyObject *res; CHECK_ATTACHED(self) - if (!PyArg_ParseTuple(args, "|O:truncate", &pos)) { - return NULL; - } res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_flush, NULL); if (res == NULL) @@ -2540,36 +2536,61 @@ error: /* Inquiries */ +/*[clinic input] +_io.TextIOWrapper.fileno +[clinic start generated code]*/ + static PyObject * -textiowrapper_fileno(textio *self, PyObject *args) +_io_TextIOWrapper_fileno_impl(textio *self) +/*[clinic end generated code: output=21490a4c3da13e6c input=c488ca83d0069f9b]*/ { CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_fileno, NULL); } +/*[clinic input] +_io.TextIOWrapper.seekable +[clinic start generated code]*/ + static PyObject * -textiowrapper_seekable(textio *self, PyObject *args) +_io_TextIOWrapper_seekable_impl(textio *self) +/*[clinic end generated code: output=ab223dbbcffc0f00 input=8b005ca06e1fca13]*/ { CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_seekable, NULL); } +/*[clinic input] +_io.TextIOWrapper.readable +[clinic start generated code]*/ + static PyObject * -textiowrapper_readable(textio *self, PyObject *args) +_io_TextIOWrapper_readable_impl(textio *self) +/*[clinic end generated code: output=72ff7ba289a8a91b input=0704ea7e01b0d3eb]*/ { CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_readable, NULL); } +/*[clinic input] +_io.TextIOWrapper.writable +[clinic start generated code]*/ + static PyObject * -textiowrapper_writable(textio *self, PyObject *args) +_io_TextIOWrapper_writable_impl(textio *self) +/*[clinic end generated code: output=a728c71790d03200 input=c41740bc9d8636e8]*/ { CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_writable, NULL); } +/*[clinic input] +_io.TextIOWrapper.isatty +[clinic start generated code]*/ + static PyObject * -textiowrapper_isatty(textio *self, PyObject *args) +_io_TextIOWrapper_isatty_impl(textio *self) +/*[clinic end generated code: output=12be1a35bace882e input=fb68d9f2c99bbfff]*/ { CHECK_ATTACHED(self); return _PyObject_CallMethodId(self->buffer, &PyId_isatty, NULL); @@ -2583,8 +2604,13 @@ textiowrapper_getstate(textio *self, PyObject *args) return NULL; } +/*[clinic input] +_io.TextIOWrapper.flush +[clinic start generated code]*/ + static PyObject * -textiowrapper_flush(textio *self, PyObject *args) +_io_TextIOWrapper_flush_impl(textio *self) +/*[clinic end generated code: output=59de9165f9c2e4d2 input=928c60590694ab85]*/ { CHECK_ATTACHED(self); CHECK_CLOSED(self); @@ -2594,8 +2620,13 @@ textiowrapper_flush(textio *self, PyObject *args) return _PyObject_CallMethodId(self->buffer, &PyId_flush, NULL); } +/*[clinic input] +_io.TextIOWrapper.close +[clinic start generated code]*/ + static PyObject * -textiowrapper_close(textio *self, PyObject *args) +_io_TextIOWrapper_close_impl(textio *self) +/*[clinic end generated code: output=056ccf8b4876e4f4 input=9c2114315eae1948]*/ { PyObject *res; int r; @@ -2739,24 +2770,81 @@ textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context) return 0; } +#include "clinic/textio.c.h" + +static PyMethodDef incrementalnewlinedecoder_methods[] = { + _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF + _IO_INCREMENTALNEWLINEDECODER_GETSTATE_METHODDEF + _IO_INCREMENTALNEWLINEDECODER_SETSTATE_METHODDEF + _IO_INCREMENTALNEWLINEDECODER_RESET_METHODDEF + {NULL} +}; + +static PyGetSetDef incrementalnewlinedecoder_getset[] = { + {"newlines", (getter)incrementalnewlinedecoder_newlines_get, NULL, NULL}, + {NULL} +}; + +PyTypeObject PyIncrementalNewlineDecoder_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_io.IncrementalNewlineDecoder", /*tp_name*/ + sizeof(nldecoder_object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)incrementalnewlinedecoder_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare */ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + _io_IncrementalNewlineDecoder___init____doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /*tp_weaklistoffset*/ + 0, /* tp_iter */ + 0, /* tp_iternext */ + incrementalnewlinedecoder_methods, /* tp_methods */ + 0, /* tp_members */ + incrementalnewlinedecoder_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + _io_IncrementalNewlineDecoder___init__, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ +}; + + static PyMethodDef textiowrapper_methods[] = { - {"detach", (PyCFunction)textiowrapper_detach, METH_NOARGS}, - {"write", (PyCFunction)textiowrapper_write, METH_VARARGS}, - {"read", (PyCFunction)textiowrapper_read, METH_VARARGS}, - {"readline", (PyCFunction)textiowrapper_readline, METH_VARARGS}, - {"flush", (PyCFunction)textiowrapper_flush, METH_NOARGS}, - {"close", (PyCFunction)textiowrapper_close, METH_NOARGS}, - - {"fileno", (PyCFunction)textiowrapper_fileno, METH_NOARGS}, - {"seekable", (PyCFunction)textiowrapper_seekable, METH_NOARGS}, - {"readable", (PyCFunction)textiowrapper_readable, METH_NOARGS}, - {"writable", (PyCFunction)textiowrapper_writable, METH_NOARGS}, - {"isatty", (PyCFunction)textiowrapper_isatty, METH_NOARGS}, + _IO_TEXTIOWRAPPER_DETACH_METHODDEF + _IO_TEXTIOWRAPPER_WRITE_METHODDEF + _IO_TEXTIOWRAPPER_READ_METHODDEF + _IO_TEXTIOWRAPPER_READLINE_METHODDEF + _IO_TEXTIOWRAPPER_FLUSH_METHODDEF + _IO_TEXTIOWRAPPER_CLOSE_METHODDEF + + _IO_TEXTIOWRAPPER_FILENO_METHODDEF + _IO_TEXTIOWRAPPER_SEEKABLE_METHODDEF + _IO_TEXTIOWRAPPER_READABLE_METHODDEF + _IO_TEXTIOWRAPPER_WRITABLE_METHODDEF + _IO_TEXTIOWRAPPER_ISATTY_METHODDEF {"__getstate__", (PyCFunction)textiowrapper_getstate, METH_NOARGS}, - {"seek", (PyCFunction)textiowrapper_seek, METH_VARARGS}, - {"tell", (PyCFunction)textiowrapper_tell, METH_NOARGS}, - {"truncate", (PyCFunction)textiowrapper_truncate, METH_VARARGS}, + _IO_TEXTIOWRAPPER_SEEK_METHODDEF + _IO_TEXTIOWRAPPER_TELL_METHODDEF + _IO_TEXTIOWRAPPER_TRUNCATE_METHODDEF {NULL, NULL} }; @@ -2802,7 +2890,7 @@ PyTypeObject PyTextIOWrapper_Type = { 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /*tp_flags*/ - textiowrapper_doc, /* tp_doc */ + _io_TextIOWrapper___init____doc__, /* tp_doc */ (traverseproc)textiowrapper_traverse, /* tp_traverse */ (inquiry)textiowrapper_clear, /* tp_clear */ 0, /* tp_richcompare */ @@ -2817,7 +2905,7 @@ PyTypeObject PyTextIOWrapper_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(textio, dict), /*tp_dictoffset*/ - (initproc)textiowrapper_init, /* tp_init */ + _io_TextIOWrapper___init__, /* tp_init */ 0, /* tp_alloc */ PyType_GenericNew, /* tp_new */ 0, /* tp_free */ -- cgit v1.2.1 From 73bb19ea7143c943ea88e281feb3a1f7a5c5019d Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Thu, 16 Apr 2015 17:21:54 +0200 Subject: Fix typo in assert statement --- Modules/_io/fileio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 3c52c802e3..145d93adeb 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -252,7 +252,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, struct _Py_stat_struct fdfstat; int async_err = 0; - assert(PyFileIO_Check(oself)); + assert(PyFileIO_Check(self)); if (self->fd >= 0) { if (self->closefd) { /* Have to close the existing file first. */ -- cgit v1.2.1 From 51e54fb71e267ac7935b58f8d15cc20b319e8f3f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 19 Apr 2015 20:38:19 +0300 Subject: Use PyArg_ParseTuple (new API) instead of PyArg_Parse (old API) for parsing tuples. --- Modules/_io/textio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index b5990f3060..f61b2818f3 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -538,7 +538,7 @@ _io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self) _PyIO_str_getstate, NULL); if (state == NULL) return NULL; - if (!PyArg_Parse(state, "(OK)", &buffer, &flag)) { + if (!PyArg_ParseTuple(state, "OK", &buffer, &flag)) { Py_DECREF(state); return NULL; } @@ -569,7 +569,7 @@ _io_IncrementalNewlineDecoder_setstate(nldecoder_object *self, PyObject *buffer; unsigned PY_LONG_LONG flag; - if (!PyArg_Parse(state, "(OK)", &buffer, &flag)) + if (!PyArg_ParseTuple(state, "OK", &buffer, &flag)) return NULL; self->pendingcr = (int) (flag & 1); @@ -1449,7 +1449,7 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) /* Given this, we know there was a valid snapshot point * len(dec_buffer) bytes ago with decoder state (b'', dec_flags). */ - if (PyArg_Parse(state, "(OO)", &dec_buffer, &dec_flags) < 0) { + if (PyArg_ParseTuple(state, "OO", &dec_buffer, &dec_flags) < 0) { Py_DECREF(state); return -1; } @@ -2305,7 +2305,7 @@ _io_TextIOWrapper_tell_impl(textio *self) goto fail; /* Skip backward to the snapshot point (see _read_chunk). */ - if (!PyArg_Parse(self->snapshot, "(iO)", &cookie.dec_flags, &next_input)) + if (!PyArg_ParseTuple(self->snapshot, "iO", &cookie.dec_flags, &next_input)) goto fail; assert (PyBytes_Check(next_input)); @@ -2331,7 +2331,7 @@ _io_TextIOWrapper_tell_impl(textio *self) _PyIO_str_getstate, NULL); \ if (_state == NULL) \ goto fail; \ - if (!PyArg_Parse(_state, "(y#i)", &dec_buffer, &dec_buffer_len, &dec_flags)) { \ + if (!PyArg_ParseTuple(_state, "y#i", &dec_buffer, &dec_buffer_len, &dec_flags)) { \ Py_DECREF(_state); \ goto fail; \ } \ -- cgit v1.2.1 From fb2b5bbc6a941ec46c28262cce7d55f4bea2658e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 24 Apr 2015 00:40:51 +0300 Subject: Issue #24007: Argument Clinic now writes the format of PyArg_Parse*() at the same line as function name. --- Modules/_io/clinic/_iomodule.c.h | 5 ++-- Modules/_io/clinic/bufferedio.c.h | 50 ++++++++++++--------------------------- Modules/_io/clinic/bytesio.c.h | 12 ++++------ Modules/_io/clinic/fileio.c.h | 19 +++++---------- Modules/_io/clinic/iobase.c.h | 11 ++++----- Modules/_io/clinic/stringio.c.h | 8 +++---- Modules/_io/clinic/textio.c.h | 24 +++++++------------ 7 files changed, 42 insertions(+), 87 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/clinic/_iomodule.c.h b/Modules/_io/clinic/_iomodule.c.h index df877a5b28..a3abb93cc7 100644 --- a/Modules/_io/clinic/_iomodule.c.h +++ b/Modules/_io/clinic/_iomodule.c.h @@ -148,8 +148,7 @@ _io_open(PyModuleDef *module, PyObject *args, PyObject *kwargs) int closefd = 1; PyObject *opener = Py_None; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|sizzziO:open", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|sizzziO:open", _keywords, &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener)) goto exit; return_value = _io_open_impl(module, file, mode, buffering, encoding, errors, newline, closefd, opener); @@ -157,4 +156,4 @@ _io_open(PyModuleDef *module, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=c51a5a443c11f02b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=97cdc09bf68a8064 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index b79b8d56c4..437e275730 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -19,9 +19,7 @@ _io__BufferedIOBase_readinto(PyObject *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, - "w*:readinto", - &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) goto exit; return_value = _io__BufferedIOBase_readinto_impl(self, &buffer); @@ -50,9 +48,7 @@ _io__BufferedIOBase_readinto1(PyObject *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, - "w*:readinto1", - &buffer)) + if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) goto exit; return_value = _io__BufferedIOBase_readinto1_impl(self, &buffer); @@ -102,8 +98,7 @@ _io__Buffered_peek(buffered *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t size = 0; - if (!PyArg_ParseTuple(args, - "|n:peek", + if (!PyArg_ParseTuple(args, "|n:peek", &size)) goto exit; return_value = _io__Buffered_peek_impl(self, size); @@ -129,8 +124,7 @@ _io__Buffered_read(buffered *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t n = -1; - if (!PyArg_ParseTuple(args, - "|O&:read", + if (!PyArg_ParseTuple(args, "|O&:read", _PyIO_ConvertSsize_t, &n)) goto exit; return_value = _io__Buffered_read_impl(self, n); @@ -156,9 +150,7 @@ _io__Buffered_read1(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_ssize_t n; - if (!PyArg_Parse(arg, - "n:read1", - &n)) + if (!PyArg_Parse(arg, "n:read1", &n)) goto exit; return_value = _io__Buffered_read1_impl(self, n); @@ -183,9 +175,7 @@ _io__Buffered_readinto(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, - "w*:readinto", - &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) goto exit; return_value = _io__Buffered_readinto_impl(self, &buffer); @@ -214,9 +204,7 @@ _io__Buffered_readinto1(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, - "w*:readinto1", - &buffer)) + if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) goto exit; return_value = _io__Buffered_readinto1_impl(self, &buffer); @@ -245,8 +233,7 @@ _io__Buffered_readline(buffered *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t size = -1; - if (!PyArg_ParseTuple(args, - "|O&:readline", + if (!PyArg_ParseTuple(args, "|O&:readline", _PyIO_ConvertSsize_t, &size)) goto exit; return_value = _io__Buffered_readline_impl(self, size); @@ -273,8 +260,7 @@ _io__Buffered_seek(buffered *self, PyObject *args) PyObject *targetobj; int whence = 0; - if (!PyArg_ParseTuple(args, - "O|i:seek", + if (!PyArg_ParseTuple(args, "O|i:seek", &targetobj, &whence)) goto exit; return_value = _io__Buffered_seek_impl(self, targetobj, whence); @@ -328,8 +314,7 @@ _io_BufferedReader___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|n:BufferedReader", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedReader", _keywords, &raw, &buffer_size)) goto exit; return_value = _io_BufferedReader___init___impl((buffered *)self, raw, buffer_size); @@ -360,8 +345,7 @@ _io_BufferedWriter___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|n:BufferedWriter", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedWriter", _keywords, &raw, &buffer_size)) goto exit; return_value = _io_BufferedWriter___init___impl((buffered *)self, raw, buffer_size); @@ -387,9 +371,7 @@ _io_BufferedWriter_write(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, - "y*:write", - &buffer)) + if (!PyArg_Parse(arg, "y*:write", &buffer)) goto exit; return_value = _io_BufferedWriter_write_impl(self, &buffer); @@ -430,8 +412,7 @@ _io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs) if ((Py_TYPE(self) == &PyBufferedRWPair_Type) && !_PyArg_NoKeywords("BufferedRWPair", kwargs)) goto exit; - if (!PyArg_ParseTuple(args, - "OO|n:BufferedRWPair", + if (!PyArg_ParseTuple(args, "OO|n:BufferedRWPair", &reader, &writer, &buffer_size)) goto exit; return_value = _io_BufferedRWPair___init___impl((rwpair *)self, reader, writer, buffer_size); @@ -462,8 +443,7 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|n:BufferedRandom", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedRandom", _keywords, &raw, &buffer_size)) goto exit; return_value = _io_BufferedRandom___init___impl((buffered *)self, raw, buffer_size); @@ -471,4 +451,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=78808e39f36e3fa9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2bbb5e239b4ffe6f input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 695c46a7b3..1ab1d65a65 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -276,9 +276,7 @@ _io_BytesIO_readinto(bytesio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, - "w*:readinto", - &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) goto exit; return_value = _io_BytesIO_readinto_impl(self, &buffer); @@ -346,8 +344,7 @@ _io_BytesIO_seek(bytesio *self, PyObject *args) Py_ssize_t pos; int whence = 0; - if (!PyArg_ParseTuple(args, - "n|i:seek", + if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) goto exit; return_value = _io_BytesIO_seek_impl(self, pos, whence); @@ -414,8 +411,7 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) static char *_keywords[] = {"initial_bytes", NULL}; PyObject *initvalue = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|O:BytesIO", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:BytesIO", _keywords, &initvalue)) goto exit; return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue); @@ -423,4 +419,4 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=e22697ada514f4eb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=500ccc149587fac4 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index bb68cc9926..4a1205e933 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -55,8 +55,7 @@ _io_FileIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) int closefd = 1; PyObject *opener = Py_None; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|siO:FileIO", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|siO:FileIO", _keywords, &nameobj, &mode, &closefd, &opener)) goto exit; return_value = _io_FileIO___init___impl((fileio *)self, nameobj, mode, closefd, opener); @@ -155,9 +154,7 @@ _io_FileIO_readinto(fileio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, - "w*:readinto", - &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) goto exit; return_value = _io_FileIO_readinto_impl(self, &buffer); @@ -212,8 +209,7 @@ _io_FileIO_read(fileio *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t size = -1; - if (!PyArg_ParseTuple(args, - "|O&:read", + if (!PyArg_ParseTuple(args, "|O&:read", _PyIO_ConvertSsize_t, &size)) goto exit; return_value = _io_FileIO_read_impl(self, size); @@ -244,9 +240,7 @@ _io_FileIO_write(fileio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer b = {NULL, NULL}; - if (!PyArg_Parse(arg, - "y*:write", - &b)) + if (!PyArg_Parse(arg, "y*:write", &b)) goto exit; return_value = _io_FileIO_write_impl(self, &b); @@ -285,8 +279,7 @@ _io_FileIO_seek(fileio *self, PyObject *args) PyObject *pos; int whence = 0; - if (!PyArg_ParseTuple(args, - "O|i:seek", + if (!PyArg_ParseTuple(args, "O|i:seek", &pos, &whence)) goto exit; return_value = _io_FileIO_seek_impl(self, pos, whence); @@ -371,4 +364,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=c6708e1980f6e02d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b1a20b10c81add64 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index ce47faadc4..3cea079d45 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -185,8 +185,7 @@ _io__IOBase_readline(PyObject *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t limit = -1; - if (!PyArg_ParseTuple(args, - "|O&:readline", + if (!PyArg_ParseTuple(args, "|O&:readline", _PyIO_ConvertSsize_t, &limit)) goto exit; return_value = _io__IOBase_readline_impl(self, limit); @@ -217,8 +216,7 @@ _io__IOBase_readlines(PyObject *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t hint = -1; - if (!PyArg_ParseTuple(args, - "|O&:readlines", + if (!PyArg_ParseTuple(args, "|O&:readlines", _PyIO_ConvertSsize_t, &hint)) goto exit; return_value = _io__IOBase_readlines_impl(self, hint); @@ -252,8 +250,7 @@ _io__RawIOBase_read(PyObject *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t n = -1; - if (!PyArg_ParseTuple(args, - "|n:read", + if (!PyArg_ParseTuple(args, "|n:read", &n)) goto exit; return_value = _io__RawIOBase_read_impl(self, n); @@ -279,4 +276,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=84eef4b7541f54b7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fe034152b6884e65 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index b830c6d3fb..a8e32a3376 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -156,8 +156,7 @@ _io_StringIO_seek(stringio *self, PyObject *args) Py_ssize_t pos; int whence = 0; - if (!PyArg_ParseTuple(args, - "n|i:seek", + if (!PyArg_ParseTuple(args, "n|i:seek", &pos, &whence)) goto exit; return_value = _io_StringIO_seek_impl(self, pos, whence); @@ -222,8 +221,7 @@ _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *value = NULL; PyObject *newline_obj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|OO:StringIO", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:StringIO", _keywords, &value, &newline_obj)) goto exit; return_value = _io_StringIO___init___impl((stringio *)self, value, newline_obj); @@ -285,4 +283,4 @@ _io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored)) { return _io_StringIO_seekable_impl(self); } -/*[clinic end generated code: output=f3062096d357c652 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f061cf3a20cd14ed input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 62603bd739..dc7e8c7584 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -29,8 +29,7 @@ _io_IncrementalNewlineDecoder___init__(PyObject *self, PyObject *args, PyObject int translate; PyObject *errors = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "Oi|O:IncrementalNewlineDecoder", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|O:IncrementalNewlineDecoder", _keywords, &decoder, &translate, &errors)) goto exit; return_value = _io_IncrementalNewlineDecoder___init___impl((nldecoder_object *)self, decoder, translate, errors); @@ -59,8 +58,7 @@ _io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *args, PyO PyObject *input; int final = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|i:decode", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:decode", _keywords, &input, &final)) goto exit; return_value = _io_IncrementalNewlineDecoder_decode_impl(self, input, final); @@ -163,8 +161,7 @@ _io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs) int line_buffering = 0; int write_through = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O|zzzii:TextIOWrapper", _keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zzzii:TextIOWrapper", _keywords, &buffer, &encoding, &errors, &newline, &line_buffering, &write_through)) goto exit; return_value = _io_TextIOWrapper___init___impl((textio *)self, buffer, encoding, errors, newline, line_buffering, write_through); @@ -207,9 +204,7 @@ _io_TextIOWrapper_write(textio *self, PyObject *arg) PyObject *return_value = NULL; PyObject *text; - if (!PyArg_Parse(arg, - "U:write", - &text)) + if (!PyArg_Parse(arg, "U:write", &text)) goto exit; return_value = _io_TextIOWrapper_write_impl(self, text); @@ -234,8 +229,7 @@ _io_TextIOWrapper_read(textio *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t n = -1; - if (!PyArg_ParseTuple(args, - "|O&:read", + if (!PyArg_ParseTuple(args, "|O&:read", _PyIO_ConvertSsize_t, &n)) goto exit; return_value = _io_TextIOWrapper_read_impl(self, n); @@ -261,8 +255,7 @@ _io_TextIOWrapper_readline(textio *self, PyObject *args) PyObject *return_value = NULL; Py_ssize_t size = -1; - if (!PyArg_ParseTuple(args, - "|n:readline", + if (!PyArg_ParseTuple(args, "|n:readline", &size)) goto exit; return_value = _io_TextIOWrapper_readline_impl(self, size); @@ -289,8 +282,7 @@ _io_TextIOWrapper_seek(textio *self, PyObject *args) PyObject *cookieObj; int whence = 0; - if (!PyArg_ParseTuple(args, - "O|i:seek", + if (!PyArg_ParseTuple(args, "O|i:seek", &cookieObj, &whence)) goto exit; return_value = _io_TextIOWrapper_seek_impl(self, cookieObj, whence); @@ -461,4 +453,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=a610bd3b694886c3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=690608f85aab8ba5 input=a9049054013a1b77]*/ -- cgit v1.2.1 From cc6bf529161d5befef04ea2c083fb22c30a6858c Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Mon, 4 May 2015 06:59:46 -0700 Subject: Issue #24001: Argument Clinic converters now use accept={type} instead of types={'type'} to specify the types the converter accepts. --- Modules/_io/_iomodule.c | 8 ++++---- Modules/_io/bufferedio.c | 16 ++++++++-------- Modules/_io/bytesio.c | 4 ++-- Modules/_io/fileio.c | 4 ++-- Modules/_io/textio.c | 8 ++++---- 5 files changed, 20 insertions(+), 20 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index ea727f25c5..528bcd4ac1 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -100,9 +100,9 @@ _io.open file: object mode: str = "r" buffering: int = -1 - encoding: str(nullable=True) = NULL - errors: str(nullable=True) = NULL - newline: str(nullable=True) = NULL + encoding: str(accept={str, NoneType}) = NULL + errors: str(accept={str, NoneType}) = NULL + newline: str(accept={str, NoneType}) = NULL closefd: int(c_default="1") = True opener: object = None @@ -230,7 +230,7 @@ static PyObject * _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, int buffering, const char *encoding, const char *errors, const char *newline, int closefd, PyObject *opener) -/*[clinic end generated code: output=7615d0d746eb14d2 input=0541ce15691a82f2]*/ +/*[clinic end generated code: output=7615d0d746eb14d2 input=f4e1ca75223987bc]*/ { unsigned i; diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 916353bdf7..2c9064855a 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -101,26 +101,26 @@ _bufferediobase_readinto_generic(PyObject *self, Py_buffer *buffer, char readint /*[clinic input] _io._BufferedIOBase.readinto - buffer: Py_buffer(types={'rwbuffer'}) + buffer: Py_buffer(accept={rwbuffer}) / [clinic start generated code]*/ static PyObject * _io__BufferedIOBase_readinto_impl(PyObject *self, Py_buffer *buffer) -/*[clinic end generated code: output=8c8cda6684af8038 input=f8242a06c21763a0]*/ +/*[clinic end generated code: output=8c8cda6684af8038 input=00a6b9a38f29830a]*/ { return _bufferediobase_readinto_generic(self, buffer, 0); } /*[clinic input] _io._BufferedIOBase.readinto1 - buffer: Py_buffer(types={'rwbuffer'}) + buffer: Py_buffer(accept={rwbuffer}) / [clinic start generated code]*/ static PyObject * _io__BufferedIOBase_readinto1_impl(PyObject *self, Py_buffer *buffer) -/*[clinic end generated code: output=358623e4fd2b69d3 input=2003e706c730bd21]*/ +/*[clinic end generated code: output=358623e4fd2b69d3 input=ebad75b4aadfb9be]*/ { return _bufferediobase_readinto_generic(self, buffer, 1); } @@ -1065,26 +1065,26 @@ end: /*[clinic input] _io._Buffered.readinto - buffer: Py_buffer(types={'rwbuffer'}) + buffer: Py_buffer(accept={rwbuffer}) / [clinic start generated code]*/ static PyObject * _io__Buffered_readinto_impl(buffered *self, Py_buffer *buffer) -/*[clinic end generated code: output=bcb376580b1d8170 input=962b7496eac38b3a]*/ +/*[clinic end generated code: output=bcb376580b1d8170 input=ed6b98b7a20a3008]*/ { return _buffered_readinto_generic(self, buffer, 0); } /*[clinic input] _io._Buffered.readinto1 - buffer: Py_buffer(types={'rwbuffer'}) + buffer: Py_buffer(accept={rwbuffer}) / [clinic start generated code]*/ static PyObject * _io__Buffered_readinto1_impl(buffered *self, Py_buffer *buffer) -/*[clinic end generated code: output=6e5c6ac5868205d6 input=834614d93f0adeb5]*/ +/*[clinic end generated code: output=6e5c6ac5868205d6 input=4455c5d55fdf1687]*/ { return _buffered_readinto_generic(self, buffer, 1); } diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 42dfe2404a..d46430dca5 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -541,7 +541,7 @@ _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg) /*[clinic input] _io.BytesIO.readinto - buffer: Py_buffer(types={'rwbuffer'}) + buffer: Py_buffer(accept={rwbuffer}) / Read up to len(buffer) bytes into buffer. @@ -552,7 +552,7 @@ is set not to block as has no data to read. static PyObject * _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer) -/*[clinic end generated code: output=a5d407217dcf0639 input=d289da851c7c4159]*/ +/*[clinic end generated code: output=a5d407217dcf0639 input=71581f32635c3a31]*/ { Py_ssize_t len, n; diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 0894ca45c8..12e37bbbbe 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -603,7 +603,7 @@ _io_FileIO_seekable_impl(fileio *self) /*[clinic input] _io.FileIO.readinto - buffer: Py_buffer(types={'rwbuffer'}) + buffer: Py_buffer(accept={rwbuffer}) / Same as RawIOBase.readinto(). @@ -611,7 +611,7 @@ Same as RawIOBase.readinto(). static PyObject * _io_FileIO_readinto_impl(fileio *self, Py_buffer *buffer) -/*[clinic end generated code: output=b01a5a22c8415cb4 input=5edd8327498d468c]*/ +/*[clinic end generated code: output=b01a5a22c8415cb4 input=4721d7b68b154eaf]*/ { Py_ssize_t n; int err; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index f61b2818f3..c45f70dc21 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -789,9 +789,9 @@ static encodefuncentry encodefuncs[] = { /*[clinic input] _io.TextIOWrapper.__init__ buffer: object - encoding: str(nullable=True) = NULL - errors: str(nullable=True) = NULL - newline: str(nullable=True) = NULL + encoding: str(accept={str, NoneType}) = NULL + errors: str(accept={str, NoneType}) = NULL + newline: str(accept={str, NoneType}) = NULL line_buffering: int(c_default="0") = False write_through: int(c_default="0") = False @@ -830,7 +830,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, const char *encoding, const char *errors, const char *newline, int line_buffering, int write_through) -/*[clinic end generated code: output=56a83402ce2a8381 input=1f20decb8d54a4ec]*/ +/*[clinic end generated code: output=56a83402ce2a8381 input=3126cb3101a2c99b]*/ { PyObject *raw, *codec_info = NULL; _PyIO_State *state = NULL; -- cgit v1.2.1 From 5b9538b353d5e18ebf42f34d5f3c5a0feead75f5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 6 May 2015 09:53:07 +0300 Subject: Issue #24009: Got rid of using rare "y#" format unit in TextIOWrapper.tell(). Parsed value should be bytes, not general robuffer, this is required in other places. --- Modules/_io/textio.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index c45f70dc21..c962c0ba08 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -2262,7 +2262,6 @@ _io_TextIOWrapper_tell_impl(textio *self) Py_ssize_t skip_bytes, skip_back; PyObject *saved_state = NULL; char *input, *input_end; - char *dec_buffer; Py_ssize_t dec_buffer_len; int dec_flags; @@ -2327,14 +2326,24 @@ _io_TextIOWrapper_tell_impl(textio *self) goto fail; #define DECODER_GETSTATE() do { \ + PyObject *dec_buffer; \ PyObject *_state = PyObject_CallMethodObjArgs(self->decoder, \ _PyIO_str_getstate, NULL); \ if (_state == NULL) \ goto fail; \ - if (!PyArg_ParseTuple(_state, "y#i", &dec_buffer, &dec_buffer_len, &dec_flags)) { \ + if (!PyArg_ParseTuple(_state, "Oi", &dec_buffer, &dec_flags)) { \ Py_DECREF(_state); \ goto fail; \ } \ + if (!PyBytes_Check(dec_buffer)) { \ + PyErr_Format(PyExc_TypeError, \ + "decoder getstate() should have returned a bytes " \ + "object, not '%.200s'", \ + Py_TYPE(dec_buffer)->tp_name); \ + Py_DECREF(_state); \ + goto fail; \ + } \ + dec_buffer_len = PyBytes_GET_SIZE(dec_buffer); \ Py_DECREF(_state); \ } while (0) -- cgit v1.2.1 From 8689bcdb5a2f2d2453268c6fe14b6441bd5f26d0 Mon Sep 17 00:00:00 2001 From: Berker Peksag Date: Tue, 12 May 2015 17:01:05 +0300 Subject: Issue #23796: peak and read1 methods of BufferedReader now raise ValueError if they called on a closed object. Patch by John Hergenroeder. --- Modules/_io/bufferedio.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Modules/_io') diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 2c9064855a..23ba3df866 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -871,6 +871,8 @@ _io__Buffered_peek_impl(buffered *self, Py_ssize_t size) PyObject *res = NULL; CHECK_INITIALIZED(self) + CHECK_CLOSED(self, "peek of closed file") + if (!ENTER_BUFFERED(self)) return NULL; @@ -947,6 +949,9 @@ _io__Buffered_read1_impl(buffered *self, Py_ssize_t n) "read length must be positive"); return NULL; } + + CHECK_CLOSED(self, "read of closed file") + if (n == 0) return PyBytes_FromStringAndSize(NULL, 0); -- cgit v1.2.1 From 50a678b95a356e30300264ca25e37d1d1910b265 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 20 May 2015 21:50:59 +0200 Subject: Issue #9858: Add missing method stubs to _io.RawIOBase. Patch by Laura Rupprecht. --- Modules/_io/iobase.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'Modules/_io') diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 79d716a98a..025007e40d 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -952,9 +952,25 @@ _io__RawIOBase_readall_impl(PyObject *self) return result; } +static PyObject * +rawiobase_readinto(PyObject *self, PyObject *args) +{ + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; +} + +static PyObject * +rawiobase_write(PyObject *self, PyObject *args) +{ + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; +} + static PyMethodDef rawiobase_methods[] = { _IO__RAWIOBASE_READ_METHODDEF _IO__RAWIOBASE_READALL_METHODDEF + {"readinto", rawiobase_readinto, METH_VARARGS}, + {"write", rawiobase_write, METH_VARARGS}, {NULL, NULL} }; -- cgit v1.2.1 From ffb38076ab94f9f3451a0eb0dbe6e2330e3d19d7 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 23 May 2015 08:59:25 -0700 Subject: Fixes cast warning in bufferedio.c --- Modules/_io/bufferedio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 23ba3df866..29e000bde4 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -297,7 +297,7 @@ _enter_buffered_busy(buffered *self) * Note that non-daemon threads have already exited here, so this * shouldn't affect carefully written threaded I/O code. */ - st = PyThread_acquire_lock_timed(self->lock, 1e6, 0); + st = PyThread_acquire_lock_timed(self->lock, (PY_TIMEOUT_T)1e6, 0); } Py_END_ALLOW_THREADS if (relax_locking && st != PY_LOCK_ACQUIRED) { -- cgit v1.2.1 From e24755b4428db490e064d9c4ea570284e7812b5f Mon Sep 17 00:00:00 2001 From: Robert Collins Date: Sun, 26 Jul 2015 06:43:13 +1200 Subject: - Issue #2091: error correctly on open() with mode 'U' and '+' open() accepted a 'U' mode string containing '+', but 'U' can only be used with 'r'. Patch from Jeff Balogh and John O'Connor. --- Modules/_io/_iomodule.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 528bcd4ac1..1c2d3a0c6c 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -248,8 +248,8 @@ _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, _Py_IDENTIFIER(close); if (!PyUnicode_Check(file) && - !PyBytes_Check(file) && - !PyNumber_Check(file)) { + !PyBytes_Check(file) && + !PyNumber_Check(file)) { PyErr_Format(PyExc_TypeError, "invalid file: %R", file); return NULL; } @@ -307,9 +307,9 @@ _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, /* Parameters validation */ if (universal) { - if (writing || appending) { + if (creating || writing || appending || updating) { PyErr_SetString(PyExc_ValueError, - "can't use U and writing mode at once"); + "mode U cannot be combined with x', 'w', 'a', or '+'"); return NULL; } if (PyErr_WarnEx(PyExc_DeprecationWarning, @@ -437,10 +437,10 @@ _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, /* wraps into a TextIOWrapper */ wrapper = PyObject_CallFunction((PyObject *)&PyTextIOWrapper_Type, - "Osssi", - buffer, - encoding, errors, newline, - line_buffering); + "Osssi", + buffer, + encoding, errors, newline, + line_buffering); if (wrapper == NULL) goto error; result = wrapper; -- cgit v1.2.1 From 96d6494d26e7bf4b6c9458160065ba022b733dc1 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 4 Sep 2015 01:08:03 +0300 Subject: Issue #24989: Fixed buffer overread in BytesIO.readline() if a position is set beyond size. Based on patch by John Leitch. --- Modules/_io/bytesio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index d46430dca5..31cc1f79a1 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -57,14 +57,18 @@ scan_eol(bytesio *self, Py_ssize_t len) Py_ssize_t maxlen; assert(self->buf != NULL); + assert(self->pos >= 0); + + if (self->pos >= self->string_size) + return 0; /* Move to the end of the line, up to the end of the string, s. */ - start = PyBytes_AS_STRING(self->buf) + self->pos; maxlen = self->string_size - self->pos; if (len < 0 || len > maxlen) len = maxlen; if (len) { + start = PyBytes_AS_STRING(self->buf) + self->pos; n = memchr(start, '\n', len); if (n) /* Get the length from the current position to the end of -- cgit v1.2.1 From c24226158488463cd15b2d3805ad0371bc8ef0a7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 4 Sep 2015 07:48:19 +0300 Subject: Issue #24989: Fixed buffer overread in BytesIO.readline() if a position is set beyond size. Based on patch by John Leitch. --- Modules/_io/bytesio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index d46430dca5..31cc1f79a1 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -57,14 +57,18 @@ scan_eol(bytesio *self, Py_ssize_t len) Py_ssize_t maxlen; assert(self->buf != NULL); + assert(self->pos >= 0); + + if (self->pos >= self->string_size) + return 0; /* Move to the end of the line, up to the end of the string, s. */ - start = PyBytes_AS_STRING(self->buf) + self->pos; maxlen = self->string_size - self->pos; if (len < 0 || len > maxlen) len = maxlen; if (len) { + start = PyBytes_AS_STRING(self->buf) + self->pos; n = memchr(start, '\n', len); if (n) /* Get the length from the current position to the end of -- cgit v1.2.1 From 51dfb6f71adbaf1e1d68ecacdfcf4a77be02e246 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 6 Sep 2015 21:25:30 +0300 Subject: Issue #15989: Fixed some scarcely probable integer overflows. It is very unlikely that they can occur in real code for now. --- Modules/_io/_iomodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1c2d3a0c6c..7428aed13b 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -238,7 +238,8 @@ _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, int text = 0, binary = 0, universal = 0; char rawmode[6], *m; - int line_buffering, isatty; + int line_buffering; + long isatty; PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL; -- cgit v1.2.1 From a608f27deca5a929a2324bfbb4373cd25e113592 Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Sat, 10 Oct 2015 10:17:57 +0000 Subject: Issue #22413: Remove comment made out of date by Argument Clinic --- Modules/_io/stringio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 21c2b19a40..73018a5390 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -696,10 +696,8 @@ _io_StringIO___init___impl(stringio *self, PyObject *value, char *newline = "\n"; Py_ssize_t value_len; - /* Parse the newline argument. This used to be done with the 'z' - specifier, however this allowed any object with the buffer interface to - be converted. Thus we have to parse it manually since we only want to - allow unicode objects or None. */ + /* Parse the newline argument. We only want to allow unicode objects or + None. */ if (newline_obj == Py_None) { newline = NULL; } -- cgit v1.2.1 From 2ec62b128f42b516353ae6d2063f87add256396f Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Sun, 6 Dec 2015 03:15:05 +0000 Subject: Issue #25717: Tolerate fstat() failures in the FileIO constructor This restores 3.4 behaviour, which was removed by revision 3b5279b5bfd1. The fstat() call fails with ENOENT for a Virtual Box shared folder filesystem if the file entry has been unlinked, e.g. for a temporary file. --- Modules/_io/fileio.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 12e37bbbbe..5f88d58c45 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -250,6 +250,7 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, int *atomic_flag_works = NULL; #endif struct _Py_stat_struct fdfstat; + int fstat_result; int async_err = 0; assert(PyFileIO_Check(self)); @@ -438,22 +439,36 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, } self->blksize = DEFAULT_BUFFER_SIZE; - if (_Py_fstat(self->fd, &fdfstat) < 0) - goto error; -#if defined(S_ISDIR) && defined(EISDIR) - /* On Unix, open will succeed for directories. - In Python, there should be no file objects referring to - directories, so we need a check. */ - if (S_ISDIR(fdfstat.st_mode)) { - errno = EISDIR; - PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); - goto error; + Py_BEGIN_ALLOW_THREADS + fstat_result = _Py_fstat_noraise(self->fd, &fdfstat); + Py_END_ALLOW_THREADS + if (fstat_result < 0) { +#ifdef MS_WINDOWS + if (GetLastError() == ERROR_INVALID_HANDLE) { + PyErr_SetFromWindowsErr(0); +#else + if (errno == EBADF) { + PyErr_SetFromErrno(PyExc_OSError); +#endif + goto error; + } } + else { +#if defined(S_ISDIR) && defined(EISDIR) + /* On Unix, open will succeed for directories. + In Python, there should be no file objects referring to + directories, so we need a check. */ + if (S_ISDIR(fdfstat.st_mode)) { + errno = EISDIR; + PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, nameobj); + goto error; + } #endif /* defined(S_ISDIR) */ #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE - if (fdfstat.st_blksize > 1) - self->blksize = fdfstat.st_blksize; + if (fdfstat.st_blksize > 1) + self->blksize = fdfstat.st_blksize; #endif /* HAVE_STRUCT_STAT_ST_BLKSIZE */ + } #if defined(MS_WINDOWS) || defined(__CYGWIN__) /* don't translate newlines (\r\n <=> \n) */ -- cgit v1.2.1 From 899719890ac4328ef16ad2cc5068e93b8424263a Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Sun, 6 Dec 2015 11:12:15 +0000 Subject: Issue #25717: Add comment explaining why errors are ignored --- Modules/_io/fileio.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 5f88d58c45..dbd604a116 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -443,6 +443,9 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, fstat_result = _Py_fstat_noraise(self->fd, &fdfstat); Py_END_ALLOW_THREADS if (fstat_result < 0) { + /* Tolerate fstat() errors other than EBADF. See Issue #25717, where + an anonymous file on a Virtual Box shared folder filesystem would + raise ENOENT. */ #ifdef MS_WINDOWS if (GetLastError() == ERROR_INVALID_HANDLE) { PyErr_SetFromWindowsErr(0); -- cgit v1.2.1 From e7fe1d033e834d6b4deb61eb6fe5984e11fb5fc0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 19 Dec 2015 20:05:25 +0200 Subject: Issue #25421: __sizeof__ methods of builtin types now use dynamic basic size. This allows sys.getsize() to work correctly with their subclasses with __slots__ defined. --- Modules/_io/bufferedio.c | 2 +- Modules/_io/bytesio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 29e000bde4..6bb2200e20 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -423,7 +423,7 @@ buffered_sizeof(buffered *self, void *unused) { Py_ssize_t res; - res = sizeof(buffered); + res = _PyObject_SIZE(Py_TYPE(self)); if (self->buffer) res += self->buffer_size; return PyLong_FromSsize_t(res); diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 31cc1f79a1..eef3b3de72 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -991,7 +991,7 @@ bytesio_sizeof(bytesio *self, void *unused) { Py_ssize_t res; - res = sizeof(bytesio); + res = _PyObject_SIZE(Py_TYPE(self)); if (self->buf && !SHARED_BUF(self)) res += _PySys_GetSizeOf(self->buf); return PyLong_FromSsize_t(res); -- cgit v1.2.1 From 585a1eed45faea53f836b1db2ac211d7f14b44c8 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 24 Dec 2015 10:35:59 +0200 Subject: Issue #20440: Massive replacing unsafe attribute setting code with special macro Py_SETREF. --- Modules/_io/bytesio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index eef3b3de72..99e71bcc7f 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -969,8 +969,7 @@ _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue) if (initvalue && initvalue != Py_None) { if (PyBytes_CheckExact(initvalue)) { Py_INCREF(initvalue); - Py_XDECREF(self->buf); - self->buf = initvalue; + Py_SETREF(self->buf, initvalue); self->string_size = PyBytes_GET_SIZE(initvalue); } else { -- cgit v1.2.1 From d1ba93f9a6a441ac31c5fd1890ce730b9e6d330d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 25 Dec 2015 19:53:18 +0200 Subject: Issue #25923: Added the const qualifier to static constant arrays. --- Modules/_io/textio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index b232b0242e..d018623470 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -772,7 +772,7 @@ typedef struct { encodefunc_t encodefunc; } encodefuncentry; -static encodefuncentry encodefuncs[] = { +static const encodefuncentry encodefuncs[] = { {"ascii", (encodefunc_t) ascii_encode}, {"iso8859-1", (encodefunc_t) latin1_encode}, {"utf-8", (encodefunc_t) utf8_encode}, @@ -1022,7 +1022,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, goto error; } else if (PyUnicode_Check(res)) { - encodefuncentry *e = encodefuncs; + const encodefuncentry *e = encodefuncs; while (e->name != NULL) { if (!PyUnicode_CompareWithASCIIString(res, e->name)) { self->encodefunc = e->encodefunc; -- cgit v1.2.1 From 5c633fc25fc6f9beee3ccb9ebc06633d1c9a1bc3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 25 Dec 2015 20:01:53 +0200 Subject: Issue #25923: Added more const qualifiers to signatures of static and private functions. --- Modules/_io/_iomodule.h | 2 +- Modules/_io/bufferedio.c | 2 +- Modules/_io/fileio.c | 4 ++-- Modules/_io/textio.c | 20 ++++++++++---------- 4 files changed, 14 insertions(+), 14 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 0c6eae26b7..3c48ff3aac 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -60,7 +60,7 @@ extern PyObject *_PyIncrementalNewlineDecoder_decode( * Otherwise, the line ending is specified by readnl, a str object */ extern Py_ssize_t _PyIO_find_line_ending( int translated, int universal, PyObject *readnl, - int kind, char *start, char *end, Py_ssize_t *consumed); + int kind, const char *start, const char *end, Py_ssize_t *consumed); /* Return 1 if an EnvironmentError with errno == EINTR is set (and then clears the error indicator), 0 otherwise. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 6bb2200e20..16f8cdf912 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -659,7 +659,7 @@ _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len); /* Sets the current error to BlockingIOError */ static void -_set_BlockingIOError(char *msg, Py_ssize_t written) +_set_BlockingIOError(const char *msg, Py_ssize_t written) { PyObject *err; PyErr_Clear(); diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index dbd604a116..8bf3922676 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -540,7 +540,7 @@ err_closed(void) } static PyObject * -err_mode(char *action) +err_mode(const char *action) { _PyIO_State *state = IO_STATE(); if (state != NULL) @@ -1043,7 +1043,7 @@ _io_FileIO_truncate_impl(fileio *self, PyObject *posobj) } #endif /* HAVE_FTRUNCATE */ -static char * +static const char * mode_string(fileio *self) { if (self->created) { diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index d018623470..140da10ab4 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1648,8 +1648,8 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) /* NOTE: `end` must point to the real end of the Py_UCS4 storage, that is to the NUL character. Otherwise the function will produce incorrect results. */ -static char * -find_control_char(int kind, char *s, char *end, Py_UCS4 ch) +static const char * +find_control_char(int kind, const char *s, const char *end, Py_UCS4 ch) { if (kind == PyUnicode_1BYTE_KIND) { assert(ch < 256); @@ -1669,13 +1669,13 @@ find_control_char(int kind, char *s, char *end, Py_UCS4 ch) Py_ssize_t _PyIO_find_line_ending( int translated, int universal, PyObject *readnl, - int kind, char *start, char *end, Py_ssize_t *consumed) + int kind, const char *start, const char *end, Py_ssize_t *consumed) { Py_ssize_t len = ((char*)end - (char*)start)/kind; if (translated) { /* Newlines are already translated, only search for \n */ - char *pos = find_control_char(kind, start, end, '\n'); + const char *pos = find_control_char(kind, start, end, '\n'); if (pos != NULL) return (pos - start)/kind + 1; else { @@ -1687,7 +1687,7 @@ _PyIO_find_line_ending( /* Universal newline search. Find any of \r, \r\n, \n * The decoder ensures that \r\n are not split in two pieces */ - char *s = start; + const char *s = start; for (;;) { Py_UCS4 ch; /* Fast path for non-control chars. The loop always ends @@ -1717,21 +1717,21 @@ _PyIO_find_line_ending( /* Assume that readnl is an ASCII character. */ assert(PyUnicode_KIND(readnl) == PyUnicode_1BYTE_KIND); if (readnl_len == 1) { - char *pos = find_control_char(kind, start, end, nl[0]); + const char *pos = find_control_char(kind, start, end, nl[0]); if (pos != NULL) return (pos - start)/kind + 1; *consumed = len; return -1; } else { - char *s = start; - char *e = end - (readnl_len - 1)*kind; - char *pos; + const char *s = start; + const char *e = end - (readnl_len - 1)*kind; + const char *pos; if (e < s) e = s; while (s < e) { Py_ssize_t i; - char *pos = find_control_char(kind, s, end, nl[0]); + const char *pos = find_control_char(kind, s, end, nl[0]); if (pos == NULL || pos >= e) break; for (i = 1; i < readnl_len; i++) { -- cgit v1.2.1 From 49b4fe42c04e1eec009aac77da7f44d985b1abbb Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 27 Dec 2015 12:36:18 +0200 Subject: Issue #20440: Applied yet one patch for using Py_SETREF. The patch is automatically generated, it replaces the code that uses Py_CLEAR. --- Modules/_io/bufferedio.c | 12 ++++-------- Modules/_io/textio.c | 12 ++++-------- 2 files changed, 8 insertions(+), 16 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 6bb2200e20..ae4af9d5ff 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1196,8 +1196,7 @@ found: Py_CLEAR(res); goto end; } - Py_CLEAR(res); - res = _PyBytes_Join(_PyIO_empty_bytes, chunks); + Py_SETREF(res, _PyBytes_Join(_PyIO_empty_bytes, chunks)); end: LEAVE_BUFFERED(self) @@ -1452,9 +1451,8 @@ _io_BufferedReader___init___impl(buffered *self, PyObject *raw, if (_PyIOBase_check_readable(raw, Py_True) == NULL) return -1; - Py_CLEAR(self->raw); Py_INCREF(raw); - self->raw = raw; + Py_SETREF(self->raw, raw); self->buffer_size = buffer_size; self->readable = 1; self->writable = 0; @@ -1805,9 +1803,8 @@ _io_BufferedWriter___init___impl(buffered *self, PyObject *raw, if (_PyIOBase_check_writable(raw, Py_True) == NULL) return -1; - Py_CLEAR(self->raw); Py_INCREF(raw); - self->raw = raw; + Py_SETREF(self->raw, raw); self->readable = 0; self->writable = 1; @@ -2309,9 +2306,8 @@ _io_BufferedRandom___init___impl(buffered *self, PyObject *raw, if (_PyIOBase_check_writable(raw, Py_True) == NULL) return -1; - Py_CLEAR(self->raw); Py_INCREF(raw); - self->raw = raw; + Py_SETREF(self->raw, raw); self->buffer_size = buffer_size; self->readable = 1; self->writable = 1; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index b232b0242e..b1d2b6febe 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -995,8 +995,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, "Oi", self->decoder, (int)self->readtranslate); if (incrementalDecoder == NULL) goto error; - Py_CLEAR(self->decoder); - self->decoder = incrementalDecoder; + Py_SETREF(self->decoder, incrementalDecoder); } } @@ -1374,8 +1373,7 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) static void textiowrapper_set_decoded_chars(textio *self, PyObject *chars) { - Py_CLEAR(self->decoded_chars); - self->decoded_chars = chars; + Py_SETREF(self->decoded_chars, chars); self->decoded_chars_used = 0; } @@ -1523,8 +1521,7 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint) dec_buffer = NULL; /* Reference lost to PyBytes_Concat */ goto fail; } - Py_CLEAR(self->snapshot); - self->snapshot = Py_BuildValue("NN", dec_flags, next_input); + Py_SETREF(self->snapshot, Py_BuildValue("NN", dec_flags, next_input)); } Py_DECREF(input_chunk); @@ -1630,8 +1627,7 @@ _io_TextIOWrapper_read_impl(textio *self, Py_ssize_t n) if (chunks != NULL) { if (result != NULL && PyList_Append(chunks, result) < 0) goto fail; - Py_CLEAR(result); - result = PyUnicode_Join(_PyIO_empty_str, chunks); + Py_SETREF(result, PyUnicode_Join(_PyIO_empty_str, chunks)); if (result == NULL) goto fail; Py_CLEAR(chunks); -- cgit v1.2.1 From 20cb777d0019af42d191eaf5d425cc8671960a89 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 27 Dec 2015 15:51:32 +0200 Subject: Issue #20440: Cleaning up the code by using Py_SETREF and Py_CLEAR. Old code is correct, but with Py_SETREF and Py_CLEAR it can be cleaner. This patch doesn't fix bugs and hence there is no need to backport it. --- Modules/_io/bytesio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index 99e71bcc7f..6333e46438 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -87,7 +87,7 @@ scan_eol(bytesio *self, Py_ssize_t len) static int unshare_buffer(bytesio *self, size_t size) { - PyObject *new_buf, *old_buf; + PyObject *new_buf; assert(SHARED_BUF(self)); assert(self->exports == 0); assert(size >= (size_t)self->string_size); @@ -96,9 +96,7 @@ unshare_buffer(bytesio *self, size_t size) return -1; memcpy(PyBytes_AS_STRING(new_buf), PyBytes_AS_STRING(self->buf), self->string_size); - old_buf = self->buf; - self->buf = new_buf; - Py_DECREF(old_buf); + Py_SETREF(self->buf, new_buf); return 0; } -- cgit v1.2.1 From e6094ad533ed236d30c68e7225ac767d1ceac1f6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 19 Mar 2016 01:03:51 +0100 Subject: On ResourceWarning, log traceback where the object was allocated Issue #26567: * Add a new function PyErr_ResourceWarning() function to pass the destroyed object * Add a source attribute to warnings.WarningMessage * Add warnings._showwarnmsg() which uses tracemalloc to get the traceback where source object was allocated. --- Modules/_io/fileio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 8bf3922676..a02a9c1be3 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -92,8 +92,7 @@ fileio_dealloc_warn(fileio *self, PyObject *source) if (self->fd >= 0 && self->closefd) { PyObject *exc, *val, *tb; PyErr_Fetch(&exc, &val, &tb); - if (PyErr_WarnFormat(PyExc_ResourceWarning, 1, - "unclosed file %R", source)) { + if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) { /* Spurious errors can appear at shutdown */ if (PyErr_ExceptionMatches(PyExc_Warning)) PyErr_WriteUnraisable((PyObject *) self); -- cgit v1.2.1 From d7dada55a8f204345b6d5e1dc8c127ebf7e0efe9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sat, 19 Mar 2016 10:36:36 +0100 Subject: cleanup iobase.c casting iobase_finalize to destructor is not needed --- Modules/_io/iobase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index 025007e40d..e289a10d96 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -827,7 +827,7 @@ PyTypeObject PyIOBase_Type = { 0, /* tp_weaklist */ 0, /* tp_del */ 0, /* tp_version_tag */ - (destructor)iobase_finalize, /* tp_finalize */ + iobase_finalize, /* tp_finalize */ }; -- cgit v1.2.1 From 3f04a353d7bac512bee38f15e8a12269a868d356 Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Sat, 4 Jun 2016 14:38:43 -0700 Subject: issue27186: add open/io.open; patch by Jelle Zijlstra --- Modules/_io/_iomodule.c | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index d8aa1df432..85b1813c92 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -238,21 +238,33 @@ _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, int text = 0, binary = 0, universal = 0; char rawmode[6], *m; - int line_buffering; + int line_buffering, is_number; long isatty; - PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL; + PyObject *raw, *modeobj = NULL, *buffer, *wrapper, *result = NULL, *path_or_fd = NULL; _Py_IDENTIFIER(_blksize); _Py_IDENTIFIER(isatty); _Py_IDENTIFIER(mode); _Py_IDENTIFIER(close); - if (!PyUnicode_Check(file) && - !PyBytes_Check(file) && - !PyNumber_Check(file)) { + is_number = PyNumber_Check(file); + + if (is_number) { + path_or_fd = file; + Py_INCREF(path_or_fd); + } else { + path_or_fd = PyOS_FSPath(file); + if (path_or_fd == NULL) { + return NULL; + } + } + + if (!is_number && + !PyUnicode_Check(path_or_fd) && + !PyBytes_Check(path_or_fd)) { PyErr_Format(PyExc_TypeError, "invalid file: %R", file); - return NULL; + goto error; } /* Decode mode */ @@ -293,7 +305,7 @@ _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, if (strchr(mode+i+1, c)) { invalid_mode: PyErr_Format(PyExc_ValueError, "invalid mode: '%s'", mode); - return NULL; + goto error; } } @@ -311,51 +323,54 @@ _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, if (creating || writing || appending || updating) { PyErr_SetString(PyExc_ValueError, "mode U cannot be combined with x', 'w', 'a', or '+'"); - return NULL; + goto error; } if (PyErr_WarnEx(PyExc_DeprecationWarning, "'U' mode is deprecated", 1) < 0) - return NULL; + goto error; reading = 1; } if (text && binary) { PyErr_SetString(PyExc_ValueError, "can't have text and binary mode at once"); - return NULL; + goto error; } if (creating + reading + writing + appending > 1) { PyErr_SetString(PyExc_ValueError, "must have exactly one of create/read/write/append mode"); - return NULL; + goto error; } if (binary && encoding != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take an encoding argument"); - return NULL; + goto error; } if (binary && errors != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take an errors argument"); - return NULL; + goto error; } if (binary && newline != NULL) { PyErr_SetString(PyExc_ValueError, "binary mode doesn't take a newline argument"); - return NULL; + goto error; } /* Create the Raw file stream */ raw = PyObject_CallFunction((PyObject *)&PyFileIO_Type, - "OsiO", file, rawmode, closefd, opener); + "OsiO", path_or_fd, rawmode, closefd, opener); if (raw == NULL) - return NULL; + goto error; result = raw; + Py_DECREF(path_or_fd); + path_or_fd = NULL; + modeobj = PyUnicode_FromString(mode); if (modeobj == NULL) goto error; @@ -461,6 +476,7 @@ _io_open_impl(PyModuleDef *module, PyObject *file, const char *mode, Py_XDECREF(close_result); Py_DECREF(result); } + Py_XDECREF(path_or_fd); Py_XDECREF(modeobj); return NULL; } -- cgit v1.2.1 From a397e56d2aad76fe5cacd54a2ecbdb03702985c7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 9 Jun 2016 16:16:06 +0300 Subject: Issue #26305: Argument Clinic now uses braces in C code as required by PEP 7. --- Modules/_io/clinic/_iomodule.c.h | 5 +-- Modules/_io/clinic/bufferedio.c.h | 65 ++++++++++++++++++++++++++------------- Modules/_io/clinic/bytesio.c.h | 26 ++++++++++------ Modules/_io/clinic/fileio.c.h | 26 ++++++++++------ Modules/_io/clinic/iobase.c.h | 11 ++++--- Modules/_io/clinic/stringio.c.h | 17 ++++++---- Modules/_io/clinic/textio.c.h | 26 ++++++++++------ 7 files changed, 115 insertions(+), 61 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/clinic/_iomodule.c.h b/Modules/_io/clinic/_iomodule.c.h index a3abb93cc7..6dcfc0812d 100644 --- a/Modules/_io/clinic/_iomodule.c.h +++ b/Modules/_io/clinic/_iomodule.c.h @@ -149,11 +149,12 @@ _io_open(PyModuleDef *module, PyObject *args, PyObject *kwargs) PyObject *opener = Py_None; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|sizzziO:open", _keywords, - &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener)) + &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener)) { goto exit; + } return_value = _io_open_impl(module, file, mode, buffering, encoding, errors, newline, closefd, opener); exit: return return_value; } -/*[clinic end generated code: output=97cdc09bf68a8064 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=079f597e71e9f0c6 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index 437e275730..c4dfc1640e 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -19,14 +19,16 @@ _io__BufferedIOBase_readinto(PyObject *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { goto exit; + } return_value = _io__BufferedIOBase_readinto_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -48,14 +50,16 @@ _io__BufferedIOBase_readinto1(PyObject *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) { goto exit; + } return_value = _io__BufferedIOBase_readinto1_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -99,8 +103,9 @@ _io__Buffered_peek(buffered *self, PyObject *args) Py_ssize_t size = 0; if (!PyArg_ParseTuple(args, "|n:peek", - &size)) + &size)) { goto exit; + } return_value = _io__Buffered_peek_impl(self, size); exit: @@ -125,8 +130,9 @@ _io__Buffered_read(buffered *self, PyObject *args) Py_ssize_t n = -1; if (!PyArg_ParseTuple(args, "|O&:read", - _PyIO_ConvertSsize_t, &n)) + _PyIO_ConvertSsize_t, &n)) { goto exit; + } return_value = _io__Buffered_read_impl(self, n); exit: @@ -150,8 +156,9 @@ _io__Buffered_read1(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_ssize_t n; - if (!PyArg_Parse(arg, "n:read1", &n)) + if (!PyArg_Parse(arg, "n:read1", &n)) { goto exit; + } return_value = _io__Buffered_read1_impl(self, n); exit: @@ -175,14 +182,16 @@ _io__Buffered_readinto(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { goto exit; + } return_value = _io__Buffered_readinto_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -204,14 +213,16 @@ _io__Buffered_readinto1(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto1", &buffer)) { goto exit; + } return_value = _io__Buffered_readinto1_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -234,8 +245,9 @@ _io__Buffered_readline(buffered *self, PyObject *args) Py_ssize_t size = -1; if (!PyArg_ParseTuple(args, "|O&:readline", - _PyIO_ConvertSsize_t, &size)) + _PyIO_ConvertSsize_t, &size)) { goto exit; + } return_value = _io__Buffered_readline_impl(self, size); exit: @@ -261,8 +273,9 @@ _io__Buffered_seek(buffered *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "O|i:seek", - &targetobj, &whence)) + &targetobj, &whence)) { goto exit; + } return_value = _io__Buffered_seek_impl(self, targetobj, whence); exit: @@ -288,8 +301,9 @@ _io__Buffered_truncate(buffered *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &pos)) + &pos)) { goto exit; + } return_value = _io__Buffered_truncate_impl(self, pos); exit: @@ -315,8 +329,9 @@ _io_BufferedReader___init__(PyObject *self, PyObject *args, PyObject *kwargs) Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedReader", _keywords, - &raw, &buffer_size)) + &raw, &buffer_size)) { goto exit; + } return_value = _io_BufferedReader___init___impl((buffered *)self, raw, buffer_size); exit: @@ -346,8 +361,9 @@ _io_BufferedWriter___init__(PyObject *self, PyObject *args, PyObject *kwargs) Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedWriter", _keywords, - &raw, &buffer_size)) + &raw, &buffer_size)) { goto exit; + } return_value = _io_BufferedWriter___init___impl((buffered *)self, raw, buffer_size); exit: @@ -371,14 +387,16 @@ _io_BufferedWriter_write(buffered *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "y*:write", &buffer)) + if (!PyArg_Parse(arg, "y*:write", &buffer)) { goto exit; + } return_value = _io_BufferedWriter_write_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -410,11 +428,13 @@ _io_BufferedRWPair___init__(PyObject *self, PyObject *args, PyObject *kwargs) Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; if ((Py_TYPE(self) == &PyBufferedRWPair_Type) && - !_PyArg_NoKeywords("BufferedRWPair", kwargs)) + !_PyArg_NoKeywords("BufferedRWPair", kwargs)) { goto exit; + } if (!PyArg_ParseTuple(args, "OO|n:BufferedRWPair", - &reader, &writer, &buffer_size)) + &reader, &writer, &buffer_size)) { goto exit; + } return_value = _io_BufferedRWPair___init___impl((rwpair *)self, reader, writer, buffer_size); exit: @@ -444,11 +464,12 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedRandom", _keywords, - &raw, &buffer_size)) + &raw, &buffer_size)) { goto exit; + } return_value = _io_BufferedRandom___init___impl((buffered *)self, raw, buffer_size); exit: return return_value; } -/*[clinic end generated code: output=2bbb5e239b4ffe6f input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4f6196c756b880c8 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 5f2abb03a7..1f736fed80 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -171,8 +171,9 @@ _io_BytesIO_read(bytesio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "read", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_BytesIO_read_impl(self, arg); exit: @@ -215,8 +216,9 @@ _io_BytesIO_readline(bytesio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "readline", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_BytesIO_readline_impl(self, arg); exit: @@ -247,8 +249,9 @@ _io_BytesIO_readlines(bytesio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "readlines", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_BytesIO_readlines_impl(self, arg); exit: @@ -276,14 +279,16 @@ _io_BytesIO_readinto(bytesio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { goto exit; + } return_value = _io_BytesIO_readinto_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -311,8 +316,9 @@ _io_BytesIO_truncate(bytesio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_BytesIO_truncate_impl(self, arg); exit: @@ -345,8 +351,9 @@ _io_BytesIO_seek(bytesio *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "n|i:seek", - &pos, &whence)) + &pos, &whence)) { goto exit; + } return_value = _io_BytesIO_seek_impl(self, pos, whence); exit: @@ -412,11 +419,12 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *initvalue = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:BytesIO", _keywords, - &initvalue)) + &initvalue)) { goto exit; + } return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue); exit: return return_value; } -/*[clinic end generated code: output=60ce2c6272718431 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3fdb62f3e3b0544d input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index 10420082ac..038836a2c1 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -56,8 +56,9 @@ _io_FileIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *opener = Py_None; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|siO:FileIO", _keywords, - &nameobj, &mode, &closefd, &opener)) + &nameobj, &mode, &closefd, &opener)) { goto exit; + } return_value = _io_FileIO___init___impl((fileio *)self, nameobj, mode, closefd, opener); exit: @@ -154,14 +155,16 @@ _io_FileIO_readinto(fileio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - if (!PyArg_Parse(arg, "w*:readinto", &buffer)) + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { goto exit; + } return_value = _io_FileIO_readinto_impl(self, &buffer); exit: /* Cleanup for buffer */ - if (buffer.obj) + if (buffer.obj) { PyBuffer_Release(&buffer); + } return return_value; } @@ -210,8 +213,9 @@ _io_FileIO_read(fileio *self, PyObject *args) Py_ssize_t size = -1; if (!PyArg_ParseTuple(args, "|O&:read", - _PyIO_ConvertSsize_t, &size)) + _PyIO_ConvertSsize_t, &size)) { goto exit; + } return_value = _io_FileIO_read_impl(self, size); exit: @@ -240,14 +244,16 @@ _io_FileIO_write(fileio *self, PyObject *arg) PyObject *return_value = NULL; Py_buffer b = {NULL, NULL}; - if (!PyArg_Parse(arg, "y*:write", &b)) + if (!PyArg_Parse(arg, "y*:write", &b)) { goto exit; + } return_value = _io_FileIO_write_impl(self, &b); exit: /* Cleanup for b */ - if (b.obj) + if (b.obj) { PyBuffer_Release(&b); + } return return_value; } @@ -280,8 +286,9 @@ _io_FileIO_seek(fileio *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "O|i:seek", - &pos, &whence)) + &pos, &whence)) { goto exit; + } return_value = _io_FileIO_seek_impl(self, pos, whence); exit: @@ -333,8 +340,9 @@ _io_FileIO_truncate(fileio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &posobj)) + &posobj)) { goto exit; + } return_value = _io_FileIO_truncate_impl(self, posobj); exit: @@ -364,4 +372,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=dcbc39b466598492 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=bf4b4bd6b976346d input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/iobase.c.h b/Modules/_io/clinic/iobase.c.h index 9762f11222..edbf73a40b 100644 --- a/Modules/_io/clinic/iobase.c.h +++ b/Modules/_io/clinic/iobase.c.h @@ -186,8 +186,9 @@ _io__IOBase_readline(PyObject *self, PyObject *args) Py_ssize_t limit = -1; if (!PyArg_ParseTuple(args, "|O&:readline", - _PyIO_ConvertSsize_t, &limit)) + _PyIO_ConvertSsize_t, &limit)) { goto exit; + } return_value = _io__IOBase_readline_impl(self, limit); exit: @@ -217,8 +218,9 @@ _io__IOBase_readlines(PyObject *self, PyObject *args) Py_ssize_t hint = -1; if (!PyArg_ParseTuple(args, "|O&:readlines", - _PyIO_ConvertSsize_t, &hint)) + _PyIO_ConvertSsize_t, &hint)) { goto exit; + } return_value = _io__IOBase_readlines_impl(self, hint); exit: @@ -251,8 +253,9 @@ _io__RawIOBase_read(PyObject *self, PyObject *args) Py_ssize_t n = -1; if (!PyArg_ParseTuple(args, "|n:read", - &n)) + &n)) { goto exit; + } return_value = _io__RawIOBase_read_impl(self, n); exit: @@ -276,4 +279,4 @@ _io__RawIOBase_readall(PyObject *self, PyObject *Py_UNUSED(ignored)) { return _io__RawIOBase_readall_impl(self); } -/*[clinic end generated code: output=b874952f5cc248a4 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0f53fed928d8e02f input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index a8e32a3376..ce9f46e879 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -61,8 +61,9 @@ _io_StringIO_read(stringio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "read", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_StringIO_read_impl(self, arg); exit: @@ -91,8 +92,9 @@ _io_StringIO_readline(stringio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "readline", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_StringIO_readline_impl(self, arg); exit: @@ -123,8 +125,9 @@ _io_StringIO_truncate(stringio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &arg)) + &arg)) { goto exit; + } return_value = _io_StringIO_truncate_impl(self, arg); exit: @@ -157,8 +160,9 @@ _io_StringIO_seek(stringio *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "n|i:seek", - &pos, &whence)) + &pos, &whence)) { goto exit; + } return_value = _io_StringIO_seek_impl(self, pos, whence); exit: @@ -222,8 +226,9 @@ _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) PyObject *newline_obj = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:StringIO", _keywords, - &value, &newline_obj)) + &value, &newline_obj)) { goto exit; + } return_value = _io_StringIO___init___impl((stringio *)self, value, newline_obj); exit: @@ -283,4 +288,4 @@ _io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored)) { return _io_StringIO_seekable_impl(self); } -/*[clinic end generated code: output=f061cf3a20cd14ed input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0513219581cbe952 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index dc7e8c7584..f115326a00 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -30,8 +30,9 @@ _io_IncrementalNewlineDecoder___init__(PyObject *self, PyObject *args, PyObject PyObject *errors = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|O:IncrementalNewlineDecoder", _keywords, - &decoder, &translate, &errors)) + &decoder, &translate, &errors)) { goto exit; + } return_value = _io_IncrementalNewlineDecoder___init___impl((nldecoder_object *)self, decoder, translate, errors); exit: @@ -59,8 +60,9 @@ _io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *args, PyO int final = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:decode", _keywords, - &input, &final)) + &input, &final)) { goto exit; + } return_value = _io_IncrementalNewlineDecoder_decode_impl(self, input, final); exit: @@ -162,8 +164,9 @@ _io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs) int write_through = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zzzii:TextIOWrapper", _keywords, - &buffer, &encoding, &errors, &newline, &line_buffering, &write_through)) + &buffer, &encoding, &errors, &newline, &line_buffering, &write_through)) { goto exit; + } return_value = _io_TextIOWrapper___init___impl((textio *)self, buffer, encoding, errors, newline, line_buffering, write_through); exit: @@ -204,8 +207,9 @@ _io_TextIOWrapper_write(textio *self, PyObject *arg) PyObject *return_value = NULL; PyObject *text; - if (!PyArg_Parse(arg, "U:write", &text)) + if (!PyArg_Parse(arg, "U:write", &text)) { goto exit; + } return_value = _io_TextIOWrapper_write_impl(self, text); exit: @@ -230,8 +234,9 @@ _io_TextIOWrapper_read(textio *self, PyObject *args) Py_ssize_t n = -1; if (!PyArg_ParseTuple(args, "|O&:read", - _PyIO_ConvertSsize_t, &n)) + _PyIO_ConvertSsize_t, &n)) { goto exit; + } return_value = _io_TextIOWrapper_read_impl(self, n); exit: @@ -256,8 +261,9 @@ _io_TextIOWrapper_readline(textio *self, PyObject *args) Py_ssize_t size = -1; if (!PyArg_ParseTuple(args, "|n:readline", - &size)) + &size)) { goto exit; + } return_value = _io_TextIOWrapper_readline_impl(self, size); exit: @@ -283,8 +289,9 @@ _io_TextIOWrapper_seek(textio *self, PyObject *args) int whence = 0; if (!PyArg_ParseTuple(args, "O|i:seek", - &cookieObj, &whence)) + &cookieObj, &whence)) { goto exit; + } return_value = _io_TextIOWrapper_seek_impl(self, cookieObj, whence); exit: @@ -327,8 +334,9 @@ _io_TextIOWrapper_truncate(textio *self, PyObject *args) if (!PyArg_UnpackTuple(args, "truncate", 0, 1, - &pos)) + &pos)) { goto exit; + } return_value = _io_TextIOWrapper_truncate_impl(self, pos); exit: @@ -453,4 +461,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=690608f85aab8ba5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=31a39bbbe07ae4e7 input=a9049054013a1b77]*/ -- cgit v1.2.1 From 96d299b2b87dd2311bcc94cbab7b1cfa2c30ccba Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 14 Aug 2016 10:52:18 +0300 Subject: Issue #27574: Decreased an overhead of parsing keyword arguments in functions implemented with using Argument Clinic. --- Modules/_io/clinic/_iomodule.c.h | 7 ++++--- Modules/_io/clinic/bufferedio.c.h | 17 ++++++++++------- Modules/_io/clinic/bytesio.c.h | 7 ++++--- Modules/_io/clinic/fileio.c.h | 7 ++++--- Modules/_io/clinic/stringio.c.h | 7 ++++--- Modules/_io/clinic/textio.c.h | 17 ++++++++++------- 6 files changed, 36 insertions(+), 26 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/clinic/_iomodule.c.h b/Modules/_io/clinic/_iomodule.c.h index ee01cfb7b3..50891c59d1 100644 --- a/Modules/_io/clinic/_iomodule.c.h +++ b/Modules/_io/clinic/_iomodule.c.h @@ -138,7 +138,8 @@ static PyObject * _io_open(PyObject *module, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - static char *_keywords[] = {"file", "mode", "buffering", "encoding", "errors", "newline", "closefd", "opener", NULL}; + static const char * const _keywords[] = {"file", "mode", "buffering", "encoding", "errors", "newline", "closefd", "opener", NULL}; + static _PyArg_Parser _parser = {"O|sizzziO:open", _keywords, 0}; PyObject *file; const char *mode = "r"; int buffering = -1; @@ -148,7 +149,7 @@ _io_open(PyObject *module, PyObject *args, PyObject *kwargs) int closefd = 1; PyObject *opener = Py_None; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|sizzziO:open", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener)) { goto exit; } @@ -157,4 +158,4 @@ _io_open(PyObject *module, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=ae2facf262cf464e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=14769629391a3130 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bufferedio.c.h b/Modules/_io/clinic/bufferedio.c.h index c4dfc1640e..58144a4015 100644 --- a/Modules/_io/clinic/bufferedio.c.h +++ b/Modules/_io/clinic/bufferedio.c.h @@ -324,11 +324,12 @@ static int _io_BufferedReader___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"raw", "buffer_size", NULL}; + static const char * const _keywords[] = {"raw", "buffer_size", NULL}; + static _PyArg_Parser _parser = {"O|n:BufferedReader", _keywords, 0}; PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedReader", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &raw, &buffer_size)) { goto exit; } @@ -356,11 +357,12 @@ static int _io_BufferedWriter___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"raw", "buffer_size", NULL}; + static const char * const _keywords[] = {"raw", "buffer_size", NULL}; + static _PyArg_Parser _parser = {"O|n:BufferedWriter", _keywords, 0}; PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedWriter", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &raw, &buffer_size)) { goto exit; } @@ -459,11 +461,12 @@ static int _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"raw", "buffer_size", NULL}; + static const char * const _keywords[] = {"raw", "buffer_size", NULL}; + static _PyArg_Parser _parser = {"O|n:BufferedRandom", _keywords, 0}; PyObject *raw; Py_ssize_t buffer_size = DEFAULT_BUFFER_SIZE; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|n:BufferedRandom", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &raw, &buffer_size)) { goto exit; } @@ -472,4 +475,4 @@ _io_BufferedRandom___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=4f6196c756b880c8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a956f394ecde4cf9 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index 1f736fed80..c64ce5c77c 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -415,10 +415,11 @@ static int _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"initial_bytes", NULL}; + static const char * const _keywords[] = {"initial_bytes", NULL}; + static _PyArg_Parser _parser = {"|O:BytesIO", _keywords, 0}; PyObject *initvalue = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:BytesIO", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &initvalue)) { goto exit; } @@ -427,4 +428,4 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=3fdb62f3e3b0544d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6382e8eb578eea64 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/fileio.c.h b/Modules/_io/clinic/fileio.c.h index 038836a2c1..908fe0f8c8 100644 --- a/Modules/_io/clinic/fileio.c.h +++ b/Modules/_io/clinic/fileio.c.h @@ -49,13 +49,14 @@ static int _io_FileIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"file", "mode", "closefd", "opener", NULL}; + static const char * const _keywords[] = {"file", "mode", "closefd", "opener", NULL}; + static _PyArg_Parser _parser = {"O|siO:FileIO", _keywords, 0}; PyObject *nameobj; const char *mode = "r"; int closefd = 1; PyObject *opener = Py_None; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|siO:FileIO", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &nameobj, &mode, &closefd, &opener)) { goto exit; } @@ -372,4 +373,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=bf4b4bd6b976346d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=51924bc0ee11d58e input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/stringio.c.h b/Modules/_io/clinic/stringio.c.h index ce9f46e879..d2c05d7cb1 100644 --- a/Modules/_io/clinic/stringio.c.h +++ b/Modules/_io/clinic/stringio.c.h @@ -221,11 +221,12 @@ static int _io_StringIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"initial_value", "newline", NULL}; + static const char * const _keywords[] = {"initial_value", "newline", NULL}; + static _PyArg_Parser _parser = {"|OO:StringIO", _keywords, 0}; PyObject *value = NULL; PyObject *newline_obj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:StringIO", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &value, &newline_obj)) { goto exit; } @@ -288,4 +289,4 @@ _io_StringIO_seekable(stringio *self, PyObject *Py_UNUSED(ignored)) { return _io_StringIO_seekable_impl(self); } -/*[clinic end generated code: output=0513219581cbe952 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5dd5c2a213e75405 input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index f115326a00..6c40819c5c 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -24,12 +24,13 @@ static int _io_IncrementalNewlineDecoder___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"decoder", "translate", "errors", NULL}; + static const char * const _keywords[] = {"decoder", "translate", "errors", NULL}; + static _PyArg_Parser _parser = {"Oi|O:IncrementalNewlineDecoder", _keywords, 0}; PyObject *decoder; int translate; PyObject *errors = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|O:IncrementalNewlineDecoder", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &decoder, &translate, &errors)) { goto exit; } @@ -55,11 +56,12 @@ static PyObject * _io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - static char *_keywords[] = {"input", "final", NULL}; + static const char * const _keywords[] = {"input", "final", NULL}; + static _PyArg_Parser _parser = {"O|i:decode", _keywords, 0}; PyObject *input; int final = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:decode", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &input, &final)) { goto exit; } @@ -155,7 +157,8 @@ static int _io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - static char *_keywords[] = {"buffer", "encoding", "errors", "newline", "line_buffering", "write_through", NULL}; + static const char * const _keywords[] = {"buffer", "encoding", "errors", "newline", "line_buffering", "write_through", NULL}; + static _PyArg_Parser _parser = {"O|zzzii:TextIOWrapper", _keywords, 0}; PyObject *buffer; const char *encoding = NULL; const char *errors = NULL; @@ -163,7 +166,7 @@ _io_TextIOWrapper___init__(PyObject *self, PyObject *args, PyObject *kwargs) int line_buffering = 0; int write_through = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zzzii:TextIOWrapper", _keywords, + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, &buffer, &encoding, &errors, &newline, &line_buffering, &write_through)) { goto exit; } @@ -461,4 +464,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=31a39bbbe07ae4e7 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7ec624a9bf6393f5 input=a9049054013a1b77]*/ -- cgit v1.2.1 From 4846ba81c69ebc815b35a89ed54fef7b5ffb1417 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 30 Aug 2016 10:47:49 -0700 Subject: Issue #27895: Spelling fixes (Contributed by Ville Skytt?). --- Modules/_io/iobase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c index f07a0ca295..472ef3b97c 100644 --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -90,7 +90,7 @@ iobase_unsupported(const char *message) return NULL; } -/* Positionning */ +/* Positioning */ PyDoc_STRVAR(iobase_seek_doc, "Change stream position.\n" -- cgit v1.2.1 From 907ccded8b6fa68f6f572ae5de6760595df0d5a1 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Mon, 5 Sep 2016 17:44:18 -0700 Subject: require a long long data type (closes #27961) --- Modules/_io/_iomodule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 3c48ff3aac..007e0c4b32 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -104,7 +104,7 @@ typedef off_t Py_off_t; # define PY_OFF_T_MIN PY_SSIZE_T_MIN # define PY_OFF_T_COMPAT Py_ssize_t # define PY_PRIdOFF "zd" -#elif (HAVE_LONG_LONG && SIZEOF_OFF_T == SIZEOF_LONG_LONG) +#elif (SIZEOF_OFF_T == SIZEOF_LONG_LONG) # define PyLong_AsOff_t PyLong_AsLongLong # define PyLong_FromOff_t PyLong_FromLongLong # define PY_OFF_T_MAX PY_LLONG_MAX -- cgit v1.2.1 From 16bd0974887b5c50b726c4455107daad3b0d41cf Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Thu, 8 Sep 2016 09:15:54 -0700 Subject: more PY_LONG_LONG to long long --- Modules/_io/_iomodule.h | 14 +++++++------- Modules/_io/textio.c | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 007e0c4b32..8b5ec88948 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -85,12 +85,12 @@ extern int _PyIO_trap_eintr(void); #ifdef MS_WINDOWS /* Windows uses long long for offsets */ -typedef PY_LONG_LONG Py_off_t; +typedef long long Py_off_t; # define PyLong_AsOff_t PyLong_AsLongLong # define PyLong_FromOff_t PyLong_FromLongLong -# define PY_OFF_T_MAX PY_LLONG_MAX -# define PY_OFF_T_MIN PY_LLONG_MIN -# define PY_OFF_T_COMPAT PY_LONG_LONG /* type compatible with off_t */ +# define PY_OFF_T_MAX LLONG_MAX +# define PY_OFF_T_MIN LLONG_MIN +# define PY_OFF_T_COMPAT long long /* type compatible with off_t */ # define PY_PRIdOFF "lld" /* format to use for that type */ #else @@ -107,9 +107,9 @@ typedef off_t Py_off_t; #elif (SIZEOF_OFF_T == SIZEOF_LONG_LONG) # define PyLong_AsOff_t PyLong_AsLongLong # define PyLong_FromOff_t PyLong_FromLongLong -# define PY_OFF_T_MAX PY_LLONG_MAX -# define PY_OFF_T_MIN PY_LLONG_MIN -# define PY_OFF_T_COMPAT PY_LONG_LONG +# define PY_OFF_T_MAX LLONG_MAX +# define PY_OFF_T_MIN LLONG_MIN +# define PY_OFF_T_COMPAT long long # define PY_PRIdOFF "lld" #elif (SIZEOF_OFF_T == SIZEOF_LONG) # define PyLong_AsOff_t PyLong_AsLong diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 96c8e7b453..508e46e713 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -531,7 +531,7 @@ _io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self) /*[clinic end generated code: output=f0d2c9c136f4e0d0 input=f8ff101825e32e7f]*/ { PyObject *buffer; - unsigned PY_LONG_LONG flag; + unsigned long long flag; if (self->decoder != Py_None) { PyObject *state = PyObject_CallMethodObjArgs(self->decoder, @@ -567,7 +567,7 @@ _io_IncrementalNewlineDecoder_setstate(nldecoder_object *self, /*[clinic end generated code: output=c10c622508b576cb input=c53fb505a76dbbe2]*/ { PyObject *buffer; - unsigned PY_LONG_LONG flag; + unsigned long long flag; if (!PyArg_ParseTuple(state, "OK", &buffer, &flag)) return NULL; -- cgit v1.2.1 From 0b262da03401df836e0d2cd8b20412aeeaec6af8 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Thu, 8 Sep 2016 11:21:54 -0700 Subject: Issue #23524: Finish removing _PyVerify_fd from sources --- Modules/_io/fileio.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 12e5156fbb..54cfb7fa7d 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -117,18 +117,13 @@ internal_close(fileio *self) int fd = self->fd; self->fd = -1; /* fd is accessible and someone else may have closed it */ - if (_PyVerify_fd(fd)) { - Py_BEGIN_ALLOW_THREADS - _Py_BEGIN_SUPPRESS_IPH - err = close(fd); - if (err < 0) - save_errno = errno; - _Py_END_SUPPRESS_IPH - Py_END_ALLOW_THREADS - } else { + Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_SUPPRESS_IPH + err = close(fd); + if (err < 0) save_errno = errno; - err = -1; - } + _Py_END_SUPPRESS_IPH + Py_END_ALLOW_THREADS } if (err < 0) { errno = save_errno; @@ -700,8 +695,6 @@ _io_FileIO_readall_impl(fileio *self) if (self->fd < 0) return err_closed(); - if (!_PyVerify_fd(self->fd)) - return PyErr_SetFromErrno(PyExc_IOError); _Py_BEGIN_SUPPRESS_IPH #ifdef MS_WINDOWS @@ -914,18 +907,15 @@ portable_lseek(int fd, PyObject *posobj, int whence) return NULL; } - if (_PyVerify_fd(fd)) { - Py_BEGIN_ALLOW_THREADS - _Py_BEGIN_SUPPRESS_IPH + Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_SUPPRESS_IPH #ifdef MS_WINDOWS - res = _lseeki64(fd, pos, whence); + res = _lseeki64(fd, pos, whence); #else - res = lseek(fd, pos, whence); + res = lseek(fd, pos, whence); #endif - _Py_END_SUPPRESS_IPH - Py_END_ALLOW_THREADS - } else - res = -1; + _Py_END_SUPPRESS_IPH + Py_END_ALLOW_THREADS if (res < 0) return PyErr_SetFromErrno(PyExc_IOError); @@ -1116,10 +1106,7 @@ _io_FileIO_isatty_impl(fileio *self) return err_closed(); Py_BEGIN_ALLOW_THREADS _Py_BEGIN_SUPPRESS_IPH - if (_PyVerify_fd(self->fd)) - res = isatty(self->fd); - else - res = 0; + res = isatty(self->fd); _Py_END_SUPPRESS_IPH Py_END_ALLOW_THREADS return PyBool_FromLong(res); -- cgit v1.2.1 From 73392d64a0328bce848b448206b668f695640538 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Tue, 30 Aug 2016 21:22:36 -0700 Subject: Issue #1602: Windows console doesn't input or print Unicode (PEP 528) Closes #17602: Adds a readline implementation for the Windows console --- Modules/_io/_iomodule.c | 24 +- Modules/_io/_iomodule.h | 10 + Modules/_io/clinic/winconsoleio.c.h | 331 +++++++++++ Modules/_io/winconsoleio.c | 1096 +++++++++++++++++++++++++++++++++++ 4 files changed, 1458 insertions(+), 3 deletions(-) create mode 100644 Modules/_io/clinic/winconsoleio.c.h create mode 100644 Modules/_io/winconsoleio.c (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index ec700f64c8..60f8b549a8 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -20,6 +20,9 @@ #include #endif /* HAVE_SYS_STAT_H */ +#ifdef MS_WINDOWS +#include +#endif /* Various interned strings */ @@ -52,7 +55,6 @@ PyObject *_PyIO_empty_str; PyObject *_PyIO_empty_bytes; PyObject *_PyIO_zero; - PyDoc_STRVAR(module_doc, "The io module provides the Python interfaces to stream handling. The\n" "builtin open function is defined in this module.\n" @@ -362,8 +364,18 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, } /* Create the Raw file stream */ - raw = PyObject_CallFunction((PyObject *)&PyFileIO_Type, - "OsiO", path_or_fd, rawmode, closefd, opener); + { + PyObject *RawIO_class = (PyObject *)&PyFileIO_Type; +#ifdef MS_WINDOWS + if (!Py_LegacyWindowsStdioFlag && _PyIO_get_console_type(path_or_fd) != '\0') { + RawIO_class = (PyObject *)&PyWindowsConsoleIO_Type; + encoding = "utf-8"; + } +#endif + raw = PyObject_CallFunction(RawIO_class, + "OsiO", path_or_fd, rawmode, closefd, opener); + } + if (raw == NULL) goto error; result = raw; @@ -708,6 +720,12 @@ PyInit__io(void) PyStringIO_Type.tp_base = &PyTextIOBase_Type; ADD_TYPE(&PyStringIO_Type, "StringIO"); +#ifdef MS_WINDOWS + /* WindowsConsoleIO */ + PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; + ADD_TYPE(&PyWindowsConsoleIO_Type, "_WindowsConsoleIO"); +#endif + /* BufferedReader */ PyBufferedReader_Type.tp_base = &PyBufferedIOBase_Type; ADD_TYPE(&PyBufferedReader_Type, "BufferedReader"); diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 8b5ec88948..5d3da29ce1 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -19,6 +19,12 @@ extern PyTypeObject PyBufferedRandom_Type; extern PyTypeObject PyTextIOWrapper_Type; extern PyTypeObject PyIncrementalNewlineDecoder_Type; +#ifndef Py_LIMITED_API +#ifdef MS_WINDOWS +extern PyTypeObject PyWindowsConsoleIO_Type; +#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), &PyWindowsConsoleIO_Type)) +#endif /* MS_WINDOWS */ +#endif /* Py_LIMITED_API */ extern int _PyIO_ConvertSsize_t(PyObject *, void *); @@ -145,6 +151,10 @@ typedef struct { extern _PyIO_State *_PyIO_get_module_state(void); extern PyObject *_PyIO_get_locale_module(_PyIO_State *); +#ifdef MS_WINDOWS +extern char _PyIO_get_console_type(PyObject *); +#endif + extern PyObject *_PyIO_str_close; extern PyObject *_PyIO_str_closed; extern PyObject *_PyIO_str_decode; diff --git a/Modules/_io/clinic/winconsoleio.c.h b/Modules/_io/clinic/winconsoleio.c.h new file mode 100644 index 0000000000..e44fcbb7a1 --- /dev/null +++ b/Modules/_io/clinic/winconsoleio.c.h @@ -0,0 +1,331 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_close__doc__, +"close($self, /)\n" +"--\n" +"\n" +"Close the handle.\n" +"\n" +"A closed handle cannot be used for further I/O operations. close() may be\n" +"called more than once without error."); + +#define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF \ + {"close", (PyCFunction)_io__WindowsConsoleIO_close, METH_NOARGS, _io__WindowsConsoleIO_close__doc__}, + +static PyObject * +_io__WindowsConsoleIO_close_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_close(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_close_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO___init____doc__, +"_WindowsConsoleIO(file, mode=\'r\', closefd=True, opener=None)\n" +"--\n" +"\n" +"Open a console buffer by file descriptor.\n" +"\n" +"The mode can be \'rb\' (default), or \'wb\' for reading or writing bytes. All\n" +"other mode characters will be ignored. Mode \'b\' will be assumed if it is\n" +"omitted. The *opener* parameter is always ignored."); + +static int +_io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, + const char *mode, int closefd, + PyObject *opener); + +static int +_io__WindowsConsoleIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static const char * const _keywords[] = {"file", "mode", "closefd", "opener", NULL}; + static _PyArg_Parser _parser = {"O|siO:_WindowsConsoleIO", _keywords, 0}; + PyObject *nameobj; + const char *mode = "r"; + int closefd = 1; + PyObject *opener = Py_None; + + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &nameobj, &mode, &closefd, &opener)) { + goto exit; + } + return_value = _io__WindowsConsoleIO___init___impl((winconsoleio *)self, nameobj, mode, closefd, opener); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_fileno__doc__, +"fileno($self, /)\n" +"--\n" +"\n" +"Return the underlying file descriptor (an integer).\n" +"\n" +"fileno is only set when a file descriptor is used to open\n" +"one of the standard streams."); + +#define _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF \ + {"fileno", (PyCFunction)_io__WindowsConsoleIO_fileno, METH_NOARGS, _io__WindowsConsoleIO_fileno__doc__}, + +static PyObject * +_io__WindowsConsoleIO_fileno_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_fileno(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_fileno_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_readable__doc__, +"readable($self, /)\n" +"--\n" +"\n" +"True if console is an input buffer."); + +#define _IO__WINDOWSCONSOLEIO_READABLE_METHODDEF \ + {"readable", (PyCFunction)_io__WindowsConsoleIO_readable, METH_NOARGS, _io__WindowsConsoleIO_readable__doc__}, + +static PyObject * +_io__WindowsConsoleIO_readable_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_readable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_readable_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_writable__doc__, +"writable($self, /)\n" +"--\n" +"\n" +"True if console is an output buffer."); + +#define _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF \ + {"writable", (PyCFunction)_io__WindowsConsoleIO_writable, METH_NOARGS, _io__WindowsConsoleIO_writable__doc__}, + +static PyObject * +_io__WindowsConsoleIO_writable_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_writable(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_writable_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_readinto__doc__, +"readinto($self, buffer, /)\n" +"--\n" +"\n" +"Same as RawIOBase.readinto()."); + +#define _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF \ + {"readinto", (PyCFunction)_io__WindowsConsoleIO_readinto, METH_O, _io__WindowsConsoleIO_readinto__doc__}, + +static PyObject * +_io__WindowsConsoleIO_readinto_impl(winconsoleio *self, Py_buffer *buffer); + +static PyObject * +_io__WindowsConsoleIO_readinto(winconsoleio *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer buffer = {NULL, NULL}; + + if (!PyArg_Parse(arg, "w*:readinto", &buffer)) { + goto exit; + } + return_value = _io__WindowsConsoleIO_readinto_impl(self, &buffer); + +exit: + /* Cleanup for buffer */ + if (buffer.obj) { + PyBuffer_Release(&buffer); + } + + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_readall__doc__, +"readall($self, /)\n" +"--\n" +"\n" +"Read all data from the console, returned as bytes.\n" +"\n" +"Return an empty bytes object at EOF."); + +#define _IO__WINDOWSCONSOLEIO_READALL_METHODDEF \ + {"readall", (PyCFunction)_io__WindowsConsoleIO_readall, METH_NOARGS, _io__WindowsConsoleIO_readall__doc__}, + +static PyObject * +_io__WindowsConsoleIO_readall_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_readall(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_readall_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_read__doc__, +"read($self, size=-1, /)\n" +"--\n" +"\n" +"Read at most size bytes, returned as bytes.\n" +"\n" +"Only makes one system call when size is a positive integer,\n" +"so less data may be returned than requested.\n" +"Return an empty bytes object at EOF."); + +#define _IO__WINDOWSCONSOLEIO_READ_METHODDEF \ + {"read", (PyCFunction)_io__WindowsConsoleIO_read, METH_VARARGS, _io__WindowsConsoleIO_read__doc__}, + +static PyObject * +_io__WindowsConsoleIO_read_impl(winconsoleio *self, Py_ssize_t size); + +static PyObject * +_io__WindowsConsoleIO_read(winconsoleio *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t size = -1; + + if (!PyArg_ParseTuple(args, "|O&:read", + _PyIO_ConvertSsize_t, &size)) { + goto exit; + } + return_value = _io__WindowsConsoleIO_read_impl(self, size); + +exit: + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_write__doc__, +"write($self, b, /)\n" +"--\n" +"\n" +"Write buffer b to file, return number of bytes written.\n" +"\n" +"Only makes one system call, so not all of the data may be written.\n" +"The number of bytes actually written is returned."); + +#define _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF \ + {"write", (PyCFunction)_io__WindowsConsoleIO_write, METH_O, _io__WindowsConsoleIO_write__doc__}, + +static PyObject * +_io__WindowsConsoleIO_write_impl(winconsoleio *self, Py_buffer *b); + +static PyObject * +_io__WindowsConsoleIO_write(winconsoleio *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer b = {NULL, NULL}; + + if (!PyArg_Parse(arg, "y*:write", &b)) { + goto exit; + } + return_value = _io__WindowsConsoleIO_write_impl(self, &b); + +exit: + /* Cleanup for b */ + if (b.obj) { + PyBuffer_Release(&b); + } + + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(_io__WindowsConsoleIO_isatty__doc__, +"isatty($self, /)\n" +"--\n" +"\n" +"Always True."); + +#define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF \ + {"isatty", (PyCFunction)_io__WindowsConsoleIO_isatty, METH_NOARGS, _io__WindowsConsoleIO_isatty__doc__}, + +static PyObject * +_io__WindowsConsoleIO_isatty_impl(winconsoleio *self); + +static PyObject * +_io__WindowsConsoleIO_isatty(winconsoleio *self, PyObject *Py_UNUSED(ignored)) +{ + return _io__WindowsConsoleIO_isatty_impl(self); +} + +#endif /* defined(MS_WINDOWS) */ + +#ifndef _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF + #define _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF + #define _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_FILENO_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_READABLE_METHODDEF + #define _IO__WINDOWSCONSOLEIO_READABLE_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_READABLE_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF + #define _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF + #define _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_READINTO_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_READALL_METHODDEF + #define _IO__WINDOWSCONSOLEIO_READALL_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_READALL_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_READ_METHODDEF + #define _IO__WINDOWSCONSOLEIO_READ_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_READ_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF + #define _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_WRITE_METHODDEF) */ + +#ifndef _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF + #define _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF +#endif /* !defined(_IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF) */ +/*[clinic end generated code: output=9eba916f8537fff7 input=a9049054013a1b77]*/ diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c new file mode 100644 index 0000000000..2527ff13ca --- /dev/null +++ b/Modules/_io/winconsoleio.c @@ -0,0 +1,1096 @@ +/* + An implementation of Windows console I/O + + Classes defined here: _WindowsConsoleIO + + Written by Steve Dower +*/ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" + +#ifdef MS_WINDOWS + +#include "structmember.h" +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#include /* For offsetof */ + +#define WIN32_LEAN_AND_MEAN +#include + +#include "_iomodule.h" + +/* BUFSIZ determines how many characters can be typed at the console + before it starts blocking. */ +#if BUFSIZ < (16*1024) +#define SMALLCHUNK (2*1024) +#elif (BUFSIZ >= (2 << 25)) +#error "unreasonable BUFSIZ > 64MB defined" +#else +#define SMALLCHUNK BUFSIZ +#endif + +/* BUFMAX determines how many bytes can be read in one go. */ +#define BUFMAX (32*1024*1024) + +char _get_console_type(HANDLE handle) { + DWORD mode, peek_count; + + if (handle == INVALID_HANDLE_VALUE) + return '\0'; + + if (!GetConsoleMode(handle, &mode)) + return '\0'; + + /* Peek at the handle to see whether it is an input or output handle */ + if (GetNumberOfConsoleInputEvents(handle, &peek_count)) + return 'r'; + return 'w'; +} + +char _PyIO_get_console_type(PyObject *path_or_fd) { + int fd; + + fd = PyLong_AsLong(path_or_fd); + PyErr_Clear(); + if (fd >= 0) { + HANDLE handle; + _Py_BEGIN_SUPPRESS_IPH + handle = (HANDLE)_get_osfhandle(fd); + _Py_END_SUPPRESS_IPH + if (!handle) + return '\0'; + return _get_console_type(handle); + } + + PyObject *decoded = Py_None; + Py_INCREF(decoded); + + int d = PyUnicode_FSDecoder(path_or_fd, &decoded); + if (!d) { + PyErr_Clear(); + Py_CLEAR(decoded); + return '\0'; + } + + char m = '\0'; + if (!PyUnicode_Check(decoded)) { + return '\0'; + } else if (PyUnicode_CompareWithASCIIString(decoded, "CONIN$") == 0) { + m = 'r'; + } else if (PyUnicode_CompareWithASCIIString(decoded, "CONOUT$") == 0 || + PyUnicode_CompareWithASCIIString(decoded, "CON") == 0) { + m = 'w'; + } + + Py_CLEAR(decoded); + return m; +} + +/*[clinic input] +module _io +class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=e897fdc1fba4e131]*/ + +/*[python input] +class io_ssize_t_converter(CConverter): + type = 'Py_ssize_t' + converter = '_PyIO_ConvertSsize_t' +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=d0a811d3cbfd1b33]*/ + +typedef struct { + PyObject_HEAD + HANDLE handle; + int fd; + unsigned int created : 1; + unsigned int readable : 1; + unsigned int writable : 1; + unsigned int closehandle : 1; + char finalizing; + unsigned int blksize; + PyObject *weakreflist; + PyObject *dict; + char buf[4]; +} winconsoleio; + +PyTypeObject PyWindowsConsoleIO_Type; + +_Py_IDENTIFIER(name); + +int +_PyWindowsConsoleIO_closed(PyObject *self) +{ + return ((winconsoleio *)self)->handle == INVALID_HANDLE_VALUE; +} + + +/* Returns 0 on success, -1 with exception set on failure. */ +static int +internal_close(winconsoleio *self) +{ + if (self->handle != INVALID_HANDLE_VALUE) { + if (self->closehandle) { + if (self->fd >= 0) { + _Py_BEGIN_SUPPRESS_IPH + close(self->fd); + _Py_END_SUPPRESS_IPH + } + CloseHandle(self->handle); + } + self->handle = INVALID_HANDLE_VALUE; + self->fd = -1; + } + return 0; +} + +/*[clinic input] +_io._WindowsConsoleIO.close + +Close the handle. + +A closed handle cannot be used for further I/O operations. 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=185617e349ae4c7b]*/ +{ + PyObject *res; + PyObject *exc, *val, *tb; + int rc; + _Py_IDENTIFIER(close); + res = _PyObject_CallMethodId((PyObject*)&PyRawIOBase_Type, + &PyId_close, "O", self); + if (!self->closehandle) { + self->handle = INVALID_HANDLE_VALUE; + return res; + } + if (res == NULL) + PyErr_Fetch(&exc, &val, &tb); + rc = internal_close(self); + if (res == NULL) + _PyErr_ChainExceptions(exc, val, tb); + if (rc < 0) + Py_CLEAR(res); + return res; +} + +static PyObject * +winconsoleio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + winconsoleio *self; + + assert(type != NULL && type->tp_alloc != NULL); + + self = (winconsoleio *) type->tp_alloc(type, 0); + if (self != NULL) { + self->handle = INVALID_HANDLE_VALUE; + self->fd = -1; + self->created = 0; + self->readable = 0; + self->writable = 0; + self->closehandle = 0; + self->blksize = 0; + self->weakreflist = NULL; + } + + return (PyObject *) self; +} + +/*[clinic input] +_io._WindowsConsoleIO.__init__ + file as nameobj: object + mode: str = "r" + closefd: int(c_default="1") = True + opener: object = None + +Open a console buffer by file descriptor. + +The mode can be 'rb' (default), or 'wb' for reading or writing bytes. All +other mode characters will be ignored. Mode 'b' will be assumed if it is +omitted. The *opener* parameter is always ignored. +[clinic start generated code]*/ + +static int +_io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, + const char *mode, int closefd, + PyObject *opener) +/*[clinic end generated code: output=3fd9cbcdd8d95429 input=61be39633a86f5d7]*/ +{ + const char *s; + wchar_t *name = NULL; + int ret = 0; + int rwa = 0; + int fd = -1; + int fd_is_own = 0; + + assert(PyWindowsConsoleIO_Check(self)); + if (self->handle >= 0) { + if (self->closehandle) { + /* Have to close the existing file first. */ + if (internal_close(self) < 0) + return -1; + } + else + self->handle = INVALID_HANDLE_VALUE; + } + + if (PyFloat_Check(nameobj)) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float"); + return -1; + } + + fd = _PyLong_AsInt(nameobj); + if (fd < 0) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "negative file descriptor"); + return -1; + } + PyErr_Clear(); + } + self->fd = fd; + + if (fd < 0) { + PyObject *decodedname = Py_None; + Py_INCREF(decodedname); + + int d = PyUnicode_FSDecoder(nameobj, (void*)&decodedname); + if (!d) + return -1; + + Py_ssize_t length; + name = PyUnicode_AsWideCharString(decodedname, &length); + Py_CLEAR(decodedname); + if (name == NULL) + return -1; + + if (wcslen(name) != length) { + PyMem_Free(name); + PyErr_SetString(PyExc_ValueError, "embedded null character"); + return -1; + } + } + + s = mode; + while (*s) { + switch (*s++) { + case '+': + case 'a': + case 'b': + case 'x': + break; + case 'r': + if (rwa) + goto bad_mode; + rwa = 1; + self->readable = 1; + break; + case 'w': + if (rwa) + goto bad_mode; + rwa = 1; + self->writable = 1; + break; + default: + PyErr_Format(PyExc_ValueError, + "invalid mode: %.200s", mode); + goto error; + } + } + + if (!rwa) + goto bad_mode; + + if (fd >= 0) { + _Py_BEGIN_SUPPRESS_IPH + self->handle = (HANDLE)_get_osfhandle(fd); + _Py_END_SUPPRESS_IPH + self->closehandle = 0; + } else { + DWORD access = GENERIC_READ; + + self->closehandle = 1; + if (!closefd) { + PyErr_SetString(PyExc_ValueError, + "Cannot use closefd=False with file name"); + goto error; + } + + if (self->writable) + access |= GENERIC_WRITE; + + Py_BEGIN_ALLOW_THREADS + /* Attempt to open for read/write initially, then fall back + on the specific access. This is required for modern names + CONIN$ and CONOUT$, which allow reading/writing state as + well as reading/writing content. */ + self->handle = CreateFileW(name, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (self->handle == INVALID_HANDLE_VALUE) + self->handle = CreateFileW(name, access, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + Py_END_ALLOW_THREADS + + if (self->handle == INVALID_HANDLE_VALUE) { + PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, GetLastError(), nameobj); + goto error; + } + } + + if (self->writable && _get_console_type(self->handle) != 'w') { + PyErr_SetString(PyExc_ValueError, + "Cannot open console input buffer for writing"); + goto error; + } + if (self->readable && _get_console_type(self->handle) != 'r') { + PyErr_SetString(PyExc_ValueError, + "Cannot open console output buffer for reading"); + goto error; + } + + self->blksize = DEFAULT_BUFFER_SIZE; + memset(self->buf, 0, 4); + + if (_PyObject_SetAttrId((PyObject *)self, &PyId_name, nameobj) < 0) + goto error; + + goto done; + +bad_mode: + PyErr_SetString(PyExc_ValueError, + "Must have exactly one of read or write mode"); +error: + ret = -1; + internal_close(self); + +done: + if (name) + PyMem_Free(name); + return ret; +} + +static int +winconsoleio_traverse(winconsoleio *self, visitproc visit, void *arg) +{ + Py_VISIT(self->dict); + return 0; +} + +static int +winconsoleio_clear(winconsoleio *self) +{ + Py_CLEAR(self->dict); + return 0; +} + +static void +winconsoleio_dealloc(winconsoleio *self) +{ + self->finalizing = 1; + if (_PyIOBase_finalize((PyObject *) self) < 0) + return; + _PyObject_GC_UNTRACK(self); + if (self->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) self); + Py_CLEAR(self->dict); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject * +err_closed(void) +{ + PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); + return NULL; +} + +static PyObject * +err_mode(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; +} + +/*[clinic input] +_io._WindowsConsoleIO.fileno + +Return the underlying file descriptor (an integer). + +fileno is only set when a file descriptor is used to open +one of the standard streams. + +[clinic start generated code]*/ + +static PyObject * +_io__WindowsConsoleIO_fileno_impl(winconsoleio *self) +/*[clinic end generated code: output=006fa74ce3b5cfbf input=079adc330ddaabe6]*/ +{ + if (self->fd < 0 && self->handle != INVALID_HANDLE_VALUE) { + _Py_BEGIN_SUPPRESS_IPH + if (self->writable) + self->fd = _open_osfhandle((intptr_t)self->handle, 'wb'); + else + self->fd = _open_osfhandle((intptr_t)self->handle, 'rb'); + _Py_END_SUPPRESS_IPH + } + if (self->fd < 0) + return err_mode("fileno"); + return PyLong_FromLong(self->fd); +} + +/*[clinic input] +_io._WindowsConsoleIO.readable + +True if console is an input buffer. +[clinic start generated code]*/ + +static PyObject * +_io__WindowsConsoleIO_readable_impl(winconsoleio *self) +/*[clinic end generated code: output=daf9cef2743becf0 input=6be9defb5302daae]*/ +{ + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); + return PyBool_FromLong((long) self->readable); +} + +/*[clinic input] +_io._WindowsConsoleIO.writable + +True if console is an output buffer. +[clinic start generated code]*/ + +static PyObject * +_io__WindowsConsoleIO_writable_impl(winconsoleio *self) +/*[clinic end generated code: output=e0a2ad7eae5abf67 input=cefbd8abc24df6a0]*/ +{ + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); + return PyBool_FromLong((long) self->writable); +} + +static DWORD +_buflen(winconsoleio *self) +{ + for (DWORD i = 0; i < 4; ++i) { + if (!self->buf[i]) + return i; + } + return 4; +} + +static DWORD +_copyfrombuf(winconsoleio *self, char *buf, DWORD len) +{ + DWORD n = 0; + + while (self->buf[0] && len--) { + n += 1; + buf[0] = self->buf[0]; + self->buf[0] = self->buf[1]; + self->buf[1] = self->buf[2]; + self->buf[2] = self->buf[3]; + self->buf[3] = 0; + } + + return n; +} + +static wchar_t * +read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { + int err = 0, sig = 0; + + wchar_t *buf = (wchar_t*)PyMem_Malloc(maxlen * sizeof(wchar_t)); + if (!buf) + goto error; + *readlen = 0; + + Py_BEGIN_ALLOW_THREADS + for (DWORD off = 0; off < maxlen; off += BUFSIZ) { + DWORD n, len = min(maxlen - off, BUFSIZ); + SetLastError(0); + BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL); + + if (!res) { + err = GetLastError(); + break; + } + if (n == 0) { + err = GetLastError(); + if (err != ERROR_OPERATION_ABORTED) + break; + err = 0; + HANDLE hInterruptEvent = _PyOS_SigintEvent(); + if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE) + == WAIT_OBJECT_0) { + ResetEvent(hInterruptEvent); + Py_BLOCK_THREADS + sig = PyErr_CheckSignals(); + Py_UNBLOCK_THREADS + if (sig < 0) + break; + } + } + *readlen += n; + + /* If we didn't read a full buffer that time, don't try + again or we will block a second time. */ + if (n < len) + break; + /* If the buffer ended with a newline, break out */ + if (buf[*readlen - 1] == '\n') + break; + } + Py_END_ALLOW_THREADS + + if (sig) + goto error; + if (err) { + PyErr_SetFromWindowsErr(err); + goto error; + } + + if (*readlen > 0 && buf[0] == L'\x1a') { + PyMem_Free(buf); + buf = (wchar_t *)PyMem_Malloc(sizeof(wchar_t)); + if (!buf) + goto error; + buf[0] = L'\0'; + *readlen = 0; + } + + return buf; + +error: + if (buf) + PyMem_Free(buf); + return NULL; +} + + +static Py_ssize_t +readinto(winconsoleio *self, char *buf, Py_ssize_t len) +{ + if (self->handle == INVALID_HANDLE_VALUE) { + err_closed(); + return -1; + } + if (!self->readable) { + err_mode("reading"); + return -1; + } + if (len == 0) + return 0; + if (len > BUFMAX) { + PyErr_Format(PyExc_ValueError, "cannot read more than %d bytes", BUFMAX); + return -1; + } + + /* Each character may take up to 4 bytes in the final buffer. + This is highly conservative, but necessary to avoid + failure for any given Unicode input (e.g. \U0010ffff). + If the caller requests fewer than 4 bytes, we buffer one + character. + */ + DWORD wlen = (DWORD)(len / 4); + if (wlen == 0) { + wlen = 1; + } + + DWORD read_len = _copyfrombuf(self, buf, (DWORD)len); + if (read_len) { + buf = &buf[read_len]; + len -= read_len; + wlen -= 1; + } + if (len == read_len || wlen == 0) + return read_len; + + DWORD n; + wchar_t *wbuf = read_console_w(self->handle, wlen, &n); + if (wbuf == NULL) + return -1; + if (n == 0) { + PyMem_Free(wbuf); + return read_len; + } + + int err = 0; + DWORD u8n = 0; + + Py_BEGIN_ALLOW_THREADS + if (len < 4) { + if (WideCharToMultiByte(CP_UTF8, 0, wbuf, n, + self->buf, sizeof(self->buf) / sizeof(self->buf[0]), + NULL, NULL)) + u8n = _copyfrombuf(self, buf, (DWORD)len); + } else { + u8n = WideCharToMultiByte(CP_UTF8, 0, wbuf, n, + buf, (DWORD)len, NULL, NULL); + } + + if (u8n) { + read_len += u8n; + u8n = 0; + } else { + err = GetLastError(); + if (err == ERROR_INSUFFICIENT_BUFFER) { + /* Calculate the needed buffer for a more useful error, as this + means our "/ 4" logic above is insufficient for some input. + */ + u8n = WideCharToMultiByte(CP_UTF8, 0, wbuf, n, + NULL, 0, NULL, NULL); + } + } + Py_END_ALLOW_THREADS + + PyMem_Free(wbuf); + + if (u8n) { + PyErr_Format(PyExc_SystemError, + "Buffer had room for %d bytes but %d bytes required", + len, u8n); + return -1; + } + if (err) { + PyErr_SetFromWindowsErr(err); + return -1; + } + + return read_len; +} + +/*[clinic input] +_io._WindowsConsoleIO.readinto + buffer: Py_buffer(accept={rwbuffer}) + / + +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]*/ +{ + Py_ssize_t len = readinto(self, buffer->buf, buffer->len); + if (len < 0) + return NULL; + + return PyLong_FromSsize_t(len); +} + +static DWORD +new_buffersize(winconsoleio *self, DWORD currentsize) +{ + DWORD addend; + + /* Expand the buffer by an amount proportional to the current size, + giving us amortized linear-time behavior. For bigger sizes, use a + less-than-double growth factor to avoid excessive allocation. */ + if (currentsize > 65536) + addend = currentsize >> 3; + else + addend = 256 + currentsize; + if (addend < SMALLCHUNK) + /* Avoid tiny read() calls. */ + addend = SMALLCHUNK; + return addend + currentsize; +} + +/*[clinic input] +_io._WindowsConsoleIO.readall + +Read all data from the console, returned as bytes. + +Return an empty bytes object at EOF. +[clinic start generated code]*/ + +static PyObject * +_io__WindowsConsoleIO_readall_impl(winconsoleio *self) +/*[clinic end generated code: output=e6d312c684f6e23b input=4024d649a1006e69]*/ +{ + wchar_t *buf; + DWORD bufsize, n, len = 0; + PyObject *bytes; + DWORD bytes_size, rn; + + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); + + bufsize = BUFSIZ; + + buf = (wchar_t*)PyMem_Malloc((bufsize + 1) * sizeof(wchar_t)); + if (buf == NULL) + return NULL; + + while (1) { + wchar_t *subbuf; + + if (len >= (Py_ssize_t)bufsize) { + DWORD newsize = new_buffersize(self, len); + if (newsize > BUFMAX) + break; + if (newsize < bufsize) { + PyErr_SetString(PyExc_OverflowError, + "unbounded read returned more bytes " + "than a Python bytes object can hold"); + PyMem_Free(buf); + return NULL; + } + bufsize = newsize; + + buf = PyMem_Realloc(buf, (bufsize + 1) * sizeof(wchar_t)); + if (!buf) { + PyMem_Free(buf); + return NULL; + } + } + + subbuf = read_console_w(self->handle, bufsize - len, &n); + + if (subbuf == NULL) { + PyMem_Free(buf); + return NULL; + } + + if (n > 0) + wcsncpy_s(&buf[len], bufsize - len + 1, subbuf, n); + + PyMem_Free(subbuf); + + /* when the read starts with ^Z or is empty we break */ + if (n == 0 || buf[len] == '\x1a') + break; + + len += n; + } + + if (len > 0 && buf[0] == '\x1a' && _buflen(self) == 0) { + /* when the result starts with ^Z we return an empty buffer */ + PyMem_Free(buf); + return PyBytes_FromStringAndSize(NULL, 0); + } + + Py_BEGIN_ALLOW_THREADS + bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, + NULL, 0, NULL, NULL); + Py_END_ALLOW_THREADS + + if (!bytes_size) { + DWORD err = GetLastError(); + PyMem_Free(buf); + return PyErr_SetFromWindowsErr(err); + } + + bytes_size += _buflen(self); + bytes = PyBytes_FromStringAndSize(NULL, bytes_size); + rn = _copyfrombuf(self, PyBytes_AS_STRING(bytes), bytes_size); + + Py_BEGIN_ALLOW_THREADS + bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, + &PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL); + Py_END_ALLOW_THREADS + + if (!bytes_size) { + DWORD err = GetLastError(); + PyMem_Free(buf); + Py_CLEAR(bytes); + return PyErr_SetFromWindowsErr(err); + } + + PyMem_Free(buf); + if (bytes_size < (size_t)PyBytes_GET_SIZE(bytes)) { + if (_PyBytes_Resize(&bytes, n * sizeof(wchar_t)) < 0) { + Py_CLEAR(bytes); + return NULL; + } + } + return bytes; +} + +/*[clinic input] +_io._WindowsConsoleIO.read + size: io_ssize_t = -1 + / + +Read at most size bytes, returned as bytes. + +Only makes one system call when size is a positive integer, +so less data may be returned than requested. +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=6c56fceec460f1dd]*/ +{ + PyObject *bytes; + Py_ssize_t bytes_size; + + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); + if (!self->readable) + return err_mode("reading"); + + if (size < 0) + return _io__WindowsConsoleIO_readall_impl(self); + if (size > BUFMAX) { + PyErr_Format(PyExc_ValueError, "cannot read more than %d bytes", BUFMAX); + return NULL; + } + + bytes = PyBytes_FromStringAndSize(NULL, size); + if (bytes == NULL) + return NULL; + + bytes_size = readinto(self, PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes)); + if (bytes_size < 0) { + Py_CLEAR(bytes); + return NULL; + } + + if (bytes_size < PyBytes_GET_SIZE(bytes)) { + if (_PyBytes_Resize(&bytes, bytes_size) < 0) { + Py_CLEAR(bytes); + return NULL; + } + } + + return bytes; +} + +/*[clinic input] +_io._WindowsConsoleIO.write + b: Py_buffer + / + +Write buffer b to file, return number of bytes written. + +Only makes one system call, so not all of the data may be written. +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]*/ +{ + BOOL res = TRUE; + wchar_t *wbuf; + DWORD len, wlen, n = 0; + + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); + if (!self->writable) + return err_mode("writing"); + + if (b->len > BUFMAX) + len = BUFMAX; + else + len = (DWORD)b->len; + + Py_BEGIN_ALLOW_THREADS + wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, NULL, 0); + + /* issue11395 there is an unspecified upper bound on how many bytes + can be written at once. We cap at 32k - the caller will have to + handle partial writes. + Since we don't know how many input bytes are being ignored, we + have to reduce and recalculate. */ + while (wlen > 32766 / sizeof(wchar_t)) { + len /= 2; + wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, NULL, 0); + } + Py_END_ALLOW_THREADS + + if (!wlen) + return PyErr_SetFromWindowsErr(0); + + wbuf = (wchar_t*)PyMem_Malloc(wlen * sizeof(wchar_t)); + + Py_BEGIN_ALLOW_THREADS + wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, wbuf, wlen); + if (wlen) { + res = WriteConsoleW(self->handle, wbuf, wlen, &n, NULL); + if (n < wlen) { + /* Wrote fewer characters than expected, which means our + * len value may be wrong. So recalculate it from the + * characters that were written. As this could potentially + * result in a different value, we also validate that value. + */ + len = WideCharToMultiByte(CP_UTF8, 0, wbuf, n, + NULL, 0, NULL, NULL); + if (len) { + wlen = MultiByteToWideChar(CP_UTF8, 0, b->buf, len, + NULL, 0); + assert(wlen == len); + } + } + } else + res = 0; + Py_END_ALLOW_THREADS + + if (!res) { + DWORD err = GetLastError(); + PyMem_Free(wbuf); + return PyErr_SetFromWindowsErr(err); + } + + PyMem_Free(wbuf); + return PyLong_FromSsize_t(len); +} + +static PyObject * +winconsoleio_repr(winconsoleio *self) +{ + if (self->handle == INVALID_HANDLE_VALUE) + return PyUnicode_FromFormat("<_io._WindowsConsoleIO [closed]>"); + + if (self->readable) + return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='rb' closefd=%s>", + self->closehandle ? "True" : "False"); + if (self->writable) + return PyUnicode_FromFormat("<_io._WindowsConsoleIO mode='wb' closefd=%s>", + self->closehandle ? "True" : "False"); + + PyErr_SetString(PyExc_SystemError, "_WindowsConsoleIO has invalid mode"); + return NULL; +} + +/*[clinic input] +_io._WindowsConsoleIO.isatty + +Always True. +[clinic start generated code]*/ + +static PyObject * +_io__WindowsConsoleIO_isatty_impl(winconsoleio *self) +/*[clinic end generated code: output=9eac09d287c11bd7 input=9b91591dbe356f86]*/ +{ + if (self->handle == INVALID_HANDLE_VALUE) + return err_closed(); + + Py_RETURN_TRUE; +} + +static PyObject * +winconsoleio_getstate(winconsoleio *self) +{ + PyErr_Format(PyExc_TypeError, + "cannot serialize '%s' object", Py_TYPE(self)->tp_name); + return NULL; +} + +#include "clinic/winconsoleio.c.h" + +static PyMethodDef winconsoleio_methods[] = { + _IO__WINDOWSCONSOLEIO_READ_METHODDEF + _IO__WINDOWSCONSOLEIO_READALL_METHODDEF + _IO__WINDOWSCONSOLEIO_READINTO_METHODDEF + _IO__WINDOWSCONSOLEIO_WRITE_METHODDEF + _IO__WINDOWSCONSOLEIO_CLOSE_METHODDEF + _IO__WINDOWSCONSOLEIO_READABLE_METHODDEF + _IO__WINDOWSCONSOLEIO_WRITABLE_METHODDEF + _IO__WINDOWSCONSOLEIO_FILENO_METHODDEF + _IO__WINDOWSCONSOLEIO_ISATTY_METHODDEF + {"__getstate__", (PyCFunction)winconsoleio_getstate, METH_NOARGS, NULL}, + {NULL, NULL} /* sentinel */ +}; + +/* 'closed' and 'mode' are attributes for compatibility with FileIO. */ + +static PyObject * +get_closed(winconsoleio *self, void *closure) +{ + return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE)); +} + +static PyObject * +get_closefd(winconsoleio *self, void *closure) +{ + return PyBool_FromLong((long)(self->closehandle)); +} + +static PyObject * +get_mode(winconsoleio *self, void *closure) +{ + return PyUnicode_FromString(self->readable ? "rb" : "wb"); +} + +static PyGetSetDef winconsoleio_getsetlist[] = { + {"closed", (getter)get_closed, NULL, "True if the file is closed"}, + {"closefd", (getter)get_closefd, NULL, + "True if the file descriptor will be closed by close()."}, + {"mode", (getter)get_mode, NULL, "String giving the file mode"}, + {NULL}, +}; + +static PyMemberDef winconsoleio_members[] = { + {"_blksize", T_UINT, offsetof(winconsoleio, blksize), 0}, + {"_finalizing", T_BOOL, offsetof(winconsoleio, finalizing), 0}, + {NULL} +}; + +PyTypeObject PyWindowsConsoleIO_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_io._WindowsConsoleIO", + sizeof(winconsoleio), + 0, + (destructor)winconsoleio_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)winconsoleio_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_FINALIZE, /* tp_flags */ + _io__WindowsConsoleIO___init____doc__, /* tp_doc */ + (traverseproc)winconsoleio_traverse, /* tp_traverse */ + (inquiry)winconsoleio_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(winconsoleio, weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + winconsoleio_methods, /* tp_methods */ + winconsoleio_members, /* tp_members */ + winconsoleio_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(winconsoleio, dict), /* tp_dictoffset */ + _io__WindowsConsoleIO___init__, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + winconsoleio_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ +}; + +#endif /* MS_WINDOWS */ -- cgit v1.2.1 From cbe82eb2f490b35235e2bfc4a5687b69514d2bd2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 11 Sep 2016 21:25:45 +0300 Subject: Issue #27810: Regenerate Argument Clinic. --- Modules/_io/clinic/_iomodule.c.h | 8 ++++---- Modules/_io/clinic/textio.c.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/clinic/_iomodule.c.h b/Modules/_io/clinic/_iomodule.c.h index 50891c59d1..f2e91a9fe6 100644 --- a/Modules/_io/clinic/_iomodule.c.h +++ b/Modules/_io/clinic/_iomodule.c.h @@ -127,7 +127,7 @@ PyDoc_STRVAR(_io_open__doc__, "opened in a binary mode."); #define _IO_OPEN_METHODDEF \ - {"open", (PyCFunction)_io_open, METH_VARARGS|METH_KEYWORDS, _io_open__doc__}, + {"open", (PyCFunction)_io_open, METH_FASTCALL, _io_open__doc__}, static PyObject * _io_open_impl(PyObject *module, PyObject *file, const char *mode, @@ -135,7 +135,7 @@ _io_open_impl(PyObject *module, PyObject *file, const char *mode, const char *newline, int closefd, PyObject *opener); static PyObject * -_io_open(PyObject *module, PyObject *args, PyObject *kwargs) +_io_open(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"file", "mode", "buffering", "encoding", "errors", "newline", "closefd", "opener", NULL}; @@ -149,7 +149,7 @@ _io_open(PyObject *module, PyObject *args, PyObject *kwargs) int closefd = 1; PyObject *opener = Py_None; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, &file, &mode, &buffering, &encoding, &errors, &newline, &closefd, &opener)) { goto exit; } @@ -158,4 +158,4 @@ _io_open(PyObject *module, PyObject *args, PyObject *kwargs) exit: return return_value; } -/*[clinic end generated code: output=14769629391a3130 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=c5b8fc8b83102bbf input=a9049054013a1b77]*/ diff --git a/Modules/_io/clinic/textio.c.h b/Modules/_io/clinic/textio.c.h index 6c40819c5c..f39c35581e 100644 --- a/Modules/_io/clinic/textio.c.h +++ b/Modules/_io/clinic/textio.c.h @@ -46,14 +46,14 @@ PyDoc_STRVAR(_io_IncrementalNewlineDecoder_decode__doc__, "\n"); #define _IO_INCREMENTALNEWLINEDECODER_DECODE_METHODDEF \ - {"decode", (PyCFunction)_io_IncrementalNewlineDecoder_decode, METH_VARARGS|METH_KEYWORDS, _io_IncrementalNewlineDecoder_decode__doc__}, + {"decode", (PyCFunction)_io_IncrementalNewlineDecoder_decode, METH_FASTCALL, _io_IncrementalNewlineDecoder_decode__doc__}, static PyObject * _io_IncrementalNewlineDecoder_decode_impl(nldecoder_object *self, PyObject *input, int final); static PyObject * -_io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *args, PyObject *kwargs) +_io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"input", "final", NULL}; @@ -61,7 +61,7 @@ _io_IncrementalNewlineDecoder_decode(nldecoder_object *self, PyObject *args, PyO PyObject *input; int final = 0; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, &input, &final)) { goto exit; } @@ -464,4 +464,4 @@ _io_TextIOWrapper_close(textio *self, PyObject *Py_UNUSED(ignored)) { return _io_TextIOWrapper_close_impl(self); } -/*[clinic end generated code: output=7ec624a9bf6393f5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=78ad14eba1667254 input=a9049054013a1b77]*/ -- cgit v1.2.1 From 562cfab80352a94996094a39e18064a637b8fda9 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 17 Sep 2016 13:51:23 -0700 Subject: Issue #28161: Opening CON for write access fails Issue #28162: WindowsConsoleIO readall() fails if first line starts with Ctrl+Z Issue #28163: WindowsConsoleIO fileno() passes wrong flags to _open_osfhandle Issue #28164: _PyIO_get_console_type fails for various paths --- Modules/_io/winconsoleio.c | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 2527ff13ca..7d13be5040 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -22,6 +22,7 @@ #define WIN32_LEAN_AND_MEAN #include +#include #include "_iomodule.h" @@ -68,27 +69,34 @@ char _PyIO_get_console_type(PyObject *path_or_fd) { return _get_console_type(handle); } - PyObject *decoded = Py_None; - Py_INCREF(decoded); + PyObject *decoded, *decoded_upper; int d = PyUnicode_FSDecoder(path_or_fd, &decoded); if (!d) { PyErr_Clear(); + return '\0'; + } + if (!PyUnicode_Check(decoded)) { Py_CLEAR(decoded); return '\0'; } + decoded_upper = PyObject_CallMethod(decoded, "upper", ""); + Py_CLEAR(decoded); + if (!decoded_upper) { + PyErr_Clear(); + return '\0'; + } char m = '\0'; - if (!PyUnicode_Check(decoded)) { - return '\0'; - } else if (PyUnicode_CompareWithASCIIString(decoded, "CONIN$") == 0) { + if (PyUnicode_CompareWithASCIIString(decoded_upper, "CONIN$") == 0) { m = 'r'; - } else if (PyUnicode_CompareWithASCIIString(decoded, "CONOUT$") == 0 || - PyUnicode_CompareWithASCIIString(decoded, "CON") == 0) { + } else if (PyUnicode_CompareWithASCIIString(decoded_upper, "CONOUT$") == 0) { m = 'w'; + } else if (PyUnicode_CompareWithASCIIString(decoded_upper, "CON") == 0) { + m = 'x'; } - Py_CLEAR(decoded); + Py_CLEAR(decoded_upper); return m; } @@ -227,6 +235,7 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, { const char *s; wchar_t *name = NULL; + char console_type = '\0'; int ret = 0; int rwa = 0; int fd = -1; @@ -270,6 +279,7 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, Py_ssize_t length; name = PyUnicode_AsWideCharString(decodedname, &length); + console_type = _PyIO_get_console_type(decodedname); Py_CLEAR(decodedname); if (name == NULL) return -1; @@ -294,12 +304,16 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, goto bad_mode; rwa = 1; self->readable = 1; + if (console_type == 'x') + console_type = 'r'; break; case 'w': if (rwa) goto bad_mode; rwa = 1; self->writable = 1; + if (console_type == 'x') + console_type = 'w'; break; default: PyErr_Format(PyExc_ValueError, @@ -327,7 +341,7 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, } if (self->writable) - access |= GENERIC_WRITE; + access = GENERIC_WRITE; Py_BEGIN_ALLOW_THREADS /* Attempt to open for read/write initially, then fall back @@ -347,12 +361,15 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, } } - if (self->writable && _get_console_type(self->handle) != 'w') { + if (console_type == '\0') + console_type = _get_console_type(self->handle); + + if (self->writable && console_type != 'w') { PyErr_SetString(PyExc_ValueError, "Cannot open console input buffer for writing"); goto error; } - if (self->readable && _get_console_type(self->handle) != 'r') { + if (self->readable && console_type != 'r') { PyErr_SetString(PyExc_ValueError, "Cannot open console output buffer for reading"); goto error; @@ -440,9 +457,9 @@ _io__WindowsConsoleIO_fileno_impl(winconsoleio *self) if (self->fd < 0 && self->handle != INVALID_HANDLE_VALUE) { _Py_BEGIN_SUPPRESS_IPH if (self->writable) - self->fd = _open_osfhandle((intptr_t)self->handle, 'wb'); + self->fd = _open_osfhandle((intptr_t)self->handle, _O_WRONLY | _O_BINARY); else - self->fd = _open_osfhandle((intptr_t)self->handle, 'rb'); + self->fd = _open_osfhandle((intptr_t)self->handle, _O_RDONLY | _O_BINARY); _Py_END_SUPPRESS_IPH } if (self->fd < 0) @@ -776,7 +793,7 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self) len += n; } - if (len > 0 && buf[0] == '\x1a' && _buflen(self) == 0) { + if (len == 0 || buf[0] == '\x1a' && _buflen(self) == 0) { /* when the result starts with ^Z we return an empty buffer */ PyMem_Free(buf); return PyBytes_FromStringAndSize(NULL, 0); -- cgit v1.2.1 From 6bf14c47b10de875bf240fdba889ba2519b9aff7 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 26 Sep 2016 14:08:47 +0200 Subject: Issue #28277: remove linefeed character from iomodule.h. Patch by Michael Felt --- Modules/_io/_iomodule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 5d3da29ce1..4ed9ebf66a 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -153,7 +153,7 @@ extern PyObject *_PyIO_get_locale_module(_PyIO_State *); #ifdef MS_WINDOWS extern char _PyIO_get_console_type(PyObject *); -#endif +#endif extern PyObject *_PyIO_str_close; extern PyObject *_PyIO_str_closed; -- cgit v1.2.1 From 3d0d1e31a864f8eac69b4fd63ccd947fb0d7c58b Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 3 Oct 2016 09:04:58 -0700 Subject: Issue #28217: Adds _testconsole module to test console input. Fixes some issues found by the tests. --- Modules/_io/_iomodule.h | 3 ++- Modules/_io/winconsoleio.c | 54 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 12 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 4ed9ebf66a..daaebd2ab6 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -22,7 +22,8 @@ extern PyTypeObject PyIncrementalNewlineDecoder_Type; #ifndef Py_LIMITED_API #ifdef MS_WINDOWS extern PyTypeObject PyWindowsConsoleIO_Type; -#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), &PyWindowsConsoleIO_Type)) +PyAPI_DATA(PyObject *) _PyWindowsConsoleIO_Type; +#define PyWindowsConsoleIO_Check(op) (PyObject_TypeCheck((op), (PyTypeObject*)_PyWindowsConsoleIO_Type)) #endif /* MS_WINDOWS */ #endif /* Py_LIMITED_API */ diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 0bf4ddf7e1..ee7a1b20a0 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -39,6 +39,11 @@ /* BUFMAX determines how many bytes can be read in one go. */ #define BUFMAX (32*1024*1024) +/* SMALLBUF determines how many utf-8 characters will be + buffered within the stream, in order to support reads + of less than one character */ +#define SMALLBUF 4 + char _get_console_type(HANDLE handle) { DWORD mode, peek_count; @@ -125,7 +130,8 @@ typedef struct { unsigned int blksize; PyObject *weakreflist; PyObject *dict; - char buf[4]; + char buf[SMALLBUF]; + wchar_t wbuf; } winconsoleio; PyTypeObject PyWindowsConsoleIO_Type; @@ -500,11 +506,11 @@ _io__WindowsConsoleIO_writable_impl(winconsoleio *self) static DWORD _buflen(winconsoleio *self) { - for (DWORD i = 0; i < 4; ++i) { + for (DWORD i = 0; i < SMALLBUF; ++i) { if (!self->buf[i]) return i; } - return 4; + return SMALLBUF; } static DWORD @@ -513,12 +519,10 @@ _copyfrombuf(winconsoleio *self, char *buf, DWORD len) DWORD n = 0; while (self->buf[0] && len--) { - n += 1; - buf[0] = self->buf[0]; - self->buf[0] = self->buf[1]; - self->buf[1] = self->buf[2]; - self->buf[2] = self->buf[3]; - self->buf[3] = 0; + buf[n++] = self->buf[0]; + for (int i = 1; i < SMALLBUF; ++i) + self->buf[i - 1] = self->buf[i]; + self->buf[SMALLBUF - 1] = 0; } return n; @@ -531,10 +535,13 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { wchar_t *buf = (wchar_t*)PyMem_Malloc(maxlen * sizeof(wchar_t)); if (!buf) goto error; + *readlen = 0; + //DebugBreak(); Py_BEGIN_ALLOW_THREADS - for (DWORD off = 0; off < maxlen; off += BUFSIZ) { + DWORD off = 0; + while (off < maxlen) { DWORD n, len = min(maxlen - off, BUFSIZ); SetLastError(0); BOOL res = ReadConsoleW(handle, &buf[off], len, &n, NULL); @@ -550,7 +557,7 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { err = 0; HANDLE hInterruptEvent = _PyOS_SigintEvent(); if (WaitForSingleObjectEx(hInterruptEvent, 100, FALSE) - == WAIT_OBJECT_0) { + == WAIT_OBJECT_0) { ResetEvent(hInterruptEvent); Py_BLOCK_THREADS sig = PyErr_CheckSignals(); @@ -568,7 +575,30 @@ read_console_w(HANDLE handle, DWORD maxlen, DWORD *readlen) { /* If the buffer ended with a newline, break out */ if (buf[*readlen - 1] == '\n') break; + /* If the buffer ends with a high surrogate, expand the + buffer and read an extra character. */ + WORD char_type; + if (off + BUFSIZ >= maxlen && + GetStringTypeW(CT_CTYPE3, &buf[*readlen - 1], 1, &char_type) && + char_type == C3_HIGHSURROGATE) { + wchar_t *newbuf; + maxlen += 1; + Py_BLOCK_THREADS + newbuf = (wchar_t*)PyMem_Realloc(buf, maxlen * sizeof(wchar_t)); + Py_UNBLOCK_THREADS + if (!newbuf) { + sig = -1; + break; + } + buf = newbuf; + /* Only advance by n and not BUFSIZ in this case */ + off += n; + continue; + } + + off += BUFSIZ; } + Py_END_ALLOW_THREADS if (sig) @@ -1110,4 +1140,6 @@ PyTypeObject PyWindowsConsoleIO_Type = { 0, /* tp_finalize */ }; +PyAPI_DATA(PyObject *) _PyWindowsConsoleIO_Type = (PyObject*)&PyWindowsConsoleIO_Type; + #endif /* MS_WINDOWS */ -- cgit v1.2.1 From 9f35fd9eea76fa28832eb7a934ba8698f87e2037 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 8 Oct 2016 12:37:33 -0700 Subject: Issue #28162: Fixes Ctrl+Z handling in console readall() --- Modules/_io/winconsoleio.c | 49 +++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 20 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index ee7a1b20a0..4666a3867a 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -816,44 +816,53 @@ _io__WindowsConsoleIO_readall_impl(winconsoleio *self) PyMem_Free(subbuf); - /* when the read starts with ^Z or is empty we break */ - if (n == 0 || buf[len] == '\x1a') + /* when the read is empty we break */ + if (n == 0) break; len += n; } - if (len == 0 || buf[0] == '\x1a' && _buflen(self) == 0) { + if (len == 0 && _buflen(self) == 0) { /* when the result starts with ^Z we return an empty buffer */ PyMem_Free(buf); return PyBytes_FromStringAndSize(NULL, 0); } - Py_BEGIN_ALLOW_THREADS - bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, - NULL, 0, NULL, NULL); - Py_END_ALLOW_THREADS + if (len) { + Py_BEGIN_ALLOW_THREADS + bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, + NULL, 0, NULL, NULL); + Py_END_ALLOW_THREADS - if (!bytes_size) { - DWORD err = GetLastError(); - PyMem_Free(buf); - return PyErr_SetFromWindowsErr(err); + if (!bytes_size) { + DWORD err = GetLastError(); + PyMem_Free(buf); + return PyErr_SetFromWindowsErr(err); + } + } else { + bytes_size = 0; } bytes_size += _buflen(self); bytes = PyBytes_FromStringAndSize(NULL, bytes_size); rn = _copyfrombuf(self, PyBytes_AS_STRING(bytes), bytes_size); - Py_BEGIN_ALLOW_THREADS - bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, - &PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL); - Py_END_ALLOW_THREADS + if (len) { + Py_BEGIN_ALLOW_THREADS + bytes_size = WideCharToMultiByte(CP_UTF8, 0, buf, len, + &PyBytes_AS_STRING(bytes)[rn], bytes_size - rn, NULL, NULL); + Py_END_ALLOW_THREADS - if (!bytes_size) { - DWORD err = GetLastError(); - PyMem_Free(buf); - Py_CLEAR(bytes); - return PyErr_SetFromWindowsErr(err); + if (!bytes_size) { + DWORD err = GetLastError(); + PyMem_Free(buf); + Py_CLEAR(bytes); + return PyErr_SetFromWindowsErr(err); + } + + /* add back the number of preserved bytes */ + bytes_size += rn; } PyMem_Free(buf); -- cgit v1.2.1 From 57c0f2e61c8a5893c37e576a3a03ba5e57c1132c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 20 Nov 2016 09:13:07 +0200 Subject: Replaced outdated macros _PyUnicode_AsString and _PyUnicode_AsStringAndSize with PyUnicode_AsUTF8 and PyUnicode_AsUTF8AndSize. --- Modules/_io/stringio.c | 2 +- Modules/_io/textio.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index ecf6dc1963..8542efd972 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -708,7 +708,7 @@ _io_StringIO___init___impl(stringio *self, PyObject *value, Py_TYPE(newline_obj)->tp_name); return -1; } - newline = _PyUnicode_AsString(newline_obj); + newline = PyUnicode_AsUTF8(newline_obj); if (newline == NULL) return -1; } diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 2f55eb0595..1c7200b0ae 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -921,7 +921,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, Py_CLEAR(self->encoding); } if (self->encoding != NULL) { - encoding = _PyUnicode_AsString(self->encoding); + encoding = PyUnicode_AsUTF8(self->encoding); if (encoding == NULL) goto error; } @@ -964,7 +964,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, } self->writetranslate = (newline == NULL || newline[0] != '\0'); if (!self->readuniversal && self->readnl) { - self->writenl = _PyUnicode_AsString(self->readnl); + self->writenl = PyUnicode_AsUTF8(self->readnl); if (self->writenl == NULL) goto error; if (!strcmp(self->writenl, "\n")) -- cgit v1.2.1 From 6ed09e25a422f7eb9093c248769b763ca823c144 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 28 Dec 2016 15:41:09 -0800 Subject: Issue #28768: Fix implicit declaration of function _setmode. Patch by Masayuki Yamamoto --- Modules/_io/fileio.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 54cfb7fa7d..6854a44e2d 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -9,6 +9,9 @@ #ifdef HAVE_SYS_STAT_H #include #endif +#ifdef HAVE_IO_H +#include +#endif #ifdef HAVE_FCNTL_H #include #endif -- cgit v1.2.1 From 34dd8d03f4f431092f5bf3adb6a59b423f196a53 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 4 Feb 2017 14:38:11 -0800 Subject: Issue #29409: Implement PEP 529 for io.FileIO (Patch by Eryk Sun) --- Modules/_io/fileio.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c index 6854a44e2d..7f3bcab962 100644 --- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -230,12 +230,13 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, int closefd, PyObject *opener) /*[clinic end generated code: output=23413f68e6484bbd input=193164e293d6c097]*/ { - const char *name = NULL; - PyObject *stringobj = NULL; - const char *s; #ifdef MS_WINDOWS Py_UNICODE *widename = NULL; +#else + const char *name = NULL; #endif + PyObject *stringobj = NULL; + const char *s; int ret = 0; int rwa = 0, plus = 0; int flags = 0; @@ -277,24 +278,21 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, PyErr_Clear(); } + if (fd < 0) { #ifdef MS_WINDOWS - if (PyUnicode_Check(nameobj)) { Py_ssize_t length; - widename = PyUnicode_AsUnicodeAndSize(nameobj, &length); - if (widename == NULL) - return -1; - if (wcslen(widename) != length) { - PyErr_SetString(PyExc_ValueError, "embedded null character"); + if (!PyUnicode_FSDecoder(nameobj, &stringobj)) { return -1; } - } else -#endif - if (fd < 0) - { + widename = PyUnicode_AsUnicodeAndSize(stringobj, &length); + if (widename == NULL) + return -1; +#else if (!PyUnicode_FSConverter(nameobj, &stringobj)) { return -1; } name = PyBytes_AS_STRING(stringobj); +#endif } s = mode; @@ -386,11 +384,10 @@ _io_FileIO___init___impl(fileio *self, PyObject *nameobj, const char *mode, do { Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS - if (widename != NULL) - self->fd = _wopen(widename, flags, 0666); - else + self->fd = _wopen(widename, flags, 0666); +#else + self->fd = open(name, flags, 0666); #endif - self->fd = open(name, flags, 0666); Py_END_ALLOW_THREADS } while (self->fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); -- cgit v1.2.1 From b23f2a20c4a98dc6d012e9fd9ce36f7c83f79d57 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 4 Feb 2017 15:07:46 -0800 Subject: Issue #28164: Correctly handle special console filenames (patch by Eryk Sun) --- Modules/_io/winconsoleio.c | 67 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 20 deletions(-) (limited to 'Modules/_io') diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 7b00a9eb6d..1ad0bfcdcd 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -60,51 +60,68 @@ char _get_console_type(HANDLE handle) { } char _PyIO_get_console_type(PyObject *path_or_fd) { - int fd; - - fd = PyLong_AsLong(path_or_fd); + int fd = PyLong_AsLong(path_or_fd); PyErr_Clear(); if (fd >= 0) { HANDLE handle; _Py_BEGIN_SUPPRESS_IPH handle = (HANDLE)_get_osfhandle(fd); _Py_END_SUPPRESS_IPH - if (!handle) + if (handle == INVALID_HANDLE_VALUE) return '\0'; return _get_console_type(handle); } - PyObject *decoded, *decoded_upper; + PyObject *decoded; + wchar_t *decoded_wstr; - int d = PyUnicode_FSDecoder(path_or_fd, &decoded); - if (!d) { + if (!PyUnicode_FSDecoder(path_or_fd, &decoded)) { PyErr_Clear(); return '\0'; } - if (!PyUnicode_Check(decoded)) { - Py_CLEAR(decoded); - return '\0'; - } - decoded_upper = PyObject_CallMethod(decoded, "upper", ""); + decoded_wstr = PyUnicode_AsWideCharString(decoded, NULL); Py_CLEAR(decoded); - if (!decoded_upper) { + if (!decoded_wstr) { PyErr_Clear(); return '\0'; } + DWORD length; + wchar_t name_buf[MAX_PATH], *pname_buf = name_buf; + + length = GetFullPathNameW(decoded_wstr, MAX_PATH, pname_buf, NULL); + if (length > MAX_PATH) { + pname_buf = PyMem_New(wchar_t, length); + if (pname_buf) + length = GetFullPathNameW(decoded_wstr, length, pname_buf, NULL); + else + length = 0; + } + PyMem_Free(decoded_wstr); + char m = '\0'; - if (_PyUnicode_EqualToASCIIString(decoded_upper, "CONIN$")) { - m = 'r'; - } else if (_PyUnicode_EqualToASCIIString(decoded_upper, "CONOUT$")) { - m = 'w'; - } else if (_PyUnicode_EqualToASCIIString(decoded_upper, "CON")) { - m = 'x'; + if (length) { + wchar_t *name = pname_buf; + if (length >= 4 && name[3] == L'\\' && + (name[2] == L'.' || name[2] == L'?') && + name[1] == L'\\' && name[0] == L'\\') { + name += 4; + } + if (!_wcsicmp(name, L"CONIN$")) { + m = 'r'; + } else if (!_wcsicmp(name, L"CONOUT$")) { + m = 'w'; + } else if (!_wcsicmp(name, L"CON")) { + m = 'x'; + } } - Py_CLEAR(decoded_upper); + if (pname_buf != name_buf) + PyMem_Free(pname_buf); return m; } + /*[clinic input] module _io class _io._WindowsConsoleIO "winconsoleio *" "&PyWindowsConsoleIO_Type" @@ -289,6 +306,11 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, Py_CLEAR(decodedname); if (name == NULL) return -1; + if (console_type == '\0') { + PyErr_SetString(PyExc_ValueError, + "Cannot open non-console file"); + return -1; + } if (wcslen(name) != length) { PyMem_Free(name); @@ -370,6 +392,11 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj, if (console_type == '\0') console_type = _get_console_type(self->handle); + if (console_type == '\0') { + PyErr_SetString(PyExc_ValueError, + "Cannot open non-console file"); + goto error; + } if (self->writable && console_type != 'w') { PyErr_SetString(PyExc_ValueError, "Cannot open console input buffer for writing"); -- cgit v1.2.1 From 2af0fb8818763f1942666dae0835baeab65340fc Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Sat, 4 Feb 2017 17:36:47 -0800 Subject: Adds precheck for console filename to fix Windows 7. --- Modules/_io/winconsoleio.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'Modules/_io') diff --git a/Modules/_io/winconsoleio.c b/Modules/_io/winconsoleio.c index 1ad0bfcdcd..1d169e2764 100644 --- a/Modules/_io/winconsoleio.c +++ b/Modules/_io/winconsoleio.c @@ -86,6 +86,19 @@ char _PyIO_get_console_type(PyObject *path_or_fd) { return '\0'; } + char m = '\0'; + if (!_wcsicmp(decoded_wstr, L"CONIN$")) { + m = 'r'; + } else if (!_wcsicmp(decoded_wstr, L"CONOUT$")) { + m = 'w'; + } else if (!_wcsicmp(decoded_wstr, L"CON")) { + m = 'x'; + } + if (m) { + PyMem_Free(decoded_wstr); + return m; + } + DWORD length; wchar_t name_buf[MAX_PATH], *pname_buf = name_buf; @@ -99,7 +112,6 @@ char _PyIO_get_console_type(PyObject *path_or_fd) { } PyMem_Free(decoded_wstr); - char m = '\0'; if (length) { wchar_t *name = pname_buf; if (length >= 4 && name[3] == L'\\' && -- cgit v1.2.1