1# sqlalchemy/events.py
2# Copyright (C) 2005-2021 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: http://www.opensource.org/licenses/mit-license.php
7
8"""Core event interfaces."""
9
10from . import event
11from . import exc
12from . import util
13from .engine import Connectable
14from .engine import Dialect
15from .engine import Engine
16from .pool import Pool
17from .sql.base import SchemaEventTarget
18
19
20class DDLEvents(event.Events):
21 """
22 Define event listeners for schema objects,
23 that is, :class:`.SchemaItem` and other :class:`.SchemaEventTarget`
24 subclasses, including :class:`_schema.MetaData`, :class:`_schema.Table`,
25 :class:`_schema.Column`.
26
27 :class:`_schema.MetaData` and :class:`_schema.Table` support events
28 specifically regarding when CREATE and DROP
29 DDL is emitted to the database.
30
31 Attachment events are also provided to customize
32 behavior whenever a child schema element is associated
33 with a parent, such as, when a :class:`_schema.Column` is associated
34 with its :class:`_schema.Table`, when a
35 :class:`_schema.ForeignKeyConstraint`
36 is associated with a :class:`_schema.Table`, etc.
37
38 Example using the ``after_create`` event::
39
40 from sqlalchemy import event
41 from sqlalchemy import Table, Column, Metadata, Integer
42
43 m = MetaData()
44 some_table = Table('some_table', m, Column('data', Integer))
45
46 def after_create(target, connection, **kw):
47 connection.execute("ALTER TABLE %s SET name=foo_%s" %
48 (target.name, target.name))
49
50 event.listen(some_table, "after_create", after_create)
51
52 DDL events integrate closely with the
53 :class:`.DDL` class and the :class:`.DDLElement` hierarchy
54 of DDL clause constructs, which are themselves appropriate
55 as listener callables::
56
57 from sqlalchemy import DDL
58 event.listen(
59 some_table,
60 "after_create",
61 DDL("ALTER TABLE %(table)s SET name=foo_%(table)s")
62 )
63
64 The methods here define the name of an event as well
65 as the names of members that are passed to listener
66 functions.
67
68 For all :class:`.DDLEvent` events, the ``propagate=True`` keyword argument
69 will ensure that a given event handler is propagated to copies of the
70 object, which are made when using the :meth:`_schema.Table.tometadata`
71 method::
72
73 from sqlalchemy import DDL
74 event.listen(
75 some_table,
76 "after_create",
77 DDL("ALTER TABLE %(table)s SET name=foo_%(table)s"),
78 propagate=True
79 )
80
81 new_table = some_table.tometadata(new_metadata)
82
83 The above :class:`.DDL` object will also be associated with the
84 :class:`_schema.Table` object represented by ``new_table``.
85
86 .. seealso::
87
88 :ref:`event_toplevel`
89
90 :class:`.DDLElement`
91
92 :class:`.DDL`
93
94 :ref:`schema_ddl_sequences`
95
96 """
97
98 _target_class_doc = "SomeSchemaClassOrObject"
99 _dispatch_target = SchemaEventTarget
100
101 def before_create(self, target, connection, **kw):
102 r"""Called before CREATE statements are emitted.
103
104 :param target: the :class:`_schema.MetaData` or :class:`_schema.Table`
105 object which is the target of the event.
106 :param connection: the :class:`_engine.Connection` where the
107 CREATE statement or statements will be emitted.
108 :param \**kw: additional keyword arguments relevant
109 to the event. The contents of this dictionary
110 may vary across releases, and include the
111 list of tables being generated for a metadata-level
112 event, the checkfirst flag, and other
113 elements used by internal events.
114
115 :func:`.event.listen` also accepts the ``propagate=True``
116 modifier for this event; when True, the listener function will
117 be established for any copies made of the target object,
118 i.e. those copies that are generated when
119 :meth:`_schema.Table.tometadata` is used.
120
121 """
122
123 def after_create(self, target, connection, **kw):
124 r"""Called after CREATE statements are emitted.
125
126 :param target: the :class:`_schema.MetaData` or :class:`_schema.Table`
127 object which is the target of the event.
128 :param connection: the :class:`_engine.Connection` where the
129 CREATE statement or statements have been emitted.
130 :param \**kw: additional keyword arguments relevant
131 to the event. The contents of this dictionary
132 may vary across releases, and include the
133 list of tables being generated for a metadata-level
134 event, the checkfirst flag, and other
135 elements used by internal events.
136
137 :func:`.event.listen` also accepts the ``propagate=True``
138 modifier for this event; when True, the listener function will
139 be established for any copies made of the target object,
140 i.e. those copies that are generated when
141 :meth:`_schema.Table.tometadata` is used.
142
143 """
144
145 def before_drop(self, target, connection, **kw):
146 r"""Called before DROP statements are emitted.
147
148 :param target: the :class:`_schema.MetaData` or :class:`_schema.Table`
149 object which is the target of the event.
150 :param connection: the :class:`_engine.Connection` where the
151 DROP statement or statements will be emitted.
152 :param \**kw: additional keyword arguments relevant
153 to the event. The contents of this dictionary
154 may vary across releases, and include the
155 list of tables being generated for a metadata-level
156 event, the checkfirst flag, and other
157 elements used by internal events.
158
159 :func:`.event.listen` also accepts the ``propagate=True``
160 modifier for this event; when True, the listener function will
161 be established for any copies made of the target object,
162 i.e. those copies that are generated when
163 :meth:`_schema.Table.tometadata` is used.
164
165 """
166
167 def after_drop(self, target, connection, **kw):
168 r"""Called after DROP statements are emitted.
169
170 :param target: the :class:`_schema.MetaData` or :class:`_schema.Table`
171 object which is the target of the event.
172 :param connection: the :class:`_engine.Connection` where the
173 DROP statement or statements have been emitted.
174 :param \**kw: additional keyword arguments relevant
175 to the event. The contents of this dictionary
176 may vary across releases, and include the
177 list of tables being generated for a metadata-level
178 event, the checkfirst flag, and other
179 elements used by internal events.
180
181 :func:`.event.listen` also accepts the ``propagate=True``
182 modifier for this event; when True, the listener function will
183 be established for any copies made of the target object,
184 i.e. those copies that are generated when
185 :meth:`_schema.Table.tometadata` is used.
186
187 """
188
189 def before_parent_attach(self, target, parent):
190 """Called before a :class:`.SchemaItem` is associated with
191 a parent :class:`.SchemaItem`.
192
193 :param target: the target object
194 :param parent: the parent to which the target is being attached.
195
196 :func:`.event.listen` also accepts the ``propagate=True``
197 modifier for this event; when True, the listener function will
198 be established for any copies made of the target object,
199 i.e. those copies that are generated when
200 :meth:`_schema.Table.tometadata` is used.
201
202 """
203
204 def after_parent_attach(self, target, parent):
205 """Called after a :class:`.SchemaItem` is associated with
206 a parent :class:`.SchemaItem`.
207
208 :param target: the target object
209 :param parent: the parent to which the target is being attached.
210
211 :func:`.event.listen` also accepts the ``propagate=True``
212 modifier for this event; when True, the listener function will
213 be established for any copies made of the target object,
214 i.e. those copies that are generated when
215 :meth:`_schema.Table.tometadata` is used.
216
217 """
218
219 def _sa_event_column_added_to_pk_constraint(self, const, col):
220 """internal event hook used for primary key naming convention
221 updates.
222
223 """
224
225 def column_reflect(self, inspector, table, column_info):
226 """Called for each unit of 'column info' retrieved when
227 a :class:`_schema.Table` is being reflected.
228
229 Currently, this event may only be applied to the :class:`_schema.Table`
230 class directly::
231
232 from sqlalchemy import Table
233
234 @event.listens_for(Table, 'column_reflect')
235 def receive_column_reflect(inspector, table, column_info):
236 # receives for all Table objects that are reflected
237
238 Or applied using the
239 :paramref:`_schema.Table.listeners` parameter::
240
241 t1 = Table(
242 "my_table",
243 autoload_with=some_engine,
244 listeners=[
245 ('column_reflect', receive_column_reflect)
246 ]
247 )
248
249 A future release will allow it to be associated with a specific
250 :class:`_schema.MetaData` object as well.
251
252 The dictionary of column information as returned by the
253 dialect is passed, and can be modified. The dictionary
254 is that returned in each element of the list returned
255 by :meth:`.reflection.Inspector.get_columns`:
256
257 * ``name`` - the column's name, is applied to the
258 :paramref:`_schema.Column.name` parameter
259
260 * ``type`` - the type of this column, which should be an instance
261 of :class:`~sqlalchemy.types.TypeEngine`, is applied to the
262 :paramref:`_schema.Column.type` parameter
263
264 * ``nullable`` - boolean flag if the column is NULL or NOT NULL,
265 is applied to the :paramref:`_schema.Column.nullable` parameter
266
267 * ``default`` - the column's server default value. This is
268 normally specified as a plain string SQL expression, however the
269 event can pass a :class:`.FetchedValue`, :class:`.DefaultClause`,
270 or :func:`_expression.text` object as well. Is applied to the
271 :paramref:`_schema.Column.server_default` parameter
272
273 .. versionchanged:: 1.1.6
274
275 The :meth:`.DDLEvents.column_reflect` event allows a non
276 string :class:`.FetchedValue`,
277 :func:`_expression.text`, or derived object to be
278 specified as the value of ``default`` in the column
279 dictionary.
280
281 The event is called before any action is taken against
282 this dictionary, and the contents can be modified; the following
283 additional keys may be added to the dictionary to further modify
284 how the :class:`_schema.Column` is constructed:
285
286
287 * ``key`` - the string key that will be used to access this
288 :class:`_schema.Column` in the ``.c`` collection; will be applied
289 to the :paramref:`_schema.Column.key` parameter. Is also used
290 for ORM mapping. See the section
291 :ref:`mapper_automated_reflection_schemes` for an example.
292
293 * ``quote`` - force or un-force quoting on the column name;
294 is applied to the :paramref:`_schema.Column.quote` parameter.
295
296 * ``info`` - a dictionary of arbitrary data to follow along with
297 the :class:`_schema.Column`, is applied to the
298 :paramref:`_schema.Column.info` parameter.
299
300 :func:`.event.listen` also accepts the ``propagate=True``
301 modifier for this event; when True, the listener function will
302 be established for any copies made of the target object,
303 i.e. those copies that are generated when
304 :meth:`_schema.Table.to_metadata` is used.
305
306 """
307
308
309class PoolEvents(event.Events):
310 """Available events for :class:`_pool.Pool`.
311
312 The methods here define the name of an event as well
313 as the names of members that are passed to listener
314 functions.
315
316 e.g.::
317
318 from sqlalchemy import event
319
320 def my_on_checkout(dbapi_conn, connection_rec, connection_proxy):
321 "handle an on checkout event"
322
323 event.listen(Pool, 'checkout', my_on_checkout)
324
325 In addition to accepting the :class:`_pool.Pool` class and
326 :class:`_pool.Pool` instances, :class:`_events.PoolEvents` also accepts
327 :class:`_engine.Engine` objects and the :class:`_engine.Engine` class as
328 targets, which will be resolved to the ``.pool`` attribute of the
329 given engine or the :class:`_pool.Pool` class::
330
331 engine = create_engine("postgresql://scott:tiger@localhost/test")
332
333 # will associate with engine.pool
334 event.listen(engine, 'checkout', my_on_checkout)
335
336 """
337
338 _target_class_doc = "SomeEngineOrPool"
339 _dispatch_target = Pool
340
341 @classmethod
342 def _accept_with(cls, target):
343 if isinstance(target, type):
344 if issubclass(target, Engine):
345 return Pool
346 elif issubclass(target, Pool):
347 return target
348 elif isinstance(target, Engine):
349 return target.pool
350 else:
351 return target
352
353 def connect(self, dbapi_connection, connection_record):
354 """Called at the moment a particular DBAPI connection is first
355 created for a given :class:`_pool.Pool`.
356
357 This event allows one to capture the point directly after which
358 the DBAPI module-level ``.connect()`` method has been used in order
359 to produce a new DBAPI connection.
360
361 :param dbapi_connection: a DBAPI connection.
362
363 :param connection_record: the :class:`._ConnectionRecord` managing the
364 DBAPI connection.
365
366 """
367
368 def first_connect(self, dbapi_connection, connection_record):
369 """Called exactly once for the first time a DBAPI connection is
370 checked out from a particular :class:`_pool.Pool`.
371
372 The rationale for :meth:`_events.PoolEvents.first_connect`
373 is to determine
374 information about a particular series of database connections based
375 on the settings used for all connections. Since a particular
376 :class:`_pool.Pool`
377 refers to a single "creator" function (which in terms
378 of a :class:`_engine.Engine`
379 refers to the URL and connection options used),
380 it is typically valid to make observations about a single connection
381 that can be safely assumed to be valid about all subsequent
382 connections, such as the database version, the server and client
383 encoding settings, collation settings, and many others.
384
385 :param dbapi_connection: a DBAPI connection.
386
387 :param connection_record: the :class:`._ConnectionRecord` managing the
388 DBAPI connection.
389
390 """
391
392 def checkout(self, dbapi_connection, connection_record, connection_proxy):
393 """Called when a connection is retrieved from the Pool.
394
395 :param dbapi_connection: a DBAPI connection.
396
397 :param connection_record: the :class:`._ConnectionRecord` managing the
398 DBAPI connection.
399
400 :param connection_proxy: the :class:`._ConnectionFairy` object which
401 will proxy the public interface of the DBAPI connection for the
402 lifespan of the checkout.
403
404 If you raise a :class:`~sqlalchemy.exc.DisconnectionError`, the current
405 connection will be disposed and a fresh connection retrieved.
406 Processing of all checkout listeners will abort and restart
407 using the new connection.
408
409 .. seealso:: :meth:`_events.ConnectionEvents.engine_connect`
410 - a similar event
411 which occurs upon creation of a new :class:`_engine.Connection`.
412
413 """
414
415 def checkin(self, dbapi_connection, connection_record):
416 """Called when a connection returns to the pool.
417
418 Note that the connection may be closed, and may be None if the
419 connection has been invalidated. ``checkin`` will not be called
420 for detached connections. (They do not return to the pool.)
421
422 :param dbapi_connection: a DBAPI connection.
423
424 :param connection_record: the :class:`._ConnectionRecord` managing the
425 DBAPI connection.
426
427 """
428
429 def reset(self, dbapi_connection, connection_record):
430 """Called before the "reset" action occurs for a pooled connection.
431
432 This event represents
433 when the ``rollback()`` method is called on the DBAPI connection
434 before it is returned to the pool. The behavior of "reset" can
435 be controlled, including disabled, using the ``reset_on_return``
436 pool argument.
437
438
439 The :meth:`_events.PoolEvents.reset` event is usually followed by the
440 :meth:`_events.PoolEvents.checkin` event is called, except in those
441 cases where the connection is discarded immediately after reset.
442
443 :param dbapi_connection: a DBAPI connection.
444
445 :param connection_record: the :class:`._ConnectionRecord` managing the
446 DBAPI connection.
447
448 .. seealso::
449
450 :meth:`_events.ConnectionEvents.rollback`
451
452 :meth:`_events.ConnectionEvents.commit`
453
454 """
455
456 def invalidate(self, dbapi_connection, connection_record, exception):
457 """Called when a DBAPI connection is to be "invalidated".
458
459 This event is called any time the :meth:`._ConnectionRecord.invalidate`
460 method is invoked, either from API usage or via "auto-invalidation",
461 without the ``soft`` flag.
462
463 The event occurs before a final attempt to call ``.close()`` on the
464 connection occurs.
465
466 :param dbapi_connection: a DBAPI connection.
467
468 :param connection_record: the :class:`._ConnectionRecord` managing the
469 DBAPI connection.
470
471 :param exception: the exception object corresponding to the reason
472 for this invalidation, if any. May be ``None``.
473
474 .. versionadded:: 0.9.2 Added support for connection invalidation
475 listening.
476
477 .. seealso::
478
479 :ref:`pool_connection_invalidation`
480
481 """
482
483 def soft_invalidate(self, dbapi_connection, connection_record, exception):
484 """Called when a DBAPI connection is to be "soft invalidated".
485
486 This event is called any time the :meth:`._ConnectionRecord.invalidate`
487 method is invoked with the ``soft`` flag.
488
489 Soft invalidation refers to when the connection record that tracks
490 this connection will force a reconnect after the current connection
491 is checked in. It does not actively close the dbapi_connection
492 at the point at which it is called.
493
494 .. versionadded:: 1.0.3
495
496 """
497
498 def close(self, dbapi_connection, connection_record):
499 """Called when a DBAPI connection is closed.
500
501 The event is emitted before the close occurs.
502
503 The close of a connection can fail; typically this is because
504 the connection is already closed. If the close operation fails,
505 the connection is discarded.
506
507 The :meth:`.close` event corresponds to a connection that's still
508 associated with the pool. To intercept close events for detached
509 connections use :meth:`.close_detached`.
510
511 .. versionadded:: 1.1
512
513 """
514
515 def detach(self, dbapi_connection, connection_record):
516 """Called when a DBAPI connection is "detached" from a pool.
517
518 This event is emitted after the detach occurs. The connection
519 is no longer associated with the given connection record.
520
521 .. versionadded:: 1.1
522
523 """
524
525 def close_detached(self, dbapi_connection):
526 """Called when a detached DBAPI connection is closed.
527
528 The event is emitted before the close occurs.
529
530 The close of a connection can fail; typically this is because
531 the connection is already closed. If the close operation fails,
532 the connection is discarded.
533
534 .. versionadded:: 1.1
535
536 """
537
538
539class ConnectionEvents(event.Events):
540 """Available events for :class:`.Connectable`, which includes
541 :class:`_engine.Connection` and :class:`_engine.Engine`.
542
543 The methods here define the name of an event as well as the names of
544 members that are passed to listener functions.
545
546 An event listener can be associated with any :class:`.Connectable`
547 class or instance, such as an :class:`_engine.Engine`, e.g.::
548
549 from sqlalchemy import event, create_engine
550
551 def before_cursor_execute(conn, cursor, statement, parameters, context,
552 executemany):
553 log.info("Received statement: %s", statement)
554
555 engine = create_engine('postgresql://scott:tiger@localhost/test')
556 event.listen(engine, "before_cursor_execute", before_cursor_execute)
557
558 or with a specific :class:`_engine.Connection`::
559
560 with engine.begin() as conn:
561 @event.listens_for(conn, 'before_cursor_execute')
562 def before_cursor_execute(conn, cursor, statement, parameters,
563 context, executemany):
564 log.info("Received statement: %s", statement)
565
566 When the methods are called with a `statement` parameter, such as in
567 :meth:`.after_cursor_execute`, :meth:`.before_cursor_execute` and
568 :meth:`.dbapi_error`, the statement is the exact SQL string that was
569 prepared for transmission to the DBAPI ``cursor`` in the connection's
570 :class:`.Dialect`.
571
572 The :meth:`.before_execute` and :meth:`.before_cursor_execute`
573 events can also be established with the ``retval=True`` flag, which
574 allows modification of the statement and parameters to be sent
575 to the database. The :meth:`.before_cursor_execute` event is
576 particularly useful here to add ad-hoc string transformations, such
577 as comments, to all executions::
578
579 from sqlalchemy.engine import Engine
580 from sqlalchemy import event
581
582 @event.listens_for(Engine, "before_cursor_execute", retval=True)
583 def comment_sql_calls(conn, cursor, statement, parameters,
584 context, executemany):
585 statement = statement + " -- some comment"
586 return statement, parameters
587
588 .. note:: :class:`_events.ConnectionEvents` can be established on any
589 combination of :class:`_engine.Engine`, :class:`_engine.Connection`,
590 as well
591 as instances of each of those classes. Events across all
592 four scopes will fire off for a given instance of
593 :class:`_engine.Connection`. However, for performance reasons, the
594 :class:`_engine.Connection` object determines at instantiation time
595 whether or not its parent :class:`_engine.Engine` has event listeners
596 established. Event listeners added to the :class:`_engine.Engine`
597 class or to an instance of :class:`_engine.Engine`
598 *after* the instantiation
599 of a dependent :class:`_engine.Connection` instance will usually
600 *not* be available on that :class:`_engine.Connection` instance.
601 The newly
602 added listeners will instead take effect for
603 :class:`_engine.Connection`
604 instances created subsequent to those event listeners being
605 established on the parent :class:`_engine.Engine` class or instance.
606
607 :param retval=False: Applies to the :meth:`.before_execute` and
608 :meth:`.before_cursor_execute` events only. When True, the
609 user-defined event function must have a return value, which
610 is a tuple of parameters that replace the given statement
611 and parameters. See those methods for a description of
612 specific return arguments.
613
614 """
615
616 _target_class_doc = "SomeEngine"
617 _dispatch_target = Connectable
618
619 @classmethod
620 def _listen(cls, event_key, retval=False):
621 target, identifier, fn = (
622 event_key.dispatch_target,
623 event_key.identifier,
624 event_key._listen_fn,
625 )
626
627 target._has_events = True
628
629 if not retval:
630 if identifier == "before_execute":
631 orig_fn = fn
632
633 def wrap_before_execute(
634 conn, clauseelement, multiparams, params
635 ):
636 orig_fn(conn, clauseelement, multiparams, params)
637 return clauseelement, multiparams, params
638
639 fn = wrap_before_execute
640 elif identifier == "before_cursor_execute":
641 orig_fn = fn
642
643 def wrap_before_cursor_execute(
644 conn, cursor, statement, parameters, context, executemany
645 ):
646 orig_fn(
647 conn,
648 cursor,
649 statement,
650 parameters,
651 context,
652 executemany,
653 )
654 return statement, parameters
655
656 fn = wrap_before_cursor_execute
657 elif retval and identifier not in (
658 "before_execute",
659 "before_cursor_execute",
660 "handle_error",
661 ):
662 raise exc.ArgumentError(
663 "Only the 'before_execute', "
664 "'before_cursor_execute' and 'handle_error' engine "
665 "event listeners accept the 'retval=True' "
666 "argument."
667 )
668 event_key.with_wrapper(fn).base_listen()
669
670 def before_execute(self, conn, clauseelement, multiparams, params):
671 """Intercept high level execute() events, receiving uncompiled
672 SQL constructs and other objects prior to rendering into SQL.
673
674 This event is good for debugging SQL compilation issues as well
675 as early manipulation of the parameters being sent to the database,
676 as the parameter lists will be in a consistent format here.
677
678 This event can be optionally established with the ``retval=True``
679 flag. The ``clauseelement``, ``multiparams``, and ``params``
680 arguments should be returned as a three-tuple in this case::
681
682 @event.listens_for(Engine, "before_execute", retval=True)
683 def before_execute(conn, clauseelement, multiparams, params):
684 # do something with clauseelement, multiparams, params
685 return clauseelement, multiparams, params
686
687 :param conn: :class:`_engine.Connection` object
688 :param clauseelement: SQL expression construct, :class:`.Compiled`
689 instance, or string statement passed to
690 :meth:`_engine.Connection.execute`.
691 :param multiparams: Multiple parameter sets, a list of dictionaries.
692 :param params: Single parameter set, a single dictionary.
693
694 .. seealso::
695
696 :meth:`.before_cursor_execute`
697
698 """
699
700 def after_execute(self, conn, clauseelement, multiparams, params, result):
701 """Intercept high level execute() events after execute.
702
703
704 :param conn: :class:`_engine.Connection` object
705 :param clauseelement: SQL expression construct, :class:`.Compiled`
706 instance, or string statement passed to
707 :meth:`_engine.Connection.execute`.
708 :param multiparams: Multiple parameter sets, a list of dictionaries.
709 :param params: Single parameter set, a single dictionary.
710 :param result: :class:`_engine.ResultProxy` generated by the execution
711 .
712
713 """
714
715 def before_cursor_execute(
716 self, conn, cursor, statement, parameters, context, executemany
717 ):
718 """Intercept low-level cursor execute() events before execution,
719 receiving the string SQL statement and DBAPI-specific parameter list to
720 be invoked against a cursor.
721
722 This event is a good choice for logging as well as late modifications
723 to the SQL string. It's less ideal for parameter modifications except
724 for those which are specific to a target backend.
725
726 This event can be optionally established with the ``retval=True``
727 flag. The ``statement`` and ``parameters`` arguments should be
728 returned as a two-tuple in this case::
729
730 @event.listens_for(Engine, "before_cursor_execute", retval=True)
731 def before_cursor_execute(conn, cursor, statement,
732 parameters, context, executemany):
733 # do something with statement, parameters
734 return statement, parameters
735
736 See the example at :class:`_events.ConnectionEvents`.
737
738 :param conn: :class:`_engine.Connection` object
739 :param cursor: DBAPI cursor object
740 :param statement: string SQL statement, as to be passed to the DBAPI
741 :param parameters: Dictionary, tuple, or list of parameters being
742 passed to the ``execute()`` or ``executemany()`` method of the
743 DBAPI ``cursor``. In some cases may be ``None``.
744 :param context: :class:`.ExecutionContext` object in use. May
745 be ``None``.
746 :param executemany: boolean, if ``True``, this is an ``executemany()``
747 call, if ``False``, this is an ``execute()`` call.
748
749 .. seealso::
750
751 :meth:`.before_execute`
752
753 :meth:`.after_cursor_execute`
754
755 """
756
757 def after_cursor_execute(
758 self, conn, cursor, statement, parameters, context, executemany
759 ):
760 """Intercept low-level cursor execute() events after execution.
761
762 :param conn: :class:`_engine.Connection` object
763 :param cursor: DBAPI cursor object. Will have results pending
764 if the statement was a SELECT, but these should not be consumed
765 as they will be needed by the :class:`_engine.ResultProxy`.
766 :param statement: string SQL statement, as passed to the DBAPI
767 :param parameters: Dictionary, tuple, or list of parameters being
768 passed to the ``execute()`` or ``executemany()`` method of the
769 DBAPI ``cursor``. In some cases may be ``None``.
770 :param context: :class:`.ExecutionContext` object in use. May
771 be ``None``.
772 :param executemany: boolean, if ``True``, this is an ``executemany()``
773 call, if ``False``, this is an ``execute()`` call.
774
775 """
776
777 @util.deprecated(
778 "0.9",
779 "The :meth:`_events.ConnectionEvents.dbapi_error` "
780 "event is deprecated and will be removed in a future release. "
781 "Please refer to the :meth:`_events.ConnectionEvents.handle_error` "
782 "event.",
783 )
784 def dbapi_error(
785 self, conn, cursor, statement, parameters, context, exception
786 ):
787 """Intercept a raw DBAPI error.
788
789 This event is called with the DBAPI exception instance
790 received from the DBAPI itself, *before* SQLAlchemy wraps the
791 exception with it's own exception wrappers, and before any
792 other operations are performed on the DBAPI cursor; the
793 existing transaction remains in effect as well as any state
794 on the cursor.
795
796 The use case here is to inject low-level exception handling
797 into an :class:`_engine.Engine`, typically for logging and
798 debugging purposes.
799
800 .. warning::
801
802 Code should **not** modify
803 any state or throw any exceptions here as this will
804 interfere with SQLAlchemy's cleanup and error handling
805 routines. For exception modification, please refer to the
806 new :meth:`_events.ConnectionEvents.handle_error` event.
807
808 Subsequent to this hook, SQLAlchemy may attempt any
809 number of operations on the connection/cursor, including
810 closing the cursor, rolling back of the transaction in the
811 case of connectionless execution, and disposing of the entire
812 connection pool if a "disconnect" was detected. The
813 exception is then wrapped in a SQLAlchemy DBAPI exception
814 wrapper and re-thrown.
815
816 :param conn: :class:`_engine.Connection` object
817 :param cursor: DBAPI cursor object
818 :param statement: string SQL statement, as passed to the DBAPI
819 :param parameters: Dictionary, tuple, or list of parameters being
820 passed to the ``execute()`` or ``executemany()`` method of the
821 DBAPI ``cursor``. In some cases may be ``None``.
822 :param context: :class:`.ExecutionContext` object in use. May
823 be ``None``.
824 :param exception: The **unwrapped** exception emitted directly from the
825 DBAPI. The class here is specific to the DBAPI module in use.
826
827 """
828
829 def handle_error(self, exception_context):
830 r"""Intercept all exceptions processed by the
831 :class:`_engine.Connection`.
832
833 This includes all exceptions emitted by the DBAPI as well as
834 within SQLAlchemy's statement invocation process, including
835 encoding errors and other statement validation errors. Other areas
836 in which the event is invoked include transaction begin and end,
837 result row fetching, cursor creation.
838
839 Note that :meth:`.handle_error` may support new kinds of exceptions
840 and new calling scenarios at *any time*. Code which uses this
841 event must expect new calling patterns to be present in minor
842 releases.
843
844 To support the wide variety of members that correspond to an exception,
845 as well as to allow extensibility of the event without backwards
846 incompatibility, the sole argument received is an instance of
847 :class:`.ExceptionContext`. This object contains data members
848 representing detail about the exception.
849
850 Use cases supported by this hook include:
851
852 * read-only, low-level exception handling for logging and
853 debugging purposes
854 * exception re-writing
855 * Establishing or disabling whether a connection or the owning
856 connection pool is invalidated or expired in response to a
857 specific exception. [1]_.
858
859 The hook is called while the cursor from the failed operation
860 (if any) is still open and accessible. Special cleanup operations
861 can be called on this cursor; SQLAlchemy will attempt to close
862 this cursor subsequent to this hook being invoked. If the connection
863 is in "autocommit" mode, the transaction also remains open within
864 the scope of this hook; the rollback of the per-statement transaction
865 also occurs after the hook is called.
866
867 .. note::
868
869 .. [1] The pool "pre_ping" handler enabled using the
870 :paramref:`_sa.create_engine.pool_pre_ping` parameter does
871 **not** consult this event before deciding if the "ping"
872 returned false, as opposed to receiving an unhandled error.
873 For this use case, the :ref:`legacy recipe based on
874 engine_connect() may be used
875 <pool_disconnects_pessimistic_custom>`. A future API allow
876 more comprehensive customization of the "disconnect"
877 detection mechanism across all functions.
878
879 A handler function has two options for replacing
880 the SQLAlchemy-constructed exception into one that is user
881 defined. It can either raise this new exception directly, in
882 which case all further event listeners are bypassed and the
883 exception will be raised, after appropriate cleanup as taken
884 place::
885
886 @event.listens_for(Engine, "handle_error")
887 def handle_exception(context):
888 if isinstance(context.original_exception,
889 psycopg2.OperationalError) and \
890 "failed" in str(context.original_exception):
891 raise MySpecialException("failed operation")
892
893 .. warning:: Because the
894 :meth:`_events.ConnectionEvents.handle_error`
895 event specifically provides for exceptions to be re-thrown as
896 the ultimate exception raised by the failed statement,
897 **stack traces will be misleading** if the user-defined event
898 handler itself fails and throws an unexpected exception;
899 the stack trace may not illustrate the actual code line that
900 failed! It is advised to code carefully here and use
901 logging and/or inline debugging if unexpected exceptions are
902 occurring.
903
904 Alternatively, a "chained" style of event handling can be
905 used, by configuring the handler with the ``retval=True``
906 modifier and returning the new exception instance from the
907 function. In this case, event handling will continue onto the
908 next handler. The "chained" exception is available using
909 :attr:`.ExceptionContext.chained_exception`::
910
911 @event.listens_for(Engine, "handle_error", retval=True)
912 def handle_exception(context):
913 if context.chained_exception is not None and \
914 "special" in context.chained_exception.message:
915 return MySpecialException("failed",
916 cause=context.chained_exception)
917
918 Handlers that return ``None`` may be used within the chain; when
919 a handler returns ``None``, the previous exception instance,
920 if any, is maintained as the current exception that is passed onto the
921 next handler.
922
923 When a custom exception is raised or returned, SQLAlchemy raises
924 this new exception as-is, it is not wrapped by any SQLAlchemy
925 object. If the exception is not a subclass of
926 :class:`sqlalchemy.exc.StatementError`,
927 certain features may not be available; currently this includes
928 the ORM's feature of adding a detail hint about "autoflush" to
929 exceptions raised within the autoflush process.
930
931 :param context: an :class:`.ExceptionContext` object. See this
932 class for details on all available members.
933
934 .. versionadded:: 0.9.7 Added the
935 :meth:`_events.ConnectionEvents.handle_error` hook.
936
937 .. versionchanged:: 1.1 The :meth:`.handle_error` event will now
938 receive all exceptions that inherit from ``BaseException``,
939 including ``SystemExit`` and ``KeyboardInterrupt``. The setting for
940 :attr:`.ExceptionContext.is_disconnect` is ``True`` in this case and
941 the default for
942 :attr:`.ExceptionContext.invalidate_pool_on_disconnect` is
943 ``False``.
944
945 .. versionchanged:: 1.0.0 The :meth:`.handle_error` event is now
946 invoked when an :class:`_engine.Engine` fails during the initial
947 call to :meth:`_engine.Engine.connect`, as well as when a
948 :class:`_engine.Connection` object encounters an error during a
949 reconnect operation.
950
951 .. versionchanged:: 1.0.0 The :meth:`.handle_error` event is
952 not fired off when a dialect makes use of the
953 ``skip_user_error_events`` execution option. This is used
954 by dialects which intend to catch SQLAlchemy-specific exceptions
955 within specific operations, such as when the MySQL dialect detects
956 a table not present within the ``has_table()`` dialect method.
957 Prior to 1.0.0, code which implements :meth:`.handle_error` needs
958 to ensure that exceptions thrown in these scenarios are re-raised
959 without modification.
960
961 """
962
963 def engine_connect(self, conn, branch):
964 """Intercept the creation of a new :class:`_engine.Connection`.
965
966 This event is called typically as the direct result of calling
967 the :meth:`_engine.Engine.connect` method.
968
969 It differs from the :meth:`_events.PoolEvents.connect` method, which
970 refers to the actual connection to a database at the DBAPI level;
971 a DBAPI connection may be pooled and reused for many operations.
972 In contrast, this event refers only to the production of a higher level
973 :class:`_engine.Connection` wrapper around such a DBAPI connection.
974
975 It also differs from the :meth:`_events.PoolEvents.checkout` event
976 in that it is specific to the :class:`_engine.Connection` object,
977 not the
978 DBAPI connection that :meth:`_events.PoolEvents.checkout` deals with,
979 although
980 this DBAPI connection is available here via the
981 :attr:`_engine.Connection.connection` attribute.
982 But note there can in fact
983 be multiple :meth:`_events.PoolEvents.checkout`
984 events within the lifespan
985 of a single :class:`_engine.Connection` object, if that
986 :class:`_engine.Connection`
987 is invalidated and re-established. There can also be multiple
988 :class:`_engine.Connection`
989 objects generated for the same already-checked-out
990 DBAPI connection, in the case that a "branch" of a
991 :class:`_engine.Connection`
992 is produced.
993
994 :param conn: :class:`_engine.Connection` object.
995 :param branch: if True, this is a "branch" of an existing
996 :class:`_engine.Connection`. A branch is generated within the course
997 of a statement execution to invoke supplemental statements, most
998 typically to pre-execute a SELECT of a default value for the purposes
999 of an INSERT statement.
1000
1001 .. versionadded:: 0.9.0
1002
1003 .. seealso::
1004
1005 :ref:`pool_disconnects_pessimistic` - illustrates how to use
1006 :meth:`_events.ConnectionEvents.engine_connect`
1007 to transparently ensure pooled connections are connected to the
1008 database.
1009
1010 :meth:`_events.PoolEvents.checkout`
1011 the lower-level pool checkout event
1012 for an individual DBAPI connection
1013
1014 :meth:`_events.ConnectionEvents.set_connection_execution_options`
1015 - a copy
1016 of a :class:`_engine.Connection` is also made when the
1017 :meth:`_engine.Connection.execution_options` method is called.
1018
1019 """
1020
1021 def set_connection_execution_options(self, conn, opts):
1022 """Intercept when the :meth:`_engine.Connection.execution_options`
1023 method is called.
1024
1025 This method is called after the new :class:`_engine.Connection`
1026 has been
1027 produced, with the newly updated execution options collection, but
1028 before the :class:`.Dialect` has acted upon any of those new options.
1029
1030 Note that this method is not called when a new
1031 :class:`_engine.Connection`
1032 is produced which is inheriting execution options from its parent
1033 :class:`_engine.Engine`; to intercept this condition, use the
1034 :meth:`_events.ConnectionEvents.engine_connect` event.
1035
1036 :param conn: The newly copied :class:`_engine.Connection` object
1037
1038 :param opts: dictionary of options that were passed to the
1039 :meth:`_engine.Connection.execution_options` method.
1040
1041 .. versionadded:: 0.9.0
1042
1043 .. seealso::
1044
1045 :meth:`_events.ConnectionEvents.set_engine_execution_options`
1046 - event
1047 which is called when :meth:`_engine.Engine.execution_options`
1048 is called.
1049
1050
1051 """
1052
1053 def set_engine_execution_options(self, engine, opts):
1054 """Intercept when the :meth:`_engine.Engine.execution_options`
1055 method is called.
1056
1057 The :meth:`_engine.Engine.execution_options` method produces a shallow
1058 copy of the :class:`_engine.Engine` which stores the new options.
1059 That new
1060 :class:`_engine.Engine` is passed here.
1061 A particular application of this
1062 method is to add a :meth:`_events.ConnectionEvents.engine_connect`
1063 event
1064 handler to the given :class:`_engine.Engine`
1065 which will perform some per-
1066 :class:`_engine.Connection` task specific to these execution options.
1067
1068 :param conn: The newly copied :class:`_engine.Engine` object
1069
1070 :param opts: dictionary of options that were passed to the
1071 :meth:`_engine.Connection.execution_options` method.
1072
1073 .. versionadded:: 0.9.0
1074
1075 .. seealso::
1076
1077 :meth:`_events.ConnectionEvents.set_connection_execution_options`
1078 - event
1079 which is called when :meth:`_engine.Connection.execution_options`
1080 is
1081 called.
1082
1083 """
1084
1085 def engine_disposed(self, engine):
1086 """Intercept when the :meth:`_engine.Engine.dispose` method is called.
1087
1088 The :meth:`_engine.Engine.dispose` method instructs the engine to
1089 "dispose" of it's connection pool (e.g. :class:`_pool.Pool`), and
1090 replaces it with a new one. Disposing of the old pool has the
1091 effect that existing checked-in connections are closed. The new
1092 pool does not establish any new connections until it is first used.
1093
1094 This event can be used to indicate that resources related to the
1095 :class:`_engine.Engine` should also be cleaned up,
1096 keeping in mind that the
1097 :class:`_engine.Engine`
1098 can still be used for new requests in which case
1099 it re-acquires connection resources.
1100
1101 .. versionadded:: 1.0.5
1102
1103 """
1104
1105 def begin(self, conn):
1106 """Intercept begin() events.
1107
1108 :param conn: :class:`_engine.Connection` object
1109
1110 """
1111
1112 def rollback(self, conn):
1113 """Intercept rollback() events, as initiated by a
1114 :class:`.Transaction`.
1115
1116 Note that the :class:`_pool.Pool` also "auto-rolls back"
1117 a DBAPI connection upon checkin, if the ``reset_on_return``
1118 flag is set to its default value of ``'rollback'``.
1119 To intercept this
1120 rollback, use the :meth:`_events.PoolEvents.reset` hook.
1121
1122 :param conn: :class:`_engine.Connection` object
1123
1124 .. seealso::
1125
1126 :meth:`_events.PoolEvents.reset`
1127
1128 """
1129
1130 def commit(self, conn):
1131 """Intercept commit() events, as initiated by a
1132 :class:`.Transaction`.
1133
1134 Note that the :class:`_pool.Pool` may also "auto-commit"
1135 a DBAPI connection upon checkin, if the ``reset_on_return``
1136 flag is set to the value ``'commit'``. To intercept this
1137 commit, use the :meth:`_events.PoolEvents.reset` hook.
1138
1139 :param conn: :class:`_engine.Connection` object
1140 """
1141
1142 def savepoint(self, conn, name):
1143 """Intercept savepoint() events.
1144
1145 :param conn: :class:`_engine.Connection` object
1146 :param name: specified name used for the savepoint.
1147
1148 """
1149
1150 def rollback_savepoint(self, conn, name, context):
1151 """Intercept rollback_savepoint() events.
1152
1153 :param conn: :class:`_engine.Connection` object
1154 :param name: specified name used for the savepoint.
1155 :param context: :class:`.ExecutionContext` in use. May be ``None``.
1156
1157 """
1158
1159 def release_savepoint(self, conn, name, context):
1160 """Intercept release_savepoint() events.
1161
1162 :param conn: :class:`_engine.Connection` object
1163 :param name: specified name used for the savepoint.
1164 :param context: :class:`.ExecutionContext` in use. May be ``None``.
1165
1166 """
1167
1168 def begin_twophase(self, conn, xid):
1169 """Intercept begin_twophase() events.
1170
1171 :param conn: :class:`_engine.Connection` object
1172 :param xid: two-phase XID identifier
1173
1174 """
1175
1176 def prepare_twophase(self, conn, xid):
1177 """Intercept prepare_twophase() events.
1178
1179 :param conn: :class:`_engine.Connection` object
1180 :param xid: two-phase XID identifier
1181 """
1182
1183 def rollback_twophase(self, conn, xid, is_prepared):
1184 """Intercept rollback_twophase() events.
1185
1186 :param conn: :class:`_engine.Connection` object
1187 :param xid: two-phase XID identifier
1188 :param is_prepared: boolean, indicates if
1189 :meth:`.TwoPhaseTransaction.prepare` was called.
1190
1191 """
1192
1193 def commit_twophase(self, conn, xid, is_prepared):
1194 """Intercept commit_twophase() events.
1195
1196 :param conn: :class:`_engine.Connection` object
1197 :param xid: two-phase XID identifier
1198 :param is_prepared: boolean, indicates if
1199 :meth:`.TwoPhaseTransaction.prepare` was called.
1200
1201 """
1202
1203
1204class DialectEvents(event.Events):
1205 """event interface for execution-replacement functions.
1206
1207 These events allow direct instrumentation and replacement
1208 of key dialect functions which interact with the DBAPI.
1209
1210 .. note::
1211
1212 :class:`.DialectEvents` hooks should be considered **semi-public**
1213 and experimental.
1214 These hooks are not for general use and are only for those situations
1215 where intricate re-statement of DBAPI mechanics must be injected onto
1216 an existing dialect. For general-use statement-interception events,
1217 please use the :class:`_events.ConnectionEvents` interface.
1218
1219 .. seealso::
1220
1221 :meth:`_events.ConnectionEvents.before_cursor_execute`
1222
1223 :meth:`_events.ConnectionEvents.before_execute`
1224
1225 :meth:`_events.ConnectionEvents.after_cursor_execute`
1226
1227 :meth:`_events.ConnectionEvents.after_execute`
1228
1229
1230 .. versionadded:: 0.9.4
1231
1232 """
1233
1234 _target_class_doc = "SomeEngine"
1235 _dispatch_target = Dialect
1236
1237 @classmethod
1238 def _listen(cls, event_key, retval=False):
1239 target = event_key.dispatch_target
1240
1241 target._has_events = True
1242 event_key.base_listen()
1243
1244 @classmethod
1245 def _accept_with(cls, target):
1246 if isinstance(target, type):
1247 if issubclass(target, Engine):
1248 return Dialect
1249 elif issubclass(target, Dialect):
1250 return target
1251 elif isinstance(target, Engine):
1252 return target.dialect
1253 else:
1254 return target
1255
1256 def do_connect(self, dialect, conn_rec, cargs, cparams):
1257 """Receive connection arguments before a connection is made.
1258
1259 Return a DBAPI connection to halt further events from invoking;
1260 the returned connection will be used.
1261
1262 Alternatively, the event can manipulate the cargs and/or cparams
1263 collections; cargs will always be a Python list that can be mutated
1264 in-place and cparams a Python dictionary. Return None to
1265 allow control to pass to the next event handler and ultimately
1266 to allow the dialect to connect normally, given the updated
1267 arguments.
1268
1269 .. versionadded:: 1.0.3
1270
1271 .. seealso::
1272
1273 :ref:`custom_dbapi_args`
1274
1275 """
1276
1277 def do_executemany(self, cursor, statement, parameters, context):
1278 """Receive a cursor to have executemany() called.
1279
1280 Return the value True to halt further events from invoking,
1281 and to indicate that the cursor execution has already taken
1282 place within the event handler.
1283
1284 """
1285
1286 def do_execute_no_params(self, cursor, statement, context):
1287 """Receive a cursor to have execute() with no parameters called.
1288
1289 Return the value True to halt further events from invoking,
1290 and to indicate that the cursor execution has already taken
1291 place within the event handler.
1292
1293 """
1294
1295 def do_execute(self, cursor, statement, parameters, context):
1296 """Receive a cursor to have execute() called.
1297
1298 Return the value True to halt further events from invoking,
1299 and to indicate that the cursor execution has already taken
1300 place within the event handler.
1301
1302 """
1303
1304 def do_setinputsizes(
1305 self, inputsizes, cursor, statement, parameters, context
1306 ):
1307 """Receive the setinputsizes dictionary for possible modification.
1308
1309 This event is emitted in the case where the dialect makes use of the
1310 DBAPI ``cursor.setinputsizes()`` method which passes information about
1311 parameter binding for a particular statement. The given
1312 ``inputsizes`` dictionary will contain :class:`.BindParameter` objects
1313 as keys, linked to DBAPI-specific type objects as values; for
1314 parameters that are not bound, they are added to the dictionary with
1315 ``None`` as the value, which means the parameter will not be included
1316 in the ultimate setinputsizes call. The event may be used to inspect
1317 and/or log the datatypes that are being bound, as well as to modify the
1318 dictionary in place. Parameters can be added, modified, or removed
1319 from this dictionary. Callers will typically want to inspect the
1320 :attr:`.BindParameter.type` attribute of the given bind objects in
1321 order to make decisions about the DBAPI object.
1322
1323 After the event, the ``inputsizes`` dictionary is converted into
1324 an appropriate datastructure to be passed to ``cursor.setinputsizes``;
1325 either a list for a positional bound parameter execution style,
1326 or a dictionary of string parameter keys to DBAPI type objects for
1327 a named bound parameter execution style.
1328
1329 Most dialects **do not use** this method at all; the only built-in
1330 dialect which uses this hook is the cx_Oracle dialect. The hook here
1331 is made available so as to allow customization of how datatypes are set
1332 up with the cx_Oracle DBAPI.
1333
1334 .. versionadded:: 1.2.9
1335
1336 .. seealso::
1337
1338 :ref:`cx_oracle_setinputsizes`
1339
1340 """
1341 pass