diff --git a/django/utils/repr.py b/django/utils/repr.py new file mode 100644 index 0000000000..5b0c467c4e --- /dev/null +++ b/django/utils/repr.py @@ -0,0 +1,13 @@ +import reprlib + + +class DjangoRepr(reprlib.Repr): + + def config(self, limit): + """Sets maximum print length for all data structures using the given value""" + for attr in dir(self): + if attr.startswith("max") and attr != "maxlevel": + setattr(self, attr, limit) + + def repr_str(self, x, level): + return x[: self.maxstring] diff --git a/django/views/debug.py b/django/views/debug.py index 696fcf04db..80e162aa2c 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -2,7 +2,6 @@ import functools import inspect import itertools import re -import reprlib import sys import types import warnings @@ -18,6 +17,7 @@ from django.utils.datastructures import MultiValueDict from django.utils.encoding import force_str from django.utils.module_loading import import_string from django.utils.regex_helper import _lazy_re_compile +from django.utils.repr import DjangoRepr from django.utils.version import PY311, get_docs_version from django.views.decorators.debug import coroutine_functions_to_sensitive_variables @@ -311,16 +311,8 @@ class SafeExceptionReporterFilter: class ExceptionReporter: """Organize and coordinate reporting on exceptions.""" - repr_instance = reprlib.Repr() - repr_instance.indent = 2 - repr_instance.maxdeque = 4096 - repr_instance.maxstring = 4096 - repr_instance.maxlist = 4096 - repr_instance.maxset = 4096 - repr_instance.maxdict = 4096 - repr_instance.maxfrozenset = 4096 - repr_instance.maxarray = 4096 - repr_instance.maxother = 4096 + repr_instance = DjangoRepr() + PRINT_LIMIT = 4096 @property def html_template_path(self): @@ -342,6 +334,8 @@ class ExceptionReporter: self.template_does_not_exist = False self.postmortem = None + self.repr_instance.config(limit=ExceptionReporter.PRINT_LIMIT) + def _get_raw_insecure_uri(self): """ Return an absolute URI from variables available in this request. Skip @@ -364,9 +358,22 @@ class ExceptionReporter: if "vars" in frame: frame_vars = [] for k, v in frame["vars"]: - if isinstance(v, Sized) and len(v) > 4096: - self.repr_instance.fillvalue = "...%d more" % (len(v) - 4096) - v = self.repr_instance.repr(v) + try: + # Check if there are any exceptions in __repr__ fn of the object + v = repr(v) + + trim_msg = "" + + if isinstance(v, Sized) and len(v) > 4096: + diff = len(v) - 4096 + trim_msg = "..." % diff + + v = self.repr_instance.repr(v) + v += trim_msg + + except Exception as e: + v = "Error in formatting: %s: %s" % (e.__class__.__name__, e) + print(v) frame_vars.append((k, v)) frame["vars"] = frame_vars frames[i] = frame diff --git a/tests/view_tests/tests/test_debug.py b/tests/view_tests/tests/test_debug.py index 45a0dc70ee..e0e0eafe4e 100644 --- a/tests/view_tests/tests/test_debug.py +++ b/tests/view_tests/tests/test_debug.py @@ -1036,15 +1036,20 @@ class ExceptionReporterTests(SimpleTestCase): def test_local_variable_escaping(self): """Safe strings in local variables are escaped.""" + # <p>Local variable</p>\ + # '<p>Local variable</p>' try: local = mark_safe("

Local variable

") + print("safe string:", repr(local)) raise ValueError(local) except Exception: exc_type, exc_value, tb = sys.exc_info() + html = ExceptionReporter(None, exc_type, exc_value, tb).get_traceback_html() self.assertIn( - '
'<p>Local variable</p>'
' - "", + #
<p>Local variable</p>
+ #
<p>Local variable</p>
+ '
'<p>Local variable</p>'
', html, ) @@ -1066,7 +1071,7 @@ class ExceptionReporterTests(SimpleTestCase): def test_too_large_values_handling(self): "Large values should not create a large HTML." - large = 256 * 1024 + large = 5000 repr_of_str_adds = len(repr("")) try: @@ -1081,9 +1086,10 @@ class ExceptionReporterTests(SimpleTestCase): reporter = ExceptionReporter(None, exc_type, exc_value, tb) html = reporter.get_traceback_html() self.assertEqual(len(html) // 1024 // 128, 0) # still fit in 128Kb - self.assertIn( - "<trimmed %d bytes string>" % (large + repr_of_str_adds,), html + msg = "<trimmed %d bytes string>" % ( + large - ExceptionReporter.PRINT_LIMIT + repr_of_str_adds, ) + self.assertIn(msg, html) def test_encoding_error(self): """