diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sqlalchemy/engine/base.py | 3 | ||||
-rw-r--r-- | lib/sqlalchemy/engine/default.py | 3 | ||||
-rw-r--r-- | lib/sqlalchemy/engine/strategies.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/exceptions.py | 110 | ||||
-rw-r--r-- | lib/sqlalchemy/pool.py | 11 |
5 files changed, 90 insertions, 39 deletions
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 78eb0922e..a4e41e996 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -1183,7 +1183,8 @@ class ResultProxy(object): rec = (type, type.dialect_impl(self.dialect), i) if rec[0] is None: - raise exceptions.DBAPIError("None for metadata " + colname) + raise exceptions.InvalidRequestError( + "None for metadata " + colname) if self.__props.setdefault(colname.lower(), rec) is not rec: self.__props[colname.lower()] = (type, ResultProxy.AmbiguousColumn(colname), 0) self.__keys.append(colname) diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py index a9ee02c1c..f7410bb0f 100644 --- a/lib/sqlalchemy/engine/default.py +++ b/lib/sqlalchemy/engine/default.py @@ -136,7 +136,8 @@ class DefaultDialect(base.Dialect): # to appropriate character upon compilation self.positional = True else: - raise exceptions.DBAPIError("Unsupported paramstyle '%s'" % self._paramstyle) + raise exceptions.InvalidRequestError( + "Unsupported paramstyle '%s'" % self._paramstyle) def _get_ischema(self): if self._ischema is None: diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py index ed9422d15..168a9c4ab 100644 --- a/lib/sqlalchemy/engine/strategies.py +++ b/lib/sqlalchemy/engine/strategies.py @@ -71,7 +71,7 @@ class DefaultEngineStrategy(EngineStrategy): try: return dbapi.connect(*cargs, **cparams) except Exception, e: - raise exceptions.DBAPIError("Connection failed", e) + raise exceptions.DBAPIError(None, None, e) creator = kwargs.pop('creator', connect) poolclass = (kwargs.pop('poolclass', None) or diff --git a/lib/sqlalchemy/exceptions.py b/lib/sqlalchemy/exceptions.py index 7fe5cf518..28e32eeb4 100644 --- a/lib/sqlalchemy/exceptions.py +++ b/lib/sqlalchemy/exceptions.py @@ -8,23 +8,6 @@ class SQLAlchemyError(Exception): """Generic error class.""" - pass - -class SQLError(SQLAlchemyError): - """Raised when the execution of a SQL statement fails. - - Includes accessors for the underlying exception, as well as the - SQL and bind parameters. - """ - - def __init__(self, statement, params, orig): - SQLAlchemyError.__init__(self, "(%s) %s"% (orig.__class__.__name__, str(orig))) - self.statement = statement - self.params = params - self.orig = orig - - def __str__(self): - return SQLAlchemyError.__str__(self) + " " + repr(self.statement) + " " + repr(self.params) class ArgumentError(SQLAlchemyError): """Raised for all those conditions where invalid arguments are @@ -32,30 +15,26 @@ class ArgumentError(SQLAlchemyError): construction time state errors. """ - pass class CompileError(SQLAlchemyError): """Raised when an error occurs during SQL compilation""" - - pass - + + class TimeoutError(SQLAlchemyError): """Raised when a connection pool times out on getting a connection.""" - pass class ConcurrentModificationError(SQLAlchemyError): """Raised when a concurrent modification condition is detected.""" - pass class CircularDependencyError(SQLAlchemyError): """Raised by topological sorts when a circular dependency is detected""" - pass + class FlushError(SQLAlchemyError): """Raised when an invalid condition is detected upon a ``flush()``.""" - pass + class InvalidRequestError(SQLAlchemyError): """SQLAlchemy was asked to do something it can't do, return @@ -64,32 +43,93 @@ class InvalidRequestError(SQLAlchemyError): This error generally corresponds to runtime state errors. """ - pass class NoSuchTableError(InvalidRequestError): """SQLAlchemy was asked to load a table's definition from the database, but the table doesn't exist. """ - pass class AssertionError(SQLAlchemyError): """Corresponds to internal state being detected in an invalid state.""" - pass class NoSuchColumnError(KeyError, SQLAlchemyError): """Raised by ``RowProxy`` when a nonexistent column is requested from a row.""" - pass + +class DisconnectionError(SQLAlchemyError): + """Raised within ``Pool`` when a disconnect is detected on a raw DBAPI connection.""" + class DBAPIError(SQLAlchemyError): - """Something weird happened with a particular DBAPI version.""" + """Raised when the execution of a database operation fails. + + ``DBAPIError`` wraps exceptions raised by the DB-API underlying the + database operation. Driver-specific implementations of the standard + DB-API exception types are wrapped by matching sub-types of SQLAlchemy's + ``DBAPIError`` when possible. DB-API's ``Error`` type maps to + ``DBAPIError`` in SQLAlchemy, otherwise the names are identical. Note + that there is no guarantee that different DB-API implementations will + raise the same exception type for any given error condition. + + If the error-raising operation occured in the execution of a SQL + statement, that statement and its parameters will be available on + the exception object in the ``statement`` and ``params`` attributes. + + The wrapped exception object is available in the ``orig`` attribute. + Its type and properties are DB-API implementation specific. + """ + + def __new__(cls, statement, params, orig, *args, **kw): + # Don't ever wrap these, just return them directly as if + # DBAPIError didn't exist. + if isinstance(orig, (KeyboardInterrupt, SystemExit)): + return orig + + if orig is not None: + name, glob = type(orig).__name__, globals() + if name in glob and issubclass(glob[name], DBAPIError): + cls = glob[name] + + return SQLAlchemyError.__new__(cls, statement, params, orig, + *args, **kw) - def __init__(self, message, orig): - SQLAlchemyError.__init__(self, "(%s) (%s) %s"% (message, orig.__class__.__name__, str(orig))) + def __init__(self, statement, params, orig): + SQLAlchemyError.__init__(self, "(%s) %s" % + (orig.__class__.__name__, str(orig))) + self.statement = statement + self.params = params self.orig = orig -class DisconnectionError(SQLAlchemyError): - """Raised within ``Pool`` when a disconnect is detected on a raw DBAPI connection.""" - pass + def __str__(self): + return ' '.join([SQLAlchemyError.__str__(self), + repr(self.statement), repr(self.params)]) + + +# As of 0.4, SQLError is now DBAPIError +SQLError = DBAPIError + +class InterfaceError(DBAPIError): + """Wraps a DB-API InterfaceError.""" + +class DatabaseError(DBAPIError): + """Wraps a DB-API DatabaseError.""" + +class DataError(DatabaseError): + """Wraps a DB-API DataError.""" + +class OperationalError(DatabaseError): + """Wraps a DB-API OperationalError.""" + +class IntegrityError(DatabaseError): + """Wraps a DB-API IntegrityError.""" + +class InterfaceError(DatabaseError): + """Wraps a DB-API InterfaceError.""" + +class ProgrammingError(DatabaseError): + """Wraps a DB-API ProgrammingError.""" + +class NotSupportedError(DatabaseError): + """Wraps a DB-API NotSupportedError.""" diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py index f6965495f..526abe81c 100644 --- a/lib/sqlalchemy/pool.py +++ b/lib/sqlalchemy/pool.py @@ -241,6 +241,8 @@ class _ConnectionRecord(object): self.connection.close() except Exception, e: self.__pool.log("Connection %s threw an error on close: %s" % (repr(self.connection), str(e))) + if isinstance(e, (SystemExit, KeyboardInterrupt)): + raise def __connect(self): try: @@ -371,6 +373,8 @@ class _ConnectionFairy(object): except Exception, e: if self._connection_record is not None: self._connection_record.invalidate(e=e) + if isinstance(e, (SystemExit, KeyboardInterrupt)): + raise if self._connection_record is not None: if self._pool.echo: self._pool.log("Connection %s being returned to pool" % repr(self.connection)) @@ -394,6 +398,8 @@ class _CursorFairy(object): self.cursor.close() except Exception, e: self.__parent._logger.warn("Error closing cursor: " + str(e)) + if isinstance(e, (SystemExit, KeyboardInterrupt)): + raise def __getattr__(self, key): return getattr(self.cursor, key) @@ -432,8 +438,11 @@ class SingletonThreadPool(Pool): for key, conn in self._conns.items(): try: conn.close() + except (SystemExit, KeyboardInterrupt): + raise except: - # sqlite won't even let you close a conn from a thread that didn't create it + # sqlite won't even let you close a conn from a thread + # that didn't create it pass del self._conns[key] |