diff -r e48ec5f5b82b Doc/library/sys.rst --- a/Doc/library/sys.rst Mon Sep 28 15:04:11 2015 +0200 +++ b/Doc/library/sys.rst Mon Sep 28 15:08:21 2015 +0200 @@ -730,6 +730,17 @@ always available. value of :func:`intern` around to benefit from it. +.. function:: is_debug_build() + + Return :const:`True` if the Python executable was compiled in debug mode, + return :const:`False` if it was compiled in release mode. + + The debug mode is enabled with ``#define Py_DEBUG``, or with + ``./configure --with-pydebug``. + + .. versionadded:: 3.6 + + .. function:: is_finalizing() Return :const:`True` if the Python interpreter is diff -r e48ec5f5b82b Lib/distutils/command/build.py --- a/Lib/distutils/command/build.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/distutils/command/build.py Mon Sep 28 15:08:21 2015 +0200 @@ -86,7 +86,7 @@ class build(Command): # Make it so Python 2.x and Python 2.x with --with-pydebug don't # share the same build directories. Doing so confuses the build # process for C modules - if hasattr(sys, 'gettotalrefcount'): + if sys.is_debug_build(): plat_specifier += '-pydebug' # 'build_purelib' and 'build_platlib' just default to 'lib' and diff -r e48ec5f5b82b Lib/distutils/tests/test_build.py --- a/Lib/distutils/tests/test_build.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/distutils/tests/test_build.py Mon Sep 28 15:08:21 2015 +0200 @@ -28,7 +28,7 @@ class BuildTestCase(support.TempdirManag # examples: # build/lib.macosx-10.3-i386-2.7 plat_spec = '.%s-%s' % (cmd.plat_name, sys.version[0:3]) - if hasattr(sys, 'gettotalrefcount'): + if sys.is_debug_build(): self.assertTrue(cmd.build_platlib.endswith('-pydebug')) plat_spec += '-pydebug' wanted = os.path.join(cmd.build_base, 'lib' + plat_spec) diff -r e48ec5f5b82b Lib/sysconfig.py --- a/Lib/sysconfig.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/sysconfig.py Mon Sep 28 15:08:21 2015 +0200 @@ -382,7 +382,7 @@ def _generate_posix_vars(): sys.modules[name] = module pybuilddir = 'build/lib.%s-%s' % (get_platform(), sys.version[:3]) - if hasattr(sys, "gettotalrefcount"): + if sys.is_debug_build(): pybuilddir += '-pydebug' os.makedirs(pybuilddir, exist_ok=True) destfile = os.path.join(pybuilddir, name + '.py') diff -r e48ec5f5b82b Lib/test/libregrtest/refleak.py --- a/Lib/test/libregrtest/refleak.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/test/libregrtest/refleak.py Mon Sep 28 15:08:21 2015 +0200 @@ -16,7 +16,7 @@ def dash_R(the_module, test, indirect_te import copyreg import collections.abc - if not hasattr(sys, 'gettotalrefcount'): + if not sys.is_debug_build(): raise Exception("Tracking reference leaks requires a debug build " "of Python") diff -r e48ec5f5b82b Lib/test/support/__init__.py --- a/Lib/test/support/__init__.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/test/support/__init__.py Mon Sep 28 15:08:21 2015 +0200 @@ -1446,7 +1446,7 @@ def python_is_optimized(): _header = 'nP' _align = '0n' -if hasattr(sys, "gettotalrefcount"): +if sys.is_debug_build(): _header = '2P' + _header _align = '0P' _vheader = _header + 'n' diff -r e48ec5f5b82b Lib/test/test_capi.py --- a/Lib/test/test_capi.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/test/test_capi.py Mon Sep 28 15:08:21 2015 +0200 @@ -23,9 +23,6 @@ except ImportError: # Skip this test if the _testcapi module isn't available. _testcapi = support.import_module('_testcapi') -# Were we compiled --with-pydebug or with #define Py_DEBUG? -Py_DEBUG = hasattr(sys, 'gettotalrefcount') - def testfunction(self): """some doc""" @@ -179,7 +176,7 @@ class CAPITest(unittest.TestCase): def test_return_null_without_error(self): # Issue #23571: A function must not return NULL without setting an # error - if Py_DEBUG: + if sys.is_debug_build(): code = textwrap.dedent(""" import _testcapi from test import support @@ -206,7 +203,7 @@ class CAPITest(unittest.TestCase): def test_return_result_with_error(self): # Issue #23571: A function must not return a result with an error set - if Py_DEBUG: + if sys.is_debug_build(): code = textwrap.dedent(""" import _testcapi from test import support diff -r e48ec5f5b82b Lib/test/test_cmd_line.py --- a/Lib/test/test_cmd_line.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/test/test_cmd_line.py Mon Sep 28 15:08:21 2015 +0200 @@ -96,7 +96,7 @@ class CmdLineTest(unittest.TestCase): # "-X showrefcount" shows the refcount, but only in debug builds rc, out, err = run_python('-X', 'showrefcount', '-c', code) self.assertEqual(out.rstrip(), b"{'showrefcount': True}") - if hasattr(sys, 'gettotalrefcount'): # debug build + if sys.is_debug_build(): self.assertRegex(err, br'^\[\d+ refs, \d+ blocks\]') else: self.assertEqual(err, b'') diff -r e48ec5f5b82b Lib/test/test_hashlib.py --- a/Lib/test/test_hashlib.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/test/test_hashlib.py Mon Sep 28 15:08:21 2015 +0200 @@ -20,9 +20,6 @@ import warnings from test import support from test.support import _4G, bigmemtest, import_fresh_module -# Were we compiled --with-pydebug or with #define Py_DEBUG? -COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') - c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) @@ -41,7 +38,7 @@ class HashLibTestCase(unittest.TestCase) 'sha384', 'SHA384', 'sha512', 'SHA512') # Issue #14693: fallback modules are always compiled under POSIX - _warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG + _warn_on_extension_import = os.name == 'posix' or sys.is_debug_build() def _conditional_import_module(self, module_name): """Import a module and return a reference to it or None on failure.""" diff -r e48ec5f5b82b Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/test/test_marshal.py Mon Sep 28 15:08:21 2015 +0200 @@ -192,7 +192,7 @@ class BugsTestCase(unittest.TestCase): # Create a deeply nested structure. head = last = [] # The max stack depth should match the value in Python/marshal.c. - if os.name == 'nt' and hasattr(sys, 'gettotalrefcount'): + if os.name == 'nt' and sys.is_debug_build(): MAX_MARSHAL_STACK_DEPTH = 1000 else: MAX_MARSHAL_STACK_DEPTH = 2000 diff -r e48ec5f5b82b Lib/test/test_sys.py --- a/Lib/test/test_sys.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/test/test_sys.py Mon Sep 28 15:08:21 2015 +0200 @@ -766,6 +766,13 @@ class SysModuleTest(unittest.TestCase): rc, stdout, stderr = assert_python_ok('-c', code) self.assertEqual(stdout.rstrip(), b'True') + @test.support.cpython_only + def test_is_debug_build(self): + self.assertIsInstance(sys.is_debug_build(), bool) + self.assertEqual(sys.is_debug_build(), + # Py_DEBUG implies Py_TRACE_REFS + hasattr(sys, 'getobjects')) + @test.support.cpython_only class SizeofTest(unittest.TestCase): diff -r e48ec5f5b82b Lib/warnings.py --- a/Lib/warnings.py Mon Sep 28 15:04:11 2015 +0200 +++ b/Lib/warnings.py Mon Sep 28 15:08:21 2015 +0200 @@ -426,7 +426,7 @@ if not _warnings_defaults: bytes_action = "ignore" simplefilter(bytes_action, category=BytesWarning, append=1) # resource usage warnings are enabled by default in pydebug mode - if hasattr(sys, 'gettotalrefcount'): + if sys.is_debug_build(): resource_action = "always" else: resource_action = "ignore" diff -r e48ec5f5b82b Python/sysmodule.c --- a/Python/sysmodule.c Mon Sep 28 15:04:11 2015 +0200 +++ b/Python/sysmodule.c Mon Sep 28 15:08:21 2015 +0200 @@ -687,6 +687,24 @@ Return the wrapper for coroutine objects ); +static PyObject * +sys_is_debug_build(PyObject *self, PyObject *args) +{ +#ifdef Py_DEBUG + Py_RETURN_TRUE; +#else + Py_RETURN_FALSE; +#endif +} + +PyDoc_STRVAR(is_debug_build_doc, +"is_debug_build()\n\ +\n\ +Return True if the running Python executable was compiled in debug mode,\n\ +False if it was compiled in release mode." +); + + static PyTypeObject Hash_InfoType; PyDoc_STRVAR(hash_info_doc, @@ -1261,6 +1279,8 @@ static PyMethodDef sys_methods[] = { set_coroutine_wrapper_doc}, {"get_coroutine_wrapper", sys_get_coroutine_wrapper, METH_NOARGS, get_coroutine_wrapper_doc}, + {"is_debug_build", sys_is_debug_build, METH_NOARGS, + is_debug_build_doc}, {NULL, NULL} /* sentinel */ };