Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/engine/events.py: 56%
77 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
1# sqlalchemy/engine/events.py
2# Copyright (C) 2005-2023 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: https://www.opensource.org/licenses/mit-license.php
9from .base import Engine
10from .interfaces import Connectable
11from .interfaces import Dialect
12from .. import event
13from .. import exc
16class ConnectionEvents(event.Events):
17 """Available events for :class:`.Connectable`, which includes
18 :class:`_engine.Connection` and :class:`_engine.Engine`.
20 The methods here define the name of an event as well as the names of
21 members that are passed to listener functions.
23 An event listener can be associated with any :class:`.Connectable`
24 class or instance, such as an :class:`_engine.Engine`, e.g.::
26 from sqlalchemy import event, create_engine
28 def before_cursor_execute(conn, cursor, statement, parameters, context,
29 executemany):
30 log.info("Received statement: %s", statement)
32 engine = create_engine('postgresql://scott:tiger@localhost/test')
33 event.listen(engine, "before_cursor_execute", before_cursor_execute)
35 or with a specific :class:`_engine.Connection`::
37 with engine.begin() as conn:
38 @event.listens_for(conn, 'before_cursor_execute')
39 def before_cursor_execute(conn, cursor, statement, parameters,
40 context, executemany):
41 log.info("Received statement: %s", statement)
43 When the methods are called with a `statement` parameter, such as in
44 :meth:`.after_cursor_execute` or :meth:`.before_cursor_execute`,
45 the statement is the exact SQL string that was prepared for transmission
46 to the DBAPI ``cursor`` in the connection's :class:`.Dialect`.
48 The :meth:`.before_execute` and :meth:`.before_cursor_execute`
49 events can also be established with the ``retval=True`` flag, which
50 allows modification of the statement and parameters to be sent
51 to the database. The :meth:`.before_cursor_execute` event is
52 particularly useful here to add ad-hoc string transformations, such
53 as comments, to all executions::
55 from sqlalchemy.engine import Engine
56 from sqlalchemy import event
58 @event.listens_for(Engine, "before_cursor_execute", retval=True)
59 def comment_sql_calls(conn, cursor, statement, parameters,
60 context, executemany):
61 statement = statement + " -- some comment"
62 return statement, parameters
64 .. note:: :class:`_events.ConnectionEvents` can be established on any
65 combination of :class:`_engine.Engine`, :class:`_engine.Connection`,
66 as well
67 as instances of each of those classes. Events across all
68 four scopes will fire off for a given instance of
69 :class:`_engine.Connection`. However, for performance reasons, the
70 :class:`_engine.Connection` object determines at instantiation time
71 whether or not its parent :class:`_engine.Engine` has event listeners
72 established. Event listeners added to the :class:`_engine.Engine`
73 class or to an instance of :class:`_engine.Engine`
74 *after* the instantiation
75 of a dependent :class:`_engine.Connection` instance will usually
76 *not* be available on that :class:`_engine.Connection` instance.
77 The newly
78 added listeners will instead take effect for
79 :class:`_engine.Connection`
80 instances created subsequent to those event listeners being
81 established on the parent :class:`_engine.Engine` class or instance.
83 :param retval=False: Applies to the :meth:`.before_execute` and
84 :meth:`.before_cursor_execute` events only. When True, the
85 user-defined event function must have a return value, which
86 is a tuple of parameters that replace the given statement
87 and parameters. See those methods for a description of
88 specific return arguments.
90 """
92 _target_class_doc = "SomeEngine"
93 _dispatch_target = Connectable
95 @classmethod
96 def _listen(cls, event_key, retval=False):
97 target, identifier, fn = (
98 event_key.dispatch_target,
99 event_key.identifier,
100 event_key._listen_fn,
101 )
103 target._has_events = True
105 if not retval:
106 if identifier == "before_execute":
107 orig_fn = fn
109 def wrap_before_execute(
110 conn, clauseelement, multiparams, params, execution_options
111 ):
112 orig_fn(
113 conn,
114 clauseelement,
115 multiparams,
116 params,
117 execution_options,
118 )
119 return clauseelement, multiparams, params
121 fn = wrap_before_execute
122 elif identifier == "before_cursor_execute":
123 orig_fn = fn
125 def wrap_before_cursor_execute(
126 conn, cursor, statement, parameters, context, executemany
127 ):
128 orig_fn(
129 conn,
130 cursor,
131 statement,
132 parameters,
133 context,
134 executemany,
135 )
136 return statement, parameters
138 fn = wrap_before_cursor_execute
139 elif retval and identifier not in (
140 "before_execute",
141 "before_cursor_execute",
142 "handle_error",
143 ):
144 raise exc.ArgumentError(
145 "Only the 'before_execute', "
146 "'before_cursor_execute' and 'handle_error' engine "
147 "event listeners accept the 'retval=True' "
148 "argument."
149 )
150 event_key.with_wrapper(fn).base_listen()
152 @event._legacy_signature(
153 "1.4",
154 ["conn", "clauseelement", "multiparams", "params"],
155 lambda conn, clauseelement, multiparams, params, execution_options: (
156 conn,
157 clauseelement,
158 multiparams,
159 params,
160 ),
161 )
162 def before_execute(
163 self, conn, clauseelement, multiparams, params, execution_options
164 ):
165 """Intercept high level execute() events, receiving uncompiled
166 SQL constructs and other objects prior to rendering into SQL.
168 This event is good for debugging SQL compilation issues as well
169 as early manipulation of the parameters being sent to the database,
170 as the parameter lists will be in a consistent format here.
172 This event can be optionally established with the ``retval=True``
173 flag. The ``clauseelement``, ``multiparams``, and ``params``
174 arguments should be returned as a three-tuple in this case::
176 @event.listens_for(Engine, "before_execute", retval=True)
177 def before_execute(conn, clauseelement, multiparams, params):
178 # do something with clauseelement, multiparams, params
179 return clauseelement, multiparams, params
181 :param conn: :class:`_engine.Connection` object
182 :param clauseelement: SQL expression construct, :class:`.Compiled`
183 instance, or string statement passed to
184 :meth:`_engine.Connection.execute`.
185 :param multiparams: Multiple parameter sets, a list of dictionaries.
186 :param params: Single parameter set, a single dictionary.
187 :param execution_options: dictionary of execution
188 options passed along with the statement, if any. This is a merge
189 of all options that will be used, including those of the statement,
190 the connection, and those passed in to the method itself for
191 the 2.0 style of execution.
193 .. versionadded: 1.4
195 .. seealso::
197 :meth:`.before_cursor_execute`
199 """
201 @event._legacy_signature(
202 "1.4",
203 ["conn", "clauseelement", "multiparams", "params", "result"],
204 lambda conn, clauseelement, multiparams, params, execution_options, result: ( # noqa
205 conn,
206 clauseelement,
207 multiparams,
208 params,
209 result,
210 ),
211 )
212 def after_execute(
213 self,
214 conn,
215 clauseelement,
216 multiparams,
217 params,
218 execution_options,
219 result,
220 ):
221 """Intercept high level execute() events after execute.
224 :param conn: :class:`_engine.Connection` object
225 :param clauseelement: SQL expression construct, :class:`.Compiled`
226 instance, or string statement passed to
227 :meth:`_engine.Connection.execute`.
228 :param multiparams: Multiple parameter sets, a list of dictionaries.
229 :param params: Single parameter set, a single dictionary.
230 :param execution_options: dictionary of execution
231 options passed along with the statement, if any. This is a merge
232 of all options that will be used, including those of the statement,
233 the connection, and those passed in to the method itself for
234 the 2.0 style of execution.
236 .. versionadded: 1.4
238 :param result: :class:`_engine.CursorResult` generated by the
239 execution.
241 """
243 def before_cursor_execute(
244 self, conn, cursor, statement, parameters, context, executemany
245 ):
246 """Intercept low-level cursor execute() events before execution,
247 receiving the string SQL statement and DBAPI-specific parameter list to
248 be invoked against a cursor.
250 This event is a good choice for logging as well as late modifications
251 to the SQL string. It's less ideal for parameter modifications except
252 for those which are specific to a target backend.
254 This event can be optionally established with the ``retval=True``
255 flag. The ``statement`` and ``parameters`` arguments should be
256 returned as a two-tuple in this case::
258 @event.listens_for(Engine, "before_cursor_execute", retval=True)
259 def before_cursor_execute(conn, cursor, statement,
260 parameters, context, executemany):
261 # do something with statement, parameters
262 return statement, parameters
264 See the example at :class:`_events.ConnectionEvents`.
266 :param conn: :class:`_engine.Connection` object
267 :param cursor: DBAPI cursor object
268 :param statement: string SQL statement, as to be passed to the DBAPI
269 :param parameters: Dictionary, tuple, or list of parameters being
270 passed to the ``execute()`` or ``executemany()`` method of the
271 DBAPI ``cursor``. In some cases may be ``None``.
272 :param context: :class:`.ExecutionContext` object in use. May
273 be ``None``.
274 :param executemany: boolean, if ``True``, this is an ``executemany()``
275 call, if ``False``, this is an ``execute()`` call.
277 .. seealso::
279 :meth:`.before_execute`
281 :meth:`.after_cursor_execute`
283 """
285 def after_cursor_execute(
286 self, conn, cursor, statement, parameters, context, executemany
287 ):
288 """Intercept low-level cursor execute() events after execution.
290 :param conn: :class:`_engine.Connection` object
291 :param cursor: DBAPI cursor object. Will have results pending
292 if the statement was a SELECT, but these should not be consumed
293 as they will be needed by the :class:`_engine.CursorResult`.
294 :param statement: string SQL statement, as passed to the DBAPI
295 :param parameters: Dictionary, tuple, or list of parameters being
296 passed to the ``execute()`` or ``executemany()`` method of the
297 DBAPI ``cursor``. In some cases may be ``None``.
298 :param context: :class:`.ExecutionContext` object in use. May
299 be ``None``.
300 :param executemany: boolean, if ``True``, this is an ``executemany()``
301 call, if ``False``, this is an ``execute()`` call.
303 """
305 def handle_error(self, exception_context):
306 r"""Intercept all exceptions processed by the
307 :class:`_engine.Connection`.
309 This includes all exceptions emitted by the DBAPI as well as
310 within SQLAlchemy's statement invocation process, including
311 encoding errors and other statement validation errors. Other areas
312 in which the event is invoked include transaction begin and end,
313 result row fetching, cursor creation.
315 Note that :meth:`.handle_error` may support new kinds of exceptions
316 and new calling scenarios at *any time*. Code which uses this
317 event must expect new calling patterns to be present in minor
318 releases.
320 To support the wide variety of members that correspond to an exception,
321 as well as to allow extensibility of the event without backwards
322 incompatibility, the sole argument received is an instance of
323 :class:`.ExceptionContext`. This object contains data members
324 representing detail about the exception.
326 Use cases supported by this hook include:
328 * read-only, low-level exception handling for logging and
329 debugging purposes
330 * exception re-writing
331 * Establishing or disabling whether a connection or the owning
332 connection pool is invalidated or expired in response to a
333 specific exception [1]_.
335 The hook is called while the cursor from the failed operation
336 (if any) is still open and accessible. Special cleanup operations
337 can be called on this cursor; SQLAlchemy will attempt to close
338 this cursor subsequent to this hook being invoked. If the connection
339 is in "autocommit" mode, the transaction also remains open within
340 the scope of this hook; the rollback of the per-statement transaction
341 also occurs after the hook is called.
343 .. note::
345 .. [1] The pool "pre_ping" handler enabled using the
346 :paramref:`_sa.create_engine.pool_pre_ping` parameter does
347 **not** consult this event before deciding if the "ping"
348 returned false, as opposed to receiving an unhandled error.
349 For this use case, the :ref:`legacy recipe based on
350 engine_connect() may be used
351 <pool_disconnects_pessimistic_custom>`. A future API allow
352 more comprehensive customization of the "disconnect"
353 detection mechanism across all functions.
355 A handler function has two options for replacing
356 the SQLAlchemy-constructed exception into one that is user
357 defined. It can either raise this new exception directly, in
358 which case all further event listeners are bypassed and the
359 exception will be raised, after appropriate cleanup as taken
360 place::
362 @event.listens_for(Engine, "handle_error")
363 def handle_exception(context):
364 if isinstance(context.original_exception,
365 psycopg2.OperationalError) and \
366 "failed" in str(context.original_exception):
367 raise MySpecialException("failed operation")
369 .. warning:: Because the
370 :meth:`_events.ConnectionEvents.handle_error`
371 event specifically provides for exceptions to be re-thrown as
372 the ultimate exception raised by the failed statement,
373 **stack traces will be misleading** if the user-defined event
374 handler itself fails and throws an unexpected exception;
375 the stack trace may not illustrate the actual code line that
376 failed! It is advised to code carefully here and use
377 logging and/or inline debugging if unexpected exceptions are
378 occurring.
380 Alternatively, a "chained" style of event handling can be
381 used, by configuring the handler with the ``retval=True``
382 modifier and returning the new exception instance from the
383 function. In this case, event handling will continue onto the
384 next handler. The "chained" exception is available using
385 :attr:`.ExceptionContext.chained_exception`::
387 @event.listens_for(Engine, "handle_error", retval=True)
388 def handle_exception(context):
389 if context.chained_exception is not None and \
390 "special" in context.chained_exception.message:
391 return MySpecialException("failed",
392 cause=context.chained_exception)
394 Handlers that return ``None`` may be used within the chain; when
395 a handler returns ``None``, the previous exception instance,
396 if any, is maintained as the current exception that is passed onto the
397 next handler.
399 When a custom exception is raised or returned, SQLAlchemy raises
400 this new exception as-is, it is not wrapped by any SQLAlchemy
401 object. If the exception is not a subclass of
402 :class:`sqlalchemy.exc.StatementError`,
403 certain features may not be available; currently this includes
404 the ORM's feature of adding a detail hint about "autoflush" to
405 exceptions raised within the autoflush process.
407 :param context: an :class:`.ExceptionContext` object. See this
408 class for details on all available members.
410 .. versionadded:: 0.9.7 Added the
411 :meth:`_events.ConnectionEvents.handle_error` hook.
413 .. versionchanged:: 1.1 The :meth:`.handle_error` event will now
414 receive all exceptions that inherit from ``BaseException``,
415 including ``SystemExit`` and ``KeyboardInterrupt``. The setting for
416 :attr:`.ExceptionContext.is_disconnect` is ``True`` in this case and
417 the default for
418 :attr:`.ExceptionContext.invalidate_pool_on_disconnect` is
419 ``False``.
421 .. versionchanged:: 1.0.0 The :meth:`.handle_error` event is now
422 invoked when an :class:`_engine.Engine` fails during the initial
423 call to :meth:`_engine.Engine.connect`, as well as when a
424 :class:`_engine.Connection` object encounters an error during a
425 reconnect operation.
427 .. versionchanged:: 1.0.0 The :meth:`.handle_error` event is
428 not fired off when a dialect makes use of the
429 ``skip_user_error_events`` execution option. This is used
430 by dialects which intend to catch SQLAlchemy-specific exceptions
431 within specific operations, such as when the MySQL dialect detects
432 a table not present within the ``has_table()`` dialect method.
433 Prior to 1.0.0, code which implements :meth:`.handle_error` needs
434 to ensure that exceptions thrown in these scenarios are re-raised
435 without modification.
437 """
439 def engine_connect(self, conn, branch):
440 """Intercept the creation of a new :class:`_engine.Connection`.
442 This event is called typically as the direct result of calling
443 the :meth:`_engine.Engine.connect` method.
445 It differs from the :meth:`_events.PoolEvents.connect` method, which
446 refers to the actual connection to a database at the DBAPI level;
447 a DBAPI connection may be pooled and reused for many operations.
448 In contrast, this event refers only to the production of a higher level
449 :class:`_engine.Connection` wrapper around such a DBAPI connection.
451 It also differs from the :meth:`_events.PoolEvents.checkout` event
452 in that it is specific to the :class:`_engine.Connection` object,
453 not the
454 DBAPI connection that :meth:`_events.PoolEvents.checkout` deals with,
455 although
456 this DBAPI connection is available here via the
457 :attr:`_engine.Connection.connection` attribute.
458 But note there can in fact
459 be multiple :meth:`_events.PoolEvents.checkout`
460 events within the lifespan
461 of a single :class:`_engine.Connection` object, if that
462 :class:`_engine.Connection`
463 is invalidated and re-established. There can also be multiple
464 :class:`_engine.Connection`
465 objects generated for the same already-checked-out
466 DBAPI connection, in the case that a "branch" of a
467 :class:`_engine.Connection`
468 is produced.
470 :param conn: :class:`_engine.Connection` object.
471 :param branch: if True, this is a "branch" of an existing
472 :class:`_engine.Connection`. A branch is generated within the course
473 of a statement execution to invoke supplemental statements, most
474 typically to pre-execute a SELECT of a default value for the purposes
475 of an INSERT statement.
477 .. seealso::
479 :meth:`_events.PoolEvents.checkout`
480 the lower-level pool checkout event
481 for an individual DBAPI connection
483 """
485 def set_connection_execution_options(self, conn, opts):
486 """Intercept when the :meth:`_engine.Connection.execution_options`
487 method is called.
489 This method is called after the new :class:`_engine.Connection`
490 has been
491 produced, with the newly updated execution options collection, but
492 before the :class:`.Dialect` has acted upon any of those new options.
494 Note that this method is not called when a new
495 :class:`_engine.Connection`
496 is produced which is inheriting execution options from its parent
497 :class:`_engine.Engine`; to intercept this condition, use the
498 :meth:`_events.ConnectionEvents.engine_connect` event.
500 :param conn: The newly copied :class:`_engine.Connection` object
502 :param opts: dictionary of options that were passed to the
503 :meth:`_engine.Connection.execution_options` method.
505 .. versionadded:: 0.9.0
507 .. seealso::
509 :meth:`_events.ConnectionEvents.set_engine_execution_options`
510 - event
511 which is called when :meth:`_engine.Engine.execution_options`
512 is called.
515 """
517 def set_engine_execution_options(self, engine, opts):
518 """Intercept when the :meth:`_engine.Engine.execution_options`
519 method is called.
521 The :meth:`_engine.Engine.execution_options` method produces a shallow
522 copy of the :class:`_engine.Engine` which stores the new options.
523 That new
524 :class:`_engine.Engine` is passed here.
525 A particular application of this
526 method is to add a :meth:`_events.ConnectionEvents.engine_connect`
527 event
528 handler to the given :class:`_engine.Engine`
529 which will perform some per-
530 :class:`_engine.Connection` task specific to these execution options.
532 :param conn: The newly copied :class:`_engine.Engine` object
534 :param opts: dictionary of options that were passed to the
535 :meth:`_engine.Connection.execution_options` method.
537 .. versionadded:: 0.9.0
539 .. seealso::
541 :meth:`_events.ConnectionEvents.set_connection_execution_options`
542 - event
543 which is called when :meth:`_engine.Connection.execution_options`
544 is
545 called.
547 """
549 def engine_disposed(self, engine):
550 """Intercept when the :meth:`_engine.Engine.dispose` method is called.
552 The :meth:`_engine.Engine.dispose` method instructs the engine to
553 "dispose" of it's connection pool (e.g. :class:`_pool.Pool`), and
554 replaces it with a new one. Disposing of the old pool has the
555 effect that existing checked-in connections are closed. The new
556 pool does not establish any new connections until it is first used.
558 This event can be used to indicate that resources related to the
559 :class:`_engine.Engine` should also be cleaned up,
560 keeping in mind that the
561 :class:`_engine.Engine`
562 can still be used for new requests in which case
563 it re-acquires connection resources.
565 .. versionadded:: 1.0.5
567 """
569 def begin(self, conn):
570 """Intercept begin() events.
572 :param conn: :class:`_engine.Connection` object
574 """
576 def rollback(self, conn):
577 """Intercept rollback() events, as initiated by a
578 :class:`.Transaction`.
580 Note that the :class:`_pool.Pool` also "auto-rolls back"
581 a DBAPI connection upon checkin, if the ``reset_on_return``
582 flag is set to its default value of ``'rollback'``.
583 To intercept this
584 rollback, use the :meth:`_events.PoolEvents.reset` hook.
586 :param conn: :class:`_engine.Connection` object
588 .. seealso::
590 :meth:`_events.PoolEvents.reset`
592 """
594 def commit(self, conn):
595 """Intercept commit() events, as initiated by a
596 :class:`.Transaction`.
598 Note that the :class:`_pool.Pool` may also "auto-commit"
599 a DBAPI connection upon checkin, if the ``reset_on_return``
600 flag is set to the value ``'commit'``. To intercept this
601 commit, use the :meth:`_events.PoolEvents.reset` hook.
603 :param conn: :class:`_engine.Connection` object
604 """
606 def savepoint(self, conn, name):
607 """Intercept savepoint() events.
609 :param conn: :class:`_engine.Connection` object
610 :param name: specified name used for the savepoint.
612 """
614 def rollback_savepoint(self, conn, name, context):
615 """Intercept rollback_savepoint() events.
617 :param conn: :class:`_engine.Connection` object
618 :param name: specified name used for the savepoint.
619 :param context: not used
621 """
622 # TODO: deprecate "context"
624 def release_savepoint(self, conn, name, context):
625 """Intercept release_savepoint() events.
627 :param conn: :class:`_engine.Connection` object
628 :param name: specified name used for the savepoint.
629 :param context: not used
631 """
632 # TODO: deprecate "context"
634 def begin_twophase(self, conn, xid):
635 """Intercept begin_twophase() events.
637 :param conn: :class:`_engine.Connection` object
638 :param xid: two-phase XID identifier
640 """
642 def prepare_twophase(self, conn, xid):
643 """Intercept prepare_twophase() events.
645 :param conn: :class:`_engine.Connection` object
646 :param xid: two-phase XID identifier
647 """
649 def rollback_twophase(self, conn, xid, is_prepared):
650 """Intercept rollback_twophase() events.
652 :param conn: :class:`_engine.Connection` object
653 :param xid: two-phase XID identifier
654 :param is_prepared: boolean, indicates if
655 :meth:`.TwoPhaseTransaction.prepare` was called.
657 """
659 def commit_twophase(self, conn, xid, is_prepared):
660 """Intercept commit_twophase() events.
662 :param conn: :class:`_engine.Connection` object
663 :param xid: two-phase XID identifier
664 :param is_prepared: boolean, indicates if
665 :meth:`.TwoPhaseTransaction.prepare` was called.
667 """
670class DialectEvents(event.Events):
671 """event interface for execution-replacement functions.
673 These events allow direct instrumentation and replacement
674 of key dialect functions which interact with the DBAPI.
676 .. note::
678 :class:`.DialectEvents` hooks should be considered **semi-public**
679 and experimental.
680 These hooks are not for general use and are only for those situations
681 where intricate re-statement of DBAPI mechanics must be injected onto
682 an existing dialect. For general-use statement-interception events,
683 please use the :class:`_events.ConnectionEvents` interface.
685 .. seealso::
687 :meth:`_events.ConnectionEvents.before_cursor_execute`
689 :meth:`_events.ConnectionEvents.before_execute`
691 :meth:`_events.ConnectionEvents.after_cursor_execute`
693 :meth:`_events.ConnectionEvents.after_execute`
696 .. versionadded:: 0.9.4
698 """
700 _target_class_doc = "SomeEngine"
701 _dispatch_target = Dialect
703 @classmethod
704 def _listen(cls, event_key, retval=False):
705 target = event_key.dispatch_target
707 target._has_events = True
708 event_key.base_listen()
710 @classmethod
711 def _accept_with(cls, target):
712 if isinstance(target, type):
713 if issubclass(target, Engine):
714 return Dialect
715 elif issubclass(target, Dialect):
716 return target
717 elif isinstance(target, Engine):
718 return target.dialect
719 elif isinstance(target, Dialect):
720 return target
721 elif hasattr(target, "dispatch") and hasattr(
722 target.dispatch._events, "_no_async_engine_events"
723 ):
724 target.dispatch._events._no_async_engine_events()
725 else:
726 return None
728 def do_connect(self, dialect, conn_rec, cargs, cparams):
729 """Receive connection arguments before a connection is made.
731 This event is useful in that it allows the handler to manipulate the
732 cargs and/or cparams collections that control how the DBAPI
733 ``connect()`` function will be called. ``cargs`` will always be a
734 Python list that can be mutated in-place, and ``cparams`` a Python
735 dictionary that may also be mutated::
737 e = create_engine("postgresql+psycopg2://user@host/dbname")
739 @event.listens_for(e, 'do_connect')
740 def receive_do_connect(dialect, conn_rec, cargs, cparams):
741 cparams["password"] = "some_password"
743 The event hook may also be used to override the call to ``connect()``
744 entirely, by returning a non-``None`` DBAPI connection object::
746 e = create_engine("postgresql+psycopg2://user@host/dbname")
748 @event.listens_for(e, 'do_connect')
749 def receive_do_connect(dialect, conn_rec, cargs, cparams):
750 return psycopg2.connect(*cargs, **cparams)
753 .. versionadded:: 1.0.3
755 .. seealso::
757 :ref:`custom_dbapi_args`
759 """
761 def do_executemany(self, cursor, statement, parameters, context):
762 """Receive a cursor to have executemany() called.
764 Return the value True to halt further events from invoking,
765 and to indicate that the cursor execution has already taken
766 place within the event handler.
768 """
770 def do_execute_no_params(self, cursor, statement, context):
771 """Receive a cursor to have execute() with no parameters called.
773 Return the value True to halt further events from invoking,
774 and to indicate that the cursor execution has already taken
775 place within the event handler.
777 """
779 def do_execute(self, cursor, statement, parameters, context):
780 """Receive a cursor to have execute() called.
782 Return the value True to halt further events from invoking,
783 and to indicate that the cursor execution has already taken
784 place within the event handler.
786 """
788 def do_setinputsizes(
789 self, inputsizes, cursor, statement, parameters, context
790 ):
791 """Receive the setinputsizes dictionary for possible modification.
793 This event is emitted in the case where the dialect makes use of the
794 DBAPI ``cursor.setinputsizes()`` method which passes information about
795 parameter binding for a particular statement. The given
796 ``inputsizes`` dictionary will contain :class:`.BindParameter` objects
797 as keys, linked to DBAPI-specific type objects as values; for
798 parameters that are not bound, they are added to the dictionary with
799 ``None`` as the value, which means the parameter will not be included
800 in the ultimate setinputsizes call. The event may be used to inspect
801 and/or log the datatypes that are being bound, as well as to modify the
802 dictionary in place. Parameters can be added, modified, or removed
803 from this dictionary. Callers will typically want to inspect the
804 :attr:`.BindParameter.type` attribute of the given bind objects in
805 order to make decisions about the DBAPI object.
807 After the event, the ``inputsizes`` dictionary is converted into
808 an appropriate datastructure to be passed to ``cursor.setinputsizes``;
809 either a list for a positional bound parameter execution style,
810 or a dictionary of string parameter keys to DBAPI type objects for
811 a named bound parameter execution style.
813 The setinputsizes hook overall is only used for dialects which include
814 the flag ``use_setinputsizes=True``. Dialects which use this
815 include cx_Oracle, pg8000, asyncpg, and pyodbc dialects.
817 .. note::
819 For use with pyodbc, the ``use_setinputsizes`` flag
820 must be passed to the dialect, e.g.::
822 create_engine("mssql+pyodbc://...", use_setinputsizes=True)
824 .. seealso::
826 :ref:`mssql_pyodbc_setinputsizes`
828 .. versionadded:: 1.2.9
830 .. seealso::
832 :ref:`cx_oracle_setinputsizes`
834 """
835 pass