Thread: [SQLObject] Patch for database exception handling
SQLObject is a Python ORM.
Brought to you by:
ianbicking,
phd
From: Dan P. <da...@ag...> - 2006-07-27 17:39:17
Attachments:
sqlobject.diff
|
Following the discussion we had about 2 months ago about having sqlobject raise a set of exceptions independent of the backend used, I asked a colleague of mine to implement this. He did it for the mysql and sqlite backends, for which we have experience. Not having any experience with the other backends, we left their implementation to someone who knows them and is interested in doing this. Still the patch would give a good start in the direction of having sqlobject handle exceptions consistently without the need of prior knowledge about the backend that is used. Below is the email my colleague tried to send to the mailing list 2 times without success. Hopefully this will go through. ---------- Forwarded Message ---------- Subject: Database exceptions handling Date: Wednesday 26 July 2006 08:03 From: Mircea Amarascu <mi...@ag...> To: sql...@li... Hello, I've read the "Handling exceptions" topic on this mailing list (http://www.mail-archive.com/sqlobject-discuss%40lists.sourceforge.net/ms g00975.html) and decided to take a step further and try to add a database exception hierarchy to SQLObject, as described in PEP249 (http://www.python.org/dev/peps/pep-0249/). I've discovered that the Database API Specification v2.0 is followed by both MySQL and SQLite Python modules, so all that need to be done in this case was a one-to-one mapping between their exceptions and the SQLObject defined ones. I have no experience in other database APIs (Postgres, Sybase, etc), so I haven't modified those backends.. The error message attached to the SQLObject database exception is basically a string, but it also contains the error code (if any), and the originating module and exception, in case these would need later inspection. We could also add more specific exceptions derived from the base ones, such as DatabaseConnectionError(OperationalError), or DuplicateEntryError(IntegrityError). In my implementation I found it useful to have a DuplicateEntryError exception, to know exactly if an IntegrityError was raised when a duplicate key constraint violation has occured. I've attached the patch (diffed against svn revision 1827), please tell me your opinion about it. ------------------------------------------------------- -- Dan |
From: Martin G. <mge...@mg...> - 2006-07-28 20:25:40
|
Dan Pascu <da...@ag...> writes: > Following the discussion we had about 2 months ago about having sqlobject= =20 > raise a set of exceptions independent of the backend used, I asked a=20 > colleague of mine to implement this. This sounds like a very good idea to me! I'm currently using a sqlite database for ease of configuration and testing, but for real use people might want to use another existing database. So it would be cool to be able to switch at a whim without having to change occurances of, say, sqlite.IntegrityError to mysql.IntegrityError (or whatever the corresponding exception might be called...). I realize that I could alias IntegrityError to one or another myself, but it would still be cleaner if SQLObject did it for me. =2D-=20 Martin Geisler --- <mge...@mg...> --- http://mgeisler.net Read, write, create Exif data in PHP with PEL: http://pel.sf.net Take control of your webserver with PHP Shell: http://phpshell.sf.net |
From: Oleg B. <ph...@ma...> - 2006-07-28 20:51:04
|
Hello! On Thu, Jul 27, 2006 at 08:39:02PM +0300, Dan Pascu wrote: > Following the discussion we had about 2 months ago about having sqlobject > raise a set of exceptions independent of the backend used, I asked a > colleague of mine to implement this. > He did it for the mysql and sqlite backends This is a good start, thank you! > ---------- Forwarded Message ---------- > Subject: Database exceptions handling > Date: Wednesday 26 July 2006 08:03 > From: Mircea Amarascu <mi...@ag...> > To: sql...@li... > > I've discovered that the Database API Specification v2.0 is followed by > both MySQL and > SQLite Python modules, so all that need to be done in this case was a > one-to-one mapping between > their exceptions and the SQLObject defined ones. I am not so sure about one-to-one mapping. On a duplicate inserts Some DB drivers raise ProgrammingError, some raise OperationError, some IntegrityError. This is what we'd like to unify in a consistent set of SQLObject's exceptions. > Index: sqlite/sqliteconnection.py > =================================================================== > > +class ErrorMessage(str): > + def __new__(cls, e): > + obj = str.__new__(cls, e[0]) > + obj.code = None > + obj.module = e.__module__ > + obj.exception = e.__class__.__name__ > + return obj > + These classes are too similar. Are they really two different classes? > Index: mysql/mysqlconnection.py > =================================================================== > > +class ErrorMessage(str): > + def __new__(cls, e): > + obj = str.__new__(cls, e[1]) > + obj.code = int(e[0]) > + obj.module = e.__module__ > + obj.exception = e.__class__.__name__ > + return obj > + Oleg. -- Oleg Broytmann http://phd.pp.ru/ ph...@ph... Programmers don't die, they just GOSUB without RETURN. |
From: Dan P. <da...@ag...> - 2006-07-29 09:48:02
|
On Friday 28 July 2006 11:13, Oleg Broytmann wrote: > > I've discovered that the Database API Specification v2.0 is followed > > by both MySQL and > > SQLite Python modules, so all that need to be done in this case was a > > one-to-one mapping between > > their exceptions and the SQLObject defined ones. > > I am not so sure about one-to-one mapping. On a duplicate inserts > Some DB drivers raise ProgrammingError, some raise OperationError, some > IntegrityError. This is what we'd like to unify in a consistent set of > SQLObject's exceptions. I think you misread that. He said that the MySQL and SQLite have 1 to 1 mappings. As for other backends, I have no idea. Each db backend will will have its own mappings, from the backend exceptions to the SQLObject exceptions. It happens both MySQL and SQLite follow the pep and the mapping is 1 to 1. I have no idea what exceptions other backends raise, so in their case the mapping may not be 1 to 1, but I don't see how this matters, as each backend will map the exceptions as it has to internally and raise the set of standard SQLObject exceptions. > > > Index: sqlite/sqliteconnection.py > > =================================================================== > > > > +class ErrorMessage(str): > > + def __new__(cls, e): > > + obj = str.__new__(cls, e[0]) > > + obj.code = None > > + obj.module = e.__module__ > > + obj.exception = e.__class__.__name__ > > + return obj > > + > > These classes are too similar. Are they really two different > classes? Not really, but each db backend has to initialize them in a very specific way, depending on its internals. They are just some internal thing, defined by each db backend as it fits the backend's needs. I find it easier that each backend defines that class internally and passed the backend exception to it, to transform it into a SQLObject error message, than to have a single common class that will require multiple parameters to initialize. Anyway, it doesn't really matter much as they are just a standard python string with some attributes (to identify the original exception if there is a need). For all it matters to the exception handler they are a string. Their purpose is to have a string (the error) with some extra attributes (for debugging and extending purposes), not to have it interpreted like a new class. Exception handler should handle them as strings with attributes. In the future after the SQLObject exceptions reach their maturity and won't need changes anymore, they can be replaced with simple strings (or maybe not). This was done this way, because you cannot attach attributes to standard python strings, and the point is to return some string with attached attributes, for which I don't really care what's its class, all I care is that it behaves like a string. > > > Index: mysql/mysqlconnection.py > > =================================================================== > > > > +class ErrorMessage(str): > > + def __new__(cls, e): > > + obj = str.__new__(cls, e[1]) > > + obj.code = int(e[0]) > > + obj.module = e.__module__ > > + obj.exception = e.__class__.__name__ > > + return obj > > + -- Dan |