Commit 44862df2 authored by Victor Stinner's avatar Victor Stinner Committed by GitHub

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

The new -X dev command line option now also enables asyncio debug
mode.
parent 04dee272
...@@ -21,7 +21,9 @@ enable *debug mode*. ...@@ -21,7 +21,9 @@ enable *debug mode*.
To enable all debug checks for an application: To enable all debug checks for an application:
* Enable the asyncio debug mode globally by setting the environment variable * 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 * Set the log level of the :ref:`asyncio logger <asyncio-logger>` to
:py:data:`logging.DEBUG`. For example, call :py:data:`logging.DEBUG`. For example, call
``logging.basicConfig(level=logging.DEBUG)`` at startup. ``logging.basicConfig(level=logging.DEBUG)`` at startup.
...@@ -42,6 +44,11 @@ Examples debug checks: ...@@ -42,6 +44,11 @@ Examples debug checks:
* :exc:`ResourceWarning` warnings are emitted when transports and event loops * :exc:`ResourceWarning` warnings are emitted when transports and event loops
are :ref:`not closed explicitly <asyncio-close-transports>`. 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:: .. seealso::
The :meth:`AbstractEventLoop.set_debug` method and the :ref:`asyncio logger The :meth:`AbstractEventLoop.set_debug` method and the :ref:`asyncio logger
......
...@@ -414,16 +414,18 @@ Miscellaneous options ...@@ -414,16 +414,18 @@ Miscellaneous options
application. Typical usage is ``python3 -X importtime -c 'import application. Typical usage is ``python3 -X importtime -c 'import
asyncio'``. See also :envvar:`PYTHONPROFILEIMPORTTIME`. asyncio'``. See also :envvar:`PYTHONPROFILEIMPORTTIME`.
* ``-X dev`` enables the "developer mode": enable debug checks at runtime. * ``-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` -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 * Add ``default`` warnings option. For example, display
:exc:`DeprecationWarning` and :exc:`ResourceWarning` warnings. :exc:`DeprecationWarning` and :exc:`ResourceWarning` warnings.
* Install debug hooks on memory allocators as if :envvar:`PYTHONMALLOC` * Install debug hooks on memory allocators: see the
is set to ``debug``. :c:func:`PyMem_SetupDebugHooks` C function.
* Enable the :mod:`faulthandler` module to dump the Python traceback * Enable the :mod:`faulthandler` module to dump the Python traceback
on a crash. on a crash.
* Enable :ref:`asyncio debug mode <asyncio-debug-mode>`.
It also allows passing arbitrary values and retrieving them through the It also allows passing arbitrary values and retrieving them through the
:data:`sys._xoptions` dictionary. :data:`sys._xoptions` dictionary.
......
...@@ -244,8 +244,7 @@ class BaseEventLoop(events.AbstractEventLoop): ...@@ -244,8 +244,7 @@ class BaseEventLoop(events.AbstractEventLoop):
self._thread_id = None self._thread_id = None
self._clock_resolution = time.get_clock_info('monotonic').resolution self._clock_resolution = time.get_clock_info('monotonic').resolution
self._exception_handler = None self._exception_handler = None
self.set_debug((not sys.flags.ignore_environment self.set_debug(coroutines._is_debug_mode())
and bool(os.environ.get('PYTHONASYNCIODEBUG'))))
# In debug mode, if the execution of a callback or a step of a task # 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. # exceed this duration in seconds, the slow callback/task is logged.
self.slow_callback_duration = 0.1 self.slow_callback_duration = 0.1
......
...@@ -19,17 +19,25 @@ from .log import logger ...@@ -19,17 +19,25 @@ from .log import logger
# Opcode of "yield from" instruction # Opcode of "yield from" instruction
_YIELD_FROM = opcode.opmap['YIELD_FROM'] _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 def _is_debug_mode():
# instance will log a message when the generator is never iterated # If you set _DEBUG to true, @coroutine will wrap the resulting
# over, which may happen when you forget to use "yield from" with a # generator objects in a CoroWrapper instance (defined below). That
# coroutine call. Note that the value of the _DEBUG flag is taken # instance will log a message when the generator is never iterated
# when the decorator is used, so to be of any use it must be set # over, which may happen when you forget to use "yield from" with a
# before you define your coroutines. A downside of using this feature # coroutine call. Note that the value of the _DEBUG flag is taken
# is that tracebacks show entries for the CoroWrapper.__next__ method # when the decorator is used, so to be of any use it must be set
# when _DEBUG is true. # before you define your coroutines. A downside of using this feature
_DEBUG = (not sys.flags.ignore_environment and # is that tracebacks show entries for the CoroWrapper.__next__ method
bool(os.environ.get('PYTHONASYNCIODEBUG'))) # 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: try:
......
...@@ -822,6 +822,10 @@ class BaseEventLoopTests(test_utils.TestCase): ...@@ -822,6 +822,10 @@ class BaseEventLoopTests(test_utils.TestCase):
PYTHONASYNCIODEBUG='1') PYTHONASYNCIODEBUG='1')
self.assertEqual(stdout.rstrip(), b'False') 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): def test_create_task(self):
class MyTask(asyncio.Task): class MyTask(asyncio.Task):
pass pass
......
...@@ -2350,6 +2350,10 @@ class GatherTestsBase: ...@@ -2350,6 +2350,10 @@ class GatherTestsBase:
PYTHONPATH=aio_path) PYTHONPATH=aio_path)
self.assertEqual(stdout.rstrip(), b'False') 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): class FutureGatherTests(GatherTestsBase, test_utils.TestCase):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment