mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	merge 3.3 (#16597)
This commit is contained in:
		
						commit
						4c05969fc4
					
				
					 5 changed files with 80 additions and 13 deletions
				
			
		|  | @ -346,7 +346,9 @@ def close(self): | |||
|         This method has no effect if the file is already closed. | ||||
|         """ | ||||
|         if not self.__closed: | ||||
|             try: | ||||
|                 self.flush() | ||||
|             finally: | ||||
|                 self.__closed = True | ||||
| 
 | ||||
|     def __del__(self): | ||||
|  | @ -1584,7 +1586,9 @@ def flush(self): | |||
| 
 | ||||
|     def close(self): | ||||
|         if self.buffer is not None and not self.closed: | ||||
|             try: | ||||
|                 self.flush() | ||||
|             finally: | ||||
|                 self.buffer.close() | ||||
| 
 | ||||
|     @property | ||||
|  |  | |||
|  | @ -603,6 +603,7 @@ def bad_flush(): | |||
|             raise IOError() | ||||
|         f.flush = bad_flush | ||||
|         self.assertRaises(IOError, f.close) # exception not swallowed | ||||
|         self.assertTrue(f.closed) | ||||
| 
 | ||||
|     def test_multi_close(self): | ||||
|         f = self.open(support.TESTFN, "wb", buffering=0) | ||||
|  | @ -780,6 +781,22 @@ def bad_flush(): | |||
|         raw.flush = bad_flush | ||||
|         b = self.tp(raw) | ||||
|         self.assertRaises(IOError, b.close) # exception not swallowed | ||||
|         self.assertTrue(b.closed) | ||||
| 
 | ||||
|     def test_close_error_on_close(self): | ||||
|         raw = self.MockRawIO() | ||||
|         def bad_flush(): | ||||
|             raise IOError('flush') | ||||
|         def bad_close(): | ||||
|             raise IOError('close') | ||||
|         raw.close = bad_close | ||||
|         b = self.tp(raw) | ||||
|         b.flush = bad_flush | ||||
|         with self.assertRaises(IOError) as err: # exception not swallowed | ||||
|             b.close() | ||||
|         self.assertEqual(err.exception.args, ('close',)) | ||||
|         self.assertEqual(err.exception.__context__.args, ('flush',)) | ||||
|         self.assertFalse(b.closed) | ||||
| 
 | ||||
|     def test_multi_close(self): | ||||
|         raw = self.MockRawIO() | ||||
|  | @ -1304,6 +1321,16 @@ def test_max_buffer_size_removal(self): | |||
|         with self.assertRaises(TypeError): | ||||
|             self.tp(self.MockRawIO(), 8, 12) | ||||
| 
 | ||||
|     def test_write_error_on_close(self): | ||||
|         raw = self.MockRawIO() | ||||
|         def bad_write(b): | ||||
|             raise IOError() | ||||
|         raw.write = bad_write | ||||
|         b = self.tp(raw) | ||||
|         b.write(b'spam') | ||||
|         self.assertRaises(IOError, b.close) # exception not swallowed | ||||
|         self.assertTrue(b.closed) | ||||
| 
 | ||||
| 
 | ||||
| class CBufferedWriterTest(BufferedWriterTest, SizeofTest): | ||||
|     tp = io.BufferedWriter | ||||
|  | @ -2473,6 +2500,7 @@ def bad_flush(): | |||
|             raise IOError() | ||||
|         txt.flush = bad_flush | ||||
|         self.assertRaises(IOError, txt.close) # exception not swallowed | ||||
|         self.assertTrue(txt.closed) | ||||
| 
 | ||||
|     def test_multi_close(self): | ||||
|         txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") | ||||
|  |  | |||
|  | @ -10,6 +10,9 @@ What's New in Python 3.4.0 Alpha 1? | |||
| Core and Builtins | ||||
| ----------------- | ||||
| 
 | ||||
| - Issue #16597: Make BufferedIO.close call close() on the underlying stream if | ||||
|   invoking flush() fails. | ||||
| 
 | ||||
| - Issue #16722: In the bytes() constructor, try to call __bytes__ on the | ||||
|   argument before __index__. | ||||
| 
 | ||||
|  |  | |||
|  | @ -484,7 +484,7 @@ buffered_closed_get(buffered *self, void *context) | |||
| static PyObject * | ||||
| buffered_close(buffered *self, PyObject *args) | ||||
| { | ||||
|     PyObject *res = NULL; | ||||
|     PyObject *res = NULL, *exc = NULL, *val, *tb; | ||||
|     int r; | ||||
| 
 | ||||
|     CHECK_INITIALIZED(self) | ||||
|  | @ -512,10 +512,10 @@ buffered_close(buffered *self, PyObject *args) | |||
|     res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL); | ||||
|     if (!ENTER_BUFFERED(self)) | ||||
|         return NULL; | ||||
|     if (res == NULL) { | ||||
|         goto end; | ||||
|     } | ||||
|     Py_XDECREF(res); | ||||
|     if (res == NULL) | ||||
|         PyErr_Fetch(&exc, &val, &tb); | ||||
|     else | ||||
|         Py_DECREF(res); | ||||
| 
 | ||||
|     res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL); | ||||
| 
 | ||||
|  | @ -524,6 +524,22 @@ buffered_close(buffered *self, PyObject *args) | |||
|         self->buffer = NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (exc != NULL) { | ||||
|         if (res != NULL) { | ||||
|             Py_CLEAR(res); | ||||
|             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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| end: | ||||
|     LEAVE_BUFFERED(self) | ||||
|     return res; | ||||
|  |  | |||
|  | @ -2548,6 +2548,7 @@ textiowrapper_close(textio *self, PyObject *args) | |||
|         Py_RETURN_NONE; /* stream already closed */ | ||||
|     } | ||||
|     else { | ||||
|         PyObject *exc = NULL, *val, *tb; | ||||
|         if (self->deallocating) { | ||||
|             res = _PyObject_CallMethodId(self->buffer, &PyId__dealloc_warn, "O", self); | ||||
|             if (res) | ||||
|  | @ -2556,13 +2557,28 @@ textiowrapper_close(textio *self, PyObject *args) | |||
|                 PyErr_Clear(); | ||||
|         } | ||||
|         res = _PyObject_CallMethodId((PyObject *)self, &PyId_flush, NULL); | ||||
|         if (res == NULL) { | ||||
|             return NULL; | ||||
|         } | ||||
|         if (res == NULL) | ||||
|             PyErr_Fetch(&exc, &val, &tb); | ||||
|         else | ||||
|             Py_DECREF(res); | ||||
| 
 | ||||
|         return _PyObject_CallMethodId(self->buffer, &PyId_close, NULL); | ||||
|         res = _PyObject_CallMethodId(self->buffer, &PyId_close, NULL); | ||||
|         if (exc != NULL) { | ||||
|             if (res != NULL) { | ||||
|                 Py_CLEAR(res); | ||||
|                 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); | ||||
|             } | ||||
|         } | ||||
|         return res; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Benjamin Peterson
						Benjamin Peterson