Merge "Upgrade exc_filters for 'engine' argument and connect behavior"

This commit is contained in:
Jenkins 2014-12-12 12:46:32 +00:00 committed by Gerrit Code Review
commit 8d07501262
4 changed files with 62 additions and 26 deletions

@ -23,6 +23,8 @@ from oslo.db.sqlalchemy.compat import handle_error as _h_err
# flake8 won't let me import handle_error directly
engine_connect = _e_conn.engine_connect
handle_error = _h_err.handle_error
ExceptionContextImpl = _h_err.ExceptionContextImpl
handle_connect_context = _h_err.handle_connect_context
__all__ = ['engine_connect', 'handle_error', 'ExceptionContextImpl']
__all__ = [
'engine_connect', 'handle_error',
'handle_connect_context']

@ -16,6 +16,7 @@ http://docs.sqlalchemy.org/en/rel_0_9/core/events.html.
"""
import contextlib
import sys
import six
@ -35,10 +36,17 @@ def handle_error(engine, listener):
in order to support safe re-raise of the exception.
"""
if utils.sqla_097:
if utils.sqla_100:
event.listen(engine, "handle_error", listener)
return
elif utils.sqla_097:
# ctx.engine added per
# https://bitbucket.org/zzzeek/sqlalchemy/issue/3266/
def wrap_listener(ctx):
ctx.engine = ctx.connection.engine
return listener(ctx)
event.listen(engine, "handle_error", wrap_listener)
return
assert isinstance(engine, Engine), \
"engine argument must be an Engine instance, not a Connection"
@ -92,7 +100,7 @@ def handle_error(engine, listener):
# new handle_error event
ctx = ExceptionContextImpl(
original_exception, sqlalchemy_exception,
self, cursor, statement,
self.engine, self, cursor, statement,
parameters, context, is_disconnect)
for fn in _oslo_handle_error_events:
@ -153,8 +161,9 @@ class ExceptionContextImpl(object):
"""
def __init__(self, exception, sqlalchemy_exception,
connection, cursor, statement, parameters,
engine, connection, cursor, statement, parameters,
context, is_disconnect):
self.engine = engine
self.connection = connection
self.sqlalchemy_exception = sqlalchemy_exception
self.original_exception = exception
@ -166,7 +175,17 @@ class ExceptionContextImpl(object):
connection = None
"""The :class:`.Connection` in use during the exception.
This member is always present.
This member is present, except in the case of a failure when
first connecting.
"""
engine = None
"""The :class:`.Engine` in use during the exception.
This member should always be present, even in the case of a failure
when first connecting.
"""
@ -247,3 +266,24 @@ class ExceptionContextImpl(object):
:meth:`.ConnectionEvents.handle_error` handler.
"""
@contextlib.contextmanager
def handle_connect_context(handler, engine):
"""Wrap connect() routines with a "handle error" context."""
try:
yield
except Exception as e:
if utils.sqla_100:
raise
if isinstance(e, sqla_exc.StatementError):
s_exc, orig = e, e.orig
else:
s_exc, orig = None, e
ctx = ExceptionContextImpl(
orig, s_exc, engine, None, None,
None, None, None, False
)
handler(ctx)

@ -19,6 +19,7 @@ _SQLA_VERSION = tuple(
for num in sqlalchemy.__version__.split(".")
)
sqla_100 = _SQLA_VERSION >= (1, 0, 0)
sqla_097 = _SQLA_VERSION >= (0, 9, 7)
sqla_094 = _SQLA_VERSION >= (0, 9, 4)
sqla_090 = _SQLA_VERSION >= (0, 9, 0)

@ -314,13 +314,13 @@ def handler(context):
more specific exception class are attempted first.
"""
def _dialect_registries(connection):
if connection.dialect.name in _registry:
yield _registry[connection.dialect.name]
def _dialect_registries(engine):
if engine.dialect.name in _registry:
yield _registry[engine.dialect.name]
if '*' in _registry:
yield _registry['*']
for per_dialect in _dialect_registries(context.connection):
for per_dialect in _dialect_registries(context.engine):
for exc in (
context.sqlalchemy_exception,
context.original_exception):
@ -334,7 +334,7 @@ def handler(context):
fn(
exc,
match,
context.connection.dialect.name,
context.engine.dialect.name,
context.is_disconnect)
except exception.DBConnectionError:
context.is_disconnect = True
@ -349,18 +349,11 @@ def handle_connect_error(engine):
"""Handle connect error.
Provide a special context that will allow on-connect errors
to be raised within the filtering context.
"""
try:
return engine.connect()
except Exception as e:
if isinstance(e, sqla_exc.StatementError):
s_exc, orig = e, e.orig
else:
s_exc, orig = None, e
to be treated within the filtering context.
ctx = compat.ExceptionContextImpl(
orig, s_exc, engine, None,
None, None, None, False
)
handler(ctx)
This routine is dependent on SQLAlchemy version, as version 1.0.0
provides this functionality natively.
"""
with compat.handle_connect_context(handler, engine):
return engine.connect()