Pointless exception re-raising in DA.py
Hi All, In Shared/DC/ZRDB/DA.py, Line 399 of Zope 2.6.1 and line 419 in 2.7.0, there's this rather pointless lump of code: try: DB__=dbc() except: raise DatabaseError, ( '%s is not connected to a database' % self.id) ...which only serves to mask the real cause of the problem when trying to obtain a connection. Would anyone have any objections if I changed this to simply: DB__ = dbc() ? (if no responses, I'll assume that means you agree with my proposed change ;-) Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Hi Chris,
In Shared/DC/ZRDB/DA.py, Line 399 of Zope 2.6.1 and line 419 in 2.7.0, there's this rather pointless lump of code:
try: DB__=dbc() except: raise DatabaseError, ( '%s is not connected to a database' % self.id)
...which only serves to mask the real cause of the problem when trying to obtain a connection.
I remeber I made a collector issue about that liens of code: http://www.zope.org/Collectors/Zope/927 Previously this has been a string valued exception. Actually I like it to be an exception of a certain type now, because I can now selectively catching this DatabaseError and distinguish it from other errors. No need for a evil bare except. The reason is that I would like to treat errors when accessing an external data base different from other errors; often the data obtained there is only "optional" to the page, so I don't want to show usered the error page in this case, only to fill up doem slot with "sorry, that certain piece of information is not availabe, because our sql data base sucks". I see Your point. However is there any chance that "dbc()" does raise something more specific? I am afraid it does not. If it does not, I would have to go back to an evil bare except ... Cheers, Clemens
Hi there, Clemens Robbenhaar wrote:
I remeber I made a collector issue about that liens of code:
Indeed. Catching everything and raising a string exception is evil, and I was glad to see that go.
Previously this has been a string valued exception. Actually I like it to be an exception of a certain type now, because I can now selectively catching this DatabaseError and distinguish it from other errors. No need for a evil bare except.
Well, I'm afraid I don't agree here...
The reason is that I would like to treat errors when accessing an external data base different from other errors; often the data obtained there is only "optional" to the page, so I don't want to show usered the error page in this case, only to fill up doem slot with "sorry, that certain piece of information is not availabe, because our sql data base sucks".
...this is an application level decision. The code currently makes it very easy, but at the expense of debugging any unexpected exceptions that code throws. While relational data may be "optional" for you, for many people it is ESSENTIAL, and is used for things like their auth details, content storage, etc. For them, this piece of code causes MAJOR suffering, especially for intermittent failures where you can't just insert a print_traceback and try again ;-)
I see Your point. However is there any chance that "dbc()" does raise something more specific? I am afraid it does not.
No, that's the whole point. If that code raises an exception, it's much more useful if it can be logged and dealt with in its original form rather than have it morphed into something uniform and meaningless.
If it does not, I would have to go back to an evil bare except ...
I wouldn't if I were you: try: *your zsql method except ConflictError: raise except Exception: return "sorry, that certain piece of information is not availabe, because our sql data base sucks" If your database adapter raises a string exception, THEN you have to add a bare except on the end of that, but if that's the case you should beat the DA author with a stick until he fixes it. cheers, Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Hi Chris, [...]
...this is an application level decision. The code currently makes it very easy, but at the expense of debugging any unexpected exceptions that code throws. While relational data may be "optional" for you, for many people it is ESSENTIAL, and is used for things like their auth details, content storage, etc. For them, this piece of code causes MAJOR suffering, especially for intermittent failures where you can't just insert a print_traceback and try again ;-)
Ok, understand (I guess ;-) [...]
If it does not, I would have to go back to an evil bare except ...
I wouldn't if I were you:
try: *your zsql method except ConflictError: raise except Exception: return "sorry, that certain piece of information is not availabe, because our sql data base sucks"
Ok, if this is the proper dance to catch such exceptions with Zope without risking ZODB corruption I will go with it. So far I have not been sure, that ConflictError is the only type needing special treatement in these cases. Clemens
Clemens Robbenhaar wrote:
Ok, if this is the proper dance to catch such exceptions with Zope without risking ZODB corruption I will go with it. So far I have not been sure, that ConflictError is the only type needing special treatement in these cases.
Well, the PROPER dance would be to only catch exceptions that you're happy to ignroe from your database. You should be able to find those otu fairly quickly. Any new ones htat come along later probably want to be looked at by you before being automatically ignored... Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Chris Withers writes:
Clemens Robbenhaar wrote:
Ok, if this is the proper dance to catch such exceptions with Zope without risking ZODB corruption I will go with it. So far I have not been sure, that ConflictError is the only type needing special treatement in these cases.
Well, the PROPER dance would be to only catch exceptions that you're happy to ignroe from your database. You should be able to find those otu fairly quickly. Any new ones htat come along later probably want to be looked at by you before being automatically ignored...
Hm, figuring out the "right" exception actually the problem; if the data base connector would raise an exception of a certain type due to unability to connect I could catch these and let the others pass. Unfortunately I am not able to figure out the interesting ones so quickly by experimenting, because I cannot think about (or even reproduce) everything that may actually fail. However, looking at the code this thread started with: Catching all exceptions in a certain (relaively high level) place and transforming them into something else does not really help a lot there; this may catch real programming errors as well. So I finally got the point why the try: except: block there should go away. I guess the specific data base connector should raise that "DB-failed" specific exception, instead, Unfortunately there is no sich general exception for it. (such as java has as java.sql.SQLException ... often not very informative, but at least one knows its from the data base.) Currently I am bound to hard wire the exception type the specific data base connection raises in my code and have to change the code if I would change the underlying data base. Maybe the "DatabaseError" class could remain in the DA.py, so specific data base connections could reuse this exception type? Or it is much to late to introduce such an exception type, as none of the supporterd of a data base connection product will rewrite their product to use this exception now? (btw: does somebody know, if Zope3 would maybe have such an "external data source connection" specific exception?) Cheers anyway, Clemens
Clemens Robbenhaar wrote:
Hm, figuring out the "right" exception actually the problem; if the data base connector would raise an exception of a certain type due to unability to connect I could catch these and let the others pass.
Which DA are you using? It _should_ do that...
Unfortunately I am not able to figure out the interesting ones so quickly by experimenting, because I cannot think about (or even reproduce) everything that may actually fail.
The specifc DA you are using should subclass all it's exceptions from a base exception. ZOracleDA does this the right wya, fro mwhat I've seen...
Unfortunately there is no sich general exception for it.
Well, it's up to the DA author to provide one...
(such as java has as java.sql.SQLException ... often not very informative, but at least one knows its from the data base.) Maybe the "DatabaseError" class could remain in the DA.py, so specific data base connections could reuse this exception type?
Sounds like a plan, now you jus thave to persuade the DA authors to start using it ;-)
product to use this exception now? (btw: does somebody know, if Zope3 would maybe have such an "external data source connection" specific exception?)
Ask on zope3-dev@zope.org... cheers, Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Chris Withers writes:
Clemens Robbenhaar wrote:
Hm, figuring out the "right" exception actually the problem; if the data base connector would raise an exception of a certain type due to unability to connect I could catch these and let the others pass.
Which DA are you using? It _should_ do that...
ZMySQLDA -> raises MySQLError and OperationalError from module MySQLdb (so far I have seen those at least ;-)
Unfortunately I am not able to figure out the interesting ones so quickly by experimenting, because I cannot think about (or even reproduce) everything that may actually fail.
The specifc DA you are using should subclass all it's exceptions from a base exception. ZOracleDA does this the right wya, fro mwhat I've seen...
But it is a base exception class in ZOracleDA, however. Thus the product using it need to explicitely import this exception, and thus explicitely depend on the used relational database; code needs to be rewritten if one exchanges the external data base. (Well, if one uses something ambitious like oracle, sure there are more implicit dependencies in the used sql statements so one cannot simply switch to something e;lse anyway ;-)
Maybe the "DatabaseError" class could remain in the DA.py, so specific data base connections could reuse this exception type?
Sounds like a plan, now you jus thave to persuade the DA authors to start using it ;-)
Well, um, yes, at least I am asking if it makes sense to keep the exception DA.DatabaseError in the code, even it it is not yet / no longer used. I see DA-maintainers are not all rushing out for using it, however ...
product to use this exception now? (btw: does somebody know, if Zope3 would maybe have such an "external data source connection" specific exception?)
Ask on zope3-dev@zope.org...
Well, I guess I should first read the Zope3 wiki ;-) Cheers, Clemens
Clemens Robbenhaar wrote:
But it is a base exception class in ZOracleDA, however. Thus the product using it need to explicitely import this exception, and thus explicitely depend on the used relational database; code needs to be rewritten if one exchanges the external data base.
So, you got sucked into the myth of SQL too? ;-) You'll need to rewrite at least some of your SQL if you change backends, so I don't see this as a huge problem...
Well, um, yes, at least I am asking if it makes sense to keep the exception DA.DatabaseError in the code, even it it is not yet / no longer used.
I think it's good ot keep it there so DA authors can subclass it, but not for stuff to be caught and re-raised as is happening now... cheers, Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Chris Withers writes:
Clemens Robbenhaar wrote:
But it is a base exception class in ZOracleDA, however. Thus the product using it need to explicitely import this exception, and thus explicitely depend on the used relational database; code needs to be rewritten if one exchanges the external data base.
So, you got sucked into the myth of SQL too? ;-) You'll need to rewrite at least some of your SQL if you change backends, so I don't see this as a huge problem...
Well, except if migrating _from_ mySQL, whose features are usually covered by all other sql data base implementation (some kind of upward compatibility ;-) (No pun on mySQL, I personally do not like to see more features than a non-expert can keep in mind anyway ... the sql experts may disagree on this, of course ;-) Actually my code just contains some few "select foo from bar" statements, so it most probably will not change when migrating the data base. But I see, my case seems to be a very specific one, and if the sql-db is migrated I will survive having to change a few lines ...
Well, um, yes, at least I am asking if it makes sense to keep the exception DA.DatabaseError in the code, even it it is not yet / no longer used.
I think it's good ot keep it there so DA authors can subclass it, but not for stuff to be caught and re-raised as is happening now...
As I understand we agree on the original point of the discussion. Cheers, Clemens
Clemens Robbenhaar wrote:
As I understand we agree on the original point of the discussion.
Cool, I'll make the change when I get a chance :-) Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Chris Withers wrote at 2004-3-29 16:54 +0100:
Clemens Robbenhaar wrote:
But it is a base exception class in ZOracleDA, however. Thus the product using it need to explicitely import this exception, and thus explicitely depend on the used relational database; code needs to be rewritten if one exchanges the external data base.
So, you got sucked into the myth of SQL too? ;-) You'll need to rewrite at least some of your SQL if you change backends, so I don't see this as a huge problem...
What an argument :-( As you need to change *something*, why bother with ideas to change as little as possible. -- Dieter
Dieter Maurer wrote:
So, you got sucked into the myth of SQL too? ;-) You'll need to rewrite at least some of your SQL if you change backends, so I don't see this as a huge problem...
What an argument :-(
As you need to change *something*, why bother with ideas to change as little as possible.
I missed off the <0.5 wink> from my reply. Portability of SQL is a myth, but I'm not advocating making life more difficult elsewhere. The proposed change as it stands now will stop the current exception masking but still let DA authors subclass their exceptions from a root exception such that code can catch all of them... cheers, Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Chris Withers wrote at 2004-3-24 15:36 +0000:
...
The reason is that I would like to treat errors when accessing an external data base different from other errors; often the data obtained there is only "optional" to the page, so I don't want to show usered the error page in this case, only to fill up doem slot with "sorry, that certain piece of information is not availabe, because our sql data base sucks".
...this is an application level decision. The code currently makes it very easy, but at the expense of debugging any unexpected exceptions that code throws.
You can have both! It is just a little more work for you (I know you are lazy...): try: DB__=dbc() except: exc_type, exc_value, trc = sys.exc_info() raise DatabaseError('%s is not connected to a database' % self.id, exc_type, exc_value), trc trc = None Define "DatabaseError" in such a way that its "__str__" includes information about the original exception. -- Dieter
Dieter Maurer wrote:
try: DB__=dbc() except: exc_type, exc_value, trc = sys.exc_info() raise DatabaseError('%s is not connected to a database' % self.id, exc_type, exc_value), trc
I didn't know you could re-raise a traceback like this... where's tha tsyntax documented?
Define "DatabaseError" in such a way that its "__str__" includes information about the original exception.
This seems needlessly overcomplicated to me... Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
On Thu, Mar 25, 2004 at 10:23:27AM +0000, Chris Withers wrote:
Dieter Maurer wrote:
try: DB__=dbc() except: exc_type, exc_value, trc = sys.exc_info() raise DatabaseError('%s is not connected to a database' % self.id, exc_type, exc_value), trc
I didn't know you could re-raise a traceback like this... where's tha tsyntax documented?
In the language reference: http://www.python.org/doc/current/ref/raise.html See also the sys.exc_info docs in the library reference: http://www.python.org/doc/current/lib/module-sys.html#l2h-331 -Andrew.
participants (5)
-
Andrew Bennetts -
Chris Withers -
Chris Withers -
Clemens Robbenhaar -
Dieter Maurer