diff -r 0eedac3d0b0a Lib/_pyio.py --- a/Lib/_pyio.py Thu May 29 01:46:48 2014 -0400 +++ b/Lib/_pyio.py Thu May 29 22:27:23 2014 +0300 @@ -200,38 +200,45 @@ (appending and "a" or "") + (updating and "+" or ""), closefd, opener=opener) - line_buffering = False - if buffering == 1 or buffering < 0 and raw.isatty(): - buffering = -1 - line_buffering = True - if buffering < 0: - buffering = DEFAULT_BUFFER_SIZE - try: - bs = os.fstat(raw.fileno()).st_blksize - except (OSError, AttributeError): - pass + result = raw + try: + line_buffering = False + if buffering == 1 or buffering < 0 and raw.isatty(): + buffering = -1 + line_buffering = True + if buffering < 0: + buffering = DEFAULT_BUFFER_SIZE + try: + bs = os.fstat(raw.fileno()).st_blksize + except (OSError, AttributeError): + pass + else: + if bs > 1: + buffering = bs + if buffering < 0: + raise ValueError("invalid buffering size") + if buffering == 0: + if binary: + return raw + raise ValueError("can't have unbuffered text I/O") + if updating: + buffer = BufferedRandom(raw, buffering) + elif creating or writing or appending: + buffer = BufferedWriter(raw, buffering) + elif reading: + buffer = BufferedReader(raw, buffering) else: - if bs > 1: - buffering = bs - if buffering < 0: - raise ValueError("invalid buffering size") - if buffering == 0: + raise ValueError("unknown mode: %r" % mode) + result = buffer if binary: - return raw - raise ValueError("can't have unbuffered text I/O") - if updating: - buffer = BufferedRandom(raw, buffering) - elif creating or writing or appending: - buffer = BufferedWriter(raw, buffering) - elif reading: - buffer = BufferedReader(raw, buffering) - else: - raise ValueError("unknown mode: %r" % mode) - if binary: - return buffer - text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering) - text.mode = mode - return text + return buffer + text = TextIOWrapper(buffer, encoding, errors, newline, line_buffering) + result = text + text.mode = mode + return text + except: + result.close() + raise class DocDescriptor: diff -r 0eedac3d0b0a Lib/test/test_io.py --- a/Lib/test/test_io.py Thu May 29 01:46:48 2014 -0400 +++ b/Lib/test/test_io.py Thu May 29 22:27:23 2014 +0300 @@ -653,6 +653,20 @@ fileio.close() f2.readline() + def test_nonbuffered_textio(self): + with warnings.catch_warnings(record=True) as recorded: + with self.assertRaises(ValueError): + self.open(support.TESTFN, 'w', buffering=0) + support.gc_collect() + self.assertEqual(recorded, []) + + def test_invalid_encoding(self): + with warnings.catch_warnings(record=True) as recorded: + with self.assertRaises(LookupError): + self.open(support.TESTFN, 'w', encoding='non-existing') + support.gc_collect() + self.assertEqual(recorded, []) + class CIOTest(IOTest): diff -r 0eedac3d0b0a Modules/_io/_iomodule.c --- a/Modules/_io/_iomodule.c Thu May 29 01:46:48 2014 -0400 +++ b/Modules/_io/_iomodule.c Thu May 29 22:27:23 2014 +0300 @@ -235,11 +235,12 @@ char rawmode[6], *m; int line_buffering, isatty; - PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL; + PyObject *raw, *modeobj = NULL, *buffer = NULL, *wrapper = NULL, *result = NULL; _Py_IDENTIFIER(isatty); _Py_IDENTIFIER(fileno); _Py_IDENTIFIER(mode); + _Py_IDENTIFIER(close); if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|sizzziO:open", kwlist, &file, &mode, &buffering, @@ -354,6 +355,7 @@ "OsiO", file, rawmode, closefd, opener); if (raw == NULL) return NULL; + result = raw; modeobj = PyUnicode_FromString(mode); if (modeobj == NULL) @@ -433,9 +435,10 @@ buffer = PyObject_CallFunction(Buffered_class, "Oi", raw, buffering); } - Py_CLEAR(raw); if (buffer == NULL) goto error; + result = buffer; + Py_DECREF(raw); /* if binary, returns the buffered file */ @@ -450,9 +453,10 @@ buffer, encoding, errors, newline, line_buffering); - Py_CLEAR(buffer); if (wrapper == NULL) goto error; + result = wrapper; + Py_DECREF(buffer); if (_PyObject_SetAttrId(wrapper, &PyId_mode, modeobj) < 0) goto error; @@ -460,10 +464,23 @@ return wrapper; error: - Py_XDECREF(raw); + if (result != NULL) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (_PyObject_CallMethodId(result, &PyId_close, NULL) != NULL) + PyErr_Restore(exc, val, tb); + else { + PyObject *val2; + Py_DECREF(exc); + Py_XDECREF(tb); + PyErr_Fetch(&exc, &val2, &tb); + PyErr_NormalizeException(&exc, &val2, &tb); + PyException_SetContext(val2, val); + PyErr_Restore(exc, val2, tb); + } + Py_DECREF(result); + } Py_XDECREF(modeobj); - Py_XDECREF(buffer); - Py_XDECREF(wrapper); return NULL; }