[Python-checkins] cpython (3.4): asyncio, Tulip issue #136: Add get/set_debug() methods to BaseEventLoopTests.
larry.hastings
python-checkins at python.org
Mon Mar 17 07:32:22 CET 2014
http://hg.python.org/cpython/rev/644acb7e3c22
changeset: 89741:644acb7e3c22
branch: 3.4
user: Victor Stinner <victor.stinner at gmail.com>
date: Wed Feb 19 23:15:02 2014 +0100
summary:
asyncio, Tulip issue #136: Add get/set_debug() methods to BaseEventLoopTests.
Add also a PYTHONASYNCIODEBUG environment variable to debug coroutines since
Python startup, to be able to debug coroutines defined directly in the asyncio
module.
files:
Doc/library/asyncio-dev.rst | 10 ++-
Doc/library/asyncio-eventloop.rst | 16 ++++++
Doc/using/cmdline.rst | 8 +++
Lib/asyncio/base_events.py | 7 ++
Lib/asyncio/events.py | 8 +++
Lib/asyncio/tasks.py | 5 +-
Lib/test/test_asyncio/test_base_events.py | 6 ++
Lib/test/test_asyncio/test_tasks.py | 28 +++++++++++
8 files changed, 83 insertions(+), 5 deletions(-)
diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst
--- a/Doc/library/asyncio-dev.rst
+++ b/Doc/library/asyncio-dev.rst
@@ -1,5 +1,7 @@
.. currentmodule:: asyncio
+.. _asyncio-dev:
+
Develop with asyncio
====================
@@ -81,10 +83,10 @@
When a coroutine function is called but not passed to :func:`async` or to the
:class:`Task` constructor, it is not scheduled and it is probably a bug.
-To detect such bug, set :data:`asyncio.tasks._DEBUG` to ``True``. When the
-coroutine object is destroyed by the garbage collector, a log will be emitted
-with the traceback where the coroutine function was called. See the
-:ref:`asyncio logger <asyncio-logger>`.
+To detect such bug, set the environment variable :envvar:`PYTHONASYNCIODEBUG`
+to ``1``. When the coroutine object is destroyed by the garbage collector, a
+log will be emitted with the traceback where the coroutine function was called.
+See the :ref:`asyncio logger <asyncio-logger>`.
The debug flag changes the behaviour of the :func:`coroutine` decorator. The
debug flag value is only used when then coroutine function is defined, not when
diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst
--- a/Doc/library/asyncio-eventloop.rst
+++ b/Doc/library/asyncio-eventloop.rst
@@ -553,6 +553,22 @@
Set the default executor used by :meth:`run_in_executor`.
+Debug mode
+----------
+
+.. method:: BaseEventLoop.get_debug()
+
+ Get the debug mode (:class:`bool`) of the event loop.
+
+.. method:: BaseEventLoop.set_debug(enabled: bool)
+
+ Set the debug mode of the event loop.
+
+.. seealso::
+
+ The :ref:`Develop with asyncio <asyncio-dev>` section.
+
+
Server
------
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -614,6 +614,14 @@
.. versionadded:: 3.4
+.. envvar:: PYTHONASYNCIODEBUG
+
+ If this environment variable is set to a non-empty string, enable the debug
+ mode of the :mod:`asyncio` module.
+
+ .. versionadded:: 3.4
+
+
Debug-mode variables
~~~~~~~~~~~~~~~~~~~~
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
@@ -123,6 +123,7 @@
self._running = False
self._clock_resolution = time.get_clock_info('monotonic').resolution
self._exception_handler = None
+ self._debug = False
def _make_socket_transport(self, sock, protocol, waiter=None, *,
extra=None, server=None):
@@ -795,3 +796,9 @@
if not handle._cancelled:
handle._run()
handle = None # Needed to break cycles when an exception occurs.
+
+ def get_debug(self):
+ return self._debug
+
+ def set_debug(self, enabled):
+ self._debug = enabled
diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py
--- a/Lib/asyncio/events.py
+++ b/Lib/asyncio/events.py
@@ -345,6 +345,14 @@
def call_exception_handler(self, context):
raise NotImplementedError
+ # Debug flag management.
+
+ def get_debug(self):
+ raise NotImplementedError
+
+ def set_debug(self, enabled):
+ raise NotImplementedError
+
class AbstractEventLoopPolicy:
"""Abstract policy for accessing the event loop."""
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -12,6 +12,8 @@
import functools
import inspect
import linecache
+import os
+import sys
import traceback
import weakref
@@ -28,7 +30,8 @@
# before you define your coroutines. A downside of using this feature
# is that tracebacks show entries for the CoroWrapper.__next__ method
# when _DEBUG is true.
-_DEBUG = False
+_DEBUG = (not sys.flags.ignore_environment
+ and bool(os.environ.get('PYTHONASYNCIODEBUG')))
class CoroWrapper:
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
@@ -197,6 +197,12 @@
self.assertEqual([h2], self.loop._scheduled)
self.assertTrue(self.loop._process_events.called)
+ def test_set_debug(self):
+ self.loop.set_debug(True)
+ self.assertTrue(self.loop.get_debug())
+ self.loop.set_debug(False)
+ self.assertFalse(self.loop.get_debug())
+
@unittest.mock.patch('asyncio.base_events.time')
@unittest.mock.patch('asyncio.base_events.logger')
def test__run_once_logging(self, m_logger, m_time):
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
@@ -1,7 +1,9 @@
"""Tests for tasks.py."""
import gc
+import os.path
import unittest
+from test.script_helper import assert_python_ok
import asyncio
from asyncio import test_utils
@@ -1461,6 +1463,32 @@
cb.assert_called_once_with(fut)
self.assertEqual(fut.result(), [3, 1, exc, exc2])
+ def test_env_var_debug(self):
+ path = os.path.dirname(asyncio.__file__)
+ path = os.path.normpath(os.path.join(path, '..'))
+ code = '\n'.join((
+ 'import sys',
+ 'sys.path.insert(0, %r)' % path,
+ 'import asyncio.tasks',
+ 'print(asyncio.tasks._DEBUG)'))
+
+ # Test with -E to not fail if the unit test was run with
+ # PYTHONASYNCIODEBUG set to a non-empty string
+ sts, stdout, stderr = assert_python_ok('-E', '-c', code)
+ self.assertEqual(stdout.rstrip(), b'False')
+
+ sts, stdout, stderr = assert_python_ok('-c', code,
+ PYTHONASYNCIODEBUG='')
+ self.assertEqual(stdout.rstrip(), b'False')
+
+ sts, stdout, stderr = assert_python_ok('-c', code,
+ PYTHONASYNCIODEBUG='1')
+ self.assertEqual(stdout.rstrip(), b'True')
+
+ sts, stdout, stderr = assert_python_ok('-E', '-c', code,
+ PYTHONASYNCIODEBUG='1')
+ self.assertEqual(stdout.rstrip(), b'False')
+
class FutureGatherTests(GatherTestsBase, unittest.TestCase):
--
Repository URL: http://hg.python.org/cpython
More information about the Python-checkins
mailing list