summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2019-06-12 23:09:04 (GMT)
committerGitHub <noreply@github.com>2019-06-12 23:09:04 (GMT)
commit95f61c8b1619e736bd5e29a0da0183234634b6e8 (patch)
tree6d70a71d5e9538ab70d9039eabf64315409e939d
parent913fa1c8245d1cde6edb4254f4fb965cc91786ef (diff)
downloadcpython-95f61c8b1619e736bd5e29a0da0183234634b6e8.zip
cpython-95f61c8b1619e736bd5e29a0da0183234634b6e8.tar.gz
cpython-95f61c8b1619e736bd5e29a0da0183234634b6e8.tar.bz2
bpo-37069: regrtest uses sys.unraisablehook (GH-13759)
regrtest now uses sys.unraisablehook() to mark a test as "environment altered" (ENV_CHANGED) if it emits an "unraisable exception". Moreover, regrtest logs a warning in this case. Use "python3 -m test --fail-env-changed" to catch unraisable exceptions in tests.
-rw-r--r--Lib/test/libregrtest/setup.py4
-rw-r--r--Lib/test/libregrtest/utils.py17
-rw-r--r--Lib/test/test_regrtest.py30
-rw-r--r--Misc/NEWS.d/next/Tests/2019-06-13-00-46-25.bpo-37069.wdktFo.rst7
4 files changed, 57 insertions, 1 deletions
diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py
index fb5ac35..36676bf 100644
--- a/Lib/test/libregrtest/setup.py
+++ b/Lib/test/libregrtest/setup.py
@@ -10,6 +10,8 @@ try:
except ImportError:
gc = None
+from test.libregrtest.utils import setup_unraisable_hook
+
def setup_tests(ns):
try:
@@ -93,6 +95,8 @@ def setup_tests(ns):
pass
sys.addaudithook(_test_audit_hook)
+ setup_unraisable_hook()
+
def suppress_msvcrt_asserts(verbose):
try:
diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py
index fb9971a..2691a2c 100644
--- a/Lib/test/libregrtest/utils.py
+++ b/Lib/test/libregrtest/utils.py
@@ -2,6 +2,7 @@ import math
import os.path
import sys
import textwrap
+from test import support
def format_duration(seconds):
@@ -59,3 +60,19 @@ def printlist(x, width=70, indent=4, file=None):
def print_warning(msg):
print(f"Warning -- {msg}", file=sys.stderr, flush=True)
+
+
+orig_unraisablehook = None
+
+
+def regrtest_unraisable_hook(unraisable):
+ global orig_unraisablehook
+ support.environment_altered = True
+ print_warning("Unraisable exception")
+ orig_unraisablehook(unraisable)
+
+
+def setup_unraisable_hook():
+ global orig_unraisablehook
+ orig_unraisablehook = sys.unraisablehook
+ sys.unraisablehook = regrtest_unraisable_hook
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index b616e89..904b326 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -499,7 +499,7 @@ class BaseTestCase(unittest.TestCase):
if not input:
input = ''
if 'stderr' not in kw:
- kw['stderr'] = subprocess.PIPE
+ kw['stderr'] = subprocess.STDOUT
proc = subprocess.run(args,
universal_newlines=True,
input=input,
@@ -1124,6 +1124,34 @@ class ArgsTestCase(BaseTestCase):
env_changed=[testname],
fail_env_changed=True)
+ def test_unraisable_exc(self):
+ # --fail-env-changed must catch unraisable exception
+ code = textwrap.dedent(r"""
+ import unittest
+ import weakref
+
+ class MyObject:
+ pass
+
+ def weakref_callback(obj):
+ raise Exception("weakref callback bug")
+
+ class Tests(unittest.TestCase):
+ def test_unraisable_exc(self):
+ obj = MyObject()
+ ref = weakref.ref(obj, weakref_callback)
+ # call weakref_callback() which logs
+ # an unraisable exception
+ obj = None
+ """)
+ testname = self.create_test(code=code)
+
+ output = self.run_tests("--fail-env-changed", "-v", testname, exitcode=3)
+ self.check_executed_tests(output, [testname],
+ env_changed=[testname],
+ fail_env_changed=True)
+ self.assertIn("Warning -- Unraisable exception", output)
+
class TestUtils(unittest.TestCase):
def test_format_duration(self):
diff --git a/Misc/NEWS.d/next/Tests/2019-06-13-00-46-25.bpo-37069.wdktFo.rst b/Misc/NEWS.d/next/Tests/2019-06-13-00-46-25.bpo-37069.wdktFo.rst
new file mode 100644
index 0000000..f9f6474
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2019-06-13-00-46-25.bpo-37069.wdktFo.rst
@@ -0,0 +1,7 @@
+regrtest now uses :func:`sys.unraisablehook` to mark a test as "environment
+altered" (ENV_CHANGED) if it emits an "unraisable exception". Moreover,
+regrtest logs a warning in this case.
+
+Use ``python3 -m test --fail-env-changed`` to catch unraisable exceptions in
+tests.
+