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.
This commit is contained in:
Victor Stinner 2019-06-13 01:09:04 +02:00 committed by GitHub
parent 913fa1c824
commit 95f61c8b16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 1 deletions

View File

@ -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:

View File

@ -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

View File

@ -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):

View File

@ -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.