Exceptions processing shoud be simpler
In my project I need to catch and process an integrity exceptions, because user want to see a understandable error message instead of framework's exception (or just http 500 error). So the easiest way I found was something like this (let's say i want to process only duplicate errors. obj
is object to save and table
is table, mapped to obj's class):
errors = {}
try:
Session.flush([obj](obj))
except sqlalchemy.exceptions.IntegrityError, e:
err = str(e.orig)
m = re.match(r'^column (\w+) is not unique$', err, re.I)
if not m: raise e
dupcol = m.groups(0)[0](0)
del m
if not dupcol in table.c: raise e
dupcol = table.c[dupcol](dupcol)
errors[dupcol](dupcol) = IntegrityError(dupcol.unique)
It is not clear and simple way, is it?
I am sorry for my English.
Comments (5)
-
repo owner -
repo owner OK, a little bit on the standard "have standard exception messages" request:
- DBAPI doesnt provide any way of getting at error codes, SQLSTATE, or anything like that. Its not in the spec at all. the actual DBAPIs we work with dont seem to provide them, either...maybe psycopg2 does (although its not documented) so we cant do too much with that.
- each DBAPI doesnt even raise the same kind of exception class for the same thing, necessarily (although they are probably fairly consistent for
IntegrityError
). - since theres no DBAPI spec for any of this, any layer that builds on top of it would not only require a ton of regexes and hardcoded string lookup tables, it would also be changing all the time, with different versions of the DB, the DBAPI, etc.
- when an error is raised, its important that the actual error from the database gets reported. the last thing we need is to have users asking on our mailing list about errors that are coming straight from their database. so I wouldn't favor any exception normalization by default.
- if there were some kind of layer that normalizes the wide variety of error codes into a single consistent list of codes, we'd welcome that. We'd have it available either as a recipe or an extension. contributions are definitely welcome.
- for reference, see
#295and#737. technically this ticket is a duplicate of#295...contributions are welcome on that ticket as well.
in practice, i think its typical that real end users dont really see any kind of message other than "an error occured" in the first place...things like integrityerrors should be seen as application failures.
-
Account Deleted Let me say, what I want to see in exceptions API in an ideal:
try: session.flush() except exceptions.UniquenessConditionError, e: return u'Нарушено условие уникальности в колонке "%s"' % localized_column_names[e.column.name](e.column.name) # return 'Uniqueness condition error in column "%s"' % e.column.name
I forgot to mention about
errors[dupcol](dupcol) = IntegrityError(dupcol.unique)
this code in the beginning.IntegrityError
here is exception class, defined in my project, notslqlachemy.exceptions.IntegrityError
. I am trying to construct mechanism, which will tell user, what does he do wrong. And printing juststr(e)
- is not a solution, just because I can not rely, that users know English. -
Account Deleted Replying to zzzeek:
- since theres no DBAPI spec for any of this, any layer that builds on top of it would not only require a ton of regexes and hardcoded string lookup tables, it would also be changing all the time, with different versions of the DB, the DBAPI, etc. For this reason I think using regexes is not reliable, it is dirty trick, which is the first thing, that can broke project after dbapi version upgrade :(
-
repo owner - changed status to wontfix
Part of this ticket is a dupe of
#295(getting standardized failure codes from DBAPI exceptions), part of it is a feature request for "higher level" exceptions, which I think would not be needed if#295could be resolved, and otherwise is not something we want to implement (a system of educated guessing as to what the exception means based on its type and string message). The one case we do do this is for detecting disconnects but in general its not an easily maintainable practice. - Log in to comment
sorry, I don't exactly understand what you're trying to achieve up there. You'd like an IntegrityError with a boolean flag in it, inside of a global dictionary ? I don't understand what that accomplishes.
to just extract the column or raise the exception can be much more succinct: