Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/future/engine.py: 61%
51 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
1from .. import util
2from ..engine import Connection as _LegacyConnection
3from ..engine import create_engine as _create_engine
4from ..engine import Engine as _LegacyEngine
5from ..engine.base import OptionEngineMixin
7NO_OPTIONS = util.immutabledict()
10def create_engine(*arg, **kw):
11 """Create a new :class:`_future.Engine` instance.
13 Arguments passed to :func:`_future.create_engine` are mostly identical
14 to those passed to the 1.x :func:`_sa.create_engine` function.
15 The difference is that the object returned is the :class:`._future.Engine`
16 which has the 2.0 version of the API.
18 """
20 kw["_future_engine_class"] = Engine
21 return _create_engine(*arg, **kw)
24class Connection(_LegacyConnection):
25 """Provides high-level functionality for a wrapped DB-API connection.
27 The :class:`_future.Connection` object is procured by calling
28 the :meth:`_future.Engine.connect` method of the :class:`_future.Engine`
29 object, and provides services for execution of SQL statements as well
30 as transaction control.
32 **This is the SQLAlchemy 2.0 version** of the :class:`_engine.Connection`
33 class. The API and behavior of this object is largely the same, with the
34 following differences in behavior:
36 * The result object returned for results is the
37 :class:`_engine.CursorResult`
38 object, which is a subclass of the :class:`_engine.Result`.
39 This object has a slightly different API and behavior than the
40 :class:`_engine.LegacyCursorResult` returned for 1.x style usage.
42 * The object has :meth:`_future.Connection.commit` and
43 :meth:`_future.Connection.rollback` methods which commit or roll back
44 the current transaction in progress, if any.
46 * The object features "autobegin" behavior, such that any call to
47 :meth:`_future.Connection.execute` will
48 unconditionally start a
49 transaction which can be controlled using the above mentioned
50 :meth:`_future.Connection.commit` and
51 :meth:`_future.Connection.rollback` methods.
53 * The object does not have any "autocommit" functionality. Any SQL
54 statement or DDL statement will not be followed by any COMMIT until
55 the transaction is explicitly committed, either via the
56 :meth:`_future.Connection.commit` method, or if the connection is
57 being used in a context manager that commits such as the one
58 returned by :meth:`_future.Engine.begin`.
60 * The SAVEPOINT method :meth:`_future.Connection.begin_nested` returns
61 a :class:`_engine.NestedTransaction` as was always the case, and the
62 savepoint can be controlled by invoking
63 :meth:`_engine.NestedTransaction.commit` or
64 :meth:`_engine.NestedTransaction.rollback` as was the case before.
65 However, this savepoint "transaction" is not associated with the
66 transaction that is controlled by the connection itself; the overall
67 transaction can be committed or rolled back directly which will not emit
68 any special instructions for the SAVEPOINT (this will typically have the
69 effect that one desires).
71 * The :class:`_future.Connection` object does not support "branching",
72 which was a pattern by which a sub "connection" would be used that
73 refers to this connection as a parent.
77 """
79 _is_future = True
81 def _branch(self):
82 raise NotImplementedError(
83 "sqlalchemy.future.Connection does not support "
84 "'branching' of new connections."
85 )
87 def begin(self):
88 """Begin a transaction prior to autobegin occurring.
90 The returned object is an instance of :class:`_engine.RootTransaction`.
91 This object represents the "scope" of the transaction,
92 which completes when either the :meth:`_engine.Transaction.rollback`
93 or :meth:`_engine.Transaction.commit` method is called.
95 The :meth:`_future.Connection.begin` method in SQLAlchemy 2.0 begins a
96 transaction that normally will be begun in any case when the connection
97 is first used to execute a statement. The reason this method might be
98 used would be to invoke the :meth:`_events.ConnectionEvents.begin`
99 event at a specific time, or to organize code within the scope of a
100 connection checkout in terms of context managed blocks, such as::
102 with engine.connect() as conn:
103 with conn.begin():
104 conn.execute(...)
105 conn.execute(...)
107 with conn.begin():
108 conn.execute(...)
109 conn.execute(...)
111 The above code is not fundamentally any different in its behavior than
112 the following code which does not use
113 :meth:`_future.Connection.begin`; the below style is referred towards
114 as "commit as you go" style::
116 with engine.connect() as conn:
117 conn.execute(...)
118 conn.execute(...)
119 conn.commit()
121 conn.execute(...)
122 conn.execute(...)
123 conn.commit()
125 From a database point of view, the :meth:`_future.Connection.begin`
126 method does not emit any SQL or change the state of the underlying
127 DBAPI connection in any way; the Python DBAPI does not have any
128 concept of explicit transaction begin.
130 .. seealso::
132 :ref:`tutorial_working_with_transactions` - in the
133 :ref:`unified_tutorial`
135 :meth:`_future.Connection.begin_nested` - use a SAVEPOINT
137 :meth:`_engine.Connection.begin_twophase` -
138 use a two phase /XID transaction
140 :meth:`_future.Engine.begin` - context manager available from
141 :class:`_future.Engine`
143 """
144 return super(Connection, self).begin()
146 def begin_nested(self):
147 """Begin a nested transaction (i.e. SAVEPOINT) and return a transaction
148 handle.
150 The returned object is an instance of
151 :class:`_engine.NestedTransaction`.
153 Nested transactions require SAVEPOINT support in the
154 underlying database. Any transaction in the hierarchy may
155 ``commit`` and ``rollback``, however the outermost transaction
156 still controls the overall ``commit`` or ``rollback`` of the
157 transaction of a whole.
159 If an outer :class:`.RootTransaction` is not present on this
160 :class:`_future.Connection`, a new one is created using "autobegin".
161 This outer transaction may be completed using "commit-as-you-go" style
162 usage, by calling upon :meth:`_future.Connection.commit` or
163 :meth:`_future.Connection.rollback`.
165 .. tip::
167 The "autobegin" behavior of :meth:`_future.Connection.begin_nested`
168 is specific to :term:`2.0 style` use; for legacy behaviors, see
169 :meth:`_engine.Connection.begin_nested`.
171 The :class:`_engine.NestedTransaction` remains independent of the
172 :class:`_future.Connection` object itself. Calling the
173 :meth:`_future.Connection.commit` or
174 :meth:`_future.Connection.rollback` will always affect the actual
175 containing database transaction itself, and not the SAVEPOINT itself.
176 When a database transaction is committed, any SAVEPOINTs that have been
177 established are cleared and the data changes within their scope is also
178 committed.
180 .. seealso::
182 :meth:`_future.Connection.begin`
185 """
186 return super(Connection, self).begin_nested()
188 def commit(self):
189 """Commit the transaction that is currently in progress.
191 This method commits the current transaction if one has been started.
192 If no transaction was started, the method has no effect, assuming
193 the connection is in a non-invalidated state.
195 A transaction is begun on a :class:`_future.Connection` automatically
196 whenever a statement is first executed, or when the
197 :meth:`_future.Connection.begin` method is called.
199 .. note:: The :meth:`_future.Connection.commit` method only acts upon
200 the primary database transaction that is linked to the
201 :class:`_future.Connection` object. It does not operate upon a
202 SAVEPOINT that would have been invoked from the
203 :meth:`_future.Connection.begin_nested` method; for control of a
204 SAVEPOINT, call :meth:`_engine.NestedTransaction.commit` on the
205 :class:`_engine.NestedTransaction` that is returned by the
206 :meth:`_future.Connection.begin_nested` method itself.
209 """
210 if self._transaction:
211 self._transaction.commit()
213 def rollback(self):
214 """Roll back the transaction that is currently in progress.
216 This method rolls back the current transaction if one has been started.
217 If no transaction was started, the method has no effect. If a
218 transaction was started and the connection is in an invalidated state,
219 the transaction is cleared using this method.
221 A transaction is begun on a :class:`_future.Connection` automatically
222 whenever a statement is first executed, or when the
223 :meth:`_future.Connection.begin` method is called.
225 .. note:: The :meth:`_future.Connection.rollback` method only acts
226 upon the primary database transaction that is linked to the
227 :class:`_future.Connection` object. It does not operate upon a
228 SAVEPOINT that would have been invoked from the
229 :meth:`_future.Connection.begin_nested` method; for control of a
230 SAVEPOINT, call :meth:`_engine.NestedTransaction.rollback` on the
231 :class:`_engine.NestedTransaction` that is returned by the
232 :meth:`_future.Connection.begin_nested` method itself.
235 """
236 if self._transaction:
237 self._transaction.rollback()
239 def close(self):
240 """Close this :class:`_future.Connection`.
242 This has the effect of also calling :meth:`_future.Connection.rollback`
243 if any transaction is in place.
245 """
246 super(Connection, self).close()
248 def execute(self, statement, parameters=None, execution_options=None):
249 r"""Executes a SQL statement construct and returns a
250 :class:`_engine.Result`.
252 :param statement: The statement to be executed. This is always
253 an object that is in both the :class:`_expression.ClauseElement` and
254 :class:`_expression.Executable` hierarchies, including:
256 * :class:`_expression.Select`
257 * :class:`_expression.Insert`, :class:`_expression.Update`,
258 :class:`_expression.Delete`
259 * :class:`_expression.TextClause` and
260 :class:`_expression.TextualSelect`
261 * :class:`_schema.DDL` and objects which inherit from
262 :class:`_schema.DDLElement`
264 :param parameters: parameters which will be bound into the statement.
265 This may be either a dictionary of parameter names to values,
266 or a mutable sequence (e.g. a list) of dictionaries. When a
267 list of dictionaries is passed, the underlying statement execution
268 will make use of the DBAPI ``cursor.executemany()`` method.
269 When a single dictionary is passed, the DBAPI ``cursor.execute()``
270 method will be used.
272 :param execution_options: optional dictionary of execution options,
273 which will be associated with the statement execution. This
274 dictionary can provide a subset of the options that are accepted
275 by :meth:`_future.Connection.execution_options`.
277 :return: a :class:`_engine.Result` object.
279 """
280 return self._execute_20(
281 statement, parameters, execution_options or NO_OPTIONS
282 )
284 def scalar(self, statement, parameters=None, execution_options=None):
285 r"""Executes a SQL statement construct and returns a scalar object.
287 This method is shorthand for invoking the
288 :meth:`_engine.Result.scalar` method after invoking the
289 :meth:`_future.Connection.execute` method. Parameters are equivalent.
291 :return: a scalar Python value representing the first column of the
292 first row returned.
294 """
295 return self.execute(statement, parameters, execution_options).scalar()
298class Engine(_LegacyEngine):
299 """Connects a :class:`_pool.Pool` and
300 :class:`_engine.Dialect` together to provide a
301 source of database connectivity and behavior.
303 **This is the SQLAlchemy 2.0 version** of the :class:`~.engine.Engine`.
305 An :class:`.future.Engine` object is instantiated publicly using the
306 :func:`~sqlalchemy.future.create_engine` function.
308 .. seealso::
310 :doc:`/core/engines`
312 :ref:`connections_toplevel`
314 """
316 _connection_cls = Connection
317 _is_future = True
319 def _not_implemented(self, *arg, **kw):
320 raise NotImplementedError(
321 "This method is not implemented for SQLAlchemy 2.0."
322 )
324 transaction = (
325 run_callable
326 ) = (
327 execute
328 ) = (
329 scalar
330 ) = (
331 _execute_clauseelement
332 ) = _execute_compiled = table_names = has_table = _not_implemented
334 def _run_ddl_visitor(self, visitorcallable, element, **kwargs):
335 # TODO: this is for create_all support etc. not clear if we
336 # want to provide this in 2.0, that is, a way to execute SQL where
337 # they aren't calling "engine.begin()" explicitly, however, DDL
338 # may be a special case for which we want to continue doing it this
339 # way. A big win here is that the full DDL sequence is inside of a
340 # single transaction rather than COMMIT for each statement.
341 with self.begin() as conn:
342 conn._run_ddl_visitor(visitorcallable, element, **kwargs)
344 @classmethod
345 def _future_facade(self, legacy_engine):
346 return Engine(
347 legacy_engine.pool,
348 legacy_engine.dialect,
349 legacy_engine.url,
350 logging_name=legacy_engine.logging_name,
351 echo=legacy_engine.echo,
352 hide_parameters=legacy_engine.hide_parameters,
353 execution_options=legacy_engine._execution_options,
354 )
356 @util.contextmanager
357 def begin(self):
358 """Return a :class:`_future.Connection` object with a transaction
359 begun.
361 Use of this method is similar to that of
362 :meth:`_future.Engine.connect`, typically as a context manager, which
363 will automatically maintain the state of the transaction when the block
364 ends, either by calling :meth:`_future.Connection.commit` when the
365 block succeeds normally, or :meth:`_future.Connection.rollback` when an
366 exception is raised, before propagating the exception outwards::
368 with engine.begin() as connection:
369 connection.execute(text("insert into table values ('foo')"))
372 .. seealso::
374 :meth:`_future.Engine.connect`
376 :meth:`_future.Connection.begin`
378 """
379 with self.connect() as conn:
380 with conn.begin():
381 yield conn
383 def connect(self):
384 """Return a new :class:`_future.Connection` object.
386 The :class:`_future.Connection` acts as a Python context manager, so
387 the typical use of this method looks like::
389 with engine.connect() as connection:
390 connection.execute(text("insert into table values ('foo')"))
391 connection.commit()
393 Where above, after the block is completed, the connection is "closed"
394 and its underlying DBAPI resources are returned to the connection pool.
395 This also has the effect of rolling back any transaction that
396 was explicitly begun or was begun via autobegin, and will
397 emit the :meth:`_events.ConnectionEvents.rollback` event if one was
398 started and is still in progress.
400 .. seealso::
402 :meth:`_future.Engine.begin`
405 """
406 return super(Engine, self).connect()
409class OptionEngine(OptionEngineMixin, Engine):
410 pass
413Engine._option_cls = OptionEngine