[Django] #25761: Re-raised exceptions with __cause__ should also set __traceback__ on the exception

40 views
Skip to first unread message

Django

unread,
Nov 16, 2015, 8:13:40 AM11/16/15
to django-...@googlegroups.com
#25761: Re-raised exceptions with __cause__ should also set __traceback__ on the
exception
----------------------------------------------+--------------------
Reporter: rhertzog | Owner: nobody
Type: Bug | Status: new
Component: Database layer (models, ORM) | Version: 1.8
Severity: Release blocker | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
----------------------------------------------+--------------------
In bug https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=802677 we have a
report that testtools is broken when handling database exceptions raised
by Django. This has been brought to the upstream developers of testtools
who were quick to point out that Django is at fault:
https://github.com/testing-
cabal/testtools/issues/162#issuecomment-156891988

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.

Django

unread,
Nov 16, 2015, 2:51:46 PM11/16/15
to django-...@googlegroups.com
#25761: Re-raised exceptions with __cause__ should also set __traceback__ on the
exception
-------------------------------------+-------------------------------------

Reporter: rhertzog | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 1.8
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by timgraham):

* 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>

Django

unread,
Nov 25, 2015, 9:38:59 AM11/25/15
to django-...@googlegroups.com
#25761: Re-raised exceptions with __cause__ should also set __traceback__ on the
exception
-------------------------------------+-------------------------------------

Reporter: rhertzog | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 1.8
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

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>

Django

unread,
Nov 25, 2015, 1:39:45 PM11/25/15
to django-...@googlegroups.com
#25761: Re-raised exceptions with __cause__ should also set __traceback__ on the
exception
-------------------------------------+-------------------------------------

Reporter: rhertzog | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 1.8
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by claudep):

* has_patch: 0 => 1


--
Ticket URL: <https://code.djangoproject.com/ticket/25761#comment:3>

Django

unread,
Dec 3, 2015, 4:31:35 PM12/3/15
to django-...@googlegroups.com
#25761: Re-raised exceptions with __cause__ should also set __traceback__ on the
exception
-------------------------------------+-------------------------------------

Reporter: rhertzog | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: 1.8
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

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>

Django

unread,
Dec 3, 2015, 4:32:21 PM12/3/15
to django-...@googlegroups.com
#25761: Re-raised exceptions with __cause__ should also set __traceback__ on the
exception
-------------------------------------+-------------------------------------
Reporter: rhertzog | Owner: nobody
Type: Bug | Status: closed

Component: Database layer | Version: 1.8
(models, ORM) |
Severity: Normal | Resolution: fixed

Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham <timograham@…>):

* 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>

Django

unread,
Jan 24, 2017, 8:32:20 AM1/24/17
to django-...@googlegroups.com
#25761: Re-raised exceptions with __cause__ should also set __traceback__ on the
exception
-------------------------------------+-------------------------------------
Reporter: Raphaël Hertzog | Owner: nobody

Type: Bug | Status: closed
Component: Database layer | Version: 1.8
(models, ORM) |
Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

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>

Reply all
Reply to author
Forward
0 new messages