Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix for #18925 - Exception information should be localized and passed to got_request_exception signal handlers #332

Closed
wants to merge 2 commits into from

1 participant

Oliver Beattie
Oliver Beattie

See ticket for explanation.

obeattie added some commits
Oliver Beattie obeattie Fixed #18925 -- Exception information should be localized
and passed to got_request_exception signal handlers

sys.exc_info() is now stored in a local variable before processing
got_request_exception signals, and passed to the signals as an argument,
to avoid issues seen with traceback information being lost if a greenlet
switch occurs during exception processing, when Django is running under
Gevent.
3be37da
Oliver Beattie obeattie Add test for #18925 63a760b
Oliver Beattie

In response to my posts on the mailing list, this has actually been fixed in gevent, so closing this.

Oliver Beattie obeattie closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 7, 2012
  1. Oliver Beattie

    Fixed #18925 -- Exception information should be localized

    obeattie authored
    and passed to got_request_exception signal handlers
    
    sys.exc_info() is now stored in a local variable before processing
    got_request_exception signals, and passed to the signals as an argument,
    to avoid issues seen with traceback information being lost if a greenlet
    switch occurs during exception processing, when Django is running under
    Gevent.
  2. Oliver Beattie

    Add test for #18925

    obeattie authored
This page is out of date. Refresh to see the latest.
32 django/core/handlers/base.py
View
@@ -153,8 +153,13 @@ def get_response(self, request):
callback, param_dict = resolver.resolve404()
response = callback(request, **param_dict)
except:
- signals.got_request_exception.send(sender=self.__class__, request=request)
- response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
+ exc_info = sys.exc_info() # See ticket #18925 for why this is localized
+ signals.got_request_exception.send(
+ sender=self.__class__, request=request,
+ exc_info=exc_info)
+ response = self.handle_uncaught_exception(request,
+ resolver, exc_info)
+ del exc_info
except exceptions.PermissionDenied:
logger.warning(
'Forbidden (Permission denied): %s', request.path,
@@ -166,17 +171,24 @@ def get_response(self, request):
callback, param_dict = resolver.resolve403()
response = callback(request, **param_dict)
except:
+ exc_info = sys.exc_info() # See ticket #18925 for why this is localized
signals.got_request_exception.send(
- sender=self.__class__, request=request)
+ sender=self.__class__, request=request,
+ exc_info=exc_info)
response = self.handle_uncaught_exception(request,
- resolver, sys.exc_info())
+ resolver, exc_info)
+ del exc_info
except SystemExit:
# Allow sys.exit() to actually exit. See tickets #1023 and #4701
raise
except: # Handle everything else, including SuspiciousOperation, etc.
# Get the exception info now, in case another exception is thrown later.
- signals.got_request_exception.send(sender=self.__class__, request=request)
- response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
+ exc_info = sys.exc_info() # See ticket #18925 for why this is localized
+ signals.got_request_exception.send(
+ sender=self.__class__, request=request,
+ exc_info=exc_info)
+ response = self.handle_uncaught_exception(request, resolver, exc_info)
+ del exc_info
finally:
# Reset URLconf for this thread on the way out for complete
# isolation of request.urlconf
@@ -188,8 +200,12 @@ def get_response(self, request):
response = middleware_method(request, response)
response = self.apply_response_fixes(request, response)
except: # Any exception should be gathered and handled
- signals.got_request_exception.send(sender=self.__class__, request=request)
- response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
+ exc_info = sys.exc_info() # See ticket #18925 for why this is localized
+ signals.got_request_exception.send(
+ sender=self.__class__, request=request,
+ exc_info=exc_info)
+ response = self.handle_uncaught_exception(request, resolver, exc_info)
+ del exc_info
return response
17 tests/regressiontests/views/tests/debug.py
View
@@ -6,12 +6,14 @@
from django.conf import settings
from django.core.files.uploadedfile import SimpleUploadedFile
+from django.core.signals import got_request_exception
from django.test import TestCase, RequestFactory
from django.test.utils import (setup_test_template_loader,
restore_template_loaders)
from django.core.urlresolvers import reverse
from django.views.debug import ExceptionReporter
from django.core import mail
+from django.core.handlers.wsgi import WSGIHandler
from .. import BrokenException, except_args
from ..views import (sensitive_view, non_sensitive_view, paranoid_view,
@@ -86,6 +88,21 @@ def test_template_loader_postmortem(self):
template_path = os.path.join('templates', 'i_dont_exist.html')
self.assertContains(response, template_path, status_code=500)
+ def test_exception_preservation(self):
+ "An exception is preserved and reported correctly, even if sys.exc_clear is called."
+ def on_request_exception(sender, request, **kwargs):
+ sys.exc_clear()
+
+ got_request_exception.connect(on_request_exception)
+ try:
+ with self.settings(DEBUG=True):
+ handler = WSGIHandler()
+ environ = RequestFactory().get(reverse('view_exception', args=(1,))).environ
+ response = handler(environ, lambda *a, **k: None)
+ self.assertContains(response, '<h2>Traceback ', status_code=500)
+ self.assertContains(response, 'raise BrokenException(', status_code=500)
+ finally:
+ got_request_exception.disconnect(on_request_exception)
class ExceptionReporterTests(TestCase):
rf = RequestFactory()
Something went wrong with that request. Please try again.