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.
This commit is contained in:
parent
706e10b186
commit
5e3806f8cf
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -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
|
||||
----
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Add :attr:`sys.flags.dev_mode` flag
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue