summaryrefslogtreecommitdiff
path: root/django/views/debug.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/views/debug.py')
-rw-r--r--django/views/debug.py296
1 files changed, 167 insertions, 129 deletions
diff --git a/django/views/debug.py b/django/views/debug.py
index 34bd57b33d..e30fd65095 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -23,7 +23,7 @@ from django.utils.version import get_docs_version
# works even if the template loader is broken.
DEBUG_ENGINE = Engine(
debug=True,
- libraries={'i18n': 'django.templatetags.i18n'},
+ libraries={"i18n": "django.templatetags.i18n"},
)
@@ -34,7 +34,7 @@ def builtin_template_path(name):
Avoid calling this function at the module level or in a class-definition
because __file__ may not exist, e.g. in frozen environments.
"""
- return Path(__file__).parent / 'templates' / name
+ return Path(__file__).parent / "templates" / name
class ExceptionCycleWarning(UserWarning):
@@ -48,6 +48,7 @@ class CallableSettingWrapper:
* Not to break the debug page if the callable forbidding to set attributes
(#23070).
"""
+
def __init__(self, callable_setting):
self._wrapped = callable_setting
@@ -61,12 +62,14 @@ def technical_500_response(request, exc_type, exc_value, tb, status_code=500):
the values returned from sys.exc_info() and friends.
"""
reporter = get_exception_reporter_class(request)(request, exc_type, exc_value, tb)
- if request.accepts('text/html'):
+ if request.accepts("text/html"):
html = reporter.get_traceback_html()
- return HttpResponse(html, status=status_code, content_type='text/html')
+ return HttpResponse(html, status=status_code, content_type="text/html")
else:
text = reporter.get_traceback_text()
- return HttpResponse(text, status=status_code, content_type='text/plain; charset=utf-8')
+ return HttpResponse(
+ text, status=status_code, content_type="text/plain; charset=utf-8"
+ )
@functools.lru_cache
@@ -77,12 +80,16 @@ def get_default_exception_reporter_filter():
def get_exception_reporter_filter(request):
default_filter = get_default_exception_reporter_filter()
- return getattr(request, 'exception_reporter_filter', default_filter)
+ return getattr(request, "exception_reporter_filter", default_filter)
def get_exception_reporter_class(request):
- default_exception_reporter_class = import_string(settings.DEFAULT_EXCEPTION_REPORTER)
- return getattr(request, 'exception_reporter_class', default_exception_reporter_class)
+ default_exception_reporter_class = import_string(
+ settings.DEFAULT_EXCEPTION_REPORTER
+ )
+ return getattr(
+ request, "exception_reporter_class", default_exception_reporter_class
+ )
def get_caller(request):
@@ -92,7 +99,7 @@ def get_caller(request):
resolver_match = resolve(request.path)
except Http404:
pass
- return '' if resolver_match is None else resolver_match._func_path
+ return "" if resolver_match is None else resolver_match._func_path
class SafeExceptionReporterFilter:
@@ -100,8 +107,11 @@ class SafeExceptionReporterFilter:
Use annotations made by the sensitive_post_parameters and
sensitive_variables decorators to filter out sensitive information.
"""
- cleansed_substitute = '********************'
- hidden_settings = _lazy_re_compile('API|TOKEN|KEY|SECRET|PASS|SIGNATURE', flags=re.I)
+
+ cleansed_substitute = "********************"
+ hidden_settings = _lazy_re_compile(
+ "API|TOKEN|KEY|SECRET|PASS|SIGNATURE", flags=re.I
+ )
def cleanse_setting(self, key, value):
"""
@@ -118,9 +128,9 @@ class SafeExceptionReporterFilter:
elif isinstance(value, dict):
cleansed = {k: self.cleanse_setting(k, v) for k, v in value.items()}
elif isinstance(value, list):
- cleansed = [self.cleanse_setting('', v) for v in value]
+ cleansed = [self.cleanse_setting("", v) for v in value]
elif isinstance(value, tuple):
- cleansed = tuple([self.cleanse_setting('', v) for v in value])
+ cleansed = tuple([self.cleanse_setting("", v) for v in value])
else:
cleansed = value
@@ -144,7 +154,7 @@ class SafeExceptionReporterFilter:
"""
Return a dictionary of request.META with sensitive values redacted.
"""
- if not hasattr(request, 'META'):
+ if not hasattr(request, "META"):
return {}
return {k: self.cleanse_setting(k, v) for k, v in request.META.items()}
@@ -163,7 +173,7 @@ class SafeExceptionReporterFilter:
This mitigates leaking sensitive POST parameters if something like
request.POST['nonexistent_key'] throws an exception (#21098).
"""
- sensitive_post_parameters = getattr(request, 'sensitive_post_parameters', [])
+ sensitive_post_parameters = getattr(request, "sensitive_post_parameters", [])
if self.is_active(request) and sensitive_post_parameters:
multivaluedict = multivaluedict.copy()
for param in sensitive_post_parameters:
@@ -179,10 +189,12 @@ class SafeExceptionReporterFilter:
if request is None:
return {}
else:
- sensitive_post_parameters = getattr(request, 'sensitive_post_parameters', [])
+ sensitive_post_parameters = getattr(
+ request, "sensitive_post_parameters", []
+ )
if self.is_active(request) and sensitive_post_parameters:
cleansed = request.POST.copy()
- if sensitive_post_parameters == '__ALL__':
+ if sensitive_post_parameters == "__ALL__":
# Cleanse all parameters.
for k in cleansed:
cleansed[k] = self.cleansed_substitute
@@ -203,7 +215,7 @@ class SafeExceptionReporterFilter:
# MultiValueDicts will have a return value.
is_multivalue_dict = isinstance(value, MultiValueDict)
except Exception as e:
- return '{!r} while evaluating {!r}'.format(e, value)
+ return "{!r} while evaluating {!r}".format(e, value)
if is_multivalue_dict:
# Cleanse MultiValueDicts (request.POST is the one we usually care about)
@@ -220,18 +232,20 @@ class SafeExceptionReporterFilter:
current_frame = tb_frame.f_back
sensitive_variables = None
while current_frame is not None:
- if (current_frame.f_code.co_name == 'sensitive_variables_wrapper' and
- 'sensitive_variables_wrapper' in current_frame.f_locals):
+ if (
+ current_frame.f_code.co_name == "sensitive_variables_wrapper"
+ and "sensitive_variables_wrapper" in current_frame.f_locals
+ ):
# The sensitive_variables decorator was used, so we take note
# of the sensitive variables' names.
- wrapper = current_frame.f_locals['sensitive_variables_wrapper']
- sensitive_variables = getattr(wrapper, 'sensitive_variables', None)
+ wrapper = current_frame.f_locals["sensitive_variables_wrapper"]
+ sensitive_variables = getattr(wrapper, "sensitive_variables", None)
break
current_frame = current_frame.f_back
cleansed = {}
if self.is_active(request) and sensitive_variables:
- if sensitive_variables == '__ALL__':
+ if sensitive_variables == "__ALL__":
# Cleanse all variables
for name in tb_frame.f_locals:
cleansed[name] = self.cleansed_substitute
@@ -249,14 +263,16 @@ class SafeExceptionReporterFilter:
for name, value in tb_frame.f_locals.items():
cleansed[name] = self.cleanse_special_types(request, value)
- if (tb_frame.f_code.co_name == 'sensitive_variables_wrapper' and
- 'sensitive_variables_wrapper' in tb_frame.f_locals):
+ if (
+ tb_frame.f_code.co_name == "sensitive_variables_wrapper"
+ and "sensitive_variables_wrapper" in tb_frame.f_locals
+ ):
# For good measure, obfuscate the decorated function's arguments in
# the sensitive_variables decorator's frame, in case the variables
# associated with those arguments were meant to be obfuscated from
# the decorated function's frame.
- cleansed['func_args'] = self.cleansed_substitute
- cleansed['func_kwargs'] = self.cleansed_substitute
+ cleansed["func_args"] = self.cleansed_substitute
+ cleansed["func_kwargs"] = self.cleansed_substitute
return cleansed.items()
@@ -266,11 +282,11 @@ class ExceptionReporter:
@property
def html_template_path(self):
- return builtin_template_path('technical_500.html')
+ return builtin_template_path("technical_500.html")
@property
def text_template_path(self):
- return builtin_template_path('technical_500.txt')
+ return builtin_template_path("technical_500.txt")
def __init__(self, request, exc_type, exc_value, tb, is_email=False):
self.request = request
@@ -280,7 +296,7 @@ class ExceptionReporter:
self.tb = tb
self.is_email = is_email
- self.template_info = getattr(self.exc_value, 'template_debug', None)
+ self.template_info = getattr(self.exc_value, "template_debug", None)
self.template_does_not_exist = False
self.postmortem = None
@@ -289,7 +305,7 @@ class ExceptionReporter:
Return an absolute URI from variables available in this request. Skip
allowed hosts protection, so may return insecure URI.
"""
- return '{scheme}://{host}{path}'.format(
+ return "{scheme}://{host}{path}".format(
scheme=self.request.scheme,
host=self.request._get_raw_host(),
path=self.request.get_full_path(),
@@ -303,26 +319,27 @@ class ExceptionReporter:
frames = self.get_traceback_frames()
for i, frame in enumerate(frames):
- if 'vars' in frame:
+ if "vars" in frame:
frame_vars = []
- for k, v in frame['vars']:
+ for k, v in frame["vars"]:
v = pprint(v)
# Trim large blobs of data
if len(v) > 4096:
- v = '%s… <trimmed %d bytes string>' % (v[0:4096], len(v))
+ v = "%s… <trimmed %d bytes string>" % (v[0:4096], len(v))
frame_vars.append((k, v))
- frame['vars'] = frame_vars
+ frame["vars"] = frame_vars
frames[i] = frame
- unicode_hint = ''
+ unicode_hint = ""
if self.exc_type and issubclass(self.exc_type, UnicodeError):
- start = getattr(self.exc_value, 'start', None)
- end = getattr(self.exc_value, 'end', None)
+ start = getattr(self.exc_value, "start", None)
+ end = getattr(self.exc_value, "end", None)
if start is not None and end is not None:
unicode_str = self.exc_value.args[1]
unicode_hint = force_str(
- unicode_str[max(start - 5, 0):min(end + 5, len(unicode_str))],
- 'ascii', errors='replace'
+ unicode_str[max(start - 5, 0) : min(end + 5, len(unicode_str))],
+ "ascii",
+ errors="replace",
)
from django import get_version
@@ -334,59 +351,61 @@ class ExceptionReporter:
except Exception:
# request.user may raise OperationalError if the database is
# unavailable, for example.
- user_str = '[unable to retrieve the current user]'
+ user_str = "[unable to retrieve the current user]"
c = {
- 'is_email': self.is_email,
- 'unicode_hint': unicode_hint,
- 'frames': frames,
- 'request': self.request,
- 'request_meta': self.filter.get_safe_request_meta(self.request),
- 'user_str': user_str,
- 'filtered_POST_items': list(self.filter.get_post_parameters(self.request).items()),
- 'settings': self.filter.get_safe_settings(),
- 'sys_executable': sys.executable,
- 'sys_version_info': '%d.%d.%d' % sys.version_info[0:3],
- 'server_time': timezone.now(),
- 'django_version_info': get_version(),
- 'sys_path': sys.path,
- 'template_info': self.template_info,
- 'template_does_not_exist': self.template_does_not_exist,
- 'postmortem': self.postmortem,
+ "is_email": self.is_email,
+ "unicode_hint": unicode_hint,
+ "frames": frames,
+ "request": self.request,
+ "request_meta": self.filter.get_safe_request_meta(self.request),
+ "user_str": user_str,
+ "filtered_POST_items": list(
+ self.filter.get_post_parameters(self.request).items()
+ ),
+ "settings": self.filter.get_safe_settings(),
+ "sys_executable": sys.executable,
+ "sys_version_info": "%d.%d.%d" % sys.version_info[0:3],
+ "server_time": timezone.now(),
+ "django_version_info": get_version(),
+ "sys_path": sys.path,
+ "template_info": self.template_info,
+ "template_does_not_exist": self.template_does_not_exist,
+ "postmortem": self.postmortem,
}
if self.request is not None:
- c['request_GET_items'] = self.request.GET.items()
- c['request_FILES_items'] = self.request.FILES.items()
- c['request_COOKIES_items'] = self.request.COOKIES.items()
- c['request_insecure_uri'] = self._get_raw_insecure_uri()
- c['raising_view_name'] = get_caller(self.request)
+ c["request_GET_items"] = self.request.GET.items()
+ c["request_FILES_items"] = self.request.FILES.items()
+ c["request_COOKIES_items"] = self.request.COOKIES.items()
+ c["request_insecure_uri"] = self._get_raw_insecure_uri()
+ c["raising_view_name"] = get_caller(self.request)
# Check whether exception info is available
if self.exc_type:
- c['exception_type'] = self.exc_type.__name__
+ c["exception_type"] = self.exc_type.__name__
if self.exc_value:
- c['exception_value'] = str(self.exc_value)
+ c["exception_value"] = str(self.exc_value)
if frames:
- c['lastframe'] = frames[-1]
+ c["lastframe"] = frames[-1]
return c
def get_traceback_html(self):
"""Return HTML version of debug 500 HTTP error page."""
- with self.html_template_path.open(encoding='utf-8') as fh:
+ with self.html_template_path.open(encoding="utf-8") as fh:
t = DEBUG_ENGINE.from_string(fh.read())
c = Context(self.get_traceback_data(), use_l10n=False)
return t.render(c)
def get_traceback_text(self):
"""Return plain text version of debug 500 HTTP error page."""
- with self.text_template_path.open(encoding='utf-8') as fh:
+ with self.text_template_path.open(encoding="utf-8") as fh:
t = DEBUG_ENGINE.from_string(fh.read())
c = Context(self.get_traceback_data(), autoescape=False, use_l10n=False)
return t.render(c)
def _get_source(self, filename, loader, module_name):
source = None
- if hasattr(loader, 'get_source'):
+ if hasattr(loader, "get_source"):
try:
source = loader.get_source(module_name)
except ImportError:
@@ -395,13 +414,15 @@ class ExceptionReporter:
source = source.splitlines()
if source is None:
try:
- with open(filename, 'rb') as fp:
+ with open(filename, "rb") as fp:
source = fp.read().splitlines()
except OSError:
pass
return source
- def _get_lines_from_file(self, filename, lineno, context_lines, loader=None, module_name=None):
+ def _get_lines_from_file(
+ self, filename, lineno, context_lines, loader=None, module_name=None
+ ):
"""
Return context_lines before and after lineno from file.
Return (pre_context_lineno, pre_context, context_line, post_context).
@@ -414,15 +435,15 @@ class ExceptionReporter:
# apply tokenize.detect_encoding to decode the source into a
# string, then we should do that ourselves.
if isinstance(source[0], bytes):
- encoding = 'ascii'
+ encoding = "ascii"
for line in source[:2]:
# File coding may be specified. Match pattern from PEP-263
# (https://www.python.org/dev/peps/pep-0263/)
- match = re.search(br'coding[:=]\s*([-\w.]+)', line)
+ match = re.search(rb"coding[:=]\s*([-\w.]+)", line)
if match:
- encoding = match[1].decode('ascii')
+ encoding = match[1].decode("ascii")
break
- source = [str(sline, encoding, 'replace') for sline in source]
+ source = [str(sline, encoding, "replace") for sline in source]
lower_bound = max(0, lineno - context_lines)
upper_bound = lineno + context_lines
@@ -430,15 +451,15 @@ class ExceptionReporter:
try:
pre_context = source[lower_bound:lineno]
context_line = source[lineno]
- post_context = source[lineno + 1:upper_bound]
+ post_context = source[lineno + 1 : upper_bound]
except IndexError:
return None, [], None, []
return lower_bound, pre_context, context_line, post_context
def _get_explicit_or_implicit_cause(self, exc_value):
- explicit = getattr(exc_value, '__cause__', None)
- suppress_context = getattr(exc_value, '__suppress_context__', None)
- implicit = getattr(exc_value, '__context__', None)
+ explicit = getattr(exc_value, "__cause__", None)
+ suppress_context = getattr(exc_value, "__suppress_context__", None)
+ implicit = getattr(exc_value, "__context__", None)
return explicit or (None if suppress_context else implicit)
def get_traceback_frames(self):
@@ -476,47 +497,58 @@ class ExceptionReporter:
def get_exception_traceback_frames(self, exc_value, tb):
exc_cause = self._get_explicit_or_implicit_cause(exc_value)
- exc_cause_explicit = getattr(exc_value, '__cause__', True)
+ exc_cause_explicit = getattr(exc_value, "__cause__", True)
if tb is None:
yield {
- 'exc_cause': exc_cause,
- 'exc_cause_explicit': exc_cause_explicit,
- 'tb': None,
- 'type': 'user',
+ "exc_cause": exc_cause,
+ "exc_cause_explicit": exc_cause_explicit,
+ "tb": None,
+ "type": "user",
}
while tb is not None:
# Support for __traceback_hide__ which is used by a few libraries
# to hide internal frames.
- if tb.tb_frame.f_locals.get('__traceback_hide__'):
+ if tb.tb_frame.f_locals.get("__traceback_hide__"):
tb = tb.tb_next
continue
filename = tb.tb_frame.f_code.co_filename
function = tb.tb_frame.f_code.co_name
lineno = tb.tb_lineno - 1
- loader = tb.tb_frame.f_globals.get('__loader__')
- module_name = tb.tb_frame.f_globals.get('__name__') or ''
- pre_context_lineno, pre_context, context_line, post_context = self._get_lines_from_file(
- filename, lineno, 7, loader, module_name,
+ loader = tb.tb_frame.f_globals.get("__loader__")
+ module_name = tb.tb_frame.f_globals.get("__name__") or ""
+ (
+ pre_context_lineno,
+ pre_context,
+ context_line,
+ post_context,
+ ) = self._get_lines_from_file(
+ filename,
+ lineno,
+ 7,
+ loader,
+ module_name,
)
if pre_context_lineno is None:
pre_context_lineno = lineno
pre_context = []
- context_line = '<source code not available>'
+ context_line = "<source code not available>"
post_context = []
yield {
- 'exc_cause': exc_cause,
- 'exc_cause_explicit': exc_cause_explicit,
- 'tb': tb,
- 'type': 'django' if module_name.startswith('django.') else 'user',
- 'filename': filename,
- 'function': function,
- 'lineno': lineno + 1,
- 'vars': self.filter.get_traceback_frame_variables(self.request, tb.tb_frame),
- 'id': id(tb),
- 'pre_context': pre_context,
- 'context_line': context_line,
- 'post_context': post_context,
- 'pre_context_lineno': pre_context_lineno + 1,
+ "exc_cause": exc_cause,
+ "exc_cause_explicit": exc_cause_explicit,
+ "tb": tb,
+ "type": "django" if module_name.startswith("django.") else "user",
+ "filename": filename,
+ "function": function,
+ "lineno": lineno + 1,
+ "vars": self.filter.get_traceback_frame_variables(
+ self.request, tb.tb_frame
+ ),
+ "id": id(tb),
+ "pre_context": pre_context,
+ "context_line": context_line,
+ "post_context": post_context,
+ "pre_context_lineno": pre_context_lineno + 1,
}
tb = tb.tb_next
@@ -524,52 +556,58 @@ class ExceptionReporter:
def technical_404_response(request, exception):
"""Create a technical 404 error response. `exception` is the Http404."""
try:
- error_url = exception.args[0]['path']
+ error_url = exception.args[0]["path"]
except (IndexError, TypeError, KeyError):
error_url = request.path_info[1:] # Trim leading slash
try:
- tried = exception.args[0]['tried']
+ tried = exception.args[0]["tried"]
except (IndexError, TypeError, KeyError):
resolved = True
tried = request.resolver_match.tried if request.resolver_match else None
else:
resolved = False
- if (not tried or ( # empty URLconf
- request.path == '/' and
- len(tried) == 1 and # default URLconf
- len(tried[0]) == 1 and
- getattr(tried[0][0], 'app_name', '') == getattr(tried[0][0], 'namespace', '') == 'admin'
- )):
+ if not tried or ( # empty URLconf
+ request.path == "/"
+ and len(tried) == 1
+ and len(tried[0]) == 1 # default URLconf
+ and getattr(tried[0][0], "app_name", "")
+ == getattr(tried[0][0], "namespace", "")
+ == "admin"
+ ):
return default_urlconf(request)
- urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF)
+ urlconf = getattr(request, "urlconf", settings.ROOT_URLCONF)
if isinstance(urlconf, types.ModuleType):
urlconf = urlconf.__name__
- with builtin_template_path('technical_404.html').open(encoding='utf-8') as fh:
+ with builtin_template_path("technical_404.html").open(encoding="utf-8") as fh:
t = DEBUG_ENGINE.from_string(fh.read())
reporter_filter = get_default_exception_reporter_filter()
- c = Context({
- 'urlconf': urlconf,
- 'root_urlconf': settings.ROOT_URLCONF,
- 'request_path': error_url,
- 'urlpatterns': tried,
- 'resolved': resolved,
- 'reason': str(exception),
- 'request': request,
- 'settings': reporter_filter.get_safe_settings(),
- 'raising_view_name': get_caller(request),
- })
- return HttpResponseNotFound(t.render(c), content_type='text/html')
+ c = Context(
+ {
+ "urlconf": urlconf,
+ "root_urlconf": settings.ROOT_URLCONF,
+ "request_path": error_url,
+ "urlpatterns": tried,
+ "resolved": resolved,
+ "reason": str(exception),
+ "request": request,
+ "settings": reporter_filter.get_safe_settings(),
+ "raising_view_name": get_caller(request),
+ }
+ )
+ return HttpResponseNotFound(t.render(c), content_type="text/html")
def default_urlconf(request):
"""Create an empty URLconf 404 error response."""
- with builtin_template_path('default_urlconf.html').open(encoding='utf-8') as fh:
+ with builtin_template_path("default_urlconf.html").open(encoding="utf-8") as fh:
t = DEBUG_ENGINE.from_string(fh.read())
- c = Context({
- 'version': get_docs_version(),
- })
+ c = Context(
+ {
+ "version": get_docs_version(),
+ }
+ )
- return HttpResponse(t.render(c), content_type='text/html')
+ return HttpResponse(t.render(c), content_type="text/html")