◐ Shell
reader mode source ↗
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
File filter
Conversations
Jump to
Diff view
Apply and reload
Show whitespace
Diff view
Apply and reload
12 changes: 6 additions & 6 deletions Doc/using/cmdline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,13 @@ 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 PYTHONASYNCIODEBUG=1 python3
-W default -X faulthandler ...``, except that the :envvar:`PYTHONMALLOC`
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: see the
:c:func:`PyMem_SetupDebugHooks` C function.
* Enable the :mod:`faulthandler` module to dump the Python traceback
Expand Down
4 changes: 3 additions & 1 deletion Include/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ typedef struct {
int faulthandler;
int tracemalloc; /* Number of saved frames, 0=don't trace */
int importtime; /* -X importtime */
} _PyCoreConfig;

#define _PyCoreConfig_INIT \
Expand All @@ -43,7 +44,8 @@ typedef struct {
.allocator = NULL, \
.faulthandler = 0, \
.tracemalloc = 0, \
.importtime = 0}

/* Placeholders while working on the new configuration API
*
Expand Down
8 changes: 2 additions & 6 deletions Lib/subprocess.py
Original file line number Diff line number Diff line change
@@ -262,15 +262,11 @@ def _args_from_interpreter_flags():
args.append('-' + opt * v)

# -W options
warnoptions = sys.warnoptions
xoptions = getattr(sys, '_xoptions', {})
if 'dev' in xoptions and warnoptions and warnoptions[-1] == 'default':
# special case: -X dev adds 'default' to sys.warnoptions
warnoptions = warnoptions[:-1]
for opt in warnoptions:
args.append('-W' + opt)

# -X options
if 'dev' in xoptions:
args.extend(('-X', 'dev'))
for opt in ('faulthandler', 'tracemalloc', 'importtime',
Expand Down
52 changes: 46 additions & 6 deletions Lib/test/test_cmd_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,14 +507,14 @@ def test_sys_flags_set(self):
with self.subTest(envar_value=value):
assert_python_ok('-c', code, **env_vars)

def run_xdev(self, code, check_exitcode=True):
env = dict(os.environ)
env.pop('PYTHONWARNINGS', 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', '-c', code)
proc = subprocess.run(args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
Expand All @@ -525,8 +525,34 @@ def run_xdev(self, code, check_exitcode=True):
return proc.stdout.rstrip()

def test_xdev(self):
out = self.run_xdev("import sys; print(sys.warnoptions)")
self.assertEqual(out, "['default']")

try:
import _testcapi
@@ -535,7 +561,7 @@ def test_xdev(self):
else:
code = "import _testcapi; _testcapi.pymem_api_misuse()"
with support.SuppressCrashReport():
out = self.run_xdev(code, check_exitcode=False)
self.assertIn("Debug memory block at address p=", out)

try:
@@ -544,9 +570,23 @@ def test_xdev(self):
pass
else:
code = "import faulthandler; print(faulthandler.is_enabled())"
out = self.run_xdev(code)
self.assertEqual(out, "True")

class IgnoreEnvironmentTest(unittest.TestCase):

def run_ignoring_vars(self, predicate, **env_vars):
Expand Down
14 changes: 11 additions & 3 deletions Lib/warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,6 @@ def __exit__(self, *exc_info):
# - a compiled regex that must match the module that is being warned
# - a line number for the line being warning, or 0 to mean any line
# If either if the compiled regexs are None, match anything.
_warnings_defaults = False
try:
from _warnings import (filters, _defaultaction, _onceregistry,
warn, warn_explicit, _filters_mutated)
Expand All @@ -504,12 +503,16 @@ def _filters_mutated():
global _filters_version
_filters_version += 1


# Module initialization
_processoptions(sys.warnoptions)
if not _warnings_defaults:
py_debug = hasattr(sys, 'gettotalrefcount')
if not py_debug:
silence = [ImportWarning, PendingDeprecationWarning]
silence.append(DeprecationWarning)
for cls in silence:
Expand All @@ -525,10 +528,15 @@ def _filters_mutated():
simplefilter(bytes_action, category=BytesWarning, append=1)

# resource usage warnings are enabled by default in pydebug mode
if py_debug:
resource_action = "always"
else:
resource_action = "ignore"
simplefilter(resource_action, category=ResourceWarning, append=1)

del _warnings_defaults
9 changes: 2 additions & 7 deletions Modules/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1397,14 +1397,9 @@ pymain_parse_envvars(_PyMain *pymain)
return -1;
}
if (pymain_get_xoption(pymain, L"dev")) {
/* "python3 -X dev ..." behaves
as "PYTHONMALLOC=debug python3 -Wd -X faulthandler ..." */
core_config->allocator = "debug";
if (pymain_optlist_append(pymain, &pymain->cmdline.warning_options,
L"default") < 0) {
return -1;
}
core_config->faulthandler = 1;
}
return 0;
}
Expand Down
37 changes: 27 additions & 10 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -1196,11 +1196,19 @@ create_filter(PyObject *category, const char *action)
static PyObject *
init_filters(void)
{
#ifndef Py_DEBUG
PyObject *filters = PyList_New(5);
#else
PyObject *filters = PyList_New(2);
#endif
unsigned int pos = 0; /* Post-incremented in each use. */
unsigned int x;
const char *bytes_action, *resource_action;
Expand All @@ -1209,12 +1217,14 @@ init_filters(void)
return NULL;

#ifndef Py_DEBUG
PyList_SET_ITEM(filters, pos++,
create_filter(PyExc_DeprecationWarning, "ignore"));
PyList_SET_ITEM(filters, pos++,
create_filter(PyExc_PendingDeprecationWarning, "ignore"));
PyList_SET_ITEM(filters, pos++,
create_filter(PyExc_ImportWarning, "ignore"));
#endif

if (Py_BytesWarningFlag > 1)
@@ -1225,14 +1235,21 @@ init_filters(void)
bytes_action = "ignore";
PyList_SET_ITEM(filters, pos++, create_filter(PyExc_BytesWarning,
bytes_action));
/* resource usage warnings are enabled by default in pydebug mode */
#ifdef Py_DEBUG
resource_action = "always";
#else
resource_action = "ignore";
#endif
PyList_SET_ITEM(filters, pos++, create_filter(PyExc_ResourceWarning,
resource_action));
for (x = 0; x < pos; x += 1) {
if (PyList_GET_ITEM(filters, x) == NULL) {
Py_DECREF(filters);
Expand Down
Toggle all file notes Toggle all file annotations