mirror of https://github.com/django/django.git
Fixed #31675 -- Added warning to ExceptionReporter when exception chain has a cycle.
This commit is contained in:
parent
69a78a4a63
commit
a59de6e89e
|
@ -2,6 +2,7 @@ import functools
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -28,6 +29,10 @@ DEBUG_ENGINE = Engine(
|
||||||
CURRENT_DIR = Path(__file__).parent
|
CURRENT_DIR = Path(__file__).parent
|
||||||
|
|
||||||
|
|
||||||
|
class ExceptionCycleWarning(UserWarning):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CallableSettingWrapper:
|
class CallableSettingWrapper:
|
||||||
"""
|
"""
|
||||||
Object to wrap callable appearing in settings.
|
Object to wrap callable appearing in settings.
|
||||||
|
@ -401,6 +406,11 @@ class ExceptionReporter:
|
||||||
exceptions.append(exc_value)
|
exceptions.append(exc_value)
|
||||||
exc_value = explicit_or_implicit_cause(exc_value)
|
exc_value = explicit_or_implicit_cause(exc_value)
|
||||||
if exc_value in exceptions:
|
if exc_value in exceptions:
|
||||||
|
warnings.warn(
|
||||||
|
"Cycle in the exception chain detected: exception '%s' "
|
||||||
|
"encountered again." % exc_value,
|
||||||
|
ExceptionCycleWarning,
|
||||||
|
)
|
||||||
# Avoid infinite loop if there's a cyclic reference (#29393).
|
# Avoid infinite loop if there's a cyclic reference (#29393).
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ from django.utils.functional import SimpleLazyObject
|
||||||
from django.utils.regex_helper import _lazy_re_compile
|
from django.utils.regex_helper import _lazy_re_compile
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.views.debug import (
|
from django.views.debug import (
|
||||||
CallableSettingWrapper, ExceptionReporter, Path as DebugPath,
|
CallableSettingWrapper, ExceptionCycleWarning, ExceptionReporter,
|
||||||
SafeExceptionReporterFilter, default_urlconf,
|
Path as DebugPath, SafeExceptionReporterFilter, default_urlconf,
|
||||||
get_default_exception_reporter_filter, technical_404_response,
|
get_default_exception_reporter_filter, technical_404_response,
|
||||||
technical_500_response,
|
technical_500_response,
|
||||||
)
|
)
|
||||||
|
@ -518,7 +518,12 @@ class ExceptionReporterTests(SimpleTestCase):
|
||||||
|
|
||||||
tb_frames = None
|
tb_frames = None
|
||||||
tb_generator = threading.Thread(target=generate_traceback_frames, daemon=True)
|
tb_generator = threading.Thread(target=generate_traceback_frames, daemon=True)
|
||||||
tb_generator.start()
|
msg = (
|
||||||
|
"Cycle in the exception chain detected: exception 'inner' "
|
||||||
|
"encountered again."
|
||||||
|
)
|
||||||
|
with self.assertWarnsMessage(ExceptionCycleWarning, msg):
|
||||||
|
tb_generator.start()
|
||||||
tb_generator.join(timeout=5)
|
tb_generator.join(timeout=5)
|
||||||
if tb_generator.is_alive():
|
if tb_generator.is_alive():
|
||||||
# tb_generator is a daemon that runs until the main thread/process
|
# tb_generator is a daemon that runs until the main thread/process
|
||||||
|
|
Loading…
Reference in New Issue