changeset: 101871:d56b3e5ebfe2 parent: 101869:77604a2f019b parent: 101870:9512cfd53903 user: Yury Selivanov date: Sat Jun 11 11:20:50 2016 -0400 files: Lib/asyncio/selector_events.py Misc/NEWS description: Merge 3.5 (issue #27223) diff -r 77604a2f019b -r d56b3e5ebfe2 Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py Sat Jun 11 04:36:34 2016 -0400 +++ b/Lib/asyncio/selector_events.py Sat Jun 11 11:20:50 2016 -0400 @@ -569,6 +569,7 @@ self._loop.remove_reader(self._sock_fd) if not self._buffer: self._conn_lost += 1 + self._loop.remove_writer(self._sock_fd) self._loop.call_soon(self._call_connection_lost, None) # On Python 3.3 and older, objects with a destructor part of a reference @@ -663,6 +664,8 @@ logger.debug("%r resumes reading", self) def _read_ready(self): + if self._conn_lost: + return try: data = self._sock.recv(self.max_size) except (BlockingIOError, InterruptedError): @@ -722,6 +725,8 @@ def _write_ready(self): assert self._buffer, 'Data should not be empty' + if self._conn_lost: + return try: n = self._sock.send(self._buffer) except (BlockingIOError, InterruptedError): @@ -892,6 +897,8 @@ logger.debug("%r resumes reading", self) def _read_ready(self): + if self._conn_lost: + return if self._write_wants_read: self._write_wants_read = False self._write_ready() @@ -924,6 +931,8 @@ self.close() def _write_ready(self): + if self._conn_lost: + return if self._read_wants_write: self._read_wants_write = False self._read_ready() @@ -1001,6 +1010,8 @@ return sum(len(data) for data, _ in self._buffer) def _read_ready(self): + if self._conn_lost: + return try: data, addr = self._sock.recvfrom(self.max_size) except (BlockingIOError, InterruptedError): diff -r 77604a2f019b -r d56b3e5ebfe2 Lib/test/test_asyncio/test_selector_events.py --- a/Lib/test/test_asyncio/test_selector_events.py Sat Jun 11 04:36:34 2016 -0400 +++ b/Lib/test/test_asyncio/test_selector_events.py Sat Jun 11 11:20:50 2016 -0400 @@ -1087,17 +1087,6 @@ err, 'Fatal write error on socket transport') - @mock.patch('asyncio.base_events.logger') - def test_write_ready_exception_and_close(self, m_log): - self.sock.send.side_effect = OSError() - remove_writer = self.loop.remove_writer = mock.Mock() - - transport = self.socket_transport() - transport.close() - transport._buffer.extend(b'data') - transport._write_ready() - remove_writer.assert_called_with(self.sock_fd) - def test_write_eof(self): tr = self.socket_transport() self.assertTrue(tr.can_write_eof()) @@ -1121,6 +1110,14 @@ self.sock.shutdown.assert_called_with(socket.SHUT_WR) tr.close() + @mock.patch('asyncio.base_events.logger') + def test_transport_close_remove_writer(self, m_log): + remove_writer = self.loop.remove_writer = mock.Mock() + + transport = self.socket_transport() + transport.close() + remove_writer.assert_called_with(self.sock_fd) + @unittest.skipIf(ssl is None, 'No ssl module') class SelectorSslTransportTests(test_utils.TestCase): @@ -1175,7 +1172,7 @@ self.sslsock.do_handshake.side_effect = exc with test_utils.disable_logger(): waiter = asyncio.Future(loop=self.loop) - transport = self.ssl_transport(waiter=waiter) + self.ssl_transport(waiter=waiter) self.assertTrue(waiter.done()) self.assertIs(exc, waiter.exception()) self.assertTrue(self.sslsock.close.called) @@ -1374,20 +1371,19 @@ def test_write_ready_send_closing(self): self.sslsock.send.return_value = 4 transport = self._make_one() + transport._buffer = list_to_buffer([b'data']) transport.close() - transport._buffer = list_to_buffer([b'data']) transport._write_ready() - self.assertFalse(self.loop.writers) self.protocol.connection_lost.assert_called_with(None) def test_write_ready_send_closing_empty_buffer(self): self.sslsock.send.return_value = 4 + call_soon = self.loop.call_soon = mock.Mock() transport = self._make_one() - transport.close() transport._buffer = list_to_buffer() + transport.close() transport._write_ready() - self.assertFalse(self.loop.writers) - self.protocol.connection_lost.assert_called_with(None) + call_soon.assert_called_with(transport._call_connection_lost, None) def test_write_ready_send_retry(self): transport = self._make_one()