[Python-checkins] bpo-32047: -X dev enables asyncio debug mode (#4418)

Victor Stinner webhook-mailer at python.org
Mon Nov 20 10:14:10 EST 2017


https://github.com/python/cpython/commit/44862df2eeec62adea20672b0fe2a5d3e160569e
commit: 44862df2eeec62adea20672b0fe2a5d3e160569e
branch: master
author: Victor Stinner <victor.stinner at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017-11-20T07:14:07-08:00
summary:

bpo-32047: -X dev enables asyncio debug mode (#4418)

The new -X dev command line option now also enables asyncio debug
mode.

files:
M Doc/library/asyncio-dev.rst
M Doc/using/cmdline.rst
M Lib/asyncio/base_events.py
M Lib/asyncio/coroutines.py
M Lib/test/test_asyncio/test_base_events.py
M Lib/test/test_asyncio/test_tasks.py

diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst
index 1838eb95a7d..b2ad87b5d02 100644
--- a/Doc/library/asyncio-dev.rst
+++ b/Doc/library/asyncio-dev.rst
@@ -21,7 +21,9 @@ enable *debug mode*.
 To enable all debug checks for an application:
 
 * Enable the asyncio debug mode globally by setting the environment variable
-  :envvar:`PYTHONASYNCIODEBUG` to ``1``, or by calling :meth:`AbstractEventLoop.set_debug`.
+  :envvar:`PYTHONASYNCIODEBUG` to ``1``, using ``-X dev`` command line option
+  (see the :option:`-X` option), or by calling
+  :meth:`AbstractEventLoop.set_debug`.
 * Set the log level of the :ref:`asyncio logger <asyncio-logger>` to
   :py:data:`logging.DEBUG`. For example, call
   ``logging.basicConfig(level=logging.DEBUG)`` at startup.
@@ -42,6 +44,11 @@ Examples debug checks:
 * :exc:`ResourceWarning` warnings are emitted when transports and event loops
   are :ref:`not closed explicitly <asyncio-close-transports>`.
 
+.. versionchanged:: 3.7
+
+   The new ``-X dev`` command line option can now also be used to enable
+   the debug mode.
+
 .. seealso::
 
    The :meth:`AbstractEventLoop.set_debug` method and the :ref:`asyncio logger
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index 01869d117f7..bf27c1e2b56 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -414,16 +414,18 @@ Miscellaneous options
      application.  Typical usage is ``python3 -X importtime -c 'import
      asyncio'``.  See also :envvar:`PYTHONPROFILEIMPORTTIME`.
    * ``-X dev`` enables the "developer mode": enable debug checks at runtime.
-     In short, ``python3 -X dev ...`` behaves as ``PYTHONMALLOC=debug python3
+     In short, ``python3 -X dev ...`` behaves as ``PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python3
      -W default -X faulthandler ...``, except that the :envvar:`PYTHONMALLOC`
-     environment variable is not set in practice. Developer mode:
+     and :envvar:`PYTHONASYNCIODEBUG` environment variables are not set in
+     practice. Developer mode:
 
      * Add ``default`` warnings option. For example, display
        :exc:`DeprecationWarning` and :exc:`ResourceWarning` warnings.
-     * Install debug hooks on memory allocators as if :envvar:`PYTHONMALLOC`
-       is set to ``debug``.
+     * Install debug hooks on memory allocators: see the
+       :c:func:`PyMem_SetupDebugHooks` C function.
      * Enable the :mod:`faulthandler` module to dump the Python traceback
        on a crash.
+     * Enable :ref:`asyncio debug mode <asyncio-debug-mode>`.
 
    It also allows passing arbitrary values and retrieving them through the
    :data:`sys._xoptions` dictionary.
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index b94856c9393..bb04aef76e8 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -244,8 +244,7 @@ def __init__(self):
         self._thread_id = None
         self._clock_resolution = time.get_clock_info('monotonic').resolution
         self._exception_handler = None
-        self.set_debug((not sys.flags.ignore_environment
-                        and bool(os.environ.get('PYTHONASYNCIODEBUG'))))
+        self.set_debug(coroutines._is_debug_mode())
         # In debug mode, if the execution of a callback or a step of a task
         # exceed this duration in seconds, the slow callback/task is logged.
         self.slow_callback_duration = 0.1
diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py
index 520a309f846..a87c9f9b0b6 100644
--- a/Lib/asyncio/coroutines.py
+++ b/Lib/asyncio/coroutines.py
@@ -19,17 +19,25 @@
 # Opcode of "yield from" instruction
 _YIELD_FROM = opcode.opmap['YIELD_FROM']
 
-# If you set _DEBUG to true, @coroutine will wrap the resulting
-# generator objects in a CoroWrapper instance (defined below).  That
-# instance will log a message when the generator is never iterated
-# over, which may happen when you forget to use "yield from" with a
-# coroutine call.  Note that the value of the _DEBUG flag is taken
-# when the decorator is used, so to be of any use it must be set
-# 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 = (not sys.flags.ignore_environment and
-          bool(os.environ.get('PYTHONASYNCIODEBUG')))
+
+def _is_debug_mode():
+    # If you set _DEBUG to true, @coroutine will wrap the resulting
+    # generator objects in a CoroWrapper instance (defined below).  That
+    # instance will log a message when the generator is never iterated
+    # over, which may happen when you forget to use "yield from" with a
+    # coroutine call.  Note that the value of the _DEBUG flag is taken
+    # when the decorator is used, so to be of any use it must be set
+    # 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 = (not sys.flags.ignore_environment and
+             bool(os.environ.get('PYTHONASYNCIODEBUG')))
+    if hasattr(sys, '_xoptions') and 'dev' in sys._xoptions:
+        debug = True
+    return debug
+
+
+_DEBUG = _is_debug_mode()
 
 
 try:
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
index a25069efb5c..98f2aef5627 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -822,6 +822,10 @@ def test_env_var_debug(self):
                                                PYTHONASYNCIODEBUG='1')
         self.assertEqual(stdout.rstrip(), b'False')
 
+        sts, stdout, stderr = assert_python_ok('-E', '-X', 'dev',
+                                               '-c', code)
+        self.assertEqual(stdout.rstrip(), b'True')
+
     def test_create_task(self):
         class MyTask(asyncio.Task):
             pass
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index 1d77f9f2c4d..f66f7f1e170 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -2350,6 +2350,10 @@ def test_env_var_debug(self):
                                                PYTHONPATH=aio_path)
         self.assertEqual(stdout.rstrip(), b'False')
 
+        sts, stdout, stderr = assert_python_ok('-E', '-X', 'dev',
+                                               '-c', code)
+        self.assertEqual(stdout.rstrip(), b'True')
+
 
 class FutureGatherTests(GatherTestsBase, test_utils.TestCase):
 



More information about the Python-checkins mailing list