From: Jason Kirtland Date: Mon, 22 Oct 2007 19:24:02 +0000 (+0000) Subject: - Now guarding against broken DB-APIs when wrapping their exceptions. X-Git-Tag: rel_0_4_1~121 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9d7c027cb76d467d2f044952287f92bb61016617;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Now guarding against broken DB-APIs when wrapping their exceptions. - Added an explicit test for exception wrapping. --- diff --git a/lib/sqlalchemy/exceptions.py b/lib/sqlalchemy/exceptions.py index 9c7caedd03..decde0efac 100644 --- a/lib/sqlalchemy/exceptions.py +++ b/lib/sqlalchemy/exceptions.py @@ -96,8 +96,14 @@ class DBAPIError(SQLAlchemyError): instance = classmethod(instance) def __init__(self, statement, params, orig): - SQLAlchemyError.__init__(self, "(%s) %s" % - (orig.__class__.__name__, str(orig))) + try: + text = str(orig) + except (KeyboardInterrupt, SystemExit): + raise + except Exception, e: + text = 'Error in str() of DB-API-generated exception: ' + str(e) + SQLAlchemyError.__init__( + self, "(%s) %s" % (orig.__class__.__name__, text)) self.statement = statement self.params = params self.orig = orig diff --git a/test/base/alltests.py b/test/base/alltests.py index 44fa9b2ecf..d14b694cba 100644 --- a/test/base/alltests.py +++ b/test/base/alltests.py @@ -6,6 +6,7 @@ def suite(): # core utilities 'base.dependency', 'base.utils', + 'base.except', ) alltests = unittest.TestSuite() for name in modules_to_test: diff --git a/test/base/except.py b/test/base/except.py new file mode 100644 index 0000000000..671597b5ff --- /dev/null +++ b/test/base/except.py @@ -0,0 +1,78 @@ +"""Tests exceptions and DB-API exception wrapping.""" + +import testbase +import sys, unittest +import exceptions as stdlib_exceptions +from sqlalchemy import exceptions as sa_exceptions +from testlib import * + + +class Error(stdlib_exceptions.StandardError): + """This class will be old-style on <= 2.4 and new-style on >= 2.5.""" +class DatabaseError(Error): + pass +class OperationalError(DatabaseError): + pass +class ProgrammingError(DatabaseError): + def __str__(self): + return "<%s>" % self.bogus +class OutOfSpec(DatabaseError): + pass + + +class WrapTest(unittest.TestCase): + def test_db_error_normal(self): + try: + raise sa_exceptions.DBAPIError.instance( + '', [], OperationalError()) + except sa_exceptions.DBAPIError: + self.assert_(True) + + def test_db_error_busted_dbapi(self): + try: + raise sa_exceptions.DBAPIError.instance( + '', [], ProgrammingError()) + except sa_exceptions.DBAPIError, e: + self.assert_(True) + self.assert_('Error in str() of DB-API' in e.args[0]) + + def test_db_error_noncompliant_dbapi(self): + try: + raise sa_exceptions.DBAPIError.instance( + '', [], OutOfSpec()) + except sa_exceptions.DBAPIError, e: + self.assert_(e.__class__ is sa_exceptions.DBAPIError) + except OutOfSpec: + self.assert_(False) + + # Make sure the DatabaseError recognition logic is limited to + # subclasses of sqlalchemy.exceptions.DBAPIError + try: + raise sa_exceptions.DBAPIError.instance( + '', [], sa_exceptions.AssertionError()) + except sa_exceptions.DBAPIError, e: + self.assert_(e.__class__ is sa_exceptions.DBAPIError) + except sa_exceptions.AssertionError: + self.assert_(False) + + def test_db_error_keyboard_interrupt(self): + try: + raise sa_exceptions.DBAPIError.instance( + '', [], stdlib_exceptions.KeyboardInterrupt()) + except sa_exceptions.DBAPIError: + self.assert_(False) + except stdlib_exceptions.KeyboardInterrupt: + self.assert_(True) + + def test_db_error_system_exit(self): + try: + raise sa_exceptions.DBAPIError.instance( + '', [], stdlib_exceptions.SystemExit()) + except sa_exceptions.DBAPIError: + self.assert_(False) + except stdlib_exceptions.SystemExit: + self.assert_(True) + + +if __name__ == "__main__": + testbase.main()