Django is setting the {{{__cause__}}} attribute thus mimicking Python's 3
behaviour, but not ensuring that the associated exception has a usable
{{{__traceback__}}} attribute. The traceback2 module (backport of Python
3's traceback) relies on this... thus Django should also make sure that
the exception has the expected attribute when it sets {{{__cause__}}}.
This needs to be fixed at least in django/db/utils.py
({{{DatabaseErrorWrapper.__exit__()}}}). But there are other cases where
Django is setting {{{__cause___}}} in django/db/migrations/loader.py,
django/utils/dictconfig.py and django/utils/timezone.py. It looks like
they might have the same problem.
A fix for the first case might possibly be something like this (untested):
{{{
--- a/django/db/utils.py
+++ b/django/db/utils.py
@@ -91,6 +91,8 @@ class DatabaseErrorWrapper(object):
if issubclass(exc_type, db_exc_type):
dj_exc_value = dj_exc_type(*exc_value.args)
dj_exc_value.__cause__ = exc_value
+ if not hasattr(exc_value, '__traceback__'):
+ setattr(exc_value, '__traceback__', traceback)
# Only set the 'errors_occurred' flag for errors that may
make
# the connection unusable.
if dj_exc_type not in (DataError, IntegrityError):
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/25761>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* needs_better_patch: => 0
* stage: Unreviewed => Accepted
* severity: Release blocker => Normal
* needs_tests: => 0
* needs_docs: => 0
Comment:
There is also some documentation to be updated. See the patch from #17601.
--
Ticket URL: <https://code.djangoproject.com/ticket/25761#comment:1>
Comment (by rhertzog):
Here's a pull request fixing this ticket:
https://github.com/django/django/pull/5721
The test suite passes but I have not tested yet if it really fixes the
issue originally reported to Debian. Also master no longer has
django/utils/dictconfig.py and you might want to fix that occurrence as
well when you backport the fix to 1.8.x / 1.9.x.
--
Ticket URL: <https://code.djangoproject.com/ticket/25761#comment:2>
* has_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/25761#comment:3>
Comment (by timgraham):
The bug fix doesn't seem to qualify for a backport since the issue has
been around as long as Django has supported Python 3 and testtools should
be able to prevent the crash.
--
Ticket URL: <https://code.djangoproject.com/ticket/25761#comment:4>
* status: new => closed
* resolution: => fixed
Comment:
In [changeset:"9f4e031bd3cb13d5879fe9ad3d889ce861b0babe" 9f4e031b]:
{{{
#!CommitTicketReference repository=""
revision="9f4e031bd3cb13d5879fe9ad3d889ce861b0babe"
Fixed #25761 -- Added __cause__.__traceback__ to reraised exceptions.
When Django reraises an exception, it sets the __cause__ attribute even
in Python 2, mimicking Python's 3 behavior for "raise Foo from Bar".
However, Python 3 also ensures that all exceptions have a __traceback__
attribute and thus the "traceback2" Python 2 module (backport of Python
3's "traceback" module) relies on the fact that whenever you have a
__cause__ attribute, the recorded exception also has a __traceback__
attribute.
This is breaking testtools which is using traceback2 (see
https://github.com/testing-cabal/testtools/issues/162).
This commit fixes this inconsistency by ensuring that Django sets
the __traceback__ attribute on any exception stored in a __cause__
attribute of a reraised exception.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/25761#comment:5>
Comment (by GitHub <noreply@…>):
In [changeset:"435e4bf38e97255acd97eacadeb8fe312ba97aff" 435e4bf3]:
{{{
#!CommitTicketReference repository=""
revision="435e4bf38e97255acd97eacadeb8fe312ba97aff"
Refs #23919 -- Removed __traceback__ setting needed for Python 2.
Partially reverted refs #25761 and refs #16245.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/25761#comment:6>