summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-11-30 10:40:24 (GMT)
committerGitHub <noreply@github.com>2017-11-30 10:40:24 (GMT)
commit5e3806f8cfd84722fc55d4299dc018ad9b0f8401 (patch)
tree436f0a963001f590a1193dba5c84627ba59513c2
parent706e10b186992e086e661a62d2c8ec9588525b31 (diff)
downloadcpython-5e3806f8cfd84722fc55d4299dc018ad9b0f8401.zip
cpython-5e3806f8cfd84722fc55d4299dc018ad9b0f8401.tar.gz
cpython-5e3806f8cfd84722fc55d4299dc018ad9b0f8401.tar.bz2
bpo-32101: Add PYTHONDEVMODE environment variable (#4624)
* bpo-32101: Add sys.flags.dev_mode flag Rename also the "Developer mode" to the "Development mode". * bpo-32101: Add PYTHONDEVMODE environment variable Mention it in the development chapiter.
-rw-r--r--Doc/library/development.rst3
-rw-r--r--Doc/library/sys.rst4
-rw-r--r--Doc/using/cmdline.rst12
-rw-r--r--Doc/whatsnew/3.7.rst11
-rw-r--r--Lib/asyncio/coroutines.py8
-rw-r--r--Lib/test/test_cmd_line.py37
-rw-r--r--Lib/test/test_sys.py6
-rw-r--r--Misc/NEWS.d/next/Library/2017-11-29-00-42-47.bpo-321010.-axD5l.rst1
-rw-r--r--Modules/main.c7
-rw-r--r--Python/sysmodule.c5
10 files changed, 78 insertions, 16 deletions
diff --git a/Doc/library/development.rst b/Doc/library/development.rst
index d2b5fa2..ab34e1f 100644
--- a/Doc/library/development.rst
+++ b/Doc/library/development.rst
@@ -24,3 +24,6 @@ The list of modules described in this chapter is:
unittest.mock-examples.rst
2to3.rst
test.rst
+
+See also the Python development mode: the :option:`-X` ``dev`` option and
+:envvar:`PYTHONDEVMODE` environment variable.
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index faf540c..9e47681 100644
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -334,6 +334,7 @@ always available.
:const:`bytes_warning` :option:`-b`
:const:`quiet` :option:`-q`
:const:`hash_randomization` :option:`-R`
+ :const:`dev_mode` :option:`-X` ``dev``
============================= =============================
.. versionchanged:: 3.2
@@ -345,6 +346,9 @@ always available.
.. versionchanged:: 3.3
Removed obsolete ``division_warning`` attribute.
+ .. versionchanged:: 3.7
+ Added ``dev_mode`` attribute for the new :option:`-X` ``dev`` flag.
+
.. data:: float_info
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index e6189fd..d110ae3 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -411,7 +411,7 @@ Miscellaneous options
nested imports). Note that its output may be broken in multi-threaded
application. Typical usage is ``python3 -X importtime -c 'import
asyncio'``. See also :envvar:`PYTHONPROFILEIMPORTTIME`.
- * ``-X dev``: enable CPython's "developer mode", introducing additional
+ * ``-X dev``: enable CPython's "development mode", introducing additional
runtime checks which are too expensive to be enabled by default. It should
not be more verbose than the default if the code is correct: new warnings
are only emitted when an issue is detected. Effect of the developer mode:
@@ -426,6 +426,8 @@ Miscellaneous options
* Enable the :mod:`faulthandler` module to dump the Python traceback
on a crash.
* Enable :ref:`asyncio debug mode <asyncio-debug-mode>`.
+ * Set the :attr:`~sys.flags.dev_mode` attribute of :attr:`sys.flags` to
+ ``True``
It also allows passing arbitrary values and retrieving them through the
:data:`sys._xoptions` dictionary.
@@ -796,6 +798,14 @@ conflict.
.. versionadded:: 3.7
See :pep:`538` for more details.
+
+.. envvar:: PYTHONDEVMODE
+
+ If this environment variable is set to a non-empty string, enable the
+ CPython "development mode". See the :option:`-X` ``dev`` option.
+
+ .. versionadded:: 3.7
+
Debug-mode variables
~~~~~~~~~~~~~~~~~~~~
diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst
index 5c00159..6545a18 100644
--- a/Doc/whatsnew/3.7.rst
+++ b/Doc/whatsnew/3.7.rst
@@ -185,10 +185,10 @@ resolution on Linux and Windows.
PEP written and implemented by Victor Stinner
-New Developer Mode: -X dev
---------------------------
+New Development Mode: -X dev
+----------------------------
-Add a new "developer mode": ``-X dev`` command line option to enable debug
+Add a new "development mode": ``-X dev`` command line option to enable debug
checks at runtime.
In short, ``python3 -X dev ...`` behaves as ``PYTHONMALLOC=debug python3 -W
@@ -371,6 +371,11 @@ string
expression pattern for braced placeholders and non-braced placeholders
separately. (Contributed by Barry Warsaw in :issue:`1198569`.)
+sys
+---
+
+Added :attr:`sys.flags.dev_mode` flag for the new development mode.
+
time
----
diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py
index b6f81a4..7d2ca05 100644
--- a/Lib/asyncio/coroutines.py
+++ b/Lib/asyncio/coroutines.py
@@ -27,11 +27,9 @@ def _is_debug_mode():
# 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
+ return (sys.flags.dev_mode
+ or (not sys.flags.ignore_environment
+ and bool(os.environ.get('PYTHONASYNCIODEBUG'))))
_DEBUG = _is_debug_mode()
diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py
index 96405e7..383302b 100644
--- a/Lib/test/test_cmd_line.py
+++ b/Lib/test/test_cmd_line.py
@@ -508,14 +508,18 @@ class CmdLineTest(unittest.TestCase):
with self.subTest(envar_value=value):
assert_python_ok('-c', code, **env_vars)
- def run_xdev(self, *args, check_exitcode=True):
+ def run_xdev(self, *args, check_exitcode=True, xdev=True):
env = dict(os.environ)
env.pop('PYTHONWARNINGS', None)
+ env.pop('PYTHONDEVMODE', None)
# Force malloc() to disable the debug hooks which are enabled
# by default for Python compiled in debug mode
env['PYTHONMALLOC'] = 'malloc'
- args = (sys.executable, '-X', 'dev', *args)
+ if xdev:
+ args = (sys.executable, '-X', 'dev', *args)
+ else:
+ args = (sys.executable, *args)
proc = subprocess.run(args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
@@ -526,6 +530,14 @@ class CmdLineTest(unittest.TestCase):
return proc.stdout.rstrip()
def test_xdev(self):
+ # sys.flags.dev_mode
+ code = "import sys; print(sys.flags.dev_mode)"
+ out = self.run_xdev("-c", code, xdev=False)
+ self.assertEqual(out, "False")
+ out = self.run_xdev("-c", code)
+ self.assertEqual(out, "True")
+
+ # Warnings
code = ("import sys, warnings; "
"print(' '.join('%s::%s' % (f[0], f[2].__name__) "
"for f in warnings.filters))")
@@ -555,6 +567,7 @@ class CmdLineTest(unittest.TestCase):
"default::ResourceWarning "
"default::Warning")
+ # Memory allocator debug hooks
try:
import _testcapi
except ImportError:
@@ -569,6 +582,7 @@ class CmdLineTest(unittest.TestCase):
alloc_name = "malloc_debug"
self.assertEqual(out, alloc_name)
+ # Faulthandler
try:
import faulthandler
except ImportError:
@@ -581,6 +595,7 @@ class CmdLineTest(unittest.TestCase):
def check_pythonmalloc(self, env_var, name):
code = 'import _testcapi; print(_testcapi.pymem_getallocatorsname())'
env = dict(os.environ)
+ env.pop('PYTHONDEVMODE', None)
if env_var is not None:
env['PYTHONMALLOC'] = env_var
else:
@@ -621,6 +636,24 @@ class CmdLineTest(unittest.TestCase):
with self.subTest(env_var=env_var, name=name):
self.check_pythonmalloc(env_var, name)
+ def test_pythondevmode_env(self):
+ # Test the PYTHONDEVMODE environment variable
+ code = "import sys; print(sys.flags.dev_mode)"
+ env = dict(os.environ)
+ env.pop('PYTHONDEVMODE', None)
+ args = (sys.executable, '-c', code)
+
+ proc = subprocess.run(args, stdout=subprocess.PIPE,
+ universal_newlines=True, env=env)
+ self.assertEqual(proc.stdout.rstrip(), 'False')
+ self.assertEqual(proc.returncode, 0, proc)
+
+ env['PYTHONDEVMODE'] = '1'
+ proc = subprocess.run(args, stdout=subprocess.PIPE,
+ universal_newlines=True, env=env)
+ self.assertEqual(proc.stdout.rstrip(), 'True')
+ self.assertEqual(proc.returncode, 0, proc)
+
class IgnoreEnvironmentTest(unittest.TestCase):
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 4b8fcb9..6346094 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -526,10 +526,12 @@ class SysModuleTest(unittest.TestCase):
attrs = ("debug",
"inspect", "interactive", "optimize", "dont_write_bytecode",
"no_user_site", "no_site", "ignore_environment", "verbose",
- "bytes_warning", "quiet", "hash_randomization", "isolated")
+ "bytes_warning", "quiet", "hash_randomization", "isolated",
+ "dev_mode")
for attr in attrs:
self.assertTrue(hasattr(sys.flags, attr), attr)
- self.assertEqual(type(getattr(sys.flags, attr)), int, attr)
+ attr_type = bool if attr == "dev_mode" else int
+ self.assertEqual(type(getattr(sys.flags, attr)), attr_type, attr)
self.assertTrue(repr(sys.flags))
self.assertEqual(len(sys.flags), len(attrs))
diff --git a/Misc/NEWS.d/next/Library/2017-11-29-00-42-47.bpo-321010.-axD5l.rst b/Misc/NEWS.d/next/Library/2017-11-29-00-42-47.bpo-321010.-axD5l.rst
new file mode 100644
index 0000000..715a269
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-11-29-00-42-47.bpo-321010.-axD5l.rst
@@ -0,0 +1 @@
+Add :attr:`sys.flags.dev_mode` flag
diff --git a/Modules/main.c b/Modules/main.c
index ec33b5f..e9d524a 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -124,7 +124,8 @@ static const char usage_6[] =
" hooks.\n"
"PYTHONCOERCECLOCALE: if this variable is set to 0, it disables the locale\n"
" coercion behavior. Use PYTHONCOERCECLOCALE=warn to request display of\n"
-" locale coercion and locale compatibility warnings on stderr.\n";
+" locale coercion and locale compatibility warnings on stderr.\n"
+"PYTHONDEVMODE: enable the development mode.\n";
static void
pymain_usage(int error, const wchar_t* program)
@@ -1520,7 +1521,9 @@ pymain_parse_envvars(_PyMain *pymain)
if (pymain_init_tracemalloc(pymain) < 0) {
return -1;
}
- if (pymain_get_xoption(pymain, L"dev")) {
+ if (pymain_get_xoption(pymain, L"dev" ) ||
+ pymain_get_env_var("PYTHONDEVMODE"))
+ {
core_config->dev_mode = 1;
core_config->faulthandler = 1;
core_config->allocator = "debug";
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index d786739..64bc14e 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -1814,6 +1814,7 @@ static PyStructSequence_Field flags_fields[] = {
{"quiet", "-q"},
{"hash_randomization", "-R"},
{"isolated", "-I"},
+ {"dev_mode", "-X dev"},
{0}
};
@@ -1821,7 +1822,7 @@ static PyStructSequence_Desc flags_desc = {
"sys.flags", /* name */
flags__doc__, /* doc */
flags_fields, /* fields */
- 13
+ 14
};
static PyObject*
@@ -1829,6 +1830,7 @@ make_flags(void)
{
int pos = 0;
PyObject *seq;
+ _PyCoreConfig *core_config = &_PyGILState_GetInterpreterStateUnsafe()->core_config;
seq = PyStructSequence_New(&FlagsType);
if (seq == NULL)
@@ -1853,6 +1855,7 @@ make_flags(void)
SetFlag(Py_HashRandomizationFlag);
SetFlag(Py_IsolatedFlag);
#undef SetFlag
+ PyStructSequence_SET_ITEM(seq, pos++, PyBool_FromLong(core_config->dev_mode));
if (PyErr_Occurred()) {
Py_DECREF(seq);