mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	merge 3.3 (#16597)
This commit is contained in:
		
						commit
						4c05969fc4
					
				
					 5 changed files with 80 additions and 13 deletions
				
			
		
							
								
								
									
										12
									
								
								Lib/_pyio.py
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								Lib/_pyio.py
									
										
									
									
									
								
							|  | @ -346,8 +346,10 @@ def close(self): | ||||||
|         This method has no effect if the file is already closed. |         This method has no effect if the file is already closed. | ||||||
|         """ |         """ | ||||||
|         if not self.__closed: |         if not self.__closed: | ||||||
|             self.flush() |             try: | ||||||
|             self.__closed = True |                 self.flush() | ||||||
|  |             finally: | ||||||
|  |                 self.__closed = True | ||||||
| 
 | 
 | ||||||
|     def __del__(self): |     def __del__(self): | ||||||
|         """Destructor.  Calls close().""" |         """Destructor.  Calls close().""" | ||||||
|  | @ -1584,8 +1586,10 @@ def flush(self): | ||||||
| 
 | 
 | ||||||
|     def close(self): |     def close(self): | ||||||
|         if self.buffer is not None and not self.closed: |         if self.buffer is not None and not self.closed: | ||||||
|             self.flush() |             try: | ||||||
|             self.buffer.close() |                 self.flush() | ||||||
|  |             finally: | ||||||
|  |                 self.buffer.close() | ||||||
| 
 | 
 | ||||||
|     @property |     @property | ||||||
|     def closed(self): |     def closed(self): | ||||||
|  |  | ||||||
|  | @ -603,6 +603,7 @@ def bad_flush(): | ||||||
|             raise IOError() |             raise IOError() | ||||||
|         f.flush = bad_flush |         f.flush = bad_flush | ||||||
|         self.assertRaises(IOError, f.close) # exception not swallowed |         self.assertRaises(IOError, f.close) # exception not swallowed | ||||||
|  |         self.assertTrue(f.closed) | ||||||
| 
 | 
 | ||||||
|     def test_multi_close(self): |     def test_multi_close(self): | ||||||
|         f = self.open(support.TESTFN, "wb", buffering=0) |         f = self.open(support.TESTFN, "wb", buffering=0) | ||||||
|  | @ -780,6 +781,22 @@ def bad_flush(): | ||||||
|         raw.flush = bad_flush |         raw.flush = bad_flush | ||||||
|         b = self.tp(raw) |         b = self.tp(raw) | ||||||
|         self.assertRaises(IOError, b.close) # exception not swallowed |         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): |     def test_multi_close(self): | ||||||
|         raw = self.MockRawIO() |         raw = self.MockRawIO() | ||||||
|  | @ -1304,6 +1321,16 @@ def test_max_buffer_size_removal(self): | ||||||
|         with self.assertRaises(TypeError): |         with self.assertRaises(TypeError): | ||||||
|             self.tp(self.MockRawIO(), 8, 12) |             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): | class CBufferedWriterTest(BufferedWriterTest, SizeofTest): | ||||||
|     tp = io.BufferedWriter |     tp = io.BufferedWriter | ||||||
|  | @ -2473,6 +2500,7 @@ def bad_flush(): | ||||||
|             raise IOError() |             raise IOError() | ||||||
|         txt.flush = bad_flush |         txt.flush = bad_flush | ||||||
|         self.assertRaises(IOError, txt.close) # exception not swallowed |         self.assertRaises(IOError, txt.close) # exception not swallowed | ||||||
|  |         self.assertTrue(txt.closed) | ||||||
| 
 | 
 | ||||||
|     def test_multi_close(self): |     def test_multi_close(self): | ||||||
|         txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") |         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 | 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 | - Issue #16722: In the bytes() constructor, try to call __bytes__ on the | ||||||
|   argument before __index__. |   argument before __index__. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -484,7 +484,7 @@ buffered_closed_get(buffered *self, void *context) | ||||||
| static PyObject * | static PyObject * | ||||||
| buffered_close(buffered *self, PyObject *args) | buffered_close(buffered *self, PyObject *args) | ||||||
| { | { | ||||||
|     PyObject *res = NULL; |     PyObject *res = NULL, *exc = NULL, *val, *tb; | ||||||
|     int r; |     int r; | ||||||
| 
 | 
 | ||||||
|     CHECK_INITIALIZED(self) |     CHECK_INITIALIZED(self) | ||||||
|  | @ -512,10 +512,10 @@ buffered_close(buffered *self, PyObject *args) | ||||||
|     res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL); |     res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL); | ||||||
|     if (!ENTER_BUFFERED(self)) |     if (!ENTER_BUFFERED(self)) | ||||||
|         return NULL; |         return NULL; | ||||||
|     if (res == NULL) { |     if (res == NULL) | ||||||
|         goto end; |         PyErr_Fetch(&exc, &val, &tb); | ||||||
|     } |     else | ||||||
|     Py_XDECREF(res); |         Py_DECREF(res); | ||||||
| 
 | 
 | ||||||
|     res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL); |     res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_close, NULL); | ||||||
| 
 | 
 | ||||||
|  | @ -524,6 +524,22 @@ buffered_close(buffered *self, PyObject *args) | ||||||
|         self->buffer = NULL; |         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: | end: | ||||||
|     LEAVE_BUFFERED(self) |     LEAVE_BUFFERED(self) | ||||||
|     return res; |     return res; | ||||||
|  |  | ||||||
|  | @ -2548,6 +2548,7 @@ textiowrapper_close(textio *self, PyObject *args) | ||||||
|         Py_RETURN_NONE; /* stream already closed */ |         Py_RETURN_NONE; /* stream already closed */ | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|  |         PyObject *exc = NULL, *val, *tb; | ||||||
|         if (self->deallocating) { |         if (self->deallocating) { | ||||||
|             res = _PyObject_CallMethodId(self->buffer, &PyId__dealloc_warn, "O", self); |             res = _PyObject_CallMethodId(self->buffer, &PyId__dealloc_warn, "O", self); | ||||||
|             if (res) |             if (res) | ||||||
|  | @ -2556,13 +2557,28 @@ textiowrapper_close(textio *self, PyObject *args) | ||||||
|                 PyErr_Clear(); |                 PyErr_Clear(); | ||||||
|         } |         } | ||||||
|         res = _PyObject_CallMethodId((PyObject *)self, &PyId_flush, NULL); |         res = _PyObject_CallMethodId((PyObject *)self, &PyId_flush, NULL); | ||||||
|         if (res == NULL) { |         if (res == NULL) | ||||||
|             return NULL; |             PyErr_Fetch(&exc, &val, &tb); | ||||||
|         } |  | ||||||
|         else |         else | ||||||
|             Py_DECREF(res); |             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