diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -350,7 +350,7 @@ """ self.call_soon(_raise_stop_error) - def close(self): + def close(self, *, _logger=logger): """Close the event loop. This clears the queues and shuts down the executor, @@ -363,7 +363,7 @@ if self._closed: return if self._debug: - logger.debug("Close %r", self) + _logger.debug("Close %r", self) self._closed = True self._ready.clear() self._scheduled.clear() @@ -380,9 +380,10 @@ # cycle are never destroyed. It's not more the case on Python 3.4 thanks # to the PEP 442. if compat.PY34: - def __del__(self): + def __del__(self, *, _warnings=warnings): if not self.is_closed(): - warnings.warn("unclosed event loop %r" % self, ResourceWarning) + _warnings.warn("unclosed event loop %r" % self, + ResourceWarning) if not self.is_running(): self.close() @@ -989,7 +990,7 @@ 'got {!r}'.format(handler)) self._exception_handler = handler - def default_exception_handler(self, context): + def default_exception_handler(self, context, *, _logger=logger): """Default exception handler. This is called when an exception occurs and no exception @@ -1031,9 +1032,9 @@ value = repr(value) log_lines.append('{}: {}'.format(key, value)) - logger.error('\n'.join(log_lines), exc_info=exc_info) + _logger.error('\n'.join(log_lines), exc_info=exc_info) - def call_exception_handler(self, context): + def call_exception_handler(self, context, *, _logger=logger): """Call the current event loop's exception handler. The context argument is a dict containing the following keys: @@ -1059,8 +1060,8 @@ # Second protection layer for unexpected errors # in the default implementation, as well as for subclassed # event loops with overloaded "default_exception_handler". - logger.error('Exception in default exception handler', - exc_info=True) + _logger.error('Exception in default exception handler', + exc_info=True) else: try: self._exception_handler(self, context) @@ -1076,10 +1077,10 @@ except Exception: # Guard 'default_exception_handler' in case it is # overloaded. - logger.error('Exception in default exception handler ' - 'while handling an unexpected error ' - 'in custom exception handler', - exc_info=True) + _logger.error('Exception in default exception handler ' + 'while handling an unexpected error ' + 'in custom exception handler', + exc_info=True) def _add_callback(self, handle): """Add a Handle to _scheduled (TimerHandle) or _ready.""" diff --git a/Lib/asyncio/base_subprocess.py b/Lib/asyncio/base_subprocess.py --- a/Lib/asyncio/base_subprocess.py +++ b/Lib/asyncio/base_subprocess.py @@ -87,7 +87,7 @@ def _start(self, args, shell, stdin, stdout, stderr, bufsize, **kwargs): raise NotImplementedError - def close(self): + def close(self, *, _logger=logger): if self._closed: return self._closed = True @@ -104,7 +104,7 @@ and self._proc.poll() is None ): if self._loop.get_debug(): - logger.warning('Close running child process: kill %r', self) + _logger.warning('Close running child process: kill %r', self) try: self._proc.kill() @@ -117,9 +117,9 @@ # cycle are never destroyed. It's not more the case on Python 3.4 thanks # to the PEP 442. if compat.PY34: - def __del__(self): + def __del__(self, *, _warnings=warnings): if not self._closed: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + _warnings.warn("unclosed transport %r" % self, ResourceWarning) self.close() def get_pid(self): diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -162,7 +162,7 @@ def cr_frame(self): return self.gen.cr_frame - def __del__(self): + def __del__(self, *, _logger=logger, _traceback=traceback): # Be careful accessing self.gen.frame -- self.gen might not exist. gen = getattr(self, 'gen', None) frame = getattr(gen, 'gi_frame', None) @@ -172,11 +172,11 @@ msg = '%r was never yielded from' % self tb = getattr(self, '_source_traceback', ()) if tb: - tb = ''.join(traceback.format_list(tb)) + tb = ''.join(_traceback.format_list(tb)) msg += ('\nCoroutine object created at ' '(most recent call last):\n') msg += tb.rstrip() - logger.error(msg) + _logger.error(msg) def coroutine(func): diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -80,9 +80,9 @@ # cycle are never destroyed. It's not more the case on Python 3.4 thanks # to the PEP 442. if compat.PY34: - def __del__(self): + def __del__(self, *, _warnings=warnings): if self._sock is not None: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + _warnings.warn("unclosed transport %r" % self, ResourceWarning) self.close() def _fatal_error(self, exc, message='Fatal error on pipe transport'): diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -569,9 +569,9 @@ # cycle are never destroyed. It's not more the case on Python 3.4 thanks # to the PEP 442. if compat.PY34: - def __del__(self): + def __del__(self, *, _warnings=warnings): if self._sock is not None: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + _warnings.warn("unclosed transport %r" % self, ResourceWarning) self._sock.close() def _fatal_error(self, exc, message='Fatal error on transport'): diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -318,9 +318,9 @@ # cycle are never destroyed. It's not more the case on Python 3.4 thanks # to the PEP 442. if compat.PY34: - def __del__(self): + def __del__(self, *, _warnings=warnings): if not self._closed: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + _warnings.warn("unclosed transport %r" % self, ResourceWarning) self.close() def pause_reading(self): diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -372,9 +372,9 @@ # cycle are never destroyed. It's not more the case on Python 3.4 thanks # to the PEP 442. if compat.PY34: - def __del__(self): + def __del__(self, *, _warnings=warnings): if self._pipe is not None: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + _warnings.warn("unclosed transport %r" % self, ResourceWarning) self._pipe.close() def _fatal_error(self, exc, message='Fatal error on pipe transport'): @@ -557,9 +557,9 @@ # cycle are never destroyed. It's not more the case on Python 3.4 thanks # to the PEP 442. if compat.PY34: - def __del__(self): + def __del__(self, *, _warnings=warnings): if self._pipe is not None: - warnings.warn("unclosed transport %r" % self, ResourceWarning) + _warnings.warn("unclosed transport %r" % self, ResourceWarning) self._pipe.close() def abort(self): diff --git a/Lib/asyncio/windows_events.py b/Lib/asyncio/windows_events.py --- a/Lib/asyncio/windows_events.py +++ b/Lib/asyncio/windows_events.py @@ -713,7 +713,7 @@ # pending operations fail quickly. self._stopped_serving.add(obj) - def close(self): + def close(self, *, _logger=logger): # Cancel remaining registered operations. for address, (fut, ov, obj, callback) in list(self._cache.items()): if fut.cancelled(): @@ -738,7 +738,7 @@ while self._cache: if not self._poll(1): - logger.debug('taking long time to close proactor') + _logger.debug('taking long time to close proactor') self._results = [] if self._iocp is not None: diff --git a/Lib/asyncio/windows_utils.py b/Lib/asyncio/windows_utils.py --- a/Lib/asyncio/windows_utils.py +++ b/Lib/asyncio/windows_utils.py @@ -157,9 +157,9 @@ CloseHandle(self._handle) self._handle = None - def __del__(self): + def __del__(self, *, _warnings=warnings): if self._handle is not None: - warnings.warn("unclosed %r" % self, ResourceWarning) + _warnings.warn("unclosed %r" % self, ResourceWarning) self.close() def __enter__(self): diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -476,7 +476,10 @@ 1/0 # Test call_soon (events.Handle) - with mock.patch('asyncio.base_events.logger') as log: + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): fut = asyncio.Future(loop=self.loop) self.loop.call_soon(zero_error, fut) fut.add_done_callback(lambda fut: self.loop.stop()) @@ -486,7 +489,10 @@ exc_info=(ZeroDivisionError, MOCK_ANY, MOCK_ANY)) # Test call_later (events.TimerHandle) - with mock.patch('asyncio.base_events.logger') as log: + log = mock.Mock() + with mock.patch.dict(asyncio.base_events.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): fut = asyncio.Future(loop=self.loop) self.loop.call_later(0.01, zero_error, fut) fut.add_done_callback(lambda fut: self.loop.stop()) @@ -504,7 +510,10 @@ 1/0 # Test Future.__del__ - with mock.patch('asyncio.base_events.logger') as log: + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): fut = asyncio.ensure_future(zero_error_coro(), loop=self.loop) fut.add_done_callback(lambda *args: self.loop.stop()) self.loop.run_forever() @@ -551,7 +560,10 @@ mock_handler.reset_mock() self.loop.set_exception_handler(None) - with mock.patch('asyncio.base_events.logger') as log: + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): run_loop() log.error.assert_called_with( test_utils.MockPattern( @@ -574,7 +586,10 @@ self.loop.set_exception_handler(handler) - with mock.patch('asyncio.base_events.logger') as log: + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): run_loop() log.error.assert_called_with( test_utils.MockPattern( @@ -605,7 +620,10 @@ loop.call_soon(zero_error) loop._run_once() - with mock.patch('asyncio.base_events.logger') as log: + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + call_exception_handler.__kwdefaults__, + {'_logger': log}): run_loop() log.error.assert_called_with( 'Exception in default exception handler', @@ -615,8 +633,11 @@ raise ValueError('ham') _context = None + log = mock.Mock() loop.set_exception_handler(custom_handler) - with mock.patch('asyncio.base_events.logger') as log: + with mock.patch.dict(asyncio.BaseEventLoop. + call_exception_handler.__kwdefaults__, + {'_logger': log}): run_loop() log.error.assert_called_with( test_utils.MockPattern('Exception in default exception.*' @@ -1206,16 +1227,19 @@ self.loop._accept_connection(MyProto, sock) self.assertFalse(sock.close.called) - @mock.patch('asyncio.base_events.logger') - def test_accept_connection_exception(self, m_log): + def test_accept_connection_exception(self): sock = mock.Mock() sock.fileno.return_value = 10 sock.accept.side_effect = OSError(errno.EMFILE, 'Too many open files') self.loop.remove_reader = mock.Mock() self.loop.call_later = mock.Mock() - self.loop._accept_connection(MyProto, sock) - self.assertTrue(m_log.error.called) + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + self.loop._accept_connection(MyProto, sock) + self.assertTrue(log.error.called) self.assertFalse(sock.close.called) self.loop.remove_reader.assert_called_with(10) self.loop.call_later.assert_called_with(constants.ACCEPT_RETRY_DELAY, diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -211,50 +211,68 @@ self.assertRaises(AssertionError, test) fut.cancel() - @mock.patch('asyncio.base_events.logger') - def test_tb_logger_abandoned(self, m_log): + def test_tb_logger_abandoned(self): fut = asyncio.Future(loop=self.loop) - del fut - self.assertFalse(m_log.error.called) + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + del fut + self.assertFalse(log.error.called) - @mock.patch('asyncio.base_events.logger') - def test_tb_logger_result_unretrieved(self, m_log): + def test_tb_logger_result_unretrieved(self): fut = asyncio.Future(loop=self.loop) fut.set_result(42) - del fut - self.assertFalse(m_log.error.called) + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + del fut + self.assertFalse(log.error.called) - @mock.patch('asyncio.base_events.logger') - def test_tb_logger_result_retrieved(self, m_log): + def test_tb_logger_result_retrieved(self): fut = asyncio.Future(loop=self.loop) fut.set_result(42) fut.result() - del fut - self.assertFalse(m_log.error.called) + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + del fut + self.assertFalse(log.error.called) - @mock.patch('asyncio.base_events.logger') - def test_tb_logger_exception_unretrieved(self, m_log): + def test_tb_logger_exception_unretrieved(self): fut = asyncio.Future(loop=self.loop) fut.set_exception(RuntimeError('boom')) - del fut + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + del fut test_utils.run_briefly(self.loop) - self.assertTrue(m_log.error.called) + self.assertTrue(log.error.called) - @mock.patch('asyncio.base_events.logger') - def test_tb_logger_exception_retrieved(self, m_log): + def test_tb_logger_exception_retrieved(self): fut = asyncio.Future(loop=self.loop) fut.set_exception(RuntimeError('boom')) fut.exception() - del fut - self.assertFalse(m_log.error.called) + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + del fut + self.assertFalse(log.error.called) - @mock.patch('asyncio.base_events.logger') - def test_tb_logger_exception_result_retrieved(self, m_log): + def test_tb_logger_exception_result_retrieved(self): fut = asyncio.Future(loop=self.loop) fut.set_exception(RuntimeError('boom')) self.assertRaises(RuntimeError, fut.result) - del fut - self.assertFalse(m_log.error.called) + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + del fut + self.assertFalse(log.error.called) def test_wrap_future(self): @@ -311,8 +329,7 @@ lineno, 'test_future_source_traceback')) - @mock.patch('asyncio.base_events.logger') - def check_future_exception_never_retrieved(self, debug, m_log): + def check_future_exception_never_retrieved(self, debug): self.loop.set_debug(debug) def memory_error(): @@ -325,10 +342,14 @@ future = asyncio.Future(loop=self.loop) if debug: source_traceback = future._source_traceback - future.set_exception(exc) - future = None - test_utils.run_briefly(self.loop) - support.gc_collect() + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + future.set_exception(exc) + future = None + test_utils.run_briefly(self.loop) + support.gc_collect() if sys.version_info >= (3, 4): if debug: @@ -351,7 +372,7 @@ r'$' ) exc_info = (type(exc), exc, exc.__traceback__) - m_log.error.assert_called_once_with(mock.ANY, exc_info=exc_info) + log.error.assert_called_once_with(mock.ANY, exc_info=exc_info) else: if debug: frame = source_traceback[-1] @@ -373,8 +394,8 @@ r'.*\n' r'MemoryError$' ) - m_log.error.assert_called_once_with(mock.ANY, exc_info=False) - message = m_log.error.call_args[0][0] + log.error.assert_called_once_with(mock.ANY, exc_info=False) + message = log.error.call_args[0][0] self.assertRegex(message, re.compile(regex, re.DOTALL)) def test_future_exception_never_retrieved(self): diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py --- a/Lib/test/test_asyncio/test_pep492.py +++ b/Lib/test/test_asyncio/test_pep492.py @@ -1,6 +1,7 @@ """Tests support for new syntax introduced by PEP 492.""" import collections.abc +import contextlib import types import unittest @@ -139,8 +140,7 @@ data = self.loop.run_until_complete(foo()) self.assertEqual(data, 'spam') - @mock.patch('asyncio.coroutines.logger') - def test_async_def_wrapped(self, m_log): + def test_async_def_wrapped(self): async def foo(): pass async def start(): @@ -149,12 +149,18 @@ repr(foo_coro), r'') - with support.check_warnings((r'.*foo.*was never', - RuntimeWarning)): + with contextlib.ExitStack() as stack: + log = mock.Mock() + stack.enter_context(support.check_warnings( + (r'.*foo.*was never', RuntimeWarning))) + stack.enter_context(mock.patch.dict( + asyncio.coroutines.CoroWrapper. + __del__.__kwdefaults__, + {'_logger': log})) foo_coro = None support.gc_collect() - self.assertTrue(m_log.error.called) - message = m_log.error.call_args[0][0] + self.assertTrue(log.error.called) + message = log.error.call_args[0][0] self.assertRegex(message, r'CoroWrapper.*foo.*was never') diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -226,13 +226,16 @@ test_utils.run_briefly(self.loop) self.assertFalse(self.protocol.connection_lost.called) - @mock.patch('asyncio.base_events.logger') - def test_fatal_error(self, m_logging): + def test_fatal_error(self): tr = self.socket_transport() tr._force_close = mock.Mock() - tr._fatal_error(None) + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + tr._fatal_error(None) self.assertTrue(tr._force_close.called) - self.assertTrue(m_logging.error.called) + self.assertTrue(log.error.called) def test_force_close(self): tr = self.socket_transport() @@ -539,8 +542,7 @@ def test_process_events(self): self.loop._process_events([]) - @mock.patch('asyncio.base_events.logger') - def test_create_server(self, m_log): + def test_create_server(self): pf = mock.Mock() call_soon = self.loop.call_soon = mock.Mock() @@ -563,9 +565,13 @@ # exception fut.result.side_effect = OSError() - loop(fut) + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + loop(fut) self.assertTrue(self.sock.close.called) - self.assertTrue(m_log.error.called) + self.assertTrue(log.error.called) def test_create_server_cancel(self): pf = mock.Mock() diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py --- a/Lib/test/test_asyncio/test_selector_events.py +++ b/Lib/test/test_asyncio/test_selector_events.py @@ -1077,16 +1077,20 @@ err, 'Fatal write error on socket transport') - @mock.patch('asyncio.base_events.logger') - def test_write_ready_exception_and_close(self, m_log): + def test_write_ready_exception_and_close(self): 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() + log = mock.Mock() + with mock.patch.dict(asyncio.BaseEventLoop. + default_exception_handler.__kwdefaults__, + {'_logger': log}): + transport._write_ready() remove_writer.assert_called_with(self.sock_fd) + self.assertTrue(log.error.called) def test_write_eof(self): tr = self.socket_transport() diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1731,25 +1731,28 @@ }) mock_handler.reset_mock() - @mock.patch('asyncio.coroutines.logger') - def test_coroutine_never_yielded(self, m_log): + def test_coroutine_never_yielded(self): with set_coroutine_debug(True): @asyncio.coroutine def coro_noop(): pass tb_filename = __file__ - tb_lineno = sys._getframe().f_lineno + 2 + tb_lineno = sys._getframe().f_lineno + 6 # create a coroutine object but don't use it - coro_noop() - support.gc_collect() + log = mock.Mock() + with mock.patch.dict(asyncio.coroutines.CoroWrapper. + __del__.__kwdefaults__, + {'_logger': log}): + coro_noop() + support.gc_collect() - self.assertTrue(m_log.error.called) - message = m_log.error.call_args[0][0] + self.assertTrue(log.error.called) + message = log.error.call_args[0][0] func_filename, func_lineno = test_utils.get_function_source(coro_noop) regex = (r'^ ' - r'was never yielded from\n' + r'was never yielded from\n' r'Coroutine object created at \(most recent call last\):\n' r'.*\n' r' File "%s", line %s, in test_coroutine_never_yielded\n'