#15901: Django should wrap all PEP 249 exceptions in db.utils
-------------------------------------+-------------------------------------
Reporter: xiaket | Owner: nobody
Type: New feature | Status: new
Component: Database layer | Version: 1.3
(models, ORM) | Resolution:
Severity: Normal | Triage Stage: Accepted
Keywords: | Needs documentation: 0
Has patch: 1 | Patch needs improvement: 0
Needs tests: 0 | UI/UX: 0
Easy pickings: 0 |
-------------------------------------+-------------------------------------
Comment (by gcbirzan):
Replying to [comment:12 jamesh]:
> Both of your suggestions prevent users from writing standard Python
"except" clauses to catch particular classes of database errors, which
seems to be one of the goals of this ticket.
>
> And for some database adapters like psycopg2, there is more useful
information in the exception than you'll find in `e.args` (e.g. the
`pgcode` attribute holding the SQL error code).
I don't understand what you mean. Your confusion might stem from the fact
that I use code as would be in the database backend, where you have import
psycopg2 as Database. With the first one:
{{{
try:
do_stuff()
except util.DatabaseError as e:
if isinstance(e.args[0], psycopg2.ProgrammingError):
print e.args[0].pgcode
}}}
second:
{{{
try:
do_stuff()
except psycopg2.ProgrammingError as e:
pass
}}}
Granted, you cannot access pgcode, but that could be hanlded either in a
backend specific manner, or, you could just put the exception's dictionary
in the new type (ugly, I know.). But either way, you're better off than
now.
I personally am leaning towards the first method, to be honest, since it's
the closest to pep3134. The original doesn't have to be put in the args,
it can be:
{{{
try:
do_stuff()
except Database.DatabaseError as e:
exc = util.DatabaseError(*e.args)
exc.__cause__ = e
raise util.DatabaseError, exc, sys.exc_info()[2]
}}}
You can even combine the two:
{{{
try:
do_stuff()
except Database.DatabaseError as e:
exc_type = type('DatabaseError', (Database.DatabaseError,
util.DatabaseError), {})
raise exc_type, exc_type(e), sys.exc_info()[2]
}}}
or
{{{
try:
do_stuff()
except Database.DatabaseError as e:
exc_type = type('DatabaseError', (Database.DatabaseError,
util.DatabaseError), {})
exc = exc_type(*e.args)
exc.__cause__ = e
raise exc_type, exc, sys.exc_info()[2]
}}}
Now you can catch it with both psycopg2.DatabaseError, and
util.DatabaseError. In the first, you will have e.args[0] for the
original, in the second, e.__cause__.
> If your concern is about not being able to distinguish exceptions that
come directly from the database adapter and exceptions from the Django
backend, what do you see as the consequences of not being able to do this?
>
> Django used to let the adapter exceptions bubble up through the
backends. It only changed when support for multiple databases were added
and it was necessary to have some backend independent exceptions to catch.
If we let the adapter exceptions bubble up but keep the ability to catch
backend independent exceptions, what do we lose?
The fact that it will violate the principle of least astonishment, like
all monkey patching.
As for your ABC suggestion, it won't work.
http://bugs.python.org/issue12029
--
Ticket URL: <https://code.djangoproject.com/ticket/15901#comment:17>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en.