diff options
Diffstat (limited to 'lib/sqlalchemy/events.py')
-rw-r--r-- | lib/sqlalchemy/events.py | 143 |
1 files changed, 82 insertions, 61 deletions
diff --git a/lib/sqlalchemy/events.py b/lib/sqlalchemy/events.py index 4fb997b9c..9f05c8b5b 100644 --- a/lib/sqlalchemy/events.py +++ b/lib/sqlalchemy/events.py @@ -1,20 +1,20 @@ # sqlalchemy/events.py -# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file> +# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors <see AUTHORS file> # # This module is part of SQLAlchemy and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php """Core event interfaces.""" -from . import event, exc, util -engine = util.importlater('sqlalchemy', 'engine') -pool = util.importlater('sqlalchemy', 'pool') - +from . import event, exc +from .pool import Pool +from .engine import Connectable, Engine +from .sql.base import SchemaEventTarget class DDLEvents(event.Events): """ Define event listeners for schema objects, - that is, :class:`.SchemaItem` and :class:`.SchemaEvent` + that is, :class:`.SchemaItem` and other :class:`.SchemaEventTarget` subclasses, including :class:`.MetaData`, :class:`.Table`, :class:`.Column`. @@ -71,6 +71,7 @@ class DDLEvents(event.Events): """ _target_class_doc = "SomeSchemaClassOrObject" + _dispatch_target = SchemaEventTarget def before_create(self, target, connection, **kw): """Called before CREATE statments are emitted. @@ -219,25 +220,6 @@ class DDLEvents(event.Events): """ -class SchemaEventTarget(object): - """Base class for elements that are the targets of :class:`.DDLEvents` - events. - - This includes :class:`.SchemaItem` as well as :class:`.SchemaType`. - - """ - dispatch = event.dispatcher(DDLEvents) - - def _set_parent(self, parent): - """Associate with this SchemaEvent's parent object.""" - - raise NotImplementedError() - - def _set_parent_with_dispatch(self, parent): - self.dispatch.before_parent_attach(self, parent) - self._set_parent(parent) - self.dispatch.after_parent_attach(self, parent) - class PoolEvents(event.Events): """Available events for :class:`.Pool`. @@ -269,62 +251,74 @@ class PoolEvents(event.Events): """ _target_class_doc = "SomeEngineOrPool" + _dispatch_target = Pool @classmethod def _accept_with(cls, target): if isinstance(target, type): - if issubclass(target, engine.Engine): - return pool.Pool - elif issubclass(target, pool.Pool): + if issubclass(target, Engine): + return Pool + elif issubclass(target, Pool): return target - elif isinstance(target, engine.Engine): + elif isinstance(target, Engine): return target.pool else: return target def connect(self, dbapi_connection, connection_record): - """Called once for each new DB-API connection or Pool's ``creator()``. + """Called at the moment a particular DBAPI connection is first + created for a given :class:`.Pool`. + + This event allows one to capture the point directly after which + the DBAPI module-level ``.connect()`` method has been used in order + to produce a new DBAPI connection. - :param dbapi_con: - A newly connected raw DB-API connection (not a SQLAlchemy - ``Connection`` wrapper). + :param dbapi_connection: a DBAPI connection. - :param con_record: - The ``_ConnectionRecord`` that persistently manages the connection + :param connection_record: the :class:`._ConnectionRecord` managing the + DBAPI connection. """ def first_connect(self, dbapi_connection, connection_record): - """Called exactly once for the first DB-API connection. + """Called exactly once for the first time a DBAPI connection is + checked out from a particular :class:`.Pool`. - :param dbapi_con: - A newly connected raw DB-API connection (not a SQLAlchemy - ``Connection`` wrapper). + The rationale for :meth:`.PoolEvents.first_connect` is to determine + information about a particular series of database connections based + on the settings used for all connections. Since a particular + :class:`.Pool` refers to a single "creator" function (which in terms + of a :class:`.Engine` refers to the URL and connection options used), + it is typically valid to make observations about a single connection + that can be safely assumed to be valid about all subsequent connections, + such as the database version, the server and client encoding settings, + collation settings, and many others. - :param con_record: - The ``_ConnectionRecord`` that persistently manages the connection + :param dbapi_connection: a DBAPI connection. + + :param connection_record: the :class:`._ConnectionRecord` managing the + DBAPI connection. """ def checkout(self, dbapi_connection, connection_record, connection_proxy): """Called when a connection is retrieved from the Pool. - :param dbapi_con: - A raw DB-API connection + :param dbapi_connection: a DBAPI connection. - :param con_record: - The ``_ConnectionRecord`` that persistently manages the connection + :param connection_record: the :class:`._ConnectionRecord` managing the + DBAPI connection. - :param con_proxy: - The ``_ConnectionFairy`` which manages the connection for the span of - the current checkout. + :param connection_proxy: the :class:`._ConnectionFairy` object which + will proxy the public interface of the DBAPI connection for the lifespan + of the checkout. If you raise a :class:`~sqlalchemy.exc.DisconnectionError`, the current connection will be disposed and a fresh connection retrieved. Processing of all checkout listeners will abort and restart using the new connection. - .. seealso:: :meth:`.ConnectionEvents.connect` - a similar event + .. seealso:: :meth:`.ConnectionEvents.engine_connect` - a similar event which occurs upon creation of a new :class:`.Connection`. """ @@ -336,15 +330,14 @@ class PoolEvents(event.Events): connection has been invalidated. ``checkin`` will not be called for detached connections. (They do not return to the pool.) - :param dbapi_con: - A raw DB-API connection + :param dbapi_connection: a DBAPI connection. - :param con_record: - The ``_ConnectionRecord`` that persistently manages the connection + :param connection_record: the :class:`._ConnectionRecord` managing the + DBAPI connection. """ - def reset(self, dbapi_con, con_record): + def reset(self, dbapi_connnection, connection_record): """Called before the "reset" action occurs for a pooled connection. This event represents @@ -358,11 +351,10 @@ class PoolEvents(event.Events): the :meth:`.PoolEvents.checkin` event is called, except in those cases where the connection is discarded immediately after reset. - :param dbapi_con: - A raw DB-API connection + :param dbapi_connection: a DBAPI connection. - :param con_record: - The ``_ConnectionRecord`` that persistently manages the connection + :param connection_record: the :class:`._ConnectionRecord` managing the + DBAPI connection. .. versionadded:: 0.8 @@ -374,6 +366,30 @@ class PoolEvents(event.Events): """ + def invalidate(self, dbapi_connection, connection_record, exception): + """Called when a DBAPI connection is to be "invalidated". + + This event is called any time the :meth:`._ConnectionRecord.invalidate` + method is invoked, either from API usage or via "auto-invalidation". + The event occurs before a final attempt to call ``.close()`` on the connection + occurs. + + :param dbapi_connection: a DBAPI connection. + + :param connection_record: the :class:`._ConnectionRecord` managing the + DBAPI connection. + + :param exception: the exception object corresponding to the reason + for this invalidation, if any. May be ``None``. + + .. versionadded:: 0.9.2 Added support for connection invalidation + listening. + + .. seealso:: + + :ref:`pool_connection_invalidation` + + """ class ConnectionEvents(event.Events): @@ -448,9 +464,14 @@ class ConnectionEvents(event.Events): """ _target_class_doc = "SomeEngine" + _dispatch_target = Connectable + @classmethod - def _listen(cls, target, identifier, fn, retval=False): + def _listen(cls, event_key, retval=False): + target, identifier, fn = \ + event_key.dispatch_target, event_key.identifier, event_key.fn + target._has_events = True if not retval: @@ -479,7 +500,7 @@ class ConnectionEvents(event.Events): "'before_cursor_execute' engine " "event listeners accept the 'retval=True' " "argument.") - event.Events._listen(target, identifier, fn) + event_key.with_wrapper(fn).base_listen() def before_execute(self, conn, clauseelement, multiparams, params): """Intercept high level execute() events, receiving uncompiled @@ -680,7 +701,7 @@ class ConnectionEvents(event.Events): Note that this method is not called when a new :class:`.Connection` is produced which is inheriting execution options from its parent :class:`.Engine`; to intercept this condition, use the - :meth:`.ConnectionEvents.connect` event. + :meth:`.ConnectionEvents.engine_connect` event. :param conn: The newly copied :class:`.Connection` object |