no deprecation warning about cgi.parse_qsl()
[ticket:1682]
+ - Added mixin class sqlalchemy.ext.DontWrapMixin.
+ User-defined exceptions of this type are never
+ wrapped in StatementException when they
+ occur in the context of a statement
+ execution.
+
+ - StatementException wrapping will display the
+ original exception class in the message.
+
- mssql
- Adjusted the pyodbc dialect such that bound
values are passed as bytes and not unicode
"""
+import traceback
class SQLAlchemyError(Exception):
"""Generic error class."""
"""SQL was attempted without a database connection to execute it on."""
+class DontWrapMixin(object):
+ """A mixin class which, when applied to a user-defined Exception class,
+ will not be wrapped inside of :class:`.StatementError` if the error is
+ emitted within the process of executing a statement.
+
+ E.g.::
+ from sqlalchemy.exc import DontWrapMixin
+
+ class MyCustomException(Exception, DontWrapMixin):
+ pass
+
+ class MySpecialType(TypeDecorator):
+ impl = String
+
+ def process_bind_param(self, value, dialect):
+ if value == 'invalid':
+ raise MyCustomException("invalid!")
+
+ """
+
# Moved to orm.exc; compatibility definition installed by orm import until 0.6
UnmappedColumnError = None
connection_invalidated=False):
# Don't ever wrap these, just return them directly as if
# DBAPIError didn't exist.
- if isinstance(orig, (KeyboardInterrupt, SystemExit)):
+ if isinstance(orig, (KeyboardInterrupt, SystemExit, DontWrapMixin)):
return orig
if orig is not None:
# not a DBAPI error, statement is present.
# raise a StatementError
if not isinstance(orig, dbapi_base_err) and statement:
- return StatementError(str(orig), statement, params, orig)
+ return StatementError(
+ "%s (original cause: %s)" % (
+ str(orig),
+ traceback.format_exception_only(orig.__class__, orig)[-1].strip()
+ ), statement, params, orig)
name, glob = orig.__class__.__name__, globals()
if name in glob and issubclass(glob[name], DBAPIError):
def _go(conn):
assert_raises_message(
tsa.exc.StatementError,
- "nope 'SELECT 1 ",
+ r"nope \(original cause: Exception: nope\) 'SELECT 1 ",
+ conn.execute,
+ select([1]).\
+ where(
+ column('foo') == literal('bar', MyType())
+ )
+ )
+ _go(testing.db)
+ conn = testing.db.connect()
+ try:
+ _go(conn)
+ finally:
+ conn.close()
+
+ @testing.requires.python25
+ def test_dont_wrap_mixin(self):
+ class MyException(Exception, tsa.exc.DontWrapMixin):
+ pass
+
+ class MyType(TypeDecorator):
+ impl = Integer
+ def process_bind_param(self, value, dialect):
+ raise MyException("nope")
+
+ def _go(conn):
+ assert_raises_message(
+ MyException,
+ "nope",
conn.execute,
select([1]).\
where(